@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,180 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "EmailProviderConfigService", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return EmailProviderConfigService;
9
+ }
10
+ });
11
+ const _classes = require("@flusys/nestjs-shared/classes");
12
+ const _modules = require("@flusys/nestjs-shared/modules");
13
+ const _common = require("@nestjs/common");
14
+ const _config = require("../config");
15
+ const _entities = require("../entities");
16
+ const _emaildatasourceprovider = require("./email-datasource.provider");
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 _ts_decorate(decorators, target, key, desc) {
31
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
32
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
33
+ 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;
34
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
35
+ }
36
+ function _ts_metadata(k, v) {
37
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
38
+ }
39
+ function _ts_param(paramIndex, decorator) {
40
+ return function(target, key) {
41
+ decorator(target, key, paramIndex);
42
+ };
43
+ }
44
+ let EmailProviderConfigService = class EmailProviderConfigService extends _classes.RequestScopedApiService {
45
+ /**
46
+ * Resolve entity class for this service
47
+ */ resolveEntity() {
48
+ const enableCompanyFeature = this.emailConfig.isCompanyFeatureEnabled();
49
+ return enableCompanyFeature ? _entities.EmailConfigWithCompany : _entities.EmailConfig;
50
+ }
51
+ /**
52
+ * Get DataSource provider for this service
53
+ */ getDataSourceProvider() {
54
+ return this.dataSourceProvider;
55
+ }
56
+ async convertSingleDtoToEntity(dto, user) {
57
+ let emailConfigEntity = {
58
+ ...dto
59
+ };
60
+ // Set company fields if company feature is enabled
61
+ if (this.emailConfig.isCompanyFeatureEnabled()) {
62
+ emailConfigEntity.companyId = user?.companyId ?? null;
63
+ }
64
+ return emailConfigEntity;
65
+ }
66
+ async getSelectQuery(query, _user, select) {
67
+ if (!select || !select.length) {
68
+ select = [
69
+ 'id',
70
+ 'name',
71
+ 'provider',
72
+ 'config',
73
+ 'fromEmail',
74
+ 'fromName',
75
+ 'isActive',
76
+ 'isDefault',
77
+ 'createdAt',
78
+ 'updatedAt'
79
+ ];
80
+ if (this.emailConfig.isCompanyFeatureEnabled()) {
81
+ select.push('companyId');
82
+ }
83
+ }
84
+ const selectFields = select.map((field)=>`${this.entityName}.${field}`);
85
+ query.select(selectFields);
86
+ return {
87
+ query,
88
+ isRaw: false
89
+ };
90
+ }
91
+ /**
92
+ * Override: Extra query manipulation - Auto-filter by user's company
93
+ */ async getExtraManipulateQuery(query, filterDto, user) {
94
+ const result = await super.getExtraManipulateQuery(query, filterDto, user);
95
+ const enableCompanyFeature = this.emailConfig.isCompanyFeatureEnabled();
96
+ if (enableCompanyFeature && user?.companyId) {
97
+ query.andWhere('emailConfig.companyId = :companyId', {
98
+ companyId: user.companyId
99
+ });
100
+ }
101
+ query.orderBy(`${this.entityName}.createdAt`, 'DESC');
102
+ return result;
103
+ }
104
+ /**
105
+ * Find config by ID directly (bypasses company filtering)
106
+ */ async findByIdDirect(id) {
107
+ await this.ensureRepositoryInitialized();
108
+ return await this.repository.findOne({
109
+ where: {
110
+ id
111
+ }
112
+ });
113
+ }
114
+ /**
115
+ * Get default email configuration (scoped to user's company if enabled)
116
+ * Priority: isDefault=true > any active config (oldest first)
117
+ */ async getDefaultConfig(user) {
118
+ await this.ensureRepositoryInitialized();
119
+ const baseWhere = {
120
+ isActive: true
121
+ };
122
+ if (this.emailConfig.isCompanyFeatureEnabled() && user?.companyId) {
123
+ baseWhere.companyId = user.companyId;
124
+ }
125
+ // First try to find config marked as default
126
+ const defaultConfig = await this.repository.findOne({
127
+ where: {
128
+ ...baseWhere,
129
+ isDefault: true
130
+ },
131
+ order: {
132
+ createdAt: 'ASC'
133
+ }
134
+ });
135
+ if (defaultConfig) {
136
+ return defaultConfig;
137
+ }
138
+ // Fall back to any available active config (oldest first for consistency)
139
+ return await this.repository.findOne({
140
+ where: baseWhere,
141
+ order: {
142
+ createdAt: 'ASC'
143
+ }
144
+ });
145
+ }
146
+ /**
147
+ * Get config by provider type
148
+ */ async getConfigByProvider(provider, user) {
149
+ await this.ensureRepositoryInitialized();
150
+ const where = {
151
+ provider,
152
+ isActive: true
153
+ };
154
+ if (this.emailConfig.isCompanyFeatureEnabled() && user?.companyId) {
155
+ where.companyId = user.companyId;
156
+ }
157
+ return await this.repository.find({
158
+ where
159
+ });
160
+ }
161
+ constructor(cacheManager, utilsService, emailConfig, dataSourceProvider){
162
+ super('emailConfig', null, cacheManager, utilsService, EmailProviderConfigService.name, true), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "emailConfig", void 0), _define_property(this, "dataSourceProvider", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.emailConfig = emailConfig, this.dataSourceProvider = dataSourceProvider;
163
+ }
164
+ };
165
+ EmailProviderConfigService = _ts_decorate([
166
+ (0, _common.Injectable)({
167
+ scope: _common.Scope.REQUEST
168
+ }),
169
+ _ts_param(0, (0, _common.Inject)('CACHE_INSTANCE')),
170
+ _ts_param(1, (0, _common.Inject)(_modules.UtilsService)),
171
+ _ts_param(2, (0, _common.Inject)(_config.EmailConfigService)),
172
+ _ts_param(3, (0, _common.Inject)(_emaildatasourceprovider.EmailDataSourceProvider)),
173
+ _ts_metadata("design:type", Function),
174
+ _ts_metadata("design:paramtypes", [
175
+ typeof _classes.HybridCache === "undefined" ? Object : _classes.HybridCache,
176
+ typeof _modules.UtilsService === "undefined" ? Object : _modules.UtilsService,
177
+ typeof _config.EmailConfigService === "undefined" ? Object : _config.EmailConfigService,
178
+ typeof _emaildatasourceprovider.EmailDataSourceProvider === "undefined" ? Object : _emaildatasourceprovider.EmailDataSourceProvider
179
+ ])
180
+ ], EmailProviderConfigService);
@@ -0,0 +1,228 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "EmailSendService", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return EmailSendService;
9
+ }
10
+ });
11
+ const _common = require("@nestjs/common");
12
+ const _config = require("../config");
13
+ const _providers = require("../providers");
14
+ const _emailproviderconfigservice = require("./email-provider-config.service");
15
+ const _emailtemplateservice = require("./email-template.service");
16
+ function _define_property(obj, key, value) {
17
+ if (key in obj) {
18
+ Object.defineProperty(obj, key, {
19
+ value: value,
20
+ enumerable: true,
21
+ configurable: true,
22
+ writable: true
23
+ });
24
+ } else {
25
+ obj[key] = value;
26
+ }
27
+ return obj;
28
+ }
29
+ function _ts_decorate(decorators, target, key, desc) {
30
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
31
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
32
+ 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;
33
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
34
+ }
35
+ function _ts_metadata(k, v) {
36
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
37
+ }
38
+ function _ts_param(paramIndex, decorator) {
39
+ return function(target, key) {
40
+ decorator(target, key, paramIndex);
41
+ };
42
+ }
43
+ let EmailSendService = class EmailSendService {
44
+ /**
45
+ * Get email provider based on config ID or default
46
+ */ async getEmailProviderWithConfig(emailConfigId, user) {
47
+ let emailConfig;
48
+ if (emailConfigId) {
49
+ const config = await this.emailProviderConfigService.findByIdDirect(emailConfigId);
50
+ if (!config) {
51
+ throw new _common.NotFoundException('Email configuration not found');
52
+ }
53
+ // Validate company ownership
54
+ if (this.emailConfigService.isCompanyFeatureEnabled() && user?.companyId) {
55
+ const configWithCompany = config;
56
+ if (configWithCompany.companyId && configWithCompany.companyId !== user.companyId) {
57
+ throw new _common.BadRequestException('Email configuration belongs to another company');
58
+ }
59
+ }
60
+ if (!config.isActive) {
61
+ throw new _common.BadRequestException('Email configuration is inactive');
62
+ }
63
+ emailConfig = config;
64
+ } else {
65
+ const defaultConfig = await this.emailProviderConfigService.getDefaultConfig(user);
66
+ if (!defaultConfig) {
67
+ throw new _common.NotFoundException('No default email configuration found. Please create one.');
68
+ }
69
+ emailConfig = defaultConfig;
70
+ }
71
+ const providerConfig = {
72
+ provider: emailConfig.provider,
73
+ config: emailConfig.config
74
+ };
75
+ const provider = await this.emailFactory.createProvider(providerConfig);
76
+ return {
77
+ provider,
78
+ config: emailConfig
79
+ };
80
+ }
81
+ /**
82
+ * Interpolate variables in template content
83
+ * Replaces {{variableName}} with actual values
84
+ */ interpolateVariables(content, variables) {
85
+ if (!variables || Object.keys(variables).length === 0) {
86
+ return content;
87
+ }
88
+ return content.replace(/\{\{(\w+)\}\}/g, (match, varName)=>{
89
+ return variables[varName] !== undefined ? String(variables[varName]) : match;
90
+ });
91
+ }
92
+ /**
93
+ * Send email directly (without template)
94
+ */ async sendEmail(dto, user) {
95
+ const { provider, config } = await this.getEmailProviderWithConfig(dto.emailConfigId, user);
96
+ const result = await provider.sendEmail({
97
+ to: dto.to,
98
+ cc: dto.cc,
99
+ bcc: dto.bcc,
100
+ subject: dto.subject,
101
+ html: dto.html,
102
+ text: dto.text,
103
+ from: dto.from || config.fromEmail || undefined,
104
+ fromName: dto.fromName || config.fromName || this.emailConfigService.getDefaultFromName(),
105
+ replyTo: dto.replyTo,
106
+ attachments: dto.attachments?.map((a)=>({
107
+ filename: a.filename,
108
+ content: Buffer.from(a.content, 'base64'),
109
+ contentType: a.contentType
110
+ }))
111
+ });
112
+ this.logger.log(`Email sent to ${Array.isArray(dto.to) ? dto.to.join(', ') : dto.to}: ${result.success ? 'SUCCESS' : 'FAILED'}`);
113
+ return result;
114
+ }
115
+ /**
116
+ * Send email using template
117
+ */ async sendTemplateEmail(dto, user) {
118
+ // Get template by ID or slug
119
+ let template;
120
+ if (dto.templateId) {
121
+ template = await this.emailTemplateService.findByIdDirect(dto.templateId);
122
+ } else if (dto.templateSlug) {
123
+ template = await this.emailTemplateService.findBySlug(dto.templateSlug, user);
124
+ } else {
125
+ throw new _common.BadRequestException('templateId or templateSlug is required');
126
+ }
127
+ if (!template) {
128
+ throw new _common.NotFoundException('Email template not found');
129
+ }
130
+ if (!template.isActive) {
131
+ throw new _common.BadRequestException('Email template is inactive');
132
+ }
133
+ // Validate company ownership
134
+ if (this.emailConfigService.isCompanyFeatureEnabled() && user?.companyId) {
135
+ const templateWithCompany = template;
136
+ if (templateWithCompany.companyId && templateWithCompany.companyId !== user.companyId) {
137
+ throw new _common.BadRequestException('Email template belongs to another company');
138
+ }
139
+ }
140
+ // Interpolate variables in subject and content
141
+ const subject = this.interpolateVariables(template.subject, dto.variables || {});
142
+ // Check isHtml to determine which content to send
143
+ let html;
144
+ let text;
145
+ if (template.isHtml) {
146
+ // HTML template - send htmlContent, with textContent as fallback
147
+ html = this.interpolateVariables(template.htmlContent, dto.variables || {});
148
+ text = template.textContent ? this.interpolateVariables(template.textContent, dto.variables || {}) : undefined;
149
+ } else {
150
+ // Plain text template - send only textContent, no HTML
151
+ text = template.textContent ? this.interpolateVariables(template.textContent, dto.variables || {}) : this.interpolateVariables(template.htmlContent, dto.variables || {}); // fallback to htmlContent if textContent is empty
152
+ html = undefined;
153
+ }
154
+ // Get provider and send
155
+ const { provider, config } = await this.getEmailProviderWithConfig(dto.emailConfigId, user);
156
+ const result = await provider.sendEmail({
157
+ to: dto.to,
158
+ cc: dto.cc,
159
+ bcc: dto.bcc,
160
+ subject,
161
+ html,
162
+ text,
163
+ from: dto.from || config.fromEmail || undefined,
164
+ fromName: dto.fromName || config.fromName || this.emailConfigService.getDefaultFromName(),
165
+ replyTo: dto.replyTo,
166
+ attachments: dto.attachments?.map((a)=>({
167
+ filename: a.filename,
168
+ content: Buffer.from(a.content, 'base64'),
169
+ contentType: a.contentType
170
+ }))
171
+ });
172
+ this.logger.log(`Template email sent to ${Array.isArray(dto.to) ? dto.to.join(', ') : dto.to} using template "${template.slug}": ${result.success ? 'SUCCESS' : 'FAILED'}`);
173
+ return result;
174
+ }
175
+ /**
176
+ * Send test email (for testing configuration)
177
+ */ async sendTestEmail(emailConfigId, recipient, user) {
178
+ const { provider, config } = await this.getEmailProviderWithConfig(emailConfigId, user);
179
+ const result = await provider.sendEmail({
180
+ to: recipient,
181
+ subject: 'Test Email from FLUSYS',
182
+ html: `
183
+ <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
184
+ <h1 style="color: #333;">Test Email</h1>
185
+ <p>This is a test email from FLUSYS Email Service.</p>
186
+ <p><strong>Configuration:</strong> ${config.name}</p>
187
+ <p><strong>Provider:</strong> ${config.provider.toUpperCase()}</p>
188
+ <p style="color: #666; font-size: 12px;">
189
+ If you received this email, your email configuration is working correctly.
190
+ </p>
191
+ </div>
192
+ `,
193
+ text: `Test Email from FLUSYS\n\nThis is a test email.\nConfiguration: ${config.name}\nProvider: ${config.provider.toUpperCase()}`,
194
+ from: config.fromEmail || undefined,
195
+ fromName: config.fromName || this.emailConfigService.getDefaultFromName()
196
+ });
197
+ this.logger.log(`Test email sent to ${recipient}: ${result.success ? 'SUCCESS' : 'FAILED'}`);
198
+ return result;
199
+ }
200
+ constructor(emailFactory, emailConfigService, emailProviderConfigService, emailTemplateService){
201
+ _define_property(this, "emailFactory", void 0);
202
+ _define_property(this, "emailConfigService", void 0);
203
+ _define_property(this, "emailProviderConfigService", void 0);
204
+ _define_property(this, "emailTemplateService", void 0);
205
+ _define_property(this, "logger", void 0);
206
+ this.emailFactory = emailFactory;
207
+ this.emailConfigService = emailConfigService;
208
+ this.emailProviderConfigService = emailProviderConfigService;
209
+ this.emailTemplateService = emailTemplateService;
210
+ this.logger = new _common.Logger(EmailSendService.name);
211
+ }
212
+ };
213
+ EmailSendService = _ts_decorate([
214
+ (0, _common.Injectable)({
215
+ scope: _common.Scope.REQUEST
216
+ }),
217
+ _ts_param(0, (0, _common.Inject)(_providers.EmailFactoryService)),
218
+ _ts_param(1, (0, _common.Inject)(_config.EmailConfigService)),
219
+ _ts_param(2, (0, _common.Inject)(_emailproviderconfigservice.EmailProviderConfigService)),
220
+ _ts_param(3, (0, _common.Inject)(_emailtemplateservice.EmailTemplateService)),
221
+ _ts_metadata("design:type", Function),
222
+ _ts_metadata("design:paramtypes", [
223
+ typeof _providers.EmailFactoryService === "undefined" ? Object : _providers.EmailFactoryService,
224
+ typeof _config.EmailConfigService === "undefined" ? Object : _config.EmailConfigService,
225
+ typeof _emailproviderconfigservice.EmailProviderConfigService === "undefined" ? Object : _emailproviderconfigservice.EmailProviderConfigService,
226
+ typeof _emailtemplateservice.EmailTemplateService === "undefined" ? Object : _emailtemplateservice.EmailTemplateService
227
+ ])
228
+ ], EmailSendService);
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "EmailTemplateService", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return EmailTemplateService;
9
+ }
10
+ });
11
+ const _classes = require("@flusys/nestjs-shared/classes");
12
+ const _modules = require("@flusys/nestjs-shared/modules");
13
+ const _common = require("@nestjs/common");
14
+ const _config = require("../config");
15
+ const _entities = require("../entities");
16
+ const _emaildatasourceprovider = require("./email-datasource.provider");
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 _ts_decorate(decorators, target, key, desc) {
31
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
32
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
33
+ 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;
34
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
35
+ }
36
+ function _ts_metadata(k, v) {
37
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
38
+ }
39
+ function _ts_param(paramIndex, decorator) {
40
+ return function(target, key) {
41
+ decorator(target, key, paramIndex);
42
+ };
43
+ }
44
+ let EmailTemplateService = class EmailTemplateService extends _classes.RequestScopedApiService {
45
+ /**
46
+ * Resolve entity class for this service
47
+ */ resolveEntity() {
48
+ const enableCompanyFeature = this.emailConfig.isCompanyFeatureEnabled();
49
+ return enableCompanyFeature ? _entities.EmailTemplateWithCompany : _entities.EmailTemplate;
50
+ }
51
+ /**
52
+ * Get DataSource provider for this service
53
+ */ getDataSourceProvider() {
54
+ return this.dataSourceProvider;
55
+ }
56
+ async convertSingleDtoToEntity(dto, user) {
57
+ // For updates, fetch existing template to handle versioning
58
+ const updateDto = dto;
59
+ if (updateDto.id) {
60
+ await this.ensureRepositoryInitialized();
61
+ const existing = await this.repository.findOne({
62
+ where: {
63
+ id: updateDto.id
64
+ }
65
+ });
66
+ if (existing) {
67
+ // Auto-increment schema version if schema changed
68
+ if (dto.schema && JSON.stringify(dto.schema) !== JSON.stringify(existing.schema)) {
69
+ dto.schemaVersion = existing.schemaVersion + 1;
70
+ this.logger.log(`Schema changed for template ${updateDto.id}, incrementing version from ${existing.schemaVersion} to ${dto.schemaVersion}`);
71
+ }
72
+ }
73
+ }
74
+ let templateEntity = {
75
+ ...dto
76
+ };
77
+ // Set company fields if company feature is enabled
78
+ if (this.emailConfig.isCompanyFeatureEnabled()) {
79
+ templateEntity.companyId = user?.companyId ?? null;
80
+ }
81
+ return templateEntity;
82
+ }
83
+ async getSelectQuery(query, _user, select) {
84
+ if (!select || !select.length) {
85
+ select = [
86
+ 'id',
87
+ 'name',
88
+ 'slug',
89
+ 'description',
90
+ 'subject',
91
+ 'schema',
92
+ 'htmlContent',
93
+ 'textContent',
94
+ 'schemaVersion',
95
+ 'isActive',
96
+ 'isHtml',
97
+ 'metadata',
98
+ 'createdAt',
99
+ 'updatedAt'
100
+ ];
101
+ if (this.emailConfig.isCompanyFeatureEnabled()) {
102
+ select.push('companyId');
103
+ }
104
+ }
105
+ const selectFields = select.map((field)=>`${this.entityName}.${field}`);
106
+ query.select(selectFields);
107
+ return {
108
+ query,
109
+ isRaw: false
110
+ };
111
+ }
112
+ /**
113
+ * Override: Extra query manipulation - Auto-filter by user's company
114
+ */ async getExtraManipulateQuery(query, filterDto, user) {
115
+ const result = await super.getExtraManipulateQuery(query, filterDto, user);
116
+ const enableCompanyFeature = this.emailConfig.isCompanyFeatureEnabled();
117
+ if (enableCompanyFeature && user?.companyId) {
118
+ query.andWhere('emailTemplate.companyId = :companyId', {
119
+ companyId: user.companyId
120
+ });
121
+ }
122
+ query.orderBy(`${this.entityName}.createdAt`, 'DESC');
123
+ return result;
124
+ }
125
+ /**
126
+ * Find template by ID directly (bypasses company filtering)
127
+ */ async findByIdDirect(id) {
128
+ await this.ensureRepositoryInitialized();
129
+ return await this.repository.findOne({
130
+ where: {
131
+ id
132
+ }
133
+ });
134
+ }
135
+ /**
136
+ * Find template by slug (scoped to user's company if enabled)
137
+ */ async findBySlug(slug, user) {
138
+ await this.ensureRepositoryInitialized();
139
+ const where = {
140
+ slug,
141
+ isActive: true
142
+ };
143
+ if (this.emailConfig.isCompanyFeatureEnabled() && user?.companyId) {
144
+ where.companyId = user.companyId;
145
+ }
146
+ return await this.repository.findOne({
147
+ where
148
+ });
149
+ }
150
+ /**
151
+ * Get all active templates (scoped to user's company if enabled)
152
+ */ async getActiveTemplates(user) {
153
+ await this.ensureRepositoryInitialized();
154
+ const where = {
155
+ isActive: true
156
+ };
157
+ if (this.emailConfig.isCompanyFeatureEnabled() && user?.companyId) {
158
+ where.companyId = user.companyId;
159
+ }
160
+ return await this.repository.find({
161
+ where,
162
+ order: {
163
+ name: 'ASC'
164
+ }
165
+ });
166
+ }
167
+ constructor(cacheManager, utilsService, emailConfig, dataSourceProvider){
168
+ super('emailTemplate', null, cacheManager, utilsService, EmailTemplateService.name, true), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "emailConfig", void 0), _define_property(this, "dataSourceProvider", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.emailConfig = emailConfig, this.dataSourceProvider = dataSourceProvider;
169
+ }
170
+ };
171
+ EmailTemplateService = _ts_decorate([
172
+ (0, _common.Injectable)({
173
+ scope: _common.Scope.REQUEST
174
+ }),
175
+ _ts_param(0, (0, _common.Inject)('CACHE_INSTANCE')),
176
+ _ts_param(1, (0, _common.Inject)(_modules.UtilsService)),
177
+ _ts_param(2, (0, _common.Inject)(_config.EmailConfigService)),
178
+ _ts_param(3, (0, _common.Inject)(_emaildatasourceprovider.EmailDataSourceProvider)),
179
+ _ts_metadata("design:type", Function),
180
+ _ts_metadata("design:paramtypes", [
181
+ typeof _classes.HybridCache === "undefined" ? Object : _classes.HybridCache,
182
+ typeof _modules.UtilsService === "undefined" ? Object : _modules.UtilsService,
183
+ typeof _config.EmailConfigService === "undefined" ? Object : _config.EmailConfigService,
184
+ typeof _emaildatasourceprovider.EmailDataSourceProvider === "undefined" ? Object : _emaildatasourceprovider.EmailDataSourceProvider
185
+ ])
186
+ ], EmailTemplateService);
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ _export_star(require("./email-datasource.provider"), exports);
6
+ _export_star(require("./email-provider-config.service"), exports);
7
+ _export_star(require("./email-template.service"), exports);
8
+ _export_star(require("./email-send.service"), exports);
9
+ function _export_star(from, to) {
10
+ Object.keys(from).forEach(function(k) {
11
+ if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
12
+ Object.defineProperty(to, k, {
13
+ enumerable: true,
14
+ get: function() {
15
+ return from[k];
16
+ }
17
+ });
18
+ }
19
+ });
20
+ return from;
21
+ }
@@ -0,0 +1,13 @@
1
+ import { EmailModuleOptions } from '../interfaces';
2
+ export declare class EmailConfigService {
3
+ private readonly options;
4
+ constructor(options: EmailModuleOptions);
5
+ isCompanyFeatureEnabled(): boolean;
6
+ getDatabaseMode(): 'single' | 'multi-tenant';
7
+ getRateLimitPerMinute(): number;
8
+ isLoggingEnabled(): boolean;
9
+ getDefaultProvider(): string | undefined;
10
+ getDefaultFromName(): string;
11
+ getDefaultDatabaseConfig(): import("@flusys/nestjs-core").IDatabaseConfig;
12
+ getOptions(): EmailModuleOptions;
13
+ }
@@ -0,0 +1,11 @@
1
+ export declare const EMAIL_MODULE_OPTIONS = "EMAIL_MODULE_OPTIONS";
2
+ export declare const EMAIL_CONFIG_SERVICE = "EMAIL_CONFIG_SERVICE";
3
+ export declare const EMAIL_DATA_SOURCE_PROVIDER = "EMAIL_DATA_SOURCE_PROVIDER";
4
+ export declare const DEFAULT_FROM_NAME = "FLUSYS";
5
+ export declare const EMAIL_VALIDATION_MESSAGES: {
6
+ readonly INVALID_RECIPIENT: "Invalid email recipient";
7
+ readonly TEMPLATE_NOT_FOUND: "Email template not found";
8
+ readonly CONFIG_NOT_FOUND: "Email configuration not found";
9
+ readonly PROVIDER_NOT_AVAILABLE: "Email provider not available";
10
+ readonly SEND_FAILED: "Failed to send email";
11
+ };
@@ -0,0 +1,2 @@
1
+ export * from './email.constants';
2
+ export * from './email-config.service';
@@ -0,0 +1,17 @@
1
+ import { CreateEmailConfigDto, EmailConfigResponseDto, UpdateEmailConfigDto } from '../dtos';
2
+ import { EmailProviderConfigService } from '../services';
3
+ declare const EmailConfigController_base: abstract new (service: EmailProviderConfigService) => {
4
+ service: EmailProviderConfigService;
5
+ insert(addDto: CreateEmailConfigDto, user: import("@flusys/nestjs-shared/interfaces").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared/dtos").SingleResponseDto<EmailConfigResponseDto>>;
6
+ insertMany(addDto: CreateEmailConfigDto[], user: import("@flusys/nestjs-shared/interfaces").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared/dtos").BulkResponseDto<EmailConfigResponseDto>>;
7
+ getById(id: string, body: import("@flusys/nestjs-shared/dtos").GetByIdBodyDto, user: import("@flusys/nestjs-shared/interfaces").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared/dtos").SingleResponseDto<EmailConfigResponseDto>>;
8
+ update(updateDto: UpdateEmailConfigDto, user: import("@flusys/nestjs-shared/interfaces").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared/dtos").SingleResponseDto<EmailConfigResponseDto>>;
9
+ updateMany(updateDtos: UpdateEmailConfigDto[], user: import("@flusys/nestjs-shared/interfaces").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared/dtos").BulkResponseDto<EmailConfigResponseDto>>;
10
+ getAll(filterAndPaginationDto: import("@flusys/nestjs-shared/dtos").FilterAndPaginationDto, user: import("@flusys/nestjs-shared/interfaces").ILoggedUserInfo | null, search?: string): Promise<import("@flusys/nestjs-shared/dtos").ListResponseDto<EmailConfigResponseDto>>;
11
+ delete(deleteDto: import("@flusys/nestjs-shared/dtos").DeleteDto, user: import("@flusys/nestjs-shared/interfaces").ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared/dtos").MessageResponseDto>;
12
+ };
13
+ export declare class EmailConfigController extends EmailConfigController_base {
14
+ emailConfigService: EmailProviderConfigService;
15
+ constructor(emailConfigService: EmailProviderConfigService);
16
+ }
17
+ export {};