Wasabi S3 presigned URLs expire after 1 hour, causing broken images on
the listening page. Download cover art at build time, serve from
/images/funkwhale-cache/, and GC any images no longer referenced by
current listening/favorites data.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add hard 22s Promise.race deadline in prefetchUrl() to guard against
TCP-level connection hangs that bypass unfurl.js's read-only timeout.
Fixes builds hanging indefinitely on unresponsive hosts.
- Add actions/cache step to deploy.yml persisting .cache/ between runs.
Prevents webmention (and all eleventy-fetch) data loss on transient
502s: a populated cache means failures return existing data, not [].
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New files from rmdes/indiekit-eleventy-theme:
- js/toc-scanner.js: Alpine.js TOC scanner with IntersectionObserver scroll spy
- lib/data-fetch.js: shared fetch helper with 10s timeout and watch-mode cache extension
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add skip-to-main-content link and main content ID target
- Add prefers-reduced-motion media queries for all animations
- Enhance visible focus indicators (2px offset, high-contrast ring)
- Replace ~160 text-surface-500 instances with text-surface-600/dark:text-surface-400
for 4.5:1+ contrast ratio compliance
- Add aria-hidden="true" to ~30+ decorative SVG icons across sidebars/widgets
- Convert facepile containers from div to semantic ul/li with role="list"
- Add aria-label to icon-only buttons (share, sort controls)
- Add sr-only labels to form inputs (webmention, search)
- Add aria-live="polite" to dynamically loaded webmentions
- Add aria-label with relative+absolute date to time-difference component
- Add keyboard handlers (Enter/Space) to custom interactive elements
- Add aria-label to nav landmarks (table of contents)
- Fix modal focus trap and dialog accessibility
- Fix lightbox keyboard navigation and screen reader announcements
Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
Use two-strategy approach to work around async shortcode limitation
in deeply nested Nunjucks includes:
- blog.njk: async {% unfurl %} shortcode (top-level, works fine)
- recent-posts.njk: sync {{ url | unfurlCard | safe }} filter
(reads from pre-populated disk cache)
eleventy.before hook scans content files and pre-fetches all
interaction URLs before templates render, ensuring the sync filter
always has data — even on first build.
The default facebookexternalhit UA causes many sites to block or
redirect-loop, resulting in timeouts. Switch to a well-identified
bot UA that sites handle correctly.
- Increase timeout from 10s to 20s
- Cache failures for 1 day (avoids retrying every build)
- Add concurrency limiter (max 5 parallel requests)
- Refactor into renderCard/renderFallbackLink helpers
Adds {% unfurl "URL" %} shortcode that renders any URL as a rich card
with OpenGraph metadata (title, description, image, favicon). Uses
unfurl.js locally — no external API dependency. Results cached for 1
week in .cache/unfurl/. Also fixes Mastodon embed server config
(mstdn.social → indieweb.social).
The Nunjucks race condition in Eleventy 3.x affects page.url too —
its value changes between {% set %} and {{ }} within the same
template render during parallel builds. Instead of trying to derive
slugs from page data, name OG images with the full filename
(including date prefix) to match URL path segments exactly.
Eleventy v3 parses YYYY-MM-DD- from filenames and removes it from
page.fileSlug. The OG generator was using the full filename (with
date prefix) causing a slug mismatch — hasOgImage filter checked
for 'slug.png' while the file was 'YYYY-MM-DD-slug.png'.
Also removes debug logging from hasOgImage filter.
The OG generation in the eleventy.before hook consumed too much memory
alongside Eleventy's data cascade, causing the Eleventy process to be
OOM-killed on Cloudron. Fix by running OG generation in a separate
child process with its own 768MB heap limit. Also write the manifest
incrementally (every 10 images) to preserve progress if interrupted.
Uses Satori + @resvg/resvg-js to create branded 1200x630 social
preview cards at build time. Cards show post title, type badge,
date, and site name on a dark background with blue accent.
Generated images are cached in .cache/og/ (persistent on Cloudron)
and passthrough-copied to the output. Posts with photos continue
using their own images. Untitled posts (notes) use body text.