/** * Patch @rmdes/indiekit-endpoint-webmention-sender controller to: * * 1. Build synthetic h-entry HTML from stored post properties instead of * fetching the live page. The stored properties already contain all * microformat target URLs (in-reply-to, like-of, bookmark-of, repost-of) * and content.html has inline links — no live page fetch needed. * * This fixes unreliable live fetches caused by internal DNS routing * blog.giersig.eu to the indiekit admin nginx (10.100.0.10) which * returns a login page for post URLs. * * 2. Don't permanently mark a post as webmention-sent when processing * fails. Skip it silently so the next poll retries. * * Handles the original upstream code, the older retry patch, and all * prior livefetch patch versions (v1–v4) via full block replacement. */ import { access, readFile, writeFile } from "node:fs/promises"; const filePath = "node_modules/@rmdes/indiekit-endpoint-webmention-sender/lib/controllers/webmention-sender.js"; const patchMarker = "// [patched:livefetch:v6]"; // Original upstream code const originalBlock = ` // If no content, try fetching the published page let contentToProcess = postContent; if (!contentToProcess) { try { const pageResponse = await fetch(postUrl); if (pageResponse.ok) { contentToProcess = await pageResponse.text(); } } catch (error) { console.log(\`[webmention] Could not fetch \${postUrl}: \${error.message}\`); } } if (!contentToProcess) { console.log(\`[webmention] No content to process for \${postUrl}\`); await markWebmentionsSent(postsCollection, postUrl, { sent: [], failed: [], skipped: [] }); continue; }`; // State left by older patch-webmention-sender-retry.mjs const retryPatchedBlock = ` // If no content, try fetching the published page let contentToProcess = postContent; let fetchFailed = false; if (!contentToProcess) { try { const pageResponse = await fetch(postUrl); if (pageResponse.ok) { contentToProcess = await pageResponse.text(); } else { fetchFailed = true; } } catch (error) { fetchFailed = true; console.log(\`[webmention] Could not fetch \${postUrl}: \${error.message}\`); } } if (!contentToProcess) { if (fetchFailed) { // Page not yet available — skip and retry on next poll rather than // permanently marking this post as sent with zero webmentions. console.log(\`[webmention] Page not yet available for \${postUrl}, will retry next poll\`); continue; } console.log(\`[webmention] No content to process for \${postUrl}\`); await markWebmentionsSent(postsCollection, postUrl, { sent: [], failed: [], skipped: [] }); continue; }`; const newBlock = ` // [patched:livefetch:v6] Build synthetic h-entry HTML from stored post properties. // The stored properties already contain all microformat target URLs // (in-reply-to, like-of, bookmark-of, repost-of) and content.html has inline // links — no live page fetch needed, and no exposure to internal DNS issues. const _propLinks = { "in-reply-to": "u-in-reply-to", "like-of": "u-like-of", "bookmark-of": "u-bookmark-of", "repost-of": "u-repost-of", "syndication": "u-syndication", }; const _anchors = []; for (const [_prop, _cls] of Object.entries(_propLinks)) { const _vals = post.properties[_prop]; if (!_vals) continue; for (const _v of (Array.isArray(_vals) ? _vals : [_vals])) { const _href = (typeof _v === "string") ? _v : (_v?.properties?.url?.[0] ?? _v?.value ?? null); if (_href && /^https?:\\/\\//.test(_href)) { _anchors.push(\`\`); } } } const _bodyHtml = post.properties.content?.html || post.properties.content?.value || ""; const contentToProcess = \`