Files
n8n/patches/@[email protected]
T
2026-10-06 16:02:03 +00:00

80 lines
3.1 KiB
Diff

diff --git a/dist/index.js b/dist/index.js
index ab5a27df2d1cde5530b33d24d6e30dc67e5be84d..6141dc9a651a2d7a568cc5b7eaa0a20c269437eb 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -25,6 +25,13 @@ var MAX_REPLY_BUTTONS = 3;
var MAX_BUTTON_TITLE_LENGTH = 20;
var MAX_BODY_LENGTH = 1024;
var MAX_HEADER_LENGTH = 60;
+// n8n patch (upstream: TODO file issue against vercel/chat) — WhatsApp's own
+// limits on interactive list messages.
+var MAX_LIST_ROWS = 10;
+var MAX_LIST_ROW_TITLE_LENGTH = 24;
+var MAX_LIST_ROW_DESCRIPTION_LENGTH = 72;
+var MAX_LIST_BUTTON_LABEL_LENGTH = 20;
+var MAX_LIST_ROW_ID_LENGTH = 200;
function encodeWhatsAppCallbackData(actionId, value) {
const payload = { a: actionId };
if (typeof value === "string") {
@@ -78,6 +85,42 @@ function cardToWhatsApp(card, options) {
}
};
}
+ // n8n patch (upstream: TODO file issue against vercel/chat) — builds a
+ // real WhatsApp list message instead of falling through to broken text.
+ const actionSelect = actions ? extractSelect(actions) : null;
+ if (actionSelect) {
+ // A long value can push a row's encoded id past MAX_LIST_ROW_ID_LENGTH,
+ // and Meta rejects the whole send if any row is invalid. Drop the row
+ // rather than truncate it, which would resume the wrong option.
+ const rows = actionSelect.options.map((opt) => ({
+ id: encodeWhatsAppCallbackData(actionSelect.id, opt.value),
+ title: truncate(opt.label, MAX_LIST_ROW_TITLE_LENGTH),
+ ...(opt.description ? { description: truncate(opt.description, MAX_LIST_ROW_DESCRIPTION_LENGTH) } : {})
+ })).filter((row) => {
+ if (row.id.length <= MAX_LIST_ROW_ID_LENGTH) return true;
+ console.warn(
+ `[WhatsAppAdapter] Dropping list option "${row.title}" — its encoded callback id exceeds WhatsApp's ${MAX_LIST_ROW_ID_LENGTH}-character row id limit.`
+ );
+ return false;
+ }).slice(0, MAX_LIST_ROWS);
+ if (rows.length > 0) {
+ const bodyText = [buildBodyText(card), ...cardLinkButtonLines(card)].filter(Boolean).join("\n");
+ return {
+ type: "interactive",
+ interactive: {
+ type: "list",
+ ...buildInteractiveEnvelope(
+ card,
+ bodyText || "Please choose an option"
+ ),
+ action: {
+ button: truncate(actionSelect.label || "Choose an option", MAX_LIST_BUTTON_LABEL_LENGTH),
+ sections: [{ rows }]
+ }
+ }
+ };
+ }
+ }
if (options?.allowCtaUrl !== false) {
const ctaLink = findPromotableCtaLink(card);
if (ctaLink) {
@@ -219,6 +262,17 @@ function extractReplyButtons(actions) {
}
return buttons.slice(0, MAX_REPLY_BUTTONS);
}
+// n8n patch (upstream: TODO file issue against vercel/chat) — mirrors
+// extractReplyButtons above, for a `select`/`radio_select` actions child.
+function extractSelect(actions) {
+ const select = actions.children.find(
+ (child) => child.type === "select" || child.type === "radio_select"
+ );
+ if (!select || !select.options || select.options.length === 0) {
+ return null;
+ }
+ return select;
+}
function buildInteractiveEnvelope(card, bodyText) {
return {
...card.title ? {