fix: Disable biz node injection for list messages to fix Web/iOS delivery

After testing, messages with list-specific biz node structure were not being
delivered. Analysis of the issue revealed that list messages with nativeFlowMessage
should NOT have biz node injection, similar to product lists.

Changes:
- Modified getButtonType() to detect list buttons (single_select/multi_select)
- Return undefined for list buttons to skip biz node injection
- Applied to both direct interactiveMessage and viewOnceMessage wrapped messages
- Simplified biz node injection logic since lists now skip it

This approach aligns with how product lists are handled (no biz node) and
should allow list messages to be delivered successfully on all platforms.

Previous attempt used custom biz node structure which caused delivery failures.
This conservative approach avoids biz node entirely for lists.

https://claude.ai/code/session_01Vgu4xrsj8aUVCHWb4pmQPF
This commit is contained in:
Claude
2026-02-06 01:35:19 +00:00
parent 932f1b17bf
commit 7b1b920104
+43 -47
View File
@@ -643,6 +643,15 @@ export const makeMessagesSocket = (config: SocketConfig) => {
} else if (message.interactiveMessage) { } else if (message.interactiveMessage) {
// Check if it has nativeFlowMessage (modern format) // Check if it has nativeFlowMessage (modern format)
if (message.interactiveMessage.nativeFlowMessage) { if (message.interactiveMessage.nativeFlowMessage) {
// Check if it's a list (single_select or multi_select)
// Lists don't need biz node injection, similar to product lists
const buttons = message.interactiveMessage.nativeFlowMessage.buttons || []
const isListButton = buttons.some(
(btn: any) => btn?.name === 'single_select' || btn?.name === 'multi_select'
)
if (isListButton) {
return undefined // No biz node for list messages
}
return 'native_flow' return 'native_flow'
} }
// Check if it's a carousel with nativeFlowMessage buttons in cards // Check if it's a carousel with nativeFlowMessage buttons in cards
@@ -689,6 +698,15 @@ export const makeMessagesSocket = (config: SocketConfig) => {
} else if (innerMessage.interactiveMessage) { } else if (innerMessage.interactiveMessage) {
// Check if it has nativeFlowMessage (modern format) // Check if it has nativeFlowMessage (modern format)
if (innerMessage.interactiveMessage.nativeFlowMessage) { if (innerMessage.interactiveMessage.nativeFlowMessage) {
// Check if it's a list (single_select or multi_select)
// Lists don't need biz node injection, similar to product lists
const buttons = innerMessage.interactiveMessage.nativeFlowMessage.buttons || []
const isListButton = buttons.some(
(btn: any) => btn?.name === 'single_select' || btn?.name === 'multi_select'
)
if (isListButton) {
return undefined // No biz node for list messages
}
return 'native_flow' return 'native_flow'
} }
// Check if it's a carousel with nativeFlowMessage buttons in cards // Check if it's a carousel with nativeFlowMessage buttons in cards
@@ -1215,54 +1233,32 @@ export const makeMessagesSocket = (config: SocketConfig) => {
metrics.interactiveMessagesSent.inc({ type: buttonType }) metrics.interactiveMessagesSent.inc({ type: buttonType })
try { try {
// Check if this is a list message to use the correct biz node structure // Use nested structure: biz > interactive > native_flow
if (isListDetected) { // For buttons, carousels, and other interactive messages
// For list messages, use direct <list> tag in biz node // NOTE: Lists now skip biz node injection (handled in getButtonType)
// This structure works on Web, iOS, and Android const interactiveType = 'native_flow'
;(stanza.content as BinaryNode[]).push({ ;(stanza.content as BinaryNode[]).push({
tag: 'biz', tag: 'biz',
attrs: {}, attrs: {},
content: [ content: [
{ {
tag: 'list', tag: 'interactive',
attrs: { attrs: {
type: 'single_select', type: interactiveType,
v: '2' v: '1'
} },
} content: [
] {
}) tag: interactiveType,
logger.info( attrs: {
{ msgId, to: destinationJid }, v: '9',
'[EXPERIMENTAL] Injected list-specific biz node for Web/iOS/Android compatibility' name: 'mixed'
)
} else {
// Use nested structure: biz > interactive > native_flow
// For buttons, carousels, and other interactive messages
const interactiveType = 'native_flow'
;(stanza.content as BinaryNode[]).push({
tag: 'biz',
attrs: {},
content: [
{
tag: 'interactive',
attrs: {
type: interactiveType,
v: '1'
},
content: [
{
tag: interactiveType,
attrs: {
v: '9',
name: 'mixed'
}
} }
] }
} ]
] }
}) ]
} })
// For private 1:1 chats, add bot node (required for some interactive messages to render) // For private 1:1 chats, add bot node (required for some interactive messages to render)
// Only inject for actual user JIDs, not broadcasts, newsletters, or Meta AI bots // Only inject for actual user JIDs, not broadcasts, newsletters, or Meta AI bots