Files
indiekit-server/scripts/patch-ap-dm-send-serialize-id.mjs
Sven bc44dda3e4
Deploy Indiekit Server / deploy (push) Successful in 1m17s
fix(ap): capture addTimelineItem return for DM serializeStatus
serializeStatus called item._id.toString() but the original timelineItem
had no _id — addTimelineItem returns the stored doc but the return value
was ignored. Fixes "Cannot read properties of undefined (reading 'toString')"
crash when sending DMs from Mona.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 17:23:29 +02:00

67 lines
2.5 KiB
JavaScript

/**
* Patch: capture addTimelineItem return value for DM serializeStatus.
*
* When sending an outbound DM via the Mastodon API, addTimelineItem returns
* the stored MongoDB document (which has _id). The return value was ignored,
* so the original timelineItem object had no _id. serializeStatus then crashed
* on item._id.toString() → "Cannot read properties of undefined (reading 'toString')".
*
* Fix: capture the addTimelineItem result and pass it to serializeStatus.
*/
import { access, readFile, writeFile } from "node:fs/promises";
const candidates = [
"node_modules/@rmdes/indiekit-endpoint-activitypub/lib/mastodon/routes/statuses.js",
"node_modules/@indiekit/indiekit/node_modules/@rmdes/indiekit-endpoint-activitypub/lib/mastodon/routes/statuses.js",
];
const MARKER = "// [patch] dm-send-serialize-id";
const OLD = ` try {
await addTimelineItem(collections, timelineItem);
} catch (storeError) {
console.warn("[Mastodon API] Failed to store outbound DM in timeline:", storeError.message);
}
// Return a full serialized status so clients (Phanpy, Elk) can render it
const status = serializeStatus(timelineItem, {`;
const NEW = ` let storedDmItem = timelineItem; // [patch] dm-send-serialize-id
try {
const _dmResult = await addTimelineItem(collections, timelineItem);
if (_dmResult?._id) storedDmItem = _dmResult;
} catch (storeError) {
console.warn("[Mastodon API] Failed to store outbound DM in timeline:", storeError.message);
}
// Return a full serialized status so clients (Phanpy, Elk) can render it
const status = serializeStatus(storedDmItem, {`;
async function exists(p) {
try { await access(p); return true; } catch { return false; }
}
let patched = false;
for (const filePath of candidates) {
if (!(await exists(filePath))) continue;
const src = await readFile(filePath, "utf8");
if (src.includes(MARKER)) {
console.log(`[postinstall] patch-ap-dm-send-serialize-id: already applied in ${filePath}`);
patched = true;
break;
}
if (!src.includes(OLD)) {
console.log(`[postinstall] patch-ap-dm-send-serialize-id: target snippet not found in ${filePath}`);
continue;
}
await writeFile(filePath, src.replace(OLD, NEW), "utf8");
console.log(`[postinstall] patch-ap-dm-send-serialize-id: applied to ${filePath}`);
patched = true;
break;
}
if (!patched) {
console.log("[postinstall] patch-ap-dm-send-serialize-id: no target file found");
}