Retro Bulletin Board Systems on atproto. Web app and TUI. lazy mirror of alyraffauf/atbbs atbbs.xyz
forums python tui atproto bbs
3
fork

Configure Feed

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

at master 61 lines 1.7 kB view raw
1/** Fetch a random list of BBSes from the Lightrail API, with avatars. */ 2 3import { getAvatars, getRecord, resolveIdentitiesBatch } from "./atproto"; 4import { SITE } from "./lexicon"; 5import { SERVICES } from "./shared"; 6import { isSiteRecord } from "./recordGuards"; 7 8export interface DiscoveredBBS { 9 did: string; 10 handle: string; 11 name: string; 12 description: string; 13 avatar?: string; 14} 15 16interface LightrailRepo { 17 did: string; 18} 19 20export async function fetchDiscovery(): Promise<DiscoveredBBS[]> { 21 let repos: LightrailRepo[] = []; 22 try { 23 const response = await fetch( 24 `${SERVICES.lightrail}/com.atproto.sync.listReposByCollection?collection=${SITE}&limit=50`, 25 ); 26 const data = (await response.json()) as { repos: LightrailRepo[] }; 27 repos = data.repos; 28 } catch { 29 return []; 30 } 31 if (!repos.length) return []; 32 33 const shuffled = repos.sort(() => Math.random() - 0.5); 34 const identities = await resolveIdentitiesBatch( 35 shuffled.map((repo) => repo.did), 36 ); 37 38 const items: DiscoveredBBS[] = []; 39 for (const repo of shuffled) { 40 if (!(repo.did in identities)) continue; 41 try { 42 const siteRecord = await getRecord(repo.did, SITE, "self"); 43 if (!isSiteRecord(siteRecord)) continue; 44 items.push({ 45 did: repo.did, 46 handle: identities[repo.did].handle, 47 name: siteRecord.value.name || identities[repo.did].handle, 48 description: siteRecord.value.description || "", 49 }); 50 } catch { 51 continue; 52 } 53 } 54 55 const avatars = await getAvatars(items.map((item) => item.did)); 56 for (const item of items) { 57 item.avatar = avatars[item.did]; 58 } 59 60 return items; 61}