fix(federation): deduplicate relay DM messages in chatStore

When a user has federated WS connections, they can receive both the
original message (from their home instance) and the relay copy (from the
remote instance). The relay copy has a different message ID but carries
sourceMessageId pointing to the original. The dedup now checks both
directions: incoming relay copy vs existing original, and incoming
original vs existing relay copy.
This commit is contained in:
Jannis Braun
2026-03-26 17:55:58 +01:00
parent 62f1d637ac
commit 523cb0c4b3
+7
View File
@@ -392,6 +392,13 @@ export const useChatStore = create<ChatState>((set, get) => ({
const current = newMessages.get(channelId) ?? []; const current = newMessages.get(channelId) ?? [];
// Avoid duplicates // Avoid duplicates
if (current.find(m => m.id === normalizedMessage.id)) return state; if (current.find(m => m.id === normalizedMessage.id)) return state;
// Federation relay dedup: skip if this is a relay copy of a message we
// already have (sourceMessageId matches an existing ID), or if we already
// have the relay copy and the original is now arriving (existing
// sourceMessageId matches incoming ID).
if ('sourceMessageId' in normalizedMessage && normalizedMessage.sourceMessageId
&& current.find(m => m.id === normalizedMessage.sourceMessageId)) return state;
if (current.find(m => 'sourceMessageId' in m && m.sourceMessageId === normalizedMessage.id)) return state;
// Remove any optimistic temp message with same content (no userId check — // Remove any optimistic temp message with same content (no userId check —
// federated messages arrive with a different replicated user ID). // federated messages arrive with a different replicated user ID).
// Normalize both sides: empty string and null are equivalent (server stores null for empty content). // Normalize both sides: empty string and null are equivalent (server stores null for empty content).