Suite of AT Protocol TypeScript libraries built on web standards
21
fork

Configure Feed

Select the types of activity you want to include in your feed.

format

+78 -49
+1 -1
cli/commands/lex.ts
··· 9 9 .command("gen-api", genApi) 10 10 .command("gen-md", genMd) 11 11 .command("gen-server", genServer) 12 - .command("gen-ts-obj", genTsObj); 12 + .command("gen-ts-obj", genTsObj);
+76 -47
cli/get.ts
··· 1 1 import { AtUri } from "@atp/syntax"; 2 2 import { IdResolver } from "@atp/identity"; 3 3 import { XrpcClient } from "@atp/xrpc"; 4 - import { Select, prompt } from "@cliffy/prompt"; 4 + import { prompt, Select } from "@cliffy/prompt"; 5 5 import { lexicons } from "@atproto/api"; 6 6 import process from "node:process"; 7 7 ··· 22 22 23 23 async function resolveDid(input: string): Promise<string> { 24 24 const idResolver = new IdResolver({}); 25 - 25 + 26 26 if (!input.startsWith("did:")) { 27 27 const handleResolution = await idResolver.handle.resolve(input); 28 28 if (!handleResolution) { ··· 30 30 } 31 31 return handleResolution; 32 32 } 33 - 33 + 34 34 return input; 35 35 } 36 36 37 37 async function getPdsUrl(did: string): Promise<string> { 38 38 const idResolver = new IdResolver({}); 39 39 const didDoc = await idResolver.did.resolve(did); 40 - 40 + 41 41 if (!didDoc?.service) { 42 42 throw new Error(`Could not resolve DID document for ${did}`); 43 43 } 44 - 44 + 45 45 const pdsService = didDoc.service.find( 46 - (s) => s.id === "#atproto_pds" || s.type === "AtprotoPersonalDataServer" 46 + (s) => s.id === "#atproto_pds" || s.type === "AtprotoPersonalDataServer", 47 47 ); 48 - 48 + 49 49 if (!pdsService?.serviceEndpoint) { 50 50 throw new Error(`Could not find PDS endpoint for ${did}`); 51 51 } 52 - 52 + 53 53 return typeof pdsService.serviceEndpoint === "string" 54 54 ? pdsService.serviceEndpoint 55 55 : String(pdsService.serviceEndpoint); ··· 66 66 const response = await xrpcClient.call("com.atproto.repo.describeRepo", { 67 67 repo: did, 68 68 }); 69 - 69 + 70 70 const collections = response.data.collections || []; 71 - 71 + 72 72 if (collections.length === 0) { 73 73 throw new Error(`No collections found for ${did}`); 74 74 } 75 - 75 + 76 76 return collections; 77 77 } 78 78 ··· 86 86 collection, 87 87 limit: 100, 88 88 }); 89 - 89 + 90 90 return response.data.records || []; 91 91 } 92 92 ··· 96 96 collection: string, 97 97 ): Promise<RecordInfo[]> { 98 98 const records = await listRecords(xrpcClient, did, collection); 99 - 99 + 100 100 if (records.length === 0) { 101 101 throw new Error(`No records found in collection ${collection}`); 102 102 } 103 - 103 + 104 104 return records; 105 105 } 106 106 ··· 115 115 collection, 116 116 rkey, 117 117 }); 118 - 118 + 119 119 return response.data; 120 120 } 121 121 122 - function formatRecordOption(record: RecordInfo): { name: string; value: RecordInfo } { 123 - const rkey = record.uri.split('/').pop() || ""; 122 + function formatRecordOption( 123 + record: RecordInfo, 124 + ): { name: string; value: RecordInfo } { 125 + const rkey = record.uri.split("/").pop() || ""; 124 126 const value = record.value || {}; 125 - const displayName = (value.displayName || value.name || value.title || "") as string; 126 - 127 + const displayName = 128 + (value.displayName || value.name || value.title || "") as string; 129 + 127 130 const name = `${rkey}${displayName ? ` - ${displayName}` : ""}`; 128 - 131 + 129 132 return { name, value: record }; 130 133 } 131 134 ··· 138 141 name: "collection", 139 142 message: `Select a collection from ${did}:`, 140 143 type: Select, 141 - before: async (_answers: unknown, next: (skip?: number | boolean) => Promise<void>) => { 144 + before: async ( 145 + _answers: unknown, 146 + next: (skip?: number | boolean) => Promise<void>, 147 + ) => { 142 148 state.collections = await loadCollections(xrpcClient, did); 143 149 collectionPrompt.options = state.collections.map((col: string) => ({ 144 150 name: col, ··· 150 156 options: [] as Array<{ name: string; value: unknown }>, 151 157 search: false, 152 158 maxRows: 10, 153 - after: async (answers: Record<string, unknown>, next: () => Promise<void>) => { 159 + after: async ( 160 + answers: Record<string, unknown>, 161 + next: () => Promise<void>, 162 + ) => { 154 163 state.collection = answers.collection as string; 155 164 await next(); 156 165 }, 157 166 }; 158 - 167 + 159 168 return collectionPrompt; 160 169 } 161 170 ··· 168 177 name: "record", 169 178 message: `Select a record from ${state.collection || "collection"}:`, 170 179 type: Select, 171 - before: async (_answers: unknown, next: (skip?: number | boolean) => Promise<void>) => { 180 + before: async ( 181 + _answers: unknown, 182 + next: (skip?: number | boolean) => Promise<void>, 183 + ) => { 172 184 if (state.rkey) { 173 185 await next(1); 174 186 return; 175 187 } 176 - 188 + 177 189 if (!state.collection) { 178 190 throw new Error("Collection is required"); 179 191 } 180 - 192 + 181 193 state.records = await loadRecords(xrpcClient, did, state.collection); 182 - 194 + 183 195 if (state.records.length === 1) { 184 196 const singleRecord = state.records[0].value || state.records[0]; 185 - state.rkey = state.records[0].uri.split('/').pop() || ""; 197 + state.rkey = state.records[0].uri.split("/").pop() || ""; 186 198 console.log(JSON.stringify(singleRecord, null, 2)); 187 199 state.recordAlreadyShown = true; 188 200 await next(true); 189 201 return; 190 202 } 191 - 203 + 192 204 recordPrompt.options = state.records.map(formatRecordOption); 193 205 recordPrompt.search = state.records.length > 5; 194 206 await next(); ··· 196 208 options: [] as Array<{ name: string; value: unknown }>, 197 209 search: false, 198 210 maxRows: 10, 199 - after: async (answers: Record<string, unknown>, next: () => Promise<void>) => { 211 + after: async ( 212 + answers: Record<string, unknown>, 213 + next: () => Promise<void>, 214 + ) => { 200 215 const selected = answers.record as RecordInfo | string | undefined; 201 216 if (selected) { 202 217 if (typeof selected === "object" && "uri" in selected) { 203 - state.rkey = selected.uri.split('/').pop() || ""; 218 + state.rkey = selected.uri.split("/").pop() || ""; 204 219 } else if (typeof selected === "string") { 205 220 state.rkey = selected; 206 221 } ··· 208 223 await next(); 209 224 }, 210 225 }; 211 - 226 + 212 227 return recordPrompt; 213 228 } 214 229 ··· 221 236 name: "fetch", 222 237 message: "", 223 238 type: Select, 224 - before: async (_answers: unknown, next: (skip?: number | boolean) => Promise<void>) => { 239 + before: async ( 240 + _answers: unknown, 241 + next: (skip?: number | boolean) => Promise<void>, 242 + ) => { 225 243 if (state.recordAlreadyShown) { 226 244 await next(true); 227 245 return; 228 246 } 229 - 247 + 230 248 if (!state.collection || !state.rkey) { 231 249 throw new Error("Collection and rkey are required"); 232 250 } 233 - 234 - const record = await fetchRecord(xrpcClient, did, state.collection, state.rkey); 251 + 252 + const record = await fetchRecord( 253 + xrpcClient, 254 + did, 255 + state.collection, 256 + state.rkey, 257 + ); 235 258 console.log(JSON.stringify(record, null, 2)); 236 259 await next(true); 237 260 }, ··· 241 264 242 265 export async function handleGetCommand(input: string) { 243 266 try { 244 - const isFullUri = input.includes('/'); 267 + const isFullUri = input.includes("/"); 245 268 let atUri: AtUri | null = null; 246 269 let did: string; 247 - 270 + 248 271 if (isFullUri) { 249 272 atUri = new AtUri(input); 250 273 did = await resolveDid(atUri.hostname); 251 274 } else { 252 275 did = await resolveDid(input); 253 276 } 254 - 277 + 255 278 const pdsUrl = await getPdsUrl(did); 256 279 const xrpcClient = createXrpcClient(pdsUrl); 257 - 280 + 258 281 const state: PromptState = { 259 282 collection: atUri?.collection, 260 283 rkey: atUri?.rkey, 261 284 recordAlreadyShown: false, 262 285 }; 263 - 286 + 264 287 const prompts: Array<{ 265 288 name: string; 266 289 message: string; 267 290 type: typeof Select; 268 - before?: (answers: unknown, next: (skip?: number | boolean) => Promise<void>) => Promise<void>; 269 - after?: (answers: Record<string, unknown>, next: () => Promise<void>) => Promise<void>; 291 + before?: ( 292 + answers: unknown, 293 + next: (skip?: number | boolean) => Promise<void>, 294 + ) => Promise<void>; 295 + after?: ( 296 + answers: Record<string, unknown>, 297 + next: () => Promise<void>, 298 + ) => Promise<void>; 270 299 options: Array<{ name: string; value: unknown }>; 271 300 search?: boolean; 272 301 maxRows?: number; 273 302 }> = []; 274 - 303 + 275 304 if (!state.collection) { 276 305 prompts.push(createCollectionPrompt(did, xrpcClient, state)); 277 306 } 278 - 307 + 279 308 prompts.push(createRecordPrompt(did, xrpcClient, state)); 280 309 prompts.push(createFetchPrompt(did, xrpcClient, state)); 281 - 310 + 282 311 await prompt(prompts as unknown as Parameters<typeof prompt>[0]); 283 312 } catch (error) { 284 313 const errorMessage = error instanceof Error ? error.message : String(error); ··· 286 315 if (isDeno) Deno.exit(1); 287 316 else process.exit(1); 288 317 } 289 - } 318 + }
+1 -1
identity/handle/index.ts
··· 68 68 try { 69 69 const backupIps = await this.getBackupNameserverIps(); 70 70 if (!backupIps || backupIps.length < 1) return undefined; 71 - const nameServers = backupIps.map(ip => ({ ipAddr: ip })); 71 + const nameServers = backupIps.map((ip) => ({ ipAddr: ip })); 72 72 chunkedResults = await Deno.resolveDns(`${SUBDOMAIN}.${handle}`, "TXT", { 73 73 nameServer: nameServers[0], // Use first backup server 74 74 });