atmosphere explorer
0
fork

Configure Feed

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

add CORS proxy as fallback

Juliet 411f5e11 6daae320

+83 -5
+32 -5
src/utils/api.ts
··· 21 21 import { setPDS } from "../components/navbar"; 22 22 import { plcDirectory } from "../views/settings"; 23 23 24 + const proxyFetch = (rewrite: (url: URL) => string): typeof fetch => { 25 + return async (input, init) => { 26 + try { 27 + return await fetch(input, init); 28 + } catch (err) { 29 + if (init?.signal?.aborted) throw err; 30 + const url = new URL( 31 + typeof input === "string" ? input 32 + : input instanceof URL ? input.href 33 + : input.url, 34 + ); 35 + return fetch(rewrite(url)); 36 + } 37 + }; 38 + }; 39 + 40 + const didWebProxyFetch = proxyFetch( 41 + (url) => `/resolve-did-web?host=${encodeURIComponent(url.host)}`, 42 + ); 43 + const dnsProxyFetch = proxyFetch( 44 + (url) => 45 + `/resolve-handle-dns?handle=${encodeURIComponent(url.searchParams.get("name")?.replace("_atproto.", "") ?? "")}`, 46 + ); 47 + const handleHttpProxyFetch = proxyFetch( 48 + (url) => `/resolve-handle-http?handle=${encodeURIComponent(url.host)}`, 49 + ); 50 + 24 51 export const didDocumentResolver = createMemo( 25 52 () => 26 53 new CompositeDidDocumentResolver({ ··· 28 55 plc: new PlcDidDocumentResolver({ 29 56 apiUrl: plcDirectory(), 30 57 }), 31 - web: new AtprotoWebDidDocumentResolver(), 58 + web: new AtprotoWebDidDocumentResolver({ fetch: didWebProxyFetch }), 32 59 }, 33 60 }), 34 61 ); 35 62 36 63 export const handleResolver = new CompositeHandleResolver({ 37 - strategy: "race", 64 + strategy: "dns-first", 38 65 methods: { 39 - dns: new DohJsonHandleResolver({ dohUrl: "https://dns.google/resolve?" }), 40 - http: new WellKnownHandleResolver(), 66 + dns: new DohJsonHandleResolver({ dohUrl: "https://dns.google/resolve?", fetch: dnsProxyFetch }), 67 + http: new WellKnownHandleResolver({ fetch: handleHttpProxyFetch }), 41 68 }, 42 69 }); 43 70 ··· 223 250 224 251 export const resolveHandleDetailed = async (handle: Handle) => { 225 252 const dnsResolver = new DohJsonHandleResolver({ dohUrl: "https://dns.google/resolve?" }); 226 - const httpResolver = new WellKnownHandleResolver(); 253 + const httpResolver = new WellKnownHandleResolver({ fetch: handleHttpProxyFetch }); 227 254 228 255 const tryResolve = async ( 229 256 resolver: DohJsonHandleResolver | WellKnownHandleResolver,
+51
src/worker.js
··· 488 488 489 489 const MAX_FAVICON_SIZE = 100 * 1024; // 100KB 490 490 491 + async function corsProxy(url, fetchOpts = {}) { 492 + const res = await fetch(url, { 493 + signal: AbortSignal.timeout(5000), 494 + ...fetchOpts, 495 + }); 496 + 497 + return new Response(res.body, { 498 + status: res.status, 499 + headers: { 500 + "Content-Type": res.headers.get("content-type") ?? "application/json", 501 + "Access-Control-Allow-Origin": "*", 502 + }, 503 + }); 504 + } 505 + 506 + function handleResolveDidWeb(searchParams) { 507 + const host = searchParams.get("host"); 508 + if (!host) return new Response("Missing host param", { status: 400 }); 509 + return corsProxy(`https://${host}/.well-known/did.json`, { 510 + redirect: "manual", 511 + headers: { accept: "application/did+ld+json,application/json" }, 512 + }); 513 + } 514 + 515 + function handleResolveHandleDns(searchParams) { 516 + const handle = searchParams.get("handle"); 517 + if (!handle) return new Response("Missing handle param", { status: 400 }); 518 + const url = new URL("https://dns.google/resolve"); 519 + url.searchParams.set("name", `_atproto.${handle}`); 520 + url.searchParams.set("type", "TXT"); 521 + return corsProxy(url, { headers: { accept: "application/dns-json" } }); 522 + } 523 + 524 + function handleResolveHandleHttp(searchParams) { 525 + const handle = searchParams.get("handle"); 526 + if (!handle) return new Response("Missing handle param", { status: 400 }); 527 + return corsProxy(`https://${handle}/.well-known/atproto-did`, { redirect: "manual" }); 528 + } 529 + 491 530 async function handleFavicon(searchParams) { 492 531 const domain = searchParams.get("domain"); 493 532 if (!domain) { ··· 601 640 if (url.pathname === "/favicon") { 602 641 return handleFavicon(url.searchParams).catch( 603 642 (err) => new Response(`Failed to fetch favicon: ${err?.message ?? err}`, { status: 500 }), 643 + ); 644 + } 645 + 646 + const proxyRoutes = { 647 + "/resolve-did-web": handleResolveDidWeb, 648 + "/resolve-handle-dns": handleResolveHandleDns, 649 + "/resolve-handle-http": handleResolveHandleHttp, 650 + }; 651 + 652 + if (url.pathname in proxyRoutes) { 653 + return proxyRoutes[url.pathname](url.searchParams).catch( 654 + (err) => new Response(`Proxy error: ${err?.message ?? err}`, { status: 500 }), 604 655 ); 605 656 } 606 657