@flusys/nestjs-email 1.1.0-beta

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 (124) hide show
  1. package/cjs/config/email-config.service.js +94 -0
  2. package/cjs/config/email.constants.js +40 -0
  3. package/cjs/config/index.js +19 -0
  4. package/cjs/controllers/email-config.controller.js +59 -0
  5. package/cjs/controllers/email-send.controller.js +142 -0
  6. package/cjs/controllers/email-template.controller.js +84 -0
  7. package/cjs/controllers/index.js +20 -0
  8. package/cjs/docs/email-swagger.config.js +176 -0
  9. package/cjs/docs/index.js +11 -0
  10. package/cjs/dtos/email-config.dto.js +238 -0
  11. package/cjs/dtos/email-send.dto.js +376 -0
  12. package/cjs/dtos/email-template.dto.js +283 -0
  13. package/cjs/dtos/index.js +20 -0
  14. package/cjs/entities/email-config-base.entity.js +111 -0
  15. package/cjs/entities/email-config-with-company.entity.js +63 -0
  16. package/cjs/entities/email-config.entity.js +25 -0
  17. package/cjs/entities/email-template-base.entity.js +134 -0
  18. package/cjs/entities/email-template-with-company.entity.js +63 -0
  19. package/cjs/entities/email-template.entity.js +25 -0
  20. package/cjs/entities/index.js +41 -0
  21. package/cjs/enums/email-provider-type.enum.js +18 -0
  22. package/cjs/enums/index.js +18 -0
  23. package/cjs/index.js +27 -0
  24. package/cjs/interfaces/email-config.interface.js +4 -0
  25. package/cjs/interfaces/email-module-options.interface.js +4 -0
  26. package/cjs/interfaces/email-provider.interface.js +6 -0
  27. package/cjs/interfaces/email-template.interface.js +4 -0
  28. package/cjs/interfaces/index.js +21 -0
  29. package/cjs/modules/email.module.js +177 -0
  30. package/cjs/modules/index.js +18 -0
  31. package/cjs/providers/email-factory.service.js +160 -0
  32. package/cjs/providers/email-provider.registry.js +51 -0
  33. package/cjs/providers/index.js +22 -0
  34. package/cjs/providers/mailgun-provider.js +125 -0
  35. package/cjs/providers/sendgrid-provider.js +156 -0
  36. package/cjs/providers/smtp-provider.js +185 -0
  37. package/cjs/services/email-datasource.provider.js +215 -0
  38. package/cjs/services/email-provider-config.service.js +180 -0
  39. package/cjs/services/email-send.service.js +228 -0
  40. package/cjs/services/email-template.service.js +186 -0
  41. package/cjs/services/index.js +21 -0
  42. package/config/email-config.service.d.ts +13 -0
  43. package/config/email.constants.d.ts +11 -0
  44. package/config/index.d.ts +2 -0
  45. package/controllers/email-config.controller.d.ts +17 -0
  46. package/controllers/email-send.controller.d.ts +19 -0
  47. package/controllers/email-template.controller.d.ts +25 -0
  48. package/controllers/index.d.ts +3 -0
  49. package/docs/email-swagger.config.d.ts +3 -0
  50. package/docs/index.d.ts +1 -0
  51. package/dtos/email-config.dto.d.ts +33 -0
  52. package/dtos/email-send.dto.d.ts +45 -0
  53. package/dtos/email-template.dto.d.ts +42 -0
  54. package/dtos/index.d.ts +3 -0
  55. package/entities/email-config-base.entity.d.ts +11 -0
  56. package/entities/email-config-with-company.entity.d.ts +4 -0
  57. package/entities/email-config.entity.d.ts +3 -0
  58. package/entities/email-template-base.entity.d.ts +14 -0
  59. package/entities/email-template-with-company.entity.d.ts +4 -0
  60. package/entities/email-template.entity.d.ts +3 -0
  61. package/entities/index.d.ts +7 -0
  62. package/enums/email-provider-type.enum.d.ts +5 -0
  63. package/enums/index.d.ts +1 -0
  64. package/fesm/config/email-config.service.js +84 -0
  65. package/fesm/config/email.constants.js +13 -0
  66. package/fesm/config/index.js +2 -0
  67. package/fesm/controllers/email-config.controller.js +49 -0
  68. package/fesm/controllers/email-send.controller.js +132 -0
  69. package/fesm/controllers/email-template.controller.js +74 -0
  70. package/fesm/controllers/index.js +3 -0
  71. package/fesm/docs/email-swagger.config.js +172 -0
  72. package/fesm/docs/index.js +1 -0
  73. package/fesm/dtos/email-config.dto.js +223 -0
  74. package/fesm/dtos/email-send.dto.js +360 -0
  75. package/fesm/dtos/email-template.dto.js +268 -0
  76. package/fesm/dtos/index.js +3 -0
  77. package/fesm/entities/email-config-base.entity.js +101 -0
  78. package/fesm/entities/email-config-with-company.entity.js +53 -0
  79. package/fesm/entities/email-config.entity.js +15 -0
  80. package/fesm/entities/email-template-base.entity.js +124 -0
  81. package/fesm/entities/email-template-with-company.entity.js +53 -0
  82. package/fesm/entities/email-template.entity.js +15 -0
  83. package/fesm/entities/index.js +20 -0
  84. package/fesm/enums/email-provider-type.enum.js +8 -0
  85. package/fesm/enums/index.js +1 -0
  86. package/fesm/index.js +10 -0
  87. package/fesm/interfaces/email-config.interface.js +3 -0
  88. package/fesm/interfaces/email-module-options.interface.js +3 -0
  89. package/fesm/interfaces/email-provider.interface.js +5 -0
  90. package/fesm/interfaces/email-template.interface.js +3 -0
  91. package/fesm/interfaces/index.js +4 -0
  92. package/fesm/modules/email.module.js +167 -0
  93. package/fesm/modules/index.js +1 -0
  94. package/fesm/providers/email-factory.service.js +109 -0
  95. package/fesm/providers/email-provider.registry.js +44 -0
  96. package/fesm/providers/index.js +5 -0
  97. package/fesm/providers/mailgun-provider.js +119 -0
  98. package/fesm/providers/sendgrid-provider.js +150 -0
  99. package/fesm/providers/smtp-provider.js +137 -0
  100. package/fesm/services/email-datasource.provider.js +164 -0
  101. package/fesm/services/email-provider-config.service.js +170 -0
  102. package/fesm/services/email-send.service.js +218 -0
  103. package/fesm/services/email-template.service.js +176 -0
  104. package/fesm/services/index.js +4 -0
  105. package/index.d.ts +9 -0
  106. package/interfaces/email-config.interface.d.ts +28 -0
  107. package/interfaces/email-module-options.interface.d.ts +26 -0
  108. package/interfaces/email-provider.interface.d.ts +34 -0
  109. package/interfaces/email-template.interface.d.ts +64 -0
  110. package/interfaces/index.d.ts +4 -0
  111. package/modules/email.module.d.ts +9 -0
  112. package/modules/index.d.ts +1 -0
  113. package/package.json +105 -0
  114. package/providers/email-factory.service.d.ts +14 -0
  115. package/providers/email-provider.registry.d.ts +10 -0
  116. package/providers/index.d.ts +5 -0
  117. package/providers/mailgun-provider.d.ts +11 -0
  118. package/providers/sendgrid-provider.d.ts +11 -0
  119. package/providers/smtp-provider.d.ts +11 -0
  120. package/services/email-datasource.provider.d.ts +25 -0
  121. package/services/email-provider-config.service.d.ts +32 -0
  122. package/services/email-send.service.d.ts +20 -0
  123. package/services/email-template.service.d.ts +31 -0
  124. package/services/index.d.ts +4 -0
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "MailgunProvider", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return MailgunProvider;
9
+ }
10
+ });
11
+ const _common = require("@nestjs/common");
12
+ function _define_property(obj, key, value) {
13
+ if (key in obj) {
14
+ Object.defineProperty(obj, key, {
15
+ value: value,
16
+ enumerable: true,
17
+ configurable: true,
18
+ writable: true
19
+ });
20
+ } else {
21
+ obj[key] = value;
22
+ }
23
+ return obj;
24
+ }
25
+ let MailgunProvider = class MailgunProvider {
26
+ /**
27
+ * Initialize the Mailgun provider with configuration
28
+ */ async initialize(config) {
29
+ this.config = config;
30
+ try {
31
+ // Dynamic import mailgun.js and form-data - use eval to bypass TypeScript module resolution
32
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval
33
+ const Mailgun = (await new Function('return import("mailgun.js")')()).default;
34
+ const FormData = (await new Function('return import("form-data")')()).default;
35
+ const mailgun = new Mailgun(FormData);
36
+ // Determine API URL based on region
37
+ const url = config.region === 'eu' ? 'https://api.eu.mailgun.net' : 'https://api.mailgun.net';
38
+ this.client = mailgun.client({
39
+ username: 'api',
40
+ key: config.apiKey,
41
+ url
42
+ });
43
+ this.logger.log(`Mailgun Provider initialized for domain: ${config.domain}`);
44
+ } catch (error) {
45
+ this.logger.error('Failed to initialize Mailgun:', error.message);
46
+ throw new Error('Mailgun initialization failed. Make sure mailgun.js and form-data are installed: npm install mailgun.js form-data');
47
+ }
48
+ }
49
+ /**
50
+ * Send a single email
51
+ */ async sendEmail(options) {
52
+ if (!this.client || !this.config) {
53
+ return {
54
+ success: false,
55
+ error: 'Mailgun provider not initialized'
56
+ };
57
+ }
58
+ try {
59
+ const to = Array.isArray(options.to) ? options.to.join(', ') : options.to;
60
+ const cc = options.cc ? Array.isArray(options.cc) ? options.cc.join(', ') : options.cc : undefined;
61
+ const bcc = options.bcc ? Array.isArray(options.bcc) ? options.bcc.join(', ') : options.bcc : undefined;
62
+ const messageData = {
63
+ from: options.fromName ? `${options.fromName} <${options.from}>` : options.from,
64
+ to,
65
+ subject: options.subject
66
+ };
67
+ // Only include html/text if they have values (required for plain text templates)
68
+ if (options.html) messageData.html = options.html;
69
+ if (options.text) messageData.text = options.text;
70
+ // Optional fields
71
+ if (cc) messageData.cc = cc;
72
+ if (bcc) messageData.bcc = bcc;
73
+ if (options.replyTo) messageData['h:Reply-To'] = options.replyTo;
74
+ // Handle attachments
75
+ if (options.attachments && options.attachments.length > 0) {
76
+ messageData.attachment = options.attachments.map((a)=>({
77
+ filename: a.filename,
78
+ data: typeof a.content === 'string' ? Buffer.from(a.content, 'base64') : a.content,
79
+ contentType: a.contentType
80
+ }));
81
+ }
82
+ const result = await this.client.messages.create(this.config.domain, messageData);
83
+ this.logger.log(`Email sent via Mailgun: ${result.id}`);
84
+ return {
85
+ success: true,
86
+ messageId: result.id
87
+ };
88
+ } catch (error) {
89
+ this.logger.error('Mailgun send failed:', error);
90
+ return {
91
+ success: false,
92
+ error: error.message
93
+ };
94
+ }
95
+ }
96
+ /**
97
+ * Send multiple emails (batch)
98
+ */ async sendBulkEmails(options) {
99
+ // Mailgun supports batch sending with recipient variables
100
+ // For simplicity, we send individually here
101
+ return Promise.all(options.map((opt)=>this.sendEmail(opt)));
102
+ }
103
+ /**
104
+ * Health check for the provider
105
+ */ async healthCheck() {
106
+ if (!this.client || !this.config) return false;
107
+ try {
108
+ // Verify domain exists
109
+ await this.client.domains.get(this.config.domain);
110
+ return true;
111
+ } catch {
112
+ return false;
113
+ }
114
+ }
115
+ /**
116
+ * Cleanup
117
+ */ async close() {
118
+ this.client = null;
119
+ }
120
+ constructor(){
121
+ _define_property(this, "logger", new _common.Logger(MailgunProvider.name));
122
+ _define_property(this, "client", null);
123
+ _define_property(this, "config", null);
124
+ }
125
+ };
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "SendGridProvider", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return SendGridProvider;
9
+ }
10
+ });
11
+ const _common = require("@nestjs/common");
12
+ function _define_property(obj, key, value) {
13
+ if (key in obj) {
14
+ Object.defineProperty(obj, key, {
15
+ value: value,
16
+ enumerable: true,
17
+ configurable: true,
18
+ writable: true
19
+ });
20
+ } else {
21
+ obj[key] = value;
22
+ }
23
+ return obj;
24
+ }
25
+ let SendGridProvider = class SendGridProvider {
26
+ /**
27
+ * Initialize the SendGrid provider with configuration
28
+ */ async initialize(config) {
29
+ this.config = config;
30
+ try {
31
+ // Dynamic import @sendgrid/mail - use eval to bypass TypeScript module resolution
32
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval
33
+ const sgMailModule = await new Function('return import("@sendgrid/mail")')();
34
+ this.sgMail = sgMailModule.default || sgMailModule;
35
+ this.sgMail.setApiKey(config.apiKey);
36
+ this.logger.log('SendGrid Provider initialized');
37
+ } catch (error) {
38
+ this.logger.error('Failed to initialize SendGrid:', error.message);
39
+ throw new Error('SendGrid initialization failed. Make sure @sendgrid/mail is installed: npm install @sendgrid/mail');
40
+ }
41
+ }
42
+ /**
43
+ * Send a single email
44
+ */ async sendEmail(options) {
45
+ if (!this.sgMail) {
46
+ return {
47
+ success: false,
48
+ error: 'SendGrid provider not initialized'
49
+ };
50
+ }
51
+ try {
52
+ const msg = {
53
+ to: Array.isArray(options.to) ? options.to : [
54
+ options.to
55
+ ],
56
+ from: options.fromName ? {
57
+ email: options.from,
58
+ name: options.fromName
59
+ } : options.from,
60
+ subject: options.subject
61
+ };
62
+ // Only include html/text if they have values (required for plain text templates)
63
+ if (options.html) msg.html = options.html;
64
+ if (options.text) msg.text = options.text;
65
+ // Optional fields
66
+ if (options.cc) {
67
+ msg.cc = Array.isArray(options.cc) ? options.cc : [
68
+ options.cc
69
+ ];
70
+ }
71
+ if (options.bcc) {
72
+ msg.bcc = Array.isArray(options.bcc) ? options.bcc : [
73
+ options.bcc
74
+ ];
75
+ }
76
+ if (options.replyTo) msg.replyTo = options.replyTo;
77
+ if (options.attachments?.length) {
78
+ msg.attachments = options.attachments.map((a)=>({
79
+ filename: a.filename,
80
+ content: typeof a.content === 'string' ? a.content : a.content.toString('base64'),
81
+ type: a.contentType,
82
+ disposition: 'attachment'
83
+ }));
84
+ }
85
+ const [response] = await this.sgMail.send(msg);
86
+ const messageId = response.headers['x-message-id'] || response.headers['X-Message-Id'];
87
+ this.logger.log(`Email sent via SendGrid: ${messageId}`);
88
+ return {
89
+ success: true,
90
+ messageId
91
+ };
92
+ } catch (error) {
93
+ this.logger.error('SendGrid send failed:', error);
94
+ const errorMessage = error.response?.body?.errors?.[0]?.message || error.message;
95
+ return {
96
+ success: false,
97
+ error: errorMessage
98
+ };
99
+ }
100
+ }
101
+ /**
102
+ * Send multiple emails (batch)
103
+ */ async sendBulkEmails(options) {
104
+ if (!this.sgMail) {
105
+ return options.map(()=>({
106
+ success: false,
107
+ error: 'SendGrid provider not initialized'
108
+ }));
109
+ }
110
+ // SendGrid supports batch sending with sendMultiple
111
+ const messages = options.map((opt)=>{
112
+ const msg = {
113
+ to: Array.isArray(opt.to) ? opt.to : [
114
+ opt.to
115
+ ],
116
+ from: opt.fromName ? {
117
+ email: opt.from,
118
+ name: opt.fromName
119
+ } : opt.from,
120
+ subject: opt.subject
121
+ };
122
+ if (opt.html) msg.html = opt.html;
123
+ if (opt.text) msg.text = opt.text;
124
+ return msg;
125
+ });
126
+ try {
127
+ await this.sgMail.send(messages);
128
+ return options.map(()=>({
129
+ success: true
130
+ }));
131
+ } catch (error) {
132
+ this.logger.error('SendGrid bulk send failed:', error);
133
+ return options.map(()=>({
134
+ success: false,
135
+ error: error.message
136
+ }));
137
+ }
138
+ }
139
+ /**
140
+ * Health check for the provider
141
+ */ async healthCheck() {
142
+ // SendGrid doesn't have a direct health check API
143
+ // We verify the API key format is valid
144
+ return !!(this.sgMail && this.config?.apiKey?.startsWith('SG.'));
145
+ }
146
+ /**
147
+ * Cleanup (no-op for SendGrid)
148
+ */ async close() {
149
+ this.sgMail = null;
150
+ }
151
+ constructor(){
152
+ _define_property(this, "logger", new _common.Logger(SendGridProvider.name));
153
+ _define_property(this, "sgMail", null);
154
+ _define_property(this, "config", null);
155
+ }
156
+ };
@@ -0,0 +1,185 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "SmtpProvider", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return SmtpProvider;
9
+ }
10
+ });
11
+ const _common = require("@nestjs/common");
12
+ function _define_property(obj, key, value) {
13
+ if (key in obj) {
14
+ Object.defineProperty(obj, key, {
15
+ value: value,
16
+ enumerable: true,
17
+ configurable: true,
18
+ writable: true
19
+ });
20
+ } else {
21
+ obj[key] = value;
22
+ }
23
+ return obj;
24
+ }
25
+ function _getRequireWildcardCache(nodeInterop) {
26
+ if (typeof WeakMap !== "function") return null;
27
+ var cacheBabelInterop = new WeakMap();
28
+ var cacheNodeInterop = new WeakMap();
29
+ return (_getRequireWildcardCache = function(nodeInterop) {
30
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
31
+ })(nodeInterop);
32
+ }
33
+ function _interop_require_wildcard(obj, nodeInterop) {
34
+ if (!nodeInterop && obj && obj.__esModule) {
35
+ return obj;
36
+ }
37
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
38
+ return {
39
+ default: obj
40
+ };
41
+ }
42
+ var cache = _getRequireWildcardCache(nodeInterop);
43
+ if (cache && cache.has(obj)) {
44
+ return cache.get(obj);
45
+ }
46
+ var newObj = {
47
+ __proto__: null
48
+ };
49
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
50
+ for(var key in obj){
51
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
52
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
53
+ if (desc && (desc.get || desc.set)) {
54
+ Object.defineProperty(newObj, key, desc);
55
+ } else {
56
+ newObj[key] = obj[key];
57
+ }
58
+ }
59
+ }
60
+ newObj.default = obj;
61
+ if (cache) {
62
+ cache.set(obj, newObj);
63
+ }
64
+ return newObj;
65
+ }
66
+ let SmtpProvider = class SmtpProvider {
67
+ /**
68
+ * Initialize the SMTP provider with configuration
69
+ */ async initialize(config) {
70
+ this.config = config;
71
+ this.logger.log(`Initializing SMTP: host=${config.host}, port=${config.port}, secure=${config.secure}, user=${config.auth?.user}`);
72
+ // Dynamic import nodemailer
73
+ const nodemailer = await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("nodemailer")));
74
+ // Determine secure mode: port 465 = implicit TLS, port 587 = STARTTLS
75
+ const isSecure = config.secure ?? config.port === 465;
76
+ this.transporter = nodemailer.createTransport({
77
+ host: config.host,
78
+ port: config.port,
79
+ secure: isSecure,
80
+ auth: config.auth,
81
+ // Timeout settings to prevent hanging
82
+ connectionTimeout: 10000,
83
+ greetingTimeout: 10000,
84
+ socketTimeout: 30000,
85
+ // TLS options for better compatibility
86
+ tls: {
87
+ rejectUnauthorized: false,
88
+ minVersion: 'TLSv1.2'
89
+ }
90
+ });
91
+ this.logger.log(`SMTP transporter created with secure=${isSecure}`);
92
+ // Verify connection with timeout
93
+ try {
94
+ const verifyPromise = this.transporter.verify();
95
+ const timeoutPromise = new Promise((_, reject)=>setTimeout(()=>reject(new Error('SMTP verification timeout')), 10000));
96
+ await Promise.race([
97
+ verifyPromise,
98
+ timeoutPromise
99
+ ]);
100
+ this.logger.log(`SMTP Provider verified successfully: ${config.host}:${config.port}`);
101
+ } catch (error) {
102
+ this.logger.warn(`SMTP verification failed: ${error.message}`);
103
+ // Don't throw - allow initialization even if verification fails
104
+ // Connection will be retried on send
105
+ }
106
+ }
107
+ /**
108
+ * Send a single email
109
+ */ async sendEmail(options) {
110
+ if (!this.transporter) {
111
+ return {
112
+ success: false,
113
+ error: 'SMTP provider not initialized'
114
+ };
115
+ }
116
+ const toAddress = Array.isArray(options.to) ? options.to.join(', ') : options.to;
117
+ this.logger.log(`Sending email to: ${toAddress}, subject: ${options.subject}`);
118
+ try {
119
+ const mailOptions = {
120
+ from: options.fromName ? `"${options.fromName}" <${options.from}>` : options.from,
121
+ to: toAddress,
122
+ cc: options.cc ? Array.isArray(options.cc) ? options.cc.join(', ') : options.cc : undefined,
123
+ bcc: options.bcc ? Array.isArray(options.bcc) ? options.bcc.join(', ') : options.bcc : undefined,
124
+ subject: options.subject,
125
+ text: options.text,
126
+ html: options.html,
127
+ replyTo: options.replyTo,
128
+ attachments: options.attachments?.map((a)=>({
129
+ filename: a.filename,
130
+ content: a.content,
131
+ contentType: a.contentType,
132
+ encoding: a.encoding
133
+ }))
134
+ };
135
+ this.logger.log(`Mail options: from=${mailOptions.from}, to=${mailOptions.to}`);
136
+ // Send with timeout
137
+ const sendPromise = this.transporter.sendMail(mailOptions);
138
+ const timeoutPromise = new Promise((_, reject)=>setTimeout(()=>reject(new Error('SMTP send timeout after 30 seconds')), 30000));
139
+ const info = await Promise.race([
140
+ sendPromise,
141
+ timeoutPromise
142
+ ]);
143
+ this.logger.log(`Email sent via SMTP: ${info.messageId}`);
144
+ return {
145
+ success: true,
146
+ messageId: info.messageId
147
+ };
148
+ } catch (error) {
149
+ this.logger.error(`SMTP send failed: ${error.message}`, error.stack);
150
+ return {
151
+ success: false,
152
+ error: error.message
153
+ };
154
+ }
155
+ }
156
+ /**
157
+ * Send multiple emails (batch)
158
+ */ async sendBulkEmails(options) {
159
+ return Promise.all(options.map((opt)=>this.sendEmail(opt)));
160
+ }
161
+ /**
162
+ * Health check for the provider
163
+ */ async healthCheck() {
164
+ if (!this.transporter) return false;
165
+ try {
166
+ await this.transporter.verify();
167
+ return true;
168
+ } catch {
169
+ return false;
170
+ }
171
+ }
172
+ /**
173
+ * Close the transporter
174
+ */ async close() {
175
+ if (this.transporter) {
176
+ this.transporter.close();
177
+ this.transporter = null;
178
+ }
179
+ }
180
+ constructor(){
181
+ _define_property(this, "logger", new _common.Logger(SmtpProvider.name));
182
+ _define_property(this, "transporter", null);
183
+ _define_property(this, "config", null);
184
+ }
185
+ };
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "EmailDataSourceProvider", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return EmailDataSourceProvider;
9
+ }
10
+ });
11
+ const _modules = require("@flusys/nestjs-shared/modules");
12
+ const _common = require("@nestjs/common");
13
+ const _core = require("@nestjs/core");
14
+ const _express = require("express");
15
+ const _interfaces = require("../interfaces");
16
+ const _emailconstants = require("../config/email.constants");
17
+ function _define_property(obj, key, value) {
18
+ if (key in obj) {
19
+ Object.defineProperty(obj, key, {
20
+ value: value,
21
+ enumerable: true,
22
+ configurable: true,
23
+ writable: true
24
+ });
25
+ } else {
26
+ obj[key] = value;
27
+ }
28
+ return obj;
29
+ }
30
+ function _getRequireWildcardCache(nodeInterop) {
31
+ if (typeof WeakMap !== "function") return null;
32
+ var cacheBabelInterop = new WeakMap();
33
+ var cacheNodeInterop = new WeakMap();
34
+ return (_getRequireWildcardCache = function(nodeInterop) {
35
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
36
+ })(nodeInterop);
37
+ }
38
+ function _interop_require_wildcard(obj, nodeInterop) {
39
+ if (!nodeInterop && obj && obj.__esModule) {
40
+ return obj;
41
+ }
42
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
43
+ return {
44
+ default: obj
45
+ };
46
+ }
47
+ var cache = _getRequireWildcardCache(nodeInterop);
48
+ if (cache && cache.has(obj)) {
49
+ return cache.get(obj);
50
+ }
51
+ var newObj = {
52
+ __proto__: null
53
+ };
54
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
55
+ for(var key in obj){
56
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
57
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
58
+ if (desc && (desc.get || desc.set)) {
59
+ Object.defineProperty(newObj, key, desc);
60
+ } else {
61
+ newObj[key] = obj[key];
62
+ }
63
+ }
64
+ }
65
+ newObj.default = obj;
66
+ if (cache) {
67
+ cache.set(obj, newObj);
68
+ }
69
+ return newObj;
70
+ }
71
+ function _ts_decorate(decorators, target, key, desc) {
72
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
73
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
74
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
75
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
76
+ }
77
+ function _ts_metadata(k, v) {
78
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
79
+ }
80
+ function _ts_param(paramIndex, decorator) {
81
+ return function(target, key) {
82
+ decorator(target, key, paramIndex);
83
+ };
84
+ }
85
+ let EmailDataSourceProvider = class EmailDataSourceProvider extends _modules.MultiTenantDataSourceService {
86
+ // ==================== Factory Methods ====================
87
+ /**
88
+ * Build parent options from EmailModuleOptions
89
+ */ static buildParentOptions(options) {
90
+ return {
91
+ bootstrapAppConfig: options.bootstrapAppConfig,
92
+ defaultDatabaseConfig: options.config?.defaultDatabaseConfig,
93
+ tenantDefaultDatabaseConfig: options.config?.tenantDefaultDatabaseConfig,
94
+ tenants: options.config?.tenants
95
+ };
96
+ }
97
+ // ==================== Feature Flags ====================
98
+ /**
99
+ * Get global enable company feature flag
100
+ */ getEnableCompanyFeature() {
101
+ return this.emailOptions.bootstrapAppConfig?.enableCompanyFeature ?? false;
102
+ }
103
+ /**
104
+ * Get enable company feature for specific tenant
105
+ * Falls back to global setting if not specified per-tenant
106
+ */ getEnableCompanyFeatureForTenant(tenant) {
107
+ return tenant?.enableCompanyFeature ?? this.getEnableCompanyFeature();
108
+ }
109
+ /**
110
+ * Get enable company feature for current request context
111
+ */ getEnableCompanyFeatureForCurrentTenant() {
112
+ return this.getEnableCompanyFeatureForTenant(this.getCurrentTenant() ?? undefined);
113
+ }
114
+ // ==================== Entity Management ====================
115
+ /**
116
+ * Get email entities for migrations based on company feature flag
117
+ */ async getEmailEntities(enableCompanyFeature) {
118
+ const enable = enableCompanyFeature ?? this.getEnableCompanyFeature();
119
+ const { EmailConfig, EmailTemplate } = await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../entities")));
120
+ if (enable) {
121
+ const { EmailConfigWithCompany, EmailTemplateWithCompany } = await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../entities")));
122
+ return [
123
+ EmailConfigWithCompany,
124
+ EmailTemplateWithCompany
125
+ ];
126
+ }
127
+ return [
128
+ EmailConfig,
129
+ EmailTemplate
130
+ ];
131
+ }
132
+ // ==================== Overrides ====================
133
+ /**
134
+ * Override to dynamically set entities based on tenant config
135
+ */ async createDataSourceFromConfig(config) {
136
+ const currentTenant = this.getCurrentTenant();
137
+ const enableCompanyFeature = this.getEnableCompanyFeatureForTenant(currentTenant ?? undefined);
138
+ const entities = await this.getEmailEntities(enableCompanyFeature);
139
+ return super.createDataSourceFromConfig(config, entities);
140
+ }
141
+ /**
142
+ * Override to use Email-specific static cache
143
+ */ async getSingleDataSource() {
144
+ // Return existing initialized connection from Email-specific cache
145
+ if (EmailDataSourceProvider.singleDataSource?.isInitialized) {
146
+ return EmailDataSourceProvider.singleDataSource;
147
+ }
148
+ // If another request is creating the connection, wait for it
149
+ if (EmailDataSourceProvider.singleConnectionLock) {
150
+ return EmailDataSourceProvider.singleConnectionLock;
151
+ }
152
+ const config = this.getDefaultDatabaseConfig();
153
+ if (!config) {
154
+ throw new Error('No database config available. Provide defaultDatabaseConfig or tenantDefaultDatabaseConfig.');
155
+ }
156
+ // Create connection with lock to prevent race conditions
157
+ const connectionPromise = this.createDataSourceFromConfig(config);
158
+ EmailDataSourceProvider.singleConnectionLock = connectionPromise;
159
+ try {
160
+ const dataSource = await connectionPromise;
161
+ EmailDataSourceProvider.singleDataSource = dataSource;
162
+ return dataSource;
163
+ } finally{
164
+ EmailDataSourceProvider.singleConnectionLock = null;
165
+ }
166
+ }
167
+ /**
168
+ * Override to use Email-specific static cache for tenant connections
169
+ */ async getOrCreateTenantConnection(tenant) {
170
+ // Return existing initialized connection from Email-specific cache
171
+ const existing = EmailDataSourceProvider.tenantConnections.get(tenant.id);
172
+ if (existing?.isInitialized) {
173
+ return existing;
174
+ }
175
+ // If another request is creating this tenant's connection, wait for it
176
+ const pendingConnection = EmailDataSourceProvider.connectionLocks.get(tenant.id);
177
+ if (pendingConnection) {
178
+ return pendingConnection;
179
+ }
180
+ // Create connection with lock to prevent race conditions
181
+ const config = this.buildTenantDatabaseConfig(tenant);
182
+ const connectionPromise = this.createDataSourceFromConfig(config);
183
+ EmailDataSourceProvider.connectionLocks.set(tenant.id, connectionPromise);
184
+ try {
185
+ const dataSource = await connectionPromise;
186
+ EmailDataSourceProvider.tenantConnections.set(tenant.id, dataSource);
187
+ return dataSource;
188
+ } finally{
189
+ EmailDataSourceProvider.connectionLocks.delete(tenant.id);
190
+ }
191
+ }
192
+ constructor(emailOptions, request){
193
+ super(EmailDataSourceProvider.buildParentOptions(emailOptions), request), _define_property(this, "emailOptions", void 0), _define_property(this, "logger", void 0), this.emailOptions = emailOptions, this.logger = new _common.Logger(EmailDataSourceProvider.name);
194
+ }
195
+ };
196
+ // Override parent's static properties to have Email-specific cache
197
+ _define_property(EmailDataSourceProvider, "tenantConnections", new Map());
198
+ _define_property(EmailDataSourceProvider, "singleDataSource", null);
199
+ _define_property(EmailDataSourceProvider, "tenantsRegistry", new Map());
200
+ _define_property(EmailDataSourceProvider, "initialized", false);
201
+ _define_property(EmailDataSourceProvider, "connectionLocks", new Map());
202
+ _define_property(EmailDataSourceProvider, "singleConnectionLock", null);
203
+ EmailDataSourceProvider = _ts_decorate([
204
+ (0, _common.Injectable)({
205
+ scope: _common.Scope.REQUEST
206
+ }),
207
+ _ts_param(0, (0, _common.Inject)(_emailconstants.EMAIL_MODULE_OPTIONS)),
208
+ _ts_param(1, (0, _common.Optional)()),
209
+ _ts_param(1, (0, _common.Inject)(_core.REQUEST)),
210
+ _ts_metadata("design:type", Function),
211
+ _ts_metadata("design:paramtypes", [
212
+ typeof _interfaces.EmailModuleOptions === "undefined" ? Object : _interfaces.EmailModuleOptions,
213
+ typeof _express.Request === "undefined" ? Object : _express.Request
214
+ ])
215
+ ], EmailDataSourceProvider);