[READ-ONLY] a fast, modern browser for the npm registry
at main 117 lines 4.3 kB view raw
1import { CONSTELLATION_HOST } from '#shared/utils/constants' 2import type { CachedFetchFunction } from './fetch-cache-config' 3 4export type Backlink = { 5 did: string 6 collection: string 7 rkey: string 8} 9 10export type BacklinksResponse = { 11 total: number 12 records: Backlink[] 13 cursor: string | undefined 14} 15 16export type LinksDistinctDidsResponse = { 17 total: number 18 linking_dids: string[] 19 cursor: string | undefined 20} 21 22export type AllLinksResponse = { 23 links: Record< 24 string, 25 Record< 26 string, 27 { 28 records: number 29 distinct_dids: number 30 } 31 > 32 > 33} 34 35const HEADERS = { 'User-Agent': 'npmx' } 36 37export class Constellation { 38 private readonly cachedFetch: CachedFetchFunction 39 constructor(fetch: CachedFetchFunction) { 40 this.cachedFetch = fetch 41 } 42 43 /** 44 * Gets backlinks from constellation 45 * https://constellation.microcosm.blue/xrpc/blue.microcosm.links.getBacklinks?subject=at%3A%2F%2Fdid%3Aplc%3Aa4pqq234yw7fqbddawjo7y35%2Fapp.bsky.feed.post%2F3m237ilwc372e&source=app.bsky.feed.like%3Asubject.uri&limit=16 46 * @param subject - A uri encoded link. did, url, or at-uri 47 * @param collection - The lexicon collection to check like dev.npmx.feed.like 48 * @param recordPath - Where in the record to check for the subject 49 * @param limit - The number of backlinks to return 50 * @param cursor - The cursor to use for pagination 51 * @param reverse - Whether to reverse the order of the results 52 * @param filterByDids - An array of dids to filter by in the results 53 * @param ttl - The ttl to use for the cache 54 */ 55 async getBackLinks( 56 subject: string, 57 collection: string, 58 recordPath: string, 59 limit = 16, 60 cursor?: string, 61 reverse = false, 62 filterByDids: [string][] = [], 63 ttl: number | undefined = undefined, 64 ) { 65 // Note that using Client from @atproto/lex here is kinda "hard" because it 66 // expects a native fetch implementation, which is "hard" to provide using 67 // this.cachedFetch as underlying fetch implementation. In addition to this, 68 // blue.microcosm.links.getBacklinks is not a published lexicon, meaning 69 // that we cannot install it using `pnpm exec lex install 70 // blue.microcosm.links.getBacklinks` and get generated type definitions, 71 // which kinda defeats the purpose of using Client in the first place. For 72 // these reasons, we are using this.cachedFetch directly to call the 73 // constellation API endpoint, and type casting the response. 74 const source = encodeURIComponent(`${collection}:${recordPath}`) 75 let urlToCall = `https://${CONSTELLATION_HOST}/xrpc/blue.microcosm.links.getBacklinks?subject=${encodeURIComponent(subject)}&source=${source}&limit=${limit}` 76 if (cursor) urlToCall += `&cursor=${cursor}` 77 if (reverse) urlToCall += '&reverse=true' 78 filterByDids.forEach(did => (urlToCall += `&did=${did}`)) 79 80 return await this.cachedFetch<BacklinksResponse>(urlToCall, { headers: HEADERS }, ttl) 81 } 82 83 /** 84 * Gets the distinct dids that link to a target record 85 * @param target - A uri encoded link. did, url, or at-uri 86 * @param collection - The lexicon collection to check like dev.npmx.feed.like 87 * @param recordPath - Where in the record to check for the subject 88 * @param limit - The number of distinct dids to return 89 * @param cursor - The cursor to use for pagination 90 * @param ttl - The ttl to use for the cache 91 */ 92 async getLinksDistinctDids( 93 target: string, 94 collection: string, 95 recordPath: string, 96 limit: number = 16, 97 cursor?: string, 98 ttl: number | undefined = undefined, 99 ) { 100 let urlToCall = `https://${CONSTELLATION_HOST}/links/distinct-dids?target=${encodeURIComponent(target)}&collection=${collection}&path=${recordPath}&limit=${limit}` 101 if (cursor) urlToCall += `&cursor=${cursor}` 102 return await this.cachedFetch<LinksDistinctDidsResponse>(urlToCall, { headers: HEADERS }, ttl) 103 } 104 105 /** 106 * Gets all links from constellation and their counts 107 * @param target - A uri encoded link. did, url, or at-uri 108 * @param ttl - The ttl to use for the cache 109 */ 110 async getAllLinks(target: string, ttl: number | undefined = undefined) { 111 return await this.cachedFetch<AllLinksResponse>( 112 `https://${CONSTELLATION_HOST}/links/all?target=${target}`, 113 { headers: HEADERS }, 114 ttl, 115 ) 116 } 117}