Files
indiekit-server/scripts/patch-microsub-compose-draft-guard.mjs
Sven fd174f2738
Deploy Indiekit Server / deploy (push) Successful in 1m22s
refactor: remove dead patches from 2026-04-15 audit
- Delete patch-webmention-sender-hentry-syntax.mjs — target snippet
  (_html.includes("h-entry"")) was replaced by livefetch:v6; dead since
- Remove its entries from postinstall + serve in package.json
- Remove orphaned utils.js target from patch-micropub-fetch-internal-url
  (endpoint-posts/lib/utils.js was rewritten; no micropubUrl fetch remains)
- Add named marker to patch-microsub-compose-draft-guard; add legacy-form
  fallback check so already-patched files don't warn about upstream change

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 09:15:56 +02:00

142 lines
4.4 KiB
JavaScript

/**
* Patch: honour post-status in the microsub compose submitCompose handler.
*
* When a post is submitted via the microsub compose form with
* post-status: draft:
* 1. Forward the post-status to Micropub so the post is saved as a draft.
* 2. Suppress all mp-syndicate-to targets — draft posts must never be
* syndicated (not to Mastodon, Bluesky, or ActivityPub).
*
* The syndicate endpoint already filters out drafts at the DB-query level
* (patch-federation-unlisted-guards), and the AP syndicator has its own
* guard (patch-ap-skip-draft-syndication), but preventing syndication
* targets from being stored in the first place is the cleanest approach.
*/
import { access, readFile, writeFile } from "node:fs/promises";
const candidates = [
"node_modules/@rmdes/indiekit-endpoint-microsub/lib/controllers/reader.js",
"node_modules/@indiekit/indiekit/node_modules/@rmdes/indiekit-endpoint-microsub/lib/controllers/reader.js",
];
const marker = "// [patch] microsub-compose-draft-guard";
const patchSpecs = [
{
name: "microsub-compose-extract-post-status",
oldSnippet: [
` const syndicateTo = request.body["mp-syndicate-to"];`,
``,
` // Debug logging`,
` console.info(`,
` "[Microsub] submitCompose request.body:",`,
` JSON.stringify(request.body),`,
` );`,
` console.info("[Microsub] Extracted values:", {`,
` content,`,
` inReplyTo,`,
` likeOf,`,
` repostOf,`,
` bookmarkOf,`,
` syndicateTo,`,
` });`,
].join("\n"),
newSnippet: [
` const syndicateTo = request.body["mp-syndicate-to"];`,
` const postStatus = request.body["post-status"]; // [patch] microsub-compose-draft-guard`,
` const isDraft = postStatus === "draft";`,
``,
` // Debug logging`,
` console.info(`,
` "[Microsub] submitCompose request.body:",`,
` JSON.stringify(request.body),`,
` );`,
` console.info("[Microsub] Extracted values:", {`,
` content,`,
` inReplyTo,`,
` likeOf,`,
` repostOf,`,
` bookmarkOf,`,
` syndicateTo,`,
` postStatus,`,
` });`,
].join("\n"),
},
{
name: "microsub-compose-draft-suppresses-syndication",
oldSnippet: [
` // Add syndication targets`,
` if (syndicateTo) {`,
` const targets = Array.isArray(syndicateTo) ? syndicateTo : [syndicateTo];`,
` for (const target of targets) {`,
` micropubData.append("mp-syndicate-to", target);`,
` }`,
` }`,
].join("\n"),
newSnippet: [
` // Set post status (e.g. draft) — must be appended before syndication logic`,
` if (postStatus) {`,
` micropubData.append("post-status", postStatus);`,
` }`,
``,
` // Add syndication targets — suppressed entirely for draft posts`,
` if (syndicateTo && !isDraft) {`,
` const targets = Array.isArray(syndicateTo) ? syndicateTo : [syndicateTo];`,
` for (const target of targets) {`,
` micropubData.append("mp-syndicate-to", target);`,
` }`,
` }`,
].join("\n"),
},
];
async function exists(filePath) {
try {
await access(filePath);
return true;
} catch {
return false;
}
}
const checkedFiles = new Set();
const patchedFiles = new Set();
for (const spec of patchSpecs) {
for (const filePath of candidates) {
if (!(await exists(filePath))) {
continue;
}
checkedFiles.add(filePath);
const source = await readFile(filePath, "utf8");
if (source.includes(marker) || source.includes(`const isDraft = postStatus === "draft"`)) {
// Already patched (marker or legacy form)
continue;
}
if (!source.includes(spec.oldSnippet)) {
console.warn(
`[postinstall] Skipping ${spec.name} patch for ${filePath}: upstream format changed`,
);
continue;
}
const updated = source.replace(spec.oldSnippet, spec.newSnippet);
await writeFile(filePath, updated, "utf8");
patchedFiles.add(filePath);
}
}
if (checkedFiles.size === 0) {
console.log("[postinstall] No microsub reader files found for draft guard patch");
} else if (patchedFiles.size === 0) {
console.log("[postinstall] microsub compose draft guard already applied");
} else {
console.log(
`[postinstall] Patched microsub compose draft guard in ${patchedFiles.size} file(s)`,
);
}