fix: activitypun fav/boost
All checks were successful
Deploy Indiekit Server / deploy (push) Successful in 1m14s
All checks were successful
Deploy Indiekit Server / deploy (push) Successful in 1m14s
This commit is contained in:
120
scripts/patch-ap-interactions-send-guard.mjs
Normal file
120
scripts/patch-ap-interactions-send-guard.mjs
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* Patch: guard sendActivity calls in likePost and boostPost with try/catch.
|
||||
*
|
||||
* Root cause:
|
||||
* - likePost: `ctx.sendActivity({ identifier }, recipient, like, ...)` is not
|
||||
* wrapped in try/catch. If Fedify or the underlying queue (Redis) throws, the
|
||||
* error propagates up through the route handler → 500, and the ap_interactions
|
||||
* DB write that follows is never reached (like not recorded locally either).
|
||||
*
|
||||
* - boostPost: `ctx.sendActivity({ identifier }, "followers", announce, ...)` is
|
||||
* the very first await in the function — also not wrapped. Same consequence:
|
||||
* any delivery error aborts the function before the DB write, returning 500.
|
||||
*
|
||||
* Fix:
|
||||
* Wrap both sendActivity calls in try/catch so federation delivery failures are
|
||||
* non-fatal. The interaction is still recorded in ap_interactions so the client
|
||||
* sees the correct UI state. Delivery of the boost to the original post author is
|
||||
* already guarded (separate try/catch added previously).
|
||||
*/
|
||||
|
||||
import { access, readFile, writeFile } from "node:fs/promises";
|
||||
|
||||
const MARKER = "// [patch] ap-interactions-send-guard";
|
||||
|
||||
const candidates = [
|
||||
"node_modules/@rmdes/indiekit-endpoint-activitypub/lib/mastodon/helpers/interactions.js",
|
||||
"node_modules/@indiekit/indiekit/node_modules/@rmdes/indiekit-endpoint-activitypub/lib/mastodon/helpers/interactions.js",
|
||||
];
|
||||
|
||||
// ── Change 1: guard likePost sendActivity ─────────────────────────────────────
|
||||
|
||||
const OLD_LIKE_SEND = ` if (recipient) {
|
||||
await ctx.sendActivity({ identifier: handle }, recipient, like, {
|
||||
orderingKey: targetUrl,
|
||||
});
|
||||
}`;
|
||||
|
||||
const NEW_LIKE_SEND = ` if (recipient) {
|
||||
try { ${MARKER}
|
||||
await ctx.sendActivity({ identifier: handle }, recipient, like, {
|
||||
orderingKey: targetUrl,
|
||||
});
|
||||
} catch { /* delivery failed — interaction still recorded locally */ }
|
||||
}`;
|
||||
|
||||
// ── Change 2: guard boostPost sendActivity("followers") ──────────────────────
|
||||
|
||||
const OLD_BOOST_SEND = ` // Send to followers
|
||||
await ctx.sendActivity({ identifier: handle }, "followers", announce, {
|
||||
preferSharedInbox: true,
|
||||
syncCollection: true,
|
||||
orderingKey: targetUrl,
|
||||
});`;
|
||||
|
||||
const NEW_BOOST_SEND = ` // Send to followers
|
||||
try { ${MARKER}
|
||||
await ctx.sendActivity({ identifier: handle }, "followers", announce, {
|
||||
preferSharedInbox: true,
|
||||
syncCollection: true,
|
||||
orderingKey: targetUrl,
|
||||
});
|
||||
} catch { /* delivery failed — interaction still recorded locally */ }`;
|
||||
|
||||
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-interactions-send-guard: already applied to ${filePath}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
let updated = source;
|
||||
let changes = 0;
|
||||
|
||||
if (!updated.includes(OLD_LIKE_SEND)) {
|
||||
console.warn(`[postinstall] patch-ap-interactions-send-guard: likePost snippet not found in ${filePath}`);
|
||||
} else {
|
||||
updated = updated.replace(OLD_LIKE_SEND, NEW_LIKE_SEND);
|
||||
changes++;
|
||||
}
|
||||
|
||||
if (!updated.includes(OLD_BOOST_SEND)) {
|
||||
console.warn(`[postinstall] patch-ap-interactions-send-guard: boostPost snippet not found in ${filePath}`);
|
||||
} else {
|
||||
updated = updated.replace(OLD_BOOST_SEND, NEW_BOOST_SEND);
|
||||
changes++;
|
||||
}
|
||||
|
||||
if (changes === 0) {
|
||||
console.log(`[postinstall] patch-ap-interactions-send-guard: no changes in ${filePath}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
await writeFile(filePath, updated, "utf8");
|
||||
patched += 1;
|
||||
console.log(`[postinstall] Applied patch-ap-interactions-send-guard to ${filePath} (${changes}/2 changes)`);
|
||||
}
|
||||
|
||||
if (checked === 0) {
|
||||
console.log("[postinstall] patch-ap-interactions-send-guard: no target files found");
|
||||
} else if (patched === 0) {
|
||||
console.log("[postinstall] patch-ap-interactions-send-guard: already up to date");
|
||||
} else {
|
||||
console.log(`[postinstall] patch-ap-interactions-send-guard: patched ${patched} file(s)`);
|
||||
}
|
||||
Reference in New Issue
Block a user