import type {} from '@atcute/atproto'; import { CompositeDidDocumentResolver, PlcDidDocumentResolver, WebDidDocumentResolver } from '@atcute/identity-resolver'; import { CompositeHandleResolver, DohJsonHandleResolver, WellKnownHandleResolver } from '@atcute/identity-resolver'; import { type ActorIdentifier, type AtprotoDid, type Handle, isHandle } from '@atcute/lexicons/syntax'; import { isAtprotoDid } from '@atcute/identity'; import { RedisClient } from 'bun'; import type { BlueRecipesActorDefs } from '@cookware/lexicons'; import type { Blob, LegacyBlob } from '@atcute/lexicons'; import { buildCdnUrl } from './cdn.js'; const handleResolver = new CompositeHandleResolver({ strategy: 'race', methods: { dns: new DohJsonHandleResolver({ dohUrl: 'https://mozilla.cloudflare-dns.com/dns-query' }), http: new WellKnownHandleResolver({ fetch }), }, }); const didResolver = new CompositeDidDocumentResolver({ methods: { plc: new PlcDidDocumentResolver(), web: new WebDidDocumentResolver(), } }); const HANDLE_CACHE_TTL = 5 * 60; // 5 minutes export const parseDid = async (id: ActorIdentifier): Promise => { if (isAtprotoDid(id)) return id; if (isHandle(id)) { return await handleResolver.resolve(id); } throw Error("Invalid DID or Handle!"); } export const getHandle = async (did: AtprotoDid, redis: RedisClient): Promise => { let handle = await redis.get(`handle:${did}`) as Handle | null; if (!handle) { const didDoc = await didResolver.resolve(did); if (didDoc.alsoKnownAs == null || didDoc.alsoKnownAs.length < 1) { throw new Error(`User ${did} had no resolvable DID document.`); } handle = didDoc.alsoKnownAs[0]!.substring(5) as Handle; redis.setex(`handle:${did}`, HANDLE_CACHE_TTL, handle); } return handle; } export const buildProfileViewBasic = async (author: { did: AtprotoDid; displayName: string; pronouns: string | null; avatarRef: Blob | LegacyBlob | null; createdAt: Date; }, redis: RedisClient): Promise => ({ did: author.did, handle: await getHandle(author.did, redis), displayName: author.displayName, pronouns: author.pronouns ?? undefined, avatar: author.avatarRef ? buildCdnUrl('avatar', author.did, author.avatarRef) : undefined, createdAt: author.createdAt.toISOString(), });