feat: fix cross-instance friends list for federated users

Friends fan-out (loadFriends/loadRequests) now waits for all remote
connections to establish before querying, fixing the empty friends list
when logged into a remote instance as a federated user.

- Add _autoConnectDone wait guard to loadFriends, loadRequests, and
  loadFederatedMutuals (same pattern as discoverStore)
- Add concurrency guards to prevent thundering herd from multiple
  ready events firing simultaneous fan-outs
- Fix deduplication to use canonical identity (homeUserId ?? id)
  instead of id:origin, preventing duplicate entries for the same
  user across instances
- Auto-connect to home instance when logged in as a federated user,
  with registry entry so it appears in Connections UI
- Allow re-adding error/disconnected instances in probeInstance
This commit is contained in:
Jannis Braun
2026-04-08 18:41:13 +02:00
parent d58464fe95
commit 213d05a810
3 changed files with 133 additions and 14 deletions
+18
View File
@@ -26,6 +26,7 @@ export interface FederatedMutuals {
* Load mutual friends and mutual spaces across all connected instances.
* Follows the same Promise.allSettled fan-out pattern as socialStore.loadFriends().
*
* - Waits for auto-connect to finish before fanning out (same guard as socialStore)
* - Deduplicates friends by canonical identity (homeUserId ?? id)
* - Concatenates spaces (spaces on different instances are distinct)
* - Normalizes assets for remote-origin results
@@ -34,6 +35,23 @@ export async function loadFederatedMutuals(
targetUserId: string,
targetHomeUserId?: string | null,
): Promise<FederatedMutuals> {
// Wait for all remote connections to establish before fanning out
if (!useInstanceStore.getState()._autoConnectDone) {
await new Promise<void>((resolve) => {
const unsub = useInstanceStore.subscribe((state) => {
if (state._autoConnectDone) {
unsub();
resolve();
}
});
// Double-check (race condition guard)
if (useInstanceStore.getState()._autoConnectDone) {
unsub();
resolve();
}
});
}
const instances = useInstanceStore.getState().instances;
const connectedInstances = instances.filter(i => i.status === 'connected');