A React component library for rendering common AT Protocol records for applications such as Bluesky and Leaflet.
1import { useEffect, useState } from 'react'; 2import { usePdsEndpoint } from './usePdsEndpoint'; 3import { createAtprotoClient } from '../utils/atproto-client'; 4 5/** 6 * Minimal profile fields returned by the Bluesky actor profile endpoint. 7 */ 8export interface BlueskyProfileData { 9 /** Actor DID. */ 10 did: string; 11 /** Actor handle. */ 12 handle: string; 13 /** Display name configured by the actor. */ 14 displayName?: string; 15 /** Profile description/bio. */ 16 description?: string; 17 /** Avatar blob (CID reference). */ 18 avatar?: string; 19 /** Banner image blob (CID reference). */ 20 banner?: string; 21 /** Creation timestamp for the profile. */ 22 createdAt?: string; 23} 24 25/** 26 * Fetches a Bluesky actor profile for a DID and exposes loading/error state. 27 * 28 * @param did - Actor DID whose profile should be retrieved. 29 * @returns {{ data: BlueskyProfileData | undefined; loading: boolean; error: Error | undefined }} Object exposing the profile payload, loading flag, and any error. 30 */ 31export function useBlueskyProfile(did: string | undefined) { 32 const { endpoint } = usePdsEndpoint(did); 33 const [data, setData] = useState<BlueskyProfileData | undefined>(); 34 const [loading, setLoading] = useState<boolean>(!!did); 35 const [error, setError] = useState<Error | undefined>(); 36 37 useEffect(() => { 38 let cancelled = false; 39 async function run() { 40 if (!did || !endpoint) return; 41 setLoading(true); 42 try { 43 const { rpc } = await createAtprotoClient({ service: endpoint }); 44 const client = rpc as unknown as { 45 get: (nsid: string, options: { params: { actor: string } }) => Promise<{ ok: boolean; data: unknown }>; 46 }; 47 const res = await client.get('app.bsky.actor.getProfile', { params: { actor: did } }); 48 if (!res.ok) throw new Error('Profile request failed'); 49 if (!cancelled) setData(res.data as BlueskyProfileData); 50 } catch (e) { 51 if (!cancelled) setError(e as Error); 52 } finally { 53 if (!cancelled) setLoading(false); 54 } 55 } 56 run(); 57 return () => { cancelled = true; }; 58 }, [did, endpoint]); 59 60 return { data, loading, error }; 61}