| author | Stephen Paul Weber
<singpolyma@singpolyma.net> 2026-10-05 19:14:30 UTC |
| committer | Stephen Paul Weber
<singpolyma@singpolyma.net> 2026-10-05 19:14:30 UTC |
| parent | e350363246f2de85932f22193accc75368eb674b |
| borogove/persistence/IDB.js | +7 | -0 |
| test/persistence-tests.ts | +66 | -0 |
diff --git a/borogove/persistence/IDB.js b/borogove/persistence/IDB.js index b04f6c4..61dab44 100644 --- a/borogove/persistence/IDB.js +++ b/borogove/persistence/IDB.js @@ -635,6 +635,13 @@ export default async (dbname, media, tokenize, stemmer) => { const dedup = {}; const versions = []; for (const version of newVersions.concat(storedVersions)) { + if ( + version.direction === enums.borogove_MessageDirection.MessageSent && + version.localId + ) { + if (dedup[version.localId]) continue; + dedup[version.localId] = true; + } if (version.serverId) { const key = version.serverId + "\n" + version.serverIdBy; if (dedup[key]) continue; diff --git a/test/persistence-tests.ts b/test/persistence-tests.ts index 6c2ace1..0d1a01b 100644 --- a/test/persistence-tests.ts +++ b/test/persistence-tests.ts @@ -624,6 +624,72 @@ export function sharedPersistenceTests(test) { expect(stored.versions[1].sortId).toBe("a0"); }); + test("dedupes unreflected and reflected correction versions when editing our own message", async ({ + borogove, + persistence, + }) => { + const account = "alice@example.com"; + const chatId = "room@example.com"; + const senderId = "room@example.com/alice"; + + const builder = new borogove.ChatMessageBuilder({ + serverId: "orig-srv", + serverIdBy: chatId, + localId: "orig-loc", + senderId, + direction: borogove.MessageDirection.MessageSent, + timeReceived: "2026-08-26T12:00:00Z", + }); + builder.sortId = "a0"; + builder.text = "Original message"; + builder.type = borogove.MessageType.MessageChannel; + builder.to = borogove.JID.parse(chatId); + builder.from = borogove.JID.parse(senderId); + builder.recipients = [builder.to]; + builder.replyTo = [builder.to]; + const original = builder.build(); + + await persistence.storeMessages(account, [original]); + + // Local edit: store a version with no serverId + builder.serverId = null; + builder.serverIdBy = null; + builder.localId = "edit-loc"; + builder.text = "Corrected message"; + builder.timeReceived = "2026-08-26T12:01:00Z"; + const localVersion = builder.build(); + + builder.localId = original.localId; + builder.versions = [localVersion]; + await persistence.storeMessages(account, [builder.build()]); + + // Channel reflects: store a duplicate version that now has a serverId + builder.serverId = "edit-srv"; + builder.serverIdBy = chatId; + builder.localId = "edit-loc"; + builder.versions = []; + const reflectedVersion = builder.build(); + + builder.localId = original.localId; + builder.versions = [reflectedVersion]; + const [stored] = await persistence.storeMessages(account, [ + builder.build(), + ]); + + const [fetched] = await persistence.getMessagesBefore(account, chatId); + + expect(stored.versions.length).toBe(2); + expect(stored.versions.map((v) => v.text)).toEqual([ + "Corrected message", + "Original message", + ]); + expect(fetched.versions.length).toBe(2); + expect(fetched.versions.map((v) => v.text)).toEqual([ + "Corrected message", + "Original message", + ]); + }); + test("storeReaction", async ({ borogove, persistence }) => { const builder = new borogove.ChatMessageBuilder({ serverId: "srv1",