/** * Patch: fix hardcoded defaultChecked handles in AP reader compose controller. * * Root cause: * composeController() in compose.js sets target.defaultChecked using a * hardcoded name comparison: * * target.defaultChecked = name === "@rick@rmendes.net" || name === "@rmendes.net"; * * These are the original developer's handles and will never match any target * on this installation. As a result, ALL syndication checkboxes in the AP * reader compose form are rendered unchecked, so replies composed through the * AP reader are never syndicated to ActivityPub. * * Fix: * Replace the hardcoded comparison with `target.checked === true`. * The Micropub config endpoint (q=config) already returns each syndicator's * `checked` state. The AP syndicator has `checked: true` in indiekit.config.mjs, * so the AP checkbox will be pre-checked by default, matching the same behaviour * as the microsub reader compose form. */ import { access, readFile, writeFile } from "node:fs/promises"; const MARKER = "// [patch] ap-compose-default-checked"; const candidates = [ "node_modules/@rmdes/indiekit-endpoint-activitypub/lib/controllers/compose.js", "node_modules/@indiekit/indiekit/node_modules/@rmdes/indiekit-endpoint-activitypub/lib/controllers/compose.js", ]; const OLD_SNIPPET = ` // Default-check only AP (Fedify) and Bluesky targets // "@rick@rmendes.net" = AP Fedify, "@rmendes.net" = Bluesky for (const target of syndicationTargets) { const name = target.name || ""; target.defaultChecked = name === "@rick@rmendes.net" || name === "@rmendes.net"; }`; const NEW_SNIPPET = ` // Pre-check syndication targets based on their configured checked state ${MARKER} for (const target of syndicationTargets) { ${MARKER} target.defaultChecked = target.checked === true; ${MARKER} } ${MARKER}`; async function exists(filePath) { try { await access(filePath); return true; } catch { return false; } } let checked = 0; let patched = 0; for (const filePath of candidates) { if (!(await exists(filePath))) continue; checked += 1; const source = await readFile(filePath, "utf8"); if (source.includes(MARKER)) { console.log(`[postinstall] patch-ap-compose-default-checked: already applied to ${filePath}`); continue; } if (!source.includes(OLD_SNIPPET)) { console.warn(`[postinstall] patch-ap-compose-default-checked: target snippet not found in ${filePath}`); continue; } const updated = source.replace(OLD_SNIPPET, NEW_SNIPPET); if (updated === source) { console.log(`[postinstall] patch-ap-compose-default-checked: no changes in ${filePath}`); continue; } await writeFile(filePath, updated, "utf8"); patched += 1; console.log(`[postinstall] Applied patch-ap-compose-default-checked to ${filePath}`); } if (checked === 0) { console.log("[postinstall] patch-ap-compose-default-checked: no target files found"); } else if (patched === 0) { console.log("[postinstall] patch-ap-compose-default-checked: already up to date"); } else { console.log(`[postinstall] patch-ap-compose-default-checked: patched ${patched} file(s)`); }