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