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