the code used for the cdn.blueat.net cloudflare worker
worker.js
1const PLC_DIRECTORY = "https://plc.directory";
2
3const PATH_RE = /^\/img\/([^/]+)\/plain\/(did:[^/]+)\/([^@/]+)(?:@([^/]+))?$/;
4
5export default {
6 async fetch(request, env, ctx) {
7 const url = new URL(request.url);
8
9 if (url.pathname === "/" || url.pathname === "") {
10 return new Response(LANDING_HTML, {
11 headers: { "Content-Type": "text/html;charset=UTF-8" },
12 });
13 }
14
15 const match = url.pathname.match(PATH_RE);
16 if (!match) return new Response("400: Invalid Path", { status: 400 });
17 const [_, type, did, cid] = match;
18
19 const cache = caches.default;
20
21 const cachedResponse = await cache.match(request);
22 if (cachedResponse) return cachedResponse;
23
24 const pdsUrl = await resolvePds(did);
25 if (!pdsUrl) {
26 return new Response("404: PDS not found for this DID", { status: 404 });
27 }
28
29 try {
30 let blobRes = await fetchBlob(pdsUrl, did, cid);
31
32 if (blobRes.status === 404 && (type === "avatar" || type === "banner")) {
33 const originalCid = await findOriginalCidFromProfile(pdsUrl, did, type);
34 if (originalCid && originalCid !== cid) {
35 blobRes = await fetchBlob(pdsUrl, did, originalCid);
36 }
37 }
38
39 if (!blobRes.ok) {
40 return new Response("404: Asset not found on PDS.", { status: 404 });
41 }
42
43 const finalRes = new Response(blobRes.body, blobRes);
44 finalRes.headers.set("Cache-Control", "public, s-maxage=604800");
45 finalRes.headers.set("X-Proxy-Source", "PDS-Direct");
46 finalRes.headers.set("Content-Disposition", "inline");
47 ctx.waitUntil(cache.put(request, finalRes.clone()));
48 return finalRes;
49
50 } catch (err) {
51 return new Response(`502: PDS Error: ${err.message}`, { status: 502 });
52 }
53 },
54};
55
56async function fetchBlob(pdsUrl, did, cid) {
57 return fetch(
58 `${pdsUrl}/xrpc/com.atproto.sync.getBlob?did=${encodeURIComponent(did)}&cid=${encodeURIComponent(cid)}`
59 );
60}
61
62async function resolvePds(did) {
63 const doc = did.startsWith("did:web:")
64 ? await resolveDidWeb(did)
65 : await resolveDidPlc(did);
66 if (!doc) return null;
67 const pds = doc.service?.find(
68 (s) => s.id === "#atproto_pds" || s.type === "AtprotoPersonalDataServer"
69 );
70 return pds?.serviceEndpoint ?? null;
71}
72
73async function resolveDidPlc(did) {
74 const res = await fetch(`${PLC_DIRECTORY}/${did}`);
75 if (!res.ok) return null;
76 return res.json();
77}
78
79async function resolveDidWeb(did) {
80 const identifier = did.slice("did:web:".length);
81 const parts = identifier.split(":");
82 const host = decodeURIComponent(parts[0]);
83 const didUrl = parts.length === 1
84 ? `https://${host}/.well-known/did.json`
85 : `https://${host}/${parts.slice(1).map(decodeURIComponent).join("/")}/did.json`;
86 const res = await fetch(didUrl);
87 if (!res.ok) return null;
88 return res.json();
89}
90
91async function findOriginalCidFromProfile(pdsUrl, did, type) {
92 const res = await fetch(
93 `${pdsUrl}/xrpc/com.atproto.repo.getRecord?repo=${encodeURIComponent(did)}&collection=app.bsky.actor.profile&rkey=self`
94 );
95 if (!res.ok) return null;
96 const data = await res.json();
97 return data.value?.[type]?.ref?.$link ?? null;
98}
99
100const LANDING_HTML = `<!DOCTYPE html>
101<html lang="en">
102<head>
103 <meta charset="UTF-8" />
104 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
105 <title>cdn.blueat.net</title>
106 <style>
107 *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
108
109 body {
110 background: #0d1117;
111 color: #e6edf3;
112 font-family: system-ui, sans-serif;
113 min-height: 100vh;
114 display: flex;
115 align-items: center;
116 justify-content: center;
117 padding: 1.5rem;
118 }
119
120 .wrap {
121 width: 100%;
122 max-width: 480px;
123 }
124
125 h1 {
126 font-size: 1.1rem;
127 font-weight: 600;
128 margin-bottom: .25rem;
129 color: #e6edf3;
130 }
131
132 p {
133 font-size: .85rem;
134 color: #7d8590;
135 margin-bottom: 1.5rem;
136 line-height: 1.5;
137 }
138
139 .row {
140 display: flex;
141 gap: .5rem;
142 margin-bottom: .75rem;
143 }
144
145 input {
146 flex: 1;
147 background: #161b22;
148 border: 1px solid #30363d;
149 border-radius: .4rem;
150 padding: .55rem .75rem;
151 color: #e6edf3;
152 font-size: .85rem;
153 outline: none;
154 }
155 input:focus { border-color: #388bfd; }
156 input::placeholder { color: #484f58; }
157
158 button {
159 background: #238636;
160 border: 1px solid #2ea043;
161 border-radius: .4rem;
162 padding: .55rem 1rem;
163 color: #fff;
164 font-size: .85rem;
165 font-weight: 500;
166 cursor: pointer;
167 white-space: nowrap;
168 }
169 button:hover { background: #2ea043; }
170
171 .output {
172 background: #161b22;
173 border: 1px solid #30363d;
174 border-radius: .4rem;
175 padding: .55rem .75rem;
176 font-size: .8rem;
177 font-family: monospace;
178 color: #7d8590;
179 word-break: break-all;
180 min-height: 2.4rem;
181 display: flex;
182 align-items: center;
183 gap: .5rem;
184 }
185 .output.ok { border-color: #238636; color: #3fb950; }
186 .output.err { border-color: #da3633; color: #f85149; }
187 .output span { flex: 1; }
188
189 .copy {
190 background: transparent;
191 border: 1px solid #30363d;
192 border-radius: .3rem;
193 padding: .2rem .5rem;
194 font-size: .75rem;
195 color: #7d8590;
196 flex-shrink: 0;
197 }
198 .copy:hover { border-color: #388bfd; color: #388bfd; background: transparent; }
199 </style>
200</head>
201<body>
202 <div class="wrap">
203 <h1>cdn.blueat.net</h1>
204 <p>Paste a <code>cdn.bsky.app</code> image URL to get the cdn.blueat.net equivalent, served directly from the user's PDS and powered by Cloudflare Workers.<br><br>
205 <i>This is intended to be used when cdn.bsky.app is down.</i></p>
206
207 <div class="row">
208 <input id="inp" type="text" placeholder="https://cdn.bsky.app/img/avatar/plain/did:plc:…/cid@jpeg" spellcheck="false" />
209 <button onclick="go()">Convert</button>
210 </div>
211
212 <div id="out" class="output"><span>—</span></div>
213 </div>
214
215 <script>
216 const inp = document.getElementById("inp");
217 const out = document.getElementById("out");
218 inp.addEventListener("keydown", e => e.key === "Enter" && go());
219
220 function go() {
221 const raw = inp.value.trim();
222 out.className = "output";
223 out.innerHTML = "<span>—</span>";
224 if (!raw) return;
225
226 let u;
227 try { u = new URL(raw); } catch { return err("Not a valid URL."); }
228
229 if (u.hostname !== "cdn.bsky.app" || !/^\\/img\\/[^\\/]+\\/plain\\/did:[^\\/]+\\//.test(u.pathname)) {
230 return err("Not a recognised cdn.bsky.app image URL.");
231 }
232
233 const result = "https://cdn.blueat.net" + u.pathname;
234 out.classList.add("ok");
235
236 const s = document.createElement("span");
237 s.textContent = result;
238
239 const btn = document.createElement("button");
240 btn.className = "copy";
241 btn.textContent = "Copy";
242 btn.onclick = () => {
243 navigator.clipboard.writeText(result);
244 btn.textContent = "✓";
245 setTimeout(() => btn.textContent = "Copy", 1500);
246 };
247
248 out.innerHTML = "";
249 out.appendChild(s);
250 out.appendChild(btn);
251 }
252
253 function err(msg) {
254 out.classList.add("err");
255 out.innerHTML = "<span>" + msg + "</span>";
256 }
257 </script>
258</body>
259</html>`;