fix(discord-gateway): handle forwarded message content via messageSnapshots
Two-layer fix for forwarded messages showing as empty/clean: Layer 1 (messageMetadata.ts): getReferencedMessageContent() now falls back to message.messageSnapshots Collection when channel.messages.cache lookup fails. Discord stores forward content in message_snapshots API field, not in message.content. Layer 2 (moderationBuilders.ts): buildReferenceXml() now parses msg. metadata JSON to extract reference.content when DB getMessageById() fails (cross-server forwards not in local DB). Previously: forward messages captured with empty parentContent → LLM saw no reference text → '99% confidence, pesan kosong'. Now: forward content flows through capture → metadata → analysis.
This commit is contained in:
@@ -48,6 +48,7 @@ export async function buildReferenceXml(msg: MessageRecord): Promise<string> {
|
|||||||
|
|
||||||
let parentContent = "";
|
let parentContent = "";
|
||||||
if (msg.reference_message_id) {
|
if (msg.reference_message_id) {
|
||||||
|
// 1. Try DB first — works for messages captured in the same server
|
||||||
try {
|
try {
|
||||||
const parent = await getMessageById(msg.reference_message_id);
|
const parent = await getMessageById(msg.reference_message_id);
|
||||||
if (parent) {
|
if (parent) {
|
||||||
@@ -55,7 +56,22 @@ export async function buildReferenceXml(msg: MessageRecord): Promise<string> {
|
|||||||
parentContent = parentText.slice(0, 500);
|
parentContent = parentText.slice(0, 500);
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// Parent fetch failed — still inject reference with available info
|
// Parent fetch failed — fall through to metadata
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Fall back to metadata — works for forwards from other servers/channels
|
||||||
|
// where the original message was never captured in this DB.
|
||||||
|
// The capture phase stores the snapshot content in metadata.reference.content.
|
||||||
|
if (!parentContent && msg.metadata) {
|
||||||
|
try {
|
||||||
|
const meta = JSON.parse(msg.metadata);
|
||||||
|
const refContent = meta?.reference?.content;
|
||||||
|
if (refContent && typeof refContent === "string") {
|
||||||
|
parentContent = refContent.slice(0, 500);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Metadata parse failed — no fallback available
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -211,17 +211,20 @@ export function getEmbedMetadata(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to get referenced message content from the channel cache.
|
* Try to get referenced message content from the channel cache or message snapshots.
|
||||||
* For replies, Discord sends `referenced_message` in the API, which
|
* For replies, Discord sends `referenced_message` in the API, which
|
||||||
* discord.js-selfbot-v13 caches in the channel's message manager.
|
* discord.js-selfbot-v13 caches in the channel's message manager.
|
||||||
* Returns null if the message isn't cached (e.g. forwards without
|
* For forwards, Discord sends `message_snapshots` which discord.js-selfbot-v13
|
||||||
* referenced_message payload).
|
* stores in `message.messageSnapshots` as a Collection of partial Message objects.
|
||||||
|
* Returns null if the message can't be resolved from either source.
|
||||||
*/
|
*/
|
||||||
function getReferencedMessageContent(
|
function getReferencedMessageContent(
|
||||||
message: Message,
|
message: Message,
|
||||||
): { content: string; username: string; userId: string } | null {
|
): { content: string; username: string; userId: string } | null {
|
||||||
const ref = message.reference;
|
const ref = message.reference;
|
||||||
if (!ref?.messageId) return null;
|
if (!ref?.messageId) return null;
|
||||||
|
|
||||||
|
// 1. Channel cache — works for same-channel replies/forwards
|
||||||
try {
|
try {
|
||||||
const cached = (message.channel as any)?.messages?.cache?.get(
|
const cached = (message.channel as any)?.messages?.cache?.get(
|
||||||
ref.messageId,
|
ref.messageId,
|
||||||
@@ -236,6 +239,23 @@ function getReferencedMessageContent(
|
|||||||
} catch {
|
} catch {
|
||||||
// Cache may not be available or message not in it
|
// Cache may not be available or message not in it
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. messageSnapshots — works for cross-channel/cross-server forwards
|
||||||
|
// Discord API sends message_snapshots for FORWARD type messages,
|
||||||
|
// and discord.js-selfbot-v13 stores them in message.messageSnapshots.
|
||||||
|
try {
|
||||||
|
const snapshot = message.messageSnapshots?.get(ref.messageId);
|
||||||
|
if (snapshot?.content) {
|
||||||
|
return {
|
||||||
|
content: snapshot.content,
|
||||||
|
username: (snapshot as any).author?.username ?? "Unknown",
|
||||||
|
userId: (snapshot as any).author?.id ?? "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Snapshots may not be available
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user