email-editor-core 0.0.4

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 (47) hide show
  1. package/README.md +438 -0
  2. package/dist/index.d.ts +127 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +260 -0
  5. package/dist/renderer/blocks/button.d.ts +18 -0
  6. package/dist/renderer/blocks/button.d.ts.map +1 -0
  7. package/dist/renderer/blocks/button.js +57 -0
  8. package/dist/renderer/blocks/divider.d.ts +18 -0
  9. package/dist/renderer/blocks/divider.d.ts.map +1 -0
  10. package/dist/renderer/blocks/divider.js +42 -0
  11. package/dist/renderer/blocks/highlight.d.ts +18 -0
  12. package/dist/renderer/blocks/highlight.d.ts.map +1 -0
  13. package/dist/renderer/blocks/highlight.js +49 -0
  14. package/dist/renderer/blocks/image.d.ts +18 -0
  15. package/dist/renderer/blocks/image.d.ts.map +1 -0
  16. package/dist/renderer/blocks/image.js +59 -0
  17. package/dist/renderer/blocks/paragraph.d.ts +18 -0
  18. package/dist/renderer/blocks/paragraph.d.ts.map +1 -0
  19. package/dist/renderer/blocks/paragraph.js +41 -0
  20. package/dist/renderer/blocks/title.d.ts +18 -0
  21. package/dist/renderer/blocks/title.d.ts.map +1 -0
  22. package/dist/renderer/blocks/title.js +49 -0
  23. package/dist/renderer/parseInlineFormatting.d.ts +14 -0
  24. package/dist/renderer/parseInlineFormatting.d.ts.map +1 -0
  25. package/dist/renderer/parseInlineFormatting.js +178 -0
  26. package/dist/renderer/renderBlock.d.ts +21 -0
  27. package/dist/renderer/renderBlock.d.ts.map +1 -0
  28. package/dist/renderer/renderBlock.js +44 -0
  29. package/dist/renderer/renderEmail.d.ts +26 -0
  30. package/dist/renderer/renderEmail.d.ts.map +1 -0
  31. package/dist/renderer/renderEmail.js +275 -0
  32. package/dist/sanitizer.d.ts +147 -0
  33. package/dist/sanitizer.d.ts.map +1 -0
  34. package/dist/sanitizer.js +533 -0
  35. package/dist/template-config.d.ts +38 -0
  36. package/dist/template-config.d.ts.map +1 -0
  37. package/dist/template-config.js +196 -0
  38. package/dist/test-formatting.d.ts +6 -0
  39. package/dist/test-formatting.d.ts.map +1 -0
  40. package/dist/test-formatting.js +132 -0
  41. package/dist/types.d.ts +243 -0
  42. package/dist/types.d.ts.map +1 -0
  43. package/dist/types.js +5 -0
  44. package/dist/validator.d.ts +86 -0
  45. package/dist/validator.d.ts.map +1 -0
  46. package/dist/validator.js +435 -0
  47. package/package.json +17 -0
@@ -0,0 +1,38 @@
1
+ /**
2
+ * TEMPLATE-SPECIFIC RULES AND CONFIGURATION
3
+ * Enforces constraints per template type
4
+ */
5
+ import type { TemplateConfiguration, BlockType } from './types.js';
6
+ /**
7
+ * OPEN-FUND TEMPLATE RULES
8
+ * Purpose: Marketing email for new fund launch
9
+ * Structure: Hero image → Title + Paragraphs + CTA → Highlight box
10
+ * Marketing-focused, needs strong CTA
11
+ */
12
+ export declare const OPEN_FUND_CONFIG: TemplateConfiguration;
13
+ /**
14
+ * CLOSE-FUND TEMPLATE RULES
15
+ * Purpose: Notification that fund is closed, transition to next phase
16
+ * Structure: Announcement → Details → Next steps → Highlight
17
+ * More formal, fewer blocks than open-fund
18
+ */
19
+ export declare const CLOSE_FUND_CONFIG: TemplateConfiguration;
20
+ /**
21
+ * NEWSLETTER TEMPLATE RULES
22
+ * Purpose: Information and updates about fund performance
23
+ * Structure: Article → Performance details → CTA → Help
24
+ * Education-focused, longer form content allowed
25
+ */
26
+ export declare const NEWSLETTER_CONFIG: TemplateConfiguration;
27
+ /**
28
+ * Registry of all template configurations
29
+ * Used by validator to look up rules
30
+ */
31
+ export declare const TEMPLATE_CONFIG_REGISTRY: Record<string, TemplateConfiguration>;
32
+ /**
33
+ * Get template configuration by type
34
+ * @throws Error if template type not found
35
+ */
36
+ export declare function getTemplateConfig(templateType: string): TemplateConfiguration;
37
+ export declare const BLOCK_CONSTRAINT_MESSAGES: Record<BlockType, string>;
38
+ //# sourceMappingURL=template-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-config.d.ts","sourceRoot":"","sources":["../src/template-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAMnE;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,qBA4D9B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,qBAgD/B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,qBA+C/B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAI1E,CAAC;AAEF;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,qBAAqB,CAM7E;AAMD,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAO/D,CAAC"}
@@ -0,0 +1,196 @@
1
+ /**
2
+ * TEMPLATE-SPECIFIC RULES AND CONFIGURATION
3
+ * Enforces constraints per template type
4
+ */
5
+ // ============================================================================
6
+ // TEMPLATE RULES
7
+ // ============================================================================
8
+ /**
9
+ * OPEN-FUND TEMPLATE RULES
10
+ * Purpose: Marketing email for new fund launch
11
+ * Structure: Hero image → Title + Paragraphs + CTA → Highlight box
12
+ * Marketing-focused, needs strong CTA
13
+ */
14
+ export const OPEN_FUND_CONFIG = {
15
+ templateType: 'open-fund',
16
+ // Which block types are allowed
17
+ allowedBlockTypes: ['title', 'paragraph', 'image', 'button', 'divider', 'highlight-box'],
18
+ // Per-block constraints
19
+ blockConstraints: {
20
+ title: {
21
+ min: 1,
22
+ max: 2,
23
+ required: true,
24
+ },
25
+ paragraph: {
26
+ min: 2,
27
+ max: 5,
28
+ required: true,
29
+ },
30
+ image: {
31
+ min: 0,
32
+ max: 3,
33
+ required: false,
34
+ },
35
+ button: {
36
+ min: 1,
37
+ max: 2,
38
+ required: true, // Must have CTA
39
+ },
40
+ divider: {
41
+ min: 0,
42
+ max: 2,
43
+ required: false,
44
+ },
45
+ 'highlight-box': {
46
+ min: 0,
47
+ max: 1,
48
+ required: false,
49
+ },
50
+ },
51
+ // Global constraints
52
+ maxTotalBlocks: 15,
53
+ allowReordering: true,
54
+ // Recommended order (but not enforced if allowReordering: true)
55
+ requireBlockOrder: [
56
+ 'title',
57
+ 'paragraph',
58
+ 'image',
59
+ 'paragraph',
60
+ 'button',
61
+ 'highlight-box',
62
+ ],
63
+ // Must always exist
64
+ mandatoryBlocks: ['title', 'paragraph', 'button'],
65
+ // Fixed sections
66
+ helpSectionRequired: true,
67
+ complianceSectionRequired: true,
68
+ };
69
+ /**
70
+ * CLOSE-FUND TEMPLATE RULES
71
+ * Purpose: Notification that fund is closed, transition to next phase
72
+ * Structure: Announcement → Details → Next steps → Highlight
73
+ * More formal, fewer blocks than open-fund
74
+ */
75
+ export const CLOSE_FUND_CONFIG = {
76
+ templateType: 'close-fund',
77
+ allowedBlockTypes: ['title', 'paragraph', 'image', 'button', 'divider', 'highlight-box'],
78
+ blockConstraints: {
79
+ title: {
80
+ min: 0,
81
+ max: 1,
82
+ required: false,
83
+ },
84
+ paragraph: {
85
+ min: 2,
86
+ max: 4,
87
+ required: true,
88
+ },
89
+ image: {
90
+ min: 0,
91
+ max: 2,
92
+ required: false,
93
+ },
94
+ button: {
95
+ min: 0,
96
+ max: 1,
97
+ required: false, // No hard CTA for close
98
+ },
99
+ divider: {
100
+ min: 0,
101
+ max: 1,
102
+ required: false,
103
+ },
104
+ 'highlight-box': {
105
+ min: 0,
106
+ max: 1,
107
+ required: false,
108
+ },
109
+ },
110
+ maxTotalBlocks: 12,
111
+ allowReordering: true,
112
+ // Suggested structure but not required
113
+ requireBlockOrder: ['paragraph', 'divider', 'paragraph', 'highlight-box'],
114
+ mandatoryBlocks: ['paragraph'],
115
+ helpSectionRequired: true,
116
+ complianceSectionRequired: true,
117
+ };
118
+ /**
119
+ * NEWSLETTER TEMPLATE RULES
120
+ * Purpose: Information and updates about fund performance
121
+ * Structure: Article → Performance details → CTA → Help
122
+ * Education-focused, longer form content allowed
123
+ */
124
+ export const NEWSLETTER_CONFIG = {
125
+ templateType: 'newsletter',
126
+ allowedBlockTypes: ['title', 'paragraph', 'image', 'button', 'divider', 'highlight-box'],
127
+ blockConstraints: {
128
+ title: {
129
+ min: 1,
130
+ max: 2,
131
+ required: true,
132
+ },
133
+ paragraph: {
134
+ min: 3,
135
+ max: 8,
136
+ required: true, // Longer articles
137
+ },
138
+ image: {
139
+ min: 1,
140
+ max: 4,
141
+ required: true, // Always include performance charts
142
+ },
143
+ button: {
144
+ min: 0,
145
+ max: 2,
146
+ required: false,
147
+ },
148
+ divider: {
149
+ min: 0,
150
+ max: 3,
151
+ required: false,
152
+ },
153
+ 'highlight-box': {
154
+ min: 0,
155
+ max: 2,
156
+ required: false,
157
+ },
158
+ },
159
+ maxTotalBlocks: 20, // Most flexible
160
+ allowReordering: true,
161
+ requireBlockOrder: ['title', 'image', 'paragraph', 'divider', 'paragraph', 'button'],
162
+ mandatoryBlocks: ['title', 'paragraph', 'image'],
163
+ helpSectionRequired: true,
164
+ complianceSectionRequired: true,
165
+ };
166
+ /**
167
+ * Registry of all template configurations
168
+ * Used by validator to look up rules
169
+ */
170
+ export const TEMPLATE_CONFIG_REGISTRY = {
171
+ 'open-fund': OPEN_FUND_CONFIG,
172
+ 'close-fund': CLOSE_FUND_CONFIG,
173
+ 'newsletter': NEWSLETTER_CONFIG,
174
+ };
175
+ /**
176
+ * Get template configuration by type
177
+ * @throws Error if template type not found
178
+ */
179
+ export function getTemplateConfig(templateType) {
180
+ const config = TEMPLATE_CONFIG_REGISTRY[templateType];
181
+ if (!config) {
182
+ throw new Error(`Unknown template type: ${templateType}`);
183
+ }
184
+ return config;
185
+ }
186
+ // ============================================================================
187
+ // CONSTRAINT DESCRIPTIONS (for error messages)
188
+ // ============================================================================
189
+ export const BLOCK_CONSTRAINT_MESSAGES = {
190
+ title: 'Section heading (appears once or twice)',
191
+ paragraph: 'Text content with optional inline formatting',
192
+ image: 'Responsive image with alt text',
193
+ button: 'Call-to-action button',
194
+ divider: 'Visual separator line',
195
+ 'highlight-box': 'Featured callout box',
196
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Test parseInlineFormatting function
3
+ * Run with: npx ts-node test-formatting.ts
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=test-formatting.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-formatting.d.ts","sourceRoot":"","sources":["../src/test-formatting.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Test parseInlineFormatting function
3
+ * Run with: npx ts-node test-formatting.ts
4
+ */
5
+ import { parseInlineFormatting } from './renderer/parseInlineFormatting.js';
6
+ // Test cases
7
+ const testCases = [
8
+ {
9
+ input: 'NOBI Dana Kripto: Solusi Investasi Kripto yang {{bold:#008867}}#SemudahItu{{/bold}}',
10
+ expected: 'NOBI Dana Kripto: Solusi Investasi Kripto yang <span style="color:#008867;font-weight:700;">#SemudahItu</span>',
11
+ description: 'Basic formatting with accent color',
12
+ },
13
+ {
14
+ input: 'Start {{bold:#FF0000}}red text{{/bold}} middle {{bold:#0000FF}}blue text{{/bold}} end',
15
+ expected: 'Start <span style="color:#FF0000;font-weight:700;">red text</span> middle <span style="color:#0000FF;font-weight:700;">blue text</span> end',
16
+ description: 'Multiple formatting tokens',
17
+ },
18
+ {
19
+ input: 'No formatting here',
20
+ expected: 'No formatting here',
21
+ description: 'No tokens present',
22
+ },
23
+ {
24
+ input: 'Invalid {{bold:NOTACOLOR}}text{{/bold}} should stay as is',
25
+ expected: 'Invalid {{bold:NOTACOLOR}}text{{/bold}} should stay as is',
26
+ description: 'Invalid color format ignored',
27
+ },
28
+ {
29
+ input: 'Valid 3-char hex {{bold:#F0F}}text{{/bold}} works',
30
+ expected: 'Valid 3-char hex <span style="color:#F0F;font-weight:700;">text</span> works',
31
+ description: '3-character hex color supported',
32
+ },
33
+ {
34
+ input: 'Visit {{link:https://example.com}}our website{{/link}} for more',
35
+ expected: 'Visit <a href="https://example.com" style="color:#008867;text-decoration:underline;font-weight:600;" target="_blank" rel="noopener noreferrer">our website</a> for more',
36
+ description: 'Basic link with https',
37
+ },
38
+ {
39
+ input: 'Email us {{link:mailto:hello@example.com}}here{{/link}} anytime',
40
+ expected: 'Email us <a href="mailto:hello@example.com" style="color:#008867;text-decoration:underline;font-weight:600;" target="_blank" rel="noopener noreferrer">here</a> anytime',
41
+ description: 'Email link with mailto',
42
+ },
43
+ {
44
+ input: 'Chat {{link:https://wa.me/1234567890}}on WhatsApp{{/link}} now',
45
+ expected: 'Chat <a href="https://wa.me/1234567890" style="color:#008867;text-decoration:underline;font-weight:600;" target="_blank" rel="noopener noreferrer">on WhatsApp</a> now',
46
+ description: 'WhatsApp link with wa.me',
47
+ },
48
+ {
49
+ input: 'Invalid {{link:javascript:alert(1)}}attack{{/link}} blocked',
50
+ expected: 'Invalid attack blocked',
51
+ description: 'JavaScript URLs rejected',
52
+ },
53
+ {
54
+ input: 'Invalid {{link:data:text/html}}data{{/link}} blocked',
55
+ expected: 'Invalid data blocked',
56
+ description: 'Data URLs rejected',
57
+ },
58
+ {
59
+ input: 'Both {{bold:#008867}}bold{{/bold}} and {{link:https://example.com}}link{{/link}} work',
60
+ expected: 'Both <span style="color:#008867;font-weight:700;">bold</span> and <a href="https://example.com" style="color:#008867;text-decoration:underline;font-weight:600;" target="_blank" rel="noopener noreferrer">link</a> work',
61
+ description: 'Both bold and link tokens in same text',
62
+ },
63
+ {
64
+ input: 'Combined {{bold:#FF0000}}bold{{/bold}} {{link:https://example.com}}link{{/link}} test',
65
+ expected: 'Combined <span style="color:#FF0000;font-weight:700;">bold</span> <a href="https://example.com" style="color:#008867;text-decoration:underline;font-weight:600;" target="_blank" rel="noopener noreferrer">link</a> test',
66
+ description: 'Adjacent bold and link tokens',
67
+ },
68
+ {
69
+ input: 'Combined {{link:https://example.com|bold|color:#FF0000}}bold red link{{/link}} test',
70
+ expected: 'Combined <a href="https://example.com" style="color:#FF0000;text-decoration:underline;font-weight:700;" target="_blank" rel="noopener noreferrer">bold red link</a> test',
71
+ description: 'Link with bold and custom color',
72
+ },
73
+ {
74
+ input: 'Just {{link:https://example.com|bold}}bold link{{/link}} no color',
75
+ expected: 'Just <a href="https://example.com" style="color:#008867;text-decoration:underline;font-weight:700;" target="_blank" rel="noopener noreferrer">bold link</a> no color',
76
+ description: 'Link with bold only',
77
+ },
78
+ {
79
+ input: 'Just {{link:https://example.com|color:#0000FF}}colored link{{/link}} no bold',
80
+ expected: 'Just <a href="https://example.com" style="color:#0000FF;text-decoration:underline;font-weight:600;" target="_blank" rel="noopener noreferrer">colored link</a> no bold',
81
+ description: 'Link with color only',
82
+ },
83
+ {
84
+ input: 'Invalid {{link:https://example.com|invalid}}modifier{{/link}} ignored',
85
+ expected: 'Invalid <a href="https://example.com" style="color:#008867;text-decoration:underline;font-weight:600;" target="_blank" rel="noopener noreferrer">modifier</a> ignored',
86
+ description: 'Invalid modifier ignored gracefully',
87
+ },
88
+ {
89
+ input: 'Text with {{style:bold}}strong emphasis{{/style}} word',
90
+ expected: 'Text with <span style="font-weight:700;">strong emphasis</span> word',
91
+ description: 'Style token with bold weight only',
92
+ },
93
+ {
94
+ input: 'Text with {{style:color:#FF0000}}red text{{/style}} here',
95
+ expected: 'Text with <span style="color:#FF0000;">red text</span> here',
96
+ description: 'Style token with color only',
97
+ },
98
+ {
99
+ input: 'Text with {{style:semibold|color:#008867}}styled{{/style}} word',
100
+ expected: 'Text with <span style="color:#008867;font-weight:600;">styled</span> word',
101
+ description: 'Style token with semibold and color',
102
+ },
103
+ {
104
+ input: 'Text with {{style:bold|color:#0000FF}}bold blue{{/style}} text',
105
+ expected: 'Text with <span style="color:#0000FF;font-weight:700;">bold blue</span> text',
106
+ description: 'Style token with bold and custom color',
107
+ },
108
+ {
109
+ input: 'Invalid {{style:invalid}}token{{/style}} ignored',
110
+ expected: 'Invalid token ignored',
111
+ description: 'Invalid style token (no valid options) renders plain text',
112
+ },
113
+ ];
114
+ console.log('Testing parseInlineFormatting function...\n');
115
+ let passed = 0;
116
+ let failed = 0;
117
+ testCases.forEach((testCase, index) => {
118
+ const result = parseInlineFormatting(testCase.input);
119
+ const isPass = result === testCase.expected;
120
+ if (isPass) {
121
+ passed++;
122
+ console.log(`✓ Test ${index + 1}: ${testCase.description}`);
123
+ }
124
+ else {
125
+ failed++;
126
+ console.log(`✗ Test ${index + 1}: ${testCase.description}`);
127
+ console.log(` Input: ${testCase.input}`);
128
+ console.log(` Expected: ${testCase.expected}`);
129
+ console.log(` Got: ${result}`);
130
+ }
131
+ });
132
+ console.log(`\n${passed} passed, ${failed} failed out of ${testCases.length} tests`);
@@ -0,0 +1,243 @@
1
+ /**
2
+ * CORE DATA MODEL FOR BLOCK-BASED HTML EMAIL GENERATOR
3
+ * Rock-solid foundation for email template management
4
+ */
5
+ /**
6
+ * Supported email template types
7
+ * Each has distinct allowed blocks and layout constraints
8
+ */
9
+ export type TemplateType = "open-fund" | "close-fund" | "newsletter";
10
+ /**
11
+ * All supported block types in the email body
12
+ * Restricted set to maintain email client compatibility
13
+ */
14
+ export type BlockType = "title" | "paragraph" | "image" | "button" | "divider" | "highlight-box";
15
+ /**
16
+ * Allowed inline HTML tags for text content
17
+ * Restricted to ensure email client compatibility and prevent XSS
18
+ */
19
+ export type AllowedInlineTag = "strong" | "b" | "em" | "i" | "u" | "a" | "br";
20
+ /**
21
+ * Text sanitization configuration
22
+ * Specifies which inline tags are allowed per block type
23
+ */
24
+ export interface TextSanitizationConfig {
25
+ stripAllHTMLExcept: AllowedInlineTag[];
26
+ stripAllStyles: boolean;
27
+ escapeUnsafeCharacters: boolean;
28
+ tagRestrictions: {
29
+ a: {
30
+ allowedAttributes: ["href"];
31
+ requireHttpProtocol: boolean;
32
+ };
33
+ img: {
34
+ allowedAttributes: ["src", "alt", "width", "height"];
35
+ requireHttpProtocol: boolean;
36
+ };
37
+ };
38
+ }
39
+ /**
40
+ * Title block: Single heading for sections
41
+ * Max 2 allowed per template typically
42
+ */
43
+ export interface TitleBlock {
44
+ type: "title";
45
+ id: string;
46
+ content: string;
47
+ level: "h1" | "h2" | "h3";
48
+ color?: string;
49
+ paddingBottom?: number;
50
+ }
51
+ /**
52
+ * Paragraph block: Text content with optional inline formatting
53
+ * Most flexible block type
54
+ */
55
+ export interface ParagraphBlock {
56
+ type: "paragraph";
57
+ id: string;
58
+ content: string;
59
+ color?: string;
60
+ lineHeight?: number;
61
+ paddingBottom?: number;
62
+ textAlign?: "left" | "center" | "right";
63
+ }
64
+ /**
65
+ * Image block: Responsive image with alt text
66
+ * Must have accessible alt text
67
+ */
68
+ export interface ImageBlock {
69
+ type: "image";
70
+ id: string;
71
+ src: string;
72
+ alt: string;
73
+ width?: number;
74
+ height?: number;
75
+ maxWidth?: number;
76
+ borderRadius?: number;
77
+ paddingBottom?: number;
78
+ }
79
+ /**
80
+ * Button block: Call-to-action button
81
+ * Limited to 1-2 per template
82
+ */
83
+ export interface ButtonBlock {
84
+ type: "button";
85
+ id: string;
86
+ label: string;
87
+ href: string;
88
+ backgroundColor?: string;
89
+ textColor?: string;
90
+ padding?: string;
91
+ borderRadius?: number;
92
+ marginTop?: number;
93
+ paddingBottom?: number;
94
+ align?: "left" | "center" | "right";
95
+ }
96
+ /**
97
+ * Divider block: Visual separator
98
+ * Horizontal line
99
+ */
100
+ export interface DividerBlock {
101
+ type: "divider";
102
+ id: string;
103
+ color?: string;
104
+ height?: number;
105
+ margin?: number;
106
+ }
107
+ /**
108
+ * Highlight box: Featured content area
109
+ * Used for callouts, warnings, feature highlights
110
+ */
111
+ export interface HighlightBoxBlock {
112
+ type: "highlight-box";
113
+ id: string;
114
+ content: string;
115
+ backgroundColor: string;
116
+ borderColor?: string;
117
+ borderLeft?: boolean;
118
+ padding?: string;
119
+ paddingBottom?: number;
120
+ borderRadius?: number;
121
+ }
122
+ /**
123
+ * Union type for all possible blocks
124
+ */
125
+ export type Block = TitleBlock | ParagraphBlock | ImageBlock | ButtonBlock | DividerBlock | HighlightBoxBlock;
126
+ /**
127
+ * Fixed section: Template logo/header
128
+ * Consistent across all templates
129
+ */
130
+ export interface EmailHeader {
131
+ logoUrl: string;
132
+ logoHeight?: number;
133
+ showDarkModeVariant?: boolean;
134
+ }
135
+ /**
136
+ * Fixed section: Contact and support info
137
+ * Consistent across all templates
138
+ */
139
+ export interface HelpSection {
140
+ title: string;
141
+ description: string;
142
+ contactItems: {
143
+ type: "email" | "phone" | "whatsapp";
144
+ label: string;
145
+ value: string;
146
+ href: string;
147
+ }[];
148
+ imageUrl?: string;
149
+ }
150
+ /**
151
+ * Fixed section: Compliance and legal
152
+ * Varies per template
153
+ */
154
+ export interface ComplianceSection {
155
+ text: string;
156
+ sandboxNumber?: string;
157
+ backgroundColor?: string;
158
+ }
159
+ /**
160
+ * Fixed section: Footer
161
+ * Company information
162
+ */
163
+ export interface EmailFooter {
164
+ logoUrl: string;
165
+ companyName: string;
166
+ address: string;
167
+ socialLinks?: {
168
+ platform: "instagram" | "twitter" | "linkedin" | "facebook" | "whatsapp" | "email";
169
+ url: string;
170
+ }[];
171
+ }
172
+ /**
173
+ * Email document: Complete structure
174
+ * Represents a fully-formed email with template, body blocks, and fixed sections
175
+ */
176
+ export interface EmailDocument {
177
+ id: string;
178
+ templateType: TemplateType;
179
+ version: number;
180
+ createdAt: Date;
181
+ updatedAt: Date;
182
+ blocks: Block[];
183
+ header: EmailHeader;
184
+ body: {
185
+ blocks: Block[];
186
+ };
187
+ helpSection: HelpSection;
188
+ complianceSection: ComplianceSection;
189
+ footer: EmailFooter;
190
+ personalizationVariables?: {
191
+ [key: string]: string;
192
+ };
193
+ isValid?: boolean;
194
+ validationErrors?: ValidationError[];
195
+ }
196
+ /**
197
+ * Validation error details
198
+ */
199
+ export interface ValidationError {
200
+ code: string;
201
+ message: string;
202
+ blockId?: string;
203
+ blockType?: BlockType;
204
+ severity: "error" | "warning";
205
+ }
206
+ /**
207
+ * Template configuration: Rules per template
208
+ * Enforced by validator
209
+ */
210
+ export interface TemplateConfiguration {
211
+ templateType: TemplateType;
212
+ allowedBlockTypes: BlockType[];
213
+ blockConstraints: {
214
+ [K in BlockType]?: {
215
+ min: number;
216
+ max: number;
217
+ required: boolean;
218
+ };
219
+ };
220
+ maxTotalBlocks: number;
221
+ allowReordering: boolean;
222
+ requireBlockOrder?: (BlockType | "any")[];
223
+ mandatoryBlocks: BlockType[];
224
+ helpSectionRequired: boolean;
225
+ complianceSectionRequired: boolean;
226
+ }
227
+ /**
228
+ * Context for validation operations
229
+ * Passed to validator to enforce rules
230
+ */
231
+ export interface ValidationContext {
232
+ templateConfig: TemplateConfiguration;
233
+ email: EmailDocument;
234
+ strict: boolean;
235
+ }
236
+ /**
237
+ * Context for text sanitization
238
+ */
239
+ export interface SanitizationContext {
240
+ blockType: BlockType;
241
+ sanitizationConfig: TextSanitizationConfig;
242
+ }
243
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * CORE DATA MODEL FOR BLOCK-BASED HTML EMAIL GENERATOR
3
+ * Rock-solid foundation for email template management
4
+ */
5
+ export {};