livefetch v6:
- Adds console.log showing which property links were built per post
(e.g. "in-reply-to" for replies) — makes it debuggable without server access
- Fixes retryPatchedBlock to include the two comment lines the retry patch
actually inserts (was missing them, causing "Target block not found" on
fresh upstream → retry → livefetch path)
- Adds v5 to priorMarkersNoContinue with contentToProcess-line end detection
so v5 → v6 in-place upgrade works correctly
reset-stale: bump to v11 to retry ca3d8 and any other posts stuck
before v5/v6 deployment.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root cause: blog.giersig.eu DNS resolves internally to 10.100.0.10 (the
indiekit admin nginx), which returns the login page for post URLs of
certain types (notes, photos, replies). Live page fetching is inherently
unreliable in this split-DNS / jailed setup.
The fix: indiekit already stores all microformat target URLs in MongoDB
(in-reply-to, like-of, bookmark-of, repost-of) and content.html has
inline links. We can build a synthetic h-entry HTML snippet directly
from post.properties — no network fetch required for the source post.
Bumps livefetch patch to v5:
- Replace live page fetch with synthetic HTML built from post.properties
- Handles string values, mf2 objects ({properties.url[0]}), and plain
value strings for each microformat property
- Simplifies patch script: single full-block replacement handles all
prior versions (v1–v4) via marker detection
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root cause: INTERNAL_FETCH_URL (10.100.0.10) points to the nginx reverse
proxy in front of indiekit's admin interface. Post URLs like /bookmarks/…
require authentication there, so the fetch returned the login page
("Anmelden - Indiekit") which has no .h-entry.
The blog HTML is served by an external host (GitHub Pages), reachable
from the jail over the public URL. INTERNAL_FETCH_URL should only be
used for indiekit API calls, not for fetching blog post pages.
Bumps livefetch patch to v4:
- Remove INTERNAL_FETCH_URL rewrite for live page fetches
- Fetch from postUrl (public URL) directly by default
- Add WEBMENTION_LIVEFETCH_URL env var as opt-in override for setups
where a local static server can serve blog pages faster
- Add v3→v4 in-place upgrade logic to the patch script
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without a Host header, nginx routes internal fetches to the wrong vhost
(sees the internal IP as Host), returning a page with no .h-entry and
causing all posts to retry indefinitely.
Bumps livefetch patch to v3:
- Sends `Host: blog.giersig.eu` when fetching via internal URL so nginx
routes to the correct virtual host
- Logs the actual fetchUrl on every internal fetch
- Logs the first 200 chars of the response body when h-entry check fails
so the root cause (wrong vhost, indiekit page, etc.) is visible
- Adds v2→v3 in-place upgrade logic to the patch script
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- retry: silently skip when livefetch:v2 marker is present instead of
logging a misleading "target snippet not found (package updated?)"
warning on every startup
- livefetch: match `h-entry"` or `h-entry ` instead of bare `h-entry`
to avoid false positives from body text containing the string
- reset-stale: update comment to reference livefetch v2 (not retry)
as the patch that prevents recurrence
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root cause: when the livefetch got a 200 response that was actually an
error page (nginx 502 HTML, login redirect, error template), it had no
.h-entry so extractLinks found 0 links — permanently marking the post
as sent with empty results.
Changes:
- livefetch v2: check fetched HTML contains "h-entry" before using it;
if missing, skip and retry next poll instead of falling back to stored
content (which also lacks microformat links for likes/reposts/bookmarks)
- livefetch v2: can detect and upgrade from v1 patch in-place
- reset-stale v9: also matches the v1.0.6+ detail format (empty arrays)
to catch posts stuck by the error-page bug
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The nested template literal in the patch output had over-escaped regex
and backticks (\\\\/ instead of \\/, \\\` instead of \`), producing
invalid JS that caused a SyntaxError at runtime.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The livefetch patch was fetching postUrl (the public HTTPS URL) which
fails behind the nginx jail. Now rewrites to INTERNAL_FETCH_URL so the
live page fetch goes through nginx on the internal network. Without
this, likes/reposts/bookmarks fall back to stored content which has no
microformat links, resulting in 0 webmentions sent.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The retry and livefetch patches both target the same upstream code block.
If retry runs first (current postinstall order), it transforms the code
into a variant that livefetch couldn't match — silently losing the
"always fetch live page" behavior. Now livefetch detects both the
original upstream code and the retry-patched variant.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The public URL (blog.giersig.eu) is reachable from inside the jail, so
the INTERNAL_FETCH_URL rewriting approach was unnecessary and caused 400/502
errors because 10.100.0.10 does not serve the static blog pages.
Simplify the livefetch patch to fetch postUrl directly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When rewriting the public URL to INTERNAL_FETCH_URL for jailed setups,
the Host header becomes the internal IP (e.g. 10.100.0.10) instead of
the public hostname (blog.giersig.eu). nginx uses the Host header for
virtual host routing and returns 400 without the correct value.
Fix: extract the host from the original public postUrl and set it as the
Host header on the internal fetch, so nginx routes to the correct vhost.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The livefetch patch used `process.env.PUBLICATION_URL || process.env.SITE_URL`
to determine the public base URL for rewriting to INTERNAL_FETCH_URL. Neither
env var is set — the publication URL comes from indiekit.config.mjs which has
a hardcoded fallback. Without a publicBase, URL rewriting never fired, the
public HTTPS URL was fetched directly, failed inside the FreeBSD jail, and fell
back to stored content.
For interaction posts (repost/bookmark/reply/like), stored content is just the
body text — the target URL (repostOf, bookmarkOf, inReplyTo, likeOf) is only
rendered in the live page via reply-context.njk. So 0 webmentions were sent.
Fix: add `|| siteUrl` as fallback. siteUrl is already in scope (derived from
`publication.me`) and is the correct value when env vars are absent.
Also bump reset-stale migration to v7 so interaction posts incorrectly marked
with 0 results (e.g. 342a5 repost) are reset and retried on next startup.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The webmention sender livefetch patch was fetching the public HTTPS URL
which hangs in the jailed setup (port 443 is on the nginx jail). Rewrite
to localhost like all other internal-fetch patches, and add a 15s
AbortController timeout. Bump reset-stale migration to v5 so posts
incorrectly marked as sent with 0/0/0 get retried.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The webmention sender was using stored post content (just the body text)
instead of the live page, missing template-rendered links like
u-in-reply-to, u-like-of, u-bookmark-of. This caused reply/like/bookmark
posts to be marked as sent with 0 webmentions. Bump reset-stale migration
to v4 so affected posts are retried.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
patch-endpoint-comments-locales: remove viewReplacements and sourceOverrides
since comments.njk was rewritten with Nunjucks macros and badge() — the old
HTML snippets no longer exist. Also drop obsolete locale keys (hiddenBadge,
targetPrefix, paginationLabel, page, of) that the new template doesn't use.
patch-webmention-sender-livefetch: delete — was orphaned (not in postinstall)
and the behavior is intentionally accepted as-is.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The core bug: stored post content (post.properties.content.html) is only
the post body text. Template-rendered microformat links (u-in-reply-to,
u-like-of, u-bookmark-of, u-repost-of) live in the 11ty HTML output, not
in MongoDB. So replies, likes, bookmarks and reposts never had their target
URLs extracted — webmentions were silently skipped.
- patch-webmention-sender-livefetch: always fetch the live page; fall back
to stored content only if the page is unavailable; skip (don't mark sent)
when no content is available so the next poll retries it. Handles both
original upstream code and the older retry-patch variant.
- patch-webmention-sender-reset-stale: bump to v2 so posts incorrectly
marked as sent today (empty results due to the content bug) get reset
and retried on next deploy.
- Remove patch-webmention-sender-retry: superseded by livefetch.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>