@zyther/tzmail 0.1.0
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/README.md +133 -0
- package/dist/core/enums/template-part.enum.d.ts +7 -0
- package/dist/core/enums/template-part.enum.d.ts.map +1 -0
- package/dist/core/enums/template-part.enum.js +10 -0
- package/dist/core/enums/theme.enum.d.ts +8 -0
- package/dist/core/enums/theme.enum.d.ts.map +1 -0
- package/dist/core/enums/theme.enum.js +11 -0
- package/dist/core/interfaces/email.interface.d.ts +30 -0
- package/dist/core/interfaces/email.interface.d.ts.map +1 -0
- package/dist/core/interfaces/email.interface.js +2 -0
- package/dist/core/interfaces/template.interface.d.ts +56 -0
- package/dist/core/interfaces/template.interface.d.ts.map +1 -0
- package/dist/core/interfaces/template.interface.js +2 -0
- package/dist/factories/email-factory.d.ts +34 -0
- package/dist/factories/email-factory.d.ts.map +1 -0
- package/dist/factories/email-factory.js +52 -0
- package/dist/factories/template-factory.d.ts +15 -0
- package/dist/factories/template-factory.d.ts.map +1 -0
- package/dist/factories/template-factory.js +96 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/services/attachment.service.d.ts +46 -0
- package/dist/services/attachment.service.d.ts.map +1 -0
- package/dist/services/attachment.service.js +103 -0
- package/dist/services/email.service.d.ts +31 -0
- package/dist/services/email.service.d.ts.map +1 -0
- package/dist/services/email.service.js +58 -0
- package/dist/services/template.service.d.ts +180 -0
- package/dist/services/template.service.d.ts.map +1 -0
- package/dist/services/template.service.js +507 -0
- package/dist/templates/base/template-builder.d.ts +23 -0
- package/dist/templates/base/template-builder.d.ts.map +1 -0
- package/dist/templates/base/template-builder.js +676 -0
- package/dist/templates/themes/corporate.theme.d.ts +65 -0
- package/dist/templates/themes/corporate.theme.d.ts.map +1 -0
- package/dist/templates/themes/corporate.theme.js +109 -0
- package/dist/templates/themes/minimal.theme.d.ts +70 -0
- package/dist/templates/themes/minimal.theme.d.ts.map +1 -0
- package/dist/templates/themes/minimal.theme.js +114 -0
- package/dist/templates/themes/modern.theme.d.ts +38 -0
- package/dist/templates/themes/modern.theme.d.ts.map +1 -0
- package/dist/templates/themes/modern.theme.js +81 -0
- package/dist/templates/themes/monokai.theme.d.ts +29 -0
- package/dist/templates/themes/monokai.theme.d.ts.map +1 -0
- package/dist/templates/themes/monokai.theme.js +73 -0
- package/dist/templates/themes/system.theme.d.ts +50 -0
- package/dist/templates/themes/system.theme.d.ts.map +1 -0
- package/dist/templates/themes/system.theme.js +54 -0
- package/dist/templates/themes/theme.interface.d.ts +42 -0
- package/dist/templates/themes/theme.interface.d.ts.map +1 -0
- package/dist/templates/themes/theme.interface.js +2 -0
- package/dist/tests/template.service.test.d.ts +1 -0
- package/dist/tests/template.service.test.d.ts.map +1 -0
- package/dist/tests/template.service.test.js +1 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# tzMail
|
|
2
|
+
|
|
3
|
+
A powerful and flexible TypeScript/Node.js email package built on top of Nodemailer, featuring a robust templating system with built-in themes, caching, and easy attachment management.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🚀 **Singleton Factory**: Easy initialization and global access.
|
|
8
|
+
|
|
9
|
+
- 🎨 **Themed Templates**: 5 built-in professional themes (Modern, Corporate, Minimal, Monokai, System).
|
|
10
|
+
|
|
11
|
+
- 🌓 **Dark Mode Support**: All templates support light and dark variants.
|
|
12
|
+
|
|
13
|
+
- âš¡ **Performance**: In-memory template caching with TTL and version history.
|
|
14
|
+
|
|
15
|
+
- 📎 **Attachment Service**: Simple helpers for local files and buffers.
|
|
16
|
+
|
|
17
|
+
- ✅ **Validation**: Built-in configuration validation for templates.
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install tzmail
|
|
23
|
+
# or
|
|
24
|
+
yarn add tzmail
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
### 1. Initialize the Factory
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import { EmailFactory } from 'tzmail';
|
|
33
|
+
|
|
34
|
+
const smtpConfig = {
|
|
35
|
+
host: 'smtp.example.com',
|
|
36
|
+
port: 587,
|
|
37
|
+
auth: {
|
|
38
|
+
user: 'user@example.com',
|
|
39
|
+
pass: 'password'
|
|
40
|
+
},
|
|
41
|
+
defaultFrom: 'My App <noreply@myapp.com>'
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const emailFactory = EmailFactory.initialize(smtpConfig);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 2. Create and Send an Email
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
const templateService = emailFactory.getTemplateService();
|
|
51
|
+
|
|
52
|
+
// Create a template
|
|
53
|
+
const welcomeTemplate = templateService.createTemplate(
|
|
54
|
+
'modern', // ThemeType
|
|
55
|
+
'light', // Variant
|
|
56
|
+
{
|
|
57
|
+
body: {
|
|
58
|
+
title: 'Welcome!',
|
|
59
|
+
message: 'Thanks for joining us.',
|
|
60
|
+
buttonText: 'Get Started',
|
|
61
|
+
buttonUrl: 'https://myapp.com'
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
// Send the email
|
|
67
|
+
const result = await emailFactory.sendEmail({
|
|
68
|
+
to: 'user@example.com',
|
|
69
|
+
subject: 'Welcome aboard!',
|
|
70
|
+
template: welcomeTemplate
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
console.log(result.success ? 'Sent!' : 'Failed');
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Core Components
|
|
77
|
+
|
|
78
|
+
### Themes
|
|
79
|
+
|
|
80
|
+
| Theme | Best For | Features |
|
|
81
|
+
| --- | --- | --- |
|
|
82
|
+
| `MODERN` | Modern UI apps | Gradients, glassmorphism, rounded corners. |
|
|
83
|
+
| `CORPORATE` | Business/Enterprise | Serif typography, gold accents, structured layout. |
|
|
84
|
+
| `MINIMAL` | Clean newsletters | High whitespace, focused content, neutral colors. |
|
|
85
|
+
| `MONOKAI` | Technical content | Syntax highlighting for code blocks, vibrant colors. |
|
|
86
|
+
| `SYSTEM` | General purpose | Clean, accessible, system-native look. |
|
|
87
|
+
|
|
88
|
+
### Attachment Service
|
|
89
|
+
|
|
90
|
+
Easily add attachments from paths or buffers:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
const attachmentService = emailFactory.getAttachmentService();
|
|
94
|
+
const file = await attachmentService.addFromPath('path/to/report.pdf');
|
|
95
|
+
|
|
96
|
+
await emailFactory.sendEmail({
|
|
97
|
+
to: 'user@example.com',
|
|
98
|
+
subject: 'Monthly Report',
|
|
99
|
+
attachments: [file],
|
|
100
|
+
html: '<p>Please find the report attached.</p>'
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Configuration Reference
|
|
105
|
+
|
|
106
|
+
### `ITemplateConfig`
|
|
107
|
+
|
|
108
|
+
Customize your email structure:
|
|
109
|
+
|
|
110
|
+
- **header**: `{ show: boolean, logo: { type: 'text' | 'image', ... } }`
|
|
111
|
+
|
|
112
|
+
- **body**: `{ title, message, buttonText, buttonUrl, alignment, ... }`
|
|
113
|
+
|
|
114
|
+
- **footer**: `{ show: boolean, links: [], socialLinks: [], copyrightText }`
|
|
115
|
+
|
|
116
|
+
- **layout**: `'full'` | `'minimal'`
|
|
117
|
+
|
|
118
|
+
- **spacing**: `'compact'` | `'normal'` | `'relaxed'`
|
|
119
|
+
|
|
120
|
+
## Error Handling
|
|
121
|
+
|
|
122
|
+
The `sendEmail` method returns a result object:
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
{
|
|
126
|
+
success: boolean;
|
|
127
|
+
messageId?: string;
|
|
128
|
+
response?: string;
|
|
129
|
+
error?: any;
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-part.enum.d.ts","sourceRoot":"","sources":["../../../src/core/enums/template-part.enum.ts"],"names":[],"mappings":"AACA,oBAAY,YAAY;IACtB,MAAM,WAAW;IACjB,IAAI,SAAS;IACb,MAAM,WAAW;IACjB,MAAM,WAAW;CAClB"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TemplatePart = void 0;
|
|
4
|
+
var TemplatePart;
|
|
5
|
+
(function (TemplatePart) {
|
|
6
|
+
TemplatePart["HEADER"] = "header";
|
|
7
|
+
TemplatePart["BODY"] = "body";
|
|
8
|
+
TemplatePart["FOOTER"] = "footer";
|
|
9
|
+
TemplatePart["BUTTON"] = "button";
|
|
10
|
+
})(TemplatePart || (exports.TemplatePart = TemplatePart = {}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.enum.d.ts","sourceRoot":"","sources":["../../../src/core/enums/theme.enum.ts"],"names":[],"mappings":"AACA,oBAAY,SAAS;IACnB,MAAM,WAAW;IACjB,OAAO,YAAY;IACnB,MAAM,WAAW;IACjB,SAAS,cAAc;IACvB,OAAO,YAAY;CACpB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ThemeType = void 0;
|
|
4
|
+
var ThemeType;
|
|
5
|
+
(function (ThemeType) {
|
|
6
|
+
ThemeType["SYSTEM"] = "system";
|
|
7
|
+
ThemeType["MONOKAI"] = "monokai";
|
|
8
|
+
ThemeType["MODERN"] = "modern";
|
|
9
|
+
ThemeType["CORPORATE"] = "corporate";
|
|
10
|
+
ThemeType["MINIMAL"] = "minimal";
|
|
11
|
+
})(ThemeType || (exports.ThemeType = ThemeType = {}));
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ITemplate } from "./template.interface";
|
|
2
|
+
export interface IEmailOptions {
|
|
3
|
+
to: string | string[];
|
|
4
|
+
subject: string;
|
|
5
|
+
from?: string;
|
|
6
|
+
cc?: string | string[];
|
|
7
|
+
bcc?: string | string[];
|
|
8
|
+
attachments?: IAttachment[];
|
|
9
|
+
template?: ITemplate;
|
|
10
|
+
text?: string;
|
|
11
|
+
html?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface IAttachment {
|
|
14
|
+
filename: string;
|
|
15
|
+
content?: string | Buffer;
|
|
16
|
+
path?: string;
|
|
17
|
+
contentType?: string;
|
|
18
|
+
cid?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface IEmailConfig {
|
|
21
|
+
host: string;
|
|
22
|
+
port: number;
|
|
23
|
+
secure: boolean;
|
|
24
|
+
auth: {
|
|
25
|
+
user: string;
|
|
26
|
+
pass: string;
|
|
27
|
+
};
|
|
28
|
+
defaultFrom?: string;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=email.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email.interface.d.ts","sourceRoot":"","sources":["../../../src/core/interfaces/email.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACxB,WAAW,CAAC,EAAE,WAAW,EAAE,CAAC;IAC5B,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ThemeType } from "../enums/theme.enum";
|
|
2
|
+
export interface ITemplate {
|
|
3
|
+
name: string;
|
|
4
|
+
theme: ThemeType;
|
|
5
|
+
variant: 'light' | 'dark';
|
|
6
|
+
config: ITemplateConfig;
|
|
7
|
+
render(data: any): Promise<string>;
|
|
8
|
+
}
|
|
9
|
+
export interface ITemplateConfig {
|
|
10
|
+
header?: IHeaderConfig;
|
|
11
|
+
body?: IBodyConfig;
|
|
12
|
+
footer?: IFooterConfig;
|
|
13
|
+
layout?: 'full' | 'minimal';
|
|
14
|
+
spacing?: 'compact' | 'normal' | 'relaxed';
|
|
15
|
+
borderRadius?: 'none' | 'small' | 'medium' | 'large';
|
|
16
|
+
}
|
|
17
|
+
export interface IBodyConfig {
|
|
18
|
+
title?: string;
|
|
19
|
+
message?: string;
|
|
20
|
+
content?: string;
|
|
21
|
+
buttonText?: string;
|
|
22
|
+
buttonUrl?: string;
|
|
23
|
+
buttonVariant?: 'primary' | 'secondary' | 'success' | 'danger';
|
|
24
|
+
alignment?: 'left' | 'center' | 'right';
|
|
25
|
+
backgroundColor?: string;
|
|
26
|
+
textColor?: string;
|
|
27
|
+
fontSize?: number;
|
|
28
|
+
}
|
|
29
|
+
export interface IHeaderConfig {
|
|
30
|
+
show: boolean;
|
|
31
|
+
logo?: {
|
|
32
|
+
type: 'text' | 'image';
|
|
33
|
+
text?: string;
|
|
34
|
+
imageUrl?: string;
|
|
35
|
+
alt?: string;
|
|
36
|
+
size?: 'small' | 'medium' | 'large';
|
|
37
|
+
};
|
|
38
|
+
backgroundColor?: string;
|
|
39
|
+
textColor?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface IFooterConfig {
|
|
42
|
+
show: boolean;
|
|
43
|
+
links?: Array<{
|
|
44
|
+
text: string;
|
|
45
|
+
url: string;
|
|
46
|
+
}>;
|
|
47
|
+
socialLinks?: Array<{
|
|
48
|
+
platform: 'facebook' | 'twitter' | 'linkedin' | 'github' | 'instagram' | 'youtube' | 'tiktok' | 'pinterest' | 'reddit' | 'pinterest' | 'tiktok' | 'gitlab' | 'stackoverflow' | 'medium' | 'dribbble' | 'behance' | 'telegram';
|
|
49
|
+
url: string;
|
|
50
|
+
}>;
|
|
51
|
+
copyrightText?: string;
|
|
52
|
+
unsubscribeText?: string;
|
|
53
|
+
backgroundColor?: string;
|
|
54
|
+
textColor?: string;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=template.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template.interface.d.ts","sourceRoot":"","sources":["../../../src/core/interfaces/template.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC;IAC1B,MAAM,EAAE,eAAe,CAAC;IACxB,MAAM,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,OAAO,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC3C,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;CACtD;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC/D,SAAS,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACxC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE;QACL,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;KACrC,CAAC;IACF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,EAAE,MAAM,CAAC;KACb,CAAC,CAAC;IACH,WAAW,CAAC,EAAE,KAAK,CAAC;QAClB,QAAQ,EAAE,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,eAAe,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC;QAC9N,GAAG,EAAE,MAAM,CAAC;KACb,CAAC,CAAC;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { IEmailConfig, IEmailOptions } from '../core/interfaces/email.interface';
|
|
2
|
+
import { TemplateService } from '../services/template.service';
|
|
3
|
+
import { AttachmentService } from '../services/attachment.service';
|
|
4
|
+
import { ThemeType } from '../core/enums/theme.enum';
|
|
5
|
+
import { ITemplateConfig } from '../core/interfaces/template.interface';
|
|
6
|
+
export declare class EmailFactory {
|
|
7
|
+
private static instance;
|
|
8
|
+
private emailService;
|
|
9
|
+
private templateService;
|
|
10
|
+
private attachmentService;
|
|
11
|
+
private constructor();
|
|
12
|
+
static initialize(config: IEmailConfig, templateOptions?: any): EmailFactory;
|
|
13
|
+
static getInstance(): EmailFactory;
|
|
14
|
+
sendEmail(options: IEmailOptions): Promise<any>;
|
|
15
|
+
getTemplateService(): TemplateService;
|
|
16
|
+
getAttachmentService(): AttachmentService;
|
|
17
|
+
previewTemplate(themeType: ThemeType, variant: 'light' | 'dark', config: ITemplateConfig, data: any): Promise<string>;
|
|
18
|
+
getThemeInfo(themeType: ThemeType): {
|
|
19
|
+
name: string;
|
|
20
|
+
description: string;
|
|
21
|
+
features: string[];
|
|
22
|
+
availableVariants: ("light" | "dark")[];
|
|
23
|
+
defaultConfig: Partial<ITemplateConfig>;
|
|
24
|
+
};
|
|
25
|
+
listThemes(): ThemeType[];
|
|
26
|
+
getTemplateStats(): {
|
|
27
|
+
totalTemplates: number;
|
|
28
|
+
cachedTemplates: number;
|
|
29
|
+
totalHits: number;
|
|
30
|
+
templatesByTheme: Record<ThemeType, number>;
|
|
31
|
+
cacheHitRate: number;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=email-factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-factory.d.ts","sourceRoot":"","sources":["../../src/factories/email-factory.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AAEjF,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AAExE,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAe;IACtC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,iBAAiB,CAAoB;IAE7C,OAAO;IAOP,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,YAAY,EAAE,eAAe,CAAC,EAAE,GAAG,GAAG,YAAY;IAO5E,MAAM,CAAC,WAAW,IAAI,YAAY;IAO5B,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC;IAIrD,kBAAkB,IAAI,eAAe;IAIrC,oBAAoB,IAAI,iBAAiB;IAInC,eAAe,CACnB,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,OAAO,GAAG,MAAM,EACzB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,GAAG,GACR,OAAO,CAAC,MAAM,CAAC;IAIlB,YAAY,CAAC,SAAS,EAAE,SAAS;;;;;;;IAIjC,UAAU;IAIV,gBAAgB;;;;;;;CAGjB"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.EmailFactory = void 0;
|
|
7
|
+
const nodemailer_1 = __importDefault(require("nodemailer"));
|
|
8
|
+
const email_service_1 = require("../services/email.service");
|
|
9
|
+
const template_service_1 = require("../services/template.service");
|
|
10
|
+
const attachment_service_1 = require("../services/attachment.service");
|
|
11
|
+
class EmailFactory {
|
|
12
|
+
constructor(config, templateOptions) {
|
|
13
|
+
const transporter = nodemailer_1.default.createTransport(config);
|
|
14
|
+
this.emailService = new email_service_1.EmailService(transporter, config.defaultFrom);
|
|
15
|
+
this.templateService = new template_service_1.TemplateService(templateOptions);
|
|
16
|
+
this.attachmentService = new attachment_service_1.AttachmentService();
|
|
17
|
+
}
|
|
18
|
+
static initialize(config, templateOptions) {
|
|
19
|
+
if (!this.instance) {
|
|
20
|
+
this.instance = new EmailFactory(config, templateOptions);
|
|
21
|
+
}
|
|
22
|
+
return this.instance;
|
|
23
|
+
}
|
|
24
|
+
static getInstance() {
|
|
25
|
+
if (!this.instance) {
|
|
26
|
+
throw new Error('EmailFactory not initialized. Call initialize() first.');
|
|
27
|
+
}
|
|
28
|
+
return this.instance;
|
|
29
|
+
}
|
|
30
|
+
async sendEmail(options) {
|
|
31
|
+
return this.emailService.send(options);
|
|
32
|
+
}
|
|
33
|
+
getTemplateService() {
|
|
34
|
+
return this.templateService;
|
|
35
|
+
}
|
|
36
|
+
getAttachmentService() {
|
|
37
|
+
return this.attachmentService;
|
|
38
|
+
}
|
|
39
|
+
async previewTemplate(themeType, variant, config, data) {
|
|
40
|
+
return this.templateService.previewTemplate(themeType, variant, config, data);
|
|
41
|
+
}
|
|
42
|
+
getThemeInfo(themeType) {
|
|
43
|
+
return this.templateService.getThemeInfo(themeType);
|
|
44
|
+
}
|
|
45
|
+
listThemes() {
|
|
46
|
+
return this.templateService.listThemes();
|
|
47
|
+
}
|
|
48
|
+
getTemplateStats() {
|
|
49
|
+
return this.templateService.getTemplateStats();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.EmailFactory = EmailFactory;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ThemeType } from '../core/enums/theme.enum';
|
|
2
|
+
import { ITemplate, ITemplateConfig } from '../core/interfaces/template.interface';
|
|
3
|
+
import { ITheme } from '../templates/themes/theme.interface';
|
|
4
|
+
export declare class TemplateFactory {
|
|
5
|
+
private static themes;
|
|
6
|
+
static createTemplate(themeType: ThemeType, variant: 'light' | 'dark', config: ITemplateConfig): ITemplate;
|
|
7
|
+
static getTheme(themeType: ThemeType): ITheme | undefined;
|
|
8
|
+
static listThemes(): ThemeType[];
|
|
9
|
+
static getThemeInfo(themeType: ThemeType): {
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
features: string[];
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=template-factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-factory.d.ts","sourceRoot":"","sources":["../../src/factories/template-factory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACnF,OAAO,EAAE,MAAM,EAAE,MAAM,qCAAqC,CAAC;AAQ7D,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAC,MAAM,CAMlB;IAEH,MAAM,CAAC,cAAc,CACnB,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,OAAO,GAAG,MAAM,EACzB,MAAM,EAAE,eAAe,GACtB,SAAS;IA+CZ,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS;IAIzD,MAAM,CAAC,UAAU,IAAI,SAAS,EAAE;IAIhC,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,SAAS,GAAG;QACzC,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB;CA+BF"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TemplateFactory = void 0;
|
|
4
|
+
const theme_enum_1 = require("../core/enums/theme.enum");
|
|
5
|
+
const system_theme_1 = require("../templates/themes/system.theme");
|
|
6
|
+
const monokai_theme_1 = require("../templates/themes/monokai.theme");
|
|
7
|
+
const modern_theme_1 = require("../templates/themes/modern.theme");
|
|
8
|
+
const corporate_theme_1 = require("../templates/themes/corporate.theme");
|
|
9
|
+
const minimal_theme_1 = require("../templates/themes/minimal.theme");
|
|
10
|
+
const template_builder_1 = require("../templates/base/template-builder");
|
|
11
|
+
class TemplateFactory {
|
|
12
|
+
static createTemplate(themeType, variant, config) {
|
|
13
|
+
const theme = this.themes.get(themeType);
|
|
14
|
+
if (!theme) {
|
|
15
|
+
throw new Error(`Theme ${themeType} not found`);
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
name: `${themeType}_${variant}`,
|
|
19
|
+
theme: themeType,
|
|
20
|
+
variant,
|
|
21
|
+
config,
|
|
22
|
+
render: async (data) => {
|
|
23
|
+
const builder = new template_builder_1.TemplateBuilder(theme, config, variant);
|
|
24
|
+
const body = data.template.config.body || {};
|
|
25
|
+
let bodyContent = body.content || `
|
|
26
|
+
<table width="100%" cellpadding="0" cellspacing="0" role="presentation">
|
|
27
|
+
<tr>
|
|
28
|
+
<td style="padding: 20px; text-align: ${body.alignment || 'left'}; background-color: ${body.backgroundColor || 'transparent'}; color: ${body.textColor || 'inherit'}; font-size: ${body.fontSize || 14}px;">
|
|
29
|
+
|
|
30
|
+
<h2 style="margin: 0 0 16px 0; font-size: ${(body.fontSize + 7) || 21}px; line-height: 1.3;">
|
|
31
|
+
${body.title || 'Hello!'}
|
|
32
|
+
</h2>
|
|
33
|
+
|
|
34
|
+
<p style="margin: 0; line-height: 1.6;">
|
|
35
|
+
${body.message || 'This is an email generated with tzMail.'}
|
|
36
|
+
</p>
|
|
37
|
+
|
|
38
|
+
</td>
|
|
39
|
+
</tr>
|
|
40
|
+
</table>
|
|
41
|
+
`;
|
|
42
|
+
builder.buildHeader(data.headerContent).buildBody(bodyContent);
|
|
43
|
+
if (body.buttonText && body.buttonUrl) {
|
|
44
|
+
builder.buildButton(body.buttonText, body.buttonUrl, body.buttonVariant);
|
|
45
|
+
}
|
|
46
|
+
return builder
|
|
47
|
+
.buildFooter()
|
|
48
|
+
.build();
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
static getTheme(themeType) {
|
|
53
|
+
return this.themes.get(themeType);
|
|
54
|
+
}
|
|
55
|
+
static listThemes() {
|
|
56
|
+
return Array.from(this.themes.keys());
|
|
57
|
+
}
|
|
58
|
+
static getThemeInfo(themeType) {
|
|
59
|
+
const themeInfo = {
|
|
60
|
+
[theme_enum_1.ThemeType.SYSTEM]: {
|
|
61
|
+
name: 'System',
|
|
62
|
+
description: 'Tema limpo e profissional com cores adaptativas',
|
|
63
|
+
features: ['Design minimalista', 'Alta acessibilidade', 'Compatibilidade total']
|
|
64
|
+
},
|
|
65
|
+
[theme_enum_1.ThemeType.MONOKAI]: {
|
|
66
|
+
name: 'Monokai',
|
|
67
|
+
description: 'Inspirado no famoso tema de código, ideal para conteúdo técnico',
|
|
68
|
+
features: ['Cores vibrantes', 'Destaque de sintaxe', 'Efeitos glow']
|
|
69
|
+
},
|
|
70
|
+
[theme_enum_1.ThemeType.MODERN]: {
|
|
71
|
+
name: 'Modern',
|
|
72
|
+
description: 'Design contemporâneo com gradientes e efeitos modernos',
|
|
73
|
+
features: ['Gradientes elegantes', 'Glassmorphism', 'Animações suaves']
|
|
74
|
+
},
|
|
75
|
+
[theme_enum_1.ThemeType.CORPORATE]: {
|
|
76
|
+
name: 'Corporate',
|
|
77
|
+
description: 'Design profissional e elegante para empresas',
|
|
78
|
+
features: ['Tipografia serifada', 'Detalhes em dourado', 'Layout estruturado']
|
|
79
|
+
},
|
|
80
|
+
[theme_enum_1.ThemeType.MINIMAL]: {
|
|
81
|
+
name: 'Minimal',
|
|
82
|
+
description: 'Design clean e focado no conteúdo',
|
|
83
|
+
features: ['Sem distrações', 'Espaçamento generoso', 'Tipografia limpa']
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
return themeInfo[themeType];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
exports.TemplateFactory = TemplateFactory;
|
|
90
|
+
TemplateFactory.themes = new Map([
|
|
91
|
+
[theme_enum_1.ThemeType.SYSTEM, new system_theme_1.SystemTheme()],
|
|
92
|
+
[theme_enum_1.ThemeType.MONOKAI, new monokai_theme_1.MonokaiTheme()],
|
|
93
|
+
[theme_enum_1.ThemeType.MODERN, new modern_theme_1.ModernTheme()],
|
|
94
|
+
[theme_enum_1.ThemeType.CORPORATE, new corporate_theme_1.CorporateTheme()],
|
|
95
|
+
[theme_enum_1.ThemeType.MINIMAL, new minimal_theme_1.MinimalTheme()]
|
|
96
|
+
]);
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { EmailFactory } from './factories/email-factory';
|
|
2
|
+
export { TemplateFactory } from './factories/template-factory';
|
|
3
|
+
export { ITemplate, ITemplateConfig } from './core/interfaces/template.interface';
|
|
4
|
+
export { ThemeType } from './core/enums/theme.enum';
|
|
5
|
+
export { ITheme } from './templates/themes/theme.interface';
|
|
6
|
+
export { TemplateService } from './services/template.service';
|
|
7
|
+
export { EmailService } from './services/email.service';
|
|
8
|
+
export { AttachmentService } from './services/attachment.service';
|
|
9
|
+
export { TemplateBuilder } from './templates/base/template-builder';
|
|
10
|
+
export { CorporateTheme } from './templates/themes/corporate.theme';
|
|
11
|
+
export { MinimalTheme } from './templates/themes/minimal.theme';
|
|
12
|
+
export { ModernTheme } from './templates/themes/modern.theme';
|
|
13
|
+
export { MonokaiTheme } from './templates/themes/monokai.theme';
|
|
14
|
+
export { SystemTheme } from './templates/themes/system.theme';
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAClF,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SystemTheme = exports.MonokaiTheme = exports.ModernTheme = exports.MinimalTheme = exports.CorporateTheme = exports.TemplateBuilder = exports.AttachmentService = exports.EmailService = exports.TemplateService = exports.ThemeType = exports.TemplateFactory = exports.EmailFactory = void 0;
|
|
4
|
+
var email_factory_1 = require("./factories/email-factory");
|
|
5
|
+
Object.defineProperty(exports, "EmailFactory", { enumerable: true, get: function () { return email_factory_1.EmailFactory; } });
|
|
6
|
+
var template_factory_1 = require("./factories/template-factory");
|
|
7
|
+
Object.defineProperty(exports, "TemplateFactory", { enumerable: true, get: function () { return template_factory_1.TemplateFactory; } });
|
|
8
|
+
var theme_enum_1 = require("./core/enums/theme.enum");
|
|
9
|
+
Object.defineProperty(exports, "ThemeType", { enumerable: true, get: function () { return theme_enum_1.ThemeType; } });
|
|
10
|
+
var template_service_1 = require("./services/template.service");
|
|
11
|
+
Object.defineProperty(exports, "TemplateService", { enumerable: true, get: function () { return template_service_1.TemplateService; } });
|
|
12
|
+
var email_service_1 = require("./services/email.service");
|
|
13
|
+
Object.defineProperty(exports, "EmailService", { enumerable: true, get: function () { return email_service_1.EmailService; } });
|
|
14
|
+
var attachment_service_1 = require("./services/attachment.service");
|
|
15
|
+
Object.defineProperty(exports, "AttachmentService", { enumerable: true, get: function () { return attachment_service_1.AttachmentService; } });
|
|
16
|
+
var template_builder_1 = require("./templates/base/template-builder");
|
|
17
|
+
Object.defineProperty(exports, "TemplateBuilder", { enumerable: true, get: function () { return template_builder_1.TemplateBuilder; } });
|
|
18
|
+
var corporate_theme_1 = require("./templates/themes/corporate.theme");
|
|
19
|
+
Object.defineProperty(exports, "CorporateTheme", { enumerable: true, get: function () { return corporate_theme_1.CorporateTheme; } });
|
|
20
|
+
var minimal_theme_1 = require("./templates/themes/minimal.theme");
|
|
21
|
+
Object.defineProperty(exports, "MinimalTheme", { enumerable: true, get: function () { return minimal_theme_1.MinimalTheme; } });
|
|
22
|
+
var modern_theme_1 = require("./templates/themes/modern.theme");
|
|
23
|
+
Object.defineProperty(exports, "ModernTheme", { enumerable: true, get: function () { return modern_theme_1.ModernTheme; } });
|
|
24
|
+
var monokai_theme_1 = require("./templates/themes/monokai.theme");
|
|
25
|
+
Object.defineProperty(exports, "MonokaiTheme", { enumerable: true, get: function () { return monokai_theme_1.MonokaiTheme; } });
|
|
26
|
+
var system_theme_1 = require("./templates/themes/system.theme");
|
|
27
|
+
Object.defineProperty(exports, "SystemTheme", { enumerable: true, get: function () { return system_theme_1.SystemTheme; } });
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { IAttachment } from '../core/interfaces/email.interface';
|
|
2
|
+
/**
|
|
3
|
+
* AttachmentService - Gerencia anexos para emails
|
|
4
|
+
*
|
|
5
|
+
* Métodos:
|
|
6
|
+
* - addFromPath(filePath: string, options?: Partial<IAttachment>): Promise<IAttachment>
|
|
7
|
+
* Adiciona um anexo a partir de um caminho de arquivo.
|
|
8
|
+
*
|
|
9
|
+
* - addFromBuffer(buffer: Buffer, filename: string, options?: Partial<IAttachment>): Promise<IAttachment>
|
|
10
|
+
* Adiciona um anexo a partir de um buffer em memória.
|
|
11
|
+
*
|
|
12
|
+
* - addFromUrl(url: string, filename: string): Promise<IAttachment>
|
|
13
|
+
* Adiciona um anexo a partir de uma URL (ainda não implementado).
|
|
14
|
+
*
|
|
15
|
+
* Exemplo de uso:
|
|
16
|
+
*
|
|
17
|
+
* const attachmentService = new AttachmentService();
|
|
18
|
+
* const attachment = await attachmentService.addFromPath('path/to/file.pdf');
|
|
19
|
+
*
|
|
20
|
+
* emailFactory.sendEmail({
|
|
21
|
+
* to: 'user@example.com',
|
|
22
|
+
* subject: 'Assunto do Email',
|
|
23
|
+
* template: myTemplate,
|
|
24
|
+
* attachments: [{...attachment}]
|
|
25
|
+
* });
|
|
26
|
+
*/
|
|
27
|
+
export declare class AttachmentService {
|
|
28
|
+
/**
|
|
29
|
+
* addFromPath - Adiciona um anexo a partir de um caminho de arquivo
|
|
30
|
+
* @param filePath - Caminho do arquivo a ser anexado
|
|
31
|
+
* @param options - Opções adicionais para o anexo (filename, contentType, cid)
|
|
32
|
+
* @returns Promise<IAttachment> - Objeto de anexo formatado para Nodemailer
|
|
33
|
+
* @throws Error se o caminho não for um arquivo válido
|
|
34
|
+
*/
|
|
35
|
+
addFromPath(filePath: string, options?: Partial<IAttachment>): Promise<IAttachment>;
|
|
36
|
+
addFromBuffer(buffer: Buffer, filename: string, options?: Partial<IAttachment>): Promise<IAttachment>;
|
|
37
|
+
/**
|
|
38
|
+
* addFromUrl - Adiciona um anexo a partir de uma URL (a ser implementado)
|
|
39
|
+
* @param url - URL do recurso a ser anexado
|
|
40
|
+
* @param filename - Nome do arquivo para o anexo
|
|
41
|
+
* @returns Promise<IAttachment> - Objeto de anexo formatado para Nodemailer
|
|
42
|
+
* @throws Error se o método não for implementado
|
|
43
|
+
*/
|
|
44
|
+
addFromUrl(url: string, filename: string): Promise<IAttachment>;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=attachment.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachment.service.d.ts","sourceRoot":"","sources":["../../src/services/attachment.service.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AAEjE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,iBAAiB;IAC5B;;;;;;OAMG;IACG,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC;IAcnF,aAAa,CACjB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAC7B,OAAO,CAAC,WAAW,CAAC;IASvB;;;;;;OAMG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;CAGhE"}
|