bsky follow audit script
1import { USER_AGENT } from "./constants"; 2import type { FollowRecord, MiniDoc, Post } from "./types"; 3 4// https://stackoverflow.com/questions/3224834/get-difference-between-2-dates-in-javascript 5export function getDateDifferenceInDays(start: Date, end: Date) { 6 const MS_PER_DAY = 1000 * 60 * 60 * 24; 7 const startUTCDate = Date.UTC( 8 start.getFullYear(), 9 start.getMonth(), 10 start.getDate(), 11 ); 12 const endUTCDate = Date.UTC(end.getFullYear(), end.getMonth(), end.getDate()); 13 return Math.floor((endUTCDate - startUTCDate) / MS_PER_DAY); 14} 15 16export async function resolveIdentity(indentifier: string): Promise<MiniDoc> { 17 try { 18 const response = await fetch( 19 `https://slingshot.microcosm.blue/xrpc/com.bad-example.identity.resolveMiniDoc?identifier=${indentifier}`, 20 { 21 headers: { 22 "User-Agent": USER_AGENT, 23 }, 24 }, 25 ); 26 if (!response.ok) { 27 // throw new Error(`Failed to fetch minidoc for ${indentifier}. Status - ${response.status}`) 28 console.error( 29 `Failed to fetch minidoc for ${indentifier}. Status - ${response.status}`, 30 ); 31 } 32 const data = (await response.json()) as MiniDoc; 33 return data; 34 } catch (error) { 35 if (error instanceof Error) { 36 console.error(error.message); 37 } 38 throw error; 39 } 40} 41 42export async function getRecentPost(doc: MiniDoc) { 43 try { 44 console.info( 45 `${doc.pds}/xrpc/com.atproto.repo.listRecords?repo=${doc.did}&collection=app.bsky.feed.post&limit=1`, 46 ); 47 if (typeof doc.pds === "undefined") { 48 console.info("could not get pds info, skipping"); 49 return; 50 } 51 52 const response = await fetch( 53 `${doc.pds}/xrpc/com.atproto.repo.listRecords?repo=${doc.did}&collection=app.bsky.feed.post&limit=1`, 54 { 55 headers: { 56 "User-Agent": USER_AGENT, 57 }, 58 }, 59 ); 60 if (!response.ok) { 61 console.error( 62 `There was an error fetching posts for ${doc.handle}. Status - ${response.status}`, 63 ); 64 } 65 const data = (await response.json()) as { records: Post[] }; 66 return data; 67 } catch (error) { 68 if (error instanceof Error) { 69 console.error(error.message); 70 } 71 72 throw error; 73 } 74} 75 76export async function getFollowRecords(doc: MiniDoc, cursor?: string) { 77 try { 78 const response = await fetch( 79 `${doc.pds}/xrpc/com.atproto.repo.listRecords?repo=${doc.did}&collection=app.bsky.graph.follow&limit=100&cursor=${cursor}`, 80 { 81 headers: { 82 "User-Agent": USER_AGENT, 83 }, 84 }, 85 ); 86 if (!response.ok) { 87 console.error("There was an error fetching follow records"); 88 } 89 90 const data = (await response.json()) as { 91 cursor: string; 92 records: FollowRecord[]; 93 }; 94 95 return { 96 cursor: data?.cursor, 97 follows: data?.records, 98 }; 99 } catch (error) { 100 if (error instanceof Error) { 101 console.error(error.message); 102 } 103 104 throw error; 105 } 106}