@@ -87,13 +87,17 @@ interface UnresolvedModifications {
8787}
8888
8989/**
90- * Find the newest message in an array that was NOT delivered with delay (offline).
91- * Delayed messages should not advance the MAM catch-up cursor, otherwise the
92- * forward query skips the gap where originals of corrections may live.
90+ * Find the newest message in an array (regardless of delay status).
91+ *
92+ * Used as the catch-up cursor for MAM forward queries. Including delayed
93+ * messages ensures the catch-up always uses a forward query, which merges
94+ * correctly via full sort. Previously skipping delayed messages caused
95+ * backward queries whose prepend-based merge put newer messages (sent
96+ * from another client while offline) at the wrong position.
9397 */
94- function findNewestLiveMessage ( messages : Array < { isDelayed ?: boolean ; timestamp ?: Date } > ) : { timestamp : Date } | undefined {
98+ function findNewestMessage ( messages : Array < { timestamp ?: Date } > ) : { timestamp : Date } | undefined {
9599 for ( let i = messages . length - 1 ; i >= 0 ; i -- ) {
96- if ( ! messages [ i ] . isDelayed && messages [ i ] . timestamp ) return messages [ i ] as { timestamp : Date }
100+ if ( messages [ i ] . timestamp ) return messages [ i ] as { timestamp : Date }
97101 }
98102 return undefined
99103}
@@ -819,21 +823,18 @@ export class MAM extends BaseModule {
819823 if ( this . deps . stores ?. connection . getStatus ( ) !== 'online' ) return
820824
821825 const messages = conv . messages || [ ]
822- // Use the newest non-delayed (live) message as the catch-up cursor.
823- // Delayed messages (offline delivery) should not advance the cursor,
824- // otherwise MAM catch-up skips the gap where originals of corrections live.
825- const newestLiveMessage = findNewestLiveMessage ( messages )
826-
827- if ( newestLiveMessage ?. timestamp ) {
828- // Forward query from the last live message
829- const startTime = new Date ( newestLiveMessage . timestamp . getTime ( ) + 1 )
826+ const newestMessage = findNewestMessage ( messages )
827+
828+ if ( newestMessage ?. timestamp ) {
829+ // Forward query from the last known message
830+ const startTime = new Date ( newestMessage . timestamp . getTime ( ) + 1 )
830831 await this . queryArchive ( {
831832 with : conv . id ,
832833 start : startTime . toISOString ( ) ,
833834 max : 100 ,
834835 } )
835836 } else {
836- // No live messages (all delayed or empty) — fetch latest from MAM
837+ // No messages (empty) — fetch latest from MAM
837838 await this . queryArchive ( {
838839 with : conv . id ,
839840 before : '' ,
@@ -947,19 +948,18 @@ export class MAM extends BaseModule {
947948 // Re-read room after cache load (store was mutated)
948949 const updatedRoom = this . deps . stores ?. room . getRoom ( room . jid )
949950 const messages = updatedRoom ?. messages || [ ]
950- // Use the newest non-delayed (live) message as the catch-up cursor.
951- const newestLiveMessage = findNewestLiveMessage ( messages )
951+ const newestMessage = findNewestMessage ( messages )
952952
953- if ( newestLiveMessage ?. timestamp ) {
954- // Forward query from the last live message
955- const startTime = new Date ( newestLiveMessage . timestamp . getTime ( ) + 1 )
953+ if ( newestMessage ?. timestamp ) {
954+ // Forward query from the last known message
955+ const startTime = new Date ( newestMessage . timestamp . getTime ( ) + 1 )
956956 await this . queryRoomArchive ( {
957957 roomJid : room . jid ,
958958 start : startTime . toISOString ( ) ,
959959 max : 100 ,
960960 } )
961961 } else {
962- // No live messages (all delayed or empty) — fetch latest from MAM
962+ // No messages (empty) — fetch latest from MAM
963963 await this . queryRoomArchive ( {
964964 roomJid : room . jid ,
965965 before : '' ,
0 commit comments