fix(web): capture mentions from media captions

This commit is contained in:
Peter Steinberger
2025-12-03 14:13:09 +00:00
parent a321bf1a90
commit 07f323222b
2 changed files with 76 additions and 5 deletions

View File

@@ -117,4 +117,52 @@ describe("web inbound media saves with extension", () => {
await listener.close();
});
it("extracts mentions from media captions", async () => {
const onMessage = vi.fn();
const listener = await monitorWebInbox({ verbose: false, onMessage });
const { createWaSocket } = await import("./session.js");
const realSock = await (
createWaSocket as unknown as () => Promise<{
ev: import("node:events").EventEmitter;
}>
)();
const upsert = {
type: "notify",
messages: [
{
key: {
id: "img2",
fromMe: false,
remoteJid: "123@g.us",
participant: "999@s.whatsapp.net",
},
message: {
messageContextInfo: {},
imageMessage: {
caption: "@bot",
contextInfo: { mentionedJid: ["999@s.whatsapp.net"] },
mimetype: "image/jpeg",
},
},
messageTimestamp: 1_700_000_002,
},
],
};
realSock.ev.emit("messages.upsert", upsert);
for (let i = 0; i < 10; i++) {
if (onMessage.mock.calls.length > 0) break;
await new Promise((resolve) => setTimeout(resolve, 5));
}
expect(onMessage).toHaveBeenCalledTimes(1);
const msg = onMessage.mock.calls[0][0];
expect(msg.chatType).toBe("group");
expect(msg.mentionedJids).toEqual(["999@s.whatsapp.net"]);
await listener.close();
});
});

View File

@@ -202,11 +202,9 @@ export async function monitorWebInbox(options: {
const timestamp = msg.messageTimestamp
? Number(msg.messageTimestamp) * 1000
: undefined;
const unwrapped = unwrapMessage(msg.message as proto.IMessage | undefined);
const mentionedJids =
unwrapped?.extendedTextMessage?.contextInfo?.mentionedJid ??
unwrapped?.extendedTextMessage?.contextInfo?.quotedMessage
?.extendedTextMessage?.contextInfo?.mentionedJid;
const mentionedJids = extractMentionedJids(
msg.message as proto.IMessage | undefined,
);
const senderName = msg.pushName ?? undefined;
inboundLogger.info(
{
@@ -355,6 +353,31 @@ function unwrapMessage(message: proto.IMessage | undefined): proto.IMessage | un
return message;
}
function extractMentionedJids(
rawMessage: proto.IMessage | undefined,
): string[] | undefined {
const message = unwrapMessage(rawMessage);
if (!message) return undefined;
const candidates: (string[] | undefined)[] = [
message.extendedTextMessage?.contextInfo?.mentionedJid,
message.extendedTextMessage?.contextInfo?.quotedMessage?.extendedTextMessage
?.contextInfo?.mentionedJid,
message.imageMessage?.contextInfo?.mentionedJid,
message.videoMessage?.contextInfo?.mentionedJid,
message.documentMessage?.contextInfo?.mentionedJid,
message.audioMessage?.contextInfo?.mentionedJid,
message.stickerMessage?.contextInfo?.mentionedJid,
message.buttonsResponseMessage?.contextInfo?.mentionedJid,
message.listResponseMessage?.contextInfo?.mentionedJid,
];
const flattened = candidates.flat().filter((j): j is string => !!j);
if (flattened.length === 0) return undefined;
// De-dupe
return Array.from(new Set(flattened));
}
export function extractText(
rawMessage: proto.IMessage | undefined,
): string | undefined {