Something went wrong. Try again.
A Space host for truly public data
Something went wrong. Try again.
2.0 kB · 52 lines
TypeScript
at main
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253// Service identifiers, as used by registerNotify / unregisterNotify.//// A subscriber is named by a DID with an optional service fragment// (`did:web:syncer.example.com#atproto_space_syncer`) rather than a bare URL,// because notifyWrite is delivered with service auth addressed to that// identifier. The delivery endpoint comes from the DID document: the named// service entry, or — for a bare DID, which names an account — its// `#atproto_pds` entry.
import { type DidDocument } from '@atproto/identity'import { DID_RE } from './space-uri'
export type ServiceRef = { did: string; fragment?: string }
export function parseServiceId(id: string): ServiceRef | null { const hash = id.indexOf('#') const did = hash === -1 ? id : id.slice(0, hash) const fragment = hash === -1 ? undefined : id.slice(hash + 1) if (!DID_RE.test(did)) return null if (fragment !== undefined && !/^[A-Za-z0-9_.-]+$/.test(fragment)) return null return { did, fragment }}
/** The http(s) endpoint a service identifier resolves to, or null. */export async function resolveServiceEndpoint( resolveDidDoc: (did: string) => Promise<DidDocument | null>, service: ServiceRef,): Promise<string | null> { let doc: DidDocument | null try { doc = await resolveDidDoc(service.did) } catch { return null } if (!doc) return null return endpointFromDoc(doc, service.did, service.fragment ?? 'atproto_pds')}
/** The http(s) endpoint of a DID document's `#fragment` service entry, or null. */export function endpointFromDoc(doc: DidDocument, did: string, fragment: string): string | null { const id = `#${fragment}` const entry = doc.service?.find((s) => s.id === id || s.id === `${did}${id}`) const endpoint = entry?.serviceEndpoint if (typeof endpoint !== 'string') return null try { const url = new URL(endpoint) if (url.protocol !== 'https:' && url.protocol !== 'http:') return null } catch { return null } return endpoint.replace(/\/$/, '')}