@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,655 @@
1
+ import type { JSONContent } from "@tiptap/core";
2
+ import {
3
+ DEFAULT_SPACER_SETTINGS,
4
+ DEFAULT_DIVIDER_SETTINGS,
5
+ DEFAULT_HEADING_SETTINGS,
6
+ DEFAULT_PARAGRAPH_SETTINGS,
7
+ DEFAULT_BUTTON_SETTINGS,
8
+ DEFAULT_GRID_SETTINGS,
9
+ DEFAULT_DISCOUNT_SETTINGS,
10
+ DEFAULT_HEADER_SETTINGS,
11
+ DEFAULT_FOOTER_SETTINGS,
12
+ DEFAULT_UNSUBSCRIBE_LINK_SETTINGS,
13
+ DEFAULT_TOP_PRODUCTS_SETTINGS,
14
+ } from "./emailblocks.v1.defaults.js";
15
+ import { BrandDefaultButtonSettings } from "./brand.js";
16
+
17
+ // ============================================================================
18
+ // EMAIL BLOCK TYPES
19
+ // ============================================================================
20
+
21
+ export const EMAIL_BLOCK_TYPES = [
22
+ "spacer",
23
+ "divider",
24
+ "heading",
25
+ "paragraph",
26
+ "image",
27
+ "button",
28
+ "grid",
29
+ "raw_html",
30
+ "discount",
31
+ "header",
32
+ "footer",
33
+ "unsubscribe_link",
34
+ "socials",
35
+ "top_products",
36
+ ] as const;
37
+
38
+ export const TRANSLATABLE_BLOCK_TYPES = [
39
+ "heading",
40
+ "paragraph",
41
+ "button",
42
+ "discount",
43
+ "footer",
44
+ "raw_html",
45
+ "unsubscribe_link",
46
+ ] as const;
47
+
48
+ export type EmailBlockType = EmailBlock["type"];
49
+ export type TranslatableBlockType = TranslatableBlock["type"];
50
+
51
+ // ============================================================================
52
+ // VALIDATION CONSTANTS
53
+ // ============================================================================
54
+
55
+ // Spacer
56
+ export const SPACER_MIN_HEIGHT = 8;
57
+ export const SPACER_MAX_HEIGHT = 200;
58
+ export const SPACER_SIZE_PRESETS = {
59
+ small: 24,
60
+ medium: 40,
61
+ large: 64,
62
+ extra_large: 96,
63
+ } as const;
64
+
65
+ // Divider
66
+ export const DIVIDER_MIN_THICKNESS = 1;
67
+ export const DIVIDER_MAX_THICKNESS = 20;
68
+ export const DIVIDER_MIN_WIDTH = 10;
69
+ export const DIVIDER_MAX_WIDTH = 100;
70
+
71
+ // Text blocks
72
+ export const FONT_SIZE_MIN = 10;
73
+ export const FONT_SIZE_MAX = 48;
74
+ export const EMAIL_SAFE_FONTS = [
75
+ "Arial",
76
+ "Helvetica",
77
+ "Georgia",
78
+ "Times New Roman",
79
+ "Trebuchet MS",
80
+ "Verdana",
81
+ "Courier New",
82
+ ] as const;
83
+ export type SafeFonts = (typeof EMAIL_SAFE_FONTS)[number];
84
+
85
+ export const EMAIL_SAFE_FONT_ITEMS = EMAIL_SAFE_FONTS.map((font) => ({
86
+ value: font,
87
+ label: font,
88
+ }));
89
+
90
+ // Heading
91
+ export const HEADING_TAGS = ["h1", "h2", "h3", "h4", "h5", "h6"] as const;
92
+ export const TEXT_TAGS = ["p", ...HEADING_TAGS] as const;
93
+
94
+ export const TAGS_DEFAULT_FONT_SIZE: Record<
95
+ (typeof TEXT_TAGS)[number],
96
+ number
97
+ > = {
98
+ h1: 28,
99
+ h2: 24,
100
+ h3: 20,
101
+ h4: 18,
102
+ h5: 16,
103
+ h6: 14,
104
+ p: 16,
105
+ };
106
+
107
+ // HTML
108
+ export const HTML_MAX_LENGTH = 50000;
109
+
110
+ // Image
111
+ export const IMAGE_MIN_WIDTH = 50;
112
+ export const IMAGE_MAX_WIDTH = 600;
113
+
114
+ // Content width
115
+ export const CONTENT_WIDTH_MIN = 400;
116
+ export const CONTENT_WIDTH_MAX = 800;
117
+
118
+ // ============================================================================
119
+ // BASE BLOCK
120
+ // ============================================================================
121
+
122
+ export interface EmailBlockBase {
123
+ id: string; // crypto.randomUUID()
124
+ type: EmailBlockType;
125
+ }
126
+
127
+ // ============================================================================
128
+ // INDIVIDUAL BLOCK TYPES
129
+ // ============================================================================
130
+
131
+ export interface SpacerBlock extends EmailBlockBase {
132
+ type: "spacer";
133
+ settings: {
134
+ customSize: boolean;
135
+ height: number; // 8-200px
136
+ backgroundColor: string; // CSS color or 'transparent'
137
+ };
138
+ }
139
+
140
+ export interface DividerBlock extends EmailBlockBase {
141
+ type: "divider";
142
+ settings: {
143
+ style: "solid" | "dashed" | "dotted";
144
+ thickness: number; // 1-10px
145
+ width: number; // 10-100%
146
+ color: string;
147
+ backgroundColor: string;
148
+ };
149
+ }
150
+
151
+ export interface HeadingBlock extends EmailBlockBase {
152
+ type: "heading";
153
+ settings: {
154
+ tag: (typeof HEADING_TAGS)[number];
155
+ content: JSONContent | undefined; // TipTap format
156
+ fontFamily?: string; // undefined = use global default
157
+ fontSize: number; // 16-48px
158
+ textColor?: string; // undefined = use global default
159
+ backgroundColor: string;
160
+ };
161
+ }
162
+
163
+ export interface ParagraphBlock extends EmailBlockBase {
164
+ type: "paragraph";
165
+ settings: {
166
+ tag: (typeof TEXT_TAGS)[number];
167
+ content: JSONContent | undefined; // TipTap rich text
168
+ fontFamily?: string; // undefined = use global default
169
+ fontSize: number; // 10-32px
170
+ textColor?: string; // undefined = use global default
171
+ backgroundColor: string;
172
+ };
173
+ }
174
+
175
+ export interface ImageBlock extends EmailBlockBase {
176
+ type: "image";
177
+ settings: {
178
+ src: string; // Image source URL
179
+ href?: string; // Optional link URL
180
+ };
181
+ }
182
+
183
+ export interface ButtonBlock extends EmailBlockBase {
184
+ type: "button";
185
+ settings: {
186
+ content: JSONContent | undefined; // Button text with formatting
187
+ linkType: "web" | "email" | "phone";
188
+ url: string;
189
+ fontFamily?: string; // undefined = use global default
190
+ fontSize: number; // 12-32px
191
+ shape: "square" | "rounded" | "pill";
192
+ width: "fit_to_text" | "full_width";
193
+ alignment: "left" | "center" | "right";
194
+ textColor?: string; // undefined = use global default
195
+ backgroundColor?: string; //undefined = use global default
196
+ backgroundBlock: string;
197
+ };
198
+ }
199
+
200
+ // Grid types
201
+ export interface GridColumn {
202
+ id: string; // UUID
203
+ blocks: GridAllowedBlock[];
204
+ }
205
+
206
+ export interface GridBlock extends EmailBlockBase {
207
+ type: "grid";
208
+ settings: {
209
+ columns: number; // 1, 2, or 3
210
+ backgroundColor: string;
211
+ columnData: GridColumn[];
212
+ };
213
+ }
214
+
215
+ // Blocks allowed inside grid columns (NO grid-in-grid, no header/footer/html/drif)
216
+ export type GridAllowedBlock =
217
+ | DiscountBlock
218
+ | HeadingBlock
219
+ | ParagraphBlock
220
+ | ImageBlock
221
+ | ButtonBlock;
222
+
223
+ export interface RawHtmlBlock extends EmailBlockBase {
224
+ type: "raw_html";
225
+ settings: {
226
+ html: string; // Max 50,000 chars
227
+ };
228
+ }
229
+
230
+ export interface DiscountBlock extends EmailBlockBase {
231
+ type: "discount";
232
+ settings: {
233
+ content: JSONContent | undefined; // Discount code text with formatting
234
+ tag: (typeof TEXT_TAGS)[number];
235
+ fontFamily?: string; // undefined = use global default
236
+ fontSize: number; // 12-48px
237
+ style: "square" | "rounded" | "pill";
238
+ width: "fit_to_text" | "full_width";
239
+ textColor?: string; // undefined = use global default
240
+ backgroundComponent: string; // Code box background
241
+ backgroundBlock: string; // Overall block background
242
+ };
243
+ }
244
+
245
+ export interface HeaderBlock extends EmailBlockBase {
246
+ type: "header";
247
+ settings: {
248
+ src: string;
249
+ alt: string;
250
+ width: number; // 100-300px
251
+ alignment: "left" | "center" | "right";
252
+ backgroundColor: string;
253
+ };
254
+ }
255
+
256
+ export interface FooterBlock extends EmailBlockBase {
257
+ type: "footer";
258
+ settings: {
259
+ content: JSONContent | undefined; // Rich text
260
+ fontSize: number; // 10-16px
261
+ fontFamily?: string; // undefined = use global default
262
+ textColor?: string; // undefined = use global default
263
+ backgroundColor: string;
264
+ alignment: "left" | "center" | "right";
265
+ };
266
+ }
267
+
268
+ export interface UnsubscribeLinkBlock extends EmailBlockBase {
269
+ type: "unsubscribe_link";
270
+ settings: {
271
+ content: JSONContent | undefined; // Must contain {{unsubscribe}}
272
+ fontFamily?: string;
273
+ fontSize: number; // default 12px
274
+ textColor?: string; // default lower contrast
275
+ backgroundColor: string;
276
+ alignment: "left" | "center" | "right";
277
+ };
278
+ }
279
+
280
+ export type SocialPlatform =
281
+ | "facebook"
282
+ | "instagram"
283
+ | "tripadvisor"
284
+ | "tiktok"
285
+ | "google";
286
+
287
+ export interface SocialLink {
288
+ enabled: boolean;
289
+ url: string;
290
+ }
291
+
292
+ export const SOCIAL_ICONS: Record<SocialPlatform, string> = {
293
+ facebook:
294
+ "http://cdn.mcauto-images-production.sendgrid.net/7f5145b378e26280/8246b205-8497-4fdc-b834-a66a6fccf009/24x24.png",
295
+ instagram:
296
+ "http://cdn.mcauto-images-production.sendgrid.net/7f5145b378e26280/0d446d50-f646-428c-83f2-73ca2b6c4c3e/24x24.png",
297
+ tripadvisor:
298
+ "http://cdn.mcauto-images-production.sendgrid.net/7f5145b378e26280/6fc003ce-242d-46a9-923e-76e7f078727e/24x24.png",
299
+ tiktok:
300
+ "http://cdn.mcauto-images-production.sendgrid.net/7f5145b378e26280/a56f5bf7-0f22-4a06-b41a-d552684e731b/24x24.png",
301
+ google:
302
+ "http://cdn.mcauto-images-production.sendgrid.net/7f5145b378e26280/2dd79979-88ea-4074-9a4e-e646ddaed114/24x24.png",
303
+ };
304
+
305
+ export const SOCIAL_PLATFORMS = Object.keys(SOCIAL_ICONS) as SocialPlatform[];
306
+
307
+ export interface SocialsBlock extends EmailBlockBase {
308
+ type: "socials";
309
+ settings: {
310
+ backgroundColor: string;
311
+ socials: Record<SocialPlatform, SocialLink>;
312
+ };
313
+ }
314
+
315
+ export interface TopProductsProduct {
316
+ name: string;
317
+ image: string;
318
+ link: string;
319
+ price: string;
320
+ }
321
+
322
+ export interface TopProductsBlock extends EmailBlockBase {
323
+ type: "top_products";
324
+ settings: {
325
+ storeId: string; // Smartconnect store identifier for the upselling API
326
+ maxProducts: number; // Max products to display (default 4)
327
+ backgroundColor: string; // Wrapper background color
328
+ };
329
+ /** Populated at compile time by the backend enrichment step */
330
+ _products?: TopProductsProduct[];
331
+ }
332
+
333
+ // ============================================================================
334
+ // UNION TYPE
335
+ // ============================================================================
336
+
337
+ export type EmailBlock =
338
+ | SpacerBlock
339
+ | DividerBlock
340
+ | HeadingBlock
341
+ | ParagraphBlock
342
+ | ImageBlock
343
+ | ButtonBlock
344
+ | GridBlock
345
+ | RawHtmlBlock
346
+ | DiscountBlock
347
+ | HeaderBlock
348
+ | FooterBlock
349
+ | UnsubscribeLinkBlock
350
+ | SocialsBlock
351
+ | TopProductsBlock;
352
+
353
+ export type TranslatableBlock =
354
+ | HeadingBlock
355
+ | ParagraphBlock
356
+ | ButtonBlock
357
+ | DiscountBlock
358
+ | FooterBlock
359
+ | UnsubscribeLinkBlock;
360
+
361
+ // ============================================================================
362
+ // GLOBAL EMAIL SETTINGS
363
+ // ============================================================================
364
+
365
+ export interface EmailGlobalSettings {
366
+ backgroundColor?: string; // Default #F3F4F6 (page/canvas background)
367
+ contentBackgroundColor?: string; // Default #FFFFFF (content area/body background)
368
+ contentWidth?: number; // Default 600px (400-800)
369
+ fontFamily?: SafeFonts; // Default Arial
370
+ textColor?: string; // Default #1F2937
371
+ verticalSpacing?: number; // Default 0px (0-50), gap between blocks
372
+ horizontalSpacing?: number; // Default 0px (0-50), left/right content inset
373
+ button?: BrandDefaultButtonSettings;
374
+ }
375
+
376
+ export const DEFAULT_EMAIL_GLOBAL_SETTINGS: Required<EmailGlobalSettings> = {
377
+ backgroundColor: "#F3F4F6",
378
+ contentBackgroundColor: "#FFFFFF",
379
+ contentWidth: 600,
380
+ fontFamily: "Arial",
381
+ textColor: "#1F2937",
382
+ verticalSpacing: 0,
383
+ horizontalSpacing: 0,
384
+ button: {
385
+ backgroundColor: "#FFFFFF",
386
+ textColor: "#000000",
387
+ },
388
+ };
389
+
390
+ export function emptySpacerBlock(): SpacerBlock {
391
+ return {
392
+ id: crypto.randomUUID(),
393
+ type: "spacer",
394
+ settings: { ...DEFAULT_SPACER_SETTINGS },
395
+ };
396
+ }
397
+
398
+ export function emptyDividerBlock(): DividerBlock {
399
+ return {
400
+ id: crypto.randomUUID(),
401
+ type: "divider",
402
+ settings: { ...DEFAULT_DIVIDER_SETTINGS },
403
+ };
404
+ }
405
+
406
+ export function emptyHeadingBlock(): HeadingBlock {
407
+ return {
408
+ id: crypto.randomUUID(),
409
+ type: "heading",
410
+ settings: { ...DEFAULT_HEADING_SETTINGS, content: undefined },
411
+ };
412
+ }
413
+
414
+ export function emptyParagraphBlock(): ParagraphBlock {
415
+ return {
416
+ id: crypto.randomUUID(),
417
+ type: "paragraph",
418
+ settings: { ...DEFAULT_PARAGRAPH_SETTINGS, content: undefined },
419
+ };
420
+ }
421
+
422
+ export function emptyImageBlock(): ImageBlock {
423
+ return {
424
+ id: crypto.randomUUID(),
425
+ type: "image",
426
+ settings: { src: "", href: undefined },
427
+ };
428
+ }
429
+
430
+ export function emptyButtonBlock(): ButtonBlock {
431
+ return {
432
+ id: crypto.randomUUID(),
433
+ type: "button",
434
+ settings: { ...DEFAULT_BUTTON_SETTINGS, content: undefined },
435
+ };
436
+ }
437
+
438
+ export function emptyGridBlock(): GridBlock {
439
+ return {
440
+ id: crypto.randomUUID(),
441
+ type: "grid",
442
+ settings: { ...DEFAULT_GRID_SETTINGS, columnData: [] },
443
+ };
444
+ }
445
+
446
+ export function emptyRawHtmlBlock(): RawHtmlBlock {
447
+ return {
448
+ id: crypto.randomUUID(),
449
+ type: "raw_html",
450
+ settings: { html: "" },
451
+ };
452
+ }
453
+
454
+ export function emptyDiscountBlock(): DiscountBlock {
455
+ return {
456
+ id: crypto.randomUUID(),
457
+ type: "discount",
458
+ settings: { ...DEFAULT_DISCOUNT_SETTINGS, content: undefined },
459
+ };
460
+ }
461
+
462
+ export function emptyHeaderBlock(): HeaderBlock {
463
+ return {
464
+ id: crypto.randomUUID(),
465
+ type: "header",
466
+ settings: { ...DEFAULT_HEADER_SETTINGS },
467
+ };
468
+ }
469
+
470
+ export function emptyFooterBlock(): FooterBlock {
471
+ return {
472
+ id: crypto.randomUUID(),
473
+ type: "footer",
474
+ settings: {
475
+ ...DEFAULT_FOOTER_SETTINGS,
476
+ content: {
477
+ type: "doc",
478
+ content: [
479
+ {
480
+ type: "paragraph",
481
+ attrs: { textAlign: null },
482
+ content: [
483
+ {
484
+ type: "text",
485
+ marks: [{ type: "bold" }],
486
+ text: "{{property_name}}",
487
+ },
488
+ ],
489
+ },
490
+ {
491
+ type: "paragraph",
492
+ attrs: { textAlign: null },
493
+ content: [{ type: "text", text: "{{property_address}}" }],
494
+ },
495
+ {
496
+ type: "paragraph",
497
+ attrs: { textAlign: null },
498
+ content: [
499
+ {
500
+ type: "text",
501
+ text: "{{property_telephone}} / {{property_email}} / {{property_website}}",
502
+ },
503
+ ],
504
+ },
505
+ ],
506
+ },
507
+ },
508
+ };
509
+ }
510
+
511
+ const UNSUBSCRIBE_LINK_CONTENT: Record<
512
+ string,
513
+ { prefix: string; linkText: string; suffix: string }
514
+ > = {
515
+ en: {
516
+ prefix:
517
+ "If you don't want to receive this type of emails anymore, you can unsubscribe ",
518
+ linkText: "here",
519
+ suffix: ".",
520
+ },
521
+ it: {
522
+ prefix:
523
+ "Se non desideri più ricevere questo tipo di email, puoi annullare l'iscrizione ",
524
+ linkText: "qui",
525
+ suffix: ".",
526
+ },
527
+ de: {
528
+ prefix:
529
+ "Wenn Sie diese Art von E-Mails nicht mehr erhalten möchten, können Sie sich ",
530
+ linkText: "hier",
531
+ suffix: " abmelden.",
532
+ },
533
+ fr: {
534
+ prefix:
535
+ "Si vous ne souhaitez plus recevoir ce type d'e-mails, vous pouvez vous désabonner ",
536
+ linkText: "ici",
537
+ suffix: ".",
538
+ },
539
+ es: {
540
+ prefix:
541
+ "Si no deseas recibir más este tipo de correos, puedes darte de baja ",
542
+ linkText: "aquí",
543
+ suffix: ".",
544
+ },
545
+ };
546
+
547
+ export function emptyUnsubscribeLinkBlock(
548
+ language?: string,
549
+ ): UnsubscribeLinkBlock {
550
+ const { prefix, linkText, suffix } = (UNSUBSCRIBE_LINK_CONTENT[
551
+ language ?? "en"
552
+ ] ?? UNSUBSCRIBE_LINK_CONTENT.en)!;
553
+
554
+ return {
555
+ id: crypto.randomUUID(),
556
+ type: "unsubscribe_link",
557
+ settings: {
558
+ ...DEFAULT_UNSUBSCRIBE_LINK_SETTINGS,
559
+ content: {
560
+ type: "doc",
561
+ content: [
562
+ {
563
+ type: "paragraph",
564
+ attrs: { textAlign: null },
565
+ content: [
566
+ {
567
+ type: "text",
568
+ text: prefix,
569
+ },
570
+ {
571
+ type: "text",
572
+ marks: [
573
+ {
574
+ type: "link",
575
+ attrs: {
576
+ href: "{{unsubscribe}}",
577
+ target: "_blank",
578
+ rel: "noopener noreferrer nofollow",
579
+ class: "underline",
580
+ },
581
+ },
582
+ ],
583
+ text: linkText,
584
+ },
585
+ { type: "text", text: suffix },
586
+ ],
587
+ },
588
+ ],
589
+ },
590
+ },
591
+ };
592
+ }
593
+
594
+ export function emptyTopProductsBlock(): TopProductsBlock {
595
+ return {
596
+ id: crypto.randomUUID(),
597
+ type: "top_products",
598
+ settings: { ...DEFAULT_TOP_PRODUCTS_SETTINGS },
599
+ };
600
+ }
601
+
602
+ export function emptySocialsBlock(): SocialsBlock {
603
+ return {
604
+ id: crypto.randomUUID(),
605
+ type: "socials",
606
+ settings: {
607
+ backgroundColor: "transparent",
608
+ socials: {
609
+ facebook: { enabled: false, url: "" },
610
+ instagram: { enabled: false, url: "" },
611
+ tripadvisor: { enabled: false, url: "" },
612
+ tiktok: { enabled: false, url: "" },
613
+ google: { enabled: false, url: "" },
614
+ },
615
+ },
616
+ };
617
+ }
618
+
619
+ export function emptyEmailBlock(
620
+ type: EmailBlockType,
621
+ language?: string,
622
+ ): EmailBlock {
623
+ switch (type) {
624
+ case "spacer":
625
+ return emptySpacerBlock();
626
+ case "divider":
627
+ return emptyDividerBlock();
628
+ case "heading":
629
+ return emptyHeadingBlock();
630
+ case "paragraph":
631
+ return emptyParagraphBlock();
632
+ case "image":
633
+ return emptyImageBlock();
634
+ case "button":
635
+ return emptyButtonBlock();
636
+ case "grid":
637
+ return emptyGridBlock();
638
+ case "raw_html":
639
+ return emptyRawHtmlBlock();
640
+ case "discount":
641
+ return emptyDiscountBlock();
642
+ case "header":
643
+ return emptyHeaderBlock();
644
+ case "footer":
645
+ return emptyFooterBlock();
646
+ case "unsubscribe_link":
647
+ return emptyUnsubscribeLinkBlock(language);
648
+ case "socials":
649
+ return emptySocialsBlock();
650
+ case "top_products":
651
+ return emptyTopProductsBlock();
652
+ default:
653
+ throw new Error(`Unknown block type: ${type}`);
654
+ }
655
+ }
@@ -0,0 +1,15 @@
1
+ export * from "./app.js";
2
+ export * from "./utils.js";
3
+ export * from "./language.js";
4
+ export * from "./message.js";
5
+ export * from "./api/index.js";
6
+ export * from "./whatsappblocks.v1.js";
7
+ export * from "./emailblocks.v1.js";
8
+ export * from "./emailblocks.v1.defaults.js";
9
+ export * from "./media.js";
10
+ export * from "./meta-webhook.js";
11
+ export * from "./meta-template.js";
12
+ export * from "./submission-job.js";
13
+ export * from "./kafka-events.js";
14
+ export * from "./dynamic-values.js";
15
+ export * from "./brand.js";
@@ -0,0 +1,46 @@
1
+ import type { MessageStatus, MessageGroupCategory } from "./message.js";
2
+
3
+ export interface KafkaEventBase {
4
+ event_id: string;
5
+ event_type: string;
6
+ timestamp: string;
7
+ message_group_id: string;
8
+ owner?: string;
9
+ user_id: string;
10
+ }
11
+
12
+ export interface MessageGroupDeletedEvent extends KafkaEventBase {
13
+ event_type: "MESSAGE_GROUP_DELETED";
14
+ message_group_name: string;
15
+ }
16
+
17
+ export interface MessageStatusChangedEvent extends KafkaEventBase {
18
+ event_type: "MESSAGE_STATUS_CHANGED";
19
+ message_id: string;
20
+ language_id: string;
21
+ previous_status: MessageStatus;
22
+ new_status: MessageStatus;
23
+ was_approved: boolean;
24
+ source: "api" | "meta_webhook";
25
+ aggregated_status: Record<MessageStatus, number>;
26
+ }
27
+
28
+ export interface MessageGroupLanguageLostEvent extends KafkaEventBase {
29
+ event_type: "MESSAGE_GROUP_LANGUAGE_LOST";
30
+ language_id: string;
31
+ }
32
+
33
+ export interface MessageGroupCategoryChangedEvent extends KafkaEventBase {
34
+ event_type: "MESSAGE_GROUP_CATEGORY_CHANGED";
35
+ previous_category: MessageGroupCategory;
36
+ new_category: MessageGroupCategory;
37
+ source: "meta_webhook";
38
+ }
39
+
40
+ export type SmartnessKafkaEvent =
41
+ | MessageGroupDeletedEvent
42
+ | MessageStatusChangedEvent
43
+ | MessageGroupLanguageLostEvent
44
+ | MessageGroupCategoryChangedEvent;
45
+
46
+ export type SmartnessKafkaEventType = SmartnessKafkaEvent["event_type"];