diff --git a/scripts/patch-ap-syndicate-deploy-delay.mjs b/scripts/patch-ap-syndicate-deploy-delay.mjs new file mode 100644 index 00000000..182ecd41 --- /dev/null +++ b/scripts/patch-ap-syndicate-deploy-delay.mjs @@ -0,0 +1,64 @@ +/** + * Patch: add a 2-minute deploy delay before ActivityPub syndication. + * + * When a post is created (via Micropub or Mastodon-API compose), the + * blog's deploy pipeline (Gitea → Eleventy → rsync) takes ~1-2 minutes. + * If ActivityPub fires immediately, followers receive a Create activity + * whose `url` still 404s — Mastodon clients show a broken link. + * + * This patch inserts a `setTimeout`-based delay at the top of the + * `syndicate()` function. The delay is configurable via the + * AP_SYNDICATE_DELAY_MS environment variable (default: 120000 = 2 min). + */ + +import { access, readFile, writeFile } from "node:fs/promises"; + +const candidates = [ + "node_modules/@rmdes/indiekit-endpoint-activitypub/lib/syndicator.js", + "node_modules/@indiekit/indiekit/node_modules/@rmdes/indiekit-endpoint-activitypub/lib/syndicator.js", +]; + +const MARKER = "// [patch] ap-syndicate-deploy-delay"; + +// The line right after the early-exit guards — insert before the +// try { const actorUrl = ... } block. +const INSERT_AFTER = ` try { + const actorUrl = plugin._getActorUrl();`; + +const DELAY_BLOCK = ` // [patch] ap-syndicate-deploy-delay — wait for deploy pipeline before federating + const _apDelay = Number.parseInt(process.env.AP_SYNDICATE_DELAY_MS ?? "120000", 10); + if (_apDelay > 0) { + console.info(\`[ActivityPub] Delaying syndication by \${_apDelay}ms for \${properties.url}\`); + await new Promise((resolve) => setTimeout(resolve, _apDelay)); + } + ${MARKER} + try { + const actorUrl = plugin._getActorUrl();`; + +async function exists(p) { + try { await access(p); return true; } catch { return false; } +} + +let patched = false; +for (const filePath of candidates) { + if (!(await exists(filePath))) continue; + let src = await readFile(filePath, "utf8"); + if (src.includes(MARKER)) { + console.log(`[postinstall] patch-ap-syndicate-deploy-delay: already applied in ${filePath}`); + patched = true; + break; + } + if (!src.includes(INSERT_AFTER)) { + console.log(`[postinstall] patch-ap-syndicate-deploy-delay: insertion point not found in ${filePath}`); + continue; + } + src = src.replace(INSERT_AFTER, DELAY_BLOCK); + await writeFile(filePath, src, "utf8"); + console.log(`[postinstall] patch-ap-syndicate-deploy-delay: applied in ${filePath}`); + patched = true; + break; +} + +if (!patched) { + console.log("[postinstall] patch-ap-syndicate-deploy-delay: no target file found"); +}