@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.
Files changed (119) hide show
  1. package/dist/types/api/aiIntegration.js +7 -0
  2. package/dist/types/api/aiIntegration.js.map +1 -0
  3. package/dist/types/api/apiMessages.js +2 -0
  4. package/dist/types/api/apiMessages.js.map +1 -0
  5. package/dist/types/api/index.js +3 -0
  6. package/dist/types/api/index.js.map +1 -0
  7. package/dist/types/app.js +23 -0
  8. package/dist/types/app.js.map +1 -0
  9. package/dist/types/brand.js +31 -0
  10. package/dist/types/brand.js.map +1 -0
  11. package/dist/types/dynamic-values.js +5 -0
  12. package/dist/types/dynamic-values.js.map +1 -0
  13. package/dist/types/emailblocks.v1.defaults.js +83 -0
  14. package/dist/types/emailblocks.v1.defaults.js.map +1 -0
  15. package/dist/types/emailblocks.v1.js +339 -0
  16. package/dist/types/emailblocks.v1.js.map +1 -0
  17. package/dist/types/index.js +16 -0
  18. package/dist/types/index.js.map +1 -0
  19. package/dist/types/kafka-events.js +2 -0
  20. package/dist/types/kafka-events.js.map +1 -0
  21. package/dist/types/language.js +2 -0
  22. package/dist/types/language.js.map +1 -0
  23. package/dist/types/media.js +6 -0
  24. package/dist/types/media.js.map +1 -0
  25. package/dist/types/message.js +41 -0
  26. package/dist/types/message.js.map +1 -0
  27. package/dist/types/meta-template.js +2 -0
  28. package/dist/types/meta-template.js.map +1 -0
  29. package/dist/types/meta-webhook.js +2 -0
  30. package/dist/types/meta-webhook.js.map +1 -0
  31. package/dist/types/submission-job.js +2 -0
  32. package/dist/types/submission-job.js.map +1 -0
  33. package/dist/types/tag.js +2 -0
  34. package/dist/types/tag.js.map +1 -0
  35. package/dist/types/utils.js +2 -0
  36. package/dist/types/utils.js.map +1 -0
  37. package/dist/types/whatsappblocks.v1.js +24 -0
  38. package/dist/types/whatsappblocks.v1.js.map +1 -0
  39. package/dist/utils/array.js +26 -0
  40. package/dist/utils/array.js.map +1 -0
  41. package/dist/utils/async.js +22 -0
  42. package/dist/utils/async.js.map +1 -0
  43. package/dist/utils/date.js +37 -0
  44. package/dist/utils/date.js.map +1 -0
  45. package/dist/utils/index.js +34 -0
  46. package/dist/utils/index.js.map +1 -0
  47. package/dist/utils/intl.js +37 -0
  48. package/dist/utils/intl.js.map +1 -0
  49. package/dist/utils/meta-status.js +21 -0
  50. package/dist/utils/meta-status.js.map +1 -0
  51. package/dist/utils/number.js +24 -0
  52. package/dist/utils/number.js.map +1 -0
  53. package/dist/utils/object.js +87 -0
  54. package/dist/utils/object.js.map +1 -0
  55. package/dist/utils/string.js +22 -0
  56. package/dist/utils/string.js.map +1 -0
  57. package/dist/utils/templates/brand-cascade.js +116 -0
  58. package/dist/utils/templates/brand-cascade.js.map +1 -0
  59. package/dist/utils/templates/email-compiler.js +126 -0
  60. package/dist/utils/templates/email-compiler.js.map +1 -0
  61. package/dist/utils/templates/email-mjml.js +444 -0
  62. package/dist/utils/templates/email-mjml.js.map +1 -0
  63. package/dist/utils/templates/email.js +580 -0
  64. package/dist/utils/templates/email.js.map +1 -0
  65. package/dist/utils/templates/html-sanitizer.js +95 -0
  66. package/dist/utils/templates/html-sanitizer.js.map +1 -0
  67. package/dist/utils/templates/messages.js +33 -0
  68. package/dist/utils/templates/messages.js.map +1 -0
  69. package/dist/utils/templates/meta.js +246 -0
  70. package/dist/utils/templates/meta.js.map +1 -0
  71. package/dist/utils/templates/tiptap.js +167 -0
  72. package/dist/utils/templates/tiptap.js.map +1 -0
  73. package/dist/utils/templates/whatsapp-compiler.js +168 -0
  74. package/dist/utils/templates/whatsapp-compiler.js.map +1 -0
  75. package/dist/utils/templates/whatsapp.js +329 -0
  76. package/dist/utils/templates/whatsapp.js.map +1 -0
  77. package/dist/utils/validations.js +39 -0
  78. package/dist/utils/validations.js.map +1 -0
  79. package/package.json +43 -0
  80. package/src/types/api/aiIntegration.ts +59 -0
  81. package/src/types/api/apiMessages.ts +22 -0
  82. package/src/types/api/index.ts +2 -0
  83. package/src/types/app.ts +76 -0
  84. package/src/types/brand.ts +80 -0
  85. package/src/types/dynamic-values.ts +47 -0
  86. package/src/types/emailblocks.v1.defaults.ts +123 -0
  87. package/src/types/emailblocks.v1.ts +655 -0
  88. package/src/types/index.ts +15 -0
  89. package/src/types/kafka-events.ts +46 -0
  90. package/src/types/language.ts +9 -0
  91. package/src/types/media.ts +26 -0
  92. package/src/types/message.ts +635 -0
  93. package/src/types/meta-template.ts +50 -0
  94. package/src/types/meta-webhook.ts +32 -0
  95. package/src/types/submission-job.ts +30 -0
  96. package/src/types/tag.ts +8 -0
  97. package/src/types/utils.ts +14 -0
  98. package/src/types/whatsappblocks.v1.ts +102 -0
  99. package/src/utils/array.ts +33 -0
  100. package/src/utils/async.ts +30 -0
  101. package/src/utils/date.ts +39 -0
  102. package/src/utils/index.ts +44 -0
  103. package/src/utils/intl.ts +51 -0
  104. package/src/utils/meta-status.ts +24 -0
  105. package/src/utils/number.ts +36 -0
  106. package/src/utils/object.ts +101 -0
  107. package/src/utils/string.ts +24 -0
  108. package/src/utils/templates/brand-cascade.ts +156 -0
  109. package/src/utils/templates/email-compiler.ts +155 -0
  110. package/src/utils/templates/email-mjml.ts +602 -0
  111. package/src/utils/templates/email.ts +713 -0
  112. package/src/utils/templates/html-sanitizer.ts +121 -0
  113. package/src/utils/templates/messages.ts +44 -0
  114. package/src/utils/templates/meta.ts +336 -0
  115. package/src/utils/templates/tiptap.ts +247 -0
  116. package/src/utils/templates/whatsapp-compiler.ts +212 -0
  117. package/src/utils/templates/whatsapp.ts +408 -0
  118. package/src/utils/validations.ts +49 -0
  119. package/tsconfig.json +10 -0
@@ -0,0 +1,168 @@
1
+ import { convertToWhatsappMarkdown } from "./whatsapp.js";
2
+ /**
3
+ * Normalize parameters to strings for Meta API compatibility
4
+ * Handles null, undefined, numbers, booleans, objects
5
+ */
6
+ export function normalizeParameters(parameters) {
7
+ return Object.fromEntries(Object.entries(parameters).map(([key, value]) => {
8
+ // Coerce to string
9
+ if (value === null || value === undefined)
10
+ return [key, ""];
11
+ if (typeof value === "string")
12
+ return [key, value]; // Allow empty strings
13
+ return [key, String(value)]; // Numbers, booleans, objects
14
+ }));
15
+ }
16
+ /**
17
+ * Extract parameter names from text containing {{param_name}} placeholders
18
+ */
19
+ function extractParameters(text) {
20
+ const paramRegex = /\{\{([^}]+)\}\}/g;
21
+ const matches = [...text.matchAll(paramRegex)];
22
+ return matches.map((match) => match[1].trim());
23
+ }
24
+ /**
25
+ * Convert JSONContent to string for parameter extraction
26
+ */
27
+ function contentToString(content) {
28
+ if (!content)
29
+ return "";
30
+ return convertToWhatsappMarkdown(content);
31
+ }
32
+ /**
33
+ * Extract all required parameters from a WhatsApp message template
34
+ */
35
+ export function extractRequiredParameters(message) {
36
+ const parameters = new Set();
37
+ // Extract from header if it's text
38
+ if (message.body.header.type === "text" && message.body.header.content) {
39
+ const headerText = contentToString(message.body.header.content);
40
+ extractParameters(headerText).forEach((p) => parameters.add(p));
41
+ }
42
+ // Extract from body
43
+ if (message.body.body.content) {
44
+ const bodyText = contentToString(message.body.body.content);
45
+ extractParameters(bodyText).forEach((p) => parameters.add(p));
46
+ }
47
+ // Extract from button URLs
48
+ if (message.body.buttons.enabled) {
49
+ message.body.buttons.buttons.forEach((button) => {
50
+ if (button.type === "link" && button.url) {
51
+ extractParameters(button.url).forEach((p) => parameters.add(p));
52
+ }
53
+ });
54
+ }
55
+ return Array.from(parameters);
56
+ }
57
+ /**
58
+ * Validate that all required parameters are provided
59
+ */
60
+ export function validateParameters(message, parameters) {
61
+ const required = extractRequiredParameters(message);
62
+ const provided = Object.keys(parameters);
63
+ const missing = required.filter((p) => !provided.includes(p));
64
+ return {
65
+ valid: missing.length === 0,
66
+ required,
67
+ missing,
68
+ };
69
+ }
70
+ /**
71
+ * Build component parameters array for Meta API
72
+ */
73
+ function buildComponentParameters(text, parameters) {
74
+ const paramNames = extractParameters(text);
75
+ return paramNames.map((paramName) => ({
76
+ type: "text",
77
+ text: parameters[paramName] ?? "",
78
+ parameter_name: paramName,
79
+ }));
80
+ }
81
+ /**
82
+ * Compile WhatsApp message template into Meta Cloud API send format
83
+ *
84
+ * @param message - The WhatsApp message template to compile
85
+ * @param parameters - Key-value pairs for parameter injection (will be normalized to strings)
86
+ * @returns WhatsApp Cloud API send payload (without 'to' field)
87
+ */
88
+ export function compileWhatsappTemplate(message, parameters) {
89
+ // Normalize parameters to strings first
90
+ const normalizedParams = normalizeParameters(parameters);
91
+ const components = [];
92
+ // Get template name from metadata
93
+ const templateName = message.metadata?.meta?.template_name;
94
+ if (!templateName) {
95
+ throw new Error("Message does not have Meta template name in metadata");
96
+ }
97
+ // Build header component if exists
98
+ if (message.body.header.type === "text" && message.body.header.content) {
99
+ const headerText = contentToString(message.body.header.content);
100
+ const headerParams = buildComponentParameters(headerText, normalizedParams);
101
+ if (headerParams.length > 0) {
102
+ components.push({
103
+ type: "HEADER",
104
+ parameters: headerParams,
105
+ });
106
+ }
107
+ }
108
+ else if ((message.body.header.type === "image" ||
109
+ message.body.header.type === "video" ||
110
+ message.body.header.type === "document") &&
111
+ message.body.header.smartchatMediaId) {
112
+ const t = message.body.header.type;
113
+ components.push({
114
+ type: "HEADER",
115
+ parameters: [
116
+ {
117
+ type: t,
118
+ [t]: {
119
+ id: message.body.header.smartchatMediaId,
120
+ },
121
+ },
122
+ ],
123
+ });
124
+ }
125
+ // Build body component (always present if it has parameters)
126
+ if (message.body.body.content) {
127
+ const bodyText = contentToString(message.body.body.content);
128
+ const bodyParams = buildComponentParameters(bodyText, normalizedParams);
129
+ if (bodyParams.length > 0) {
130
+ components.push({
131
+ type: "BODY",
132
+ parameters: bodyParams,
133
+ });
134
+ }
135
+ }
136
+ // Note: Footer doesn't support parameters in Meta API
137
+ // Build button components for URL buttons with parameters
138
+ if (message.body.buttons.enabled) {
139
+ message.body.buttons.buttons.forEach((button, index) => {
140
+ if (button.type === "link" && button.url) {
141
+ const urlParams = buildComponentParameters(button.url, normalizedParams);
142
+ urlParams.forEach((param) => {
143
+ param.parameter_name = `{{${index + 1}}}`;
144
+ });
145
+ if (urlParams.length > 0) {
146
+ components.push({
147
+ type: "BUTTON",
148
+ sub_type: "url",
149
+ index: String(index),
150
+ parameters: urlParams,
151
+ });
152
+ }
153
+ }
154
+ });
155
+ }
156
+ return {
157
+ messaging_product: "whatsapp",
158
+ type: "template",
159
+ template: {
160
+ name: templateName,
161
+ language: {
162
+ code: message.language_id,
163
+ },
164
+ components: components.length > 0 ? components : undefined,
165
+ },
166
+ };
167
+ }
168
+ //# sourceMappingURL=whatsapp-compiler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whatsapp-compiler.js","sourceRoot":"","sources":["../../../src/utils/templates/whatsapp-compiler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,329 @@
1
+ import { WA_HEADER_TEXT_MAX_LENGTH, WA_BODY_MAX_LENGTH, WA_FOOTER_MAX_LENGTH, WA_BUTTON_TEXT_MAX_LENGTH, } from "../../types/index.js";
2
+ import { generateHTML, generateText } from "@tiptap/core";
3
+ import { shortcodeToEmoji, gitHubEmojis } from "@tiptap/extension-emoji";
4
+ import { getTipTapExtensions } from "./tiptap.js";
5
+ import { isValidPhoneNumber, isValidUrl } from "../validations.js";
6
+ export function getWhatsappEmpty(languageId) {
7
+ return {
8
+ user_id: "",
9
+ status: "draft",
10
+ render_type: "whatsapp_v1",
11
+ body: {
12
+ header: {
13
+ type: "none",
14
+ },
15
+ body: {
16
+ enabled: true,
17
+ content: undefined,
18
+ },
19
+ footer: {
20
+ enabled: false,
21
+ content: "",
22
+ },
23
+ buttons: {
24
+ enabled: false,
25
+ buttons: [],
26
+ },
27
+ },
28
+ metadata: {},
29
+ language_id: languageId,
30
+ message_group_id: "",
31
+ };
32
+ }
33
+ /**
34
+ * Validates WhatsApp message compliance with Meta requirements
35
+ * Checks:
36
+ * - Body content exists and not empty
37
+ * - Header text length (max 60 chars)
38
+ * - Body text length (max 1024 chars)
39
+ * - Footer text length (max 60 chars)
40
+ * - Button text length (max 20 chars per button)
41
+ * - Max 10 buttons total
42
+ * - Max 1 link button
43
+ * - Max 1 phone button
44
+ * - Phone numbers are valid E.164 format
45
+ * - Max 1 unsubscribe button
46
+ * - Max 3 quick_reply buttons
47
+ */
48
+ export function isWhatsappValid(message) {
49
+ const errors = [];
50
+ if (message.render_type !== "whatsapp_v1") {
51
+ return {
52
+ valid: false,
53
+ errors: ["editor.validation.error.invalidRenderType"],
54
+ };
55
+ }
56
+ // Validate header text length (use markdown output to match what Meta receives)
57
+ if (message.body.header.type === "text" &&
58
+ message.body.header.content &&
59
+ !isContentEmpty(message.body.header.content)) {
60
+ const headerText = convertToWhatsappMarkdown(message.body.header.content);
61
+ if (headerText.length > WA_HEADER_TEXT_MAX_LENGTH) {
62
+ errors.push("editor.validation.error.headerTooLong");
63
+ }
64
+ }
65
+ // Validate header media url
66
+ if (["image", "video", "document"].includes(message.body.header.type)) {
67
+ if (!("url" in message.body.header) ||
68
+ !message.body.header.url?.trim()) {
69
+ errors.push("editor.validation.error.headerMediaRequired");
70
+ }
71
+ }
72
+ // Validate body content
73
+ if (!message.body.body.content) {
74
+ errors.push("editor.validation.error.bodyRequired");
75
+ }
76
+ else if (isContentEmpty(message.body.body.content)) {
77
+ errors.push("editor.validation.error.bodyEmpty");
78
+ }
79
+ else {
80
+ // Validate body text length (use markdown output to match what Meta receives)
81
+ const bodyText = convertToWhatsappMarkdown(message.body.body.content);
82
+ if (bodyText.length > WA_BODY_MAX_LENGTH) {
83
+ errors.push("editor.validation.error.bodyTooLong");
84
+ }
85
+ }
86
+ // Validate footer text length
87
+ if (message.body.footer?.enabled && message.body.footer.content) {
88
+ if (message.body.footer.content.length > WA_FOOTER_MAX_LENGTH) {
89
+ errors.push("editor.validation.error.footerTooLong");
90
+ }
91
+ }
92
+ // Validate buttons if enabled
93
+ if (message.body.buttons?.enabled &&
94
+ message.body.buttons.buttons.length > 0) {
95
+ const buttons = message.body.buttons.buttons;
96
+ // Check max total buttons
97
+ if (buttons.length > 10) {
98
+ errors.push("editor.validation.error.maxButtons");
99
+ }
100
+ // Count button types
101
+ const linkButtons = buttons.filter((b) => b.type === "link").length;
102
+ const phoneButtons = buttons.filter((b) => b.type === "phone").length;
103
+ const unsubscribeButtons = buttons.filter((b) => b.type === "unsubscribe").length;
104
+ const quickReplyButtons = buttons.filter((b) => b.type === "quick_reply").length;
105
+ // Validate button type limits
106
+ if (linkButtons > 1) {
107
+ errors.push("editor.validation.error.maxLinkButtons");
108
+ }
109
+ if (phoneButtons > 1) {
110
+ errors.push("editor.validation.error.maxPhoneButtons");
111
+ }
112
+ if (unsubscribeButtons > 1) {
113
+ errors.push("editor.validation.error.maxUnsubscribeButtons");
114
+ }
115
+ if (quickReplyButtons > 3) {
116
+ errors.push("editor.validation.error.maxQuickReplyButtons");
117
+ }
118
+ // Validate button text length, phone numbers, and URLs
119
+ buttons.forEach((button) => {
120
+ // Validate button text
121
+ const buttonText = typeof button.text === "string" ? button.text : "";
122
+ if (!buttonText.trim()) {
123
+ errors.push(`editor.validation.error.buttonTextRequired`);
124
+ }
125
+ else if (buttonText.length > WA_BUTTON_TEXT_MAX_LENGTH) {
126
+ errors.push(`editor.validation.error.buttonTextTooLong`);
127
+ }
128
+ if (button.type === "phone") {
129
+ const phone = button.phoneNumber?.trim();
130
+ if (!phone) {
131
+ errors.push(`editor.validation.error.phoneRequired`);
132
+ }
133
+ else if (!isValidPhoneNumber(phone)) {
134
+ errors.push(`editor.validation.error.phoneInvalid`);
135
+ }
136
+ }
137
+ if (button.type === "link") {
138
+ const url = button.url?.trim();
139
+ if (!url) {
140
+ errors.push(`editor.validation.error.urlRequired`);
141
+ }
142
+ else if (!isValidUrl(url)) {
143
+ errors.push(`editor.validation.error.urlInvalid`);
144
+ }
145
+ }
146
+ });
147
+ }
148
+ return {
149
+ valid: errors.length === 0,
150
+ errors,
151
+ };
152
+ }
153
+ export function isContentEmpty(content) {
154
+ if (content == null) {
155
+ return true;
156
+ }
157
+ if (typeof content === "string") {
158
+ return content === "";
159
+ }
160
+ if (Array.isArray(content)) {
161
+ return content.every((item) => isContentEmpty(item));
162
+ }
163
+ if (!content.content) {
164
+ return true;
165
+ }
166
+ return content.content.every((item) => !item.content);
167
+ }
168
+ export function generateWhatsappTextPreview(message) {
169
+ if (!message?.body.body.content)
170
+ return "";
171
+ return generateWhatsappText(message.body.body.content);
172
+ }
173
+ export function generateWhatsappText(content) {
174
+ if (!content)
175
+ return "";
176
+ return generateText(content, getTipTapExtensions({ preset: "whatsapp" }));
177
+ }
178
+ export function generateWhatsappHtml(content) {
179
+ if (!content)
180
+ return "";
181
+ return generateHTML(content, getTipTapExtensions({ preset: "whatsapp" }));
182
+ }
183
+ /**
184
+ * Converts TipTap JSONContent to WhatsApp markdown format
185
+ * Supports: *bold*, _italic_, ~strikethrough~, ```code```
186
+ */
187
+ export function convertToWhatsappMarkdown(content) {
188
+ if (!content)
189
+ return "";
190
+ function processNode(node) {
191
+ if (typeof node === "string") {
192
+ return node;
193
+ }
194
+ if (Array.isArray(node)) {
195
+ return node.map(processNode).join("");
196
+ }
197
+ if (!node || typeof node !== "object") {
198
+ return "";
199
+ }
200
+ let text = "";
201
+ // Process content recursively
202
+ if (node.content) {
203
+ text = node.content.map(processNode).join("");
204
+ }
205
+ // Handle text nodes with marks
206
+ if (node.type === "text" && node.text) {
207
+ text = node.text;
208
+ // Apply formatting based on marks
209
+ if (node.marks) {
210
+ for (const mark of node.marks) {
211
+ switch (mark.type) {
212
+ case "bold":
213
+ text = `*${text}*`;
214
+ break;
215
+ case "italic":
216
+ text = `_${text}_`;
217
+ break;
218
+ case "strike":
219
+ text = `~${text}~`;
220
+ break;
221
+ case "code":
222
+ text = `\`\`\`${text}\`\`\``;
223
+ break;
224
+ }
225
+ }
226
+ }
227
+ }
228
+ // Handle block-level elements
229
+ switch (node.type) {
230
+ case "paragraph":
231
+ return text + "\n";
232
+ case "mention":
233
+ return `{{${node.attrs?.label}}}`;
234
+ case "emoji": {
235
+ const emojiItem = shortcodeToEmoji(node.attrs?.name, gitHubEmojis);
236
+ return emojiItem?.emoji || `:${node.attrs?.name}:`;
237
+ }
238
+ case "hardBreak":
239
+ return "\n";
240
+ case "doc":
241
+ return text.trim();
242
+ default:
243
+ return text;
244
+ }
245
+ }
246
+ return processNode(content);
247
+ }
248
+ /**
249
+ * Calculates the translation completion percentage for a WhatsApp message
250
+ * Compares against a base message to determine which fields need translation
251
+ * @param message - The message to calculate percentage for
252
+ * @param baseMessage - The base language message to compare structure against
253
+ * @returns A number between 0-100 representing the completion percentage
254
+ */
255
+ export function calculateWhatsappTranslationPercentage(message, baseMessage) {
256
+ if (!message || message.render_type !== "whatsapp_v1")
257
+ return 0;
258
+ if (!baseMessage || baseMessage.render_type !== "whatsapp_v1")
259
+ return 0;
260
+ let totalFields = 0;
261
+ let filledFields = 0;
262
+ // Body content is always required
263
+ totalFields++;
264
+ if (message.body.body.content && !isContentEmpty(message.body.body.content)) {
265
+ filledFields++;
266
+ }
267
+ // Check header if it exists in base message
268
+ if (baseMessage.body.header.type === "text") {
269
+ totalFields++;
270
+ if (message.body.header.type === "text" &&
271
+ message.body.header.content &&
272
+ !isContentEmpty(message.body.header.content)) {
273
+ filledFields++;
274
+ }
275
+ }
276
+ // Check media header if it exists in base message
277
+ if (["image", "video", "document"].includes(baseMessage.body.header.type)) {
278
+ totalFields++;
279
+ if (message.body.header.type === baseMessage.body.header.type &&
280
+ "url" in message.body.header &&
281
+ message.body.header.url?.trim()) {
282
+ filledFields++;
283
+ }
284
+ }
285
+ // Check footer if enabled in base message
286
+ if (baseMessage.body.footer.enabled) {
287
+ totalFields++;
288
+ if (message.body.footer.enabled &&
289
+ message.body.footer.content &&
290
+ message.body.footer.content.trim() !== "") {
291
+ filledFields++;
292
+ }
293
+ }
294
+ // Check buttons if they exist in base message
295
+ if (baseMessage.body.buttons?.buttons &&
296
+ baseMessage.body.buttons.buttons.length > 0) {
297
+ for (let i = 0; i < baseMessage.body.buttons.buttons.length; i++) {
298
+ const baseButton = baseMessage.body.buttons.buttons[i];
299
+ const messageButton = message.body.buttons?.buttons?.[i];
300
+ // Button text
301
+ totalFields++;
302
+ if (messageButton?.text && messageButton.text.trim() !== "") {
303
+ filledFields++;
304
+ }
305
+ // URL for link buttons
306
+ if (baseButton.type === "link") {
307
+ totalFields++;
308
+ if (messageButton?.type === "link" &&
309
+ messageButton.url &&
310
+ messageButton.url.trim() !== "") {
311
+ filledFields++;
312
+ }
313
+ }
314
+ // Phone number for phone buttons
315
+ if (baseButton.type === "phone") {
316
+ totalFields++;
317
+ if (messageButton?.type === "phone" &&
318
+ messageButton.phoneNumber &&
319
+ messageButton.phoneNumber.trim() !== "") {
320
+ filledFields++;
321
+ }
322
+ }
323
+ }
324
+ }
325
+ if (totalFields === 0)
326
+ return 0;
327
+ return Math.round((filledFields / totalFields) * 100);
328
+ }
329
+ //# sourceMappingURL=whatsapp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whatsapp.js","sourceRoot":"","sources":["../../../src/utils/templates/whatsapp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ // Common validation functions
2
+ export const isEmail = (email) => {
3
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
4
+ return emailRegex.test(email);
5
+ };
6
+ export const isRequired = (value) => {
7
+ if (value === null || value === undefined)
8
+ return false;
9
+ if (typeof value === "string")
10
+ return value.trim().length > 0;
11
+ if (Array.isArray(value))
12
+ return value.length > 0;
13
+ return true;
14
+ };
15
+ export const minLength = (value, min) => {
16
+ return value.length >= min;
17
+ };
18
+ export const maxLength = (value, max) => {
19
+ return value.length <= max;
20
+ };
21
+ export const isNumeric = (value) => {
22
+ return !isNaN(Number(value)) && !isNaN(parseFloat(value));
23
+ };
24
+ export const isPositiveNumber = (value) => {
25
+ return value > 0;
26
+ };
27
+ // WhatsApp Button validations
28
+ export const isValidButtonText = (text) => {
29
+ return text.length > 0 && text.length <= 20;
30
+ };
31
+ export const VALID_PHONE_NUMBER_REGEX = /^\+?[1-9]\d{8,14}$/;
32
+ export const isValidPhoneNumber = (phoneNumber) => {
33
+ return VALID_PHONE_NUMBER_REGEX.test(phoneNumber);
34
+ };
35
+ export const VALID_URL_REGEX = /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#={}]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//={}]*)$/;
36
+ export const isValidUrl = (url) => {
37
+ return VALID_URL_REGEX.test(url);
38
+ };
39
+ //# sourceMappingURL=validations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validations.js","sourceRoot":"","sources":["../../src/utils/validations.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,KAAa,EAAW,EAAE;IAChD,MAAM,UAAU,GAAG,4BAA4B,CAAC;IAChD,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAChC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAc,EAAW,EAAE;IACpD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACxD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;IAC9D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IAClD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAAa,EAAE,GAAW,EAAW,EAAE;IAC/D,OAAO,KAAK,CAAC,MAAM,IAAI,GAAG,CAAC;AAC7B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAAa,EAAE,GAAW,EAAW,EAAE;IAC/D,OAAO,KAAK,CAAC,MAAM,IAAI,GAAG,CAAC;AAC7B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAAa,EAAW,EAAE;IAClD,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5D,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAa,EAAW,EAAE;IACzD,OAAO,KAAK,GAAG,CAAC,CAAC;AACnB,CAAC,CAAC;AAOF,8BAA8B;AAC9B,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,IAAY,EAAW,EAAE;IACzD,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;AAC9C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,wBAAwB,GAAG,oBAAoB,CAAC;AAC7D,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,WAAmB,EAAW,EAAE;IACjE,OAAO,wBAAwB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;AACpD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAC1B,+GAA+G,CAAC;AAClH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,GAAW,EAAW,EAAE;IACjD,OAAO,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACnC,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@dev.smartpricing/message-composer-utils",
3
+ "version": "3.1.2",
4
+ "description": "Shared types and utilities for the message composer",
5
+ "type": "module",
6
+ "exports": {
7
+ "./types": {
8
+ "types": "./src/types/index.ts",
9
+ "import": "./dist/types/index.js"
10
+ },
11
+ "./utils": {
12
+ "types": "./src/utils/index.ts",
13
+ "import": "./dist/utils/index.js"
14
+ }
15
+ },
16
+ "keywords": [],
17
+ "author": "",
18
+ "license": "ISC",
19
+ "dependencies": {
20
+ "@tiptap/core": "^3.22.5",
21
+ "@tiptap/extension-emoji": "^3.22.5",
22
+ "@tiptap/extension-mention": "^3.22.5",
23
+ "@tiptap/extension-text-align": "^3.22.5",
24
+ "@tiptap/extensions": "^3.22.5",
25
+ "@tiptap/html": "^3.22.5",
26
+ "@tiptap/starter-kit": "^3.22.5",
27
+ "zod": "^4.2.1"
28
+ },
29
+ "devDependencies": {
30
+ "@tsconfig/node22": "^22.0.5",
31
+ "eslint": "^9.39.2",
32
+ "typescript": "^5.9.3",
33
+ "vitest": "^4.0.16"
34
+ },
35
+ "scripts": {
36
+ "build": "tsc",
37
+ "dev": "tsc --watch",
38
+ "type-check": "tsc --noEmit",
39
+ "test": "vitest",
40
+ "clean": "rm -rf dist node_modules",
41
+ "cleanup": "rm -rf node_modules pnpm-lock.yaml"
42
+ }
43
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Request and response types for AI integration endpoints
3
+ */
4
+
5
+ export const GENERATE_TEXT_PROMPT_MIN_LENGTH = 10;
6
+ export const GENERATE_TEXT_PROMPT_MAX_LENGTH = 500;
7
+ export const GENERATE_TEXT_SUGGESTIONS_COUNT = 3;
8
+
9
+ /**
10
+ * Request body for the /refine-text endpoint
11
+ */
12
+ export interface RefineTextRequest {
13
+ text: string;
14
+ }
15
+
16
+ /**
17
+ * Response body for the /refine-text endpoint
18
+ */
19
+ export interface RefineTextResponse {
20
+ refinedText: string;
21
+ }
22
+
23
+ /**
24
+ * Request body for the /translate endpoint
25
+ */
26
+ export interface TranslateTextRequest {
27
+ text: string;
28
+ sourceLanguage?: string;
29
+ targetLanguages: string[];
30
+ }
31
+
32
+ /**
33
+ * Response body for the /translate endpoint
34
+ */
35
+ export interface TranslationResponse {
36
+ translations: Record<string, string>;
37
+ }
38
+
39
+ /**
40
+ * Widget types that support AI text generation
41
+ */
42
+ export type GenerateTextWidgetType = "heading" | "paragraph" | "whatsapp_body";
43
+
44
+ /**
45
+ * Request body for the /generate-text endpoint
46
+ */
47
+ export interface GenerateTextRequest {
48
+ prompt: string;
49
+ widgetType: GenerateTextWidgetType;
50
+ language: string;
51
+ context?: string;
52
+ }
53
+
54
+ /**
55
+ * Response body for the /generate-text endpoint
56
+ */
57
+ export interface GenerateTextResponse {
58
+ suggestions: string[];
59
+ }