fix(carousel): bypass proto fromObject for carousel messages to fix error 479

Three changes matching Pastorini's working implementation:

1. Always set root header in generateCarouselMessage - the root
   interactiveMessage header must always be present with title and
   hasMediaAttachment:false. Previously it was undefined when no text
   was provided, which violates WhatsApp MD protocol requirements.

2. Return plain JS object from generateWAMessageContent for carousel -
   skip WAProto.Message.fromObject() which can corrupt nested carousel
   structures by incorrectly handling oneOf fields in deeply nested
   InteractiveMessage cards. protobuf encode() handles plain objects
   correctly during serialization.

3. Pass plain JS object directly to relayMessage in sendMessage - call
   relayMessage(jid, msgContent) with the plain object instead of
   going through proto.WebMessageInfo.fromObject() first. This matches
   Pastorini's approach of relayMessage(jid, plainObject, opts).

https://claude.ai/code/session_018DkDxsjWzM131jy3ivWjZp
This commit is contained in:
Claude
2026-02-06 22:11:54 +00:00
parent 8cd62b964d
commit 1589c82b0d
2 changed files with 29 additions and 18 deletions
+10 -7
View File
@@ -641,8 +641,10 @@ export const generateCarouselMessage = async (
}))
// Build the interactive message with carousel
// Root header MUST always be present for carousel messages (WhatsApp MD requirement)
// Missing root header causes error 479 on some devices
const interactiveMessage: proto.Message.IInteractiveMessage = {
header: text ? { title: text } : undefined,
header: { title: text || '', hasMediaAttachment: false },
body: { text: text || '' },
footer: footer ? { text: footer } : undefined,
carouselMessage: {
@@ -1156,12 +1158,13 @@ export const generateWAMessageContent = async (
// Pass options for media processing if cards have images/videos
const generated = await generateCarouselMessage(carouselOptions, options)
m.viewOnceMessage = generated.viewOnceMessage
options.logger?.info('Sending carousel with viewOnceMessage wrapper + fromObject encoding')
// Return early with fromObject for proper deep conversion of nested carousel structure
// fromObject recursively converts nested plain objects to protobuf message instances
// whereas create() does shallow property copy which may not properly encode deep structures
// This matches the working implementation's encoding approach
return WAProto.Message.fromObject(m)
options.logger?.info('Sending carousel with viewOnceMessage wrapper (plain object, no proto conversion)')
// Return the plain JS object directly WITHOUT calling WAProto.Message.fromObject()
// This matches Pastorini's working approach where plain objects are passed directly
// to relayMessage. The fromObject() conversion can corrupt nested carousel structures
// by incorrectly handling oneOf fields in deeply nested InteractiveMessage cards.
// The protobuf encode() method handles plain objects correctly when serializing.
return m as WAMessageContent
}
// Check for nativeList
else if (hasNonNullishProperty(message, 'nativeList')) {