a tool to help your Letta AI agents navigate bluesky
at main 2.8 kB view raw
1import { bsky } from "./bsky.ts"; 2/** 3 * Checks if user follows target on Bluesky. 4 * 5 * @param userDID - The DID of the user (does this user follow target?) 6 * @param targetDID - The DID of the target 7 * @returns `true` if user follows target, `false` if not, `null` if unable to determine 8 */ 9export const doesUserFollowTarget = async ( 10 userDID: string, 11 targetDID: string, 12): Promise<boolean | null> => { 13 const maxAPICalls = 50; 14 const itemsPerPage = 100; 15 // Reserve 2 API calls for fetching both user and target profiles 16 const maxFollowersToCheck = (maxAPICalls - 2) * itemsPerPage; 17 18 try { 19 // Fetch both profiles to determine which list is shorter 20 const [userProfile, targetProfile] = await Promise.all([ 21 bsky.getProfile({ actor: userDID }), 22 bsky.getProfile({ actor: targetDID }), 23 ]); 24 25 const userFollowingCount = userProfile.data.followsCount || 0; 26 const targetFollowersCount = targetProfile.data.followersCount || 0; 27 28 // If both counts exceed our limit, we can't reliably check 29 if ( 30 userFollowingCount > maxFollowersToCheck && 31 targetFollowersCount > maxFollowersToCheck 32 ) { 33 return null; 34 } 35 36 // Determine which list to check (choose the shorter one) 37 const checkUserFollowing = userFollowingCount <= targetFollowersCount; 38 39 let cursor: string | undefined = undefined; 40 let itemsChecked = 0; 41 42 while (itemsChecked < maxFollowersToCheck) { 43 if (checkUserFollowing) { 44 // Check who userDID follows 45 const { data: followsData } = await bsky.getFollows({ 46 actor: userDID, 47 limit: itemsPerPage, 48 cursor: cursor, 49 }); 50 51 // Check if targetDID is in the follows list 52 for (const followed of followsData.follows) { 53 if (followed.did === targetDID) { 54 return true; 55 } 56 } 57 58 itemsChecked += followsData.follows.length; 59 60 if (!followsData.cursor) { 61 break; 62 } 63 64 cursor = followsData.cursor; 65 } else { 66 // Check who follows targetDID 67 const { data: followersData } = await bsky.getFollowers({ 68 actor: targetDID, 69 limit: itemsPerPage, 70 cursor: cursor, 71 }); 72 73 // Check if userDID is in the followers list 74 for (const follower of followersData.followers) { 75 if (follower.did === userDID) { 76 return true; 77 } 78 } 79 80 itemsChecked += followersData.followers.length; 81 82 if (!followersData.cursor) { 83 break; 84 } 85 86 cursor = followersData.cursor; 87 } 88 } 89 90 // If we get here, we didn't find the relationship 91 return false; 92 } catch (_error) { 93 // Return null on any error - allows calling code to continue without this info 94 return null; 95 } 96};