@bernierllc/email-manager 0.1.1
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/LICENSE +5 -0
- package/README.md +534 -0
- package/dist/email-manager.d.ts +134 -0
- package/dist/email-manager.d.ts.map +1 -0
- package/dist/email-manager.js +360 -0
- package/dist/email-manager.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/managers/email-analytics.d.ts +92 -0
- package/dist/managers/email-analytics.d.ts.map +1 -0
- package/dist/managers/email-analytics.js +375 -0
- package/dist/managers/email-analytics.js.map +1 -0
- package/dist/managers/email-scheduler.d.ts +81 -0
- package/dist/managers/email-scheduler.d.ts.map +1 -0
- package/dist/managers/email-scheduler.js +288 -0
- package/dist/managers/email-scheduler.js.map +1 -0
- package/dist/managers/provider-manager.d.ts +104 -0
- package/dist/managers/provider-manager.d.ts.map +1 -0
- package/dist/managers/provider-manager.js +436 -0
- package/dist/managers/provider-manager.js.map +1 -0
- package/dist/managers/template-manager.d.ts +65 -0
- package/dist/managers/template-manager.d.ts.map +1 -0
- package/dist/managers/template-manager.js +314 -0
- package/dist/managers/template-manager.js.map +1 -0
- package/dist/types.d.ts +507 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +60 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/simple-template-engine.d.ts +27 -0
- package/dist/utils/simple-template-engine.d.ts.map +1 -0
- package/dist/utils/simple-template-engine.js +61 -0
- package/dist/utils/simple-template-engine.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2025 Bernier LLC
|
|
3
|
+
|
|
4
|
+
This file is licensed to the client under a limited-use license.
|
|
5
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
6
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
7
|
+
*/
|
|
8
|
+
import { EmailSender } from '@bernierllc/email-sender';
|
|
9
|
+
// import { MagicLinkManager } from '@bernierllc/magic-link';
|
|
10
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
11
|
+
import { SimpleTemplateEngine } from './utils/simple-template-engine.js';
|
|
12
|
+
import { TemplateManager } from './managers/template-manager.js';
|
|
13
|
+
import { ProviderManager } from './managers/provider-manager.js';
|
|
14
|
+
import { EmailScheduler } from './managers/email-scheduler.js';
|
|
15
|
+
import { EmailAnalytics } from './managers/email-analytics.js';
|
|
16
|
+
import { EmailDataSchema } from './types.js';
|
|
17
|
+
/**
|
|
18
|
+
* EmailManager - Main orchestration service for email operations
|
|
19
|
+
*
|
|
20
|
+
* This service orchestrates email-sender, template-engine, and magic-link packages
|
|
21
|
+
* to provide comprehensive email management with templates, scheduling, and analytics.
|
|
22
|
+
*/
|
|
23
|
+
export class EmailManager {
|
|
24
|
+
constructor(config) {
|
|
25
|
+
this.config = config;
|
|
26
|
+
// Initialize core dependencies
|
|
27
|
+
this.emailSender = new EmailSender({
|
|
28
|
+
provider: 'smtp',
|
|
29
|
+
fromEmail: 'noreply@example.com'
|
|
30
|
+
});
|
|
31
|
+
this.templateEngine = new SimpleTemplateEngine();
|
|
32
|
+
// this.magicLinkManager = new MagicLinkManager({
|
|
33
|
+
// encryptionKey: process.env.MAGIC_LINK_SECRET || 'default-secret-key-32chars',
|
|
34
|
+
// defaultExpiryHours: 0.5 // 30 minutes
|
|
35
|
+
// });
|
|
36
|
+
// Initialize managers
|
|
37
|
+
this.templateManager = new TemplateManager(this.templateEngine);
|
|
38
|
+
this.providerManager = new ProviderManager(this.emailSender);
|
|
39
|
+
this.scheduler = new EmailScheduler((email) => this.sendEmail(email), config.scheduling);
|
|
40
|
+
this.analytics = new EmailAnalytics(config.analytics);
|
|
41
|
+
// Initialize with configuration
|
|
42
|
+
this.initializeFromConfig();
|
|
43
|
+
// Start scheduler if enabled
|
|
44
|
+
if (config.scheduling?.enabled !== false) {
|
|
45
|
+
this.scheduler.startScheduler();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// ======================
|
|
49
|
+
// Core Email Methods
|
|
50
|
+
// ======================
|
|
51
|
+
/**
|
|
52
|
+
* Send an email immediately
|
|
53
|
+
*/
|
|
54
|
+
async sendEmail(email) {
|
|
55
|
+
try {
|
|
56
|
+
// Validate email data
|
|
57
|
+
const validation = EmailDataSchema.safeParse(email);
|
|
58
|
+
if (!validation.success) {
|
|
59
|
+
return {
|
|
60
|
+
success: false,
|
|
61
|
+
provider: 'none',
|
|
62
|
+
sentAt: new Date(),
|
|
63
|
+
errors: validation.error.errors.map(e => ({
|
|
64
|
+
code: 'VALIDATION_ERROR',
|
|
65
|
+
message: `${e.path.join('.')}: ${e.message}`
|
|
66
|
+
}))
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const emailId = uuidv4();
|
|
70
|
+
// Track send attempt
|
|
71
|
+
const recipients = Array.isArray(email.to) ? email.to : [email.to];
|
|
72
|
+
recipients.forEach(recipient => {
|
|
73
|
+
this.analytics.trackEmailSent(emailId, email.provider || 'default', recipient);
|
|
74
|
+
});
|
|
75
|
+
// Send via provider manager
|
|
76
|
+
const result = await this.providerManager.sendEmail(email);
|
|
77
|
+
if (result.success) {
|
|
78
|
+
// Track successful delivery
|
|
79
|
+
recipients.forEach(recipient => {
|
|
80
|
+
this.analytics.trackEmailDelivered(emailId, recipient);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
...result,
|
|
85
|
+
messageId: result.messageId || emailId
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
return {
|
|
90
|
+
success: false,
|
|
91
|
+
provider: 'none',
|
|
92
|
+
sentAt: new Date(),
|
|
93
|
+
errors: [{
|
|
94
|
+
code: 'SEND_ERROR',
|
|
95
|
+
message: error instanceof Error ? error.message : 'Unknown error occurred'
|
|
96
|
+
}]
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Send a templated email
|
|
102
|
+
*/
|
|
103
|
+
async sendTemplatedEmail(templateId, context, recipients) {
|
|
104
|
+
try {
|
|
105
|
+
// Render the template
|
|
106
|
+
const renderedTemplate = await this.templateManager.renderTemplate(templateId, context);
|
|
107
|
+
// Prepare email data
|
|
108
|
+
const emailData = {
|
|
109
|
+
to: recipients,
|
|
110
|
+
subject: renderedTemplate.subject,
|
|
111
|
+
html: renderedTemplate.html,
|
|
112
|
+
text: renderedTemplate.text,
|
|
113
|
+
templateId
|
|
114
|
+
};
|
|
115
|
+
// Send the email
|
|
116
|
+
return await this.sendEmail(emailData);
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
return {
|
|
120
|
+
success: false,
|
|
121
|
+
provider: 'none',
|
|
122
|
+
sentAt: new Date(),
|
|
123
|
+
errors: [{
|
|
124
|
+
code: 'TEMPLATE_ERROR',
|
|
125
|
+
message: error instanceof Error ? error.message : 'Template processing failed'
|
|
126
|
+
}]
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Schedule an email for future delivery
|
|
132
|
+
*/
|
|
133
|
+
async scheduleEmail(email, scheduleTime) {
|
|
134
|
+
return await this.scheduler.scheduleEmail(email, scheduleTime);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Cancel a scheduled email
|
|
138
|
+
*/
|
|
139
|
+
async cancelScheduledEmail(scheduleId) {
|
|
140
|
+
return await this.scheduler.cancelScheduledEmail(scheduleId);
|
|
141
|
+
}
|
|
142
|
+
// ======================
|
|
143
|
+
// Template Management
|
|
144
|
+
// ======================
|
|
145
|
+
/**
|
|
146
|
+
* Create a new email template
|
|
147
|
+
*/
|
|
148
|
+
async createTemplate(template) {
|
|
149
|
+
return await this.templateManager.createTemplate(template);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Update an existing template
|
|
153
|
+
*/
|
|
154
|
+
async updateTemplate(templateId, template) {
|
|
155
|
+
return await this.templateManager.updateTemplate(templateId, template);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Delete a template
|
|
159
|
+
*/
|
|
160
|
+
async deleteTemplate(templateId) {
|
|
161
|
+
return await this.templateManager.deleteTemplate(templateId);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Get a template by ID
|
|
165
|
+
*/
|
|
166
|
+
async getTemplate(templateId) {
|
|
167
|
+
return await this.templateManager.getTemplate(templateId);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* List templates with filtering and pagination
|
|
171
|
+
*/
|
|
172
|
+
async listTemplates(options) {
|
|
173
|
+
return await this.templateManager.listTemplates(options);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Render a template with context (without sending)
|
|
177
|
+
*/
|
|
178
|
+
async renderTemplate(templateId, context) {
|
|
179
|
+
return await this.templateManager.renderTemplate(templateId, context);
|
|
180
|
+
}
|
|
181
|
+
// ======================
|
|
182
|
+
// Provider Management
|
|
183
|
+
// ======================
|
|
184
|
+
/**
|
|
185
|
+
* Add an email provider
|
|
186
|
+
*/
|
|
187
|
+
async addProvider(provider) {
|
|
188
|
+
return await this.providerManager.addProvider(provider);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Remove an email provider
|
|
192
|
+
*/
|
|
193
|
+
async removeProvider(providerId) {
|
|
194
|
+
return await this.providerManager.removeProvider(providerId);
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Get a provider by ID
|
|
198
|
+
*/
|
|
199
|
+
async getProvider(providerId) {
|
|
200
|
+
return await this.providerManager.getProvider(providerId);
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* List all providers
|
|
204
|
+
*/
|
|
205
|
+
async listProviders() {
|
|
206
|
+
return await this.providerManager.listProviders();
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Get provider status and health
|
|
210
|
+
*/
|
|
211
|
+
async getProviderStatus(providerId) {
|
|
212
|
+
return await this.providerManager.getProviderStatus(providerId);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Test provider connection
|
|
216
|
+
*/
|
|
217
|
+
async testConnection(providerId) {
|
|
218
|
+
return await this.providerManager.testConnection(providerId);
|
|
219
|
+
}
|
|
220
|
+
// ======================
|
|
221
|
+
// Analytics and Monitoring
|
|
222
|
+
// ======================
|
|
223
|
+
/**
|
|
224
|
+
* Get email statistics for a specific email
|
|
225
|
+
*/
|
|
226
|
+
async getEmailStats(emailId) {
|
|
227
|
+
return this.analytics.getEmailStats(emailId);
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Get delivery report for a time period
|
|
231
|
+
*/
|
|
232
|
+
async getDeliveryReport(options) {
|
|
233
|
+
return this.analytics.getDeliveryReport(options);
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Get bounce report for a time period
|
|
237
|
+
*/
|
|
238
|
+
async getBounceReport(options) {
|
|
239
|
+
return this.analytics.getBounceReport(options);
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Get analytics summary
|
|
243
|
+
*/
|
|
244
|
+
async getAnalyticsSummary(days = 30) {
|
|
245
|
+
return this.analytics.getSummary(days);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Track email events (for webhook integration)
|
|
249
|
+
*/
|
|
250
|
+
trackEmailEvent(eventType, emailId, recipient, metadata) {
|
|
251
|
+
switch (eventType) {
|
|
252
|
+
case 'opened':
|
|
253
|
+
this.analytics.trackEmailOpened(emailId, recipient);
|
|
254
|
+
break;
|
|
255
|
+
case 'clicked':
|
|
256
|
+
this.analytics.trackEmailClicked(emailId, recipient, metadata?.url || '');
|
|
257
|
+
break;
|
|
258
|
+
case 'bounced':
|
|
259
|
+
this.analytics.trackEmailBounced(emailId, recipient, metadata?.reason || 'Unknown');
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// ======================
|
|
264
|
+
// Utility Methods
|
|
265
|
+
// ======================
|
|
266
|
+
/**
|
|
267
|
+
* Validate an email address
|
|
268
|
+
*/
|
|
269
|
+
validateEmail(email) {
|
|
270
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
271
|
+
return emailRegex.test(email);
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Generate a magic link for email authentication
|
|
275
|
+
*/
|
|
276
|
+
async generateMagicLink(email, purpose, metadata) {
|
|
277
|
+
// TODO: Re-enable when magic-link package is properly built
|
|
278
|
+
throw new Error('Magic link functionality temporarily disabled');
|
|
279
|
+
// return this.magicLinkManager.generateMagicLink(email, purpose, {
|
|
280
|
+
// metadata
|
|
281
|
+
// });
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Verify a magic link
|
|
285
|
+
*/
|
|
286
|
+
async verifyMagicLink(token) {
|
|
287
|
+
// TODO: Re-enable when magic-link package is properly built
|
|
288
|
+
throw new Error('Magic link functionality temporarily disabled');
|
|
289
|
+
// return this.magicLinkManager.validateToken(token);
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Get overall system statistics
|
|
293
|
+
*/
|
|
294
|
+
getSystemStats() {
|
|
295
|
+
return {
|
|
296
|
+
templates: this.templateManager.getStats(),
|
|
297
|
+
providers: this.providerManager.getStats(),
|
|
298
|
+
scheduler: this.scheduler.getStats(),
|
|
299
|
+
analytics: {
|
|
300
|
+
totalEvents: this.analytics.getEventCount()
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Shutdown the email manager (cleanup resources)
|
|
306
|
+
*/
|
|
307
|
+
shutdown() {
|
|
308
|
+
this.scheduler.stopScheduler();
|
|
309
|
+
}
|
|
310
|
+
// ======================
|
|
311
|
+
// Private Methods
|
|
312
|
+
// ======================
|
|
313
|
+
/**
|
|
314
|
+
* Initialize managers with configuration data
|
|
315
|
+
*/
|
|
316
|
+
async initializeFromConfig() {
|
|
317
|
+
// Initialize providers
|
|
318
|
+
if (this.config.providers) {
|
|
319
|
+
for (const provider of this.config.providers) {
|
|
320
|
+
try {
|
|
321
|
+
await this.providerManager.addProvider(provider);
|
|
322
|
+
}
|
|
323
|
+
catch (error) {
|
|
324
|
+
console.error(`Failed to initialize provider ${provider.id}:`, error);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
// Initialize templates
|
|
329
|
+
if (this.config.templates) {
|
|
330
|
+
for (const template of this.config.templates) {
|
|
331
|
+
try {
|
|
332
|
+
await this.templateManager.createTemplate(template);
|
|
333
|
+
}
|
|
334
|
+
catch (error) {
|
|
335
|
+
console.error(`Failed to initialize template ${template.id}:`, error);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Get configuration
|
|
342
|
+
*/
|
|
343
|
+
getConfig() {
|
|
344
|
+
return { ...this.config };
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Update configuration
|
|
348
|
+
*/
|
|
349
|
+
updateConfig(updates) {
|
|
350
|
+
this.config = { ...this.config, ...updates };
|
|
351
|
+
// Update dependent managers
|
|
352
|
+
if (updates.scheduling) {
|
|
353
|
+
this.scheduler.updateConfig(updates.scheduling);
|
|
354
|
+
}
|
|
355
|
+
if (updates.analytics) {
|
|
356
|
+
this.analytics.updateConfig(updates.analytics);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
//# sourceMappingURL=email-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-manager.js","sourceRoot":"","sources":["../src/email-manager.ts"],"names":[],"mappings":"AAAA;;;;;;EAME;AAEF,OAAO,EAAE,WAAW,EAAuB,MAAM,0BAA0B,CAAC;AAC5E,6DAA6D;AAC7D,OAAO,EAAE,EAAE,IAAI,MAAM,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAEzE,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAE/D,OAAO,EAqBL,eAAe,EAChB,MAAM,YAAY,CAAC;AAEpB;;;;;GAKG;AACH,MAAM,OAAO,YAAY;IAUvB,YAAY,MAA0B;QACpC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAErB,iCAAiC;QACjC,IAAI,CAAC,WAAW,GAAG,IAAI,WAAW,CAAC;YACjC,QAAQ,EAAE,MAAM;YAChB,SAAS,EAAE,qBAAqB;SACjC,CAAC,CAAC;QACH,IAAI,CAAC,cAAc,GAAG,IAAI,oBAAoB,EAAE,CAAC;QACjD,iDAAiD;QACjD,kFAAkF;QAClF,0CAA0C;QAC1C,MAAM;QAEN,sBAAsB;QACtB,IAAI,CAAC,eAAe,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAChE,IAAI,CAAC,eAAe,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC7D,IAAI,CAAC,SAAS,GAAG,IAAI,cAAc,CACjC,CAAC,KAAgB,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAC3C,MAAM,CAAC,UAAU,CAClB,CAAC;QACF,IAAI,CAAC,SAAS,GAAG,IAAI,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAEtD,gCAAgC;QAChC,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAE5B,6BAA6B;QAC7B,IAAI,MAAM,CAAC,UAAU,EAAE,OAAO,KAAK,KAAK,EAAE,CAAC;YACzC,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE,CAAC;QAClC,CAAC;IACH,CAAC;IAED,yBAAyB;IACzB,qBAAqB;IACrB,yBAAyB;IAEzB;;OAEG;IACH,KAAK,CAAC,SAAS,CAAC,KAAgB;QAC9B,IAAI,CAAC;YACH,sBAAsB;YACtB,MAAM,UAAU,GAAG,eAAe,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YACpD,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;gBACxB,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,QAAQ,EAAE,MAAM;oBAChB,MAAM,EAAE,IAAI,IAAI,EAAE;oBAClB,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;wBACxC,IAAI,EAAE,kBAAkB;wBACxB,OAAO,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE;qBAC7C,CAAC,CAAC;iBACJ,CAAC;YACJ,CAAC;YAED,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC;YAEzB,qBAAqB;YACrB,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACnE,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE;gBAC7B,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,OAAO,EAAE,KAAK,CAAC,QAAQ,IAAI,SAAS,EAAE,SAAS,CAAC,CAAC;YACjF,CAAC,CAAC,CAAC;YAEH,4BAA4B;YAC5B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YAE3D,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnB,4BAA4B;gBAC5B,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE;oBAC7B,IAAI,CAAC,SAAS,CAAC,mBAAmB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;gBACzD,CAAC,CAAC,CAAC;YACL,CAAC;YAED,OAAO;gBACL,GAAG,MAAM;gBACT,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,OAAO;aACvC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,QAAQ,EAAE,MAAM;gBAChB,MAAM,EAAE,IAAI,IAAI,EAAE;gBAClB,MAAM,EAAE,CAAC;wBACP,IAAI,EAAE,YAAY;wBAClB,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB;qBAC3E,CAAC;aACH,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,kBAAkB,CAAC,UAAkB,EAAE,OAAwB,EAAE,UAAoB;QACzF,IAAI,CAAC;YACH,sBAAsB;YACtB,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAExF,qBAAqB;YACrB,MAAM,SAAS,GAAc;gBAC3B,EAAE,EAAE,UAAU;gBACd,OAAO,EAAE,gBAAgB,CAAC,OAAO;gBACjC,IAAI,EAAE,gBAAgB,CAAC,IAAI;gBAC3B,IAAI,EAAE,gBAAgB,CAAC,IAAI;gBAC3B,UAAU;aACX,CAAC;YAEF,iBAAiB;YACjB,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,QAAQ,EAAE,MAAM;gBAChB,MAAM,EAAE,IAAI,IAAI,EAAE;gBAClB,MAAM,EAAE,CAAC;wBACP,IAAI,EAAE,gBAAgB;wBACtB,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,4BAA4B;qBAC/E,CAAC;aACH,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa,CAAC,KAAgB,EAAE,YAAkB;QACtD,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IACjE,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,oBAAoB,CAAC,UAAkB;QAC3C,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC;IAC/D,CAAC;IAED,yBAAyB;IACzB,sBAAsB;IACtB,yBAAyB;IAEzB;;OAEG;IACH,KAAK,CAAC,cAAc,CAAC,QAAwD;QAC3E,OAAO,MAAM,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC7D,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc,CAAC,UAAkB,EAAE,QAAgC;QACvE,OAAO,MAAM,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IACzE,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc,CAAC,UAAkB;QACrC,OAAO,MAAM,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IAC/D,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW,CAAC,UAAkB;QAClC,OAAO,MAAM,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IAC5D,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa,CAAC,OAAqB;QACvC,OAAO,MAAM,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC3D,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc,CAAC,UAAkB,EAAE,OAAwB;QAC/D,OAAO,MAAM,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACxE,CAAC;IAED,yBAAyB;IACzB,sBAAsB;IACtB,yBAAyB;IAEzB;;OAEG;IACH,KAAK,CAAC,WAAW,CAAC,QAAuB;QACvC,OAAO,MAAM,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC1D,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc,CAAC,UAAkB;QACrC,OAAO,MAAM,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IAC/D,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW,CAAC,UAAkB;QAClC,OAAO,MAAM,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IAC5D,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa;QACjB,OAAO,MAAM,IAAI,CAAC,eAAe,CAAC,aAAa,EAAE,CAAC;IACpD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,iBAAiB,CAAC,UAAkB;QACxC,OAAO,MAAM,IAAI,CAAC,eAAe,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAClE,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc,CAAC,UAAkB;QACrC,OAAO,MAAM,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IAC/D,CAAC;IAED,yBAAyB;IACzB,2BAA2B;IAC3B,yBAAyB;IAEzB;;OAEG;IACH,KAAK,CAAC,aAAa,CAAC,OAAe;QACjC,OAAO,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,iBAAiB,CAAC,OAAuB;QAC7C,OAAO,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;IACnD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe,CAAC,OAAuB;QAC3C,OAAO,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;IACjD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,mBAAmB,CAAC,OAAe,EAAE;QACzC,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;IAED;;OAEG;IACH,eAAe,CAAC,SAA2C,EAAE,OAAe,EAAE,SAAiB,EAAE,QAAc;QAC7G,QAAQ,SAAS,EAAE,CAAC;YAClB,KAAK,QAAQ;gBACX,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;gBACpD,MAAM;YACR,KAAK,SAAS;gBACZ,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;gBAC1E,MAAM;YACR,KAAK,SAAS;gBACZ,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,IAAI,SAAS,CAAC,CAAC;gBACpF,MAAM;QACV,CAAC;IACH,CAAC;IAED,yBAAyB;IACzB,kBAAkB;IAClB,yBAAyB;IAEzB;;OAEG;IACH,aAAa,CAAC,KAAa;QACzB,MAAM,UAAU,GAAG,4BAA4B,CAAC;QAChD,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,iBAAiB,CAAC,KAAa,EAAE,OAAe,EAAE,QAAc;QACpE,4DAA4D;QAC5D,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACjE,mEAAmE;QACnE,aAAa;QACb,MAAM;IACR,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe,CAAC,KAAa;QACjC,4DAA4D;QAC5D,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACjE,qDAAqD;IACvD,CAAC;IAED;;OAEG;IACH,cAAc;QACZ,OAAO;YACL,SAAS,EAAE,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE;YAC1C,SAAS,EAAE,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE;YAC1C,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE;YACpC,SAAS,EAAE;gBACT,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE;aAC5C;SACF,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,QAAQ;QACN,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,CAAC;IACjC,CAAC;IAED,yBAAyB;IACzB,kBAAkB;IAClB,yBAAyB;IAEzB;;OAEG;IACK,KAAK,CAAC,oBAAoB;QAChC,uBAAuB;QACvB,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;YAC1B,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;gBAC7C,IAAI,CAAC;oBACH,MAAM,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;gBACnD,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,KAAK,CAAC,iCAAiC,QAAQ,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;gBACxE,CAAC;YACH,CAAC;QACH,CAAC;QAED,uBAAuB;QACvB,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;YAC1B,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;gBAC7C,IAAI,CAAC;oBACH,MAAM,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;gBACtD,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,KAAK,CAAC,iCAAiC,QAAQ,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;gBACxE,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,SAAS;QACP,OAAO,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,OAAoC;QAC/C,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,OAAO,EAAE,CAAC;QAE7C,4BAA4B;QAC5B,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACvB,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAClD,CAAC;QAED,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YACtB,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { EmailManager } from './email-manager.js';
|
|
2
|
+
export { TemplateManager } from './managers/template-manager.js';
|
|
3
|
+
export { ProviderManager } from './managers/provider-manager.js';
|
|
4
|
+
export { EmailScheduler } from './managers/email-scheduler.js';
|
|
5
|
+
export { EmailAnalytics } from './managers/email-analytics.js';
|
|
6
|
+
export * from './types.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAG/D,cAAc,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2025 Bernier LLC
|
|
3
|
+
|
|
4
|
+
This file is licensed to the client under a limited-use license.
|
|
5
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
6
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
7
|
+
*/
|
|
8
|
+
// Main EmailManager class
|
|
9
|
+
export { EmailManager } from './email-manager.js';
|
|
10
|
+
// Manager classes (for advanced usage)
|
|
11
|
+
export { TemplateManager } from './managers/template-manager.js';
|
|
12
|
+
export { ProviderManager } from './managers/provider-manager.js';
|
|
13
|
+
export { EmailScheduler } from './managers/email-scheduler.js';
|
|
14
|
+
export { EmailAnalytics } from './managers/email-analytics.js';
|
|
15
|
+
// Types and interfaces
|
|
16
|
+
export * from './types.js';
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;EAME;AAEF,0BAA0B;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,uCAAuC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAE/D,uBAAuB;AACvB,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { EmailEvent, EmailStats, DeliveryReport, BounceReport, ReportOptions, AnalyticsConfig } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Email Analytics System
|
|
4
|
+
* Handles email performance tracking and reporting
|
|
5
|
+
*/
|
|
6
|
+
export declare class EmailAnalytics {
|
|
7
|
+
private events;
|
|
8
|
+
private stats;
|
|
9
|
+
private config;
|
|
10
|
+
constructor(config?: AnalyticsConfig);
|
|
11
|
+
/**
|
|
12
|
+
* Track email sent event
|
|
13
|
+
*/
|
|
14
|
+
trackEmailSent(emailId: string, provider: string, recipient: string): void;
|
|
15
|
+
/**
|
|
16
|
+
* Track email delivered event
|
|
17
|
+
*/
|
|
18
|
+
trackEmailDelivered(emailId: string, recipient: string): void;
|
|
19
|
+
/**
|
|
20
|
+
* Track email opened event
|
|
21
|
+
*/
|
|
22
|
+
trackEmailOpened(emailId: string, recipient: string): void;
|
|
23
|
+
/**
|
|
24
|
+
* Track email clicked event
|
|
25
|
+
*/
|
|
26
|
+
trackEmailClicked(emailId: string, recipient: string, url: string): void;
|
|
27
|
+
/**
|
|
28
|
+
* Track email bounced event
|
|
29
|
+
*/
|
|
30
|
+
trackEmailBounced(emailId: string, recipient: string, reason: string): void;
|
|
31
|
+
/**
|
|
32
|
+
* Get email statistics for a specific email
|
|
33
|
+
*/
|
|
34
|
+
getEmailStats(emailId: string): EmailStats;
|
|
35
|
+
/**
|
|
36
|
+
* Get delivery report for a time period
|
|
37
|
+
*/
|
|
38
|
+
getDeliveryReport(options?: ReportOptions): DeliveryReport;
|
|
39
|
+
/**
|
|
40
|
+
* Get bounce report for a time period
|
|
41
|
+
*/
|
|
42
|
+
getBounceReport(options?: ReportOptions): BounceReport;
|
|
43
|
+
/**
|
|
44
|
+
* Get analytics summary
|
|
45
|
+
*/
|
|
46
|
+
getSummary(days?: number): any;
|
|
47
|
+
/**
|
|
48
|
+
* Get daily statistics for a period
|
|
49
|
+
*/
|
|
50
|
+
private getDailyStats;
|
|
51
|
+
/**
|
|
52
|
+
* Record an event
|
|
53
|
+
*/
|
|
54
|
+
private recordEvent;
|
|
55
|
+
/**
|
|
56
|
+
* Update email stats cache
|
|
57
|
+
*/
|
|
58
|
+
private updateEmailStats;
|
|
59
|
+
/**
|
|
60
|
+
* Calculate delivery rate from events
|
|
61
|
+
*/
|
|
62
|
+
private calculateDeliveryRate;
|
|
63
|
+
/**
|
|
64
|
+
* Calculate open rate from events
|
|
65
|
+
*/
|
|
66
|
+
private calculateOpenRate;
|
|
67
|
+
/**
|
|
68
|
+
* Calculate click rate from events
|
|
69
|
+
*/
|
|
70
|
+
private calculateClickRate;
|
|
71
|
+
/**
|
|
72
|
+
* Update analytics configuration
|
|
73
|
+
*/
|
|
74
|
+
updateConfig(config: Partial<AnalyticsConfig>): void;
|
|
75
|
+
/**
|
|
76
|
+
* Export events data (for backup or migration)
|
|
77
|
+
*/
|
|
78
|
+
exportEvents(): EmailEvent[];
|
|
79
|
+
/**
|
|
80
|
+
* Import events data (for restore or migration)
|
|
81
|
+
*/
|
|
82
|
+
importEvents(events: EmailEvent[]): void;
|
|
83
|
+
/**
|
|
84
|
+
* Clear all analytics data (for testing)
|
|
85
|
+
*/
|
|
86
|
+
clear(): void;
|
|
87
|
+
/**
|
|
88
|
+
* Get total event count
|
|
89
|
+
*/
|
|
90
|
+
getEventCount(): number;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=email-analytics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-analytics.d.ts","sourceRoot":"","sources":["../../src/managers/email-analytics.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,UAAU,EACV,UAAU,EACV,cAAc,EACd,YAAY,EACZ,aAAa,EACb,eAAe,EAChB,MAAM,aAAa,CAAC;AAErB;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,KAAK,CAAsC;IACnD,OAAO,CAAC,MAAM,CAAkB;gBAEpB,MAAM,GAAE,eAMnB;IAID;;OAEG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAc1E;;OAEG;IACH,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAa7D;;OAEG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAa1D;;OAEG;IACH,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAcxE;;OAEG;IACH,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAc3E;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU;IAgC1C;;OAEG;IACH,iBAAiB,CAAC,OAAO,GAAE,aAAkB,GAAG,cAAc;IAuC9D;;OAEG;IACH,eAAe,CAAC,OAAO,GAAE,aAAkB,GAAG,YAAY;IA8C1D;;OAEG;IACH,UAAU,CAAC,IAAI,GAAE,MAAW,GAAG,GAAG;IAwClC;;OAEG;IACH,OAAO,CAAC,aAAa;IA+BrB;;OAEG;IACH,OAAO,CAAC,WAAW;IAcnB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAwCxB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAM7B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAMzB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAM1B;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI;IAIpD;;OAEG;IACH,YAAY,IAAI,UAAU,EAAE;IAI5B;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI;IAKxC;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb;;OAEG;IACH,aAAa,IAAI,MAAM;CAGxB"}
|