my fork of the bluesky client
at main 163 lines 4.2 kB view raw
1import { 2 AppBskyActorDefs, 3 AppBskyGraphGetStarterPack, 4 BskyAgent, 5 Facet, 6} from '@atproto/api' 7import {msg} from '@lingui/macro' 8import {useLingui} from '@lingui/react' 9import {useMutation} from '@tanstack/react-query' 10 11import {until} from '#/lib/async/until' 12import {sanitizeDisplayName} from '#/lib/strings/display-names' 13import {sanitizeHandle} from '#/lib/strings/handles' 14import {enforceLen} from '#/lib/strings/helpers' 15import {useAgent} from '#/state/session' 16 17export const createStarterPackList = async ({ 18 name, 19 description, 20 descriptionFacets, 21 profiles, 22 agent, 23}: { 24 name: string 25 description?: string 26 descriptionFacets?: Facet[] 27 profiles: AppBskyActorDefs.ProfileViewBasic[] 28 agent: BskyAgent 29}): Promise<{uri: string; cid: string}> => { 30 if (profiles.length === 0) throw new Error('No profiles given') 31 32 const list = await agent.app.bsky.graph.list.create( 33 {repo: agent.session!.did}, 34 { 35 name, 36 description, 37 descriptionFacets, 38 avatar: undefined, 39 createdAt: new Date().toISOString(), 40 purpose: 'app.bsky.graph.defs#referencelist', 41 }, 42 ) 43 if (!list) throw new Error('List creation failed') 44 await agent.com.atproto.repo.applyWrites({ 45 repo: agent.session!.did, 46 writes: [ 47 createListItem({did: agent.session!.did, listUri: list.uri}), 48 ].concat( 49 profiles 50 // Ensure we don't have ourselves in this list twice 51 .filter(p => p.did !== agent.session!.did) 52 .map(p => createListItem({did: p.did, listUri: list.uri})), 53 ), 54 }) 55 56 return list 57} 58 59export function useGenerateStarterPackMutation({ 60 onSuccess, 61 onError, 62}: { 63 onSuccess: ({uri, cid}: {uri: string; cid: string}) => void 64 onError: (e: Error) => void 65}) { 66 const {_} = useLingui() 67 const agent = useAgent() 68 69 return useMutation<{uri: string; cid: string}, Error, void>({ 70 mutationFn: async () => { 71 let profile: AppBskyActorDefs.ProfileViewBasic | undefined 72 let profiles: AppBskyActorDefs.ProfileViewBasic[] | undefined 73 74 await Promise.all([ 75 (async () => { 76 profile = ( 77 await agent.app.bsky.actor.getProfile({ 78 actor: agent.session!.did, 79 }) 80 ).data 81 })(), 82 (async () => { 83 profiles = ( 84 await agent.app.bsky.actor.searchActors({ 85 q: encodeURIComponent('*'), 86 limit: 49, 87 }) 88 ).data.actors.filter(p => p.viewer?.following) 89 })(), 90 ]) 91 92 if (!profile || !profiles) { 93 throw new Error('ERROR_DATA') 94 } 95 96 // We include ourselves when we make the list 97 if (profiles.length < 7) { 98 throw new Error('NOT_ENOUGH_FOLLOWERS') 99 } 100 101 const displayName = enforceLen( 102 profile.displayName 103 ? sanitizeDisplayName(profile.displayName) 104 : `@${sanitizeHandle(profile.handle)}`, 105 25, 106 true, 107 ) 108 const starterPackName = _(msg`${displayName}'s Starter Pack`) 109 110 const list = await createStarterPackList({ 111 name: starterPackName, 112 profiles, 113 agent, 114 }) 115 116 return await agent.app.bsky.graph.starterpack.create( 117 { 118 repo: agent.session!.did, 119 }, 120 { 121 name: starterPackName, 122 list: list.uri, 123 createdAt: new Date().toISOString(), 124 }, 125 ) 126 }, 127 onSuccess: async data => { 128 await whenAppViewReady(agent, data.uri, v => { 129 return typeof v?.data.starterPack.uri === 'string' 130 }) 131 onSuccess(data) 132 }, 133 onError: error => { 134 onError(error) 135 }, 136 }) 137} 138 139function createListItem({did, listUri}: {did: string; listUri: string}) { 140 return { 141 $type: 'com.atproto.repo.applyWrites#create', 142 collection: 'app.bsky.graph.listitem', 143 value: { 144 $type: 'app.bsky.graph.listitem', 145 subject: did, 146 list: listUri, 147 createdAt: new Date().toISOString(), 148 }, 149 } 150} 151 152async function whenAppViewReady( 153 agent: BskyAgent, 154 uri: string, 155 fn: (res?: AppBskyGraphGetStarterPack.Response) => boolean, 156) { 157 await until( 158 5, // 5 tries 159 1e3, // 1s delay between tries 160 fn, 161 () => agent.app.bsky.graph.getStarterPack({starterPack: uri}), 162 ) 163}