diff --git a/packages/web/src/hooks/useWebSocket.ts b/packages/web/src/hooks/useWebSocket.ts index 8fd9ae21..6c8ee7ff 100644 --- a/packages/web/src/hooks/useWebSocket.ts +++ b/packages/web/src/hooks/useWebSocket.ts @@ -335,12 +335,14 @@ function handleEvent(origin: string, event: ServerEvent): void { // ─── Social events (all origins — federation) ────────────────────────── case 'friend_request_received': { + if (!isHome && event.request.user) normalizeUserAssets(event.request.user, origin); const { addIncomingRequest } = useSocialStore.getState(); addIncomingRequest(event.request, origin); break; } case 'friend_request_accepted': { + if (!isHome) normalizeUserAssets(event.friend, origin); const { addFriendFromAccepted } = useSocialStore.getState(); addFriendFromAccepted(event.friend, event.requestId, origin); break; diff --git a/packages/web/src/stores/exploreStore.ts b/packages/web/src/stores/exploreStore.ts index 526c5ab7..92b8bd45 100644 --- a/packages/web/src/stores/exploreStore.ts +++ b/packages/web/src/stores/exploreStore.ts @@ -1,6 +1,7 @@ import { create } from 'zustand'; import type { ExploreSpace, JoinRequest, SpaceWithChannelsAndMembers } from '@backspace/shared'; import { api } from '../api/client'; +import { resolveAssetUrl } from '../utils/assetUrls'; import { useInstanceStore } from './instanceStore'; import { useSpaceStore } from './spaceStore'; @@ -89,6 +90,9 @@ export const useExploreStore = create((set, get) => ({ const key = `${space.id}:${origin}`; if (seen.has(key)) continue; seen.add(key); + if (origin && space.icon) { + space.icon = resolveAssetUrl(space.icon, origin) ?? space.icon; + } allSpaces.push({ ...space, _instanceOrigin: origin, joined: space.joined ?? false }); } } diff --git a/packages/web/src/stores/socialStore.ts b/packages/web/src/stores/socialStore.ts index 6344f4eb..a523cc42 100644 --- a/packages/web/src/stores/socialStore.ts +++ b/packages/web/src/stores/socialStore.ts @@ -2,6 +2,7 @@ import { create } from 'zustand'; import type { Friend, FriendRequest, User } from '@backspace/shared'; import { api } from '../api/client'; import { useInstanceStore } from './instanceStore'; +import { normalizeUserAssets } from '../utils/assetUrls'; // ─── Tagged types (origin tracking for federation) ─────────────────────────── @@ -66,6 +67,7 @@ export const useSocialStore = create((set, get) => ({ const key = `${friend.id}:${origin}`; if (seen.has(key)) continue; seen.add(key); + if (origin) normalizeUserAssets(friend, origin); allFriends.push({ ...friend, _instanceOrigin: origin }); } } @@ -99,6 +101,7 @@ export const useSocialStore = create((set, get) => ({ const key = `${request.id}:${origin}`; if (seen.has(key)) continue; seen.add(key); + if (origin && request.user) normalizeUserAssets(request.user, origin); allRequests.push({ ...request, _instanceOrigin: origin }); } } @@ -217,22 +220,30 @@ export const useSocialStore = create((set, get) => ({ const instances = useInstanceStore.getState().instances; const connectedInstances = instances.filter(i => i.status === 'connected'); - const results = await Promise.allSettled([ - api.social.search(query), - ...connectedInstances.map(inst => inst.api.social.search(query)), - ]); + // Pair each promise with its origin for asset normalization + const searches: { promise: Promise; origin: string }[] = [ + { promise: api.social.search(query), origin: '' }, + ...connectedInstances.map(inst => ({ + promise: inst.api.social.search(query), + origin: inst.origin, + })), + ]; + + const results = await Promise.allSettled(searches.map(s => s.promise)); const allUsers: User[] = []; const seen = new Set(); - for (const result of results) { - if (result.status !== 'fulfilled') continue; + results.forEach((result, i) => { + if (result.status !== 'fulfilled') return; + const origin = searches[i]!.origin; for (const user of result.value) { if (seen.has(user.id)) continue; seen.add(user.id); + if (origin) normalizeUserAssets(user, origin); allUsers.push(user); } - } + }); return allUsers; } catch (err) {