/** * 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"); }