@ethora/chat-component-rn 26.8.4 → 26.8.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.
Files changed (417) hide show
  1. package/README.md +55 -0
  2. package/lib/commonjs/assets/emojiData.js +40 -0
  3. package/lib/commonjs/assets/emojiData.js.map +1 -0
  4. package/lib/commonjs/assets/icons.js +1 -1
  5. package/lib/commonjs/assets/icons.js.map +1 -1
  6. package/lib/commonjs/components/Header/HeaderRoomList.js +12 -7
  7. package/lib/commonjs/components/Header/HeaderRoomList.js.map +1 -1
  8. package/lib/commonjs/components/MainComponents/ChatHeader.js +7 -9
  9. package/lib/commonjs/components/MainComponents/ChatHeader.js.map +1 -1
  10. package/lib/commonjs/components/MainComponents/ChatRoom.js +47 -26
  11. package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
  12. package/lib/commonjs/components/MainComponents/ChatWrapper.js +58 -21
  13. package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
  14. package/lib/commonjs/components/MainComponents/KeyboardInputDock.js +40 -0
  15. package/lib/commonjs/components/MainComponents/KeyboardInputDock.js.map +1 -0
  16. package/lib/commonjs/components/MainComponents/MessageContainer.js +4 -12
  17. package/lib/commonjs/components/MainComponents/MessageContainer.js.map +1 -1
  18. package/lib/commonjs/components/MainComponents/MessageList.js +110 -35
  19. package/lib/commonjs/components/MainComponents/MessageList.js.map +1 -1
  20. package/lib/commonjs/components/MainComponents/RoomList.js +32 -29
  21. package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
  22. package/lib/commonjs/components/MainComponents/RoomStack.js +270 -0
  23. package/lib/commonjs/components/MainComponents/RoomStack.js.map +1 -0
  24. package/lib/commonjs/components/MainComponents/SystemMessage.js +6 -2
  25. package/lib/commonjs/components/MainComponents/SystemMessage.js.map +1 -1
  26. package/lib/commonjs/components/MessageBubble/Avatar.js +5 -1
  27. package/lib/commonjs/components/MessageBubble/Avatar.js.map +1 -1
  28. package/lib/commonjs/components/MessageBubble/BottomReplyContainer.js +17 -21
  29. package/lib/commonjs/components/MessageBubble/BottomReplyContainer.js.map +1 -1
  30. package/lib/commonjs/components/MessageBubble/EmojiPickerSheet.js +447 -0
  31. package/lib/commonjs/components/MessageBubble/EmojiPickerSheet.js.map +1 -0
  32. package/lib/commonjs/components/MessageBubble/Message.js +200 -132
  33. package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
  34. package/lib/commonjs/components/MessageBubble/MessageInteractions.js +213 -12
  35. package/lib/commonjs/components/MessageBubble/MessageInteractions.js.map +1 -1
  36. package/lib/commonjs/components/MessageBubble/MessageReaction.js +113 -94
  37. package/lib/commonjs/components/MessageBubble/MessageReaction.js.map +1 -1
  38. package/lib/commonjs/components/MessageBubble/MessageReply.js +66 -24
  39. package/lib/commonjs/components/MessageBubble/MessageReply.js.map +1 -1
  40. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js +6 -1
  41. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  42. package/lib/commonjs/components/Modals/Modal/Modal.js +24 -0
  43. package/lib/commonjs/components/Modals/Modal/Modal.js.map +1 -1
  44. package/lib/commonjs/components/Modals/Modal/SwipeBackLayer.js +178 -0
  45. package/lib/commonjs/components/Modals/Modal/SwipeBackLayer.js.map +1 -0
  46. package/lib/commonjs/components/Modals/ProfileHeader/ProfileHeader.js +28 -10
  47. package/lib/commonjs/components/Modals/ProfileHeader/ProfileHeader.js.map +1 -1
  48. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js +9 -3
  49. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  50. package/lib/commonjs/components/RoomComponents/ChatRoomItem.js +5 -4
  51. package/lib/commonjs/components/RoomComponents/ChatRoomItem.js.map +1 -1
  52. package/lib/commonjs/components/RoomComponents/styled/LastMessageEmoji.js +8 -9
  53. package/lib/commonjs/components/RoomComponents/styled/LastMessageEmoji.js.map +1 -1
  54. package/lib/commonjs/components/Thread/ThreadWrapper.js +265 -152
  55. package/lib/commonjs/components/Thread/ThreadWrapper.js.map +1 -1
  56. package/lib/commonjs/components/styled/DateLabel.js +6 -3
  57. package/lib/commonjs/components/styled/DateLabel.js.map +1 -1
  58. package/lib/commonjs/context/MessageNotificationContext.js +188 -9
  59. package/lib/commonjs/context/MessageNotificationContext.js.map +1 -1
  60. package/lib/commonjs/context/xmppProvider.js +22 -7
  61. package/lib/commonjs/context/xmppProvider.js.map +1 -1
  62. package/lib/commonjs/helpers/createRoomFromApi.js +36 -2
  63. package/lib/commonjs/helpers/createRoomFromApi.js.map +1 -1
  64. package/lib/commonjs/helpers/emoji.js +51 -0
  65. package/lib/commonjs/helpers/emoji.js.map +1 -0
  66. package/lib/commonjs/helpers/haptics.js +29 -0
  67. package/lib/commonjs/helpers/haptics.js.map +1 -0
  68. package/lib/commonjs/helpers/historyPreloadScheduler.js +32 -66
  69. package/lib/commonjs/helpers/historyPreloadScheduler.js.map +1 -1
  70. package/lib/commonjs/helpers/insertMessageWithDelimiter.js +21 -12
  71. package/lib/commonjs/helpers/insertMessageWithDelimiter.js.map +1 -1
  72. package/lib/commonjs/helpers/keyboardLayout.js +23 -1
  73. package/lib/commonjs/helpers/keyboardLayout.js.map +1 -1
  74. package/lib/commonjs/helpers/mamReactions.js +57 -0
  75. package/lib/commonjs/helpers/mamReactions.js.map +1 -0
  76. package/lib/commonjs/helpers/parseMessageReference.js +42 -0
  77. package/lib/commonjs/helpers/parseMessageReference.js.map +1 -0
  78. package/lib/commonjs/helpers/reactionsConfig.js +17 -0
  79. package/lib/commonjs/helpers/reactionsConfig.js.map +1 -0
  80. package/lib/commonjs/helpers/updateMessagesTillLast.js +17 -2
  81. package/lib/commonjs/helpers/updateMessagesTillLast.js.map +1 -1
  82. package/lib/commonjs/hooks/useHeapSender.js +3 -1
  83. package/lib/commonjs/hooks/useHeapSender.js.map +1 -1
  84. package/lib/commonjs/hooks/useMessageHeapState.js +3 -2
  85. package/lib/commonjs/hooks/useMessageHeapState.js.map +1 -1
  86. package/lib/commonjs/hooks/useRoomInitialization.js +16 -7
  87. package/lib/commonjs/hooks/useRoomInitialization.js.map +1 -1
  88. package/lib/commonjs/hooks/useSendMessage.js +14 -8
  89. package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
  90. package/lib/commonjs/hooks/useUnreadMessagesCounter.js +1 -1
  91. package/lib/commonjs/hooks/useUnreadMessagesCounter.js.map +1 -1
  92. package/lib/commonjs/networking/stanzaHandlers.js +106 -50
  93. package/lib/commonjs/networking/stanzaHandlers.js.map +1 -1
  94. package/lib/commonjs/networking/xmpp/getHistory.xmpp.js +29 -74
  95. package/lib/commonjs/networking/xmpp/getHistory.xmpp.js.map +1 -1
  96. package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js +4 -0
  97. package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
  98. package/lib/commonjs/networking/xmpp/mamRouter.js +186 -0
  99. package/lib/commonjs/networking/xmpp/mamRouter.js.map +1 -0
  100. package/lib/commonjs/networking/xmpp/presenceInRoom.xmpp.js +41 -4
  101. package/lib/commonjs/networking/xmpp/presenceInRoom.xmpp.js.map +1 -1
  102. package/lib/commonjs/networking/xmppClient.js +98 -23
  103. package/lib/commonjs/networking/xmppClient.js.map +1 -1
  104. package/lib/commonjs/roomStore/Middleware/newMessageMidlleware.js +29 -34
  105. package/lib/commonjs/roomStore/Middleware/newMessageMidlleware.js.map +1 -1
  106. package/lib/commonjs/roomStore/Middleware/perfMiddleware.js +51 -0
  107. package/lib/commonjs/roomStore/Middleware/perfMiddleware.js.map +1 -0
  108. package/lib/commonjs/roomStore/Middleware/reactionsMiddleware.js +66 -43
  109. package/lib/commonjs/roomStore/Middleware/reactionsMiddleware.js.map +1 -1
  110. package/lib/commonjs/roomStore/Middleware/unreadMidlleware.js +88 -68
  111. package/lib/commonjs/roomStore/Middleware/unreadMidlleware.js.map +1 -1
  112. package/lib/commonjs/roomStore/index.js +18 -14
  113. package/lib/commonjs/roomStore/index.js.map +1 -1
  114. package/lib/commonjs/roomStore/persistBackend.js +96 -0
  115. package/lib/commonjs/roomStore/persistBackend.js.map +1 -0
  116. package/lib/commonjs/roomStore/persistence.js +245 -50
  117. package/lib/commonjs/roomStore/persistence.js.map +1 -1
  118. package/lib/commonjs/roomStore/roomsSlice.js +282 -136
  119. package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
  120. package/lib/commonjs/theme/theme.js +3 -0
  121. package/lib/commonjs/theme/theme.js.map +1 -1
  122. package/lib/commonjs/utils/devLogger.js +14 -0
  123. package/lib/commonjs/utils/devLogger.js.map +1 -1
  124. package/lib/commonjs/version.js +1 -1
  125. package/lib/module/assets/emojiData.js +36 -0
  126. package/lib/module/assets/emojiData.js.map +1 -0
  127. package/lib/module/assets/icons.js +1 -1
  128. package/lib/module/assets/icons.js.map +1 -1
  129. package/lib/module/components/Header/HeaderRoomList.js +12 -7
  130. package/lib/module/components/Header/HeaderRoomList.js.map +1 -1
  131. package/lib/module/components/MainComponents/ChatHeader.js +8 -10
  132. package/lib/module/components/MainComponents/ChatHeader.js.map +1 -1
  133. package/lib/module/components/MainComponents/ChatRoom.js +49 -28
  134. package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
  135. package/lib/module/components/MainComponents/ChatWrapper.js +60 -23
  136. package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
  137. package/lib/module/components/MainComponents/KeyboardInputDock.js +33 -0
  138. package/lib/module/components/MainComponents/KeyboardInputDock.js.map +1 -0
  139. package/lib/module/components/MainComponents/MessageContainer.js +7 -14
  140. package/lib/module/components/MainComponents/MessageContainer.js.map +1 -1
  141. package/lib/module/components/MainComponents/MessageList.js +110 -35
  142. package/lib/module/components/MainComponents/MessageList.js.map +1 -1
  143. package/lib/module/components/MainComponents/RoomList.js +32 -29
  144. package/lib/module/components/MainComponents/RoomList.js.map +1 -1
  145. package/lib/module/components/MainComponents/RoomStack.js +266 -0
  146. package/lib/module/components/MainComponents/RoomStack.js.map +1 -0
  147. package/lib/module/components/MainComponents/SystemMessage.js +6 -2
  148. package/lib/module/components/MainComponents/SystemMessage.js.map +1 -1
  149. package/lib/module/components/MessageBubble/Avatar.js +5 -1
  150. package/lib/module/components/MessageBubble/Avatar.js.map +1 -1
  151. package/lib/module/components/MessageBubble/BottomReplyContainer.js +18 -22
  152. package/lib/module/components/MessageBubble/BottomReplyContainer.js.map +1 -1
  153. package/lib/module/components/MessageBubble/EmojiPickerSheet.js +438 -0
  154. package/lib/module/components/MessageBubble/EmojiPickerSheet.js.map +1 -0
  155. package/lib/module/components/MessageBubble/Message.js +203 -134
  156. package/lib/module/components/MessageBubble/Message.js.map +1 -1
  157. package/lib/module/components/MessageBubble/MessageInteractions.js +215 -14
  158. package/lib/module/components/MessageBubble/MessageInteractions.js.map +1 -1
  159. package/lib/module/components/MessageBubble/MessageReaction.js +115 -94
  160. package/lib/module/components/MessageBubble/MessageReaction.js.map +1 -1
  161. package/lib/module/components/MessageBubble/MessageReply.js +65 -24
  162. package/lib/module/components/MessageBubble/MessageReply.js.map +1 -1
  163. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js +6 -1
  164. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  165. package/lib/module/components/Modals/Modal/Modal.js +25 -1
  166. package/lib/module/components/Modals/Modal/Modal.js.map +1 -1
  167. package/lib/module/components/Modals/Modal/SwipeBackLayer.js +172 -0
  168. package/lib/module/components/Modals/Modal/SwipeBackLayer.js.map +1 -0
  169. package/lib/module/components/Modals/ProfileHeader/ProfileHeader.js +29 -11
  170. package/lib/module/components/Modals/ProfileHeader/ProfileHeader.js.map +1 -1
  171. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js +10 -4
  172. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  173. package/lib/module/components/RoomComponents/ChatRoomItem.js +5 -4
  174. package/lib/module/components/RoomComponents/ChatRoomItem.js.map +1 -1
  175. package/lib/module/components/RoomComponents/styled/LastMessageEmoji.js +8 -9
  176. package/lib/module/components/RoomComponents/styled/LastMessageEmoji.js.map +1 -1
  177. package/lib/module/components/Thread/ThreadWrapper.js +264 -152
  178. package/lib/module/components/Thread/ThreadWrapper.js.map +1 -1
  179. package/lib/module/components/styled/DateLabel.js +6 -3
  180. package/lib/module/components/styled/DateLabel.js.map +1 -1
  181. package/lib/module/context/MessageNotificationContext.js +190 -11
  182. package/lib/module/context/MessageNotificationContext.js.map +1 -1
  183. package/lib/module/context/xmppProvider.js +22 -7
  184. package/lib/module/context/xmppProvider.js.map +1 -1
  185. package/lib/module/helpers/createRoomFromApi.js +36 -2
  186. package/lib/module/helpers/createRoomFromApi.js.map +1 -1
  187. package/lib/module/helpers/emoji.js +44 -0
  188. package/lib/module/helpers/emoji.js.map +1 -0
  189. package/lib/module/helpers/haptics.js +24 -0
  190. package/lib/module/helpers/haptics.js.map +1 -0
  191. package/lib/module/helpers/historyPreloadScheduler.js +32 -66
  192. package/lib/module/helpers/historyPreloadScheduler.js.map +1 -1
  193. package/lib/module/helpers/insertMessageWithDelimiter.js +21 -12
  194. package/lib/module/helpers/insertMessageWithDelimiter.js.map +1 -1
  195. package/lib/module/helpers/keyboardLayout.js +20 -0
  196. package/lib/module/helpers/keyboardLayout.js.map +1 -1
  197. package/lib/module/helpers/mamReactions.js +51 -0
  198. package/lib/module/helpers/mamReactions.js.map +1 -0
  199. package/lib/module/helpers/parseMessageReference.js +37 -0
  200. package/lib/module/helpers/parseMessageReference.js.map +1 -0
  201. package/lib/module/helpers/reactionsConfig.js +10 -0
  202. package/lib/module/helpers/reactionsConfig.js.map +1 -0
  203. package/lib/module/helpers/updateMessagesTillLast.js +17 -2
  204. package/lib/module/helpers/updateMessagesTillLast.js.map +1 -1
  205. package/lib/module/hooks/useHeapSender.js +3 -1
  206. package/lib/module/hooks/useHeapSender.js.map +1 -1
  207. package/lib/module/hooks/useMessageHeapState.js +3 -2
  208. package/lib/module/hooks/useMessageHeapState.js.map +1 -1
  209. package/lib/module/hooks/useRoomInitialization.js +17 -8
  210. package/lib/module/hooks/useRoomInitialization.js.map +1 -1
  211. package/lib/module/hooks/useSendMessage.js +14 -8
  212. package/lib/module/hooks/useSendMessage.js.map +1 -1
  213. package/lib/module/hooks/useUnreadMessagesCounter.js +1 -1
  214. package/lib/module/hooks/useUnreadMessagesCounter.js.map +1 -1
  215. package/lib/module/networking/stanzaHandlers.js +107 -51
  216. package/lib/module/networking/stanzaHandlers.js.map +1 -1
  217. package/lib/module/networking/xmpp/getHistory.xmpp.js +29 -74
  218. package/lib/module/networking/xmpp/getHistory.xmpp.js.map +1 -1
  219. package/lib/module/networking/xmpp/handleStanzas.xmpp.js +4 -0
  220. package/lib/module/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
  221. package/lib/module/networking/xmpp/mamRouter.js +175 -0
  222. package/lib/module/networking/xmpp/mamRouter.js.map +1 -0
  223. package/lib/module/networking/xmpp/presenceInRoom.xmpp.js +38 -2
  224. package/lib/module/networking/xmpp/presenceInRoom.xmpp.js.map +1 -1
  225. package/lib/module/networking/xmppClient.js +99 -24
  226. package/lib/module/networking/xmppClient.js.map +1 -1
  227. package/lib/module/roomStore/Middleware/newMessageMidlleware.js +29 -34
  228. package/lib/module/roomStore/Middleware/newMessageMidlleware.js.map +1 -1
  229. package/lib/module/roomStore/Middleware/perfMiddleware.js +45 -0
  230. package/lib/module/roomStore/Middleware/perfMiddleware.js.map +1 -0
  231. package/lib/module/roomStore/Middleware/reactionsMiddleware.js +66 -43
  232. package/lib/module/roomStore/Middleware/reactionsMiddleware.js.map +1 -1
  233. package/lib/module/roomStore/Middleware/unreadMidlleware.js +89 -69
  234. package/lib/module/roomStore/Middleware/unreadMidlleware.js.map +1 -1
  235. package/lib/module/roomStore/index.js +19 -15
  236. package/lib/module/roomStore/index.js.map +1 -1
  237. package/lib/module/roomStore/persistBackend.js +89 -0
  238. package/lib/module/roomStore/persistBackend.js.map +1 -0
  239. package/lib/module/roomStore/persistence.js +245 -48
  240. package/lib/module/roomStore/persistence.js.map +1 -1
  241. package/lib/module/roomStore/roomsSlice.js +275 -134
  242. package/lib/module/roomStore/roomsSlice.js.map +1 -1
  243. package/lib/module/theme/theme.js +3 -0
  244. package/lib/module/theme/theme.js.map +1 -1
  245. package/lib/module/utils/devLogger.js +13 -0
  246. package/lib/module/utils/devLogger.js.map +1 -1
  247. package/lib/module/version.js +1 -1
  248. package/lib/typescript/assets/emojiData.d.ts +8 -0
  249. package/lib/typescript/assets/emojiData.d.ts.map +1 -0
  250. package/lib/typescript/components/Header/HeaderRoomList.d.ts.map +1 -1
  251. package/lib/typescript/components/MainComponents/ChatHeader.d.ts.map +1 -1
  252. package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
  253. package/lib/typescript/components/MainComponents/ChatWrapper.d.ts.map +1 -1
  254. package/lib/typescript/components/MainComponents/KeyboardInputDock.d.ts +16 -0
  255. package/lib/typescript/components/MainComponents/KeyboardInputDock.d.ts.map +1 -0
  256. package/lib/typescript/components/MainComponents/MessageContainer.d.ts +2 -2
  257. package/lib/typescript/components/MainComponents/MessageContainer.d.ts.map +1 -1
  258. package/lib/typescript/components/MainComponents/MessageList.d.ts.map +1 -1
  259. package/lib/typescript/components/MainComponents/RoomList.d.ts.map +1 -1
  260. package/lib/typescript/components/MainComponents/RoomStack.d.ts +42 -0
  261. package/lib/typescript/components/MainComponents/RoomStack.d.ts.map +1 -0
  262. package/lib/typescript/components/MainComponents/SystemMessage.d.ts.map +1 -1
  263. package/lib/typescript/components/MessageBubble/Avatar.d.ts +2 -0
  264. package/lib/typescript/components/MessageBubble/Avatar.d.ts.map +1 -1
  265. package/lib/typescript/components/MessageBubble/BottomReplyContainer.d.ts.map +1 -1
  266. package/lib/typescript/components/MessageBubble/EmojiPickerSheet.d.ts +11 -0
  267. package/lib/typescript/components/MessageBubble/EmojiPickerSheet.d.ts.map +1 -0
  268. package/lib/typescript/components/MessageBubble/Message.d.ts +2 -2
  269. package/lib/typescript/components/MessageBubble/Message.d.ts.map +1 -1
  270. package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts +2 -0
  271. package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts.map +1 -1
  272. package/lib/typescript/components/MessageBubble/MessageReaction.d.ts +1 -0
  273. package/lib/typescript/components/MessageBubble/MessageReaction.d.ts.map +1 -1
  274. package/lib/typescript/components/MessageBubble/MessageReply.d.ts +7 -7
  275. package/lib/typescript/components/MessageBubble/MessageReply.d.ts.map +1 -1
  276. package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts.map +1 -1
  277. package/lib/typescript/components/Modals/Modal/Modal.d.ts.map +1 -1
  278. package/lib/typescript/components/Modals/Modal/SwipeBackLayer.d.ts +16 -0
  279. package/lib/typescript/components/Modals/Modal/SwipeBackLayer.d.ts.map +1 -0
  280. package/lib/typescript/components/Modals/ProfileHeader/ProfileHeader.d.ts.map +1 -1
  281. package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts.map +1 -1
  282. package/lib/typescript/components/RoomComponents/ChatRoomItem.d.ts +2 -2
  283. package/lib/typescript/components/RoomComponents/ChatRoomItem.d.ts.map +1 -1
  284. package/lib/typescript/components/RoomComponents/styled/LastMessageEmoji.d.ts +3 -6
  285. package/lib/typescript/components/RoomComponents/styled/LastMessageEmoji.d.ts.map +1 -1
  286. package/lib/typescript/components/Thread/ThreadWrapper.d.ts +7 -1
  287. package/lib/typescript/components/Thread/ThreadWrapper.d.ts.map +1 -1
  288. package/lib/typescript/components/styled/DateLabel.d.ts +1 -0
  289. package/lib/typescript/components/styled/DateLabel.d.ts.map +1 -1
  290. package/lib/typescript/context/MessageNotificationContext.d.ts.map +1 -1
  291. package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
  292. package/lib/typescript/helpers/createRoomFromApi.d.ts.map +1 -1
  293. package/lib/typescript/helpers/emoji.d.ts +6 -0
  294. package/lib/typescript/helpers/emoji.d.ts.map +1 -0
  295. package/lib/typescript/helpers/haptics.d.ts +3 -0
  296. package/lib/typescript/helpers/haptics.d.ts.map +1 -0
  297. package/lib/typescript/helpers/historyPreloadScheduler.d.ts +1 -0
  298. package/lib/typescript/helpers/historyPreloadScheduler.d.ts.map +1 -1
  299. package/lib/typescript/helpers/insertMessageWithDelimiter.d.ts.map +1 -1
  300. package/lib/typescript/helpers/keyboardLayout.d.ts +6 -0
  301. package/lib/typescript/helpers/keyboardLayout.d.ts.map +1 -1
  302. package/lib/typescript/helpers/mamReactions.d.ts +13 -0
  303. package/lib/typescript/helpers/mamReactions.d.ts.map +1 -0
  304. package/lib/typescript/helpers/parseMessageReference.d.ts +16 -0
  305. package/lib/typescript/helpers/parseMessageReference.d.ts.map +1 -0
  306. package/lib/typescript/helpers/reactionsConfig.d.ts +5 -0
  307. package/lib/typescript/helpers/reactionsConfig.d.ts.map +1 -0
  308. package/lib/typescript/helpers/updateMessagesTillLast.d.ts.map +1 -1
  309. package/lib/typescript/hooks/useHeapSender.d.ts.map +1 -1
  310. package/lib/typescript/hooks/useMessageHeapState.d.ts.map +1 -1
  311. package/lib/typescript/hooks/useRoomInitialization.d.ts +2 -2
  312. package/lib/typescript/hooks/useRoomInitialization.d.ts.map +1 -1
  313. package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
  314. package/lib/typescript/networking/stanzaHandlers.d.ts +4 -2
  315. package/lib/typescript/networking/stanzaHandlers.d.ts.map +1 -1
  316. package/lib/typescript/networking/xmpp/getHistory.xmpp.d.ts +3 -1
  317. package/lib/typescript/networking/xmpp/getHistory.xmpp.d.ts.map +1 -1
  318. package/lib/typescript/networking/xmpp/handleStanzas.xmpp.d.ts.map +1 -1
  319. package/lib/typescript/networking/xmpp/mamRouter.d.ts +23 -0
  320. package/lib/typescript/networking/xmpp/mamRouter.d.ts.map +1 -0
  321. package/lib/typescript/networking/xmpp/presenceInRoom.xmpp.d.ts +1 -0
  322. package/lib/typescript/networking/xmpp/presenceInRoom.xmpp.d.ts.map +1 -1
  323. package/lib/typescript/networking/xmppClient.d.ts +22 -1
  324. package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
  325. package/lib/typescript/roomStore/Middleware/newMessageMidlleware.d.ts.map +1 -1
  326. package/lib/typescript/roomStore/Middleware/perfMiddleware.d.ts +4 -0
  327. package/lib/typescript/roomStore/Middleware/perfMiddleware.d.ts.map +1 -0
  328. package/lib/typescript/roomStore/Middleware/reactionsMiddleware.d.ts +9 -0
  329. package/lib/typescript/roomStore/Middleware/reactionsMiddleware.d.ts.map +1 -1
  330. package/lib/typescript/roomStore/Middleware/unreadMidlleware.d.ts.map +1 -1
  331. package/lib/typescript/roomStore/index.d.ts.map +1 -1
  332. package/lib/typescript/roomStore/persistBackend.d.ts +11 -0
  333. package/lib/typescript/roomStore/persistBackend.d.ts.map +1 -0
  334. package/lib/typescript/roomStore/persistence.d.ts +5 -6
  335. package/lib/typescript/roomStore/persistence.d.ts.map +1 -1
  336. package/lib/typescript/roomStore/roomsSlice.d.ts +41 -1
  337. package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
  338. package/lib/typescript/theme/theme.d.ts +4 -1
  339. package/lib/typescript/theme/theme.d.ts.map +1 -1
  340. package/lib/typescript/types/models/message.model.d.ts +4 -0
  341. package/lib/typescript/types/models/message.model.d.ts.map +1 -1
  342. package/lib/typescript/types/models/room.model.d.ts +16 -0
  343. package/lib/typescript/types/models/room.model.d.ts.map +1 -1
  344. package/lib/typescript/types/models/xmpp.model.d.ts +6 -1
  345. package/lib/typescript/types/models/xmpp.model.d.ts.map +1 -1
  346. package/lib/typescript/types/types.d.ts +15 -3
  347. package/lib/typescript/types/types.d.ts.map +1 -1
  348. package/lib/typescript/utils/devLogger.d.ts +8 -0
  349. package/lib/typescript/utils/devLogger.d.ts.map +1 -1
  350. package/lib/typescript/version.d.ts +1 -1
  351. package/package.json +10 -1
  352. package/src/assets/emojiData.ts +2146 -0
  353. package/src/assets/icons.tsx +5 -5
  354. package/src/components/Header/HeaderRoomList.tsx +7 -5
  355. package/src/components/MainComponents/ChatHeader.tsx +16 -7
  356. package/src/components/MainComponents/ChatRoom.tsx +64 -32
  357. package/src/components/MainComponents/ChatWrapper.tsx +73 -21
  358. package/src/components/MainComponents/KeyboardInputDock.tsx +47 -0
  359. package/src/components/MainComponents/MessageContainer.tsx +7 -15
  360. package/src/components/MainComponents/MessageList.tsx +96 -43
  361. package/src/components/MainComponents/RoomList.tsx +28 -29
  362. package/src/components/MainComponents/RoomStack.tsx +309 -0
  363. package/src/components/MainComponents/SystemMessage.tsx +6 -2
  364. package/src/components/MessageBubble/Avatar.tsx +7 -1
  365. package/src/components/MessageBubble/BottomReplyContainer.tsx +19 -21
  366. package/src/components/MessageBubble/EmojiPickerSheet.tsx +468 -0
  367. package/src/components/MessageBubble/Message.tsx +146 -87
  368. package/src/components/MessageBubble/MessageInteractions.tsx +213 -12
  369. package/src/components/MessageBubble/MessageReaction.tsx +120 -96
  370. package/src/components/MessageBubble/MessageReply.tsx +65 -32
  371. package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +4 -0
  372. package/src/components/Modals/Modal/Modal.tsx +32 -1
  373. package/src/components/Modals/Modal/SwipeBackLayer.tsx +221 -0
  374. package/src/components/Modals/ProfileHeader/ProfileHeader.tsx +29 -8
  375. package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +6 -3
  376. package/src/components/RoomComponents/ChatRoomItem.tsx +11 -4
  377. package/src/components/RoomComponents/styled/LastMessageEmoji.tsx +7 -8
  378. package/src/components/Thread/ThreadWrapper.tsx +274 -198
  379. package/src/components/styled/DateLabel.tsx +7 -3
  380. package/src/context/MessageNotificationContext.tsx +205 -7
  381. package/src/context/xmppProvider.tsx +29 -9
  382. package/src/helpers/createRoomFromApi.tsx +37 -1
  383. package/src/helpers/emoji.ts +39 -0
  384. package/src/helpers/haptics.ts +19 -0
  385. package/src/helpers/historyPreloadScheduler.ts +37 -69
  386. package/src/helpers/insertMessageWithDelimiter.ts +23 -16
  387. package/src/helpers/keyboardLayout.ts +26 -0
  388. package/src/helpers/mamReactions.ts +59 -0
  389. package/src/helpers/parseMessageReference.ts +38 -0
  390. package/src/helpers/reactionsConfig.ts +13 -0
  391. package/src/helpers/updateMessagesTillLast.tsx +14 -2
  392. package/src/hooks/useHeapSender.tsx +3 -2
  393. package/src/hooks/useMessageHeapState.tsx +6 -2
  394. package/src/hooks/useRoomInitialization.tsx +32 -15
  395. package/src/hooks/useSendMessage.tsx +18 -11
  396. package/src/hooks/useUnreadMessagesCounter.ts +1 -1
  397. package/src/networking/stanzaHandlers.ts +116 -60
  398. package/src/networking/xmpp/getHistory.xmpp.ts +44 -106
  399. package/src/networking/xmpp/handleStanzas.xmpp.ts +2 -0
  400. package/src/networking/xmpp/mamRouter.ts +176 -0
  401. package/src/networking/xmpp/presenceInRoom.xmpp.ts +46 -3
  402. package/src/networking/xmppClient.ts +105 -20
  403. package/src/roomStore/Middleware/newMessageMidlleware.tsx +35 -38
  404. package/src/roomStore/Middleware/perfMiddleware.ts +50 -0
  405. package/src/roomStore/Middleware/reactionsMiddleware.tsx +53 -52
  406. package/src/roomStore/Middleware/unreadMidlleware.tsx +92 -80
  407. package/src/roomStore/index.ts +28 -27
  408. package/src/roomStore/persistBackend.ts +96 -0
  409. package/src/roomStore/persistence.ts +280 -73
  410. package/src/roomStore/roomsSlice.ts +304 -155
  411. package/src/theme/theme.ts +10 -1
  412. package/src/types/models/message.model.ts +4 -0
  413. package/src/types/models/room.model.ts +17 -0
  414. package/src/types/models/xmpp.model.ts +4 -2
  415. package/src/types/types.ts +15 -3
  416. package/src/utils/devLogger.ts +16 -0
  417. package/src/version.ts +1 -1
@@ -1,15 +1,22 @@
1
1
  import { Element } from 'ltx';
2
2
  import { store } from '../roomStore';
3
3
  import {
4
- addRoom,
4
+ claimMamResult,
5
+ collectMamMessage,
6
+ collectMamReaction,
7
+ } from './xmpp/mamRouter';
8
+ import { extractReaction } from '../helpers/mamReactions';
9
+ import {
10
+ addRooms,
5
11
  addRoomMessage,
6
12
  deleteRoomMessage,
7
13
  editRoomMessage,
8
14
  setComposing,
9
15
  setCurrentRoom,
10
16
  setRoomRole,
17
+ setReactions,
11
18
  } from '../roomStore/roomsSlice';
12
- import { IRoom } from '../types/types';
19
+ import { IMessage, IRoom } from '../types/types';
13
20
  import { createMessageFromXml } from '../helpers/createMessageFromXml';
14
21
  import { getDataFromXml } from '../helpers/getDataFromXml';
15
22
  import { setDeleteModal } from '../roomStore/chatSettingsSlice';
@@ -33,7 +40,8 @@ const onRealtimeMessage = async (stanza: Element) => {
33
40
  !stanza.getChild('paused') &&
34
41
  !stanza.getChild('subject') &&
35
42
  !stanza.is('iq') &&
36
- stanza.attrs.id !== 'deleteMessageStanza'
43
+ stanza.attrs.id !== 'deleteMessageStanza' &&
44
+ !stanza.getChild('reactions')
37
45
  ) {
38
46
  const body = stanza?.getChild('body');
39
47
  const archived = stanza?.getChild('archived');
@@ -47,8 +55,6 @@ const onRealtimeMessage = async (stanza: Element) => {
47
55
  ?.getChild('deleted');
48
56
 
49
57
  if (!data) {
50
- console.log(stanza.toString());
51
- console.log('Missing data elements in real-time message.');
52
58
  return;
53
59
  }
54
60
 
@@ -66,8 +72,6 @@ const onRealtimeMessage = async (stanza: Element) => {
66
72
  // to the same tolerance.
67
73
  const senderJID = data.attrs.senderJID || stanza.attrs.from;
68
74
  if (!senderJID) {
69
- console.log(stanza.toString());
70
- console.log('Missing sender information in real-time message.');
71
75
  return;
72
76
  }
73
77
 
@@ -189,11 +193,36 @@ const onEditMessage = async (stanza: Element) => {
189
193
  }
190
194
  };
191
195
 
192
- const onMessageHistory = async (stanza: any) => {
193
- if (
194
- stanza.is('message') &&
195
- stanza.children[0].attrs.xmlns === 'urn:xmpp:mam:2'
196
- ) {
196
+ const isMamResult = (stanza: any): boolean =>
197
+ !!stanza?.is?.('message') &&
198
+ stanza.children?.[0]?.attrs?.xmlns === 'urn:xmpp:mam:2';
199
+
200
+ const parseMamResult = async (stanza: any): Promise<IMessage | undefined> => {
201
+ {
202
+ const forwardedMsg = stanza
203
+ .getChild('result')
204
+ ?.getChild('forwarded')
205
+ ?.getChild('message');
206
+ if (forwardedMsg?.getChild?.('reactions')) {
207
+ const reaction = extractReaction(
208
+ forwardedMsg,
209
+ stanza.attrs?.from,
210
+ stanza.getChild('result')?.attrs?.id
211
+ );
212
+ if (reaction && !collectMamReaction(stanza, reaction)) {
213
+ store.dispatch(
214
+ setReactions({
215
+ roomJID: reaction.roomJID,
216
+ messageId: reaction.messageId,
217
+ from: reaction.from,
218
+ reactions: reaction.emoji,
219
+ data: reaction.data,
220
+ latestReactionTimestamp: reaction.ts,
221
+ })
222
+ );
223
+ }
224
+ return undefined;
225
+ }
197
226
  // console.log("stanza -->", stanza.toString());
198
227
  const body = stanza
199
228
  .getChild('result')
@@ -218,11 +247,9 @@ const onMessageHistory = async (stanza: any) => {
218
247
  const id = stanza.getChild('result')?.attrs.id;
219
248
  if (!delay) {
220
249
  if (stanza.getChild('subject')) {
221
- console.log('Subject.');
222
250
  return;
223
251
  }
224
252
  if (!data || !body || !id) {
225
- console.log('Missing required elements in message history.');
226
253
  return;
227
254
  }
228
255
  }
@@ -295,6 +322,22 @@ const onMessageHistory = async (stanza: any) => {
295
322
  rawMessage,
296
323
  store.getState().chatSettingStore.user?.xmppUsername || ''
297
324
  );
325
+ return message;
326
+ }
327
+ };
328
+
329
+ const onMessageHistory = async (stanza: any) => {
330
+ if (!isMamResult(stanza)) {return;}
331
+ const claimed = claimMamResult(stanza);
332
+ let message: IMessage | undefined;
333
+ try {
334
+ message = await parseMamResult(stanza);
335
+ } finally {
336
+ if (claimed) {
337
+ collectMamMessage(stanza, message);
338
+ }
339
+ }
340
+ if (!claimed && message) {
298
341
  store.dispatch(
299
342
  addRoomMessage({
300
343
  roomJID: stanza.attrs.from,
@@ -360,7 +403,9 @@ const onPresenceInRoom = (stanza: Element | any) => {
360
403
  ) {
361
404
  const roomJID: string = stanza.attrs.from.split('/')[0];
362
405
  const role: string = stanza?.children[1]?.children[0]?.attrs.role;
363
- store.dispatch(setRoomRole({ chatJID: roomJID, role: role }));
406
+ if (role && store.getState().rooms.rooms?.[roomJID]?.role !== role) {
407
+ store.dispatch(setRoomRole({ chatJID: roomJID, role: role }));
408
+ }
364
409
  }
365
410
  };
366
411
 
@@ -423,53 +468,47 @@ const onGetChatRooms = (stanza: Element, xmpp: any) => {
423
468
  Array.isArray(stanza.getChild('query')?.children)
424
469
  ) {
425
470
  const children = stanza.getChild('query')?.children || [];
426
- children.forEach(async (result: any) => {
427
- const currentChatRooms = store.getState().rooms.rooms;
428
-
429
- const isRoomAlreadyAdded = Object.values(currentChatRooms).some(
430
- (element) => element.jid === result?.attrs?.jid
431
- );
432
-
471
+ const known = store.getState().rooms.rooms;
472
+ const fresh: IRoom[] = [];
473
+ const jids: string[] = [];
474
+ for (const result of children as any[]) {
433
475
  const jid = result?.attrs?.jid;
434
-
435
- if (!isRoomAlreadyAdded) {
436
- try {
437
- const roomData: IRoom = {
438
- jid: jid || '',
439
- name: result?.attrs?.name || '',
440
- id: '',
441
- title: result?.attrs?.name || '',
442
- usersCnt: Number(result?.attrs?.users_cnt || 0),
443
- messages: [],
444
- isLoading: false,
445
- roomBg:
446
- result?.attrs?.room_background !== 'none'
447
- ? result?.attrs?.room_background
448
- : null,
449
- icon:
450
- result?.attrs?.room_thumbnail !== 'none'
451
- ? result?.attrs?.room_thumbnail
452
- : null,
453
- unreadMessages: 0,
454
- lastViewedTimestamp: 0,
455
- };
456
-
457
- store.dispatch(addRoom({ roomData: { ...roomData } }));
458
-
459
- if (!store.getState().rooms.activeRoomJID) {
460
- store.dispatch(setCurrentRoom({ roomJID: roomData.jid }));
461
- }
462
- } catch (error) {}
476
+ if (!jid) {continue;}
477
+ jids.push(jid);
478
+ if (known[jid]) {continue;}
479
+ fresh.push({
480
+ jid,
481
+ name: result?.attrs?.name || '',
482
+ id: '',
483
+ title: result?.attrs?.name || '',
484
+ usersCnt: Number(result?.attrs?.users_cnt || 0),
485
+ messages: [],
486
+ isLoading: false,
487
+ roomBg:
488
+ result?.attrs?.room_background !== 'none'
489
+ ? result?.attrs?.room_background
490
+ : null,
491
+ icon:
492
+ result?.attrs?.room_thumbnail !== 'none'
493
+ ? result?.attrs?.room_thumbnail
494
+ : null,
495
+ unreadMessages: 0,
496
+ lastViewedTimestamp: 0,
497
+ });
498
+ }
499
+ if (fresh.length) {
500
+ store.dispatch(addRooms({ rooms: fresh }));
501
+ if (!store.getState().rooms.activeRoomJID) {
502
+ store.dispatch(setCurrentRoom({ roomJID: fresh[0].jid }));
463
503
  }
464
-
465
- if (jid) {
466
- try {
467
- xmpp.presenceInRoomStanza(jid);
468
- } catch (e) {
469
- console.warn('presenceInRoomStanza failed', jid, e);
470
- }
504
+ }
505
+ for (const jid of jids) {
506
+ try {
507
+ xmpp.presenceInRoomStanza(jid);
508
+ } catch (e) {
509
+ console.warn('presenceInRoomStanza failed', jid, e);
471
510
  }
472
- });
511
+ }
473
512
  }
474
513
  };
475
514
 
@@ -477,7 +516,24 @@ const onGetChatRooms = (stanza: Element, xmpp: any) => {
477
516
  // RN side hasn't ported yet. Without these the bundle compiles but
478
517
  // require() returns undefined at runtime → "X is not a function".
479
518
  const onMessageError = (_stanza: Element, _xmpp?: any) => {};
480
- const onReactionMessage = (_stanza: Element) => {};
519
+ /** A live reaction: the reactor's full current list on one message. */
520
+ const onReactionMessage = (stanza: Element) => {
521
+ if (!stanza?.is?.('message') || stanza.getChild('result')) {return;}
522
+ if (!stanza.getChild('reactions')) {return;}
523
+ const reaction = extractReaction(stanza, stanza.attrs?.from);
524
+ if (!reaction) {return;}
525
+ store.dispatch(
526
+ setReactions({
527
+ roomJID: reaction.roomJID,
528
+ messageId: reaction.messageId,
529
+ latestReactionTimestamp: reaction.ts,
530
+ reactions: reaction.emoji,
531
+ from: reaction.from,
532
+ data: reaction.data,
533
+ })
534
+ );
535
+ };
536
+ // Archived reactions are handled by parseMamResult + the MAM router.
481
537
  const onReactionHistory = (_stanza: Element) => {};
482
538
  const onRoomKicked = (_stanza: Element) => {};
483
539
 
@@ -1,16 +1,19 @@
1
1
  import { Client, xml } from '@xmpp/client';
2
2
  import { createTimeoutPromise } from './createTimeoutPromise.xmpp';
3
- import { Element } from 'ltx';
4
3
  import { IMessage } from '../../types/types';
5
- import { getDataFromXml } from '../../helpers/getDataFromXml';
6
- import { createMessageFromXml } from '../../helpers/createMessageFromXml';
4
+ import { beginMamQuery, cancelMamQuery } from './mamRouter';
5
+
6
+ declare const __DEV__: boolean | undefined;
7
+
8
+ let historyIdCounter = 0;
7
9
 
8
10
  export const getHistory = async (
9
11
  client: Client,
10
12
  chatJID: string,
11
13
  max: number,
12
14
  before?: number,
13
- otherId?: string
15
+ otherId?: string,
16
+ options?: { selfApplied?: boolean }
14
17
  ): Promise<IMessage[] | undefined> => {
15
18
  if (typeof chatJID !== 'string') {return;}
16
19
  // If a caller passes a bare local-part (no `@host`), pick a default
@@ -25,121 +28,56 @@ export const getHistory = async (
25
28
  return `${chatJID}@conference.${host}`;
26
29
  })();
27
30
 
28
- const id = otherId ?? `get-history:${Date.now().toString()}`;
29
-
30
- let stanzaHdlrPointer: {
31
- (el: Element): void;
32
- (stanza: any): void;
33
- };
34
-
35
- const unsubscribe = () => {
36
- client.off('stanza', stanzaHdlrPointer);
37
- };
38
-
39
- const responsePromise = new Promise((resolve, reject) => {
40
- let messages: Element[] = [];
41
-
42
- stanzaHdlrPointer = async (stanza) => {
43
- const result = stanza.getChild('result');
44
-
45
- if (
46
- stanza.is('message') &&
47
- stanza.attrs.from &&
48
- stanza.attrs.from.startsWith(fixedChatJid) &&
49
- result
50
- ) {
51
- const messageEl = result.getChild('forwarded')?.getChild('message');
52
-
53
- messages.push(messageEl);
54
- }
55
-
56
- if (
57
- stanza.is('iq') &&
58
- stanza.attrs.id === id &&
59
- stanza.attrs.type === 'result'
60
- ) {
61
- let mainMessages: IMessage[] = [];
62
31
 
63
- for (const msg of messages) {
64
- const reactions = msg?.getChild('reactions');
65
- const text = msg.getChild('body')?.getText();
32
+ const id = otherId ?? `get-history:${Date.now().toString(36)}-${(++historyIdCounter).toString(36)}`;
66
33
 
67
- if (text || reactions) {
68
- const result = await getDataFromXml(msg);
69
- if (!result) {
70
- return;
71
- }
72
- const { data, id, body, ...rest } = result;
34
+ const page = beginMamQuery(id, fixedChatJid, !options?.selfApplied);
73
35
 
74
- if (!data) {
75
- console.log('No data in stanza');
76
- return;
77
- }
78
-
79
- const message = await createMessageFromXml({
80
- data,
81
- id,
82
- body: body || '',
83
- ...rest,
84
- } as any);
85
-
86
- mainMessages.push(message);
87
- }
88
- }
89
- resolve(mainMessages);
90
- }
91
-
92
- if (
93
- stanza.is('iq') &&
94
- stanza.attrs.id === id &&
95
- stanza.attrs.type === 'error'
96
- ) {
97
- reject();
98
- }
99
- };
100
-
101
- client?.on('stanza', stanzaHdlrPointer);
102
-
103
- const message = xml(
104
- 'iq',
105
- {
106
- type: 'set',
107
- to: fixedChatJid,
108
- id: id,
109
- },
36
+ const message = xml(
37
+ 'iq',
38
+ {
39
+ type: 'set',
40
+ to: fixedChatJid,
41
+ id: id,
42
+ },
43
+ xml(
44
+ 'query',
45
+ { xmlns: 'urn:xmpp:mam:2', queryid: id },
110
46
  xml(
111
- 'query',
112
- { xmlns: 'urn:xmpp:mam:2' },
113
- xml(
114
- 'set',
115
- { xmlns: 'http://jabber.org/protocol/rsm' },
116
- xml('max', {}, max.toString()),
117
- before ? xml('before', {}, before.toString()) : xml('before')
118
- )
47
+ 'set',
48
+ { xmlns: 'http://jabber.org/protocol/rsm' },
49
+ xml('max', {}, max.toString()),
50
+ before ? xml('before', {}, before.toString()) : xml('before')
119
51
  )
120
- );
52
+ )
53
+ );
121
54
 
122
- client?.send(message).catch((err: any) => console.log('err on load', err));
123
- });
55
+ client?.send(message).catch((err: any) => console.log('err on load', err));
124
56
 
125
57
  const timeoutPromise = createTimeoutPromise(10000);
126
58
 
127
59
  try {
128
- // @ts-ignore
129
- const res: IMessage[] | null = await Promise.race<[IMessage[] | null]>([
130
- responsePromise as Promise<IMessage[] | null>,
60
+ const res = await Promise.race<IMessage[] | null>([
61
+ page,
131
62
  timeoutPromise as Promise<null>,
132
63
  ]);
133
- return res === null ? [] : res;
64
+ if (res === null) {
65
+ const partial = cancelMamQuery(id);
66
+ if (typeof __DEV__ !== 'undefined' && __DEV__) {
67
+ console.log(
68
+ `[mam] history request for ${fixedChatJid} timed out after 10s (${partial.length} results arrived)`
69
+ );
70
+ }
71
+ return partial;
72
+ }
73
+ return res;
134
74
  } catch (e) {
135
- // MAM rejects with no value when an iq error returns; the timeout
136
- // path resolves with null instead of throwing. Either is expected
137
- // for a room with no history yet — only log if `e` is meaningful.
138
- if (e !== undefined) {
139
- console.log('=-> error in', fixedChatJid, e);
75
+ const partial = cancelMamQuery(id);
76
+ if (typeof __DEV__ !== 'undefined' && __DEV__ && e === undefined) {
77
+ console.log(
78
+ `[mam] history request for ${fixedChatJid} got no closing iq within 10s (${partial.length} results arrived)`
79
+ );
140
80
  }
141
- return [];
142
- } finally {
143
- unsubscribe();
81
+ return partial;
144
82
  }
145
83
  };
@@ -1,4 +1,5 @@
1
1
  import { Element } from 'ltx';
2
+ import { routeMamIq } from './mamRouter';
2
3
  import {
3
4
  onDeleteMessage,
4
5
  onEditMessage,
@@ -80,6 +81,7 @@ export function handleStanza(stanza: Element, xmppWs: XmppClient) {
80
81
  onPresenceInRoom(stanza);
81
82
  break;
82
83
  case 'iq':
84
+ if (routeMamIq(stanza)) {break;}
83
85
  onGetChatRooms(stanza, xmppWs);
84
86
  onRealtimeMessage(stanza);
85
87
  onPresenceInRoom(stanza);
@@ -0,0 +1,176 @@
1
+ import { store } from '../../roomStore';
2
+ import { addRoomMessages, setReactions } from '../../roomStore/roomsSlice';
3
+ import { IMessage } from '../../types/types';
4
+ import { applyMamReactions, type ExtractedReaction } from '../../helpers/mamReactions';
5
+
6
+ interface PendingQuery {
7
+ roomJID: string;
8
+ apply: boolean;
9
+ messages: IMessage[];
10
+ reactions: ExtractedReaction[];
11
+ inflight: number;
12
+ closed: null | { error: boolean };
13
+ resolve: (messages: IMessage[]) => void;
14
+ reject: (error: Error) => void;
15
+ }
16
+
17
+ const pending = new Map<string, PendingQuery>();
18
+
19
+ const flush = (query: PendingQuery) => {
20
+ // Every step is guarded: a failure in one (a middleware throwing on a
21
+ // reaction, say) used to escape `settle` before the waiting request was
22
+ // resolved — the page was lost and the room stayed empty until opened.
23
+ let deferred: ExtractedReaction[] = [];
24
+ try {
25
+ // Reactions ride in the archive as their own entries: fold them onto
26
+ // the page's messages first, so they are stored together.
27
+ deferred = applyMamReactions(query.messages, query.reactions);
28
+ } catch (e) {
29
+ console.warn('[mam] applying reactions to a page failed', e);
30
+ }
31
+ if (query.apply && query.messages.length > 0) {
32
+ try {
33
+ store.dispatch(
34
+ addRoomMessages({ roomJID: query.roomJID, messages: query.messages })
35
+ );
36
+ } catch (e) {
37
+ console.warn('[mam] applying a history page failed', e);
38
+ }
39
+ }
40
+ for (const reaction of deferred) {
41
+ try {
42
+ store.dispatch(
43
+ setReactions({
44
+ roomJID: reaction.roomJID || query.roomJID,
45
+ messageId: reaction.messageId,
46
+ from: reaction.from,
47
+ reactions: reaction.emoji,
48
+ data: reaction.data,
49
+ latestReactionTimestamp: reaction.ts,
50
+ })
51
+ );
52
+ } catch (e) {
53
+ console.warn('[mam] applying a reaction failed', e);
54
+ }
55
+ }
56
+ };
57
+
58
+ export const beginMamQuery = (
59
+ queryId: string,
60
+ roomJID: string,
61
+ apply = true
62
+ ): Promise<IMessage[]> =>
63
+ new Promise((resolve, reject) => {
64
+ pending.set(queryId, {
65
+ roomJID,
66
+ apply,
67
+ messages: [],
68
+ reactions: [],
69
+ inflight: 0,
70
+ closed: null,
71
+ resolve,
72
+ reject,
73
+ });
74
+ });
75
+
76
+ /**
77
+ * Give up waiting (timeout). Whatever arrived is still applied — a late
78
+ * page is better than a lost one — and handed back.
79
+ */
80
+ export const cancelMamQuery = (queryId: string): IMessage[] => {
81
+ const query = pending.get(queryId);
82
+ if (!query) {return [];}
83
+ pending.delete(queryId);
84
+ flush(query);
85
+ query.resolve(query.messages);
86
+ return query.messages;
87
+ };
88
+
89
+ const bareLower = (jid: unknown): string =>
90
+ String(jid || '').split('/')[0].toLowerCase();
91
+
92
+ // By the echoed `queryid` when the server provides one; otherwise by the
93
+ // room the result came from — the oldest still-open query for that room.
94
+ // (Results are per room anyway: a query only ever asks one archive.)
95
+ const queryOf = (stanza: any): PendingQuery | undefined => {
96
+ const queryId = stanza?.getChild?.('result')?.attrs?.queryid;
97
+ const byId = queryId ? pending.get(queryId) : undefined;
98
+ if (byId) {return byId;}
99
+ const room = bareLower(stanza?.attrs?.from);
100
+ if (!room) {return undefined;}
101
+ for (const query of pending.values()) {
102
+ if (!query.closed && bareLower(query.roomJID) === room) {return query;}
103
+ }
104
+ return undefined;
105
+ };
106
+
107
+ const settle = (queryId: string, query: PendingQuery) => {
108
+ if (pending.get(queryId) === query) {pending.delete(queryId);}
109
+ try {
110
+ flush(query);
111
+ } finally {
112
+ // The waiting request is always answered, whatever happened above.
113
+ if (query.closed?.error) {
114
+ query.reject(new Error('mam query error'));
115
+ } else {
116
+ query.resolve(query.messages);
117
+ }
118
+ }
119
+ };
120
+
121
+ const settleIfDone = (query: PendingQuery) => {
122
+ if (!query.closed || query.inflight > 0) {return;}
123
+ const entry = [...pending.entries()].find(([, q]) => q === query);
124
+ settle(entry ? entry[0] : '', query);
125
+ };
126
+
127
+ /**
128
+ * Claim a result for its pending query — synchronously, the moment the
129
+ * stanza arrives — so the router knows a parse is outstanding. Returns
130
+ * true when a pending query owns it (the caller must then always follow
131
+ * up with `collectMamMessage`, even when the parse yields nothing).
132
+ */
133
+ export const claimMamResult = (stanza: any): boolean => {
134
+ const query = queryOf(stanza);
135
+ if (!query) {return false;}
136
+ query.inflight += 1;
137
+ return true;
138
+ };
139
+
140
+ /** The parsed result of a claimed stanza (undefined: dropped). */
141
+ export const collectMamReaction = (
142
+ stanza: any,
143
+ reaction: ExtractedReaction
144
+ ): boolean => {
145
+ const query = queryOf(stanza);
146
+ if (!query) {return false;}
147
+ query.reactions.push(reaction);
148
+ return true;
149
+ };
150
+
151
+ export const collectMamMessage = (
152
+ stanza: any,
153
+ message: IMessage | undefined
154
+ ): boolean => {
155
+ const query = queryOf(stanza);
156
+ if (!query) {return false;}
157
+ if (message) {query.messages.push(message);}
158
+ query.inflight = Math.max(0, query.inflight - 1);
159
+ settleIfDone(query);
160
+ return true;
161
+ };
162
+
163
+ /** The query's closing iq; true when it belonged to a pending query. */
164
+ export const routeMamIq = (stanza: any): boolean => {
165
+ if (!stanza?.is?.('iq')) {return false;}
166
+ const query = pending.get(stanza.attrs?.id);
167
+ if (!query) {return false;}
168
+ query.closed = { error: stanza.attrs.type === 'error' };
169
+ // Results that are still being parsed settle the page when they land;
170
+ // until then the query stays registered so they can find it.
171
+ if (query.inflight === 0) {settle(stanza.attrs.id, query);}
172
+ return true;
173
+ };
174
+
175
+ /** Test hook. */
176
+ export const __resetMamRouter = () => pending.clear();