···11<script lang="ts" module>
22- // Cache for synchronous access during component recycling
32 const profileCache = new SvelteMap<string, { displayName?: string; handle: string }>();
43</script>
54···87 import { getRelativeTime } from '$lib/date';
98 import { generateColorForDid } from '$lib/accounts';
109 import type { Did } from '@atcute/lexicons';
1111- import type { AtprotoDid } from '@atcute/lexicons/syntax';
1210 import type { calculateFollowedUserStats, Sort } from '$lib/following';
1313- import type { AtpClient } from '$lib/at/client';
1111+ import { resolveDidDoc, type AtpClient } from '$lib/at/client';
1412 import { SvelteMap } from 'svelte/reactivity';
1515- import { clients, getClient, router } from '$lib/state.svelte';
1313+ import { router } from '$lib/state.svelte';
1414+ import { map } from '$lib/result';
16151716 interface Props {
1817 style: string;
···3534 const c = profileCache.get(targetDid)!;
3635 displayName = c.displayName;
3736 handle = c.handle;
3838- } else {
3939- const existingClient = clients.get(targetDid as AtprotoDid);
4040- if (existingClient?.user?.handle) {
4141- handle = existingClient.user.handle;
4242- } else {
4343- handle = 'handle.invalid';
4444- displayName = undefined;
4545- }
4637 }
47384839 try {
4949- // Optimization: Check clients map first to avoid async overhead if possible
5050- // but we need to ensure we have the profile data, not just client existence.
5151- const userClient = await getClient(targetDid as AtprotoDid);
5252-5353- // Check if the component has been recycled for a different user while we were awaiting
5454- if (did !== targetDid) return;
5555-5656- let newHandle = handle;
5757- let newDisplayName = displayName;
5858-5959- if (userClient.user?.handle) {
6060- newHandle = userClient.user.handle;
6161- handle = newHandle;
6262- } else {
6363- newHandle = targetDid;
6464- handle = newHandle;
6565- }
6666-6767- const profileRes = await userClient.getProfile();
6868-4040+ const [profileRes, handleRes] = await Promise.all([
4141+ client.getProfile(),
4242+ resolveDidDoc(targetDid).then((r) => map(r, (doc) => doc.handle))
4343+ ]);
6944 if (did !== targetDid) return;
7070-7171- if (profileRes.ok) {
7272- newDisplayName = profileRes.value.displayName;
7373- displayName = newDisplayName;
7474- }
4545+ if (profileRes.ok) displayName = profileRes.value.displayName;
4646+ if (handleRes.ok) handle = handleRes.value;
75477676- // Update cache
7748 profileCache.set(targetDid, {
7878- handle: newHandle,
7979- displayName: newDisplayName
4949+ handle,
5050+ displayName
8051 });
8152 } catch (e) {
8253 if (did !== targetDid) return;
···8556 }
8657 };
87588888- // Re-run whenever `did` changes
8959 $effect(() => {
9060 loadProfile(did);
9161 });
+10-10
src/components/TimelineView.svelte
···1111 fetchTimeline,
1212 allPosts,
1313 timelines,
1414- fetchInteractionsUntil
1414+ fetchInteractionsToTimelineEnd
1515 } from '$lib/state.svelte';
1616 import Icon from '@iconify/svelte';
1717 import { buildThreads, filterThreads, type ThreadPost } from '$lib/thread';
···5353 const loaderState = new LoaderState();
5454 let scrollContainer = $state<HTMLDivElement>();
5555 let loading = $state(false);
5656- let fetchMoreInteractions: boolean | undefined = $state(false);
5756 let loadError = $state('');
58575958 const loadMore = async () => {
···6362 loaderState.status = 'LOADING';
64636564 try {
6666- await fetchTimeline(did as AtprotoDid, 7, showReplies);
6767- // interaction fetching is done lazily so we dont block loading posts
6868- fetchMoreInteractions = true;
6565+ await fetchTimeline(client, did as AtprotoDid, 7, showReplies);
6666+ // only fetch interactions if logged in (because if not who is the interactor)
6767+ if (client.user) await fetchInteractionsToTimelineEnd(client, did);
6968 loaderState.loaded();
7069 } catch (error) {
7170 loadError = `${error}`;
···8786 const cursor = did ? postCursors.get(did as AtprotoDid) : undefined;
8887 if (!cursor?.end) loadMore();
8988 }
9090- if (client && did && fetchMoreInteractions) {
9191- // set to false so it doesnt attempt to fetch again while its already fetching
9292- fetchMoreInteractions = false;
9393- fetchInteractionsUntil(client, did).then(() => (fetchMoreInteractions = undefined));
9494- }
8989+ });
9090+ // we want to load interactions when changing logged in user on timelines
9191+ // only on timelines that arent logged in users, because those are already
9292+ // loaded by loadMore
9393+ $effect(() => {
9494+ if (client && did && client.user?.did !== did) fetchInteractionsToTimelineEnd(client, did);
9595 });
9696</script>
9797
···11import { settings } from '$lib/settings';
22+import type { Did } from '@atcute/lexicons';
23import { get } from 'svelte/store';
3445export const slingshotUrl: URL = new URL(get(settings).endpoints.slingshot);
56export const spacedustUrl: URL = new URL(get(settings).endpoints.spacedust);
67export const constellationUrl: URL = new URL(get(settings).endpoints.constellation);
88+99+export const httpToDidWeb = (url: string): Did => `did:web:${new URL(url).hostname}`;