fix(carousel): bypass proto fromObject for carousel messages to fix
fix(carousel): bypass proto fromObject for carousel messages to fix
This commit is contained in:
+19
-11
@@ -2020,12 +2020,16 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
|||||||
|
|
||||||
const userJid = authState.creds.me!.id
|
const userJid = authState.creds.me!.id
|
||||||
|
|
||||||
// Special path for carousel: call relayMessage directly
|
// Special path for carousel: call relayMessage directly with plain JS object
|
||||||
// This bypasses generateWAMessageFromContent (which adds contextInfo.expiration
|
// This matches Pastorini's working approach:
|
||||||
// and calls WAProto.Message.create that may corrupt nested carousel structures)
|
// 1. Build message as plain JS object (not proto instance)
|
||||||
// Matches the working implementation's approach: generateWAMessageContent → relayMessage
|
// 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) {
|
if (typeof content === 'object' && 'nativeCarousel' in content && (content as any).nativeCarousel) {
|
||||||
const messageId = generateMessageIDV2(sock.user?.id)
|
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, {
|
const msgContent = await generateWAMessageContent(content, {
|
||||||
logger,
|
logger,
|
||||||
upload: waUploadToServer,
|
upload: waUploadToServer,
|
||||||
@@ -2034,6 +2038,17 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
|||||||
jid,
|
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 timestamp = unixTimestampSeconds()
|
||||||
const fullMsg = proto.WebMessageInfo.fromObject({
|
const fullMsg = proto.WebMessageInfo.fromObject({
|
||||||
key: {
|
key: {
|
||||||
@@ -2048,13 +2063,6 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
|||||||
status: proto.WebMessageInfo.Status.PENDING
|
status: proto.WebMessageInfo.Status.PENDING
|
||||||
}) as WAMessage
|
}) as WAMessage
|
||||||
|
|
||||||
await relayMessage(jid, fullMsg.message!, {
|
|
||||||
messageId: fullMsg.key.id!,
|
|
||||||
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
||||||
additionalAttributes: {},
|
|
||||||
statusJidList: options.statusJidList,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (config.emitOwnEvents) {
|
if (config.emitOwnEvents) {
|
||||||
process.nextTick(async () => {
|
process.nextTick(async () => {
|
||||||
const mutexKey = fullMsg.key.remoteJid || fullMsg.key.id || 'unknown'
|
const mutexKey = fullMsg.key.remoteJid || fullMsg.key.id || 'unknown'
|
||||||
|
|||||||
+10
-7
@@ -641,8 +641,10 @@ export const generateCarouselMessage = async (
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
// Build the interactive message with carousel
|
// 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 = {
|
const interactiveMessage: proto.Message.IInteractiveMessage = {
|
||||||
header: text ? { title: text } : undefined,
|
header: { title: text || '', hasMediaAttachment: false },
|
||||||
body: { text: text || '' },
|
body: { text: text || '' },
|
||||||
footer: footer ? { text: footer } : undefined,
|
footer: footer ? { text: footer } : undefined,
|
||||||
carouselMessage: {
|
carouselMessage: {
|
||||||
@@ -1156,12 +1158,13 @@ export const generateWAMessageContent = async (
|
|||||||
// Pass options for media processing if cards have images/videos
|
// Pass options for media processing if cards have images/videos
|
||||||
const generated = await generateCarouselMessage(carouselOptions, options)
|
const generated = await generateCarouselMessage(carouselOptions, options)
|
||||||
m.viewOnceMessage = generated.viewOnceMessage
|
m.viewOnceMessage = generated.viewOnceMessage
|
||||||
options.logger?.info('Sending carousel with viewOnceMessage wrapper + fromObject encoding')
|
options.logger?.info('Sending carousel with viewOnceMessage wrapper (plain object, no proto conversion)')
|
||||||
// Return early with fromObject for proper deep conversion of nested carousel structure
|
// Return the plain JS object directly WITHOUT calling WAProto.Message.fromObject()
|
||||||
// fromObject recursively converts nested plain objects to protobuf message instances
|
// This matches Pastorini's working approach where plain objects are passed directly
|
||||||
// whereas create() does shallow property copy which may not properly encode deep structures
|
// to relayMessage. The fromObject() conversion can corrupt nested carousel structures
|
||||||
// This matches the working implementation's encoding approach
|
// by incorrectly handling oneOf fields in deeply nested InteractiveMessage cards.
|
||||||
return WAProto.Message.fromObject(m)
|
// The protobuf encode() method handles plain objects correctly when serializing.
|
||||||
|
return m as WAMessageContent
|
||||||
}
|
}
|
||||||
// Check for nativeList
|
// Check for nativeList
|
||||||
else if (hasNonNullishProperty(message, 'nativeList')) {
|
else if (hasNonNullishProperty(message, 'nativeList')) {
|
||||||
|
|||||||
Reference in New Issue
Block a user