Webhooks for the AT Protocol airglow.run
atproto atprotocol automation webhook
12
fork

Configure Feed

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

chore: better favicon handling

Hugo be0e2295 1591bce7

+123 -41
+11 -7
app/components/NsidCode/index.tsx
··· 2 2 import { InlineCode } from "../CodeBlock/index.tsx"; 3 3 import * as s from "./styles.css.ts"; 4 4 5 + const STATIC_FAVICONS: Record<string, string> = { 6 + "bsky.app": "/static/favicons/bsky.app.png", 7 + "standard.site": "/static/favicons/standard.site.ico", 8 + "npmx.dev": "/static/favicons/npmx.dev.ico", 9 + "tangled.sh": "/static/favicons/tangled.sh.svg", 10 + "airglow.run": "/static/favicons/airglow.run.svg", 11 + "exosphere.site": "/static/favicons/exosphere.site.svg", 12 + }; 13 + 5 14 export function NsidCode({ children }: { children: string }) { 6 15 const domain = nsidToDomain(children); 16 + const src = STATIC_FAVICONS[domain] ?? `/api/favicon/${domain}`; 7 17 return ( 8 18 <span class={s.wrapper}> 9 - <img 10 - src={`/api/favicon/${domain}`} 11 - alt="" 12 - class={s.favicon} 13 - loading="lazy" 14 - onerror="this.style.display='none'" 15 - /> 19 + <img src={src} alt="" class={s.favicon} loading="lazy" onerror="this.style.display='none'" /> 16 20 <InlineCode>{children}</InlineCode> 17 21 </span> 18 22 );
-34
lib/favicon.ts
··· 56 56 } 57 57 } 58 58 59 - /** Known favicon URLs for domains that don't serve at standard paths. */ 60 - const KNOWN_FAVICONS: Record<string, string> = { 61 - "bsky.app": "https://web-cdn.bsky.app/static/favicon-32x32.png", 62 - "standard.site": "https://standard.site/favicon.ico", 63 - "npmx.dev": "https://npmx.dev/favicon.ico", 64 - "tangled.sh": "https://tangled.org/static/logos/dolly.svg", 65 - "airglow.run": "https://airglow.run/favicon.svg", 66 - "exosphere.site": "https://exosphere.site/favicon.svg", 67 - }; 68 - 69 - async function fetchKnownFavicon( 70 - domain: string, 71 - ): Promise<{ data: Buffer; contentType: string } | null> { 72 - const url = KNOWN_FAVICONS[domain]; 73 - if (!url) return null; 74 - try { 75 - const res = await fetch(url, { 76 - signal: AbortSignal.timeout(FETCH_TIMEOUT), 77 - redirect: "error", 78 - }); 79 - if (!res.ok) return null; 80 - const ct = res.headers.get("content-type") ?? ""; 81 - if (!ct.startsWith("image/")) return null; 82 - const buf = Buffer.from(await res.arrayBuffer()); 83 - if (buf.length === 0 || buf.length > MAX_SIZE) return null; 84 - return { data: buf, contentType: ct.split(";")[0]! }; 85 - } catch { 86 - return null; 87 - } 88 - } 89 - 90 59 async function fetchFavicon(domain: string): Promise<{ data: Buffer; contentType: string } | null> { 91 - const known = await fetchKnownFavicon(domain); 92 - if (known) return known; 93 - 94 60 const ip = await resolveSafeIP(domain); 95 61 if (!ip) return null; 96 62
+5
public/static/favicons/airglow.run.svg
··· 1 + <svg viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 + <circle cx="32" cy="32" r="10" fill="#E8923A"/> 3 + <circle cx="32" cy="32" r="20" stroke="#E8923A" stroke-width="3.5" opacity="0.45"/> 4 + <circle cx="32" cy="32" r="29" stroke="#E8923A" stroke-width="2.5" opacity="0.2"/> 5 + </svg>
public/static/favicons/bsky.app.png

This is a binary file and will not be displayed.

+12
public/static/favicons/exosphere.site.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"> 2 + <style> 3 + :root { --fg: #3b82f6; --ring: #1a1a2e; } 4 + @media (prefers-color-scheme: dark) { 5 + :root { --fg: #60a5fa; --ring: #f1f5f9; } 6 + } 7 + </style> 8 + <!-- Inner sphere --> 9 + <circle cx="32" cy="32" r="14" fill="var(--fg)" /> 10 + <!-- Exosphere ring --> 11 + <circle cx="32" cy="32" r="27" fill="none" stroke="var(--ring)" stroke-width="2.5" /> 12 + </svg>
public/static/favicons/npmx.dev.ico

This is a binary file and will not be displayed.

public/static/favicons/standard.site.ico

This is a binary file and will not be displayed.

+95
public/static/favicons/tangled.sh.svg
··· 1 + 2 + <svg 3 + version="1.1" 4 + id="svg1" 5 + class="" 6 + width="25" 7 + height="25" 8 + viewBox="0 0 25 25" 9 + sodipodi:docname="tangled_dolly_face_only_black_on_trans.svg" 10 + inkscape:export-filename="tangled_logotype_black_on_trans.svg" 11 + inkscape:export-xdpi="96" 12 + inkscape:export-ydpi="96" 13 + inkscape:version="1.4 (e7c3feb100, 2024-10-09)" 14 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 15 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 16 + xmlns="http://www.w3.org/2000/svg" 17 + xmlns:svg="http://www.w3.org/2000/svg" 18 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 19 + xmlns:cc="http://creativecommons.org/ns#"> 20 + <style> 21 + .dolly { 22 + color: #000000; 23 + } 24 + 25 + @media (prefers-color-scheme: dark) { 26 + .dolly { 27 + color: #ffffff; 28 + } 29 + } 30 + </style> 31 + <sodipodi:namedview 32 + id="namedview1" 33 + pagecolor="#ffffff" 34 + bordercolor="#000000" 35 + borderopacity="0.25" 36 + inkscape:showpageshadow="2" 37 + inkscape:pageopacity="0.0" 38 + inkscape:pagecheckerboard="true" 39 + inkscape:deskcolor="#d5d5d5" 40 + inkscape:zoom="45.254834" 41 + inkscape:cx="3.1377863" 42 + inkscape:cy="8.9382717" 43 + inkscape:window-width="3840" 44 + inkscape:window-height="2160" 45 + inkscape:window-x="0" 46 + inkscape:window-y="0" 47 + inkscape:window-maximized="0" 48 + inkscape:current-layer="g1" 49 + borderlayer="true"> 50 + <inkscape:page 51 + x="0" 52 + y="0" 53 + width="25" 54 + height="25" 55 + id="page2" 56 + margin="0" 57 + bleed="0" /> 58 + </sodipodi:namedview> 59 + <g 60 + inkscape:groupmode="layer" 61 + inkscape:label="Image" 62 + id="g1" 63 + transform="translate(-0.42924038,-0.87777209)"> 64 + <path 65 + class="dolly" 66 + fill="currentColor" 67 + style="stroke-width:0.111183;" 68 + d="m 16.775491,24.987061 c -0.78517,-0.0064 -1.384202,-0.234614 -2.033994,-0.631295 -0.931792,-0.490188 -1.643475,-1.31368 -2.152014,-2.221647 C 11.781409,23.136647 10.701392,23.744942 9.4922931,24.0886 8.9774725,24.238111 8.0757679,24.389777 6.5811304,23.84827 4.4270703,23.124679 2.8580086,20.883331 3.0363279,18.599583 3.0037061,17.652919 3.3488675,16.723769 3.8381157,15.925061 2.5329485,15.224503 1.4686756,14.048584 1.0611184,12.606459 0.81344502,11.816973 0.82385989,10.966486 0.91519098,10.154906 1.2422711,8.2387903 2.6795811,6.5725716 4.5299585,5.9732484 5.2685364,4.290122 6.8802592,3.0349975 8.706276,2.7794663 c 1.2124148,-0.1688264 2.46744,0.084987 3.52811,0.7011837 1.545426,-1.7139736 4.237779,-2.2205077 6.293579,-1.1676231 1.568222,0.7488935 2.689625,2.3113526 2.961888,4.0151464 1.492195,0.5977882 2.749007,1.8168898 3.242225,3.3644951 0.329805,0.9581836 0.340709,2.0135956 0.127128,2.9974286 -0.381606,1.535184 -1.465322,2.842146 -2.868035,3.556463 0.0034,0.273204 0.901506,2.243045 0.751284,3.729647 -0.03281,1.858525 -1.211631,3.619894 -2.846433,4.475452 -0.953967,0.556812 -2.084452,0.546309 -3.120531,0.535398 z m -4.470079,-5.349839 c 1.322246,-0.147248 2.189053,-1.300106 2.862307,-2.338363 0.318287,-0.472954 0.561404,-1.002348 0.803,-1.505815 0.313265,0.287151 0.578698,0.828085 1.074141,0.956909 0.521892,0.162542 1.133743,0.03052 1.45325,-0.443554 0.611414,-1.140449 0.31004,-2.516537 -0.04602,-3.698347 C 18.232844,11.92927 17.945151,11.232927 17.397785,10.751793 17.514522,9.9283111 17.026575,9.0919791 16.332883,8.6609491 15.741721,9.1323278 14.842258,9.1294949 14.271975,8.6252369 13.178927,9.7400102 12.177239,9.7029996 11.209704,8.8195135 10.992255,8.6209543 10.577326,10.031484 9.1211947,9.2324497 8.2846288,9.9333947 7.6359672,10.607693 7.0611981,11.578553 6.5026891,12.62523 5.9177873,13.554793 5.867393,14.69141 c -0.024234,0.66432 0.4948601,1.360337 1.1982269,1.306329 0.702996,0.06277 1.1815208,-0.629091 1.7138087,-0.916491 0.079382,0.927141 0.1688108,1.923227 0.4821259,2.828358 0.3596254,1.171275 1.6262605,1.915695 2.8251855,1.745211 0.08481,-0.0066 0.218672,-0.01769 0.218672,-0.0176 z m 0.686342,-3.497495 c -0.643126,-0.394168 -0.33365,-1.249599 -0.359402,-1.870938 0.064,-0.749774 0.115321,-1.538054 0.452402,-2.221125 0.356724,-0.487008 1.226721,-0.299139 1.265134,0.325689 -0.02558,0.628509 -0.314101,1.25416 -0.279646,1.9057 -0.07482,0.544043 0.05418,1.155133 -0.186476,1.652391 -0.197455,0.275121 -0.599638,0.355105 -0.892012,0.208283 z m -2.808766,-0.358124 c -0.605767,-0.328664 -0.4133176,-1.155655 -0.5083256,-1.73063 0.078762,-0.66567 0.013203,-1.510085 0.5705316,-1.976886 0.545037,-0.380109 1.286917,0.270803 1.029164,0.868384 -0.274913,0.755214 -0.09475,1.580345 -0.08893,2.34609 -0.104009,0.451702 -0.587146,0.691508 -1.002445,0.493042 z" 69 + id="path4" 70 + sodipodi:nodetypes="sccccccccccccccccccsscccccccccsccccccccccccccccccccccc" /> 71 + </g> 72 + <metadata 73 + id="metadata1"> 74 + <rdf:RDF> 75 + <cc:Work 76 + rdf:about=""> 77 + <cc:license 78 + rdf:resource="http://creativecommons.org/licenses/by/4.0/" /> 79 + </cc:Work> 80 + <cc:License 81 + rdf:about="http://creativecommons.org/licenses/by/4.0/"> 82 + <cc:permits 83 + rdf:resource="http://creativecommons.org/ns#Reproduction" /> 84 + <cc:permits 85 + rdf:resource="http://creativecommons.org/ns#Distribution" /> 86 + <cc:requires 87 + rdf:resource="http://creativecommons.org/ns#Notice" /> 88 + <cc:requires 89 + rdf:resource="http://creativecommons.org/ns#Attribution" /> 90 + <cc:permits 91 + rdf:resource="http://creativecommons.org/ns#DerivativeWorks" /> 92 + </cc:License> 93 + </rdf:RDF> 94 + </metadata> 95 + </svg>