diff --git a/ios/patching/038-social-app-ios-profile-services.patch b/ios/patching/038-social-app-ios-profile-services.patch index 4867998..d9064ac 100644 --- a/ios/patching/038-social-app-ios-profile-services.patch +++ b/ios/patching/038-social-app-ios-profile-services.patch @@ -7,20 +7,19 @@ import { type AppBskyActorDefs, moderateProfile, -@@ -9,9 +9,12 @@ +@@ -9,9 +9,11 @@ } from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' +import {useQuery} from '@tanstack/react-query' import {useActorStatus} from '#/lib/actor-status' -+import {BSKY_SERVICE} from '#/lib/constants' import {useHaptics} from '#/lib/haptics' +import {useOpenLink} from '#/lib/hooks/useOpenLink' import {sanitizeDisplayName} from '#/lib/strings/display-names' import {sanitizeHandle} from '#/lib/strings/handles' import {logger} from '#/logger' -@@ -45,6 +48,84 @@ +@@ -45,6 +47,103 @@ import {ProfileHeaderMetrics} from './Metrics' import {ProfileHeaderShell} from './Shell' import {ProfileHeaderSuggestedFollows} from './SuggestedFollows' @@ -31,6 +30,24 @@ + 'atproto.com': require('../../../../assets/favicons/atproto.com.png'), +} + ++async function resolvePds(did: string): Promise { ++ if (did.startsWith('did:web:')) { ++ const host = did.split(':').slice(2).join(':') ++ const res = await fetch(`https://${host}/.well-known/did.json`) ++ if (!res.ok) throw new Error('failed to resolve did:web') ++ const doc = await res.json() ++ const pds = doc.service?.find((s: any) => s.id === '#atproto_pds')?.serviceEndpoint ++ if (pds) return pds ++ return `https://${host}` ++ } ++ const res = await fetch(`https://plc.directory/${did}`) ++ if (!res.ok) throw new Error('failed to resolve DID') ++ const doc = await res.json() ++ const pds = doc.service?.find((s: any) => s.id === '#atproto_pds')?.serviceEndpoint ++ if (!pds) throw new Error('no PDS found') ++ return pds ++} ++ +function ProfileServiceLinks({ + profile, +}: { @@ -42,8 +59,9 @@ + const {data: services} = useQuery({ + queryKey: ['profile-services', profile.did], + queryFn: async () => { ++ const pds = await resolvePds(profile.did) + const res = await fetch( -+ `${BSKY_SERVICE}/xrpc/com.atproto.repo.describeRepo?repo=${encodeURIComponent(profile.did)}`, ++ `${pds}/xrpc/com.atproto.repo.describeRepo?repo=${encodeURIComponent(profile.did)}`, + ) + if (!res.ok) throw new Error('failed') + const data = await res.json() @@ -105,7 +123,7 @@ interface Props { profile: AppBskyActorDefs.ProfileViewDetailed -@@ -151,6 +232,7 @@ +@@ -151,6 +250,7 @@ {!isPlaceholderProfile && !isBlockedUser && ( diff --git a/ios/patching/ProfileAtLinks.tsx b/ios/patching/ProfileAtLinks.tsx index bad7a66..88feb3f 100644 --- a/ios/patching/ProfileAtLinks.tsx +++ b/ios/patching/ProfileAtLinks.tsx @@ -3,7 +3,6 @@ import {Pressable, View} from 'react-native' import {type AppBskyActorDefs} from '@atproto/api' import {useQuery} from '@tanstack/react-query' -import {BSKY_SERVICE} from '#/lib/constants' import {useOpenLink} from '#/lib/hooks/useOpenLink' import {atoms as a, useTheme} from '#/alf' import {Text} from '#/components/Typography' @@ -66,6 +65,26 @@ const SERVICE_CONFIG: Record< }, } +// --- PDS Resolution --- + +async function resolvePds(did: string): Promise { + if (did.startsWith('did:web:')) { + const host = did.split(':').slice(2).join(':') + const res = await fetch(`https://${host}/.well-known/did.json`) + if (!res.ok) throw new Error('failed to resolve did:web') + const doc = await res.json() + const pds = doc.service?.find((s: any) => s.id === '#atproto_pds')?.serviceEndpoint + if (pds) return pds + return `https://${host}` + } + const res = await fetch(`https://plc.directory/${did}`) + if (!res.ok) throw new Error('failed to resolve DID') + const doc = await res.json() + const pds = doc.service?.find((s: any) => s.id === '#atproto_pds')?.serviceEndpoint + if (!pds) throw new Error('no PDS found') + return pds +} + // --- Component --- export function ProfileAtLinks({ @@ -79,8 +98,9 @@ export function ProfileAtLinks({ const {data: linkData} = useQuery({ queryKey: ['at-links', profile.did], queryFn: async () => { + const pds = await resolvePds(profile.did) const res = await fetch( - `${BSKY_SERVICE}/xrpc/com.atproto.repo.getRecord?repo=${encodeURIComponent(profile.did)}&collection=ai.syui.at.link&rkey=self`, + `${pds}/xrpc/com.atproto.repo.getRecord?repo=${encodeURIComponent(profile.did)}&collection=ai.syui.at.link&rkey=self`, ) if (!res.ok) throw new Error('not found') const json = await res.json()