@nauth-toolkit/core 0.1.95 → 0.1.97

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.
@@ -1,711 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HtmlTemplateEngine = void 0;
4
- const template_interface_1 = require("../interfaces/template.interface");
5
- const nauth_exception_1 = require("../exceptions/nauth.exception");
6
- const error_codes_enum_1 = require("../enums/error-codes.enum");
7
- /**
8
- * HTML Template Engine
9
- *
10
- * Simple yet powerful template engine for email templates using HTML with placeholder tokens.
11
- * Supports {{variable}} syntax for variable injection.
12
- *
13
- * Features:
14
- * - Simple {{variable}} placeholder syntax
15
- * - Built-in default templates for all email types
16
- * - Custom template registration
17
- * - Automatic HTML entity escaping for security
18
- * - Plain text generation from HTML
19
- *
20
- * @example
21
- * ```typescript
22
- * const engine = new HtmlTemplateEngine();
23
- * const result = await engine.render(
24
- * TemplateType.VERIFICATION,
25
- * { userName: 'John', code: '123456', expiryMinutes: 60 }
26
- * );
27
- * ```
28
- */
29
- class HtmlTemplateEngine {
30
- /**
31
- * Storage for registered templates
32
- * Maps template type to template definition
33
- */
34
- templates = new Map();
35
- /**
36
- * Constructor
37
- * Initializes the engine with default templates
38
- */
39
- constructor() {
40
- this.registerDefaultTemplates();
41
- }
42
- /**
43
- * Render a template with variables
44
- *
45
- * Replaces all {{variable}} placeholders with actual values.
46
- * Variables are HTML-escaped for security.
47
- * Handles firstName/username fallback for greetings.
48
- *
49
- * @param type - Template type to render
50
- * @param variables - Variables to inject
51
- * @returns Rendered email template
52
- * @throws {Error} If template type not found
53
- */
54
- async render(type, variables) {
55
- const template = this.templates.get(type);
56
- if (!template) {
57
- throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.INTERNAL_ERROR, `Template "${type}" not found. Available templates: ${Array.from(this.templates.keys()).join(', ')}`);
58
- }
59
- // Merge with default variables and add greeting name
60
- const allVariables = {
61
- currentYear: new Date().getFullYear(),
62
- ...variables,
63
- greetingName: this.getGreetingName(variables),
64
- };
65
- // Render subject and HTML
66
- const subject = this.replaceVariables(template.subject, allVariables);
67
- const html = this.replaceVariables(template.html, allVariables);
68
- // Generate plain text if not provided
69
- const text = template.text ? this.replaceVariablesForText(template.text, allVariables) : this.htmlToText(html);
70
- return { subject, html, text };
71
- }
72
- /**
73
- * Register a custom template
74
- *
75
- * @param type - Template type identifier
76
- * @param template - Template definition
77
- */
78
- registerTemplate(type, template) {
79
- this.templates.set(type, template);
80
- }
81
- /**
82
- * Get all available template types
83
- *
84
- * @returns Array of template type identifiers
85
- */
86
- getAvailableTemplates() {
87
- return Array.from(this.templates.keys());
88
- }
89
- /**
90
- * Check if a template exists
91
- *
92
- * @param type - Template type to check
93
- * @returns True if template is registered
94
- */
95
- hasTemplate(type) {
96
- return this.templates.has(type);
97
- }
98
- /**
99
- * Replace {{variable}} placeholders with values
100
- *
101
- * Escapes HTML entities in variables for security.
102
- * Handles missing variables gracefully (replaces with empty string).
103
- * Supports firstName/username fallback logic and simple conditionals.
104
- *
105
- * @param template - Template string with {{placeholders}}
106
- * @param variables - Variables to inject
107
- * @returns Template with variables replaced
108
- * @private
109
- */
110
- replaceVariables(template, variables) {
111
- let result = template;
112
- // Handle simple conditionals like {{#if greetingName}}Hi {{greetingName}},{{else}}Hi,{{/if}}
113
- result = result.replace(/\{\{#if (\w+)\}\}(.*?)\{\{else\}\}(.*?)\{\{\/if\}\}/g, (_match, key, ifContent, elseContent) => {
114
- const value = variables[key];
115
- if (value && value !== '') {
116
- return ifContent;
117
- }
118
- else {
119
- return elseContent;
120
- }
121
- });
122
- // Replace regular variables
123
- result = result.replace(/\{\{(\w+)\}\}/g, (_match, key) => {
124
- const value = variables[key];
125
- // Return empty string if variable is undefined
126
- if (value === undefined || value === null) {
127
- return '';
128
- }
129
- // Convert to string and escape HTML entities
130
- return this.escapeHtml(String(value));
131
- });
132
- return result;
133
- }
134
- /**
135
- * Replace {{variable}} placeholders with values for text content
136
- *
137
- * Similar to replaceVariables but doesn't escape HTML entities for plain text.
138
- *
139
- * @param template - Template string with {{placeholders}}
140
- * @param variables - Variables to inject
141
- * @returns Template with variables replaced
142
- * @private
143
- */
144
- replaceVariablesForText(template, variables) {
145
- let result = template;
146
- // Handle simple conditionals like {{#if greetingName}}Hi {{greetingName}},{{else}}Hi,{{/if}}
147
- result = result.replace(/\{\{#if (\w+)\}\}(.*?)\{\{else\}\}(.*?)\{\{\/if\}\}/g, (_match, key, ifContent, elseContent) => {
148
- const value = variables[key];
149
- if (value && value !== '') {
150
- return ifContent;
151
- }
152
- else {
153
- return elseContent;
154
- }
155
- });
156
- // Replace regular variables without HTML escaping
157
- result = result.replace(/\{\{(\w+)\}\}/g, (_match, key) => {
158
- const value = variables[key];
159
- // Return empty string if variable is undefined
160
- if (value === undefined || value === null) {
161
- return '';
162
- }
163
- // Convert to string without escaping HTML entities for text
164
- return String(value);
165
- });
166
- return result;
167
- }
168
- /**
169
- * Get greeting name with firstName/username fallback logic
170
- *
171
- * @param variables - Template variables
172
- * @returns Greeting name or empty string
173
- * @private
174
- */
175
- getGreetingName(variables) {
176
- if (variables.firstName) {
177
- return variables.firstName;
178
- }
179
- if (variables.userName) {
180
- return variables.userName;
181
- }
182
- return '';
183
- }
184
- /**
185
- * Escape HTML entities to prevent XSS
186
- *
187
- * @param text - Text to escape
188
- * @returns HTML-safe text
189
- * @private
190
- */
191
- escapeHtml(text) {
192
- const map = {
193
- '&': '&',
194
- '<': '&lt;',
195
- '>': '&gt;',
196
- '"': '&quot;',
197
- "'": '&#039;',
198
- };
199
- return text.replace(/[&<>"']/g, (char) => map[char] || char);
200
- }
201
- /**
202
- * Convert HTML to plain text
203
- *
204
- * Simple conversion: strips HTML tags and decodes entities.
205
- *
206
- * @param html - HTML content
207
- * @returns Plain text
208
- * @private
209
- */
210
- htmlToText(html) {
211
- // Strip HTML tags
212
- let text = html.replace(/<[^>]*>/g, '');
213
- // Decode common HTML entities
214
- text = text.replace(/&nbsp;/g, ' ');
215
- text = text.replace(/&lt;/g, '<');
216
- text = text.replace(/&gt;/g, '>');
217
- text = text.replace(/&quot;/g, '"');
218
- text = text.replace(/&#039;/g, "'");
219
- text = text.replace(/&amp;/g, '&');
220
- // Normalize whitespace
221
- text = text.replace(/\s+/g, ' ').trim();
222
- return text;
223
- }
224
- /**
225
- * Register default templates for all email types
226
- *
227
- * These templates can be overridden using registerTemplate().
228
- * @private
229
- */
230
- registerDefaultTemplates() {
231
- // ============================================================================
232
- // Email Verification Template
233
- // ============================================================================
234
- this.registerTemplate(template_interface_1.TemplateType.VERIFICATION, {
235
- subject: 'Email Verification - {{appName}}',
236
- html: `
237
- <!DOCTYPE html>
238
- <html>
239
- <head>
240
- <meta charset="UTF-8">
241
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
242
- <title>Email Verification</title>
243
- <style>
244
- body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; margin: 0; padding: 20px; }
245
- .container { max-width: 600px; margin: 0 auto; }
246
- h1 { font-size: 24px; margin: 0 0 20px 0; }
247
- p { margin: 0 0 15px 0; }
248
- .code { font-size: 24px; font-weight: bold; letter-spacing: 3px; margin: 20px 0; }
249
- </style>
250
- </head>
251
- <body>
252
- <div class="container">
253
- <h1>Email Verification</h1>
254
- <p>{{#if greetingName}}Hi {{greetingName}},{{else}}Hi,{{/if}}</p>
255
- <p>Thank you for signing up! Please verify your email address to activate your account.</p>
256
-
257
- <p>Your Verification Code:</p>
258
- <div class="code">{{code}}</div>
259
-
260
- <p>Or click the link below to verify:</p>
261
- <p><a href="{{link}}">Verify Email Address</a></p>
262
-
263
- <p>This code expires in {{expiryMinutes}} minutes.</p>
264
- <p>If you didn't request this verification, please ignore this email.</p>
265
- </div>
266
- </body>
267
- </html>
268
- `,
269
- text: `
270
- Email Verification
271
-
272
- {{#if greetingName}}Hi {{greetingName}},{{else}}Hi,{{/if}}
273
-
274
- Thank you for signing up! Please verify your email address to activate your account.
275
-
276
- Your Verification Code: {{code}}
277
-
278
- Or use this link: {{link}}
279
-
280
- This code expires in {{expiryMinutes}} minutes.
281
-
282
- If you didn't request this verification, please ignore this email.
283
- `,
284
- });
285
- // ============================================================================
286
- // Password Reset Template
287
- // ============================================================================
288
- this.registerTemplate(template_interface_1.TemplateType.PASSWORD_RESET, {
289
- subject: 'Password Reset - {{appName}}',
290
- html: `
291
- <!DOCTYPE html>
292
- <html>
293
- <head>
294
- <meta charset="UTF-8">
295
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
296
- <title>Password Reset</title>
297
- <style>
298
- body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; margin: 0; padding: 20px; }
299
- .container { max-width: 600px; margin: 0 auto; }
300
- h1 { font-size: 24px; margin: 0 0 20px 0; }
301
- p { margin: 0 0 15px 0; }
302
- </style>
303
- </head>
304
- <body>
305
- <div class="container">
306
- <h1>Password Reset</h1>
307
- <p>{{#if greetingName}}Hi {{greetingName}},{{else}}Hi,{{/if}}</p>
308
- <p>We received a request to reset your password. Click the link below to create a new password:</p>
309
-
310
- <p><a href="{{link}}">Reset Your Password</a></p>
311
-
312
- <p>This link expires in {{expiryMinutes}} minutes.</p>
313
- <p>If you didn't request a password reset, your account is secure and you can ignore this email.</p>
314
-
315
- <p>If the link doesn't work, copy and paste this URL into your browser:</p>
316
- <p>{{link}}</p>
317
- </div>
318
- </body>
319
- </html>
320
- `,
321
- text: `
322
- Password Reset
323
-
324
- {{#if greetingName}}Hi {{greetingName}},{{else}}Hi,{{/if}}
325
-
326
- We received a request to reset your password. Use the link below to create a new password:
327
-
328
- {{link}}
329
-
330
- This link expires in {{expiryMinutes}} minutes.
331
-
332
- If you didn't request a password reset, your account is secure and you can ignore this email.
333
- `,
334
- });
335
- // ============================================================================
336
- // Admin Password Reset Template
337
- // ============================================================================
338
- this.registerTemplate(template_interface_1.TemplateType.ADMIN_PASSWORD_RESET, {
339
- subject: 'Password Reset Initiated by Administrator - {{appName}}',
340
- html: `
341
- <!DOCTYPE html>
342
- <html>
343
- <head>
344
- <meta charset="UTF-8">
345
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
346
- <title>Admin Password Reset</title>
347
- <style>
348
- body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; margin: 0; padding: 20px; }
349
- .container { max-width: 600px; margin: 0 auto; }
350
- h1 { font-size: 24px; margin: 0 0 20px 0; }
351
- p { margin: 0 0 15px 0; }
352
- .code { font-size: 24px; font-weight: bold; letter-spacing: 3px; margin: 20px 0; text-align: center; padding: 15px; background-color: #f5f5f5; border-radius: 5px; }
353
- .warning { background-color: #fff3cd; border-left: 4px solid #ffc107; padding: 12px; margin: 20px 0; }
354
- </style>
355
- </head>
356
- <body>
357
- <div class="container">
358
- <h1>Password Reset Initiated</h1>
359
- <p>{{#if greetingName}}Hi {{greetingName}},{{else}}Hi,{{/if}}</p>
360
- <p><strong>An administrator has initiated a password reset for your {{appName}} account.</strong></p>
361
-
362
- <p>Your Reset Code:</p>
363
- <div class="code">{{code}}</div>
364
-
365
- {{#if link}}
366
- <p>Or click the link below to reset your password:</p>
367
- <p><a href="{{link}}">Reset Password</a></p>
368
- {{/if}}
369
-
370
- <p>This code expires in {{expiryMinutes}} minutes.</p>
371
-
372
- <div class="warning">
373
- <p><strong>Important:</strong> If you did not request this password reset, please contact your administrator immediately.</p>
374
- </div>
375
- </div>
376
- </body>
377
- </html>
378
- `,
379
- text: `
380
- Password Reset Initiated by Administrator
381
-
382
- {{#if greetingName}}Hi {{greetingName}},{{else}}Hi,{{/if}}
383
-
384
- An administrator has initiated a password reset for your {{appName}} account.
385
-
386
- Your Reset Code: {{code}}
387
-
388
- {{#if link}}
389
- Or use this link: {{link}}
390
- {{/if}}
391
-
392
- This code expires in {{expiryMinutes}} minutes.
393
-
394
- IMPORTANT: If you did not request this password reset, please contact your administrator immediately.
395
- `,
396
- });
397
- // ============================================================================
398
- // Welcome Email Template
399
- // ============================================================================
400
- this.registerTemplate(template_interface_1.TemplateType.WELCOME, {
401
- subject: 'Welcome to {{appName}}!',
402
- html: `
403
- <!DOCTYPE html>
404
- <html>
405
- <head>
406
- <meta charset="UTF-8">
407
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
408
- <title>Welcome</title>
409
- <style>
410
- body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; margin: 0; padding: 20px; }
411
- .container { max-width: 600px; margin: 0 auto; }
412
- h1 { font-size: 24px; margin: 0 0 20px 0; }
413
- p { margin: 0 0 15px 0; }
414
- </style>
415
- </head>
416
- <body>
417
- <div class="container">
418
- <h1>Welcome</h1>
419
- <p>{{#if greetingName}}Hi {{greetingName}},{{else}}Hi,{{/if}}</p>
420
- <p>We're excited to have you with us! Your account has been successfully created and you're ready to get started.</p>
421
-
422
- <p><a href="{{dashboardUrl}}">Get Started</a></p>
423
-
424
- <p>If you have any questions or need assistance, feel free to reach out to our support team at {{supportEmail}}.</p>
425
-
426
- <p>Happy exploring!</p>
427
- </div>
428
- </body>
429
- </html>
430
- `,
431
- text: `
432
- Welcome to {{appName}}!
433
-
434
- {{#if greetingName}}Hi {{greetingName}},{{else}}Hi,{{/if}}
435
-
436
- We're excited to have you with us! Your account has been successfully created and you're ready to get started.
437
-
438
- Visit: {{dashboardUrl}}
439
-
440
- If you have any questions or need assistance, reach out to our support team at {{supportEmail}}.
441
-
442
- Happy exploring!
443
- `,
444
- });
445
- // ============================================================================
446
- // Account Lockout Template
447
- // ============================================================================
448
- this.registerTemplate(template_interface_1.TemplateType.ACCOUNT_LOCKOUT, {
449
- subject: 'Account Locked - {{appName}}',
450
- html: `
451
- <!DOCTYPE html>
452
- <html>
453
- <head>
454
- <meta charset="UTF-8">
455
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
456
- <title>Account Lockout</title>
457
- <style>
458
- body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; margin: 0; padding: 20px; }
459
- .container { max-width: 600px; margin: 0 auto; }
460
- h1 { font-size: 24px; margin: 0 0 20px 0; }
461
- p { margin: 0 0 15px 0; }
462
- ul { margin: 0 0 15px 0; }
463
- </style>
464
- </head>
465
- <body>
466
- <div class="container">
467
- <h1>Account Locked</h1>
468
- <p>{{#if greetingName}}Hi {{greetingName}},{{else}}Hi,{{/if}}</p>
469
- <p>Your account has been temporarily locked for security reasons.</p>
470
-
471
- <p><strong>Reason:</strong> {{reason}}</p>
472
- <p><strong>Duration:</strong> Your account will be automatically unlocked in {{durationMinutes}} minutes.</p>
473
-
474
- <p><strong>What happened?</strong></p>
475
- <p>We detected multiple failed login attempts or suspicious activity on your account. As a security measure, we've temporarily locked your account to protect it.</p>
476
-
477
- <p><strong>What should I do?</strong></p>
478
- <ul>
479
- <li>Wait {{durationMinutes}} minutes for automatic unlock</li>
480
- <li>If this was you, try logging in again after the lockout period</li>
481
- <li>If this wasn't you, please contact support immediately at {{supportEmail}}</li>
482
- <li>Consider changing your password after unlock</li>
483
- </ul>
484
- </div>
485
- </body>
486
- </html>
487
- `,
488
- text: `
489
- Account Locked
490
-
491
- {{#if greetingName}}Hi {{greetingName}},{{else}}Hi,{{/if}}
492
-
493
- Your account has been temporarily locked for security reasons.
494
-
495
- Reason: {{reason}}
496
- Duration: Your account will be automatically unlocked in {{durationMinutes}} minutes.
497
-
498
- What happened?
499
- We detected multiple failed login attempts or suspicious activity on your account.
500
-
501
- What should I do?
502
- - Wait {{durationMinutes}} minutes for automatic unlock
503
- - If this was you, try logging in again after the lockout period
504
- - If this wasn't you, contact support at {{supportEmail}}
505
- - Consider changing your password after unlock
506
- `,
507
- });
508
- // ============================================================================
509
- // New Device Login Template
510
- // ============================================================================
511
- this.registerTemplate(template_interface_1.TemplateType.NEW_DEVICE, {
512
- subject: 'New Device Login - {{appName}}',
513
- html: `
514
- <!DOCTYPE html>
515
- <html>
516
- <head>
517
- <meta charset="UTF-8">
518
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
519
- <title>New Device Login</title>
520
- <style>
521
- body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; margin: 0; padding: 20px; }
522
- .container { max-width: 600px; margin: 0 auto; }
523
- h1 { font-size: 24px; margin: 0 0 20px 0; }
524
- p { margin: 0 0 15px 0; }
525
- ul { margin: 0 0 15px 0; }
526
- </style>
527
- </head>
528
- <body>
529
- <div class="container">
530
- <h1>New Device Login</h1>
531
- <p>{{#if greetingName}}Hi {{greetingName}},{{else}}Hi,{{/if}}</p>
532
- <p>We detected a login to your account from a new device.</p>
533
-
534
- <p><strong>Device:</strong> {{deviceName}}</p>
535
- <p><strong>Type:</strong> {{deviceType}}</p>
536
- <p><strong>IP Address:</strong> {{ipAddress}}</p>
537
- <p><strong>Location:</strong> {{location}}</p>
538
- <p><strong>Time:</strong> {{timestamp}}</p>
539
-
540
- <p><strong>Was this you?</strong></p>
541
- <p>If you recognize this login, no action is needed. Your account is secure.</p>
542
-
543
- <p><strong>Not you?</strong></p>
544
- <p>If you don't recognize this activity, please secure your account immediately:</p>
545
- <ul>
546
- <li>Change your password</li>
547
- <li>Review your recent account activity</li>
548
- <li>Contact support at {{supportEmail}}</li>
549
- </ul>
550
- </div>
551
- </body>
552
- </html>
553
- `,
554
- text: `
555
- New Device Login
556
-
557
- {{#if greetingName}}Hi {{greetingName}},{{else}}Hi,{{/if}}
558
-
559
- We detected a login to your account from a new device.
560
-
561
- Device: {{deviceName}}
562
- Type: {{deviceType}}
563
- IP Address: {{ipAddress}}
564
- Location: {{location}}
565
- Time: {{timestamp}}
566
-
567
- Was this you?
568
- If you recognize this login, no action is needed.
569
-
570
- Not you?
571
- If you don't recognize this activity, secure your account immediately:
572
- - Change your password
573
- - Review your recent account activity
574
- - Contact support at {{supportEmail}}
575
- `,
576
- });
577
- // Password Changed Template
578
- // ============================================================================
579
- this.registerTemplate(template_interface_1.TemplateType.PASSWORD_CHANGED, {
580
- subject: 'Password Changed - {{appName}}',
581
- html: `
582
- <!DOCTYPE html>
583
- <html>
584
- <head>
585
- <meta charset="UTF-8">
586
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
587
- <title>Password Changed</title>
588
- <style>
589
- body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; margin: 0; padding: 20px; }
590
- .container { max-width: 600px; margin: 0 auto; }
591
- h1 { font-size: 24px; margin: 0 0 20px 0; }
592
- p { margin: 0 0 15px 0; }
593
- </style>
594
- </head>
595
- <body>
596
- <div class="container">
597
- <h1>Password Changed</h1>
598
- <p>{{#if greetingName}}Hi {{greetingName}},{{else}}Hi,{{/if}}</p>
599
- <p>Your password has been successfully changed.</p>
600
-
601
- <p>If you made this change, no further action is required.</p>
602
-
603
- <p>If you didn't make this change, please contact support immediately at {{supportEmail}}.</p>
604
- </div>
605
- </body>
606
- </html>
607
- `,
608
- text: `
609
- Password Changed
610
-
611
- {{#if greetingName}}Hi {{greetingName}},{{else}}Hi,{{/if}}
612
-
613
- Your password has been successfully changed.
614
-
615
- If you made this change, no further action is required.
616
-
617
- If you didn't make this change, please contact support immediately at {{supportEmail}}.
618
- `,
619
- });
620
- // ============================================================================
621
- // Email Changed Template
622
- // ============================================================================
623
- this.registerTemplate(template_interface_1.TemplateType.EMAIL_CHANGED, {
624
- subject: 'Email Address Changed - {{appName}}',
625
- html: `
626
- <!DOCTYPE html>
627
- <html>
628
- <head>
629
- <meta charset="UTF-8">
630
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
631
- <title>Email Changed</title>
632
- <style>
633
- body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; margin: 0; padding: 20px; }
634
- .container { max-width: 600px; margin: 0 auto; }
635
- h1 { font-size: 24px; margin: 0 0 20px 0; }
636
- p { margin: 0 0 15px 0; }
637
- </style>
638
- </head>
639
- <body>
640
- <div class="container">
641
- <h1>Email Address Changed</h1>
642
- <p>{{#if greetingName}}Hi {{greetingName}},{{else}}Hi,{{/if}}</p>
643
- <p>Your email address has been successfully changed to {{userEmail}}.</p>
644
-
645
- <p>If you made this change, no further action is required.</p>
646
-
647
- <p>If you didn't make this change, please contact support immediately at {{supportEmail}}.</p>
648
- </div>
649
- </body>
650
- </html>
651
- `,
652
- text: `
653
- Email Address Changed
654
-
655
- {{#if greetingName}}Hi {{greetingName}},{{else}}Hi,{{/if}}
656
-
657
- Your email address has been successfully changed to {{userEmail}}.
658
-
659
- If you made this change, no further action is required.
660
-
661
- If you didn't make this change, please contact support immediately at {{supportEmail}}.
662
- `,
663
- });
664
- // ============================================================================
665
- // MFA Enabled Template
666
- // ============================================================================
667
- this.registerTemplate(template_interface_1.TemplateType.MFA_ENABLED, {
668
- subject: 'Two-Factor Authentication Enabled - {{appName}}',
669
- html: `
670
- <!DOCTYPE html>
671
- <html>
672
- <head>
673
- <meta charset="UTF-8">
674
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
675
- <title>MFA Enabled</title>
676
- <style>
677
- body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; margin: 0; padding: 20px; }
678
- .container { max-width: 600px; margin: 0 auto; }
679
- h1 { font-size: 24px; margin: 0 0 20px 0; }
680
- p { margin: 0 0 15px 0; }
681
- </style>
682
- </head>
683
- <body>
684
- <div class="container">
685
- <h1>Two-Factor Authentication Enabled</h1>
686
- <p>{{#if greetingName}}Hi {{greetingName}},{{else}}Hi,{{/if}}</p>
687
- <p>Two-factor authentication has been successfully enabled for your account.</p>
688
-
689
- <p>Your account is now more secure. You'll need to provide both your password and a verification code when logging in.</p>
690
-
691
- <p>If you didn't enable this feature, please contact support immediately at {{supportEmail}}.</p>
692
- </div>
693
- </body>
694
- </html>
695
- `,
696
- text: `
697
- Two-Factor Authentication Enabled
698
-
699
- {{#if greetingName}}Hi {{greetingName}},{{else}}Hi,{{/if}}
700
-
701
- Two-factor authentication has been successfully enabled for your account.
702
-
703
- Your account is now more secure. You'll need to provide both your password and a verification code when logging in.
704
-
705
- If you didn't enable this feature, please contact support immediately at {{supportEmail}}.
706
- `,
707
- });
708
- }
709
- }
710
- exports.HtmlTemplateEngine = HtmlTemplateEngine;
711
- //# sourceMappingURL=html-template.engine.js.map