const PLC_DIRECTORY = "https://plc.directory"; export default { async fetch(request, env, ctx) { const url = new URL(request.url); const cache = caches.default; // Regex to extract Type, DID, and CID const pathRegex = /^\/img\/([^/]+)\/plain\/(did:[^/]+)\/([^@/]+)(?:@([^/]+))?$/; const match = url.pathname.match(pathRegex); if (!match) return new Response("400: Invalid Path", { status: 400 }); const [_, type, did, cid] = match; // 1. TRY OFFICIAL CDN FIRST (Best for resized/transformed images) const bskyCdnUrl = `https://cdn.bsky.app${url.pathname}`; let response = await fetch(bskyCdnUrl, { cf: { cacheTtl: 3600 } }); // If CDN works (200 OK), return it immediately if (response.ok) { const cdnRes = new Response(response.body, response); cdnRes.headers.set("X-Proxy-Source", "Bluesky-CDN"); return cdnRes; } // 2. GLOBAL CACHE CHECK (For the Fallback) let cachedResponse = await cache.match(request); if (cachedResponse) return cachedResponse; // 3. PDS FALLBACK LOGIC try { const pdsUrl = await resolvePds(did); if (!pdsUrl) throw new Error("PDS not found for this DID"); // A. Try the CID from the URL directly on the PDS (Works if it's the original) let blobRes = await fetchBlob(pdsUrl, did, cid); // B. TRANSFORMED IMAGE FIX: If 404, the CID is a thumbnail. // We look up the 'Original' CID from the user's Profile Record. if (blobRes.status === 404 && (type === 'avatar' || type === 'banner')) { console.log(`Thumbnail CID not found. Fetching original for ${type}...`); const originalCid = await findOriginalCidFromProfile(pdsUrl, did, type); if (originalCid && originalCid !== cid) { blobRes = await fetchBlob(pdsUrl, did, originalCid); } } if (blobRes.ok) { const finalRes = new Response(blobRes.body, blobRes); finalRes.headers.set("Cache-Control", "public, s-maxage=604800"); finalRes.headers.set("X-Proxy-Source", "PDS-Discovery"); ctx.waitUntil(cache.put(request, finalRes.clone())); return finalRes; } return new Response(`404: Asset not found on CDN or PDS.`, { status: 404 }); } catch (err) { return new Response(`502: Failover Error: ${err.message}`, { status: 502 }); } } }; /** * Helpers **/ async function fetchBlob(pdsUrl, did, cid) { return fetch(`${pdsUrl}/xrpc/com.atproto.sync.getBlob?did=${encodeURIComponent(did)}&cid=${encodeURIComponent(cid)}`); } async function resolvePds(did) { const res = await fetch(`${PLC_DIRECTORY}/${did}`, { cf: { cacheTtl: 3600 } }); if (!res.ok) return null; const doc = await res.json(); const pds = doc.service?.find(s => s.id === "#atproto_pds" || s.type === "AtprotoPersonalDataServer"); return pds?.serviceEndpoint; } async function findOriginalCidFromProfile(pdsUrl, did, type) { // Collection: app.bsky.actor.profile, Key: self const recordUrl = `${pdsUrl}/xrpc/com.atproto.repo.getRecord?repo=${encodeURIComponent(did)}&collection=app.bsky.actor.profile&rkey=self`; const res = await fetch(recordUrl); if (!res.ok) return null; const data = await res.json(); // Navigate the JSON to find the blob reference for 'avatar' or 'banner' return data.value?.[type]?.ref?.$link; }