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:
+19
-11
@@ -2020,12 +2020,16 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
||||
|
||||
const userJid = authState.creds.me!.id
|
||||
|
||||
// Special path for carousel: call relayMessage directly
|
||||
// This bypasses generateWAMessageFromContent (which adds contextInfo.expiration
|
||||
// and calls WAProto.Message.create that may corrupt nested carousel structures)
|
||||
// Matches the working implementation's approach: generateWAMessageContent → relayMessage
|
||||
// Special path for carousel: call relayMessage directly with plain JS object
|
||||
// This matches Pastorini's working approach:
|
||||
// 1. Build message as plain JS object (not proto instance)
|
||||
// 2. Pass directly to relayMessage (no WAProto.Message.fromObject/create)
|
||||
// 3. protobuf encode() handles plain objects correctly during serialization
|
||||
// Going through fromObject() can corrupt nested carousel InteractiveMessage oneOf fields
|
||||
if (typeof content === 'object' && 'nativeCarousel' in content && (content as any).nativeCarousel) {
|
||||
const messageId = generateMessageIDV2(sock.user?.id)
|
||||
// generateWAMessageContent returns a plain JS object for carousel
|
||||
// (not a proto instance) to preserve nested structure integrity
|
||||
const msgContent = await generateWAMessageContent(content, {
|
||||
logger,
|
||||
upload: waUploadToServer,
|
||||
@@ -2034,6 +2038,17 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
||||
jid,
|
||||
})
|
||||
|
||||
// Pass the plain JS object directly to relayMessage
|
||||
// This avoids proto.WebMessageInfo.fromObject() which would call
|
||||
// Message.fromObject() on the nested message, potentially corrupting it
|
||||
await relayMessage(jid, msgContent, {
|
||||
messageId,
|
||||
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
||||
additionalAttributes: {},
|
||||
statusJidList: options.statusJidList,
|
||||
})
|
||||
|
||||
// Build WebMessageInfo only for event emission and return value
|
||||
const timestamp = unixTimestampSeconds()
|
||||
const fullMsg = proto.WebMessageInfo.fromObject({
|
||||
key: {
|
||||
@@ -2048,13 +2063,6 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
||||
status: proto.WebMessageInfo.Status.PENDING
|
||||
}) as WAMessage
|
||||
|
||||
await relayMessage(jid, fullMsg.message!, {
|
||||
messageId: fullMsg.key.id!,
|
||||
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
||||
additionalAttributes: {},
|
||||
statusJidList: options.statusJidList,
|
||||
})
|
||||
|
||||
if (config.emitOwnEvents) {
|
||||
process.nextTick(async () => {
|
||||
const mutexKey = fullMsg.key.remoteJid || fullMsg.key.id || 'unknown'
|
||||
|
||||
Reference in New Issue
Block a user