https://domlink.deployments.hotsocket.fyi/
at main 110 lines 3.9 kB view raw
1// skinny atproto types file for supporting constellation.ts 2 3const DEFAULT_SERVICE = "https://api.bsky.app"; 4 5/** Type used to imply that a parameter will be run through {@link ValidateNSID} */ 6export type NSID = string; 7const NSIDExpression = /^[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(\.[a-zA-Z]([a-zA-Z0-9]{0,62})?)$/; 8export function ValidateNSID(nsid: string): string | null { 9 return NSIDExpression.test(nsid) ? nsid : null; 10} 11 12export type Handle = string; 13export function StripHandle(handle: Handle) { 14 return handle.replace("@", ""); 15} 16export type DID = `did:${"web"|"plc"}:${string}`; 17export function ValidateDID(did: string): string | null { 18 const parts = did.split(":"); 19 const isValid = parts.length == 3 && parts[0] == "did" && (parts[1] == "plc" || parts[1] == "web") && parts[2].length > 0; 20 return isValid ? did : null; 21} 22 23export type AtURIString = string; //`at://${string}/${string}/${string}`; 24export class AtURI { 25 readonly authority: string | null; 26 readonly collection: string | null; 27 readonly rkey: string | null; 28 static fromString(uri: AtURIString): AtURI { 29 const parts = uri.split("/").slice(2); 30 return new AtURI(ValidateDID(parts[0]), ValidateNSID(parts[1]), parts[2]); 31 } 32 constructor(authority: string | null, collection: string | null = null, rkey: string | null = null) { 33 this.authority = authority; 34 this.collection = collection; 35 this.rkey = rkey; 36 } 37 /** 38 * Converts URI to at:// URI. 39 * @returns The string form of this URI, unless if any parts are specified without any preceding elements. 40 * @example ``` 41 * // Invalid collection NSID, returns null. 42 * new AtURI("at://did:web:example.com/cheese/abc123").toString() 43 * // Invalid 'authority' DID, returns null. 44 * new AtURI("at://not-a-did/com.example.nsid").toString() 45 * // All good and happy, returns the string fed in. 46 * new AtURI("at://did:web:example.com/com.example.nsid/abc123").toString() 47 * ``` 48 */ 49 toString(): string | null { 50 const ret: (string|null)[] = ["at://"]; 51 // using `?? ""` to have a "bad" value to find 52 if (this.authority) { 53 ret.push(this.authority ?? ""); 54 } else ret.push(null); 55 if (this.collection) { 56 if (ret.indexOf(null) != -1) {return null;} 57 ret.push("/"); 58 ret.push(this.collection ?? ""); 59 } else ret.push(null); 60 if (this.rkey) { 61 if (ret.indexOf(null) != -1) {return null;} 62 ret.push("/"); 63 ret.push(this.rkey ?? ""); 64 } 65 return ret.join(""); 66 } 67} 68 69export type RecordResponse<T> = { 70 cid: string; 71 uri: AtURIString; 72 value: T; 73} 74 75// technically you can cast it to whatever you want but i feel like using a generic(?) makes it cleaner 76/** Calls an XRPC "query" method (HTTP GET) 77 * @param service Defaults to the {@link https://api.bsky.app/ Bluesky (PBC) API} service. 78*/ 79export async function XQuery<T>(method: string, params: Record<string, string | number | null> | null = null, service: string = DEFAULT_SERVICE) { 80 let QueryURL = `${service}/xrpc/${method}`; 81 if (params) { 82 const usp = new URLSearchParams(); 83 for (const key in params) { 84 if (params[key]) { 85 usp.append(key, params[key].toString()); 86 } 87 } 88 QueryURL += "?" + usp.toString(); 89 } 90 return (await (await fetch(QueryURL)).json()) as T; 91} 92/** Calls com.atproto.repo.getRecord with XQuery */ 93export async function GetRecord<T>(uri: AtURI, service: string = "https://slingshot.microcosm.blue") { 94 return await XQuery<RecordResponse<T>>("com.atproto.repo.getRecord", { 95 repo: uri.authority!, 96 collection: uri.collection!, 97 rkey: uri.rkey! 98 }, service); 99} 100type ListRecordsResponse<T> = { 101 cursor: string; 102 records: RecordResponse<T>[]; 103}; 104export async function ListRecords<T>(repo: string, collection: NSID, service: string, limit: number = 50) { 105 return await XQuery<ListRecordsResponse<T>>("com.atproto.repo.listRecords", { 106 repo: repo, 107 collection: collection, 108 limit: limit 109 }, service); 110}