fix(list-message): convert nativeFlowMessage to direct listMessage for delivery
The viewOnceMessage > interactiveMessage > nativeFlowMessage wrapper with single_select button was causing error 479 even with correct biz node. WhatsApp requires the message to be in direct listMessage format (legacy) paired with biz > list (type=product_list, v=2) node. This matches the Pastorini implementation which sends: - messageKeys: ['listMessage'] (NOT viewOnceMessage) - biz > list (type=product_list, v=2) The conversion extracts sections from nativeFlowMessage's single_select buttonParamsJson and creates a proper listMessage with SINGLE_SELECT type. https://claude.ai/code/session_01SJdSHiUxtwzV8bb5dedodb
This commit is contained in:
@@ -829,6 +829,61 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
|||||||
useUserDevicesCache = useUserDevicesCache !== false
|
useUserDevicesCache = useUserDevicesCache !== false
|
||||||
useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus
|
useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus
|
||||||
|
|
||||||
|
// Convert nativeFlowMessage with single_select to direct listMessage (legacy format)
|
||||||
|
// This is required because WhatsApp expects listMessage format with biz > list node
|
||||||
|
// The viewOnceMessage > interactiveMessage > nativeFlowMessage wrapper causes error 479
|
||||||
|
// Reference: Pastorini sends as direct listMessage and it works on phone + web
|
||||||
|
const innerMsg = message.viewOnceMessage?.message
|
||||||
|
const nativeFlow = innerMsg?.interactiveMessage?.nativeFlowMessage
|
||||||
|
if (nativeFlow?.buttons?.length) {
|
||||||
|
const singleSelectBtn = nativeFlow.buttons.find(
|
||||||
|
(btn: any) => btn?.name === 'single_select'
|
||||||
|
)
|
||||||
|
if (singleSelectBtn?.buttonParamsJson) {
|
||||||
|
try {
|
||||||
|
const params = JSON.parse(singleSelectBtn.buttonParamsJson)
|
||||||
|
const sections = params.sections?.map((section: any) => ({
|
||||||
|
title: section.title,
|
||||||
|
rows: section.rows?.map((row: any) => ({
|
||||||
|
rowId: row.id || row.rowId,
|
||||||
|
title: row.title,
|
||||||
|
description: row.description || ''
|
||||||
|
}))
|
||||||
|
}))
|
||||||
|
|
||||||
|
if (sections?.length) {
|
||||||
|
// Build direct listMessage (legacy format that works)
|
||||||
|
const listMessage = proto.Message.ListMessage.fromObject({
|
||||||
|
title: innerMsg?.interactiveMessage?.header?.title || '',
|
||||||
|
description: innerMsg?.interactiveMessage?.body?.text || '',
|
||||||
|
buttonText: params.title || 'Menu',
|
||||||
|
footerText: innerMsg?.interactiveMessage?.footer?.text || '',
|
||||||
|
listType: proto.Message.ListMessage.ListType.SINGLE_SELECT,
|
||||||
|
sections
|
||||||
|
})
|
||||||
|
|
||||||
|
// Mutate message in-place: remove viewOnceMessage, add listMessage
|
||||||
|
delete message.viewOnceMessage
|
||||||
|
message.listMessage = listMessage
|
||||||
|
// Keep messageContextInfo if it was nested
|
||||||
|
if (!message.messageContextInfo && innerMsg?.messageContextInfo) {
|
||||||
|
message.messageContextInfo = innerMsg.messageContextInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
{ msgId, sectionsCount: sections.length, buttonText: params.title },
|
||||||
|
'[LIST CONVERT] Converted nativeFlowMessage(single_select) to direct listMessage format'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
logger.warn(
|
||||||
|
{ msgId, error: (err as Error).message },
|
||||||
|
'[LIST CONVERT] Failed to convert nativeFlowMessage to listMessage, sending as-is'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const participants: BinaryNode[] = []
|
const participants: BinaryNode[] = []
|
||||||
const destinationJid = !isStatus ? finalJid : statusJid
|
const destinationJid = !isStatus ? finalJid : statusJid
|
||||||
const binaryNodeContent: BinaryNode[] = []
|
const binaryNodeContent: BinaryNode[] = []
|
||||||
|
|||||||
Reference in New Issue
Block a user