/** * Parsed AT-URI components */ export interface AtUri { protocol: string; did: string; collection: string; rkey: string; fragment?: string; } /** * Parse an AT-URI into its components * Format: at://did:method:identifier/collection/rkey#fragment */ export function parseAtUri(uri: string): AtUri { if (!uri.startsWith("at://")) { throw new Error(`Invalid AT-URI: must start with at:// - got ${uri}`); } const withoutProtocol = uri.slice(5); // Remove 'at://' const [didAndPath, fragment] = withoutProtocol.split("#"); const parts = didAndPath.split("/"); if (parts.length < 3) { throw new Error(`Invalid AT-URI: missing required parts - got ${uri}`); } const [did, collection, rkey, ...rest] = parts; if (rest.length > 0) { throw new Error(`Invalid AT-URI: too many path segments - got ${uri}`); } return { protocol: "at", did, collection, rkey, fragment, }; } /** * Build an AT-URI from components */ export function buildAtUri(components: Omit): string { const { did, collection, rkey, fragment } = components; let uri = `at://${did}/${collection}/${rkey}`; if (fragment) { uri += `#${fragment}`; } return uri; } /** * Extract just the record key from an AT-URI */ export function getRkeyFromUri(uri: string): string { return parseAtUri(uri).rkey; } /** * Extract the DID from an AT-URI */ export function getDidFromUri(uri: string): string { return parseAtUri(uri).did; } /** * Extract the collection from an AT-URI */ export function getCollectionFromUri(uri: string): string { return parseAtUri(uri).collection; } /** * Build a slice URI from DID and slice ID */ export function buildSliceUri(did: string, sliceId: string): string { return buildAtUri({ did, collection: "network.slices.slice", rkey: sliceId }); }