@ethora/chat-component-rn 26.7.8 → 26.7.10

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 (232) hide show
  1. package/CHANGELOG.md +3 -2
  2. package/README.md +10 -0
  3. package/lib/commonjs/assets/icons.js +2 -2
  4. package/lib/commonjs/assets/icons.js.map +1 -1
  5. package/lib/commonjs/components/MainComponents/ChatRoom.js +76 -19
  6. package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
  7. package/lib/commonjs/components/MainComponents/MediaMessage.js +8 -5
  8. package/lib/commonjs/components/MainComponents/MediaMessage.js.map +1 -1
  9. package/lib/commonjs/components/MainComponents/MessageContainer.js +5 -1
  10. package/lib/commonjs/components/MainComponents/MessageContainer.js.map +1 -1
  11. package/lib/commonjs/components/MainComponents/MessageList.js +2 -1
  12. package/lib/commonjs/components/MainComponents/MessageList.js.map +1 -1
  13. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js +1 -51
  14. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  15. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +51 -12
  16. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  17. package/lib/commonjs/components/RoomComponents/styled/LastMessageFile.js +12 -1
  18. package/lib/commonjs/components/RoomComponents/styled/LastMessageFile.js.map +1 -1
  19. package/lib/commonjs/components/RoomComponents/styled/LastMessagePhoto.js +13 -2
  20. package/lib/commonjs/components/RoomComponents/styled/LastMessagePhoto.js.map +1 -1
  21. package/lib/commonjs/components/RoomComponents/styled/LastMessageVideo.js +13 -2
  22. package/lib/commonjs/components/RoomComponents/styled/LastMessageVideo.js.map +1 -1
  23. package/lib/commonjs/components/styled/MessageImage.js +3 -1
  24. package/lib/commonjs/components/styled/MessageImage.js.map +1 -1
  25. package/lib/commonjs/components/styled/UnsupportedType.js +14 -4
  26. package/lib/commonjs/components/styled/UnsupportedType.js.map +1 -1
  27. package/lib/commonjs/components/styled/VideoMessage.js +3 -1
  28. package/lib/commonjs/components/styled/VideoMessage.js.map +1 -1
  29. package/lib/commonjs/context/xmppProvider.js +95 -36
  30. package/lib/commonjs/context/xmppProvider.js.map +1 -1
  31. package/lib/commonjs/helpers/createMessageFromXml.js +19 -1
  32. package/lib/commonjs/helpers/createMessageFromXml.js.map +1 -1
  33. package/lib/commonjs/helpers/getDisplayFileName.js +79 -0
  34. package/lib/commonjs/helpers/getDisplayFileName.js.map +1 -0
  35. package/lib/commonjs/helpers/getServerReadTimestamp.js +188 -0
  36. package/lib/commonjs/helpers/getServerReadTimestamp.js.map +1 -0
  37. package/lib/commonjs/helpers/initXmppRooms.js +9 -7
  38. package/lib/commonjs/helpers/initXmppRooms.js.map +1 -1
  39. package/lib/commonjs/helpers/insertMessageWithDelimiter.js +51 -9
  40. package/lib/commonjs/helpers/insertMessageWithDelimiter.js.map +1 -1
  41. package/lib/commonjs/helpers/isOwnMessage.js +75 -0
  42. package/lib/commonjs/helpers/isOwnMessage.js.map +1 -0
  43. package/lib/commonjs/helpers/keyboardLayout.js +12 -2
  44. package/lib/commonjs/helpers/keyboardLayout.js.map +1 -1
  45. package/lib/commonjs/helpers/mimeToExtension.js +6 -14
  46. package/lib/commonjs/helpers/mimeToExtension.js.map +1 -1
  47. package/lib/commonjs/helpers/msgSortableMs.js +37 -0
  48. package/lib/commonjs/helpers/msgSortableMs.js.map +1 -0
  49. package/lib/commonjs/hooks/useChatRoomFocus.js +45 -12
  50. package/lib/commonjs/hooks/useChatRoomFocus.js.map +1 -1
  51. package/lib/commonjs/hooks/useChatWrapperInit.js +12 -7
  52. package/lib/commonjs/hooks/useChatWrapperInit.js.map +1 -1
  53. package/lib/commonjs/hooks/useLogout.js +8 -0
  54. package/lib/commonjs/hooks/useLogout.js.map +1 -1
  55. package/lib/commonjs/i18n/strings.js +0 -18
  56. package/lib/commonjs/i18n/strings.js.map +1 -1
  57. package/lib/commonjs/networking/api-requests/rooms.api.js +0 -13
  58. package/lib/commonjs/networking/api-requests/rooms.api.js.map +1 -1
  59. package/lib/commonjs/networking/stanzaHandlers.js +20 -2
  60. package/lib/commonjs/networking/stanzaHandlers.js.map +1 -1
  61. package/lib/commonjs/networking/xmpp/flushLastViewedToPrivateStore.js +45 -11
  62. package/lib/commonjs/networking/xmpp/flushLastViewedToPrivateStore.js.map +1 -1
  63. package/lib/commonjs/networking/xmppClient.js +36 -2
  64. package/lib/commonjs/networking/xmppClient.js.map +1 -1
  65. package/lib/commonjs/roomStore/index.js +35 -2
  66. package/lib/commonjs/roomStore/index.js.map +1 -1
  67. package/lib/commonjs/roomStore/persistence.js +200 -11
  68. package/lib/commonjs/roomStore/persistence.js.map +1 -1
  69. package/lib/commonjs/roomStore/roomsSlice.js +148 -37
  70. package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
  71. package/lib/module/assets/icons.js +1 -1
  72. package/lib/module/assets/icons.js.map +1 -1
  73. package/lib/module/components/MainComponents/ChatRoom.js +77 -20
  74. package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
  75. package/lib/module/components/MainComponents/MediaMessage.js +9 -6
  76. package/lib/module/components/MainComponents/MediaMessage.js.map +1 -1
  77. package/lib/module/components/MainComponents/MessageContainer.js +5 -1
  78. package/lib/module/components/MainComponents/MessageContainer.js.map +1 -1
  79. package/lib/module/components/MainComponents/MessageList.js +2 -1
  80. package/lib/module/components/MainComponents/MessageList.js.map +1 -1
  81. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js +3 -53
  82. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  83. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +52 -13
  84. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  85. package/lib/module/components/RoomComponents/styled/LastMessageFile.js +12 -1
  86. package/lib/module/components/RoomComponents/styled/LastMessageFile.js.map +1 -1
  87. package/lib/module/components/RoomComponents/styled/LastMessagePhoto.js +13 -2
  88. package/lib/module/components/RoomComponents/styled/LastMessagePhoto.js.map +1 -1
  89. package/lib/module/components/RoomComponents/styled/LastMessageVideo.js +13 -2
  90. package/lib/module/components/RoomComponents/styled/LastMessageVideo.js.map +1 -1
  91. package/lib/module/components/styled/MessageImage.js +3 -1
  92. package/lib/module/components/styled/MessageImage.js.map +1 -1
  93. package/lib/module/components/styled/UnsupportedType.js +14 -4
  94. package/lib/module/components/styled/UnsupportedType.js.map +1 -1
  95. package/lib/module/components/styled/VideoMessage.js +3 -1
  96. package/lib/module/components/styled/VideoMessage.js.map +1 -1
  97. package/lib/module/context/xmppProvider.js +96 -37
  98. package/lib/module/context/xmppProvider.js.map +1 -1
  99. package/lib/module/helpers/createMessageFromXml.js +19 -1
  100. package/lib/module/helpers/createMessageFromXml.js.map +1 -1
  101. package/lib/module/helpers/getDisplayFileName.js +73 -0
  102. package/lib/module/helpers/getDisplayFileName.js.map +1 -0
  103. package/lib/module/helpers/getServerReadTimestamp.js +181 -0
  104. package/lib/module/helpers/getServerReadTimestamp.js.map +1 -0
  105. package/lib/module/helpers/initXmppRooms.js +9 -7
  106. package/lib/module/helpers/initXmppRooms.js.map +1 -1
  107. package/lib/module/helpers/insertMessageWithDelimiter.js +52 -9
  108. package/lib/module/helpers/insertMessageWithDelimiter.js.map +1 -1
  109. package/lib/module/helpers/isOwnMessage.js +70 -0
  110. package/lib/module/helpers/isOwnMessage.js.map +1 -0
  111. package/lib/module/helpers/keyboardLayout.js +12 -2
  112. package/lib/module/helpers/keyboardLayout.js.map +1 -1
  113. package/lib/module/helpers/mimeToExtension.js +6 -13
  114. package/lib/module/helpers/mimeToExtension.js.map +1 -1
  115. package/lib/module/helpers/msgSortableMs.js +32 -0
  116. package/lib/module/helpers/msgSortableMs.js.map +1 -0
  117. package/lib/module/hooks/useChatRoomFocus.js +46 -13
  118. package/lib/module/hooks/useChatRoomFocus.js.map +1 -1
  119. package/lib/module/hooks/useChatWrapperInit.js +12 -7
  120. package/lib/module/hooks/useChatWrapperInit.js.map +1 -1
  121. package/lib/module/hooks/useLogout.js +8 -0
  122. package/lib/module/hooks/useLogout.js.map +1 -1
  123. package/lib/module/i18n/strings.js +0 -18
  124. package/lib/module/i18n/strings.js.map +1 -1
  125. package/lib/module/networking/api-requests/rooms.api.js +0 -12
  126. package/lib/module/networking/api-requests/rooms.api.js.map +1 -1
  127. package/lib/module/networking/stanzaHandlers.js +20 -2
  128. package/lib/module/networking/stanzaHandlers.js.map +1 -1
  129. package/lib/module/networking/xmpp/flushLastViewedToPrivateStore.js +45 -11
  130. package/lib/module/networking/xmpp/flushLastViewedToPrivateStore.js.map +1 -1
  131. package/lib/module/networking/xmppClient.js +36 -2
  132. package/lib/module/networking/xmppClient.js.map +1 -1
  133. package/lib/module/roomStore/index.js +37 -4
  134. package/lib/module/roomStore/index.js.map +1 -1
  135. package/lib/module/roomStore/persistence.js +197 -11
  136. package/lib/module/roomStore/persistence.js.map +1 -1
  137. package/lib/module/roomStore/roomsSlice.js +136 -33
  138. package/lib/module/roomStore/roomsSlice.js.map +1 -1
  139. package/lib/typescript/assets/icons.d.ts +0 -8
  140. package/lib/typescript/assets/icons.d.ts.map +1 -1
  141. package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
  142. package/lib/typescript/components/MainComponents/MediaMessage.d.ts.map +1 -1
  143. package/lib/typescript/components/MainComponents/MessageContainer.d.ts.map +1 -1
  144. package/lib/typescript/components/MainComponents/MessageList.d.ts.map +1 -1
  145. package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts.map +1 -1
  146. package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts.map +1 -1
  147. package/lib/typescript/components/RoomComponents/styled/LastMessageFile.d.ts +1 -1
  148. package/lib/typescript/components/RoomComponents/styled/LastMessageFile.d.ts.map +1 -1
  149. package/lib/typescript/components/RoomComponents/styled/LastMessagePhoto.d.ts +1 -1
  150. package/lib/typescript/components/RoomComponents/styled/LastMessagePhoto.d.ts.map +1 -1
  151. package/lib/typescript/components/RoomComponents/styled/LastMessageVideo.d.ts +1 -1
  152. package/lib/typescript/components/RoomComponents/styled/LastMessageVideo.d.ts.map +1 -1
  153. package/lib/typescript/components/styled/MessageImage.d.ts +6 -0
  154. package/lib/typescript/components/styled/MessageImage.d.ts.map +1 -1
  155. package/lib/typescript/components/styled/UnsupportedType.d.ts.map +1 -1
  156. package/lib/typescript/components/styled/VideoMessage.d.ts +6 -0
  157. package/lib/typescript/components/styled/VideoMessage.d.ts.map +1 -1
  158. package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
  159. package/lib/typescript/helpers/createMessageFromXml.d.ts.map +1 -1
  160. package/lib/typescript/helpers/getAvatarColor.d.ts +1 -1
  161. package/lib/typescript/helpers/getDisplayFileName.d.ts +49 -0
  162. package/lib/typescript/helpers/getDisplayFileName.d.ts.map +1 -0
  163. package/lib/typescript/helpers/getServerReadTimestamp.d.ts +108 -0
  164. package/lib/typescript/helpers/getServerReadTimestamp.d.ts.map +1 -0
  165. package/lib/typescript/helpers/initXmppRooms.d.ts.map +1 -1
  166. package/lib/typescript/helpers/insertMessageWithDelimiter.d.ts +1 -1
  167. package/lib/typescript/helpers/insertMessageWithDelimiter.d.ts.map +1 -1
  168. package/lib/typescript/helpers/isOwnMessage.d.ts +36 -0
  169. package/lib/typescript/helpers/isOwnMessage.d.ts.map +1 -0
  170. package/lib/typescript/helpers/keyboardLayout.d.ts +5 -1
  171. package/lib/typescript/helpers/keyboardLayout.d.ts.map +1 -1
  172. package/lib/typescript/helpers/mimeToExtension.d.ts +0 -15
  173. package/lib/typescript/helpers/mimeToExtension.d.ts.map +1 -1
  174. package/lib/typescript/helpers/msgSortableMs.d.ts +2 -0
  175. package/lib/typescript/helpers/msgSortableMs.d.ts.map +1 -0
  176. package/lib/typescript/hooks/useChatRoomFocus.d.ts +4 -1
  177. package/lib/typescript/hooks/useChatRoomFocus.d.ts.map +1 -1
  178. package/lib/typescript/hooks/useChatWrapperInit.d.ts.map +1 -1
  179. package/lib/typescript/hooks/useLogout.d.ts.map +1 -1
  180. package/lib/typescript/i18n/strings.d.ts.map +1 -1
  181. package/lib/typescript/networking/api-requests/rooms.api.d.ts +0 -1
  182. package/lib/typescript/networking/api-requests/rooms.api.d.ts.map +1 -1
  183. package/lib/typescript/networking/stanzaHandlers.d.ts.map +1 -1
  184. package/lib/typescript/networking/xmpp/flushLastViewedToPrivateStore.d.ts +9 -2
  185. package/lib/typescript/networking/xmpp/flushLastViewedToPrivateStore.d.ts.map +1 -1
  186. package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
  187. package/lib/typescript/roomStore/index.d.ts.map +1 -1
  188. package/lib/typescript/roomStore/persistence.d.ts +18 -1
  189. package/lib/typescript/roomStore/persistence.d.ts.map +1 -1
  190. package/lib/typescript/roomStore/roomsSlice.d.ts +42 -3
  191. package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
  192. package/lib/typescript/types/models/room.model.d.ts +0 -1
  193. package/lib/typescript/types/models/room.model.d.ts.map +1 -1
  194. package/lib/typescript/types/types.d.ts +1 -1
  195. package/lib/typescript/types/types.d.ts.map +1 -1
  196. package/package.json +1 -1
  197. package/src/assets/icons.tsx +0 -24
  198. package/src/components/MainComponents/ChatRoom.tsx +81 -19
  199. package/src/components/MainComponents/MediaMessage.tsx +8 -5
  200. package/src/components/MainComponents/MessageContainer.tsx +5 -1
  201. package/src/components/MainComponents/MessageList.tsx +2 -1
  202. package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +2 -36
  203. package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +63 -26
  204. package/src/components/RoomComponents/styled/LastMessageFile.tsx +14 -2
  205. package/src/components/RoomComponents/styled/LastMessagePhoto.tsx +14 -2
  206. package/src/components/RoomComponents/styled/LastMessageVideo.tsx +14 -2
  207. package/src/components/styled/MessageImage.tsx +8 -1
  208. package/src/components/styled/UnsupportedType.tsx +14 -4
  209. package/src/components/styled/VideoMessage.tsx +8 -1
  210. package/src/context/xmppProvider.tsx +122 -30
  211. package/src/helpers/createMessageFromXml.ts +20 -1
  212. package/src/helpers/getDisplayFileName.ts +87 -0
  213. package/src/helpers/getServerReadTimestamp.ts +197 -0
  214. package/src/helpers/initXmppRooms.tsx +9 -9
  215. package/src/helpers/insertMessageWithDelimiter.ts +55 -19
  216. package/src/helpers/isOwnMessage.ts +90 -0
  217. package/src/helpers/keyboardLayout.ts +23 -2
  218. package/src/helpers/mimeToExtension.ts +6 -22
  219. package/src/helpers/msgSortableMs.ts +25 -0
  220. package/src/hooks/useChatRoomFocus.ts +49 -9
  221. package/src/hooks/useChatWrapperInit.ts +12 -7
  222. package/src/hooks/useLogout.tsx +14 -0
  223. package/src/i18n/strings.ts +0 -18
  224. package/src/networking/api-requests/rooms.api.ts +0 -9
  225. package/src/networking/stanzaHandlers.ts +20 -6
  226. package/src/networking/xmpp/flushLastViewedToPrivateStore.ts +65 -18
  227. package/src/networking/xmppClient.ts +41 -2
  228. package/src/roomStore/index.ts +40 -4
  229. package/src/roomStore/persistence.ts +197 -7
  230. package/src/roomStore/roomsSlice.ts +158 -28
  231. package/src/types/models/room.model.ts +0 -1
  232. package/src/types/types.ts +14 -1
@@ -0,0 +1,181 @@
1
+ "use strict";
2
+
3
+ import { msgSortableMs } from './msgSortableMs';
4
+
5
+ // A stored/stamped read marker more than this far past the newest
6
+ // message we actually know about for a room is not "the user is a
7
+ // little ahead" - it's a leftover from a device whose clock was wrong
8
+ // when it stamped the marker (bug #38). Generous on purpose: this value
9
+ // only controls when we're willing to treat an existing marker as
10
+ // corrupt and self-heal it, never how far off a legitimate new write can
11
+ // be, so a false positive here just means a bad value survives one extra
12
+ // cycle, not that a good value gets rejected.
13
+ export const FUTURE_READ_MARKER_TOLERANCE_MS = 5 * 60 * 1000;
14
+ /**
15
+ * Resolve the "read up to here" marker for `room` using SERVER time,
16
+ * never the device clock.
17
+ *
18
+ * Bug #38: if the device clock is ahead when the user leaves a room, a
19
+ * `Date.now()` read marker lands in the future. The private-store merge
20
+ * (flushLastViewedToPrivateStore.ts) is forward-only ("if (prevNum >=
21
+ * ts) continue"), so once a future marker is written, no later
22
+ * *correct* write can ever replace it - the room's unread count is
23
+ * stuck wrong forever, on every device, from that point on. Anchoring
24
+ * to the newest SERVER-acknowledged message's own timestamp instead
25
+ * means the marker we write can never be ahead of what the server
26
+ * itself has recorded for the room.
27
+ *
28
+ * "Server-acknowledged" excludes:
29
+ * - a message still marked `pending` (the optimistic bubble shown
30
+ * while a send is in flight - it carries the DEVICE send time via
31
+ * `date`, not a server timestamp, until the server echoes it back
32
+ * and insertMessageWithDelimiter flips `pending` off);
33
+ * - a message id present in `heapState.messageHeap` (queued retry -
34
+ * used for offline media sends, see roomHeapSlice.ts) or
35
+ * `heapState.failedMessages` (a send that never reached the server
36
+ * at all).
37
+ *
38
+ * `msgSortableMs` (helpers/msgSortableMs.ts) reads the server-assigned microsecond
39
+ * timestamp encoded in the first 13 digits of the message id - the same
40
+ * source already used for message ordering and unread counting - so
41
+ * this stays consistent with the rest of the read/unread pipeline.
42
+ *
43
+ * Falls back to the room's existing `lastViewedTimestamp` (so leaving
44
+ * an empty or never-scrolled room doesn't regress the marker), then to
45
+ * `0` when there's truly nothing to anchor to yet (a brand new room
46
+ * with no history and no prior marker). Callers should treat `0` as
47
+ * "skip the write" rather than substituting a device-clock guess.
48
+ */
49
+ export function getServerReadTimestamp(room, heapState) {
50
+ if (!room) {
51
+ return 0;
52
+ }
53
+ const heapIds = new Set((heapState?.messageHeap || []).filter(m => m && m.id != null).map(m => String(m.id)));
54
+ const failedIds = new Set(Object.keys(heapState?.failedMessages || {}));
55
+ let newest = 0;
56
+ const messages = room.messages || [];
57
+ for (const m of messages) {
58
+ if (!m || !m.id) {
59
+ continue;
60
+ }
61
+ const id = String(m.id);
62
+ if (id === 'delimiter-new' || id === 'delimiter-new-local') {
63
+ continue;
64
+ }
65
+ if (m.pending) {
66
+ continue;
67
+ }
68
+ if (heapIds.has(id) || failedIds.has(id)) {
69
+ continue;
70
+ }
71
+ const ts = msgSortableMs(m);
72
+ if (ts > newest) {
73
+ newest = ts;
74
+ }
75
+ }
76
+ if (newest > 0) {
77
+ return newest;
78
+ }
79
+ if (room.lastViewedTimestamp && room.lastViewedTimestamp > 0) {
80
+ return room.lastViewedTimestamp;
81
+ }
82
+ return 0;
83
+ }
84
+
85
+ /**
86
+ * Is `marker` a leftover from a device whose clock was wrong when it
87
+ * stamped a read marker (bug #38)?
88
+ *
89
+ * TWO independent signals must agree before we're willing to throw a
90
+ * stored marker away, because "waive the forward-only guard" is a
91
+ * destructive operation:
92
+ *
93
+ * 1. it sits well past the newest message we know the room has, AND
94
+ * 2. it sits well past real time.
95
+ *
96
+ * Signal 1 alone is NOT enough, and that is the whole point of this
97
+ * function: a device whose local cache for a room is simply stale (very
98
+ * common - any room whose history hasn't been synced yet this session)
99
+ * sees a perfectly legitimate marker written by another device that HAS
100
+ * seen newer messages, and would happily "heal" it backwards, resurrecting
101
+ * already-read messages as unread on every device. A real timestamp can
102
+ * never be ahead of real time, so requiring signal 2 as well means a
103
+ * stale cache on its own can no longer trigger the self-heal.
104
+ *
105
+ * Signal 2 alone is not used either: it would let a device whose own
106
+ * clock is running SLOW mistake every correct marker for a corrupt one.
107
+ */
108
+ export function isCorruptFutureReadMarker(marker, newestAckedMs) {
109
+ if (!Number.isFinite(marker) || marker <= 0) {
110
+ return false;
111
+ }
112
+ if (!(newestAckedMs > 0)) {
113
+ return false;
114
+ }
115
+ if (marker <= newestAckedMs + FUTURE_READ_MARKER_TOLERANCE_MS) {
116
+ return false;
117
+ }
118
+ return marker > Date.now() + FUTURE_READ_MARKER_TOLERANCE_MS;
119
+ }
120
+
121
+ /**
122
+ * Resolve the marker to STAMP (locally and to the server) for `room`,
123
+ * honouring an explicit read boundary when one is set.
124
+ *
125
+ * Bug #42 (a regression of #33, reintroduced by #38): #38 made every
126
+ * caller stamp the newest server-acknowledged message unconditionally.
127
+ * That is correct for a user who is at the bottom of the room, but wrong
128
+ * for a user who scrolled up, received messages, and left without
129
+ * scrolling back down - stamping "newest" there silently marks
130
+ * messages they never saw as read, both locally and (because the
131
+ * private-store merge is forward-only) permanently on the server.
132
+ *
133
+ * `boundaryTs` is the msgSortableMs of the newest message the user
134
+ * actually reached (see `readBoundaries` on `RoomMessagesState`,
135
+ * populated by MessageList's `onReadBoundaryChange`). When it's set and
136
+ * positive, it wins - but is still clamped to never exceed the newest
137
+ * server-acknowledged message, so a stale/corrupt boundary can't stamp a
138
+ * marker further ahead than the room's own history supports. When no
139
+ * boundary is set (the common case - the user is at the bottom), this is
140
+ * exactly `getServerReadTimestamp`.
141
+ *
142
+ * Never returns `Date.now()`, directly or indirectly - same rule as
143
+ * `getServerReadTimestamp` (bug #38).
144
+ */
145
+ export function getReadMarkerTimestamp(room, heapState, boundaryTs) {
146
+ const newestAcked = getServerReadTimestamp(room, heapState);
147
+ if (typeof boundaryTs === 'number' && Number.isFinite(boundaryTs) && boundaryTs > 0) {
148
+ // `newestAcked === 0` means this room has NOTHING server-acked and no
149
+ // prior marker, so there is nothing to clamp the boundary against -
150
+ // and MessageList derives the boundary from the rendered list, which
151
+ // at that point can only contain pending/failed sends carrying the
152
+ // DEVICE clock via `date`. Returning it here would smuggle a
153
+ // device-clock marker back in through the boundary (bug #38). Return
154
+ // 0 = "nothing to anchor to, skip the write", same contract as
155
+ // getServerReadTimestamp.
156
+ return newestAcked > 0 ? Math.min(boundaryTs, newestAcked) : 0;
157
+ }
158
+ return newestAcked;
159
+ }
160
+
161
+ /**
162
+ * The value to hand `flushLastViewedToPrivateStore` as `visibleRoomTs`
163
+ * for a room being left, or `undefined` when no boundary applies (the
164
+ * flush then uses its own newest-acked default).
165
+ *
166
+ * Exists so the SERVER write goes through the SAME clamp as the local
167
+ * stamp. Passing the raw redux boundary straight through would bypass
168
+ * `getReadMarkerTimestamp`'s clamp on exactly the path where a bad value
169
+ * is permanent: the private-store merge is forward-only, so a boundary
170
+ * that (through a pending own message's device `date`, or a stale
171
+ * readBoundaries entry) sat ahead of the room's real history would be
172
+ * written verbatim and could never be corrected again (bug #38).
173
+ */
174
+ export function getFlushBoundaryTs(room, heapState, boundaryTs) {
175
+ if (typeof boundaryTs !== 'number' || !Number.isFinite(boundaryTs) || boundaryTs <= 0) {
176
+ return undefined;
177
+ }
178
+ const clamped = getReadMarkerTimestamp(room, heapState, boundaryTs);
179
+ return clamped > 0 ? clamped : undefined;
180
+ }
181
+ //# sourceMappingURL=getServerReadTimestamp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["msgSortableMs","FUTURE_READ_MARKER_TOLERANCE_MS","getServerReadTimestamp","room","heapState","heapIds","Set","messageHeap","filter","m","id","map","String","failedIds","Object","keys","failedMessages","newest","messages","pending","has","ts","lastViewedTimestamp","isCorruptFutureReadMarker","marker","newestAckedMs","Number","isFinite","Date","now","getReadMarkerTimestamp","boundaryTs","newestAcked","Math","min","getFlushBoundaryTs","undefined","clamped"],"sourceRoot":"../../../src","sources":["helpers/getServerReadTimestamp.ts"],"mappings":"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","ignoreList":[]}
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
 
3
3
  import { setCurrentRoom, setIsLoading } from '../roomStore/roomsSlice';
4
- import { updatedChatLastTimestamps } from './updatedChatLastTimestamps';
5
4
  import { initRoomsPresence } from './initRoomsPresence';
6
5
  import { store } from '../roomStore';
7
6
  import { refreshAuthTokensQuietly } from '../networking/authRefresh';
@@ -40,13 +39,16 @@ const initXmppRooms = async (user, config, xmmpClient, rooms, roomJID) => {
40
39
  console.log(res);
41
40
  }
42
41
 
43
- //@ts-ignore
44
- const roomTimestampObject = await xmmpClient.getChatsPrivateStoreRequestStanza();
45
- updatedChatLastTimestamps(roomTimestampObject, store.dispatch);
42
+ // getChatsPrivateStoreRequestStanza hydrates redux itself
43
+ // (dispatch(applyPrivateStoreMarkers(...)) internally, clamped +
44
+ // forward-only) - do not also apply the raw return value here. That
45
+ // used to double-dispatch via updatedChatLastTimestamps' unconditional
46
+ // setLastViewedTimestamp, which has neither the forward-only guard
47
+ // nor the future-marker clamp, so it could silently re-clobber a
48
+ // value the clamp had just corrected (bug #38).
49
+ await xmmpClient.getChatsPrivateStoreRequestStanza();
46
50
  } else {
47
- //@ts-ignore
48
- const roomTimestampObject = await xmmpClient.getChatsPrivateStoreRequestStanza();
49
- updatedChatLastTimestamps(roomTimestampObject, store.dispatch);
51
+ await xmmpClient.getChatsPrivateStoreRequestStanza();
50
52
  }
51
53
  if (config?.refreshTokens?.enabled) {
52
54
  // Was a bare call to the consumer-supplied refreshFunction, i.e. a
@@ -1 +1 @@
1
- {"version":3,"names":["setCurrentRoom","setIsLoading","updatedChatLastTimestamps","initRoomsPresence","store","refreshAuthTokensQuietly","initXmppRooms","user","config","xmmpClient","rooms","roomJID","dispatch","defaultWallet","walletAddress","console","log","Object","keys","length","newArch","res","getRoomsStanza","roomTimestampObject","getChatsPrivateStoreRequestStanza","refreshTokens","enabled","error","loading"],"sourceRoot":"../../../src","sources":["helpers/initXmppRooms.tsx"],"mappings":";;AAAA,SAASA,cAAc,EAAEC,YAAY,QAAQ,yBAAyB;AACtE,SAASC,yBAAyB,QAAQ,6BAA6B;AACvE,SAASC,iBAAiB,QAAQ,qBAAqB;AAGvD,SAASC,KAAK,QAAQ,cAAc;AACpC,SAASC,wBAAwB,QAAQ,2BAA2B;AAEpE,MAAMC,aAAa,GAAG,MAAAA,CACpBC,IAAU,EACVC,MAAe,EACfC,UAAsB,EACtBC,KAAgC,EAChCC,OAAgB,KACb;EACH,IAAIA,OAAO,EAAE;IACXP,KAAK,CAACQ,QAAQ,CAACZ,cAAc,CAAC;MAAEW,OAAO,EAAEA;IAAQ,CAAC,CAAC,CAAC;EACtD;EAEA,IAAI;IACF,IAAI,CAACJ,IAAI,CAACM,aAAa,IAAI,CAACN,IAAI,CAACM,aAAa,CAACC,aAAa,EAAE;MAC5DC,OAAO,CAACC,GAAG,CAAC,gBAAgB,CAAC;MAC7B;IACF;IAEA,IAAI,CAACP,UAAU,EAAE;MACfM,OAAO,CAACC,GAAG,CAAC,iCAAiC,CAAC;MAE9C,IAAIN,KAAK,IAAIO,MAAM,CAACC,IAAI,CAACR,KAAK,CAAC,CAACS,MAAM,GAAG,CAAC,EAAE;QAC1C,MAAMhB,iBAAiB,CAACM,UAAU,EAAEC,KAAK,CAAC;MAC5C,CAAC,MAAM;QACL,IAAIF,MAAM,EAAEY,OAAO,EAAE;UACnB;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;QACF;QACA,MAAMC,GAAG,GAAG,MAAOZ,UAAU,CAAuBa,cAAc,CAAC,CAAC;QACpEP,OAAO,CAACC,GAAG,CAACK,GAAG,CAAC;MAClB;;MAEA;MACA,MAAME,mBAAqD,GACzD,MAAOd,UAAU,CAAuBe,iCAAiC,CAAC,CAAC;MAC7EtB,yBAAyB,CAACqB,mBAAmB,EAAEnB,KAAK,CAACQ,QAAQ,CAAC;IAChE,CAAC,MAAM;MACL;MACA,MAAMW,mBAAqD,GACzD,MAAMd,UAAU,CAACe,iCAAiC,CAAC,CAAC;MACtDtB,yBAAyB,CAACqB,mBAAmB,EAAEnB,KAAK,CAACQ,QAAQ,CAAC;IAChE;IAEA,IAAIJ,MAAM,EAAEiB,aAAa,EAAEC,OAAO,EAAE;MAClC;MACA;MACA;MACArB,wBAAwB,CAAC,CAAC;IAC5B;EACF,CAAC,CAAC,OAAOsB,KAAK,EAAE;IACdZ,OAAO,CAACY,KAAK,CAACA,KAAK,CAAC;EACtB,CAAC,SAAS;IACRvB,KAAK,CAACQ,QAAQ,CAACX,YAAY,CAAC;MAAE2B,OAAO,EAAE;IAAM,CAAC,CAAC,CAAC;EAClD;AACF,CAAC;AAED,eAAetB,aAAa","ignoreList":[]}
1
+ {"version":3,"names":["setCurrentRoom","setIsLoading","initRoomsPresence","store","refreshAuthTokensQuietly","initXmppRooms","user","config","xmmpClient","rooms","roomJID","dispatch","defaultWallet","walletAddress","console","log","Object","keys","length","newArch","res","getRoomsStanza","getChatsPrivateStoreRequestStanza","refreshTokens","enabled","error","loading"],"sourceRoot":"../../../src","sources":["helpers/initXmppRooms.tsx"],"mappings":";;AAAA,SAASA,cAAc,EAAEC,YAAY,QAAQ,yBAAyB;AACtE,SAASC,iBAAiB,QAAQ,qBAAqB;AAGvD,SAASC,KAAK,QAAQ,cAAc;AACpC,SAASC,wBAAwB,QAAQ,2BAA2B;AAEpE,MAAMC,aAAa,GAAG,MAAAA,CACpBC,IAAU,EACVC,MAAe,EACfC,UAAsB,EACtBC,KAAgC,EAChCC,OAAgB,KACb;EACH,IAAIA,OAAO,EAAE;IACXP,KAAK,CAACQ,QAAQ,CAACX,cAAc,CAAC;MAAEU,OAAO,EAAEA;IAAQ,CAAC,CAAC,CAAC;EACtD;EAEA,IAAI;IACF,IAAI,CAACJ,IAAI,CAACM,aAAa,IAAI,CAACN,IAAI,CAACM,aAAa,CAACC,aAAa,EAAE;MAC5DC,OAAO,CAACC,GAAG,CAAC,gBAAgB,CAAC;MAC7B;IACF;IAEA,IAAI,CAACP,UAAU,EAAE;MACfM,OAAO,CAACC,GAAG,CAAC,iCAAiC,CAAC;MAE9C,IAAIN,KAAK,IAAIO,MAAM,CAACC,IAAI,CAACR,KAAK,CAAC,CAACS,MAAM,GAAG,CAAC,EAAE;QAC1C,MAAMhB,iBAAiB,CAACM,UAAU,EAAEC,KAAK,CAAC;MAC5C,CAAC,MAAM;QACL,IAAIF,MAAM,EAAEY,OAAO,EAAE;UACnB;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;QACF;QACA,MAAMC,GAAG,GAAG,MAAOZ,UAAU,CAAuBa,cAAc,CAAC,CAAC;QACpEP,OAAO,CAACC,GAAG,CAACK,GAAG,CAAC;MAClB;;MAEA;MACA;MACA;MACA;MACA;MACA;MACA;MACA,MAAOZ,UAAU,CAAuBc,iCAAiC,CAAC,CAAC;IAC7E,CAAC,MAAM;MACL,MAAMd,UAAU,CAACc,iCAAiC,CAAC,CAAC;IACtD;IAEA,IAAIf,MAAM,EAAEgB,aAAa,EAAEC,OAAO,EAAE;MAClC;MACA;MACA;MACApB,wBAAwB,CAAC,CAAC;IAC5B;EACF,CAAC,CAAC,OAAOqB,KAAK,EAAE;IACdX,OAAO,CAACW,KAAK,CAACA,KAAK,CAAC;EACtB,CAAC,SAAS;IACRtB,KAAK,CAACQ,QAAQ,CAACV,YAAY,CAAC;MAAEyB,OAAO,EAAE;IAAM,CAAC,CAAC,CAAC;EAClD;AACF,CAAC;AAED,eAAerB,aAAa","ignoreList":[]}
@@ -1,6 +1,38 @@
1
1
  "use strict";
2
2
 
3
3
  import { isDateAfter, isDateBefore } from './dateComparison';
4
+ import { msgSortableMs } from './msgSortableMs';
5
+
6
+ // Robustly resolve a caller-supplied read marker to epoch milliseconds.
7
+ // Callers pass a plain number (the redux read boundary, or a room's
8
+ // lastViewedTimestamp), a Date object (older call sites), or occasionally
9
+ // a numeric string. These are NOT interchangeable through the Date
10
+ // constructor: `new Date(1757000000123)` (a number) reads as epoch-ms,
11
+ // but `new Date("1757000000123")` (a string) is parsed as a date STRING
12
+ // - a bare 13-digit string matches no recognized date format, so the
13
+ // result is silently Invalid Date and every comparison against it is
14
+ // `false`. Try Number() first so a numeric string/number is read as
15
+ // epoch-ms; only fall through to Date parsing for genuine date/ISO
16
+ // strings (e.g. a Date object's own `.toString()`). Never falls back to
17
+ // `Date.now()` - a marker we can't resolve is treated as "no marker",
18
+ // not "now" (bug #38).
19
+ function resolveMarkerMs(marker) {
20
+ if (marker == null) {
21
+ return 0;
22
+ }
23
+ if (typeof marker === 'number') {
24
+ return Number.isFinite(marker) ? marker : 0;
25
+ }
26
+ const raw = marker.toString();
27
+ if (raw.trim() !== '') {
28
+ const asNumber = Number(raw);
29
+ if (Number.isFinite(asNumber)) {
30
+ return asNumber;
31
+ }
32
+ }
33
+ const parsed = Date.parse(raw);
34
+ return Number.isFinite(parsed) ? parsed : 0;
35
+ }
4
36
  function deepMerge(target, source) {
5
37
  for (const key in source) {
6
38
  if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
@@ -49,21 +81,32 @@ export function insertMessageWithDelimiter(roomMessages, message, lastViewedTime
49
81
  } else {
50
82
  roomMessages.push(message);
51
83
  }
52
- if (lastViewedTimestamp && !roomMessages.some(msg => msg.id === 'delimiter-new') && isDateAfter(newMessageDate.toString(), lastViewedTimestamp.toString())) {
53
- const delimiterIndex = roomMessages.findIndex(msg => isDateAfter(msg.date?.toString() ?? '', lastViewedTimestamp.toString()));
84
+ const lastViewedMs = resolveMarkerMs(lastViewedTimestamp);
85
+ const newMessageMs = msgSortableMs(message);
86
+ if (lastViewedMs > 0 && newMessageMs > lastViewedMs && !roomMessages.some(msg => msg.id === 'delimiter-new')) {
87
+ // Find the first message STRICTLY newer than the marker, using the
88
+ // SAME timestamp source (msgSortableMs - the server id-encoded ms)
89
+ // as the unread middleware and countNewerMessages use to decide
90
+ // what counts as unread. Comparing against a DIFFERENT source (the
91
+ // old code compared `msg.date` strings) risks the boundary message
92
+ // itself landing on the wrong side of the cut: since bug #38 the
93
+ // marker can equal a real message's own timestamp exactly, and any
94
+ // drift between `date` and the id-encoded ms - or a raw numeric
95
+ // marker silently producing an Invalid Date via the Date
96
+ // constructor's string-parsing path - could count that message as
97
+ // unread, pushing the divider one message too early (ABOVE the
98
+ // last read message instead of directly below it). Customer #42.
99
+ const delimiterIndex = roomMessages.findIndex(msg => msg.id !== 'delimiter-new' && msgSortableMs(msg) > lastViewedMs);
54
100
  if (delimiterIndex !== -1) {
55
101
  // The divider's date is what ORDERS it: roomsSlice re-sorts every
56
102
  // merged page by timestamp (see `byMs`), so a divider stamped with
57
- // `new Date()` — i.e. now — sorted past every real message and
103
+ // `new Date()` (i.e. now) sorted past every real message and
58
104
  // rendered at the very bottom, BELOW the new messages it is
59
105
  // supposed to introduce. Anchor it a hair before the first unread
60
106
  // instead, which is where it belongs and where any later sort keeps
61
- // it. Derived from that message rather than from
62
- // lastViewedTimestamp so it works whatever format the caller passes.
63
- const firstUnreadMs = Date.parse(String(roomMessages[delimiterIndex]?.date ?? ''));
64
- const rawLastViewed = lastViewedTimestamp.toString();
65
- const lastViewedMs = Date.parse(rawLastViewed) || Number(rawLastViewed) || Date.now();
66
- const anchorMs = Number.isFinite(firstUnreadMs) ? firstUnreadMs - 1 : lastViewedMs;
107
+ // it.
108
+ const firstUnreadMs = msgSortableMs(roomMessages[delimiterIndex]);
109
+ const anchorMs = firstUnreadMs > 0 ? firstUnreadMs - 1 : lastViewedMs;
67
110
  roomMessages.splice(delimiterIndex, 0, {
68
111
  id: 'delimiter-new',
69
112
  user: {
@@ -1 +1 @@
1
- {"version":3,"names":["isDateAfter","isDateBefore","deepMerge","target","source","key","Array","isArray","insertMessageWithDelimiter","roomMessages","message","lastViewedTimestamp","existingIndex","findIndex","msg","id","xmppId","existing","preservedUserId","user","merged","pending","newMessageDate","date","lastMessage","length","firstMessage","toString","index","push","some","delimiterIndex","firstUnreadMs","Date","parse","String","rawLastViewed","lastViewedMs","Number","now","anchorMs","isFinite","splice","name","undefined","token","refreshToken","toISOString","body","roomJid","unshift","i"],"sourceRoot":"../../../src","sources":["helpers/insertMessageWithDelimiter.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["isDateAfter","isDateBefore","msgSortableMs","resolveMarkerMs","marker","Number","isFinite","raw","toString","trim","asNumber","parsed","Date","parse","deepMerge","target","source","key","Array","isArray","insertMessageWithDelimiter","roomMessages","message","lastViewedTimestamp","existingIndex","findIndex","msg","id","xmppId","existing","preservedUserId","user","merged","pending","newMessageDate","date","lastMessage","length","firstMessage","index","push","lastViewedMs","newMessageMs","some","delimiterIndex","firstUnreadMs","anchorMs","splice","name","undefined","token","refreshToken","toISOString","body","roomJid","unshift","i"],"sourceRoot":"../../../src","sources":["helpers/insertMessageWithDelimiter.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Bug #41: during reconnect catch-up (app was backgrounded/offline, then
5
+ * comes back online), messages replayed from MAM could transiently render
6
+ * on the RIGHT (as if sent by the current user) before flipping to the
7
+ * LEFT a moment later. Root cause: `message.user.id === walletAddress`
8
+ * treats `undefined === undefined` (or `'' === ''`) as a match, and the
9
+ * two sides could independently be empty for one frame -- the message's
10
+ * sender id before the MAM-derived value settled, and/or the current
11
+ * user's id before it rehydrated. Two blank ids must never compare equal.
12
+ *
13
+ * A second, related issue: the same logical sender id can show up in
14
+ * different shapes depending on which code path produced it -- a bare
15
+ * id ("wallet123") or a bare JID with an incidental session resource
16
+ * ("wallet123@host/sessionResource", as `senderJID` attrs carry on the
17
+ * wire -- see src/assets/test.xml). In every shape used in this
18
+ * codebase the identifying segment is the part BEFORE the first '@' (or
19
+ * before '/' when there's no '@'); anything after that -- domain,
20
+ * resource -- is noise. Comparing raw strings with `===` fails whenever
21
+ * one side still carries that noise and the other doesn't. Normalizing
22
+ * both sides (strip resource, strip domain, lowercase) before comparing
23
+ * makes the check tolerant of that drift.
24
+ */
25
+
26
+ /**
27
+ * Strip a MUC resource (`room@host/resource` -> `room@host`) and then a
28
+ * JID domain (`local@host` -> `local`), lowercasing the result. Applies
29
+ * to both plain ids and full/partial JIDs so either shape normalizes to
30
+ * the same comparable value.
31
+ */
32
+ const normalizeId = raw => {
33
+ const value = String(raw ?? '').trim();
34
+ if (!value) {
35
+ return '';
36
+ }
37
+ const withoutResource = value.split('/')[0];
38
+ const withoutDomain = withoutResource.includes('@') ? withoutResource.split('@')[0] : withoutResource;
39
+ return withoutDomain.toLowerCase();
40
+ };
41
+
42
+ // Same precedence the rest of the app uses when it needs "who am I" as a
43
+ // single id: xmppUsername first, walletAddress as the fallback.
44
+ const resolveCurrentUserId = currentUser => {
45
+ if (typeof currentUser === 'string') {
46
+ return currentUser;
47
+ }
48
+ if (!currentUser) {
49
+ return '';
50
+ }
51
+ return currentUser.xmppUsername || currentUser.walletAddress || currentUser.id || '';
52
+ };
53
+
54
+ /**
55
+ * Robustly determine whether `message` was sent by `currentUser`. Never
56
+ * returns true from two blank/undefined ids, and tolerates bare-id vs.
57
+ * full-JID mismatches between the sender id and the current user id.
58
+ */
59
+ export const isOwnMessage = (message, currentUser) => {
60
+ const messageUserId = normalizeId(message?.user?.id);
61
+ if (!messageUserId) {
62
+ return false;
63
+ }
64
+ const currentUserId = normalizeId(resolveCurrentUserId(currentUser));
65
+ if (!currentUserId) {
66
+ return false;
67
+ }
68
+ return messageUserId === currentUserId;
69
+ };
70
+ //# sourceMappingURL=isOwnMessage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["normalizeId","raw","value","String","trim","withoutResource","split","withoutDomain","includes","toLowerCase","resolveCurrentUserId","currentUser","xmppUsername","walletAddress","id","isOwnMessage","message","messageUserId","user","currentUserId"],"sourceRoot":"../../../src","sources":["helpers/isOwnMessage.ts"],"mappings":";;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAcA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMA,WAAW,GAAIC,GAAY,IAAa;EAC5C,MAAMC,KAAK,GAAGC,MAAM,CAACF,GAAG,IAAI,EAAE,CAAC,CAACG,IAAI,CAAC,CAAC;EACtC,IAAI,CAACF,KAAK,EAAE;IACV,OAAO,EAAE;EACX;EACA,MAAMG,eAAe,GAAGH,KAAK,CAACI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;EAC3C,MAAMC,aAAa,GAAGF,eAAe,CAACG,QAAQ,CAAC,GAAG,CAAC,GAC/CH,eAAe,CAACC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAC7BD,eAAe;EACnB,OAAOE,aAAa,CAACE,WAAW,CAAC,CAAC;AACpC,CAAC;;AAED;AACA;AACA,MAAMC,oBAAoB,GAAIC,WAAkC,IAAa;EAC3E,IAAI,OAAOA,WAAW,KAAK,QAAQ,EAAE;IACnC,OAAOA,WAAW;EACpB;EACA,IAAI,CAACA,WAAW,EAAE;IAChB,OAAO,EAAE;EACX;EACA,OACEA,WAAW,CAACC,YAAY,IAAID,WAAW,CAACE,aAAa,IAAIF,WAAW,CAACG,EAAE,IAAI,EAAE;AAEjF,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,YAAY,GAAGA,CAC1BC,OAAkD,EAClDL,WAAkC,KACtB;EACZ,MAAMM,aAAa,GAAGjB,WAAW,CAACgB,OAAO,EAAEE,IAAI,EAAEJ,EAAE,CAAC;EACpD,IAAI,CAACG,aAAa,EAAE;IAClB,OAAO,KAAK;EACd;EAEA,MAAME,aAAa,GAAGnB,WAAW,CAACU,oBAAoB,CAACC,WAAW,CAAC,CAAC;EACpE,IAAI,CAACQ,aAAa,EAAE;IAClB,OAAO,KAAK;EACd;EAEA,OAAOF,aAAa,KAAKE,aAAa;AACxC,CAAC","ignoreList":[]}
@@ -9,6 +9,16 @@ export const getKeyboardVerticalOffset = ({
9
9
  export const getInputDockPaddingBottom = ({
10
10
  platform,
11
11
  bottomInset = 0,
12
- keyboardVisible = false
13
- }) => platform === 'ios' ? bottomInset : ANDROID_INPUT_DOCK_GAP;
12
+ keyboardVisible = false,
13
+ configuredPadding,
14
+ hostOwnsLayout = false
15
+ }) => {
16
+ if (typeof configuredPadding === 'number') {
17
+ return configuredPadding;
18
+ }
19
+ if (hostOwnsLayout) {
20
+ return 0;
21
+ }
22
+ return platform === 'ios' ? bottomInset : ANDROID_INPUT_DOCK_GAP;
23
+ };
14
24
  //# sourceMappingURL=keyboardLayout.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["ANDROID_INPUT_DOCK_GAP","getKeyboardVerticalOffset","platform","configuredOffset","bottomInset","getInputDockPaddingBottom","keyboardVisible"],"sourceRoot":"../../../src","sources":["helpers/keyboardLayout.ts"],"mappings":";;AAOA,OAAO,MAAMA,sBAAsB,GAAG,EAAE;AAExC,OAAO,MAAMC,yBAAyB,GAAGA,CAAC;EACxCC,QAAQ;EACRC,gBAAgB,GAAG,CAAC;EACpBC,WAAW,GAAG;AACI,CAAC,KACnBD,gBAAgB,IAAID,QAAQ,KAAK,KAAK,GAAGE,WAAW,GAAG,CAAC,CAAC;AAE3D,OAAO,MAAMC,yBAAyB,GAAGA,CAAC;EACxCH,QAAQ;EACRE,WAAW,GAAG,CAAC;EACfE,eAAe,GAAG;AAC0B,CAAC,KAC7CJ,QAAQ,KAAK,KAAK,GAAGE,WAAW,GAAGJ,sBAAsB","ignoreList":[]}
1
+ {"version":3,"names":["ANDROID_INPUT_DOCK_GAP","getKeyboardVerticalOffset","platform","configuredOffset","bottomInset","getInputDockPaddingBottom","keyboardVisible","configuredPadding","hostOwnsLayout"],"sourceRoot":"../../../src","sources":["helpers/keyboardLayout.ts"],"mappings":";;AAOA,OAAO,MAAMA,sBAAsB,GAAG,EAAE;AAExC,OAAO,MAAMC,yBAAyB,GAAGA,CAAC;EACxCC,QAAQ;EACRC,gBAAgB,GAAG,CAAC;EACpBC,WAAW,GAAG;AACI,CAAC,KACnBD,gBAAgB,IAAID,QAAQ,KAAK,KAAK,GAAGE,WAAW,GAAG,CAAC,CAAC;AAc3D,OAAO,MAAMC,yBAAyB,GAAGA,CAAC;EACxCH,QAAQ;EACRE,WAAW,GAAG,CAAC;EACfE,eAAe,GAAG,KAAK;EACvBC,iBAAiB;EACjBC,cAAc,GAAG;AACG,CAAC,KAAa;EAClC,IAAI,OAAOD,iBAAiB,KAAK,QAAQ,EAAE;IACzC,OAAOA,iBAAiB;EAC1B;EACA,IAAIC,cAAc,EAAE;IAClB,OAAO,CAAC;EACV;EACA,OAAON,QAAQ,KAAK,KAAK,GAAGE,WAAW,GAAGJ,sBAAsB;AAClE,CAAC","ignoreList":[]}
@@ -227,17 +227,10 @@ export function ensureFilenameHasExtension(fileName, mime) {
227
227
  return `${base}${getExtensionForMime(mime)}`;
228
228
  }
229
229
 
230
- /**
231
- * Best-effort filename derivation for a message bubble:
232
- * - server-provided `fileName`
233
- * - server-provided `originalName`
234
- * - URL pathname
235
- * - generic `media_<timestamp>` so we never render an empty label
236
- *
237
- * Always returns a string with a valid extension.
238
- */
239
- export function deriveDisplayFilename(opts) {
240
- const candidate = opts.fileName && opts.fileName.trim() || opts.originalName && opts.originalName.trim() || filenameFromUrl(opts.url) || '';
241
- return ensureFilenameHasExtension(candidate, opts.mime);
242
- }
230
+ // NOTE: the "which name wins" decision (originalName vs the stored
231
+ // fileName vs the URL) lives in helpers/getDisplayFileName.ts - that is
232
+ // the single source of truth used across display, save, share and
233
+ // download call sites (bug #40: this used to be duplicated here with
234
+ // the priority backwards, so attachments showed/saved under the
235
+ // server's hash name instead of the sender's original one).
243
236
  //# sourceMappingURL=mimeToExtension.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["MIME_TO_EXT","VALID_EXT_RE","AUDIO_EXTENSIONS","IOS_AUDIO_PLAYBACK_EXTENSIONS","IOS_AUDIO_UNSUPPORTED_EXTENSIONS","AUDIO_EXT_RE","RegExp","map","e","replace","join","IOS_AUDIO_PLAYBACK_EXT_RE","AUDIO_NAME_HINT_RE","isLikelyAudio","mime","fileName","url","opts","m","toLowerCase","startsWith","durationNum","duration","Number","isFinite","waveForm","trim","length","name","originalName","urlLast","filenameFromUrl","test","urlPath","noQuery","split","decodeURIComponent","getExtensionForMime","normalized","last","pop","getLowerExtension","value","match","shouldCacheAudioForIosPlayback","src","urlName","candidates","hasIosPlayableName","some","getIosAudioPlaybackCacheExtension","candidate","ext","isUnsupportedAudioForIosPlayback","includes","ensureFilenameHasExtension","base","Date","now","deriveDisplayFilename"],"sourceRoot":"../../../src","sources":["helpers/mimeToExtension.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["MIME_TO_EXT","VALID_EXT_RE","AUDIO_EXTENSIONS","IOS_AUDIO_PLAYBACK_EXTENSIONS","IOS_AUDIO_UNSUPPORTED_EXTENSIONS","AUDIO_EXT_RE","RegExp","map","e","replace","join","IOS_AUDIO_PLAYBACK_EXT_RE","AUDIO_NAME_HINT_RE","isLikelyAudio","mime","fileName","url","opts","m","toLowerCase","startsWith","durationNum","duration","Number","isFinite","waveForm","trim","length","name","originalName","urlLast","filenameFromUrl","test","urlPath","noQuery","split","decodeURIComponent","getExtensionForMime","normalized","last","pop","getLowerExtension","value","match","shouldCacheAudioForIosPlayback","src","urlName","candidates","hasIosPlayableName","some","getIosAudioPlaybackCacheExtension","candidate","ext","isUnsupportedAudioForIosPlayback","includes","ensureFilenameHasExtension","base","Date","now"],"sourceRoot":"../../../src","sources":["helpers/mimeToExtension.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+
3
+ // Count messages strictly newer than a given millisecond timestamp using
4
+ // `msg.id` (the server-authoritative microsecond timestamp prefixed by a
5
+ // 13-digit millis, see `helpers/dateComparison`'s
6
+ // `getHighResolutionTimestamp`) rather than `msg.date`, which can be
7
+ // derived client-side (`createMessageFromXml` falls back to `Date.now()`
8
+ // for realtime stanzas without a `date` attr) and drift from what the
9
+ // server actually assigned.
10
+ //
11
+ // Extracted to its own module (rather than living in roomsSlice.ts, its
12
+ // original home) so helpers that need the SAME ordering source - notably
13
+ // `insertMessageWithDelimiter.ts`, which decides where the "New messages"
14
+ // divider sits - can import it without creating a roomStore <-> helpers
15
+ // import cycle (roomsSlice.ts already imports insertMessageWithDelimiter).
16
+ // roomsSlice.ts re-exports this for backward compatibility with existing
17
+ // call sites.
18
+ export const msgSortableMs = msg => {
19
+ const id = String(msg?.id || '');
20
+ const m = /^(\d{13})/.exec(id);
21
+ if (m) {
22
+ return Number(m[1]);
23
+ }
24
+ if (msg?.date) {
25
+ const t = new Date(msg.date).getTime();
26
+ if (Number.isFinite(t)) {
27
+ return t;
28
+ }
29
+ }
30
+ return 0;
31
+ };
32
+ //# sourceMappingURL=msgSortableMs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["msgSortableMs","msg","id","String","m","exec","Number","date","t","Date","getTime","isFinite"],"sourceRoot":"../../../src","sources":["helpers/msgSortableMs.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMA,aAAa,GAAIC,GAAQ,IAAa;EACjD,MAAMC,EAAE,GAAGC,MAAM,CAACF,GAAG,EAAEC,EAAE,IAAI,EAAE,CAAC;EAChC,MAAME,CAAC,GAAG,WAAW,CAACC,IAAI,CAACH,EAAE,CAAC;EAC9B,IAAIE,CAAC,EAAE;IAAC,OAAOE,MAAM,CAACF,CAAC,CAAC,CAAC,CAAC,CAAC;EAAC;EAC5B,IAAIH,GAAG,EAAEM,IAAI,EAAE;IACb,MAAMC,CAAC,GAAG,IAAIC,IAAI,CAACR,GAAG,CAACM,IAAW,CAAC,CAACG,OAAO,CAAC,CAAC;IAC7C,IAAIJ,MAAM,CAACK,QAAQ,CAACH,CAAC,CAAC,EAAE;MAAC,OAAOA,CAAC;IAAC;EACpC;EACA,OAAO,CAAC;AACV,CAAC","ignoreList":[]}