Thread viewer for Bluesky
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}