@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.
Files changed (604) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +43 -10
  3. package/lib/commonjs/assets/icons.js +7 -2
  4. package/lib/commonjs/assets/icons.js.map +1 -1
  5. package/lib/commonjs/components/AuthForms/Login.js +4 -4
  6. package/lib/commonjs/components/AuthForms/Login.js.map +1 -1
  7. package/lib/commonjs/components/Header/HeaderRoomList.js +29 -8
  8. package/lib/commonjs/components/Header/HeaderRoomList.js.map +1 -1
  9. package/lib/commonjs/components/MainComponents/ChatHeader.js +9 -3
  10. package/lib/commonjs/components/MainComponents/ChatHeader.js.map +1 -1
  11. package/lib/commonjs/components/MainComponents/ChatRoom.js +150 -14
  12. package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
  13. package/lib/commonjs/components/MainComponents/ChatWrapper.js +34 -13
  14. package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
  15. package/lib/commonjs/components/MainComponents/LoginWrapper.js +2 -1
  16. package/lib/commonjs/components/MainComponents/LoginWrapper.js.map +1 -1
  17. package/lib/commonjs/components/MainComponents/MediaMessage.js +29 -9
  18. package/lib/commonjs/components/MainComponents/MediaMessage.js.map +1 -1
  19. package/lib/commonjs/components/MainComponents/MessageContainer.js +5 -1
  20. package/lib/commonjs/components/MainComponents/MessageContainer.js.map +1 -1
  21. package/lib/commonjs/components/MainComponents/MessageList.js +13 -5
  22. package/lib/commonjs/components/MainComponents/MessageList.js.map +1 -1
  23. package/lib/commonjs/components/MainComponents/ProfileImagePlaceholder.js +14 -13
  24. package/lib/commonjs/components/MainComponents/ProfileImagePlaceholder.js.map +1 -1
  25. package/lib/commonjs/components/MainComponents/RoomList.js +208 -35
  26. package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
  27. package/lib/commonjs/components/Menu/HeaderRoomListMenu.js +317 -98
  28. package/lib/commonjs/components/Menu/HeaderRoomListMenu.js.map +1 -1
  29. package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js +322 -110
  30. package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
  31. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js +546 -203
  32. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  33. package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js +226 -0
  34. package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js.map +1 -0
  35. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +69 -27
  36. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  37. package/lib/commonjs/components/Modals/FilePreviewModal/PdfView.js +2 -1
  38. package/lib/commonjs/components/Modals/FilePreviewModal/PdfView.js.map +1 -1
  39. package/lib/commonjs/components/Modals/Modal/Modal.js +8 -0
  40. package/lib/commonjs/components/Modals/Modal/Modal.js.map +1 -1
  41. package/lib/commonjs/components/Modals/NewChatModal/ModalContent.js +2 -1
  42. package/lib/commonjs/components/Modals/NewChatModal/ModalContent.js.map +1 -1
  43. package/lib/commonjs/components/Modals/NewChatModal/NewChatModal.js +202 -106
  44. package/lib/commonjs/components/Modals/NewChatModal/NewChatModal.js.map +1 -1
  45. package/lib/commonjs/components/Modals/NewChatModal/UpdNewChatModal.js +8 -0
  46. package/lib/commonjs/components/Modals/NewChatModal/UpdNewChatModal.js.map +1 -1
  47. package/lib/commonjs/components/Modals/ProfileHeader/ProfileHeader.js +563 -0
  48. package/lib/commonjs/components/Modals/ProfileHeader/ProfileHeader.js.map +1 -0
  49. package/lib/commonjs/components/Modals/ProfileHeader/ProfileMenu.js +210 -0
  50. package/lib/commonjs/components/Modals/ProfileHeader/ProfileMenu.js.map +1 -0
  51. package/lib/commonjs/components/Modals/SelectUsersModal/SelectUsersModal.js +4 -2
  52. package/lib/commonjs/components/Modals/SelectUsersModal/SelectUsersModal.js.map +1 -1
  53. package/lib/commonjs/components/Modals/UserProfileModal/EditUserModal.js +7 -21
  54. package/lib/commonjs/components/Modals/UserProfileModal/EditUserModal.js.map +1 -1
  55. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js +507 -244
  56. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  57. package/lib/commonjs/components/Modals/UserSettingsModal/UserSettingsModal.js +74 -46
  58. package/lib/commonjs/components/Modals/UserSettingsModal/UserSettingsModal.js.map +1 -1
  59. package/lib/commonjs/components/Modals/styledModalComponents.js +9 -2
  60. package/lib/commonjs/components/Modals/styledModalComponents.js.map +1 -1
  61. package/lib/commonjs/components/RoomComponents/ChatRoomItem.js +21 -7
  62. package/lib/commonjs/components/RoomComponents/ChatRoomItem.js.map +1 -1
  63. package/lib/commonjs/components/RoomComponents/styled/LastMessageFile.js +22 -3
  64. package/lib/commonjs/components/RoomComponents/styled/LastMessageFile.js.map +1 -1
  65. package/lib/commonjs/components/RoomComponents/styled/LastMessagePhoto.js +17 -3
  66. package/lib/commonjs/components/RoomComponents/styled/LastMessagePhoto.js.map +1 -1
  67. package/lib/commonjs/components/RoomComponents/styled/LastMessageVideo.js +17 -3
  68. package/lib/commonjs/components/RoomComponents/styled/LastMessageVideo.js.map +1 -1
  69. package/lib/commonjs/components/VideoCalls/VideoCallSession.js +6 -3
  70. package/lib/commonjs/components/VideoCalls/VideoCallSession.js.map +1 -1
  71. package/lib/commonjs/components/styled/AudioMessage.js +2 -1
  72. package/lib/commonjs/components/styled/AudioMessage.js.map +1 -1
  73. package/lib/commonjs/components/styled/MessageImage.js +37 -9
  74. package/lib/commonjs/components/styled/MessageImage.js.map +1 -1
  75. package/lib/commonjs/components/styled/SendInput.js +80 -11
  76. package/lib/commonjs/components/styled/SendInput.js.map +1 -1
  77. package/lib/commonjs/components/styled/StyledComponents.js +9 -3
  78. package/lib/commonjs/components/styled/StyledComponents.js.map +1 -1
  79. package/lib/commonjs/components/styled/StyledInputComponents/StyledInputComponents.js +11 -4
  80. package/lib/commonjs/components/styled/StyledInputComponents/StyledInputComponents.js.map +1 -1
  81. package/lib/commonjs/components/styled/UnsupportedType.js +14 -4
  82. package/lib/commonjs/components/styled/UnsupportedType.js.map +1 -1
  83. package/lib/commonjs/components/styled/VideoMessage.js +119 -61
  84. package/lib/commonjs/components/styled/VideoMessage.js.map +1 -1
  85. package/lib/commonjs/context/xmppProvider.js +184 -59
  86. package/lib/commonjs/context/xmppProvider.js.map +1 -1
  87. package/lib/commonjs/helpers/createMessageFromXml.js +19 -1
  88. package/lib/commonjs/helpers/createMessageFromXml.js.map +1 -1
  89. package/lib/commonjs/helpers/ensureScopedChatCache.js +2 -2
  90. package/lib/commonjs/helpers/ensureScopedChatCache.js.map +1 -1
  91. package/lib/commonjs/helpers/getChatBackground.js +23 -0
  92. package/lib/commonjs/helpers/getChatBackground.js.map +1 -0
  93. package/lib/commonjs/helpers/getDisplayFileName.js +79 -0
  94. package/lib/commonjs/helpers/getDisplayFileName.js.map +1 -0
  95. package/lib/commonjs/helpers/getServerReadTimestamp.js +188 -0
  96. package/lib/commonjs/helpers/getServerReadTimestamp.js.map +1 -0
  97. package/lib/commonjs/helpers/historyPreloadScheduler.js +65 -2
  98. package/lib/commonjs/helpers/historyPreloadScheduler.js.map +1 -1
  99. package/lib/commonjs/helpers/initXmppRooms.js +14 -8
  100. package/lib/commonjs/helpers/initXmppRooms.js.map +1 -1
  101. package/lib/commonjs/helpers/insertMessageWithDelimiter.js +51 -9
  102. package/lib/commonjs/helpers/insertMessageWithDelimiter.js.map +1 -1
  103. package/lib/commonjs/helpers/isOwnMessage.js +75 -0
  104. package/lib/commonjs/helpers/isOwnMessage.js.map +1 -0
  105. package/lib/commonjs/helpers/keyboardLayout.js +12 -2
  106. package/lib/commonjs/helpers/keyboardLayout.js.map +1 -1
  107. package/lib/commonjs/helpers/mediaLibraryRuntime.js +31 -0
  108. package/lib/commonjs/helpers/mediaLibraryRuntime.js.map +1 -0
  109. package/lib/commonjs/helpers/mimeToExtension.js +6 -14
  110. package/lib/commonjs/helpers/mimeToExtension.js.map +1 -1
  111. package/lib/commonjs/helpers/msgSortableMs.js +37 -0
  112. package/lib/commonjs/helpers/msgSortableMs.js.map +1 -0
  113. package/lib/commonjs/helpers/persistCrypto.js +122 -0
  114. package/lib/commonjs/helpers/persistCrypto.js.map +1 -0
  115. package/lib/commonjs/helpers/pickImageAsset.js +68 -0
  116. package/lib/commonjs/helpers/pickImageAsset.js.map +1 -0
  117. package/lib/commonjs/helpers/pushPayload.js +71 -0
  118. package/lib/commonjs/helpers/pushPayload.js.map +1 -0
  119. package/lib/commonjs/helpers/resolveInitBeforeLoadUser.js +130 -17
  120. package/lib/commonjs/helpers/resolveInitBeforeLoadUser.js.map +1 -1
  121. package/lib/commonjs/helpers/secureFileUrl.js +101 -0
  122. package/lib/commonjs/helpers/secureFileUrl.js.map +1 -0
  123. package/lib/commonjs/helpers/secureKeyValue.js +83 -0
  124. package/lib/commonjs/helpers/secureKeyValue.js.map +1 -0
  125. package/lib/commonjs/helpers/secureStoreRuntime.js +59 -0
  126. package/lib/commonjs/helpers/secureStoreRuntime.js.map +1 -0
  127. package/lib/commonjs/helpers/secureUserStorage.js +75 -0
  128. package/lib/commonjs/helpers/secureUserStorage.js.map +1 -0
  129. package/lib/commonjs/helpers/shallowEqual.js +36 -0
  130. package/lib/commonjs/helpers/shallowEqual.js.map +1 -0
  131. package/lib/commonjs/helpers/sheetGestures.js +32 -0
  132. package/lib/commonjs/helpers/sheetGestures.js.map +1 -0
  133. package/lib/commonjs/hooks/useChatRoomFocus.js +45 -12
  134. package/lib/commonjs/hooks/useChatRoomFocus.js.map +1 -1
  135. package/lib/commonjs/hooks/useChatWrapperInit.js +30 -10
  136. package/lib/commonjs/hooks/useChatWrapperInit.js.map +1 -1
  137. package/lib/commonjs/hooks/useComposing.js +27 -0
  138. package/lib/commonjs/hooks/useComposing.js.map +1 -1
  139. package/lib/commonjs/hooks/useFileToken.js +10 -0
  140. package/lib/commonjs/hooks/useFileToken.js.map +1 -0
  141. package/lib/commonjs/hooks/useLogout.js +23 -7
  142. package/lib/commonjs/hooks/useLogout.js.map +1 -1
  143. package/lib/commonjs/hooks/usePendingNotification.js +8 -11
  144. package/lib/commonjs/hooks/usePendingNotification.js.map +1 -1
  145. package/lib/commonjs/hooks/useSendMessage.js +50 -14
  146. package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
  147. package/lib/commonjs/hooks/useUnreadMessagesCounter.js +6 -1
  148. package/lib/commonjs/hooks/useUnreadMessagesCounter.js.map +1 -1
  149. package/lib/commonjs/i18n/strings.js +145 -37
  150. package/lib/commonjs/i18n/strings.js.map +1 -1
  151. package/lib/commonjs/main.js +44 -0
  152. package/lib/commonjs/main.js.map +1 -1
  153. package/lib/commonjs/networking/api-requests/auth.api.js +134 -60
  154. package/lib/commonjs/networking/api-requests/auth.api.js.map +1 -1
  155. package/lib/commonjs/networking/api-requests/roomMembers.api.js +1 -1
  156. package/lib/commonjs/networking/api-requests/roomMembers.api.js.map +1 -1
  157. package/lib/commonjs/networking/api-requests/rooms.api.js +9 -9
  158. package/lib/commonjs/networking/api-requests/rooms.api.js.map +1 -1
  159. package/lib/commonjs/networking/api-requests/user.api.js +68 -9
  160. package/lib/commonjs/networking/api-requests/user.api.js.map +1 -1
  161. package/lib/commonjs/networking/apiClient.js +62 -112
  162. package/lib/commonjs/networking/apiClient.js.map +1 -1
  163. package/lib/commonjs/networking/authRefresh.js +332 -0
  164. package/lib/commonjs/networking/authRefresh.js.map +1 -0
  165. package/lib/commonjs/networking/stanzaHandlers.js +41 -28
  166. package/lib/commonjs/networking/stanzaHandlers.js.map +1 -1
  167. package/lib/commonjs/networking/xmpp/flushLastViewedToPrivateStore.js +46 -8
  168. package/lib/commonjs/networking/xmpp/flushLastViewedToPrivateStore.js.map +1 -1
  169. package/lib/commonjs/networking/xmpp/presenceInRoom.xmpp.js +8 -1
  170. package/lib/commonjs/networking/xmpp/presenceInRoom.xmpp.js.map +1 -1
  171. package/lib/commonjs/networking/xmpp/subscribeToRoomMessages.xmpp.js +5 -1
  172. package/lib/commonjs/networking/xmpp/subscribeToRoomMessages.xmpp.js.map +1 -1
  173. package/lib/commonjs/networking/xmppClient.js +124 -8
  174. package/lib/commonjs/networking/xmppClient.js.map +1 -1
  175. package/lib/commonjs/roomStore/chatSettingsSlice.js +26 -7
  176. package/lib/commonjs/roomStore/chatSettingsSlice.js.map +1 -1
  177. package/lib/commonjs/roomStore/index.js +35 -2
  178. package/lib/commonjs/roomStore/index.js.map +1 -1
  179. package/lib/commonjs/roomStore/persistence.js +226 -23
  180. package/lib/commonjs/roomStore/persistence.js.map +1 -1
  181. package/lib/commonjs/roomStore/roomsSlice.js +151 -38
  182. package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
  183. package/lib/commonjs/services/pushSubscriptionService.js +15 -13
  184. package/lib/commonjs/services/pushSubscriptionService.js.map +1 -1
  185. package/lib/commonjs/version.js +1 -1
  186. package/lib/module/assets/icons.js +6 -1
  187. package/lib/module/assets/icons.js.map +1 -1
  188. package/lib/module/components/AuthForms/Login.js +4 -4
  189. package/lib/module/components/AuthForms/Login.js.map +1 -1
  190. package/lib/module/components/Header/HeaderRoomList.js +29 -8
  191. package/lib/module/components/Header/HeaderRoomList.js.map +1 -1
  192. package/lib/module/components/MainComponents/ChatHeader.js +9 -3
  193. package/lib/module/components/MainComponents/ChatHeader.js.map +1 -1
  194. package/lib/module/components/MainComponents/ChatRoom.js +152 -16
  195. package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
  196. package/lib/module/components/MainComponents/ChatWrapper.js +35 -14
  197. package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
  198. package/lib/module/components/MainComponents/LoginWrapper.js +2 -1
  199. package/lib/module/components/MainComponents/LoginWrapper.js.map +1 -1
  200. package/lib/module/components/MainComponents/MediaMessage.js +30 -10
  201. package/lib/module/components/MainComponents/MediaMessage.js.map +1 -1
  202. package/lib/module/components/MainComponents/MessageContainer.js +5 -1
  203. package/lib/module/components/MainComponents/MessageContainer.js.map +1 -1
  204. package/lib/module/components/MainComponents/MessageList.js +13 -5
  205. package/lib/module/components/MainComponents/MessageList.js.map +1 -1
  206. package/lib/module/components/MainComponents/ProfileImagePlaceholder.js +14 -13
  207. package/lib/module/components/MainComponents/ProfileImagePlaceholder.js.map +1 -1
  208. package/lib/module/components/MainComponents/RoomList.js +207 -35
  209. package/lib/module/components/MainComponents/RoomList.js.map +1 -1
  210. package/lib/module/components/Menu/HeaderRoomListMenu.js +319 -101
  211. package/lib/module/components/Menu/HeaderRoomListMenu.js.map +1 -1
  212. package/lib/module/components/Modals/AttachSheet/AttachSheet.js +313 -113
  213. package/lib/module/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
  214. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js +549 -207
  215. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  216. package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js +223 -0
  217. package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js.map +1 -0
  218. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +70 -28
  219. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  220. package/lib/module/components/Modals/FilePreviewModal/PdfView.js +2 -1
  221. package/lib/module/components/Modals/FilePreviewModal/PdfView.js.map +1 -1
  222. package/lib/module/components/Modals/Modal/Modal.js +9 -1
  223. package/lib/module/components/Modals/Modal/Modal.js.map +1 -1
  224. package/lib/module/components/Modals/NewChatModal/ModalContent.js +2 -1
  225. package/lib/module/components/Modals/NewChatModal/ModalContent.js.map +1 -1
  226. package/lib/module/components/Modals/NewChatModal/NewChatModal.js +205 -108
  227. package/lib/module/components/Modals/NewChatModal/NewChatModal.js.map +1 -1
  228. package/lib/module/components/Modals/NewChatModal/UpdNewChatModal.js +8 -0
  229. package/lib/module/components/Modals/NewChatModal/UpdNewChatModal.js.map +1 -1
  230. package/lib/module/components/Modals/ProfileHeader/ProfileHeader.js +555 -0
  231. package/lib/module/components/Modals/ProfileHeader/ProfileHeader.js.map +1 -0
  232. package/lib/module/components/Modals/ProfileHeader/ProfileMenu.js +205 -0
  233. package/lib/module/components/Modals/ProfileHeader/ProfileMenu.js.map +1 -0
  234. package/lib/module/components/Modals/SelectUsersModal/SelectUsersModal.js +4 -2
  235. package/lib/module/components/Modals/SelectUsersModal/SelectUsersModal.js.map +1 -1
  236. package/lib/module/components/Modals/UserProfileModal/EditUserModal.js +9 -23
  237. package/lib/module/components/Modals/UserProfileModal/EditUserModal.js.map +1 -1
  238. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js +509 -248
  239. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  240. package/lib/module/components/Modals/UserSettingsModal/UserSettingsModal.js +76 -48
  241. package/lib/module/components/Modals/UserSettingsModal/UserSettingsModal.js.map +1 -1
  242. package/lib/module/components/Modals/styledModalComponents.js +9 -2
  243. package/lib/module/components/Modals/styledModalComponents.js.map +1 -1
  244. package/lib/module/components/RoomComponents/ChatRoomItem.js +21 -7
  245. package/lib/module/components/RoomComponents/ChatRoomItem.js.map +1 -1
  246. package/lib/module/components/RoomComponents/styled/LastMessageFile.js +22 -3
  247. package/lib/module/components/RoomComponents/styled/LastMessageFile.js.map +1 -1
  248. package/lib/module/components/RoomComponents/styled/LastMessagePhoto.js +17 -3
  249. package/lib/module/components/RoomComponents/styled/LastMessagePhoto.js.map +1 -1
  250. package/lib/module/components/RoomComponents/styled/LastMessageVideo.js +17 -3
  251. package/lib/module/components/RoomComponents/styled/LastMessageVideo.js.map +1 -1
  252. package/lib/module/components/VideoCalls/VideoCallSession.js +6 -3
  253. package/lib/module/components/VideoCalls/VideoCallSession.js.map +1 -1
  254. package/lib/module/components/styled/AudioMessage.js +2 -1
  255. package/lib/module/components/styled/AudioMessage.js.map +1 -1
  256. package/lib/module/components/styled/MessageImage.js +37 -9
  257. package/lib/module/components/styled/MessageImage.js.map +1 -1
  258. package/lib/module/components/styled/SendInput.js +81 -12
  259. package/lib/module/components/styled/SendInput.js.map +1 -1
  260. package/lib/module/components/styled/StyledComponents.js +9 -3
  261. package/lib/module/components/styled/StyledComponents.js.map +1 -1
  262. package/lib/module/components/styled/StyledInputComponents/StyledInputComponents.js +11 -4
  263. package/lib/module/components/styled/StyledInputComponents/StyledInputComponents.js.map +1 -1
  264. package/lib/module/components/styled/UnsupportedType.js +14 -4
  265. package/lib/module/components/styled/UnsupportedType.js.map +1 -1
  266. package/lib/module/components/styled/VideoMessage.js +120 -62
  267. package/lib/module/components/styled/VideoMessage.js.map +1 -1
  268. package/lib/module/context/xmppProvider.js +184 -60
  269. package/lib/module/context/xmppProvider.js.map +1 -1
  270. package/lib/module/helpers/createMessageFromXml.js +19 -1
  271. package/lib/module/helpers/createMessageFromXml.js.map +1 -1
  272. package/lib/module/helpers/ensureScopedChatCache.js +2 -2
  273. package/lib/module/helpers/ensureScopedChatCache.js.map +1 -1
  274. package/lib/module/helpers/getChatBackground.js +18 -0
  275. package/lib/module/helpers/getChatBackground.js.map +1 -0
  276. package/lib/module/helpers/getDisplayFileName.js +73 -0
  277. package/lib/module/helpers/getDisplayFileName.js.map +1 -0
  278. package/lib/module/helpers/getServerReadTimestamp.js +181 -0
  279. package/lib/module/helpers/getServerReadTimestamp.js.map +1 -0
  280. package/lib/module/helpers/historyPreloadScheduler.js +66 -3
  281. package/lib/module/helpers/historyPreloadScheduler.js.map +1 -1
  282. package/lib/module/helpers/initXmppRooms.js +14 -8
  283. package/lib/module/helpers/initXmppRooms.js.map +1 -1
  284. package/lib/module/helpers/insertMessageWithDelimiter.js +52 -9
  285. package/lib/module/helpers/insertMessageWithDelimiter.js.map +1 -1
  286. package/lib/module/helpers/isOwnMessage.js +70 -0
  287. package/lib/module/helpers/isOwnMessage.js.map +1 -0
  288. package/lib/module/helpers/keyboardLayout.js +12 -2
  289. package/lib/module/helpers/keyboardLayout.js.map +1 -1
  290. package/lib/module/helpers/mediaLibraryRuntime.js +25 -0
  291. package/lib/module/helpers/mediaLibraryRuntime.js.map +1 -0
  292. package/lib/module/helpers/mimeToExtension.js +6 -13
  293. package/lib/module/helpers/mimeToExtension.js.map +1 -1
  294. package/lib/module/helpers/msgSortableMs.js +32 -0
  295. package/lib/module/helpers/msgSortableMs.js.map +1 -0
  296. package/lib/module/helpers/persistCrypto.js +115 -0
  297. package/lib/module/helpers/persistCrypto.js.map +1 -0
  298. package/lib/module/helpers/pickImageAsset.js +63 -0
  299. package/lib/module/helpers/pickImageAsset.js.map +1 -0
  300. package/lib/module/helpers/pushPayload.js +63 -0
  301. package/lib/module/helpers/pushPayload.js.map +1 -0
  302. package/lib/module/helpers/resolveInitBeforeLoadUser.js +130 -16
  303. package/lib/module/helpers/resolveInitBeforeLoadUser.js.map +1 -1
  304. package/lib/module/helpers/secureFileUrl.js +91 -0
  305. package/lib/module/helpers/secureFileUrl.js.map +1 -0
  306. package/lib/module/helpers/secureKeyValue.js +75 -0
  307. package/lib/module/helpers/secureKeyValue.js.map +1 -0
  308. package/lib/module/helpers/secureStoreRuntime.js +52 -0
  309. package/lib/module/helpers/secureStoreRuntime.js.map +1 -0
  310. package/lib/module/helpers/secureUserStorage.js +72 -0
  311. package/lib/module/helpers/secureUserStorage.js.map +1 -0
  312. package/lib/module/helpers/shallowEqual.js +31 -0
  313. package/lib/module/helpers/shallowEqual.js.map +1 -0
  314. package/lib/module/helpers/sheetGestures.js +26 -0
  315. package/lib/module/helpers/sheetGestures.js.map +1 -0
  316. package/lib/module/hooks/useChatRoomFocus.js +46 -13
  317. package/lib/module/hooks/useChatRoomFocus.js.map +1 -1
  318. package/lib/module/hooks/useChatWrapperInit.js +30 -10
  319. package/lib/module/hooks/useChatWrapperInit.js.map +1 -1
  320. package/lib/module/hooks/useComposing.js +28 -1
  321. package/lib/module/hooks/useComposing.js.map +1 -1
  322. package/lib/module/hooks/useFileToken.js +5 -0
  323. package/lib/module/hooks/useFileToken.js.map +1 -0
  324. package/lib/module/hooks/useLogout.js +23 -7
  325. package/lib/module/hooks/useLogout.js.map +1 -1
  326. package/lib/module/hooks/usePendingNotification.js +8 -11
  327. package/lib/module/hooks/usePendingNotification.js.map +1 -1
  328. package/lib/module/hooks/useSendMessage.js +52 -16
  329. package/lib/module/hooks/useSendMessage.js.map +1 -1
  330. package/lib/module/hooks/useUnreadMessagesCounter.js +6 -1
  331. package/lib/module/hooks/useUnreadMessagesCounter.js.map +1 -1
  332. package/lib/module/i18n/strings.js +145 -37
  333. package/lib/module/i18n/strings.js.map +1 -1
  334. package/lib/module/main.js +14 -2
  335. package/lib/module/main.js.map +1 -1
  336. package/lib/module/networking/api-requests/auth.api.js +131 -59
  337. package/lib/module/networking/api-requests/auth.api.js.map +1 -1
  338. package/lib/module/networking/api-requests/roomMembers.api.js +1 -1
  339. package/lib/module/networking/api-requests/roomMembers.api.js.map +1 -1
  340. package/lib/module/networking/api-requests/rooms.api.js +9 -9
  341. package/lib/module/networking/api-requests/rooms.api.js.map +1 -1
  342. package/lib/module/networking/api-requests/user.api.js +64 -7
  343. package/lib/module/networking/api-requests/user.api.js.map +1 -1
  344. package/lib/module/networking/apiClient.js +61 -113
  345. package/lib/module/networking/apiClient.js.map +1 -1
  346. package/lib/module/networking/authRefresh.js +321 -0
  347. package/lib/module/networking/authRefresh.js.map +1 -0
  348. package/lib/module/networking/stanzaHandlers.js +41 -28
  349. package/lib/module/networking/stanzaHandlers.js.map +1 -1
  350. package/lib/module/networking/xmpp/flushLastViewedToPrivateStore.js +46 -8
  351. package/lib/module/networking/xmpp/flushLastViewedToPrivateStore.js.map +1 -1
  352. package/lib/module/networking/xmpp/presenceInRoom.xmpp.js +8 -1
  353. package/lib/module/networking/xmpp/presenceInRoom.xmpp.js.map +1 -1
  354. package/lib/module/networking/xmpp/subscribeToRoomMessages.xmpp.js +5 -1
  355. package/lib/module/networking/xmpp/subscribeToRoomMessages.xmpp.js.map +1 -1
  356. package/lib/module/networking/xmppClient.js +124 -8
  357. package/lib/module/networking/xmppClient.js.map +1 -1
  358. package/lib/module/roomStore/chatSettingsSlice.js +26 -7
  359. package/lib/module/roomStore/chatSettingsSlice.js.map +1 -1
  360. package/lib/module/roomStore/index.js +37 -4
  361. package/lib/module/roomStore/index.js.map +1 -1
  362. package/lib/module/roomStore/persistence.js +223 -22
  363. package/lib/module/roomStore/persistence.js.map +1 -1
  364. package/lib/module/roomStore/roomsSlice.js +139 -34
  365. package/lib/module/roomStore/roomsSlice.js.map +1 -1
  366. package/lib/module/services/pushSubscriptionService.js +15 -13
  367. package/lib/module/services/pushSubscriptionService.js.map +1 -1
  368. package/lib/module/version.js +1 -1
  369. package/lib/typescript/assets/icons.d.ts +16 -0
  370. package/lib/typescript/assets/icons.d.ts.map +1 -1
  371. package/lib/typescript/components/AuthForms/Login.d.ts.map +1 -1
  372. package/lib/typescript/components/Header/HeaderRoomList.d.ts.map +1 -1
  373. package/lib/typescript/components/MainComponents/ChatHeader.d.ts.map +1 -1
  374. package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
  375. package/lib/typescript/components/MainComponents/ChatWrapper.d.ts.map +1 -1
  376. package/lib/typescript/components/MainComponents/LoginWrapper.d.ts.map +1 -1
  377. package/lib/typescript/components/MainComponents/MediaMessage.d.ts.map +1 -1
  378. package/lib/typescript/components/MainComponents/MessageContainer.d.ts.map +1 -1
  379. package/lib/typescript/components/MainComponents/MessageList.d.ts +10 -1
  380. package/lib/typescript/components/MainComponents/MessageList.d.ts.map +1 -1
  381. package/lib/typescript/components/MainComponents/ProfileImagePlaceholder.d.ts.map +1 -1
  382. package/lib/typescript/components/MainComponents/RoomList.d.ts +7 -0
  383. package/lib/typescript/components/MainComponents/RoomList.d.ts.map +1 -1
  384. package/lib/typescript/components/Menu/HeaderRoomListMenu.d.ts +3 -0
  385. package/lib/typescript/components/Menu/HeaderRoomListMenu.d.ts.map +1 -1
  386. package/lib/typescript/components/Modals/AttachSheet/AttachSheet.d.ts +9 -0
  387. package/lib/typescript/components/Modals/AttachSheet/AttachSheet.d.ts.map +1 -1
  388. package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts +10 -0
  389. package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts.map +1 -1
  390. package/lib/typescript/components/Modals/ChatProfileModal/ReportChatModal.d.ts +9 -0
  391. package/lib/typescript/components/Modals/ChatProfileModal/ReportChatModal.d.ts.map +1 -0
  392. package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts.map +1 -1
  393. package/lib/typescript/components/Modals/FilePreviewModal/PdfView.d.ts.map +1 -1
  394. package/lib/typescript/components/Modals/Modal/Modal.d.ts.map +1 -1
  395. package/lib/typescript/components/Modals/NewChatModal/ModalContent.d.ts +4 -2
  396. package/lib/typescript/components/Modals/NewChatModal/ModalContent.d.ts.map +1 -1
  397. package/lib/typescript/components/Modals/NewChatModal/NewChatModal.d.ts +1 -1
  398. package/lib/typescript/components/Modals/NewChatModal/NewChatModal.d.ts.map +1 -1
  399. package/lib/typescript/components/Modals/NewChatModal/UpdNewChatModal.d.ts.map +1 -1
  400. package/lib/typescript/components/Modals/ProfileHeader/ProfileHeader.d.ts +75 -0
  401. package/lib/typescript/components/Modals/ProfileHeader/ProfileHeader.d.ts.map +1 -0
  402. package/lib/typescript/components/Modals/ProfileHeader/ProfileMenu.d.ts +25 -0
  403. package/lib/typescript/components/Modals/ProfileHeader/ProfileMenu.d.ts.map +1 -0
  404. package/lib/typescript/components/Modals/SelectUsersModal/SelectUsersModal.d.ts +6 -1
  405. package/lib/typescript/components/Modals/SelectUsersModal/SelectUsersModal.d.ts.map +1 -1
  406. package/lib/typescript/components/Modals/UserProfileModal/EditUserModal.d.ts.map +1 -1
  407. package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts +16 -0
  408. package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts.map +1 -1
  409. package/lib/typescript/components/Modals/UserSettingsModal/UserSettingsModal.d.ts +1 -0
  410. package/lib/typescript/components/Modals/UserSettingsModal/UserSettingsModal.d.ts.map +1 -1
  411. package/lib/typescript/components/Modals/styledModalComponents.d.ts.map +1 -1
  412. package/lib/typescript/components/RoomComponents/ChatRoomItem.d.ts.map +1 -1
  413. package/lib/typescript/components/RoomComponents/styled/LastMessageFile.d.ts +1 -1
  414. package/lib/typescript/components/RoomComponents/styled/LastMessageFile.d.ts.map +1 -1
  415. package/lib/typescript/components/RoomComponents/styled/LastMessagePhoto.d.ts +1 -1
  416. package/lib/typescript/components/RoomComponents/styled/LastMessagePhoto.d.ts.map +1 -1
  417. package/lib/typescript/components/RoomComponents/styled/LastMessageVideo.d.ts +1 -1
  418. package/lib/typescript/components/RoomComponents/styled/LastMessageVideo.d.ts.map +1 -1
  419. package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts.map +1 -1
  420. package/lib/typescript/components/styled/AudioMessage.d.ts.map +1 -1
  421. package/lib/typescript/components/styled/MessageImage.d.ts +14 -0
  422. package/lib/typescript/components/styled/MessageImage.d.ts.map +1 -1
  423. package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
  424. package/lib/typescript/components/styled/StyledComponents.d.ts.map +1 -1
  425. package/lib/typescript/components/styled/StyledInputComponents/StyledInputComponents.d.ts.map +1 -1
  426. package/lib/typescript/components/styled/UnsupportedType.d.ts.map +1 -1
  427. package/lib/typescript/components/styled/VideoMessage.d.ts +8 -0
  428. package/lib/typescript/components/styled/VideoMessage.d.ts.map +1 -1
  429. package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
  430. package/lib/typescript/helpers/createMessageFromXml.d.ts.map +1 -1
  431. package/lib/typescript/helpers/getChatBackground.d.ts +15 -0
  432. package/lib/typescript/helpers/getChatBackground.d.ts.map +1 -0
  433. package/lib/typescript/helpers/getDisplayFileName.d.ts +49 -0
  434. package/lib/typescript/helpers/getDisplayFileName.d.ts.map +1 -0
  435. package/lib/typescript/helpers/getServerReadTimestamp.d.ts +108 -0
  436. package/lib/typescript/helpers/getServerReadTimestamp.d.ts.map +1 -0
  437. package/lib/typescript/helpers/historyPreloadScheduler.d.ts.map +1 -1
  438. package/lib/typescript/helpers/initXmppRooms.d.ts.map +1 -1
  439. package/lib/typescript/helpers/insertMessageWithDelimiter.d.ts +1 -1
  440. package/lib/typescript/helpers/insertMessageWithDelimiter.d.ts.map +1 -1
  441. package/lib/typescript/helpers/isOwnMessage.d.ts +36 -0
  442. package/lib/typescript/helpers/isOwnMessage.d.ts.map +1 -0
  443. package/lib/typescript/helpers/keyboardLayout.d.ts +5 -1
  444. package/lib/typescript/helpers/keyboardLayout.d.ts.map +1 -1
  445. package/lib/typescript/helpers/mediaLibraryRuntime.d.ts +3 -0
  446. package/lib/typescript/helpers/mediaLibraryRuntime.d.ts.map +1 -0
  447. package/lib/typescript/helpers/mimeToExtension.d.ts +0 -15
  448. package/lib/typescript/helpers/mimeToExtension.d.ts.map +1 -1
  449. package/lib/typescript/helpers/msgSortableMs.d.ts +2 -0
  450. package/lib/typescript/helpers/msgSortableMs.d.ts.map +1 -0
  451. package/lib/typescript/helpers/persistCrypto.d.ts +13 -0
  452. package/lib/typescript/helpers/persistCrypto.d.ts.map +1 -0
  453. package/lib/typescript/helpers/pickImageAsset.d.ts +27 -0
  454. package/lib/typescript/helpers/pickImageAsset.d.ts.map +1 -0
  455. package/lib/typescript/helpers/pushPayload.d.ts +7 -0
  456. package/lib/typescript/helpers/pushPayload.d.ts.map +1 -0
  457. package/lib/typescript/helpers/resolveInitBeforeLoadUser.d.ts.map +1 -1
  458. package/lib/typescript/helpers/secureFileUrl.d.ts +7 -0
  459. package/lib/typescript/helpers/secureFileUrl.d.ts.map +1 -0
  460. package/lib/typescript/helpers/secureKeyValue.d.ts +13 -0
  461. package/lib/typescript/helpers/secureKeyValue.d.ts.map +1 -0
  462. package/lib/typescript/helpers/secureStoreRuntime.d.ts +29 -0
  463. package/lib/typescript/helpers/secureStoreRuntime.d.ts.map +1 -0
  464. package/lib/typescript/helpers/secureUserStorage.d.ts +23 -0
  465. package/lib/typescript/helpers/secureUserStorage.d.ts.map +1 -0
  466. package/lib/typescript/helpers/shallowEqual.d.ts +11 -0
  467. package/lib/typescript/helpers/shallowEqual.d.ts.map +1 -0
  468. package/lib/typescript/helpers/sheetGestures.d.ts +20 -0
  469. package/lib/typescript/helpers/sheetGestures.d.ts.map +1 -0
  470. package/lib/typescript/hooks/useChatRoomFocus.d.ts +4 -1
  471. package/lib/typescript/hooks/useChatRoomFocus.d.ts.map +1 -1
  472. package/lib/typescript/hooks/useChatWrapperInit.d.ts.map +1 -1
  473. package/lib/typescript/hooks/useComposing.d.ts.map +1 -1
  474. package/lib/typescript/hooks/useFileToken.d.ts +2 -0
  475. package/lib/typescript/hooks/useFileToken.d.ts.map +1 -0
  476. package/lib/typescript/hooks/useLogout.d.ts.map +1 -1
  477. package/lib/typescript/hooks/usePendingNotification.d.ts.map +1 -1
  478. package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
  479. package/lib/typescript/hooks/useUnreadMessagesCounter.d.ts +1 -0
  480. package/lib/typescript/hooks/useUnreadMessagesCounter.d.ts.map +1 -1
  481. package/lib/typescript/i18n/strings.d.ts.map +1 -1
  482. package/lib/typescript/main.d.ts +9 -2
  483. package/lib/typescript/main.d.ts.map +1 -1
  484. package/lib/typescript/networking/api-requests/auth.api.d.ts +3 -1
  485. package/lib/typescript/networking/api-requests/auth.api.d.ts.map +1 -1
  486. package/lib/typescript/networking/api-requests/user.api.d.ts +27 -0
  487. package/lib/typescript/networking/api-requests/user.api.d.ts.map +1 -1
  488. package/lib/typescript/networking/apiClient.d.ts +12 -6
  489. package/lib/typescript/networking/apiClient.d.ts.map +1 -1
  490. package/lib/typescript/networking/authRefresh.d.ts +95 -0
  491. package/lib/typescript/networking/authRefresh.d.ts.map +1 -0
  492. package/lib/typescript/networking/stanzaHandlers.d.ts.map +1 -1
  493. package/lib/typescript/networking/xmpp/flushLastViewedToPrivateStore.d.ts +10 -2
  494. package/lib/typescript/networking/xmpp/flushLastViewedToPrivateStore.d.ts.map +1 -1
  495. package/lib/typescript/networking/xmpp/presenceInRoom.xmpp.d.ts.map +1 -1
  496. package/lib/typescript/networking/xmpp/subscribeToRoomMessages.xmpp.d.ts.map +1 -1
  497. package/lib/typescript/networking/xmppClient.d.ts +14 -0
  498. package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
  499. package/lib/typescript/roomStore/chatSettingsSlice.d.ts +16 -0
  500. package/lib/typescript/roomStore/chatSettingsSlice.d.ts.map +1 -1
  501. package/lib/typescript/roomStore/index.d.ts.map +1 -1
  502. package/lib/typescript/roomStore/persistence.d.ts +18 -1
  503. package/lib/typescript/roomStore/persistence.d.ts.map +1 -1
  504. package/lib/typescript/roomStore/roomsSlice.d.ts +43 -3
  505. package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
  506. package/lib/typescript/services/pushSubscriptionService.d.ts +1 -1
  507. package/lib/typescript/services/pushSubscriptionService.d.ts.map +1 -1
  508. package/lib/typescript/types/types.d.ts +50 -5
  509. package/lib/typescript/types/types.d.ts.map +1 -1
  510. package/lib/typescript/version.d.ts +1 -1
  511. package/package.json +41 -28
  512. package/src/assets/icons.tsx +48 -9
  513. package/src/components/AuthForms/Login.tsx +3 -3
  514. package/src/components/Header/HeaderRoomList.tsx +29 -7
  515. package/src/components/MainComponents/ChatHeader.tsx +9 -3
  516. package/src/components/MainComponents/ChatRoom.tsx +161 -15
  517. package/src/components/MainComponents/ChatWrapper.tsx +36 -20
  518. package/src/components/MainComponents/LoginWrapper.tsx +1 -0
  519. package/src/components/MainComponents/MediaMessage.tsx +26 -8
  520. package/src/components/MainComponents/MessageContainer.tsx +5 -1
  521. package/src/components/MainComponents/MessageList.tsx +23 -4
  522. package/src/components/MainComponents/ProfileImagePlaceholder.tsx +21 -14
  523. package/src/components/MainComponents/RoomList.tsx +236 -39
  524. package/src/components/Menu/HeaderRoomListMenu.tsx +328 -75
  525. package/src/components/Modals/AttachSheet/AttachSheet.tsx +333 -97
  526. package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +600 -282
  527. package/src/components/Modals/ChatProfileModal/ReportChatModal.tsx +244 -0
  528. package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +79 -38
  529. package/src/components/Modals/FilePreviewModal/PdfView.tsx +2 -1
  530. package/src/components/Modals/Modal/Modal.tsx +7 -0
  531. package/src/components/Modals/NewChatModal/ModalContent.tsx +6 -3
  532. package/src/components/Modals/NewChatModal/NewChatModal.tsx +219 -119
  533. package/src/components/Modals/NewChatModal/UpdNewChatModal.tsx +12 -1
  534. package/src/components/Modals/ProfileHeader/ProfileHeader.tsx +624 -0
  535. package/src/components/Modals/ProfileHeader/ProfileMenu.tsx +217 -0
  536. package/src/components/Modals/SelectUsersModal/SelectUsersModal.tsx +14 -4
  537. package/src/components/Modals/UserProfileModal/EditUserModal.tsx +9 -25
  538. package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +617 -307
  539. package/src/components/Modals/UserSettingsModal/UserSettingsModal.tsx +75 -58
  540. package/src/components/Modals/styledModalComponents.tsx +9 -2
  541. package/src/components/RoomComponents/ChatRoomItem.tsx +18 -3
  542. package/src/components/RoomComponents/styled/LastMessageFile.tsx +28 -4
  543. package/src/components/RoomComponents/styled/LastMessagePhoto.tsx +18 -3
  544. package/src/components/RoomComponents/styled/LastMessageVideo.tsx +18 -3
  545. package/src/components/VideoCalls/VideoCallSession.tsx +8 -3
  546. package/src/components/styled/AudioMessage.tsx +2 -1
  547. package/src/components/styled/MessageImage.tsx +53 -7
  548. package/src/components/styled/SendInput.tsx +83 -12
  549. package/src/components/styled/StyledComponents.ts +9 -3
  550. package/src/components/styled/StyledInputComponents/StyledInputComponents.tsx +11 -4
  551. package/src/components/styled/UnsupportedType.tsx +14 -4
  552. package/src/components/styled/VideoMessage.tsx +131 -54
  553. package/src/context/xmppProvider.tsx +216 -57
  554. package/src/helpers/createMessageFromXml.ts +20 -1
  555. package/src/helpers/ensureScopedChatCache.ts +2 -2
  556. package/src/helpers/getChatBackground.ts +18 -0
  557. package/src/helpers/getDisplayFileName.ts +87 -0
  558. package/src/helpers/getServerReadTimestamp.ts +197 -0
  559. package/src/helpers/historyPreloadScheduler.ts +80 -3
  560. package/src/helpers/initXmppRooms.tsx +14 -10
  561. package/src/helpers/insertMessageWithDelimiter.ts +55 -19
  562. package/src/helpers/isOwnMessage.ts +90 -0
  563. package/src/helpers/keyboardLayout.ts +23 -2
  564. package/src/helpers/mediaLibraryRuntime.ts +25 -0
  565. package/src/helpers/mimeToExtension.ts +6 -22
  566. package/src/helpers/msgSortableMs.ts +25 -0
  567. package/src/helpers/persistCrypto.ts +127 -0
  568. package/src/helpers/pickImageAsset.ts +68 -0
  569. package/src/helpers/pushPayload.ts +62 -0
  570. package/src/helpers/resolveInitBeforeLoadUser.ts +125 -18
  571. package/src/helpers/secureFileUrl.ts +103 -0
  572. package/src/helpers/secureKeyValue.ts +80 -0
  573. package/src/helpers/secureStoreRuntime.ts +62 -0
  574. package/src/helpers/secureUserStorage.ts +80 -0
  575. package/src/helpers/shallowEqual.ts +33 -0
  576. package/src/helpers/sheetGestures.ts +25 -0
  577. package/src/hooks/useChatRoomFocus.ts +49 -9
  578. package/src/hooks/useChatWrapperInit.ts +30 -10
  579. package/src/hooks/useComposing.tsx +37 -1
  580. package/src/hooks/useFileToken.ts +7 -0
  581. package/src/hooks/useLogout.tsx +29 -9
  582. package/src/hooks/usePendingNotification.ts +5 -11
  583. package/src/hooks/useSendMessage.tsx +60 -15
  584. package/src/hooks/useUnreadMessagesCounter.ts +11 -0
  585. package/src/i18n/strings.ts +145 -37
  586. package/src/main.ts +26 -2
  587. package/src/networking/api-requests/auth.api.ts +156 -48
  588. package/src/networking/api-requests/roomMembers.api.ts +1 -1
  589. package/src/networking/api-requests/rooms.api.ts +9 -9
  590. package/src/networking/api-requests/user.api.ts +79 -7
  591. package/src/networking/apiClient.ts +68 -123
  592. package/src/networking/authRefresh.ts +451 -0
  593. package/src/networking/stanzaHandlers.ts +44 -28
  594. package/src/networking/xmpp/flushLastViewedToPrivateStore.ts +71 -10
  595. package/src/networking/xmpp/presenceInRoom.xmpp.ts +6 -1
  596. package/src/networking/xmpp/subscribeToRoomMessages.xmpp.ts +12 -1
  597. package/src/networking/xmppClient.ts +141 -9
  598. package/src/roomStore/chatSettingsSlice.ts +34 -10
  599. package/src/roomStore/index.ts +40 -4
  600. package/src/roomStore/persistence.ts +234 -24
  601. package/src/roomStore/roomsSlice.ts +161 -29
  602. package/src/services/pushSubscriptionService.ts +18 -13
  603. package/src/types/types.ts +72 -5
  604. package/src/version.ts +1 -1
@@ -8,9 +8,8 @@ import {
8
8
  setComposing,
9
9
  setCurrentRoom,
10
10
  setRoomRole,
11
- updateRoom,
12
11
  } from '../roomStore/roomsSlice';
13
- import { IRoom, RoomMember } from '../types/types';
12
+ import { IRoom } from '../types/types';
14
13
  import { createMessageFromXml } from '../helpers/createMessageFromXml';
15
14
  import { getDataFromXml } from '../helpers/getDataFromXml';
16
15
  import { setDeleteModal } from '../roomStore/chatSettingsSlice';
@@ -238,11 +237,11 @@ const onMessageHistory = async (stanza: any) => {
238
237
  // what senderJID would have held — fall back to it. createMessageFromXml
239
238
  // already derives a display name from the jid when senderFirstName/
240
239
  // senderLastName are absent.
241
- const innerFrom =
242
- stanza
243
- .getChild('result')
244
- ?.getChild('forwarded')
245
- ?.getChild('message')?.attrs?.from || stanza.attrs.from;
240
+ const forwardedMessage = stanza
241
+ .getChild('result')
242
+ ?.getChild('forwarded')
243
+ ?.getChild('message');
244
+ const innerFrom = forwardedMessage?.attrs?.from || stanza.attrs.from;
246
245
  const senderJID = data?.attrs?.senderJID || innerFrom;
247
246
  if (!data?.attrs || !senderJID) {
248
247
  // console.log(
@@ -251,27 +250,44 @@ const onMessageHistory = async (stanza: any) => {
251
250
  // );
252
251
  return;
253
252
  }
254
- // Parse the FULL stanza the same way the realtime path does (and the
255
- // web SDK's history path does): the positional call used here before
256
- // read only <data> attrs + <body>, so the <translations> payload and
257
- // the <translate source> tag never made it onto archived messages.
258
- // Since every transcript is MAM-backfilled on room open, that alone
259
- // made translation look completely dead — the translations existed on
260
- // the wire and were dropped at this exact parse. getDataFromXml also
261
- // supplies xmppId (dedupe against the optimistic copy) and the
262
- // resource||senderJID-localpart sender id.
263
- const parsed = await getDataFromXml(stanza);
264
- const { data: pData, id: pId, body: pBody, ...pRest } =
265
- parsed ?? ({} as Partial<NonNullable<typeof parsed>>);
266
- const mergedData: Record<string, unknown> = { ...(pData || data.attrs) };
267
- if (!mergedData.senderJID) {mergedData.senderJID = senderJID;}
268
- const rawMessage = await createMessageFromXml({
269
- data: mergedData,
270
- id: pId || id,
271
- body: pBody ?? (typeof body === 'string' ? body : body?.getText?.() || ''),
272
- ...pRest,
273
- isDeleted: !!deleted || !!pRest?.deleted,
274
- } as Parameters<typeof createMessageFromXml>[0]);
253
+ const mergedAttrs = { ...data.attrs };
254
+ if (!mergedAttrs.senderJID) {mergedAttrs.senderJID = senderJID;}
255
+ // The forwarded <message>'s own stanza id is our original send id
256
+ // (what `xmppId` holds on the live/wrapped paths) - capture it so
257
+ // this MAM-replayed message dedupes against its live echo /
258
+ // optimistic pending bubble the same way, instead of never carrying
259
+ // an xmppId at all.
260
+ if (forwardedMessage?.attrs?.id) {mergedAttrs.xmppId = forwardedMessage.attrs.id;}
261
+ const positionalMessage = await createMessageFromXml(
262
+ mergedAttrs,
263
+ body,
264
+ id,
265
+ // Bug #41: pass the resource-bearing occupant `from`
266
+ // (room@conference/sender-id) here, not the outer envelope's
267
+ // `stanza.attrs.from` (which has no resource for a MAM result).
268
+ // createMessageFromXml derives `user.id` from this field's
269
+ // resource - the same authoritative source getDataFromXml uses
270
+ // for live messages - so catch-up rows resolve the correct
271
+ // sender from the very first render instead of needing a later
272
+ // correction once the "official" history fetch lands.
273
+ innerFrom,
274
+ !!deleted
275
+ );
276
+
277
+ // Translations ride on the archived stanza too (<translations> +
278
+ // <translate source>), but the positional parse above only reads
279
+ // <data> attrs + <body>, so every MAM-backfilled message lost them -
280
+ // translation looked dead on every room open. Parse the full stanza
281
+ // the way the realtime path does and carry ONLY those two fields over,
282
+ // so sender/xmppId resolution above (bug #41) stays exactly as is.
283
+ const parsedFull = await getDataFromXml(stanza).catch(() => undefined);
284
+ const rawMessage = {
285
+ ...positionalMessage,
286
+ ...(parsedFull?.translations
287
+ ? { translations: parsedFull.translations }
288
+ : {}),
289
+ ...(parsedFull?.langSource ? { langSource: parsedFull.langSource } : {}),
290
+ };
275
291
 
276
292
  // Same call-log transform as the realtime path, applied to archived
277
293
  // history so calls received while offline still render as log entries.
@@ -1,21 +1,45 @@
1
1
  import { getChatsPrivateStoreRequest } from './getChatsPrivateStoreRequest.xmpp';
2
2
  import { setChatsPrivateStoreRequest } from './setChatsPrivateStoreRequest.xmpp';
3
+ import {
4
+ getServerReadTimestamp,
5
+ isCorruptFutureReadMarker,
6
+ type ReadTimestampHeapState,
7
+ } from '../../helpers/getServerReadTimestamp';
8
+ import type { IMessage } from '../../types/types';
3
9
 
4
10
  interface RoomLike {
5
11
  jid: string;
6
12
  lastViewedTimestamp?: number;
7
13
  unreadMessages?: number;
14
+ // Needed to resolve a SERVER-timestamp read marker via
15
+ // getServerReadTimestamp instead of the device clock - see bug #38.
16
+ messages?: IMessage[];
8
17
  }
9
18
 
10
19
  interface FlushOpts {
11
20
  // When visibleRoomJID is set, treat it as "user just viewed everything
12
- // up to now" and stamp it with Date.now() — even if its in-memory
13
- // lastViewedTimestamp has not been updated yet.
21
+ // up to now" and stamp it with the newest server-acknowledged message
22
+ // timestamp for that room - even if its in-memory lastViewedTimestamp
23
+ // has not been updated yet.
14
24
  visibleRoomJID?: string | null;
25
+ // Explicit read boundary for the visible room, used INSTEAD of the
26
+ // newest-message fallback. ChatRoom passes the timestamp of the newest
27
+ // message the user actually reached when they leave a room while
28
+ // scrolled up - without it, the default writes "read everything" to
29
+ // the server and the messages they never scrolled down to come back as
30
+ // read on the next login, even though the local count was correct.
31
+ // Customer-reported #33 (server half).
32
+ visibleRoomTs?: number | null;
15
33
  // If true, only write entries for rooms where unreadMessages === 0
16
34
  // (or the visible room). Used at logout time: rooms with outstanding
17
35
  // unread keep their old marker so the next login still surfaces them.
18
36
  onlyIfNoUnread?: boolean;
37
+ // Pending/failed-send state (store.getState().roomHeapSlice), combined
38
+ // with each room's `messages` to resolve the newest SERVER-acked
39
+ // message timestamp via getServerReadTimestamp. Passed in rather than
40
+ // read from the store here so this module stays a pure function of its
41
+ // arguments - existing jest coverage builds `rooms` by hand.
42
+ heapState?: ReadTimestampHeapState;
19
43
  }
20
44
 
21
45
  /**
@@ -25,8 +49,11 @@ interface FlushOpts {
25
49
  * each other's entries.
26
50
  *
27
51
  * Called on: tab change away from chat, AppState background/inactive,
28
- * and (with onlyIfNoUnread=true) logout. ChatRoom's own unmount path
29
- * still uses actionSetTimestampToPrivateStore for the single-room case.
52
+ * and (with onlyIfNoUnread=true) logout. ChatRoom's own unmount path also
53
+ * goes through this (via flushLastViewedToPrivateStoreStanza) for the
54
+ * single-room case - actionSetTimestampToPrivateStore is a separate,
55
+ * unconditional low-level write primitive kept for direct/external use
56
+ * and is not part of this merge path.
30
57
  */
31
58
  export async function flushLastViewedToPrivateStore(
32
59
  client: any,
@@ -34,7 +61,7 @@ export async function flushLastViewedToPrivateStore(
34
61
  opts: FlushOpts = {}
35
62
  ): Promise<boolean> {
36
63
  if (!client?.client) {return false;}
37
- const { visibleRoomJID, onlyIfNoUnread } = opts;
64
+ const { visibleRoomJID, visibleRoomTs, onlyIfNoUnread, heapState } = opts;
38
65
  const roomList = Object.values(rooms || {});
39
66
  if (roomList.length === 0) {return false;}
40
67
 
@@ -46,7 +73,6 @@ export async function flushLastViewedToPrivateStore(
46
73
  }
47
74
  if (!storeObj || typeof storeObj !== 'object') {storeObj = {};}
48
75
 
49
- const nowMs = Date.now();
50
76
  let dirty = false;
51
77
 
52
78
  for (const room of roomList) {
@@ -54,21 +80,56 @@ export async function flushLastViewedToPrivateStore(
54
80
  const isVisible = !!visibleRoomJID && room.jid === visibleRoomJID;
55
81
  const hasUnread = Number(room.unreadMessages || 0) > 0;
56
82
 
57
- // For the visible room, persist "now" — read state is driven by
58
- // room visibility, not by a sentinel timestamp.
83
+ // Newest message this room actually has server-side proof of. Used
84
+ // both as the "read up to now" fallback for the visible room and as
85
+ // the yardstick for detecting a corrupt (future) stored marker below
86
+ // - never as a substitute for the device clock (bug #38: a device
87
+ // with a fast clock previously stamped Date.now() here, and once
88
+ // that future value reached the server the forward-only check a few
89
+ // lines down rejected every later correct write, forever).
90
+ const newestAckedMs = getServerReadTimestamp(room as any, heapState);
91
+
92
+ // For the visible room, persist "read up to the newest message we
93
+ // know the server has" - read state is driven by room visibility,
94
+ // not by a sentinel timestamp. The exception is an explicit
95
+ // `visibleRoomTs`: the caller knows the user only read up to a
96
+ // certain point (left the room while scrolled up), so stamping
97
+ // "everything" here would mark genuinely-unread messages as read.
59
98
  let ts: number | undefined;
60
99
  if (isVisible) {
61
- ts = nowMs;
100
+ ts =
101
+ typeof visibleRoomTs === 'number' && visibleRoomTs > 0
102
+ ? visibleRoomTs
103
+ : newestAckedMs || undefined;
62
104
  } else if (room.lastViewedTimestamp && room.lastViewedTimestamp > 0) {
63
105
  ts = room.lastViewedTimestamp;
64
106
  }
65
107
 
108
+ // Nothing to anchor a write to (no boundary, no existing marker, no
109
+ // known messages yet) - skip rather than write a device-clock guess.
66
110
  if (!ts) {continue;}
67
111
  if (onlyIfNoUnread && hasUnread && !isVisible) {continue;}
68
112
 
69
113
  const prev = storeObj[room.jid];
70
114
  const prevNum = prev != null ? Number(prev) : 0;
71
- if (Number.isFinite(prevNum) && prevNum >= ts) {continue;}
115
+ // A currently-stored value that sits well past the newest message we
116
+ // know this room has is not "fresher" - it's a leftover future
117
+ // marker (bug #38). Forward-only logic normally protects a fresher
118
+ // read from being clobbered by a stale fetch, but applied to a
119
+ // corrupt future value it does the opposite: it permanently blocks
120
+ // the correct (smaller) value from ever landing. Detect that case
121
+ // and waive the forward-only check for it specifically; sane values
122
+ // keep the normal forward-only protection.
123
+ //
124
+ // "Well past the newest message we know about" is deliberately NOT
125
+ // sufficient on its own - see isCorruptFutureReadMarker. THIS device's
126
+ // copy of the room can simply be stale (history not synced yet this
127
+ // session), in which case a legitimate marker written by another
128
+ // device that HAS seen newer messages looks exactly like a corrupt
129
+ // one, and "healing" it here would push the server marker BACKWARDS
130
+ // and resurrect already-read messages on every device.
131
+ const prevLooksCorrupt = isCorruptFutureReadMarker(prevNum, newestAckedMs);
132
+ if (!prevLooksCorrupt && Number.isFinite(prevNum) && prevNum >= ts) {continue;}
72
133
  storeObj[room.jid] = String(ts);
73
134
  dirty = true;
74
135
  }
@@ -70,7 +70,12 @@ export const presenceInRoom = async (
70
70
  try {
71
71
  await createTimeoutPromise(2000, unsubscribe);
72
72
  } catch (err) {
73
- reject(err);
73
+ // The room's reply schedules resolve() `delay` ms later (2000 by
74
+ // default) — the same length as this timeout, so the timeout used
75
+ // to win the race and reject a join that had actually succeeded
76
+ // (allRoomPresences "failed" with undefined on every bootstrap).
77
+ // Only a join that never got an answer is a failure.
78
+ if (!settled) {reject(err);}
74
79
  }
75
80
  })();
76
81
  });
@@ -2,12 +2,14 @@ import { Client, xml } from '@xmpp/client';
2
2
  import { Element } from '@xmpp/xml';
3
3
  import { createTimeoutPromise } from './createTimeoutPromise.xmpp';
4
4
 
5
+ let subscribeIdCounter = 0;
6
+
5
7
  export async function subscribeToRoomMessages(
6
8
  client: Client,
7
9
  roomJID: string,
8
10
  userNick?: string
9
11
  ): Promise<boolean> {
10
- const id = `newSubscription:${Date.now().toString()}`;
12
+ const id = `newSubscription:${Date.now().toString(36)}-${(++subscribeIdCounter).toString(36)}`;
11
13
  let stanzaHandler: (stanza: Element) => void;
12
14
 
13
15
  const unsubscribe = () => {
@@ -33,6 +35,15 @@ export async function subscribeToRoomMessages(
33
35
  if (stanza.attrs.type === 'result') {
34
36
  finish(resolve, true);
35
37
  } else if (stanza.attrs.type === 'error') {
38
+ const errorEl = typeof stanza.getChild === 'function' ? stanza.getChild('error') : null;
39
+ const condition = errorEl?.children?.find(
40
+ (c: any) => c?.name && c.name !== 'text'
41
+ ) as Element | undefined;
42
+ console.warn(
43
+ '[PushService] MucSub subscribe error for',
44
+ roomJID,
45
+ condition?.name ?? 'unknown'
46
+ );
36
47
  finish(resolve, false);
37
48
  }
38
49
  }
@@ -32,6 +32,10 @@ import {
32
32
  enqueueOutboundSend,
33
33
  flushOutboundSends,
34
34
  } from './outboundQueue';
35
+ import {
36
+ getServerReadTimestamp,
37
+ isCorruptFutureReadMarker,
38
+ } from '../helpers/getServerReadTimestamp';
35
39
 
36
40
  // Canonical production XMPP WSS endpoint (standard wss/443, no port suffix).
37
41
  const DEFAULT_DEV_SERVER = 'xmpp.chat.ethora.com';
@@ -94,6 +98,13 @@ interface MamInFlightEntry {
94
98
  startedAt: number;
95
99
  }
96
100
 
101
+ /**
102
+ * Floor between two credential rotations driven by reconnects. Well under
103
+ * the XMPP password's one-hour life, but high enough that a link flapping
104
+ * every few seconds rotates once, not thirty times.
105
+ */
106
+ const CREDENTIALS_REFRESH_MIN_INTERVAL_MS = 60_000;
107
+
97
108
  export type XmppCredentialsProvider = () => Promise<{
98
109
  username: string;
99
110
  password: string;
@@ -137,6 +148,12 @@ export class XmppClient {
137
148
  // derived XMPP password after idle). Triggers the credentialsProvider
138
149
  // refresh path in reconnect().
139
150
  lastAuthError: 'not-authorized' | null = null;
151
+ /**
152
+ * When the credentials currently held were last (re)minted. Drives the
153
+ * throttle in `reconnect()` so a flapping connection can't rotate the
154
+ * session once per flap.
155
+ */
156
+ private credentialsRefreshedAt = 0;
140
157
  private credentialsProvider: XmppCredentialsProvider | null = null;
141
158
  private credentialsRefreshInFlight: Promise<void> | null = null;
142
159
  // Fired by the provider on every 'online' so it can re-join MUC rooms
@@ -329,6 +346,7 @@ export class XmppClient {
329
346
  }
330
347
 
331
348
  initializeClient() {
349
+ this.clientAlreadyStopped = false;
332
350
  try {
333
351
  const devServer = this.devServer || DEFAULT_DEV_SERVER;
334
352
  const url = `wss://${devServer}/ws`;
@@ -700,14 +718,32 @@ export class XmppClient {
700
718
  console.log('Attempting to reconnect xmpp client...');
701
719
 
702
720
  try {
703
- // If the last failure was a SASL `not-authorized` (typically a stale
704
- // JWT-derived XMPP password after idle), try to fetch fresh creds
705
- // before retrying. Without this, reconnect retries with the same
706
- // stale password forever and the user has to kill the app.
707
- if (this.lastAuthError === 'not-authorized' && this.credentialsProvider) {
721
+ // Re-mint credentials BEFORE reconnecting.
722
+ //
723
+ // This deliberately no longer waits for a SASL `not-authorized`.
724
+ // The XMPP password expires after an hour, and an expiry does NOT
725
+ // drop an established connection — authentication happens once, at
726
+ // bind. So by the time anything disconnects us (a network blip, a
727
+ // sleeping device, a server restart) the password we still hold may
728
+ // well be dead, and we have no way to know. Reconnecting with it
729
+ // burns a guaranteed-failed bind plus a backoff delay before the
730
+ // old `lastAuthError` path could even start recovering.
731
+ //
732
+ // Throttled, because reconnects are not rare: a flapping link would
733
+ // otherwise rotate the whole session (access + refresh + file token
734
+ // + XMPP password) once per flap. A SASL failure bypasses the
735
+ // throttle — there the credentials are known bad.
736
+ const authFailed = this.lastAuthError === 'not-authorized';
737
+ const staleCreds =
738
+ Date.now() - this.credentialsRefreshedAt >=
739
+ CREDENTIALS_REFRESH_MIN_INTERVAL_MS;
740
+
741
+ if (this.credentialsProvider && (authFailed || staleCreds)) {
708
742
  try {
709
743
  await this.refreshCredentialsOnce();
710
744
  } catch (err) {
745
+ // Offline is the common case here — reconnect with what we
746
+ // have and let the next attempt try again.
711
747
  console.warn(
712
748
  'XMPP credential refresh failed; reconnecting with cached creds',
713
749
  err
@@ -721,7 +757,10 @@ export class XmppClient {
721
757
  // `this.client` still points at the old client — i.e. before
722
758
  // initializeClient() reassigns it.
723
759
  const old = this.client;
724
- if (old) {
760
+ if (old && this.clientAlreadyStopped) {
761
+ this.detachEventListeners();
762
+ this.clientAlreadyStopped = false;
763
+ } else if (old) {
725
764
  this.detachEventListeners();
726
765
  // NEVER await a bare stop(): on a half-dead socket (the exact case
727
766
  // we're reconnecting for) @xmpp/client's stop() can hang forever
@@ -736,6 +775,9 @@ export class XmppClient {
736
775
  await withTimeout(old.stop(), STOP_TIMEOUT_MS);
737
776
  }
738
777
  this.initializeClient();
778
+ if (this.suspendedForBackground) {
779
+ await this.stopClientQuietly();
780
+ }
739
781
  } finally {
740
782
  this.reconnecting = false;
741
783
  }
@@ -763,6 +805,7 @@ export class XmppClient {
763
805
  // creds really are stale we simply get not-authorized again and
764
806
  // retry, which is the confirmed-good 26.5.7 behaviour.
765
807
  this.updateCredentials(fresh.username, fresh.password);
808
+ this.credentialsRefreshedAt = Date.now();
766
809
  this.lastAuthError = null;
767
810
  }
768
811
  } finally {
@@ -772,6 +815,56 @@ export class XmppClient {
772
815
  return this.credentialsRefreshInFlight;
773
816
  }
774
817
 
818
+ private suspendedForBackground = false;
819
+ private clientAlreadyStopped = false;
820
+
821
+ private async stopClientQuietly(): Promise<void> {
822
+ const c: any = this.client;
823
+ if (c) {
824
+ const sock = c.socket;
825
+ if (sock && typeof sock.end === 'function') {
826
+ try {
827
+ sock.end();
828
+ } catch {}
829
+ try {
830
+ if (c.status !== 'offline') c._status?.('offline');
831
+ } catch {}
832
+ } else {
833
+ await withTimeout(
834
+ Promise.resolve(c.stop()).catch(() => undefined),
835
+ STOP_TIMEOUT_MS
836
+ );
837
+ }
838
+ this.clientAlreadyStopped = true;
839
+ }
840
+ this.status = 'offline';
841
+ this.presencesReady = false;
842
+ }
843
+
844
+ async suspend(): Promise<void> {
845
+ if (this.suspendedForBackground) {return;}
846
+ this.suspendedForBackground = true;
847
+ this.suppressReconnect = true;
848
+ if (this.reconnectTimer) {
849
+ clearTimeout(this.reconnectTimer);
850
+ this.reconnectTimer = null;
851
+ }
852
+ await this.stopClientQuietly();
853
+ console.log('XMPP suspended (background).');
854
+ }
855
+
856
+ /** Back in the foreground: allow reconnects again and reconnect at once. */
857
+ resume(): void {
858
+ if (!this.suspendedForBackground) {return;}
859
+ this.suspendedForBackground = false;
860
+ this.suppressReconnect = false;
861
+ this.forceReconnect();
862
+ }
863
+
864
+ get isSuspended(): boolean {
865
+ return this.suspendedForBackground;
866
+ }
867
+
775
868
  async disconnect(options?: { suppressReconnect?: boolean }): Promise<void> {
776
869
  if (options?.suppressReconnect) {this.suppressReconnect = true;}
777
870
  return this.close();
@@ -971,9 +1064,37 @@ export class XmppClient {
971
1064
  // `getChatsPrivateStoreRequest` directly and intentionally skip this.
972
1065
  if (markers && typeof markers === 'object') {
973
1066
  const normalized: Record<string, number> = {};
1067
+ const roomsState = store.getState().rooms?.rooms || {};
1068
+ const heapState = store.getState().roomHeapSlice;
974
1069
  for (const jid of Object.keys(markers as Record<string, unknown>)) {
975
1070
  const n = Number((markers as Record<string, unknown>)[jid]);
976
- if (jid && Number.isFinite(n) && n > 0) {normalized[jid] = n;}
1071
+ if (!jid || !Number.isFinite(n) || n <= 0) {continue;}
1072
+ // Defensive clamp (bug #38): a marker written while some
1073
+ // device's clock was ahead can land in the future relative to
1074
+ // the newest message the server actually has for this room.
1075
+ // The redux merge (applyPrivateStoreMarkers) and the
1076
+ // server-side merge (flushLastViewedToPrivateStore) both treat
1077
+ // "newer" as "better", so an uncorrected future value would
1078
+ // block every later correct write forever - useUnread() would
1079
+ // report 0 for that room on every cold start. When we already
1080
+ // know this room's messages locally, clamp an implausible
1081
+ // marker down to the newest one we actually have instead of
1082
+ // trusting the server value verbatim.
1083
+ //
1084
+ // "Implausible" needs BOTH "past the newest message we know
1085
+ // about" AND "past real time" (isCorruptFutureReadMarker):
1086
+ // this device's cache for a room is routinely stale, and
1087
+ // clamping on staleness alone would drag a perfectly good
1088
+ // marker written by another device backwards.
1089
+ const room = roomsState[jid];
1090
+ const newestKnownMs = room
1091
+ ? getServerReadTimestamp(room, heapState)
1092
+ : 0;
1093
+ if (isCorruptFutureReadMarker(n, newestKnownMs)) {
1094
+ normalized[jid] = newestKnownMs;
1095
+ } else {
1096
+ normalized[jid] = n;
1097
+ }
977
1098
  }
978
1099
  if (Object.keys(normalized).length > 0) {
979
1100
  store.dispatch(applyPrivateStoreMarkers(normalized));
@@ -1007,11 +1128,22 @@ export class XmppClient {
1007
1128
  // src/networking/xmpp/flushLastViewedToPrivateStore.ts for details.
1008
1129
  async flushLastViewedToPrivateStoreStanza(
1009
1130
  rooms: Record<string, any> | null | undefined,
1010
- opts: { visibleRoomJID?: string | null; onlyIfNoUnread?: boolean } = {}
1131
+ opts: {
1132
+ visibleRoomJID?: string | null;
1133
+ visibleRoomTs?: number | null;
1134
+ onlyIfNoUnread?: boolean;
1135
+ } = {}
1011
1136
  ) {
1012
1137
  if (this.disableLastRead) {return false;}
1013
1138
  try {
1014
- return await flushLastViewedToPrivateStore(this, rooms, opts);
1139
+ // Auto-inject the pending/failed-send heap so every caller gets
1140
+ // getServerReadTimestamp's exclusion of optimistic messages for
1141
+ // free, without needing to reach into the redux store themselves.
1142
+ const heapState = store.getState().roomHeapSlice;
1143
+ return await flushLastViewedToPrivateStore(this, rooms, {
1144
+ ...opts,
1145
+ heapState,
1146
+ });
1015
1147
  } catch {
1016
1148
  return false;
1017
1149
  }
@@ -11,8 +11,7 @@ import {
11
11
  } from '../types/types';
12
12
  import { Iso639_1Codes } from '../types/models/language.model';
13
13
  import type { TranslateMode } from '../utils/translateModePolicy';
14
- import { localStorageConstants } from '../helpers/constants/LOCAL_STORAGE';
15
- import { asyncLocalStorage } from '../hooks/useLocalStorage';
14
+ import { secureUserStorage } from '../helpers/secureUserStorage';
16
15
 
17
16
  export interface ChatState {
18
17
  user: User;
@@ -34,12 +33,15 @@ export interface ChatState {
34
33
 
35
34
  export const unpackAndTransform = (input?: User): User => {
36
35
  return {
37
- description: '',
36
+ // Was hardcoded to '' — every setUser dropped the user's own bio, so
37
+ // the profile's About section could never show one.
38
+ description: input?.description || '',
38
39
  token: input?.token || '',
39
40
  profileImage: input?.profileImage || '',
40
41
  _id: input?._id || '',
41
42
  walletAddress: input?.defaultWallet?.walletAddress || '',
42
43
  xmppPassword: input?.xmppPassword || '',
44
+ fileToken: input?.fileToken || '',
43
45
  refreshToken: input?.refreshToken || '',
44
46
  firstName: input?.firstName || '',
45
47
  lastName: input?.lastName || '',
@@ -73,6 +75,7 @@ const initialState: ChatState = {
73
75
  _id: '',
74
76
  walletAddress: '',
75
77
  xmppPassword: '',
78
+ fileToken: '',
76
79
  refreshToken: '',
77
80
  firstName: '',
78
81
  lastName: '',
@@ -111,9 +114,7 @@ const initialState: ChatState = {
111
114
  const reducers = {
112
115
  setUser: (state: WritableDraft<ChatState>, action: PayloadAction<User>) => {
113
116
  state.user = unpackAndTransform(action.payload);
114
- asyncLocalStorage(localStorageConstants.ETHORA_USER).set(
115
- unpackAndTransform(action.payload)
116
- );
117
+ secureUserStorage().set(unpackAndTransform(action.payload));
117
118
  },
118
119
  updateUser(state: WritableDraft<ChatState>, action: PayloadAction<{ updates: Partial<User> }>) {
119
120
  const { updates } = action.payload;
@@ -146,14 +147,37 @@ const reducers = {
146
147
  setSelectedUser: (state: WritableDraft<ChatState>, action: PayloadAction<IUser | undefined>) => {
147
148
  state.selectedUser = action.payload;
148
149
  },
150
+ /**
151
+ * Token rotation. Dispatched from ONE place only — `authRefresh` —
152
+ * which awaits the AsyncStorage write immediately afterwards, before
153
+ * resolving its promise.
154
+ *
155
+ * The reducer used to fire its own best-effort write here. That was
156
+ * both redundant and racy (two writers, no ordering), and a
157
+ * fire-and-forget write can be lost if the app dies right after a
158
+ * rotation — which on a backend with reuse detection means the next
159
+ * launch presents a burned token. Persistence now belongs to the
160
+ * caller, which can actually await it.
161
+ */
149
162
  refreshTokens: (
150
163
  state: WritableDraft<ChatState>,
151
- action: PayloadAction<{ token: string; refreshToken: string }>
164
+ action: PayloadAction<{
165
+ token: string;
166
+ refreshToken: string;
167
+ xmppPassword?: string;
168
+ fileToken?: string;
169
+ }>
152
170
  ) => {
153
171
  state.user.refreshToken = action.payload.refreshToken;
154
172
  state.user.token = action.payload.token;
155
- // AsyncStorage is async; fire-and-forget so the reducer stays sync.
156
- asyncLocalStorage(localStorageConstants.ETHORA_USER).set(state.user);
173
+
174
+ if (action.payload.xmppPassword) {
175
+ state.user.xmppPassword = action.payload.xmppPassword;
176
+ }
177
+
178
+ if (action.payload.fileToken) {
179
+ state.user.fileToken = action.payload.fileToken;
180
+ }
157
181
  },
158
182
  logout: (state: WritableDraft<ChatState>) => {
159
183
  state.user = unpackAndTransform();
@@ -161,7 +185,7 @@ const reducers = {
161
185
  state.client = undefined;
162
186
  state.langSource = undefined;
163
187
  state.translateMode = undefined;
164
- asyncLocalStorage(localStorageConstants.ETHORA_USER).remove();
188
+ secureUserStorage().remove();
165
189
  },
166
190
  setLangSource: (
167
191
  state: WritableDraft<ChatState>,