A fork of pds-dash for selfhosted.social
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 93 lines 2.8 kB view raw
1import type { RequestHandler } from './$types'; 2import type { At, AppBskyActorProfile } from '@atcute/client/lexicons'; 3import { accountMetadataCache } from '$lib/server/sqlCache'; 4import type { AccountMetadata } from '$lib/server/sqlCache'; 5import { json } from '@sveltejs/kit'; 6import { simpleFetchHandler, XRPC } from '@atcute/client'; 7import '@atcute/bluesky/lexicons'; 8import { Config } from '$lib/config'; 9import type { Repo } from '@atproto/api/dist/client/types/com/atproto/sync/listRepos'; 10import { blueskyHandleFromDid } from '$lib/server/identity'; 11 12const rpc = new XRPC({ 13 handler: simpleFetchHandler({ 14 service: Config.PDS_URL, 15 }), 16}); 17 18const getAccountMetadata = async (did: At.Did): Promise<AccountMetadata | null> => { 19 // Check cache first with the accounts:${did} key 20 const cacheKey = `metadata:${did}`; 21 const cachedResult = accountMetadataCache.get(cacheKey); 22 if (cachedResult) { 23 return cachedResult; 24 } 25 26 const account: AccountMetadata = { 27 did: did, 28 handle: '', // Guaranteed to be filled out later 29 displayName: '', 30 avatarCid: null, 31 }; 32 33 try { 34 const { data } = await rpc.get('com.atproto.repo.getRecord', { 35 params: { 36 repo: did, 37 collection: 'app.bsky.actor.profile', 38 rkey: 'self', 39 }, 40 }); 41 const value = data.value as AppBskyActorProfile.Record; 42 account.displayName = value.displayName || ''; 43 if (value.avatar) { 44 account.avatarCid = value.avatar.ref['$link']; 45 } 46 } catch (e) { 47 console.warn(`Error fetching profile for ${did}:`, e); 48 } 49 50 try { 51 account.handle = await blueskyHandleFromDid(did); 52 } catch (e) { 53 console.error(`Error fetching handle for ${did}:`, e); 54 return null; 55 } 56 57 // Cache the result with the accounts:${did} key 58 accountMetadataCache.set(cacheKey, account); 59 return account; 60}; 61 62const getDidsFromPDS = async (): Promise<At.Did[]> => { 63 const { data } = await rpc.get('com.atproto.sync.listRepos', { 64 params: { 65 limit: 1000, 66 }, 67 }); 68 return data.repos.filter((x) => x.active).map((repo: Repo) => repo.did) 69 .reverse() as At.Did[]; 70}; 71 72const getAllMetadataFromPds = async (): Promise<AccountMetadata[]> => { 73 const dids = await getDidsFromPDS(); 74 const metadata = await Promise.all( 75 dids.map(async (repo: `did:${string}:${string}`) => { 76 return await getAccountMetadata(repo); 77 }), 78 ); 79 return metadata.filter((account) => account !== null) as AccountMetadata[]; 80}; 81 82export const GET: RequestHandler = async () => { 83 try { 84 const metadata = await getAllMetadataFromPds(); 85 return json(metadata); 86 } catch (error) { 87 console.error('Error fetching all accounts:', error); 88 return json( 89 { error: 'Failed to fetch accounts' }, 90 { status: 500 } 91 ); 92 } 93};