forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {
2 type $Typed,
3 type AppBskyGraphFollow,
4 type AppBskyGraphGetFollows,
5 type BskyAgent,
6 type ComAtprotoRepoApplyWrites,
7} from '@atproto/api'
8import {TID} from '@atproto/common-web'
9import chunk from 'lodash.chunk'
10
11import {until} from '#/lib/async/until'
12
13export async function bulkWriteFollows(agent: BskyAgent, dids: string[]) {
14 const session = agent.session
15
16 if (!session) {
17 throw new Error(`bulkWriteFollows failed: no session`)
18 }
19
20 const followRecords: $Typed<AppBskyGraphFollow.Record>[] = dids.map(did => {
21 return {
22 $type: 'app.bsky.graph.follow',
23 subject: did,
24 createdAt: new Date().toISOString(),
25 }
26 })
27
28 const followWrites: $Typed<ComAtprotoRepoApplyWrites.Create>[] =
29 followRecords.map(r => ({
30 $type: 'com.atproto.repo.applyWrites#create',
31 collection: 'app.bsky.graph.follow',
32 rkey: TID.nextStr(),
33 value: r,
34 }))
35
36 const chunks = chunk(followWrites, 50)
37 for (const chunk of chunks) {
38 await agent.com.atproto.repo.applyWrites({
39 repo: session.did,
40 writes: chunk,
41 })
42 }
43 await whenFollowsIndexed(agent, session.did, res => !!res.data.follows.length)
44
45 const followUris = new Map<string, string>()
46 for (const r of followWrites) {
47 followUris.set(
48 r.value.subject as string,
49 `at://${session.did}/app.bsky.graph.follow/${r.rkey}`,
50 )
51 }
52 return followUris
53}
54
55async function whenFollowsIndexed(
56 agent: BskyAgent,
57 actor: string,
58 fn: (res: AppBskyGraphGetFollows.Response) => boolean,
59) {
60 await until(
61 5, // 5 tries
62 1e3, // 1s delay between tries
63 fn,
64 () =>
65 agent.app.bsky.graph.getFollows({
66 actor,
67 limit: 1,
68 }),
69 )
70}