Files
indiekit-server/scripts/patch-microsub-no-bookmark-autofollow.mjs
Sven a85086faa7
Deploy Indiekit Server / deploy (push) Successful in 1m25s
Disable microsub auto-follow and blogroll injection on bookmark-of posts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 08:57:27 +02:00

141 lines
4.4 KiB
JavaScript

/**
* 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");
}