@dev.smartpricing/message-composer-utils 3.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/types/api/aiIntegration.js +7 -0
- package/dist/types/api/aiIntegration.js.map +1 -0
- package/dist/types/api/apiMessages.js +2 -0
- package/dist/types/api/apiMessages.js.map +1 -0
- package/dist/types/api/index.js +3 -0
- package/dist/types/api/index.js.map +1 -0
- package/dist/types/app.js +23 -0
- package/dist/types/app.js.map +1 -0
- package/dist/types/brand.js +31 -0
- package/dist/types/brand.js.map +1 -0
- package/dist/types/dynamic-values.js +5 -0
- package/dist/types/dynamic-values.js.map +1 -0
- package/dist/types/emailblocks.v1.defaults.js +83 -0
- package/dist/types/emailblocks.v1.defaults.js.map +1 -0
- package/dist/types/emailblocks.v1.js +339 -0
- package/dist/types/emailblocks.v1.js.map +1 -0
- package/dist/types/index.js +16 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/kafka-events.js +2 -0
- package/dist/types/kafka-events.js.map +1 -0
- package/dist/types/language.js +2 -0
- package/dist/types/language.js.map +1 -0
- package/dist/types/media.js +6 -0
- package/dist/types/media.js.map +1 -0
- package/dist/types/message.js +41 -0
- package/dist/types/message.js.map +1 -0
- package/dist/types/meta-template.js +2 -0
- package/dist/types/meta-template.js.map +1 -0
- package/dist/types/meta-webhook.js +2 -0
- package/dist/types/meta-webhook.js.map +1 -0
- package/dist/types/submission-job.js +2 -0
- package/dist/types/submission-job.js.map +1 -0
- package/dist/types/tag.js +2 -0
- package/dist/types/tag.js.map +1 -0
- package/dist/types/utils.js +2 -0
- package/dist/types/utils.js.map +1 -0
- package/dist/types/whatsappblocks.v1.js +24 -0
- package/dist/types/whatsappblocks.v1.js.map +1 -0
- package/dist/utils/array.js +26 -0
- package/dist/utils/array.js.map +1 -0
- package/dist/utils/async.js +22 -0
- package/dist/utils/async.js.map +1 -0
- package/dist/utils/date.js +37 -0
- package/dist/utils/date.js.map +1 -0
- package/dist/utils/index.js +34 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/intl.js +37 -0
- package/dist/utils/intl.js.map +1 -0
- package/dist/utils/meta-status.js +21 -0
- package/dist/utils/meta-status.js.map +1 -0
- package/dist/utils/number.js +24 -0
- package/dist/utils/number.js.map +1 -0
- package/dist/utils/object.js +87 -0
- package/dist/utils/object.js.map +1 -0
- package/dist/utils/string.js +22 -0
- package/dist/utils/string.js.map +1 -0
- package/dist/utils/templates/brand-cascade.js +116 -0
- package/dist/utils/templates/brand-cascade.js.map +1 -0
- package/dist/utils/templates/email-compiler.js +126 -0
- package/dist/utils/templates/email-compiler.js.map +1 -0
- package/dist/utils/templates/email-mjml.js +444 -0
- package/dist/utils/templates/email-mjml.js.map +1 -0
- package/dist/utils/templates/email.js +580 -0
- package/dist/utils/templates/email.js.map +1 -0
- package/dist/utils/templates/html-sanitizer.js +95 -0
- package/dist/utils/templates/html-sanitizer.js.map +1 -0
- package/dist/utils/templates/messages.js +33 -0
- package/dist/utils/templates/messages.js.map +1 -0
- package/dist/utils/templates/meta.js +246 -0
- package/dist/utils/templates/meta.js.map +1 -0
- package/dist/utils/templates/tiptap.js +167 -0
- package/dist/utils/templates/tiptap.js.map +1 -0
- package/dist/utils/templates/whatsapp-compiler.js +168 -0
- package/dist/utils/templates/whatsapp-compiler.js.map +1 -0
- package/dist/utils/templates/whatsapp.js +329 -0
- package/dist/utils/templates/whatsapp.js.map +1 -0
- package/dist/utils/validations.js +39 -0
- package/dist/utils/validations.js.map +1 -0
- package/package.json +43 -0
- package/src/types/api/aiIntegration.ts +59 -0
- package/src/types/api/apiMessages.ts +22 -0
- package/src/types/api/index.ts +2 -0
- package/src/types/app.ts +76 -0
- package/src/types/brand.ts +80 -0
- package/src/types/dynamic-values.ts +47 -0
- package/src/types/emailblocks.v1.defaults.ts +123 -0
- package/src/types/emailblocks.v1.ts +655 -0
- package/src/types/index.ts +15 -0
- package/src/types/kafka-events.ts +46 -0
- package/src/types/language.ts +9 -0
- package/src/types/media.ts +26 -0
- package/src/types/message.ts +635 -0
- package/src/types/meta-template.ts +50 -0
- package/src/types/meta-webhook.ts +32 -0
- package/src/types/submission-job.ts +30 -0
- package/src/types/tag.ts +8 -0
- package/src/types/utils.ts +14 -0
- package/src/types/whatsappblocks.v1.ts +102 -0
- package/src/utils/array.ts +33 -0
- package/src/utils/async.ts +30 -0
- package/src/utils/date.ts +39 -0
- package/src/utils/index.ts +44 -0
- package/src/utils/intl.ts +51 -0
- package/src/utils/meta-status.ts +24 -0
- package/src/utils/number.ts +36 -0
- package/src/utils/object.ts +101 -0
- package/src/utils/string.ts +24 -0
- package/src/utils/templates/brand-cascade.ts +156 -0
- package/src/utils/templates/email-compiler.ts +155 -0
- package/src/utils/templates/email-mjml.ts +602 -0
- package/src/utils/templates/email.ts +713 -0
- package/src/utils/templates/html-sanitizer.ts +121 -0
- package/src/utils/templates/messages.ts +44 -0
- package/src/utils/templates/meta.ts +336 -0
- package/src/utils/templates/tiptap.ts +247 -0
- package/src/utils/templates/whatsapp-compiler.ts +212 -0
- package/src/utils/templates/whatsapp.ts +408 -0
- package/src/utils/validations.ts +49 -0
- package/tsconfig.json +10 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { type Content, type Extensions } from "@tiptap/core";
|
|
2
|
+
import { generateJSON } from "@tiptap/html";
|
|
3
|
+
import StarterKit from "@tiptap/starter-kit";
|
|
4
|
+
import Mention from "@tiptap/extension-mention";
|
|
5
|
+
import Emoji, { gitHubEmojis } from "@tiptap/extension-emoji";
|
|
6
|
+
import { CharacterCount } from "@tiptap/extensions";
|
|
7
|
+
import TextAlign from "@tiptap/extension-text-align";
|
|
8
|
+
import type { JSONContent } from "@tiptap/core";
|
|
9
|
+
import { RenderType, WA_BODY_MAX_LENGTH } from "../../types/index.js";
|
|
10
|
+
import { generateHtml, generateText } from "./messages.js";
|
|
11
|
+
|
|
12
|
+
export interface TipTapExtensionOptions {
|
|
13
|
+
preset?: "whatsapp" | "whatsapp-header" | "email";
|
|
14
|
+
bold?: boolean;
|
|
15
|
+
italic?: boolean;
|
|
16
|
+
emoji?: boolean;
|
|
17
|
+
underline?: boolean;
|
|
18
|
+
link?: boolean;
|
|
19
|
+
bulletList?: boolean;
|
|
20
|
+
orderedList?: boolean;
|
|
21
|
+
textAlign?: boolean;
|
|
22
|
+
dynamicValues?: boolean;
|
|
23
|
+
characterLimit?: number;
|
|
24
|
+
horizontalRule?: boolean;
|
|
25
|
+
hardBreak?: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const PRESETS: Record<
|
|
29
|
+
NonNullable<TipTapExtensionOptions["preset"]>,
|
|
30
|
+
Omit<TipTapExtensionOptions, "preset" | "dynamicValues" | "characterLimit">
|
|
31
|
+
> = {
|
|
32
|
+
whatsapp: {
|
|
33
|
+
bold: true,
|
|
34
|
+
italic: true,
|
|
35
|
+
emoji: true,
|
|
36
|
+
},
|
|
37
|
+
"whatsapp-header": {
|
|
38
|
+
bold: true,
|
|
39
|
+
italic: true,
|
|
40
|
+
emoji: true,
|
|
41
|
+
},
|
|
42
|
+
email: {
|
|
43
|
+
bold: true,
|
|
44
|
+
italic: true,
|
|
45
|
+
emoji: true,
|
|
46
|
+
underline: true,
|
|
47
|
+
link: true,
|
|
48
|
+
bulletList: true,
|
|
49
|
+
orderedList: true,
|
|
50
|
+
textAlign: true,
|
|
51
|
+
horizontalRule: true,
|
|
52
|
+
hardBreak: true,
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export function getTipTapExtensions(
|
|
57
|
+
options: TipTapExtensionOptions = {},
|
|
58
|
+
): Extensions {
|
|
59
|
+
const presetOptions = options.preset ? PRESETS[options.preset] : {};
|
|
60
|
+
const merged = { ...presetOptions, ...options };
|
|
61
|
+
|
|
62
|
+
const {
|
|
63
|
+
bold = false,
|
|
64
|
+
italic = false,
|
|
65
|
+
emoji = false,
|
|
66
|
+
underline = false,
|
|
67
|
+
link = false,
|
|
68
|
+
bulletList = false,
|
|
69
|
+
orderedList = false,
|
|
70
|
+
textAlign = false,
|
|
71
|
+
dynamicValues = true,
|
|
72
|
+
characterLimit,
|
|
73
|
+
horizontalRule = false,
|
|
74
|
+
hardBreak = false,
|
|
75
|
+
} = merged;
|
|
76
|
+
|
|
77
|
+
const extensions: Extensions = [];
|
|
78
|
+
|
|
79
|
+
// Add character count if limit is set
|
|
80
|
+
if (characterLimit) {
|
|
81
|
+
extensions.push(
|
|
82
|
+
CharacterCount.configure({
|
|
83
|
+
limit: characterLimit,
|
|
84
|
+
}),
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Add mention support if dynamic values are provided
|
|
89
|
+
if (dynamicValues) {
|
|
90
|
+
extensions.push(
|
|
91
|
+
Mention.configure({
|
|
92
|
+
renderText: (mention) => `{{${mention.node.attrs.label}}}`,
|
|
93
|
+
renderHTML: (mention) =>
|
|
94
|
+
`{{${mention.node.attrs.label || mention.node.attrs.id}}}`,
|
|
95
|
+
HTMLAttributes: {
|
|
96
|
+
class: "dynamic-data",
|
|
97
|
+
},
|
|
98
|
+
deleteTriggerWithBackspace: true,
|
|
99
|
+
}),
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Add emoji support if enabled
|
|
104
|
+
if (emoji) {
|
|
105
|
+
extensions.push(
|
|
106
|
+
Emoji.configure({
|
|
107
|
+
emojis: gitHubEmojis,
|
|
108
|
+
HTMLAttributes: {
|
|
109
|
+
class: "tiptap-emoji",
|
|
110
|
+
},
|
|
111
|
+
suggestion: {
|
|
112
|
+
char: ":",
|
|
113
|
+
items: (props) =>
|
|
114
|
+
gitHubEmojis.filter((emoji) => emoji.name.includes(props.query)),
|
|
115
|
+
},
|
|
116
|
+
}),
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Add text align extension if enabled
|
|
121
|
+
if (textAlign) {
|
|
122
|
+
extensions.push(
|
|
123
|
+
TextAlign.configure({
|
|
124
|
+
types: ["paragraph"],
|
|
125
|
+
}),
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Configure StarterKit based on enabled features
|
|
130
|
+
extensions.push(
|
|
131
|
+
StarterKit.configure({
|
|
132
|
+
bold: bold ? undefined : false,
|
|
133
|
+
italic: italic ? undefined : false,
|
|
134
|
+
underline: underline ? undefined : false,
|
|
135
|
+
link: link
|
|
136
|
+
? {
|
|
137
|
+
openOnClick: false,
|
|
138
|
+
}
|
|
139
|
+
: false,
|
|
140
|
+
heading: false,
|
|
141
|
+
bulletList: bulletList ? undefined : false,
|
|
142
|
+
orderedList: orderedList ? undefined : false,
|
|
143
|
+
listItem: bulletList || orderedList ? undefined : false,
|
|
144
|
+
blockquote: false,
|
|
145
|
+
code: false,
|
|
146
|
+
codeBlock: false,
|
|
147
|
+
horizontalRule: horizontalRule
|
|
148
|
+
? {
|
|
149
|
+
HTMLAttributes: {
|
|
150
|
+
style: "border-top: 1px solid #E5E7EB; margin: 16px 0;",
|
|
151
|
+
},
|
|
152
|
+
}
|
|
153
|
+
: false,
|
|
154
|
+
hardBreak: hardBreak ? undefined : false,
|
|
155
|
+
strike: false,
|
|
156
|
+
}),
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
return extensions;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function getAllMentions(content: Content | undefined): Array<Content> {
|
|
163
|
+
if (!content) return [];
|
|
164
|
+
|
|
165
|
+
function processNode(node: Content): Array<Content> {
|
|
166
|
+
if (typeof node === "string") {
|
|
167
|
+
return [];
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (Array.isArray(node)) {
|
|
171
|
+
return node.map(processNode);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (!node || typeof node !== "object") {
|
|
175
|
+
return [];
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Process content recursively
|
|
179
|
+
if (node.content) {
|
|
180
|
+
const a = node.content.map(processNode);
|
|
181
|
+
return a.flat();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Handle block-level elements
|
|
185
|
+
switch (node.type) {
|
|
186
|
+
case "mention":
|
|
187
|
+
return [node];
|
|
188
|
+
|
|
189
|
+
default:
|
|
190
|
+
return [];
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return (processNode(content)?.flat().filter(Boolean) as Array<Content>) ?? [];
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export function extractText(
|
|
198
|
+
field: JSONContent | string | undefined,
|
|
199
|
+
renderType: RenderType,
|
|
200
|
+
): string {
|
|
201
|
+
if (!field) return "";
|
|
202
|
+
|
|
203
|
+
// If it's TipTap content (object with type and content)
|
|
204
|
+
if (typeof field === "object" && field.type) {
|
|
205
|
+
return generateHtml(field, renderType);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// If it's plain text
|
|
209
|
+
if (typeof field === "string") {
|
|
210
|
+
return field;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return "";
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export function isTiptapEmpty(
|
|
217
|
+
field: JSONContent | string | undefined,
|
|
218
|
+
renderType: RenderType,
|
|
219
|
+
): boolean {
|
|
220
|
+
if (!field) return true;
|
|
221
|
+
|
|
222
|
+
// For TipTap content
|
|
223
|
+
if (typeof field === "object" && field.type) {
|
|
224
|
+
const text = generateText(field, renderType);
|
|
225
|
+
return !text || text.trim() === "";
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// For plain text
|
|
229
|
+
if (typeof field === "string") {
|
|
230
|
+
return !field || field.trim() === "";
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Create TipTap JSON structure from plain text
|
|
238
|
+
*/
|
|
239
|
+
export function createTipTapContent(
|
|
240
|
+
text: string,
|
|
241
|
+
options: TipTapExtensionOptions = {
|
|
242
|
+
preset: "whatsapp",
|
|
243
|
+
characterLimit: WA_BODY_MAX_LENGTH,
|
|
244
|
+
},
|
|
245
|
+
) {
|
|
246
|
+
return generateJSON(text, getTipTapExtensions(options));
|
|
247
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
WhatsappMessage,
|
|
3
|
+
WhatsAppSendPayload,
|
|
4
|
+
ParameterValidationResult,
|
|
5
|
+
WhatsappHeaderParam,
|
|
6
|
+
} from "../../types/index.js";
|
|
7
|
+
import type { JSONContent } from "@tiptap/core";
|
|
8
|
+
import { convertToWhatsappMarkdown } from "./whatsapp.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Normalize parameters to strings for Meta API compatibility
|
|
12
|
+
* Handles null, undefined, numbers, booleans, objects
|
|
13
|
+
*/
|
|
14
|
+
export function normalizeParameters(
|
|
15
|
+
parameters: Record<string, unknown>,
|
|
16
|
+
): Record<string, string> {
|
|
17
|
+
return Object.fromEntries(
|
|
18
|
+
Object.entries(parameters).map(([key, value]) => {
|
|
19
|
+
// Coerce to string
|
|
20
|
+
if (value === null || value === undefined) return [key, ""];
|
|
21
|
+
if (typeof value === "string") return [key, value]; // Allow empty strings
|
|
22
|
+
return [key, String(value)]; // Numbers, booleans, objects
|
|
23
|
+
}),
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Extract parameter names from text containing {{param_name}} placeholders
|
|
29
|
+
*/
|
|
30
|
+
function extractParameters(text: string): string[] {
|
|
31
|
+
const paramRegex = /\{\{([^}]+)\}\}/g;
|
|
32
|
+
const matches = [...text.matchAll(paramRegex)];
|
|
33
|
+
return matches.map((match) => match[1].trim());
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Convert JSONContent to string for parameter extraction
|
|
38
|
+
*/
|
|
39
|
+
function contentToString(content: JSONContent | undefined): string {
|
|
40
|
+
if (!content) return "";
|
|
41
|
+
return convertToWhatsappMarkdown(content);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Extract all required parameters from a WhatsApp message template
|
|
46
|
+
*/
|
|
47
|
+
export function extractRequiredParameters(message: WhatsappMessage): string[] {
|
|
48
|
+
const parameters = new Set<string>();
|
|
49
|
+
|
|
50
|
+
// Extract from header if it's text
|
|
51
|
+
if (message.body.header.type === "text" && message.body.header.content) {
|
|
52
|
+
const headerText = contentToString(message.body.header.content);
|
|
53
|
+
extractParameters(headerText).forEach((p) => parameters.add(p));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Extract from body
|
|
57
|
+
if (message.body.body.content) {
|
|
58
|
+
const bodyText = contentToString(message.body.body.content);
|
|
59
|
+
extractParameters(bodyText).forEach((p) => parameters.add(p));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Extract from button URLs
|
|
63
|
+
if (message.body.buttons.enabled) {
|
|
64
|
+
message.body.buttons.buttons.forEach((button) => {
|
|
65
|
+
if (button.type === "link" && button.url) {
|
|
66
|
+
extractParameters(button.url).forEach((p) => parameters.add(p));
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return Array.from(parameters);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Validate that all required parameters are provided
|
|
76
|
+
*/
|
|
77
|
+
export function validateParameters(
|
|
78
|
+
message: WhatsappMessage,
|
|
79
|
+
parameters: Record<string, unknown>,
|
|
80
|
+
): ParameterValidationResult {
|
|
81
|
+
const required = extractRequiredParameters(message);
|
|
82
|
+
const provided = Object.keys(parameters);
|
|
83
|
+
|
|
84
|
+
const missing = required.filter((p) => !provided.includes(p));
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
valid: missing.length === 0,
|
|
88
|
+
required,
|
|
89
|
+
missing,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Build component parameters array for Meta API
|
|
95
|
+
*/
|
|
96
|
+
function buildComponentParameters(
|
|
97
|
+
text: string,
|
|
98
|
+
parameters: Record<string, string>,
|
|
99
|
+
): Array<{ type: "text"; text: string; parameter_name: string }> {
|
|
100
|
+
const paramNames = extractParameters(text);
|
|
101
|
+
return paramNames.map((paramName) => ({
|
|
102
|
+
type: "text" as const,
|
|
103
|
+
text: parameters[paramName] ?? "",
|
|
104
|
+
parameter_name: paramName,
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Compile WhatsApp message template into Meta Cloud API send format
|
|
110
|
+
*
|
|
111
|
+
* @param message - The WhatsApp message template to compile
|
|
112
|
+
* @param parameters - Key-value pairs for parameter injection (will be normalized to strings)
|
|
113
|
+
* @returns WhatsApp Cloud API send payload (without 'to' field)
|
|
114
|
+
*/
|
|
115
|
+
export function compileWhatsappTemplate(
|
|
116
|
+
message: WhatsappMessage,
|
|
117
|
+
parameters: Record<string, unknown>,
|
|
118
|
+
): Omit<WhatsAppSendPayload, "to"> {
|
|
119
|
+
// Normalize parameters to strings first
|
|
120
|
+
const normalizedParams = normalizeParameters(parameters);
|
|
121
|
+
|
|
122
|
+
const components: NonNullable<WhatsAppSendPayload["template"]["components"]> =
|
|
123
|
+
[];
|
|
124
|
+
|
|
125
|
+
// Get template name from metadata
|
|
126
|
+
const templateName = message.metadata?.meta?.template_name;
|
|
127
|
+
if (!templateName) {
|
|
128
|
+
throw new Error("Message does not have Meta template name in metadata");
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Build header component if exists
|
|
132
|
+
if (message.body.header.type === "text" && message.body.header.content) {
|
|
133
|
+
const headerText = contentToString(message.body.header.content);
|
|
134
|
+
const headerParams = buildComponentParameters(headerText, normalizedParams);
|
|
135
|
+
|
|
136
|
+
if (headerParams.length > 0) {
|
|
137
|
+
components.push({
|
|
138
|
+
type: "HEADER",
|
|
139
|
+
parameters: headerParams,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
} else if (
|
|
143
|
+
(message.body.header.type === "image" ||
|
|
144
|
+
message.body.header.type === "video" ||
|
|
145
|
+
message.body.header.type === "document") &&
|
|
146
|
+
message.body.header.smartchatMediaId
|
|
147
|
+
) {
|
|
148
|
+
const t = message.body.header.type;
|
|
149
|
+
components.push({
|
|
150
|
+
type: "HEADER",
|
|
151
|
+
parameters: [
|
|
152
|
+
{
|
|
153
|
+
type: t,
|
|
154
|
+
[t]: {
|
|
155
|
+
id: message.body.header.smartchatMediaId,
|
|
156
|
+
},
|
|
157
|
+
} as WhatsappHeaderParam,
|
|
158
|
+
],
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Build body component (always present if it has parameters)
|
|
163
|
+
if (message.body.body.content) {
|
|
164
|
+
const bodyText = contentToString(message.body.body.content);
|
|
165
|
+
const bodyParams = buildComponentParameters(bodyText, normalizedParams);
|
|
166
|
+
|
|
167
|
+
if (bodyParams.length > 0) {
|
|
168
|
+
components.push({
|
|
169
|
+
type: "BODY",
|
|
170
|
+
parameters: bodyParams,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Note: Footer doesn't support parameters in Meta API
|
|
176
|
+
|
|
177
|
+
// Build button components for URL buttons with parameters
|
|
178
|
+
if (message.body.buttons.enabled) {
|
|
179
|
+
message.body.buttons.buttons.forEach((button, index) => {
|
|
180
|
+
if (button.type === "link" && button.url) {
|
|
181
|
+
const urlParams = buildComponentParameters(
|
|
182
|
+
button.url,
|
|
183
|
+
normalizedParams,
|
|
184
|
+
);
|
|
185
|
+
urlParams.forEach((param) => {
|
|
186
|
+
param.parameter_name = `{{${index + 1}}}`;
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
if (urlParams.length > 0) {
|
|
190
|
+
components.push({
|
|
191
|
+
type: "BUTTON",
|
|
192
|
+
sub_type: "url",
|
|
193
|
+
index: String(index),
|
|
194
|
+
parameters: urlParams,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
messaging_product: "whatsapp",
|
|
203
|
+
type: "template",
|
|
204
|
+
template: {
|
|
205
|
+
name: templateName,
|
|
206
|
+
language: {
|
|
207
|
+
code: message.language_id,
|
|
208
|
+
},
|
|
209
|
+
components: components.length > 0 ? components : undefined,
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
}
|