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