Files
indiekit-server/scripts/patch-ap-dm-bsky-source-content.mjs
Sven fdba547124
Deploy Indiekit Server / deploy (push) Successful in 1m15s
fix(ap): extract DM content from source.content for bsky.brid.gy
bsky.brid.gy DMs arrive as ChatMessage objects with content in
source.content (plain text) instead of content (HTML). The inbox
handler only checked object.content, so all bridged DMs were stored
with empty text and unviewable in Mona.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 16:59:24 +02:00

62 lines
2.3 KiB
JavaScript

/**
* Patch: extract DM content from object.source.content when object.content is empty.
*
* Bluesky DMs bridged via bsky.brid.gy arrive as Create activities wrapping a
* ChatMessage object. Bridgy Fed sends the message text in `source.content`
* (plain text, mediaType: text/plain) without a `content` field (HTML).
*
* The DM handler only checked `object.content`, so all bsky.brid.gy DMs were
* stored with empty content, making them unviewable in Mona.
*
* Fix: after extracting `rawHtml` from `object.content`, also read
* `object.source?.content` as a plain-text fallback for `contentText` when
* `rawHtml` is empty.
*/
import { access, readFile, writeFile } from "node:fs/promises";
const candidates = [
"node_modules/@rmdes/indiekit-endpoint-activitypub/lib/inbox-handlers.js",
"node_modules/@indiekit/indiekit/node_modules/@rmdes/indiekit-endpoint-activitypub/lib/inbox-handlers.js",
];
const MARKER = "// [patch] bsky-source-content-fallback";
const OLD = ` const rawHtml = object.content?.toString() || "";
const contentHtml = sanitizeContent(rawHtml);
const contentText = rawHtml.replace(/<[^>]*>/g, "").substring(0, 500);`;
const NEW = ` const rawHtml = object.content?.toString() || "";
const sourceText = object.source?.content?.toString() || ""; // [patch] bsky-source-content-fallback
const contentHtml = sanitizeContent(rawHtml);
const contentText = rawHtml
? rawHtml.replace(/<[^>]*>/g, "").substring(0, 500)
: sourceText.substring(0, 500);`;
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-bsky-source-content: already applied in ${filePath}`);
patched = true;
break;
}
if (!src.includes(OLD)) {
console.log(`[postinstall] patch-ap-dm-bsky-source-content: target snippet not found in ${filePath}`);
continue;
}
await writeFile(filePath, src.replace(OLD, NEW), "utf8");
console.log(`[postinstall] patch-ap-dm-bsky-source-content: applied to ${filePath}`);
patched = true;
break;
}
if (!patched) {
console.log("[postinstall] patch-ap-dm-bsky-source-content: no target file found");
}