Something went wrong. Try again.
A Bsky-like frontend using the atprotocol natively.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
const pdsCache = new Map<string, string>();
let resolvePromise: Promise<void> | null = null;
const pendingDids = new Set<string>();
export function getPdsUrlForDid(did: string): string | null { return pdsCache.get(did) ?? null;}
export function setPdsForDid(did: string, pdsUrl: string): void { pdsCache.set(did, pdsUrl.replace(/\/$/, ''));}
export async function resolvePdsForDids(dids: string[], timeoutMs = 10000): Promise<void> { if (!dids || dids.length === 0) return;
const uncached = dids.filter((d) => !pdsCache.has(d) && !pendingDids.has(d)); if (uncached.length === 0) return;
for (const did of uncached) pendingDids.add(did);
if (resolvePromise) { try { await Promise.race([ resolvePromise, new Promise<void>((_, reject) => setTimeout(() => reject(new Error('timeout')), timeoutMs)), ]); } catch { } const stillUncached = dids.filter((d) => !pdsCache.has(d)); if (stillUncached.length === 0) return; return resolvePdsForDids(stillUncached, timeoutMs); }
const toFetch = [...pendingDids];
resolvePromise = (async () => { try {
const batchSize = 10; for (let i = 0; i < toFetch.length; i += batchSize) { const batch = toFetch.slice(i, i + batchSize); const results = await Promise.allSettled( batch.map((did) => resolveDidToPds(did)), ); for (let j = 0; j < results.length; j++) { const result = results[j]; if (result.status === 'fulfilled' && result.value) { pdsCache.set(batch[j], result.value); } } } } catch {
} finally { pendingDids.clear(); resolvePromise = null; } })();
try { await Promise.race([ resolvePromise, new Promise<void>((_, reject) => setTimeout(() => reject(new Error('timeout')), timeoutMs)), ]); } catch { // Resolution timed out; URL rewriting will proceed without PDS URLs }}
export function getPdsCacheSize(): number { return pdsCache.size;}
export function clearPdsCache(): void { pdsCache.clear();}
interface DidDocument { id?: string; service?: Array<{ id: string; type: string; serviceEndpoint: string; }>;}
function fetchWithTimeout(url: string, timeoutMs: number): Promise<Response> { const controller = new AbortController(); const timer = setTimeout(() => controller.abort(), timeoutMs); return fetch(url, { signal: controller.signal }).finally(() => clearTimeout(timer));}
async function resolveDidToPds(did: string): Promise<string | null> { try { let doc: DidDocument;
if (did.startsWith('did:plc:')) { const resp = await fetchWithTimeout(`https://plc.directory/${encodeURIComponent(did)}`, 5000); if (!resp.ok) return null; doc = await resp.json(); } else if (did.startsWith('did:web:')) { const domain = did.slice('did:web:'.length); const resp = await fetchWithTimeout(`https://${domain}/.well-known/did.json`, 5000); if (!resp.ok) return null; doc = await resp.json(); } else { return null; }
const pdsService = doc.service?.find( (s) => s.id === '#atproto_pds' || s.type === 'AtprotoPersonalDataServer', );
if (pdsService?.serviceEndpoint) { return pdsService.serviceEndpoint.replace(/\/$/, ''); }
return null; } catch { return null; }}