diff --git a/scripts/patch-ap-accounts-id-cache-fallback.mjs b/scripts/patch-ap-accounts-id-cache-fallback.mjs new file mode 100644 index 00000000..4aa263e0 --- /dev/null +++ b/scripts/patch-ap-accounts-id-cache-fallback.mjs @@ -0,0 +1,62 @@ +/** + * patch-ap-accounts-id-cache-fallback.mjs + * + * Fixes 404 on /api/v1/accounts/:id for actors resolved via /lookup but not + * in followers/following/timeline. After resolveActorData() returns null, + * checks in-memory idToUrl cache and ap_actor_cache MongoDB collection for + * the actor URL, then calls resolveRemoteAccount() if found. + */ +import { readFileSync, writeFileSync } from "node:fs"; + +const MARKER = "// [patch] ap-accounts-id-cache-fallback"; +const TARGET = "/usr/local/indiekit/node_modules/@rmdes/indiekit-endpoint-activitypub/lib/mastodon/routes/accounts.js"; + +const src = readFileSync(TARGET, "utf8"); + +if (src.includes(MARKER)) { + console.log("[postinstall] ap-accounts-id-cache-fallback: already applied"); + process.exit(0); +} + +// Find the 404 return in the GET /accounts/:id handler. +// We need to insert a cache-fallback block BEFORE the 404 return. +// The pattern: after the resolveActorData block, before `return res.status(404)` +// in the :id handler. + +const needle = ` return res.status(404).json({ error: "Record not found" }); + } catch (error) { + next(error); + } +}); + +// ─── GET /api/v1/accounts/:id/statuses`; + +if (!src.includes(needle)) { + console.error("[postinstall] ap-accounts-id-cache-fallback: cannot find insertion point"); + process.exit(1); +} + +const replacement = ` // Cache fallback: actor not in followers/following/timeline, ${MARKER} + // but may have been resolved via /lookup and cached in ap_actor_cache + let cachedActorUrl = getActorUrlFromId(id); ${MARKER} + if (!cachedActorUrl && collections.ap_actor_cache) { ${MARKER} + const cached = await collections.ap_actor_cache.findOne({ _id: id }); ${MARKER} + if (cached?.actorUrl) cachedActorUrl = cached.actorUrl; ${MARKER} + } ${MARKER} + if (cachedActorUrl) { ${MARKER} + const cachedAccount = await resolveRemoteAccount( ${MARKER} + cachedActorUrl, pluginOptions, baseUrl, collections, ${MARKER} + ); ${MARKER} + if (cachedAccount) return res.json(cachedAccount); ${MARKER} + } ${MARKER} + + return res.status(404).json({ error: "Record not found" }); + } catch (error) { + next(error); + } +}); + +// ─── GET /api/v1/accounts/:id/statuses`; + +writeFileSync(TARGET, src.replace(needle, replacement)); +console.log("[postinstall] ap-accounts-id-cache-fallback: applied successfully");