Graphical PDS migrator for AT Protocol
1import { IdResolver } from "npm:@atproto/identity"; 2import { Did } from "npm:@atproto/api"; 3 4interface AtprotoData { 5 did: string; 6 signingKey: string; 7 handle: string; 8 pds: string; 9} 10 11interface DidService { 12 id: string; 13 type: string; 14 serviceEndpoint: string; 15} 16 17/** 18 * ID resolver instance. 19 */ 20const idResolver = createIdResolver(); 21export const resolver = createBidirectionalResolver(idResolver); 22 23/** 24 * Create the ID resolver. 25 * @returns The ID resolver 26 */ 27export function createIdResolver() { 28 return new IdResolver(); 29} 30 31/** 32 * The bidirectional resolver. 33 * @interface 34 */ 35export interface BidirectionalResolver { 36 resolveDidToHandle(did: string): Promise<string>; 37 resolveDidsToHandles(dids: string[]): Promise<Record<string, string>>; 38 resolveDidToPdsUrl(did: string): Promise<string | undefined>; 39} 40 41/** 42 * Create the bidirectional resolver. 43 * @param resolver - The ID resolver 44 * @returns The bidirectional resolver 45 */ 46export function createBidirectionalResolver(resolver: IdResolver) { 47 return { 48 async resolveDidToHandle(did: string): Promise<string> { 49 const didDoc = await resolver.did.resolveAtprotoData(did) as AtprotoData; 50 const resolvedHandle = await resolver.handle.resolve(didDoc.handle); 51 if (resolvedHandle === did) { 52 return didDoc.handle; 53 } 54 return did; 55 }, 56 57 async resolveHandleToDid(handle: string) { 58 return await resolver.handle.resolve(handle) as Did 59 }, 60 61 async resolveDidToPdsUrl(did: string): Promise<string | undefined> { 62 try { 63 // First try the standard resolution 64 const didDoc = await resolver.did.resolveAtprotoData( 65 did, 66 ) as AtprotoData; 67 if (didDoc.pds) { 68 return didDoc.pds; 69 } else { 70 const forcedDidDoc = await resolver.did.resolveAtprotoData( 71 did, 72 true, 73 ) 74 if (forcedDidDoc.pds) { 75 return forcedDidDoc.pds; 76 } 77 } 78 } catch (err) { 79 console.error("Error resolving PDS URL:", err); 80 return undefined; 81 } 82 }, 83 84 async resolveDidsToHandles( 85 dids: string[], 86 ): Promise<Record<string, string>> { 87 const didHandleMap: Record<string, string> = {}; 88 const resolves = await Promise.all( 89 dids.map((did) => this.resolveDidToHandle(did).catch((_) => did)), 90 ); 91 for (let i = 0; i < dids.length; i++) { 92 didHandleMap[dids[i]] = resolves[i]; 93 } 94 return didHandleMap; 95 }, 96 }; 97}