atmosphere explorer pds.ls
tool typescript atproto
434
fork

Configure Feed

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

add fallback to resolve lexicon authority in search

Juliet 693cf161 6ad2a565

+37 -4
+9 -4
src/components/search.tsx
··· 11 11 Show, 12 12 } from "solid-js"; 13 13 import { isTouchDevice } from "../layout"; 14 - import { resolveLexiconAuthority } from "../utils/api"; 14 + import { resolveLexiconAuthority, resolveLexiconAuthorityDirect } from "../utils/api"; 15 15 import { appHandleLink, appList, appName, AppUrl } from "../utils/app-urls"; 16 16 import { createDebouncedValue } from "../utils/hooks/debounced"; 17 17 import { Modal } from "./modal"; ··· 160 160 } else if (prefix === "at:") { 161 161 navigate(`/${input}`); 162 162 } else if (prefix === "lex:") { 163 - const nsid = query as Nsid; 164 - const res = await resolveLexiconAuthority(nsid); 165 - navigate(`/at://${res}/com.atproto.lexicon.schema/${nsid}`); 163 + if (query.split(".").length >= 3) { 164 + const nsid = query as Nsid; 165 + const res = await resolveLexiconAuthority(nsid); 166 + navigate(`/at://${res}/com.atproto.lexicon.schema/${nsid}`); 167 + } else { 168 + const did = await resolveLexiconAuthorityDirect(query); 169 + navigate(`/at://${did}/com.atproto.lexicon.schema`); 170 + } 166 171 } else if (prefix === "pds:") { 167 172 navigate(`/${query}`); 168 173 } else if (input.startsWith("https://") || input.startsWith("http://")) {
+28
src/utils/api.ts
··· 112 112 return await authorityResolver.resolve(nsid); 113 113 }; 114 114 115 + const resolveLexiconAuthorityDirect = async (authority: string) => { 116 + const dohUrl = "https://dns.google/resolve?"; 117 + const reversedAuthority = authority.split(".").reverse().join("."); 118 + const domain = `_lexicon.${reversedAuthority}`; 119 + const url = new URL(dohUrl); 120 + url.searchParams.set("name", domain); 121 + url.searchParams.set("type", "TXT"); 122 + 123 + const response = await fetch(url.toString()); 124 + if (!response.ok) { 125 + throw new Error(`Failed to resolve lexicon authority for ${authority}`); 126 + } 127 + 128 + const data = await response.json(); 129 + if (!data.Answer || data.Answer.length === 0) { 130 + throw new Error(`No lexicon authority found for ${authority}`); 131 + } 132 + 133 + const txtRecord = data.Answer[0].data.replace(/"/g, ""); 134 + 135 + if (!txtRecord.startsWith("did=")) { 136 + throw new Error(`Invalid lexicon authority record for ${authority}`); 137 + } 138 + 139 + return txtRecord.replace("did=", ""); 140 + }; 141 + 115 142 const resolveLexiconSchema = async (authority: AtprotoDid, nsid: Nsid) => { 116 143 return await schemaResolver.resolve(authority, nsid); 117 144 }; ··· 178 205 resolveDidDoc, 179 206 resolveHandle, 180 207 resolveLexiconAuthority, 208 + resolveLexiconAuthorityDirect, 181 209 resolveLexiconSchema, 182 210 resolvePDS, 183 211 validateHandle,