From b8f63a86f3b1e57808a8a20e4d47fbbedb9abb60 Mon Sep 17 00:00:00 2001 From: martincupela Date: Thu, 23 Oct 2025 16:39:21 +0200 Subject: [PATCH] fix: prevent reporting delivery for already reported message --- src/channel.ts | 9 +++++ test/unit/channel.test.js | 85 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/src/channel.ts b/src/channel.ts index 47be99ab1..20a87c4fe 100644 --- a/src/channel.ts +++ b/src/channel.ts @@ -1936,6 +1936,15 @@ export class Channel { deliveredAt: event.created_at, lastDeliveredMessageId: event.last_delivered_message_id, }); + + const client = this.getClient(); + const isOwnEvent = event.user?.id === client.user?.id; + + // make sure not to report deliveries that were + // already confirmed from own user from another device + if (isOwnEvent) { + client.syncDeliveredCandidates([this]); + } } break; case 'user.watching.start': diff --git a/test/unit/channel.test.js b/test/unit/channel.test.js index 87bbb5492..3115d0d98 100644 --- a/test/unit/channel.test.js +++ b/test/unit/channel.test.js @@ -213,6 +213,7 @@ describe('Channel count unread', function () { describe('Channel _handleChannelEvent', function () { const user = { id: 'user' }; + const otherUser = { id: 'other-user' }; let client; let channel; @@ -880,6 +881,90 @@ describe('Channel _handleChannelEvent', function () { event.last_delivered_message_id, ); }); + + it('prevents reporting delivery just reported', () => { + // enable delivery events + client._addChannelConfig({ + cid: channel.cid, + config: { ...channel.getConfig(), delivery_events: true }, + }); + channel.state.read[user.id] = initialReadState; + + channel._handleChannelEvent({ + type: 'message.new', + user: otherUser, + message: generateMsg({ + id: messageDeliveredEvent.last_delivered_message_id, + date: messageDeliveredEvent.last_delivered_at, + }), + }); + expect(client.messageDeliveryReporter.deliveryReportCandidates.size).toBe(1); + expect( + client.messageDeliveryReporter.deliveryReportCandidates.get(channel.cid), + ).toBe(messageDeliveredEvent.last_delivered_message_id); + + channel._handleChannelEvent(messageDeliveredEvent); + expect(client.messageDeliveryReporter.deliveryReportCandidates.size).toBe(0); + }); + + it('keeps reporting delivery if having newer deliveries', () => { + // enable delivery events + client._addChannelConfig({ + cid: channel.cid, + config: { ...channel.getConfig(), delivery_events: true }, + }); + channel.state.read[user.id] = initialReadState; + const newerMessage = generateMsg({ + id: 'some-other-id', + date: new Date(3000).toISOString(), + }); + channel._handleChannelEvent({ + type: 'message.new', + user: otherUser, + message: newerMessage, + }); + + expect(client.messageDeliveryReporter.deliveryReportCandidates.size).toBe(1); + expect( + client.messageDeliveryReporter.deliveryReportCandidates.get(channel.cid), + ).toBe(newerMessage.id); + + // event refers to a message delivered 1000ms earlier than newerMessage - still want to report the newerMessage + channel._handleChannelEvent(messageDeliveredEvent); + expect(client.messageDeliveryReporter.deliveryReportCandidates.size).toBe(1); + expect( + client.messageDeliveryReporter.deliveryReportCandidates.get(channel.cid), + ).toBe(newerMessage.id); + }); + + it("does not sync the delivery buffer upon other user's delivery confirmation", () => { + // enable delivery events + client._addChannelConfig({ + cid: channel.cid, + config: { ...channel.getConfig(), delivery_events: true }, + }); + channel.state.read[user.id] = initialReadState; + + channel._handleChannelEvent({ + type: 'message.new', + user: otherUser, + message: generateMsg({ + id: messageDeliveredEvent.last_delivered_message_id, + date: messageDeliveredEvent.last_delivered_at, + }), + }); + expect(client.messageDeliveryReporter.deliveryReportCandidates.size).toBe(1); + expect( + client.messageDeliveryReporter.deliveryReportCandidates.get(channel.cid), + ).toBe(messageDeliveredEvent.last_delivered_message_id); + + channel._handleChannelEvent({ ...messageDeliveredEvent, user: otherUser }); + expect(client.messageDeliveryReporter.deliveryReportCandidates.size).toBe(1); + // the originally planned message id is kept to be reported + expect( + client.messageDeliveryReporter.deliveryReportCandidates.get(channel.cid), + ).toBe(messageDeliveredEvent.last_delivered_message_id); + }); }); it('should include unread_messages for message events from another user', () => {