git » sdk » commit 3e8dacb

When getting backwards keep going backwards

author Stephen Paul Weber
2026-04-22 16:15:41 UTC
committer Stephen Paul Weber
2026-04-22 16:15:41 UTC
parent bdf23dec43f75464f479e95efe998fd988c2a906

When getting backwards keep going backwards

This might be bad and mess up sortId, but right now we only do this in
the code in a case where we are getting last page and then got nothing
from that so it's safe enough in practise for now.

borogove/MessageSync.hx +5 -1
test/TestSortId.hx +53 -0

diff --git a/borogove/MessageSync.hx b/borogove/MessageSync.hx
index 60bfde8..cc1e5bd 100644
--- a/borogove/MessageSync.hx
+++ b/borogove/MessageSync.hx
@@ -58,7 +58,11 @@ class MessageSync {
 		final promisedMessages:Array<Promise<Message>> = [];
 		if (lastPage != null) {
 			if (filter.page == null) filter.page = {};
-			filter.page.after = lastPage.last;
+			if (filter.page.before == null) {
+				filter.page.after = lastPage.last;
+			} else {
+				filter.page.before = lastPage.first;
+			}
 		}
 		var query = new MAMQuery(filter, serviceJID);
 		var previousMessageTime = "";
diff --git a/test/TestSortId.hx b/test/TestSortId.hx
index 79746c2..39f58f0 100644
--- a/test/TestSortId.hx
+++ b/test/TestSortId.hx
@@ -178,6 +178,59 @@ class TestSortId extends utest.Test {
 		);
 	}
 
+	public function testSyncBeforePagingStaysBefore(async: Async) {
+		final persistence = new Dummy();
+		final client = new Client("test@example.com", persistence);
+		final stream = client.stream;
+
+		var sendCount = 0;
+		var firstIqId = null;
+		var secondIqId = null;
+
+		stream.on("sendStanza", (stanza: Stanza) -> {
+			final query = stanza.findChild("{urn:xmpp:mam:2}query");
+			if (stanza.name != "iq" || query == null) return EventUnhandled;
+
+			sendCount++;
+			final rsm = stanza.findChild("{urn:xmpp:mam:2}query/{http://jabber.org/protocol/rsm}set");
+			Assert.notNull(rsm, "RSM set should be present");
+
+			final before = rsm.getChild("before");
+			final after = rsm.getChild("after");
+
+			if (sendCount == 1) {
+				firstIqId = stanza.attr.get("id");
+				Assert.notNull(before, "first page should use before");
+				Assert.equals("", before.getText());
+				Assert.isNull(after, "first page should not use after");
+			} else if (sendCount == 2) {
+				secondIqId = stanza.attr.get("id");
+				Assert.notNull(before, "second page should still use before");
+				Assert.equals("mam-first", before.getText());
+				Assert.isNull(after, "second page should not switch to after");
+				async.done();
+			}
+
+			return EventHandled;
+		});
+
+		final sync = new MessageSync(client, stream, { with: "sync@example.com", page: { before: "" } }, null, null);
+		sync.onMessages((list) -> {});
+
+		sync.fetchNext();
+
+		stream.onStanza(new Stanza("iq", { type: "result", id: firstIqId, from: "test@example.com", xmlns: "jabber:client" })
+			.tag("fin", { xmlns: "urn:xmpp:mam:2" })
+				.tag("set", { xmlns: "http://jabber.org/protocol/rsm" })
+					.textTag("first", "mam-first")
+					.textTag("last", "mam-last")
+				.up()
+			.up()
+		);
+
+		sync.fetchNext();
+	}
+
 	public function testMessageChannelPrivateSequence() {
 		final persistence = new Dummy();
 		final client = new Client("test@example.com", persistence);