Sifa professional network API (Fastify, AT Protocol, Jetstream) sifa.id/
at main 50 lines 1.5 kB view raw
1import { isValidHandle } from '@atproto/syntax'; 2import { Agent } from '@atproto/api'; 3import { logger } from '../logger.js'; 4 5export interface ResolvedProfile { 6 did: string; 7 handle: string; 8 displayName: string | undefined; 9 avatar: string | undefined; 10 about: string | undefined; 11} 12 13const SIMPLE_HANDLE_RE = /^[a-zA-Z0-9-]+$/; 14const publicAgent = new Agent('https://public.api.bsky.app'); 15 16export async function resolveHandleFromNetwork(query: string): Promise<ResolvedProfile | null> { 17 const candidates: string[] = []; 18 19 if (isValidHandle(query)) { 20 candidates.push(query); 21 } 22 23 // If no dots and looks like a simple username, also try .bsky.social 24 if (SIMPLE_HANDLE_RE.test(query) && !query.includes('.')) { 25 const bskySocial = `${query}.bsky.social`; 26 if (isValidHandle(bskySocial) && !candidates.includes(bskySocial)) { 27 candidates.push(bskySocial); 28 } 29 } 30 31 for (const handle of candidates) { 32 try { 33 const response = await publicAgent.getProfile( 34 { actor: handle }, 35 { signal: AbortSignal.timeout(3000) }, 36 ); 37 return { 38 did: response.data.did, 39 handle: response.data.handle, 40 displayName: response.data.displayName || undefined, 41 avatar: response.data.avatar || undefined, 42 about: response.data.description || undefined, 43 }; 44 } catch (err) { 45 logger.debug({ handle, err }, 'Handle resolution failed'); 46 } 47 } 48 49 return null; 50}