/** * Patch: disable automatic microsub/blogroll subscription on bookmark-of posts. * * By default, creating a Micropub bookmark-of post triggers a hook that * discovers the bookmarked URL's feed, subscribes to it in microsub, and * adds it to the blogroll. This patch disables that behavior entirely. */ import { access, readFile, writeFile } from "node:fs/promises"; const MARKER = "// [patch] microsub-no-bookmark-autofollow"; const candidates = [ "node_modules/@rmdes/indiekit-endpoint-microsub/index.js", "node_modules/@indiekit/indiekit/node_modules/@rmdes/indiekit-endpoint-microsub/index.js", ]; const OLD_SNIPPET = ` response.on("finish", () => { if (request.method !== "POST") return; const action = request.query?.action || request.body?.action || "create"; const { application } = request.app.locals; const userId = getUserId(request); // ── CREATE: new bookmark post ──────────────────────────────────────────── if ( action === "create" && (response.statusCode === 201 || response.statusCode === 202) ) { const bookmarkOf = request.body?.["bookmark-of"] || request.body?.properties?.["bookmark-of"]?.[0]; if (!bookmarkOf) return; // Collect all tags (all micropub body formats) const rawCategory = request.body?.category || request.body?.properties?.category; const tags = Array.isArray(rawCategory) ? rawCategory.filter(Boolean) : rawCategory ? [rawCategory] : []; // The post permalink may appear in the Location response header const postUrl = response.getHeader?.("Location") || undefined; importBookmarkAsFollow(application, bookmarkOf, tags, userId, postUrl).catch( (err) => console.warn("[Microsub] bookmark-import failed:", err.message), ); return; } // ── UPDATE: bookmark post edited ───────────────────────────────────────── if ( action === "update" && (response.statusCode === 200 || response.statusCode === 204) ) { const postUrl = request.body?.url; if (!postUrl) return; // Detect what changed const replace = request.body?.replace || {}; const deleteFields = request.body?.delete || []; const deleteList = Array.isArray(deleteFields) ? deleteFields : Object.keys(deleteFields); // bookmark-of removed? const bookmarkRemoved = deleteList.includes("bookmark-of") || (replace["bookmark-of"] !== undefined && !replace["bookmark-of"]?.[0]); // New tags? const rawNewTags = replace.category || replace?.properties?.category; const newTags = rawNewTags ? Array.isArray(rawNewTags) ? rawNewTags.filter(Boolean) : [rawNewTags] : null; if (bookmarkRemoved || newTags) { updateBookmarkFollow( application, postUrl, { bookmarkRemoved: !!bookmarkRemoved, newTags: newTags || undefined }, userId, ).catch((err) => console.warn("[Microsub] bookmark-update failed:", err.message), ); } return; } });`; const NEW_SNIPPET = ` response.on("finish", () => { ${MARKER} // Disabled: bookmark posts no longer auto-subscribed in microsub or blogroll });`; async function exists(filePath) { try { await access(filePath); return true; } catch { return false; } } let patched = 0; let checked = 0; for (const filePath of candidates) { if (!(await exists(filePath))) continue; checked++; const source = await readFile(filePath, "utf8"); if (source.includes(MARKER)) { console.log(`[postinstall] microsub-no-bookmark-autofollow already applied to ${filePath}`); continue; } if (!source.includes(OLD_SNIPPET)) { console.warn(`[postinstall] Skipping microsub-no-bookmark-autofollow for ${filePath}: upstream format changed`); continue; } await writeFile(filePath, source.replace(OLD_SNIPPET, NEW_SNIPPET), "utf8"); patched++; console.log(`[postinstall] Patched microsub-no-bookmark-autofollow in ${filePath}`); } if (checked === 0) { console.log("[postinstall] No microsub index.js found for bookmark-autofollow patch"); }