feat(federation): dmAlternatives fallback in dm_message_created

Adds a new resolution step before the legacy 2-member-identity fallback:
if the event's dmChannelId is an alternate-origin local id for a DM
whose primary is in dmChannels, route the message to the primary via
resolveDmChannelId. Covers 1-on-1 AND group DMs uniformly — closes a
pre-existing phantom-sidebar-entry bug for group DMs in multi-instance
sessions and handles post-failover routing when the reconnected original
origin's WS still addresses the DM by its old local id.
This commit is contained in:
Jannis Braun
2026-04-23 01:29:28 +02:00
parent cd1f5c2b64
commit b1844e126f
2 changed files with 95 additions and 1 deletions
+25 -1
View File
@@ -1,6 +1,6 @@
import React, { useEffect, useRef } from 'react';
import { useAuthStore } from '../stores/authStore';
import { useSpaceStore, getChannelOrigin, getMyUserIdForOrigin, setMyUserIdForOrigin } from '../stores/spaceStore';
import { useSpaceStore, getChannelOrigin, getMyUserIdForOrigin, setMyUserIdForOrigin, resolveDmChannelId } from '../stores/spaceStore';
import { useChatStore } from '../stores/chatStore';
import { useVoiceStore } from '../stores/voiceStore';
import { useSocialStore } from '../stores/socialStore';
@@ -679,6 +679,30 @@ function handleEvent(origin: string, event: ServerEvent): void {
// (same conversation, different channel ID). If so, skip adding a new sidebar entry
// and route the message to the existing channel instead.
if (!knownDm) {
// dmAlternatives-based resolution: if this channelId is an alternate-origin
// local id for a DM whose primary is in dmChannels, reroute to the primary.
// Covers 1-on-1 AND group DMs uniformly; also the post-failover path where
// the reconnected original origin's WS still uses its old local id.
const primaryId = resolveDmChannelId(event.message.dmChannelId);
if (primaryId && primaryId !== event.message.dmChannelId) {
addRealtimeMessage(primaryId, { ...event.message, dmChannelId: primaryId } as any);
const updatedDms = currentDmChannels.map(dm =>
dm.id === primaryId ? { ...dm, lastMessage: event.message } : dm,
);
const { unreadChannels: u1, currentChannelId: c1 } = useChatStore.getState();
setDms(sortDmChannels(updatedDms, u1, c1));
{
const { currentChannelId: u1cc, markChannelUnread: u1mu } = useChatStore.getState();
const myId = isHome ? useAuthStore.getState().user?.id : getMyUserIdForOrigin(origin);
if (primaryId !== u1cc && event.message.userId !== myId) {
u1mu(primaryId);
}
}
break;
}
// Legacy 2-member-identity fallback: covers DMs without a federatedId
// (pre-federation or never-federated 1-on-1 DMs).
const msgUser = event.message.user;
const msgHomeUserId = msgUser?.homeUserId || msgUser?.id;
if (msgHomeUserId) {