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}