@ethora/chat-component-rn 26.10.5 → 26.10.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (365) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +15 -0
  3. package/app.plugin.js +2 -0
  4. package/lib/commonjs/assets/icons.js +2 -2
  5. package/lib/commonjs/assets/icons.js.map +1 -1
  6. package/lib/commonjs/components/MainComponents/AlbumGrid.js +152 -0
  7. package/lib/commonjs/components/MainComponents/AlbumGrid.js.map +1 -0
  8. package/lib/commonjs/components/MainComponents/ChatRoom.js +2 -2
  9. package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
  10. package/lib/commonjs/components/MainComponents/MediaMessage.js +199 -123
  11. package/lib/commonjs/components/MainComponents/MediaMessage.js.map +1 -1
  12. package/lib/commonjs/components/MainComponents/MediaUploadOverlay.js +109 -0
  13. package/lib/commonjs/components/MainComponents/MediaUploadOverlay.js.map +1 -0
  14. package/lib/commonjs/components/MessageBubble/MediaCaption.js +51 -0
  15. package/lib/commonjs/components/MessageBubble/MediaCaption.js.map +1 -0
  16. package/lib/commonjs/components/MessageBubble/Message.js +40 -1
  17. package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
  18. package/lib/commonjs/components/MessageBubble/MessageInteractions.js +2 -1
  19. package/lib/commonjs/components/MessageBubble/MessageInteractions.js.map +1 -1
  20. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +75 -0
  21. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  22. package/lib/commonjs/components/RoomComponents/LastMessageItem.js +20 -4
  23. package/lib/commonjs/components/RoomComponents/LastMessageItem.js.map +1 -1
  24. package/lib/commonjs/components/RoomComponents/styled/LastAudioMessage.js +3 -2
  25. package/lib/commonjs/components/RoomComponents/styled/LastAudioMessage.js.map +1 -1
  26. package/lib/commonjs/components/RoomComponents/styled/LastMessageFile.js +3 -2
  27. package/lib/commonjs/components/RoomComponents/styled/LastMessageFile.js.map +1 -1
  28. package/lib/commonjs/components/RoomComponents/styled/LastMessagePhoto.js +3 -2
  29. package/lib/commonjs/components/RoomComponents/styled/LastMessagePhoto.js.map +1 -1
  30. package/lib/commonjs/components/RoomComponents/styled/LastMessageVideo.js +3 -2
  31. package/lib/commonjs/components/RoomComponents/styled/LastMessageVideo.js.map +1 -1
  32. package/lib/commonjs/components/Thread/ThreadWrapper.js +3 -2
  33. package/lib/commonjs/components/Thread/ThreadWrapper.js.map +1 -1
  34. package/lib/commonjs/components/styled/MediaFilePreview.js +60 -47
  35. package/lib/commonjs/components/styled/MediaFilePreview.js.map +1 -1
  36. package/lib/commonjs/components/styled/MessageImage.js +16 -6
  37. package/lib/commonjs/components/styled/MessageImage.js.map +1 -1
  38. package/lib/commonjs/components/styled/SendInput.js +99 -68
  39. package/lib/commonjs/components/styled/SendInput.js.map +1 -1
  40. package/lib/commonjs/components/styled/VideoMessage.js +24 -10
  41. package/lib/commonjs/components/styled/VideoMessage.js.map +1 -1
  42. package/lib/commonjs/context/xmppProvider.js +46 -0
  43. package/lib/commonjs/context/xmppProvider.js.map +1 -1
  44. package/lib/commonjs/e2ee/fileEnvelope.js +6 -0
  45. package/lib/commonjs/e2ee/fileEnvelope.js.map +1 -1
  46. package/lib/commonjs/e2ee/sealedBody.js +32 -2
  47. package/lib/commonjs/e2ee/sealedBody.js.map +1 -1
  48. package/lib/commonjs/helpers/albumLayout.js +150 -0
  49. package/lib/commonjs/helpers/albumLayout.js.map +1 -0
  50. package/lib/commonjs/helpers/attachments.js +255 -0
  51. package/lib/commonjs/helpers/attachments.js.map +1 -0
  52. package/lib/commonjs/helpers/caption.js +214 -0
  53. package/lib/commonjs/helpers/caption.js.map +1 -0
  54. package/lib/commonjs/helpers/createMainMessageForThread.js +5 -1
  55. package/lib/commonjs/helpers/createMainMessageForThread.js.map +1 -1
  56. package/lib/commonjs/helpers/createMessageFromXml.js +19 -5
  57. package/lib/commonjs/helpers/createMessageFromXml.js.map +1 -1
  58. package/lib/commonjs/helpers/fileKind.js +40 -0
  59. package/lib/commonjs/helpers/fileKind.js.map +1 -0
  60. package/lib/commonjs/helpers/getDataFromXml.js +6 -1
  61. package/lib/commonjs/helpers/getDataFromXml.js.map +1 -1
  62. package/lib/commonjs/helpers/mapWithConcurrency.js +41 -0
  63. package/lib/commonjs/helpers/mapWithConcurrency.js.map +1 -0
  64. package/lib/commonjs/helpers/mediaLimits.js +33 -0
  65. package/lib/commonjs/helpers/mediaLimits.js.map +1 -0
  66. package/lib/commonjs/helpers/mediaSendRetry.js +64 -0
  67. package/lib/commonjs/helpers/mediaSendRetry.js.map +1 -0
  68. package/lib/commonjs/helpers/mediaWireData.js +62 -0
  69. package/lib/commonjs/helpers/mediaWireData.js.map +1 -0
  70. package/lib/commonjs/helpers/mentionSpans.js +19 -0
  71. package/lib/commonjs/helpers/mentionSpans.js.map +1 -0
  72. package/lib/commonjs/helpers/mimeToExtension.js +45 -0
  73. package/lib/commonjs/helpers/mimeToExtension.js.map +1 -1
  74. package/lib/commonjs/helpers/readReceipts.js +173 -0
  75. package/lib/commonjs/helpers/readReceipts.js.map +1 -0
  76. package/lib/commonjs/helpers/repairFilenameEncoding.js +79 -0
  77. package/lib/commonjs/helpers/repairFilenameEncoding.js.map +1 -0
  78. package/lib/commonjs/helpers/safeJson.js +18 -0
  79. package/lib/commonjs/helpers/safeJson.js.map +1 -0
  80. package/lib/commonjs/hooks/useSendMessage.js +384 -193
  81. package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
  82. package/lib/commonjs/i18n/strings.js +96 -0
  83. package/lib/commonjs/i18n/strings.js.map +1 -1
  84. package/lib/commonjs/networking/api-requests/auth.api.js +62 -3
  85. package/lib/commonjs/networking/api-requests/auth.api.js.map +1 -1
  86. package/lib/commonjs/networking/stanzaHandlers.js +100 -3
  87. package/lib/commonjs/networking/stanzaHandlers.js.map +1 -1
  88. package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js +4 -2
  89. package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
  90. package/lib/commonjs/networking/xmpp/sendDisplayedMarker.xmpp.js +28 -0
  91. package/lib/commonjs/networking/xmpp/sendDisplayedMarker.xmpp.js.map +1 -0
  92. package/lib/commonjs/networking/xmpp/sendMediaMessage.xmpp.js +53 -2
  93. package/lib/commonjs/networking/xmpp/sendMediaMessage.xmpp.js.map +1 -1
  94. package/lib/commonjs/networking/xmpp/sendReceivedReceipt.xmpp.js +28 -0
  95. package/lib/commonjs/networking/xmpp/sendReceivedReceipt.xmpp.js.map +1 -0
  96. package/lib/commonjs/networking/xmppClient.js +64 -0
  97. package/lib/commonjs/networking/xmppClient.js.map +1 -1
  98. package/lib/commonjs/roomStore/persistence.js +78 -5
  99. package/lib/commonjs/roomStore/persistence.js.map +1 -1
  100. package/lib/commonjs/roomStore/roomHeapSlice.js +4 -0
  101. package/lib/commonjs/roomStore/roomHeapSlice.js.map +1 -1
  102. package/lib/commonjs/roomStore/roomsSlice.js +114 -1
  103. package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
  104. package/lib/commonjs/types/models/attachment.model.js +2 -0
  105. package/lib/commonjs/types/models/attachment.model.js.map +1 -0
  106. package/lib/commonjs/version.js +1 -1
  107. package/lib/module/assets/icons.js +1 -1
  108. package/lib/module/assets/icons.js.map +1 -1
  109. package/lib/module/components/MainComponents/AlbumGrid.js +146 -0
  110. package/lib/module/components/MainComponents/AlbumGrid.js.map +1 -0
  111. package/lib/module/components/MainComponents/ChatRoom.js +2 -2
  112. package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
  113. package/lib/module/components/MainComponents/MediaMessage.js +200 -124
  114. package/lib/module/components/MainComponents/MediaMessage.js.map +1 -1
  115. package/lib/module/components/MainComponents/MediaUploadOverlay.js +104 -0
  116. package/lib/module/components/MainComponents/MediaUploadOverlay.js.map +1 -0
  117. package/lib/module/components/MessageBubble/MediaCaption.js +46 -0
  118. package/lib/module/components/MessageBubble/MediaCaption.js.map +1 -0
  119. package/lib/module/components/MessageBubble/Message.js +44 -5
  120. package/lib/module/components/MessageBubble/Message.js.map +1 -1
  121. package/lib/module/components/MessageBubble/MessageInteractions.js +2 -1
  122. package/lib/module/components/MessageBubble/MessageInteractions.js.map +1 -1
  123. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +75 -0
  124. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  125. package/lib/module/components/RoomComponents/LastMessageItem.js +20 -4
  126. package/lib/module/components/RoomComponents/LastMessageItem.js.map +1 -1
  127. package/lib/module/components/RoomComponents/styled/LastAudioMessage.js +3 -2
  128. package/lib/module/components/RoomComponents/styled/LastAudioMessage.js.map +1 -1
  129. package/lib/module/components/RoomComponents/styled/LastMessageFile.js +3 -2
  130. package/lib/module/components/RoomComponents/styled/LastMessageFile.js.map +1 -1
  131. package/lib/module/components/RoomComponents/styled/LastMessagePhoto.js +3 -2
  132. package/lib/module/components/RoomComponents/styled/LastMessagePhoto.js.map +1 -1
  133. package/lib/module/components/RoomComponents/styled/LastMessageVideo.js +3 -2
  134. package/lib/module/components/RoomComponents/styled/LastMessageVideo.js.map +1 -1
  135. package/lib/module/components/Thread/ThreadWrapper.js +3 -2
  136. package/lib/module/components/Thread/ThreadWrapper.js.map +1 -1
  137. package/lib/module/components/styled/MediaFilePreview.js +61 -48
  138. package/lib/module/components/styled/MediaFilePreview.js.map +1 -1
  139. package/lib/module/components/styled/MessageImage.js +16 -6
  140. package/lib/module/components/styled/MessageImage.js.map +1 -1
  141. package/lib/module/components/styled/SendInput.js +99 -68
  142. package/lib/module/components/styled/SendInput.js.map +1 -1
  143. package/lib/module/components/styled/VideoMessage.js +24 -10
  144. package/lib/module/components/styled/VideoMessage.js.map +1 -1
  145. package/lib/module/context/xmppProvider.js +46 -0
  146. package/lib/module/context/xmppProvider.js.map +1 -1
  147. package/lib/module/e2ee/fileEnvelope.js +1 -1
  148. package/lib/module/e2ee/fileEnvelope.js.map +1 -1
  149. package/lib/module/e2ee/sealedBody.js +32 -2
  150. package/lib/module/e2ee/sealedBody.js.map +1 -1
  151. package/lib/module/helpers/albumLayout.js +143 -0
  152. package/lib/module/helpers/albumLayout.js.map +1 -0
  153. package/lib/module/helpers/attachments.js +245 -0
  154. package/lib/module/helpers/attachments.js.map +1 -0
  155. package/lib/module/helpers/caption.js +207 -0
  156. package/lib/module/helpers/caption.js.map +1 -0
  157. package/lib/module/helpers/createMainMessageForThread.js +5 -1
  158. package/lib/module/helpers/createMainMessageForThread.js.map +1 -1
  159. package/lib/module/helpers/createMessageFromXml.js +20 -6
  160. package/lib/module/helpers/createMessageFromXml.js.map +1 -1
  161. package/lib/module/helpers/fileKind.js +34 -0
  162. package/lib/module/helpers/fileKind.js.map +1 -0
  163. package/lib/module/helpers/getDataFromXml.js +6 -1
  164. package/lib/module/helpers/getDataFromXml.js.map +1 -1
  165. package/lib/module/helpers/mapWithConcurrency.js +37 -0
  166. package/lib/module/helpers/mapWithConcurrency.js.map +1 -0
  167. package/lib/module/helpers/mediaLimits.js +27 -0
  168. package/lib/module/helpers/mediaLimits.js.map +1 -0
  169. package/lib/module/helpers/mediaSendRetry.js +55 -0
  170. package/lib/module/helpers/mediaSendRetry.js.map +1 -0
  171. package/lib/module/helpers/mediaWireData.js +58 -0
  172. package/lib/module/helpers/mediaWireData.js.map +1 -0
  173. package/lib/module/helpers/mentionSpans.js +14 -0
  174. package/lib/module/helpers/mentionSpans.js.map +1 -0
  175. package/lib/module/helpers/mimeToExtension.js +43 -0
  176. package/lib/module/helpers/mimeToExtension.js.map +1 -1
  177. package/lib/module/helpers/readReceipts.js +160 -0
  178. package/lib/module/helpers/readReceipts.js.map +1 -0
  179. package/lib/module/helpers/repairFilenameEncoding.js +74 -0
  180. package/lib/module/helpers/repairFilenameEncoding.js.map +1 -0
  181. package/lib/module/helpers/safeJson.js +13 -0
  182. package/lib/module/helpers/safeJson.js.map +1 -0
  183. package/lib/module/hooks/useSendMessage.js +387 -195
  184. package/lib/module/hooks/useSendMessage.js.map +1 -1
  185. package/lib/module/i18n/strings.js +96 -0
  186. package/lib/module/i18n/strings.js.map +1 -1
  187. package/lib/module/networking/api-requests/auth.api.js +62 -3
  188. package/lib/module/networking/api-requests/auth.api.js.map +1 -1
  189. package/lib/module/networking/stanzaHandlers.js +97 -4
  190. package/lib/module/networking/stanzaHandlers.js.map +1 -1
  191. package/lib/module/networking/xmpp/handleStanzas.xmpp.js +5 -3
  192. package/lib/module/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
  193. package/lib/module/networking/xmpp/sendDisplayedMarker.xmpp.js +25 -0
  194. package/lib/module/networking/xmpp/sendDisplayedMarker.xmpp.js.map +1 -0
  195. package/lib/module/networking/xmpp/sendMediaMessage.xmpp.js +53 -2
  196. package/lib/module/networking/xmpp/sendMediaMessage.xmpp.js.map +1 -1
  197. package/lib/module/networking/xmpp/sendReceivedReceipt.xmpp.js +25 -0
  198. package/lib/module/networking/xmpp/sendReceivedReceipt.xmpp.js.map +1 -0
  199. package/lib/module/networking/xmppClient.js +64 -0
  200. package/lib/module/networking/xmppClient.js.map +1 -1
  201. package/lib/module/roomStore/persistence.js +78 -5
  202. package/lib/module/roomStore/persistence.js.map +1 -1
  203. package/lib/module/roomStore/roomHeapSlice.js +4 -0
  204. package/lib/module/roomStore/roomHeapSlice.js.map +1 -1
  205. package/lib/module/roomStore/roomsSlice.js +109 -0
  206. package/lib/module/roomStore/roomsSlice.js.map +1 -1
  207. package/lib/module/types/models/attachment.model.js +2 -0
  208. package/lib/module/types/models/attachment.model.js.map +1 -0
  209. package/lib/module/version.js +1 -1
  210. package/lib/typescript/assets/icons.d.ts +6 -1
  211. package/lib/typescript/assets/icons.d.ts.map +1 -1
  212. package/lib/typescript/components/MainComponents/AlbumGrid.d.ts +21 -0
  213. package/lib/typescript/components/MainComponents/AlbumGrid.d.ts.map +1 -0
  214. package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
  215. package/lib/typescript/components/MainComponents/MediaMessage.d.ts.map +1 -1
  216. package/lib/typescript/components/MainComponents/MediaUploadOverlay.d.ts +17 -0
  217. package/lib/typescript/components/MainComponents/MediaUploadOverlay.d.ts.map +1 -0
  218. package/lib/typescript/components/MessageBubble/MediaCaption.d.ts +12 -0
  219. package/lib/typescript/components/MessageBubble/MediaCaption.d.ts.map +1 -0
  220. package/lib/typescript/components/MessageBubble/Message.d.ts.map +1 -1
  221. package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts.map +1 -1
  222. package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts.map +1 -1
  223. package/lib/typescript/components/RoomComponents/LastMessageItem.d.ts.map +1 -1
  224. package/lib/typescript/components/RoomComponents/styled/LastAudioMessage.d.ts +2 -0
  225. package/lib/typescript/components/RoomComponents/styled/LastAudioMessage.d.ts.map +1 -1
  226. package/lib/typescript/components/RoomComponents/styled/LastMessageFile.d.ts +2 -0
  227. package/lib/typescript/components/RoomComponents/styled/LastMessageFile.d.ts.map +1 -1
  228. package/lib/typescript/components/RoomComponents/styled/LastMessagePhoto.d.ts +2 -0
  229. package/lib/typescript/components/RoomComponents/styled/LastMessagePhoto.d.ts.map +1 -1
  230. package/lib/typescript/components/RoomComponents/styled/LastMessageVideo.d.ts +2 -0
  231. package/lib/typescript/components/RoomComponents/styled/LastMessageVideo.d.ts.map +1 -1
  232. package/lib/typescript/components/Thread/ThreadWrapper.d.ts.map +1 -1
  233. package/lib/typescript/components/styled/MediaFilePreview.d.ts.map +1 -1
  234. package/lib/typescript/components/styled/MessageImage.d.ts +10 -0
  235. package/lib/typescript/components/styled/MessageImage.d.ts.map +1 -1
  236. package/lib/typescript/components/styled/SendInput.d.ts +7 -1
  237. package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
  238. package/lib/typescript/components/styled/VideoMessage.d.ts +7 -0
  239. package/lib/typescript/components/styled/VideoMessage.d.ts.map +1 -1
  240. package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
  241. package/lib/typescript/e2ee/fileEnvelope.d.ts +1 -1
  242. package/lib/typescript/e2ee/fileEnvelope.d.ts.map +1 -1
  243. package/lib/typescript/e2ee/sealedBody.d.ts +16 -0
  244. package/lib/typescript/e2ee/sealedBody.d.ts.map +1 -1
  245. package/lib/typescript/helpers/albumLayout.d.ts +66 -0
  246. package/lib/typescript/helpers/albumLayout.d.ts.map +1 -0
  247. package/lib/typescript/helpers/attachments.d.ts +55 -0
  248. package/lib/typescript/helpers/attachments.d.ts.map +1 -0
  249. package/lib/typescript/helpers/caption.d.ts +64 -0
  250. package/lib/typescript/helpers/caption.d.ts.map +1 -0
  251. package/lib/typescript/helpers/createMainMessageForThread.d.ts.map +1 -1
  252. package/lib/typescript/helpers/createMessageFromXml.d.ts.map +1 -1
  253. package/lib/typescript/helpers/fileKind.d.ts +20 -0
  254. package/lib/typescript/helpers/fileKind.d.ts.map +1 -0
  255. package/lib/typescript/helpers/getDataFromXml.d.ts.map +1 -1
  256. package/lib/typescript/helpers/mapWithConcurrency.d.ts +9 -0
  257. package/lib/typescript/helpers/mapWithConcurrency.d.ts.map +1 -0
  258. package/lib/typescript/helpers/mediaLimits.d.ts +13 -0
  259. package/lib/typescript/helpers/mediaLimits.d.ts.map +1 -0
  260. package/lib/typescript/helpers/mediaSendRetry.d.ts +26 -0
  261. package/lib/typescript/helpers/mediaSendRetry.d.ts.map +1 -0
  262. package/lib/typescript/helpers/mediaWireData.d.ts +16 -0
  263. package/lib/typescript/helpers/mediaWireData.d.ts.map +1 -0
  264. package/lib/typescript/helpers/mentionSpans.d.ts +8 -0
  265. package/lib/typescript/helpers/mentionSpans.d.ts.map +1 -0
  266. package/lib/typescript/helpers/mimeToExtension.d.ts +7 -0
  267. package/lib/typescript/helpers/mimeToExtension.d.ts.map +1 -1
  268. package/lib/typescript/helpers/readReceipts.d.ts +82 -0
  269. package/lib/typescript/helpers/readReceipts.d.ts.map +1 -0
  270. package/lib/typescript/helpers/repairFilenameEncoding.d.ts +12 -0
  271. package/lib/typescript/helpers/repairFilenameEncoding.d.ts.map +1 -0
  272. package/lib/typescript/helpers/safeJson.d.ts +2 -0
  273. package/lib/typescript/helpers/safeJson.d.ts.map +1 -0
  274. package/lib/typescript/hooks/useSendMessage.d.ts +2 -1
  275. package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
  276. package/lib/typescript/i18n/strings.d.ts.map +1 -1
  277. package/lib/typescript/networking/api-requests/auth.api.d.ts +2 -0
  278. package/lib/typescript/networking/api-requests/auth.api.d.ts.map +1 -1
  279. package/lib/typescript/networking/stanzaHandlers.d.ts +7 -3
  280. package/lib/typescript/networking/stanzaHandlers.d.ts.map +1 -1
  281. package/lib/typescript/networking/xmpp/handleStanzas.xmpp.d.ts.map +1 -1
  282. package/lib/typescript/networking/xmpp/sendDisplayedMarker.xmpp.d.ts +3 -0
  283. package/lib/typescript/networking/xmpp/sendDisplayedMarker.xmpp.d.ts.map +1 -0
  284. package/lib/typescript/networking/xmpp/sendMediaMessage.xmpp.d.ts +12 -0
  285. package/lib/typescript/networking/xmpp/sendMediaMessage.xmpp.d.ts.map +1 -1
  286. package/lib/typescript/networking/xmpp/sendReceivedReceipt.xmpp.d.ts +3 -0
  287. package/lib/typescript/networking/xmpp/sendReceivedReceipt.xmpp.d.ts.map +1 -0
  288. package/lib/typescript/networking/xmppClient.d.ts +15 -0
  289. package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
  290. package/lib/typescript/roomStore/persistence.d.ts.map +1 -1
  291. package/lib/typescript/roomStore/roomHeapSlice.d.ts +22 -1
  292. package/lib/typescript/roomStore/roomHeapSlice.d.ts.map +1 -1
  293. package/lib/typescript/roomStore/roomsSlice.d.ts +67 -3
  294. package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
  295. package/lib/typescript/types/models/attachment.model.d.ts +52 -0
  296. package/lib/typescript/types/models/attachment.model.d.ts.map +1 -0
  297. package/lib/typescript/types/models/message.model.d.ts +26 -0
  298. package/lib/typescript/types/models/message.model.d.ts.map +1 -1
  299. package/lib/typescript/types/models/modal.model.d.ts +7 -0
  300. package/lib/typescript/types/models/modal.model.d.ts.map +1 -1
  301. package/lib/typescript/types/models/room.model.d.ts +2 -0
  302. package/lib/typescript/types/models/room.model.d.ts.map +1 -1
  303. package/lib/typescript/types/types.d.ts +29 -1
  304. package/lib/typescript/types/types.d.ts.map +1 -1
  305. package/lib/typescript/version.d.ts +1 -1
  306. package/package.json +4 -1
  307. package/plugins/notification-service/Info.plist +31 -0
  308. package/plugins/notification-service/NotificationService.swift +82 -0
  309. package/plugins/withNotificationServiceExtension.js +137 -0
  310. package/src/assets/icons.tsx +20 -2
  311. package/src/components/MainComponents/AlbumGrid.tsx +183 -0
  312. package/src/components/MainComponents/ChatRoom.tsx +4 -2
  313. package/src/components/MainComponents/MediaMessage.tsx +246 -130
  314. package/src/components/MainComponents/MediaUploadOverlay.tsx +102 -0
  315. package/src/components/MessageBubble/MediaCaption.tsx +45 -0
  316. package/src/components/MessageBubble/Message.tsx +71 -3
  317. package/src/components/MessageBubble/MessageInteractions.tsx +2 -1
  318. package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +64 -0
  319. package/src/components/RoomComponents/LastMessageItem.tsx +15 -4
  320. package/src/components/RoomComponents/styled/LastAudioMessage.tsx +6 -3
  321. package/src/components/RoomComponents/styled/LastMessageFile.tsx +6 -2
  322. package/src/components/RoomComponents/styled/LastMessagePhoto.tsx +6 -2
  323. package/src/components/RoomComponents/styled/LastMessageVideo.tsx +6 -2
  324. package/src/components/Thread/ThreadWrapper.tsx +5 -9
  325. package/src/components/styled/MediaFilePreview.tsx +49 -34
  326. package/src/components/styled/MessageImage.tsx +21 -5
  327. package/src/components/styled/SendInput.tsx +101 -87
  328. package/src/components/styled/VideoMessage.tsx +34 -9
  329. package/src/context/xmppProvider.tsx +32 -0
  330. package/src/e2ee/fileEnvelope.ts +1 -1
  331. package/src/e2ee/sealedBody.ts +44 -5
  332. package/src/helpers/albumLayout.ts +207 -0
  333. package/src/helpers/attachments.ts +316 -0
  334. package/src/helpers/caption.ts +283 -0
  335. package/src/helpers/createMainMessageForThread.ts +6 -1
  336. package/src/helpers/createMessageFromXml.ts +21 -5
  337. package/src/helpers/fileKind.ts +38 -0
  338. package/src/helpers/getDataFromXml.ts +5 -1
  339. package/src/helpers/mapWithConcurrency.ts +32 -0
  340. package/src/helpers/mediaLimits.ts +27 -0
  341. package/src/helpers/mediaSendRetry.ts +59 -0
  342. package/src/helpers/mediaWireData.ts +57 -0
  343. package/src/helpers/mentionSpans.ts +17 -0
  344. package/src/helpers/mimeToExtension.ts +51 -0
  345. package/src/helpers/readReceipts.ts +219 -0
  346. package/src/helpers/repairFilenameEncoding.ts +82 -0
  347. package/src/helpers/safeJson.ts +11 -0
  348. package/src/hooks/useSendMessage.tsx +448 -249
  349. package/src/i18n/strings.ts +96 -0
  350. package/src/networking/api-requests/auth.api.ts +60 -3
  351. package/src/networking/stanzaHandlers.ts +91 -2
  352. package/src/networking/xmpp/handleStanzas.xmpp.ts +6 -2
  353. package/src/networking/xmpp/sendDisplayedMarker.xmpp.ts +31 -0
  354. package/src/networking/xmpp/sendMediaMessage.xmpp.ts +60 -3
  355. package/src/networking/xmpp/sendReceivedReceipt.xmpp.ts +31 -0
  356. package/src/networking/xmppClient.ts +48 -0
  357. package/src/roomStore/persistence.ts +94 -3
  358. package/src/roomStore/roomHeapSlice.ts +23 -1
  359. package/src/roomStore/roomsSlice.ts +112 -1
  360. package/src/types/models/attachment.model.ts +51 -0
  361. package/src/types/models/message.model.ts +29 -0
  362. package/src/types/models/modal.model.ts +7 -0
  363. package/src/types/models/room.model.ts +2 -0
  364. package/src/types/types.ts +35 -1
  365. package/src/version.ts +1 -1
@@ -17,6 +17,8 @@ import {
17
17
  } from './xmpp/getHistory.xmpp';
18
18
  import { sendTextMessage } from './xmpp/sendTextMessage.xmpp';
19
19
  import { sendMessageReaction } from './xmpp/sendMessageReaction.xmpp';
20
+ import { sendReceivedReceipt } from './xmpp/sendReceivedReceipt.xmpp';
21
+ import { sendDisplayedMarker } from './xmpp/sendDisplayedMarker.xmpp';
20
22
  import { sendTextMessageWithTranslateTag } from './xmpp/sendTextMessageWithTranslateTag.xmpp';
21
23
  import { deleteMessage } from './xmpp/deleteMessage.xmpp';
22
24
  import { RoomJoinManager } from './xmpp/roomJoinSweep';
@@ -48,6 +50,8 @@ import {
48
50
 
49
51
  // Canonical production XMPP WSS endpoint (standard wss/443, no port suffix).
50
52
  const DEFAULT_DEV_SERVER = 'xmpp.chat.ethora.com';
53
+ // Upper bound on remembered XEP-0184 acks (oldest forgotten first).
54
+ const RECEIPT_ACKED_CAP = 2000;
51
55
 
52
56
  // How long to wait for the old client's stop() during a reconnect before
53
57
  // giving up on it. Short on purpose: we are already tearing this client
@@ -279,6 +283,13 @@ export class XmppClient {
279
283
  }
280
284
  disableLastRead = false;
281
285
  private activeRoomJID: string | null = null;
286
+ // XEP-0184 acks already sent, as `room:messageId`. A message is acked once,
287
+ // whether it arrived live or again inside a MAM page. Oldest entries drop
288
+ // first once the set passes the cap.
289
+ private receiptAckedIds: Set<string> = new Set();
290
+ // XEP-0333: the last read watermark sent per room. A repeat flush for the
291
+ // same newest message sends nothing.
292
+ private lastWatermarkSentByRoom: Map<string, string> = new Map();
282
293
  private activeRoomBoostUntil = 0;
283
294
  private softPauseUntil = 0;
284
295
  private mamInFlightByRoom: Map<string, MamInFlightEntry> = new Map();
@@ -1594,6 +1605,43 @@ export class XmppClient {
1594
1605
  return typeof result === 'string' ? result : '';
1595
1606
  }
1596
1607
 
1608
+ /**
1609
+ * XEP-0184 delivery receipt for a message from someone else. Sent for live
1610
+ * messages and for messages a MAM page brings in; a message already acked
1611
+ * is skipped. When the stream is down (or `config.disableReadReceipts` is
1612
+ * on) nothing is recorded, so a later page can still ack it.
1613
+ */
1614
+ sendReceivedReceiptStanza(messageId: string, roomJid: string) {
1615
+ // Privacy switch: with read receipts off this client stays silent, so
1616
+ // nobody learns that (or when) it received their message.
1617
+ if (store.getState().chatSettingStore.config?.disableReadReceipts) {return;}
1618
+ if (!messageId || !roomJid || !this.isStreamReady()) {return;}
1619
+ const jid = normalizeRoomJid(roomJid, this.conference);
1620
+ const key = `${jid}:${messageId}`;
1621
+ if (this.receiptAckedIds.has(key)) {return;}
1622
+ this.receiptAckedIds.add(key);
1623
+ if (this.receiptAckedIds.size > RECEIPT_ACKED_CAP) {
1624
+ const oldest = this.receiptAckedIds.values().next().value;
1625
+ if (oldest !== undefined) {this.receiptAckedIds.delete(oldest);}
1626
+ }
1627
+ sendReceivedReceipt(this.client, messageId, jid);
1628
+ }
1629
+
1630
+ /**
1631
+ * XEP-0333 read watermark for a room: the newest message the user has
1632
+ * displayed. Off with `disableLastRead` or `config.disableReadReceipts`.
1633
+ * The caller decides when the room counts as read (see computeReadWatermark).
1634
+ */
1635
+ sendDisplayedMarkerStanza(messageId: string, roomJid: string) {
1636
+ if (this.disableLastRead) {return;}
1637
+ if (store.getState().chatSettingStore.config?.disableReadReceipts) {return;}
1638
+ if (!messageId || !roomJid || !this.isStreamReady()) {return;}
1639
+ const jid = normalizeRoomJid(roomJid, this.conference);
1640
+ if (this.lastWatermarkSentByRoom.get(jid) === messageId) {return;}
1641
+ this.lastWatermarkSentByRoom.set(jid, messageId);
1642
+ sendDisplayedMarker(this.client, messageId, jid);
1643
+ }
1644
+
1597
1645
  sendMessageReactionStanza(
1598
1646
  messageId: string,
1599
1647
  roomJid: string,
@@ -1,6 +1,6 @@
1
1
  import { Middleware } from '@reduxjs/toolkit';
2
2
  import { IMessage, IRoom, User } from '../types/types';
3
- import type { FailedMessagePayload } from './roomHeapSlice';
3
+ import type { FailedMediaFile, FailedMessagePayload } from './roomHeapSlice';
4
4
  import {
5
5
  getPersistBackend,
6
6
  legacyAsyncStorageBackend,
@@ -107,6 +107,11 @@ const PERSISTED_MESSAGE_FIELDS: (keyof IMessage)[] = [
107
107
  'fileName',
108
108
  'originalName',
109
109
  'size',
110
+ // Every file of a multi-attach message and its caption: without them a
111
+ // restored album paints as its first file only (see compactAttachments).
112
+ 'attachments',
113
+ 'caption',
114
+ 'captionMentions',
110
115
  'langSource',
111
116
  // `translations` MUST be here. A previous version of this list dropped
112
117
  // it, on the theory that it mirrored the web SDK's persist contract —
@@ -185,8 +190,45 @@ const pickDefined = <T extends object>(
185
190
  return out;
186
191
  };
187
192
 
193
+ // What a restored attachment is rendered from. Ownership and timestamp
194
+ // fields the storage returns, and the sender's local upload state, are not
195
+ // ours to cache and would repeat across up to ten files of every message.
196
+ const PERSISTED_ATTACHMENT_FIELDS = [
197
+ 'attachmentId',
198
+ 'location',
199
+ 'locationPreview',
200
+ 'mimetype',
201
+ 'originalName',
202
+ 'fileName',
203
+ 'size',
204
+ 'duration',
205
+ 'width',
206
+ 'height',
207
+ ] as const;
208
+
209
+ const compactAttachments = (attachments: unknown): IMessage['attachments'] => {
210
+ if (!Array.isArray(attachments) || attachments.length === 0) {return undefined;}
211
+ return attachments
212
+ .filter((item) => item && typeof item === 'object')
213
+ .map(
214
+ (item) =>
215
+ pickDefined(
216
+ item,
217
+ PERSISTED_ATTACHMENT_FIELDS as unknown as readonly string[]
218
+ ) as NonNullable<IMessage['attachments']>[number]
219
+ );
220
+ };
221
+
188
222
  const compactMessageForPersist = (message: IMessage): IMessage => {
189
223
  const compact = pickDefined(message, PERSISTED_MESSAGE_FIELDS) as IMessage;
224
+ if (compact.attachments !== undefined) {
225
+ const attachments = compactAttachments(compact.attachments);
226
+ if (attachments) {
227
+ compact.attachments = attachments;
228
+ } else {
229
+ delete compact.attachments;
230
+ }
231
+ }
190
232
  const user = message?.user as Record<string, any> | undefined;
191
233
  if (user) {
192
234
  compact.user = pickDefined(
@@ -209,11 +251,17 @@ const sanitizeMessages = (messages: IMessage[]): IMessage[] => {
209
251
  /**
210
252
  * Room fields that describe ONE session and must never be written to disk:
211
253
  * the server's unread snapshot (a moment-in-time number the next /chats/my
212
- * re-seeds). Volatile slice state that is not on the room at all (jumpWindow,
254
+ * re-seeds) and the read watermarks other occupants sent this session. Volatile slice state that is not on the room at all (jumpWindow,
213
255
  * pendingJump, archivedMessage, usersSet) is never persisted because only
214
256
  * `rooms.rooms` is picked from the slice.
215
257
  */
216
- const SESSION_ROOM_FIELDS = ['apiUnreadCount', 'apiUnreadSeededAt'] as const;
258
+ const SESSION_ROOM_FIELDS = [
259
+ 'apiUnreadCount',
260
+ 'apiUnreadSeededAt',
261
+ // XEP-0333 read watermarks: a peer's "seen" state is re-learned from the
262
+ // live marker stanzas, never restored from a previous session.
263
+ 'lastDisplayedByUser',
264
+ ] as const;
217
265
 
218
266
  /**
219
267
  * Rehydrate step: a persisted room must be refetched once per session, so
@@ -303,6 +351,21 @@ const sanitizeMediaData = (
303
351
  return out;
304
352
  };
305
353
 
354
+ // Every file of a multi-file failed send, trimmed the same way as `data`.
355
+ // Capped so a corrupt payload cannot grow the cache without bound.
356
+ const MAX_PERSISTED_FAILED_FILES = 10;
357
+ const sanitizeMediaFiles = (files: unknown): FailedMediaFile[] | undefined => {
358
+ if (!Array.isArray(files)) {return undefined;}
359
+ const out: FailedMediaFile[] = [];
360
+ for (const file of files.slice(0, MAX_PERSISTED_FAILED_FILES)) {
361
+ const clean = sanitizeMediaData(file) as FailedMediaFile;
362
+ if (typeof (file as any)?.duration === 'number') {clean.duration = (file as any).duration;}
363
+ if (typeof (file as any)?.waveForm === 'string') {clean.waveForm = (file as any).waveForm;}
364
+ out.push(clean);
365
+ }
366
+ return out.length > 0 ? out : undefined;
367
+ };
368
+
306
369
  const sanitizeFailedMessagePayload = (
307
370
  payload: FailedMessagePayload
308
371
  ): FailedMessagePayload | null => {
@@ -310,6 +373,8 @@ const sanitizeFailedMessagePayload = (
310
373
  if (!payload.id || typeof payload.id !== 'string') {return null;}
311
374
  if (!payload.roomJID || typeof payload.roomJID !== 'string') {return null;}
312
375
  if (payload.kind === 'media') {
376
+ const files = sanitizeMediaFiles(payload.files);
377
+ const caption = typeof payload.caption === 'string' ? payload.caption : undefined;
313
378
  return {
314
379
  kind: 'media',
315
380
  id: payload.id,
@@ -319,6 +384,11 @@ const sanitizeFailedMessagePayload = (
319
384
  isReply: payload.isReply,
320
385
  isChecked: payload.isChecked,
321
386
  mainMessage: payload.mainMessage,
387
+ ...(files ? { files } : {}),
388
+ ...(caption ? { caption } : {}),
389
+ ...(caption && Array.isArray(payload.captionMentions)
390
+ ? { captionMentions: payload.captionMentions }
391
+ : {}),
322
392
  };
323
393
  }
324
394
  if (payload.kind === 'text') {
@@ -377,6 +447,25 @@ export function reconstructFailedMessagePayload(
377
447
  const isChecked = message.showInChannel === 'true';
378
448
  const mainMessage = message.mainMessage;
379
449
  if (message.isMediafile === 'true') {
450
+ // A multi-file send keeps every file. Only a file still on this device
451
+ // has a uri to replay; an uploaded one has no local copy left to send.
452
+ const localUri = (value: unknown): string | undefined =>
453
+ typeof value === 'string' && /^(file|content|ph|assets-library):\/\//.test(value)
454
+ ? value
455
+ : undefined;
456
+ const attachments = Array.isArray(message.attachments) ? message.attachments : [];
457
+ const files: FailedMediaFile[] | undefined =
458
+ attachments.length > 1
459
+ ? attachments.slice(0, MAX_PERSISTED_FAILED_FILES).map((attachment) => ({
460
+ uri: localUri(attachment.localUrl) ?? localUri(attachment.location),
461
+ name: attachment.originalName || attachment.fileName,
462
+ type: attachment.mimetype,
463
+ size:
464
+ attachment.size !== undefined && attachment.size !== null
465
+ ? Number(attachment.size)
466
+ : undefined,
467
+ }))
468
+ : undefined;
380
469
  return {
381
470
  kind: 'media',
382
471
  id: message.id,
@@ -394,6 +483,8 @@ export function reconstructFailedMessagePayload(
394
483
  isReply,
395
484
  isChecked,
396
485
  mainMessage,
486
+ ...(files ? { files } : {}),
487
+ ...(message.caption ? { caption: message.caption } : {}),
397
488
  };
398
489
  }
399
490
  return {
@@ -1,11 +1,24 @@
1
1
  import { createSlice, PayloadAction, type Slice } from '@reduxjs/toolkit';
2
2
  import type { WritableDraft } from 'immer';
3
- import { IMessage } from '../types/types';
3
+ import { IMentionSpan, IMessage } from '../types/types';
4
4
 
5
5
  // Saved alongside a failed-message id so the retry button can resend
6
6
  // without the bubble needing to remember the original draft itself.
7
7
  // `kind === 'text'` carries the plain body; `kind === 'media'` carries
8
8
  // the upload payload so we don't have to make the user re-pick the file.
9
+ /**
10
+ * One file of a failed media send, as the retry replays it. Only the fields
11
+ * an upload needs, so it persists as a plain JSON object.
12
+ */
13
+ export interface FailedMediaFile {
14
+ uri?: string;
15
+ type?: string;
16
+ name?: string;
17
+ size?: number;
18
+ duration?: number;
19
+ waveForm?: string;
20
+ }
21
+
9
22
  export type FailedMessagePayload =
10
23
  | {
11
24
  kind: 'text';
@@ -20,11 +33,20 @@ export type FailedMessagePayload =
20
33
  kind: 'media';
21
34
  id: string;
22
35
  roomJID: string;
36
+ /** The first file (or the only one); kept for single-file readers. */
23
37
  data: any;
24
38
  type: string;
25
39
  isReply?: boolean;
26
40
  isChecked?: boolean;
27
41
  mainMessage?: string;
42
+ /**
43
+ * Every file of the message, in selection order. Retry replays the
44
+ * whole list; a message with no list falls back to `data`.
45
+ */
46
+ files?: FailedMediaFile[];
47
+ /** The caption the files were sent with, if any. */
48
+ caption?: string;
49
+ captionMentions?: IMentionSpan[];
28
50
  };
29
51
 
30
52
  export interface roomHeapSliceState {
@@ -1,6 +1,6 @@
1
1
  import { createAsyncThunk, createSlice, PayloadAction, type Slice } from '@reduxjs/toolkit';
2
2
  import type { WritableDraft } from 'immer';
3
- import { EditAction, HistoryPreloadState, IMessage, IRoom } from '../types/types';
3
+ import { EditAction, HistoryPreloadState, IAttachment, IMessage, IRoom } from '../types/types';
4
4
  import { insertMessageWithDelimiter } from '../helpers/insertMessageWithDelimiter';
5
5
  import { msgSortableMs } from '../helpers/msgSortableMs';
6
6
  import type XmppClient from '../networking/xmppClient';
@@ -955,6 +955,66 @@ const reducers = {
955
955
  message.translations[locale] = entry;
956
956
  });
957
957
  },
958
+ /**
959
+ * Local upload state of one file of an outgoing media message: its
960
+ * `uploadStatus` ('uploading' | 'failed') and `uploadProgress` (0-100).
961
+ * `null` for `uploadStatus` clears both, once the file is up. Matches the
962
+ * message in the room and in the jump window, like the other patches.
963
+ * Never persisted: the persist whitelist drops these fields.
964
+ */
965
+ setMediaUploadState(
966
+ state: WritableDraft<RoomMessagesState>,
967
+ action: PayloadAction<{
968
+ roomJID: string;
969
+ messageId: string;
970
+ attachmentId: string;
971
+ uploadStatus?: 'uploading' | 'failed' | null;
972
+ uploadProgress?: number;
973
+ }>
974
+ ) {
975
+ const { roomJID, messageId, attachmentId, uploadStatus, uploadProgress } =
976
+ action.payload;
977
+ if (!isSafeKey(roomJID) || !isSafeKey(messageId) || !isSafeKey(attachmentId)) {
978
+ return;
979
+ }
980
+ forEachMessageCopy(state, roomJID, messageId, (message) => {
981
+ const target = message.attachments?.find(
982
+ (attachment) => attachment.attachmentId === attachmentId
983
+ );
984
+ if (!target) {return;}
985
+ if (uploadStatus === null) {
986
+ delete target.uploadStatus;
987
+ delete target.uploadProgress;
988
+ return;
989
+ }
990
+ if (uploadStatus !== undefined) {target.uploadStatus = uploadStatus;}
991
+ if (typeof uploadProgress === 'number' && Number.isFinite(uploadProgress)) {
992
+ target.uploadProgress = Math.min(100, Math.max(0, uploadProgress));
993
+ }
994
+ });
995
+ },
996
+ /**
997
+ * Replaces the attachments of a message the sender already has, without
998
+ * touching its other fields: `pending` stays as it is, so the bubble is
999
+ * still waiting for the server echo. (addRoomMessage would count this as
1000
+ * the echo and clear `pending`.)
1001
+ */
1002
+ setMessageAttachments(
1003
+ state: WritableDraft<RoomMessagesState>,
1004
+ action: PayloadAction<{
1005
+ roomJID: string;
1006
+ messageId: string;
1007
+ attachments: IAttachment[];
1008
+ }>
1009
+ ) {
1010
+ const { roomJID, messageId, attachments } = action.payload;
1011
+ if (!isSafeKey(roomJID) || !isSafeKey(messageId) || !Array.isArray(attachments)) {
1012
+ return;
1013
+ }
1014
+ forEachMessageCopy(state, roomJID, messageId, (message) => {
1015
+ message.attachments = attachments.map((attachment) => ({ ...attachment }));
1016
+ });
1017
+ },
958
1018
  addRoomMessage(
959
1019
  state: WritableDraft<RoomMessagesState>,
960
1020
  action: PayloadAction<{
@@ -1412,6 +1472,53 @@ const reducers = {
1412
1472
  list.push({ from, reactions, data, ts: latestReactionTimestamp });
1413
1473
  }
1414
1474
  },
1475
+ /**
1476
+ * XEP-0184: an occupant's client acknowledged one of our messages. Only
1477
+ * the message id is matched (archive ids), on the live list and on a jump
1478
+ * window copy. Session-only: not persisted.
1479
+ */
1480
+ setReceivedReceipt: (
1481
+ state: WritableDraft<RoomMessagesState>,
1482
+ action: PayloadAction<{
1483
+ roomJID: string;
1484
+ messageId: string;
1485
+ fromXmppUsername: string;
1486
+ timestamp: number;
1487
+ }>
1488
+ ) => {
1489
+ const { roomJID, messageId, fromXmppUsername, timestamp } = action.payload;
1490
+ // Both keys become property names: an unsafe key must never reach the write.
1491
+ if (!isSafeKey(roomJID) || !isSafeKey(fromXmppUsername)) {return;}
1492
+ if (!state.rooms[roomJID] || !messageId) {return;}
1493
+ forEachMessageCopy(
1494
+ state,
1495
+ roomJID,
1496
+ (message) => message.id === messageId,
1497
+ (message) => {
1498
+ if (!message.receivedBy) {message.receivedBy = {};}
1499
+ message.receivedBy[fromXmppUsername] = timestamp;
1500
+ }
1501
+ );
1502
+ },
1503
+ /**
1504
+ * XEP-0333: an occupant displayed up to `messageId`. One watermark per
1505
+ * user and room, replaced on every marker. Session-only: not persisted.
1506
+ */
1507
+ setDisplayedMarker: (
1508
+ state: WritableDraft<RoomMessagesState>,
1509
+ action: PayloadAction<{
1510
+ roomJID: string;
1511
+ xmppUsername: string;
1512
+ messageId: string;
1513
+ }>
1514
+ ) => {
1515
+ const { roomJID, xmppUsername, messageId } = action.payload;
1516
+ if (!isSafeKey(roomJID) || !isSafeKey(xmppUsername)) {return;}
1517
+ const room = state.rooms[roomJID];
1518
+ if (!room || !messageId) {return;}
1519
+ if (!room.lastDisplayedByUser) {room.lastDisplayedByUser = {};}
1520
+ room.lastDisplayedByUser[xmppUsername] = messageId;
1521
+ },
1415
1522
  setLogoutState: (state: WritableDraft<RoomMessagesState>) => {
1416
1523
  state.rooms = {};
1417
1524
  state.pendingReactions = {};
@@ -1640,6 +1747,8 @@ export const {
1640
1747
  deleteAllRooms,
1641
1748
  setRoomMessages,
1642
1749
  addRoomMessage,
1750
+ setMediaUploadState,
1751
+ setMessageAttachments,
1643
1752
  deleteRoomMessage,
1644
1753
  setEditAction,
1645
1754
  editRoomMessage,
@@ -1671,6 +1780,8 @@ export const {
1671
1780
  setJoiningRoom,
1672
1781
  clearJoiningRoom,
1673
1782
  setReactions,
1783
+ setReceivedReceipt,
1784
+ setDisplayedMarker,
1674
1785
  mergeUsersSet,
1675
1786
  removeRoomMessage,
1676
1787
  addRoomFromApi,
@@ -0,0 +1,51 @@
1
+ /**
2
+ * One uploaded file carried by a media message.
3
+ *
4
+ * Historically a media message described exactly one file through flat
5
+ * `IMessage` fields (`location`, `mimetype`, `originalName`, ...). Those
6
+ * fields are still written (they are what every already-shipped client
7
+ * reads), and they now double as attachment #0 of `IMessage.attachments`.
8
+ * Anything past #0 only exists in the `attachments` payload, so old clients
9
+ * degrade to "shows the first file" instead of breaking.
10
+ */
11
+ export interface IAttachment {
12
+ /** `_id` returned by POST /files/ - stable per upload, used as a render key. */
13
+ attachmentId?: string;
14
+ /** Canonical file URL. */
15
+ location: string;
16
+ /** Server-side generated preview (images always, other types sometimes). */
17
+ locationPreview?: string;
18
+ mimetype?: string;
19
+ /** Name the user picked. */
20
+ originalName?: string;
21
+ /** Name on the storage side. */
22
+ fileName?: string;
23
+ /** Bytes, as a string - that is how it travels on the wire. */
24
+ size?: string;
25
+ duration?: string;
26
+ /** Natural pixel size, when the storage recorded it. */
27
+ width?: number;
28
+ height?: number;
29
+ ownerKey?: string;
30
+ userId?: string;
31
+ createdAt?: string;
32
+ updatedAt?: string;
33
+ expiresAt?: string;
34
+ isVisible?: boolean;
35
+ isPrivate?: boolean;
36
+ /**
37
+ * Local-only state of an outgoing attachment, set by the sender while its
38
+ * message is still being sent. Never written to the wire.
39
+ * uploading - the file is going up (or every file is up and the message
40
+ * is waiting on its siblings); `uploadProgress` is 0 to 100.
41
+ * failed - this file did not upload; the message is held until it
42
+ * is retried.
43
+ */
44
+ uploadStatus?: 'uploading' | 'failed';
45
+ uploadProgress?: number;
46
+ /**
47
+ * The file as it is on this device (`file://`), shown on the sender's own
48
+ * bubble while it uploads. Local only, like the upload state above.
49
+ */
50
+ localUrl?: string;
51
+ }
@@ -1,6 +1,7 @@
1
1
  import { IUser } from './user.model';
2
2
  import { TranslationObject } from '../../helpers/transformTranslatations';
3
3
  import { Iso639_1Codes } from './language.model';
4
+ import type { IAttachment } from './attachment.model';
4
5
 
5
6
  export interface IMessage {
6
7
  id: string;
@@ -35,6 +36,25 @@ export interface IMessage {
35
36
  langSource?: Iso639_1Codes;
36
37
  originalName?: string;
37
38
  size?: string;
39
+ /**
40
+ * Every file carried by this message. `attachments[0]` mirrors the flat
41
+ * `location`/`mimetype`/`originalName` fields above. Undefined on messages
42
+ * that predate multi-attach; read it through `getMessageAttachments()`.
43
+ */
44
+ attachments?: IAttachment[];
45
+ /**
46
+ * Text sent with a media message's files. `body` stays "media". In a sealed
47
+ * message it comes out of the encrypted body, never from `<data>`. Read it
48
+ * through `getMessageCaption()`.
49
+ */
50
+ caption?: string;
51
+ /** @-mention spans into `caption`. Stored, not rendered on RN. */
52
+ captionMentions?: IMentionSpan[];
53
+ /**
54
+ * XEP-0184 delivery receipts: xmpp username -> epoch ms when that
55
+ * occupant's client acknowledged the message. Session-only (never persisted).
56
+ */
57
+ receivedBy?: Record<string, number>;
38
58
  xmppId?: string;
39
59
  xmppFrom?: string;
40
60
  deleted?: boolean;
@@ -52,6 +72,15 @@ export interface IMessage {
52
72
  };
53
73
  }
54
74
 
75
+ // One @-mention span inside a caption (or text body). `offset`/`length` index
76
+ // into that string in UTF-16 code units.
77
+ export interface IMentionSpan {
78
+ jid: string;
79
+ name: string;
80
+ offset: number;
81
+ length: number;
82
+ }
83
+
55
84
  export interface ReactionMessage {
56
85
  emoji: string[];
57
86
  data: Record<string, string> | undefined;
@@ -9,4 +9,11 @@ export interface ModalFile {
9
9
  originalName?: string;
10
10
  duration?: number | string;
11
11
  waveForm?: string;
12
+ /**
13
+ * The other files of the album this one was opened from, this one
14
+ * included, in order. With `index` it lets the viewer page through them.
15
+ */
16
+ siblings?: ModalFile[];
17
+ /** Position of this file in `siblings`. */
18
+ index?: number;
12
19
  }
@@ -52,6 +52,8 @@ export interface IRoom {
52
52
  composing?: boolean;
53
53
  composingList?: string[];
54
54
  lastViewedTimestamp?: number;
55
+ /** XEP-0333 read watermark per user (last displayed message id). Session-only. */
56
+ lastDisplayedByUser?: Record<string, string>;
55
57
  unreadMessages?: number;
56
58
  /**
57
59
  * Unread count the server reported for this room in `GET /v1/chats/my`
@@ -43,6 +43,11 @@ export interface IRoom {
43
43
  composing?: boolean;
44
44
  composingList?: string[];
45
45
  lastViewedTimestamp?: number;
46
+ /**
47
+ * XEP-0333 read watermark per user: the id of the newest message each other
48
+ * occupant has displayed. Session-only (never persisted). See readReceipts.ts.
49
+ */
50
+ lastDisplayedByUser?: Record<string, string>;
46
51
  unreadMessages?: number;
47
52
  /**
48
53
  * Unread count the server reported for this room in `GET /v1/chats/my`
@@ -473,6 +478,15 @@ export interface IConfig {
473
478
  };
474
479
  disableHeader?: boolean;
475
480
  disableMedia?: boolean;
481
+ /**
482
+ * Limits for files picked in the composer. One message carries up to
483
+ * `maxFiles` files (hard ceiling 10, the default); `maxSizeMB` lowers the
484
+ * per-file cap below the built-in 50 MB upload limit.
485
+ */
486
+ attachments?: {
487
+ maxFiles?: number;
488
+ maxSizeMB?: number;
489
+ };
476
490
  /**
477
491
  * Enable in-chat voice-message recording. **Opt-in — off by default.**
478
492
  * When `true`, an idle input (no text, no attachments) shows a
@@ -580,6 +594,12 @@ export interface IConfig {
580
594
  // ----- xmpp / QoS -----
581
595
  xmppSettings?: xmppSettingsInterface;
582
596
  disableLastRead?: boolean;
597
+ /**
598
+ * Stops this client from sending receipts: both the XEP-0184 delivery
599
+ * receipt and the XEP-0333 read marker, so other members see neither
600
+ * "delivered" nor "seen" for what this reader gets. Default false.
601
+ */
602
+ disableReadReceipts?: boolean;
583
603
  historyQoS?: HistoryQoSConfig;
584
604
  /**
585
605
  * Background history preload for the room list.
@@ -1129,13 +1149,27 @@ export interface ModalFile {
1129
1149
  originalName?: string;
1130
1150
  duration?: number | string;
1131
1151
  waveForm?: string;
1152
+ /**
1153
+ * The other files of the album this one was opened from, this one
1154
+ * included, in order. With `index` it lets the viewer page through them.
1155
+ */
1156
+ siblings?: ModalFile[];
1157
+ /** Position of this file in `siblings`. */
1158
+ index?: number;
1132
1159
  }
1133
1160
 
1134
1161
  // Re-export so middleware/hooks that historically import from `types`
1135
1162
  // keep working without reaching into `types/models/...`.
1136
1163
  export type { ReactionAction } from './models/action.model';
1137
1164
  export type { Iso639_1Codes } from './models/language.model';
1138
- export type { IMessage, IReply, LastMessage, ReactionMessage } from './models/message.model';
1165
+ export type {
1166
+ IMessage,
1167
+ IReply,
1168
+ LastMessage,
1169
+ ReactionMessage,
1170
+ IMentionSpan,
1171
+ } from './models/message.model';
1172
+ export type { IAttachment } from './models/attachment.model';
1139
1173
  export type { RoomMember, ApiRoom, ChatAccessOption } from './models/room.model';
1140
1174
  export type { MediaFile } from './models/media.model';
1141
1175
  export type { TranslationObject } from '../helpers/transformTranslatations';
package/src/version.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  // Generated by scripts/sync-version.mjs on `npm version`.
2
2
  // Edit package.json's version instead of this file.
3
- export const ETHORA_CHAT_COMPONENT_VERSION = '26.10.5';
3
+ export const ETHORA_CHAT_COMPONENT_VERSION = '26.10.6';