forked from
jollywhoppers.com/witchsky.app
fork
Configure Feed
Select the types of activity you want to include in your feed.
Bluesky app fork with some witchin' additions 馃挮
fork
Configure Feed
Select the types of activity you want to include in your feed.
1import {type Did, isDid} from '@atproto/api'
2import {useQuery} from '@tanstack/react-query'
3
4import {STALE} from '.'
5import {LRU} from './direct-fetch-record'
6const RQKEY_ROOT = 'resolve-identity'
7export const RQKEY = (did: string) => [RQKEY_ROOT, did]
8
9// this isn't trusted...
10export type DidDocument = {
11 '@context'?: string[]
12 id?: string
13 alsoKnownAs?: string[]
14 verificationMethod?: VerificationMethod[]
15 service?: Service[]
16}
17
18export type VerificationMethod = {
19 id?: string
20 type?: string
21 controller?: string
22 publicKeyMultibase?: string
23}
24
25export type Service = {
26 id?: string
27 type?: string
28 serviceEndpoint?: string
29}
30
31const serviceCache = new LRU<Did, DidDocument>()
32
33export async function resolveDidDocument(did: Did) {
34 return await serviceCache.getOrTryInsertWith(did, async () => {
35 const docUrl = did.startsWith('did:plc:')
36 ? `https://plc.directory/${did}`
37 : `https://${did.substring(8)}/.well-known/did.json`
38
39 // TODO: we should probably validate this...
40 return await (await fetch(docUrl)).json()
41 })
42}
43
44export function findService(doc: DidDocument, id: string, type?: string) {
45 // probably not defensive enough, but we don't have atproto/did as a dep...
46 if (!Array.isArray(doc?.service)) return
47 return doc.service.find(
48 s => s?.serviceEndpoint && s?.id === id && (!type || s?.type === type),
49 )
50}
51
52export async function resolvePdsServiceUrl(did: Did) {
53 const doc = await resolveDidDocument(did)
54 return findService(doc, '#atproto_pds', 'AtprotoPersonalDataServer')
55 ?.serviceEndpoint
56}
57
58export function useDidDocument({did}: {did: string}) {
59 return useQuery<DidDocument | undefined>({
60 staleTime: STALE.HOURS.ONE,
61 queryKey: RQKEY(did || ''),
62 async queryFn() {
63 if (!isDid(did)) return undefined
64 return await resolveDidDocument(did)
65 },
66 enabled: isDid(did) && !(did.includes('#') || did.includes('?')),
67 })
68}