From b7c4a020db6a2032841d46a3020b09918eb85597 Mon Sep 17 00:00:00 2001 From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com> Date: Tue, 7 Apr 2026 19:54:16 +0200 Subject: [PATCH] feat: accept DMs from all origins with federatedId dedup Replace home-only DM filter with unified DM list. DMs from all connected instances are merged, deduplicated by federatedId. First-loaded copy wins; both copies are in sync via S2S relay. --- packages/web/src/stores/spaceStore.ts | 30 ++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/packages/web/src/stores/spaceStore.ts b/packages/web/src/stores/spaceStore.ts index 27284a83..ac83623b 100644 --- a/packages/web/src/stores/spaceStore.ts +++ b/packages/web/src/stores/spaceStore.ts @@ -644,11 +644,10 @@ export const useSpaceStore = create((set, get) => ({ } } - // S2S DM Unification: DMs are managed exclusively by the home instance. - // Skip DM channels from remote origins — they're replicas served by S2S relay. - const incomingDms = origin === '' ? (dmChannels ?? []) : []; + // Accept DMs from all origins. Each instance serves its own DM data. + const incomingDms = dmChannels ?? []; - // Normalize asset URLs for DMs (only relevant for home origin in practice) + // Normalize asset URLs for remote-origin DMs if (origin !== '') { for (const dm of incomingDms) { for (const member of dm.members) { @@ -657,7 +656,28 @@ export const useSpaceStore = create((set, get) => ({ } } + // Build a set of existing federatedIds for dedup + const existingFederatedIds = new Map(); // federatedId → dmChannelId + for (const dm of get().dmChannels) { + if (dm.federatedId) { + existingFederatedIds.set(dm.federatedId, dm.id); + } + } + + // Filter incoming DMs: skip duplicates (same federatedId already loaded from another origin) + const filteredDms: typeof incomingDms = []; for (const dm of incomingDms) { + if (dm.federatedId && existingFederatedIds.has(dm.federatedId)) { + // Duplicate cross-instance DM — keep the existing copy + continue; + } + filteredDms.push(dm); + if (dm.federatedId) { + existingFederatedIds.set(dm.federatedId, dm.id); + } + } + + for (const dm of filteredDms) { channelOriginMap.set(dm.id, origin); if (dm.lastMessage?.id) { channelLastMessageIds.set(dm.id, dm.lastMessage.id); @@ -669,7 +689,7 @@ export const useSpaceStore = create((set, get) => ({ const dmOrigin = get().channelOriginMap.get(dm.id); return dmOrigin !== origin; }); - const mergedDms = [...existingDmsFromOtherOrigins, ...incomingDms]; + const mergedDms = [...existingDmsFromOtherOrigins, ...filteredDms]; // Sort DMs using unread-first ordering. On initial load, unreadChannels may // still be empty (read states are processed after populateFromReady); the