Thread viewer for Bluesky
at master 58 lines 1.7 kB view raw
1import { appView } from '../api.js'; 2import { APIError } from './minisky.js'; 3 4/** 5 * Thrown when DID or DID document is invalid. 6 */ 7 8export class DIDError extends Error {} 9 10export class LoginError extends Error {} 11 12export async function pdsEndpointForDID(did: string): Promise<string> { 13 let documentURL: URL; 14 15 if (did.startsWith('did:plc:')) { 16 documentURL = new URL(`https://plc.directory/${did}`); 17 18 } else if (did.startsWith('did:web:')) { 19 let host = did.replace(/^did:web:/, ''); 20 documentURL = new URL(`https://${host}/.well-known/did.json`); 21 22 } else { 23 throw new DIDError(`Unknown DID type: ${did}`); 24 } 25 26 let response = await fetch(documentURL); 27 let text = await response.text(); 28 let json = text.trim().length > 0 ? JSON.parse(text) : undefined; 29 30 if (response.status == 200) { 31 let service = (json.service || []).find((s: json) => s.id == '#atproto_pds'); 32 33 if (service) { 34 return service.serviceEndpoint.replace('https://', ''); 35 } else { 36 throw new DIDError("Missing #atproto_pds service definition"); 37 } 38 } else { 39 throw new APIError(response.status, json); 40 } 41} 42 43export async function pdsEndpointForIdentifier(identifier: string): Promise<string> { 44 if (identifier.match(/^did:/)) { 45 return await pdsEndpointForDID(identifier); 46 47 } else if (identifier.match(/^[^@]+@[^@]+$/)) { 48 return 'bsky.social'; 49 50 } else if (identifier.match(/^@?[\w\-]+(\.[\w\-]+)+$/)) { 51 identifier = identifier.replace(/^@/, ''); 52 let did = await appView.resolveHandle(identifier); 53 return await pdsEndpointForDID(did); 54 55 } else { 56 throw new LoginError('Please enter your handle or DID.'); 57 } 58}