import { getDidDocument, getRecord } from "./atcuteUtils.ts"; import { getAtprotoHandle, getPdsEndpoint } from "@atcute/identity"; class DidResolver { private cache = new Map(); private pendingRequests = new Map>(); async resolve(did: Did): Promise { // Check cache first const cached = this.cache.get(did); if (cached) { return cached; } // Check if there's already a pending request for this DID const pending = this.pendingRequests.get(did); if (pending) { return pending; } // Create new request const request = this.fetchProfile(did); this.pendingRequests.set(did, request); try { const profile = await request; this.cache.set(did, profile); return profile; } finally { this.pendingRequests.delete(did); } } private async fetchProfile(did: Did): Promise { try { const didDocument = await getDidDocument(did); const pdsHostUrl = getPdsEndpoint(didDocument); const handle = getAtprotoHandle(didDocument); if (!pdsHostUrl || !handle) { throw new Error(`Error fetching PDS host or handle for ${did}`); } const [actorProfileResult, chatProfileResult] = await Promise .allSettled([ getRecord(pdsHostUrl, { repo: did, collection: "app.bsky.actor.profile", rkey: "self", }), getRecord(pdsHostUrl, { repo: did, collection: "place.stream.chat.profile", rkey: "self", }), ]); // Extract values from results, handling failures gracefully const actorProfile = actorProfileResult.status === "fulfilled" ? actorProfileResult.value?.value : null; const chatProfile = chatProfileResult.status === "fulfilled" ? chatProfileResult.value?.value : null; const userProfile: UserProfile = { handle: handle as Handle, pdsEndpoint: pdsHostUrl as `${string}:${string}`, }; if (actorProfile) { userProfile.actorProfile = actorProfile as ActorProfile; } if (chatProfile) { userProfile.chatProfile = chatProfile as ChatProfile; } return userProfile; } catch (error) { console.error(`Error fetching profile for ${did}:`, error); throw new Error( `Failed to fetch profile for ${did}: ${ error instanceof Error ? error.message : "Unknown error" }`, ); } } getUser(did: Did): UserProfile | undefined { return this.cache.get(did); } setUser(did: Did, profile: UserProfile) { this.cache.set(did, profile); } clearUserFromCache(did: Did) { this.cache.delete(did); } clearCache() { this.cache.clear(); } getCacheSize(): number { return this.cache.size; } } // Export singleton instance export const didResolver = new DidResolver();