@flusys/nestjs-email 4.1.1 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/README.md +93 -384
  2. package/cjs/config/message-keys.js +1 -38
  3. package/cjs/controllers/email-template.controller.js +9 -3
  4. package/cjs/docs/email-swagger.config.js +5 -3
  5. package/cjs/dtos/email-template.dto.js +1 -21
  6. package/cjs/entities/email-config.entity.js +2 -1
  7. package/cjs/entities/email-template.entity.js +3 -8
  8. package/cjs/providers/email-factory.service.js +5 -5
  9. package/cjs/providers/mailgun-provider.js +5 -2
  10. package/cjs/providers/sendgrid-provider.js +5 -2
  11. package/cjs/services/email-provider-config.service.js +0 -10
  12. package/cjs/services/email-template.service.js +0 -13
  13. package/config/message-keys.d.ts +0 -68
  14. package/dtos/email-template.dto.d.ts +0 -2
  15. package/entities/email-template.entity.d.ts +0 -1
  16. package/fesm/config/message-keys.js +1 -33
  17. package/fesm/controllers/email-template.controller.js +10 -4
  18. package/fesm/docs/email-swagger.config.js +5 -3
  19. package/fesm/dtos/email-template.dto.js +1 -21
  20. package/fesm/entities/email-config.entity.js +2 -1
  21. package/fesm/entities/email-template.entity.js +3 -8
  22. package/fesm/providers/email-factory.service.js +5 -5
  23. package/fesm/providers/mailgun-provider.js +5 -2
  24. package/fesm/providers/sendgrid-provider.js +5 -2
  25. package/fesm/services/email-provider-config.service.js +0 -10
  26. package/fesm/services/email-template.service.js +0 -13
  27. package/interfaces/email-template.interface.d.ts +0 -1
  28. package/package.json +3 -3
  29. package/services/email-provider-config.service.d.ts +0 -2
  30. package/services/email-template.service.d.ts +0 -1
@@ -22,7 +22,8 @@ Object.defineProperty(exports, "emailSwaggerConfig", {
22
22
  ]
23
23
  }
24
24
  ];
25
- function buildDescription(enableCompanyFeature) {
25
+ function buildDescription(enableCompanyFeature, isMultiTenant) {
26
+ const multiTenantNote = isMultiTenant ? `\n> **Multi-Tenant Mode**: Include \`x-tenant-id\` header to target a specific tenant database.\n` : '';
26
27
  const companyConfigs = enableCompanyFeature ? '\n- **Company-level email configs**' : '';
27
28
  const companyIsolation = enableCompanyFeature ? '\n- **Company isolation**' : '';
28
29
  const multiTenantSection = enableCompanyFeature ? `
@@ -35,7 +36,7 @@ All queries automatically filter by current user's company context.
35
36
  ` : '';
36
37
  return `
37
38
  # Email Management API
38
-
39
+ ${multiTenantNote}
39
40
  Complete email management system${enableCompanyFeature ? ' with multi-tenant and company support' : ''}.
40
41
 
41
42
  ## Features
@@ -102,9 +103,10 @@ All email endpoints are prefixed with \`/email\`:
102
103
  }
103
104
  function emailSwaggerConfig(bootstrapConfig) {
104
105
  const enableCompanyFeature = bootstrapConfig?.enableCompanyFeature ?? true;
106
+ const isMultiTenant = bootstrapConfig?.databaseMode === 'multi-tenant';
105
107
  return {
106
108
  title: 'Email API',
107
- description: buildDescription(enableCompanyFeature),
109
+ description: buildDescription(enableCompanyFeature, isMultiTenant),
108
110
  version: '1.0',
109
111
  path: 'api/docs/email',
110
112
  bearerAuth: true,
@@ -55,7 +55,6 @@ let CreateEmailTemplateDto = class CreateEmailTemplateDto {
55
55
  _define_property(this, "textContent", void 0);
56
56
  _define_property(this, "isActive", void 0);
57
57
  _define_property(this, "isHtml", void 0);
58
- _define_property(this, "metadata", void 0);
59
58
  }
60
59
  };
61
60
  _ts_decorate([
@@ -139,18 +138,6 @@ _ts_decorate([
139
138
  (0, _classvalidator.IsOptional)(),
140
139
  _ts_metadata("design:type", Boolean)
141
140
  ], CreateEmailTemplateDto.prototype, "isHtml", void 0);
142
- _ts_decorate([
143
- (0, _swagger.ApiPropertyOptional)({
144
- type: 'object',
145
- additionalProperties: true,
146
- example: {
147
- category: 'onboarding'
148
- }
149
- }),
150
- (0, _classvalidator.IsObject)(),
151
- (0, _classvalidator.IsOptional)(),
152
- _ts_metadata("design:type", typeof Record === "undefined" ? Object : Record)
153
- ], CreateEmailTemplateDto.prototype, "metadata", void 0);
154
141
  let UpdateEmailTemplateDto = class UpdateEmailTemplateDto extends (0, _swagger.PartialType)(CreateEmailTemplateDto) {
155
142
  constructor(...args){
156
143
  super(...args), _define_property(this, "id", void 0);
@@ -166,7 +153,7 @@ _ts_decorate([
166
153
  ], UpdateEmailTemplateDto.prototype, "id", void 0);
167
154
  let EmailTemplateResponseDto = class EmailTemplateResponseDto extends _dtos.IdentityResponseDto {
168
155
  constructor(...args){
169
- super(...args), _define_property(this, "name", void 0), _define_property(this, "slug", void 0), _define_property(this, "description", void 0), _define_property(this, "subject", void 0), _define_property(this, "schema", void 0), _define_property(this, "htmlContent", void 0), _define_property(this, "textContent", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "isActive", void 0), _define_property(this, "isHtml", void 0), _define_property(this, "metadata", void 0);
156
+ super(...args), _define_property(this, "name", void 0), _define_property(this, "slug", void 0), _define_property(this, "description", void 0), _define_property(this, "subject", void 0), _define_property(this, "schema", void 0), _define_property(this, "htmlContent", void 0), _define_property(this, "textContent", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "isActive", void 0), _define_property(this, "isHtml", void 0);
170
157
  }
171
158
  };
172
159
  _ts_decorate([
@@ -212,10 +199,3 @@ _ts_decorate([
212
199
  (0, _swagger.ApiProperty)(),
213
200
  _ts_metadata("design:type", Boolean)
214
201
  ], EmailTemplateResponseDto.prototype, "isHtml", void 0);
215
- _ts_decorate([
216
- (0, _swagger.ApiPropertyOptional)({
217
- type: 'object',
218
- additionalProperties: true
219
- }),
220
- _ts_metadata("design:type", Object)
221
- ], EmailTemplateResponseDto.prototype, "metadata", void 0);
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "EmailConfig", {
8
8
  return EmailConfig;
9
9
  }
10
10
  });
11
+ const _nestjsshared = require("@flusys/nestjs-shared");
11
12
  const _entities = require("@flusys/nestjs-shared/entities");
12
13
  const _typeorm = require("typeorm");
13
14
  function _define_property(obj, key, value) {
@@ -55,7 +56,7 @@ _ts_decorate([
55
56
  ], EmailConfig.prototype, "provider", void 0);
56
57
  _ts_decorate([
57
58
  (0, _typeorm.Column)({
58
- type: 'json',
59
+ type: (0, _nestjsshared.getJsonColumnType)(),
59
60
  nullable: false
60
61
  }),
61
62
  _ts_metadata("design:type", typeof Record === "undefined" ? Object : Record)
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "EmailTemplate", {
8
8
  return EmailTemplate;
9
9
  }
10
10
  });
11
+ const _nestjsshared = require("@flusys/nestjs-shared");
11
12
  const _entities = require("@flusys/nestjs-shared/entities");
12
13
  const _typeorm = require("typeorm");
13
14
  function _define_property(obj, key, value) {
@@ -34,7 +35,7 @@ function _ts_metadata(k, v) {
34
35
  }
35
36
  let EmailTemplate = class EmailTemplate extends _entities.Identity {
36
37
  constructor(...args){
37
- super(...args), _define_property(this, "name", void 0), _define_property(this, "slug", void 0), _define_property(this, "description", void 0), _define_property(this, "subject", void 0), _define_property(this, "schema", void 0), _define_property(this, "htmlContent", void 0), _define_property(this, "textContent", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "isActive", void 0), _define_property(this, "isHtml", void 0), _define_property(this, "metadata", void 0);
38
+ super(...args), _define_property(this, "name", void 0), _define_property(this, "slug", void 0), _define_property(this, "description", void 0), _define_property(this, "subject", void 0), _define_property(this, "schema", void 0), _define_property(this, "htmlContent", void 0), _define_property(this, "textContent", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "isActive", void 0), _define_property(this, "isHtml", void 0);
38
39
  }
39
40
  };
40
41
  _ts_decorate([
@@ -71,7 +72,7 @@ _ts_decorate([
71
72
  ], EmailTemplate.prototype, "subject", void 0);
72
73
  _ts_decorate([
73
74
  (0, _typeorm.Column)({
74
- type: 'json',
75
+ type: (0, _nestjsshared.getJsonColumnType)(),
75
76
  nullable: false
76
77
  }),
77
78
  _ts_metadata("design:type", typeof Record === "undefined" ? Object : Record)
@@ -117,12 +118,6 @@ _ts_decorate([
117
118
  }),
118
119
  _ts_metadata("design:type", Boolean)
119
120
  ], EmailTemplate.prototype, "isHtml", void 0);
120
- _ts_decorate([
121
- (0, _typeorm.Column)('simple-json', {
122
- nullable: true
123
- }),
124
- _ts_metadata("design:type", Object)
125
- ], EmailTemplate.prototype, "metadata", void 0);
126
121
  EmailTemplate = _ts_decorate([
127
122
  (0, _typeorm.Entity)({
128
123
  name: 'email_template'
@@ -9,9 +9,9 @@ Object.defineProperty(exports, "EmailFactoryService", {
9
9
  }
10
10
  });
11
11
  const _nestjsshared = require("@flusys/nestjs-shared");
12
- const _config = require("../config");
13
12
  const _common = require("@nestjs/common");
14
13
  const _crypto = require("crypto");
14
+ const _config = require("../config");
15
15
  const _interfaces = require("../interfaces");
16
16
  const _emailproviderregistry = require("./email-provider.registry");
17
17
  function _define_property(obj, key, value) {
@@ -47,7 +47,7 @@ let EmailFactoryService = class EmailFactoryService {
47
47
  throw new _common.NotFoundException({
48
48
  message: `Email provider '${config.provider}' is not registered`,
49
49
  messageKey: _config.EMAIL_SEND_MESSAGES.CONFIG_NOT_FOUND,
50
- messageParams: {
50
+ messageVariables: {
51
51
  provider: config.provider,
52
52
  available: _emailproviderregistry.EmailProviderRegistry.getAll().join(', ')
53
53
  }
@@ -60,11 +60,11 @@ let EmailFactoryService = class EmailFactoryService {
60
60
  return instance;
61
61
  } catch (error) {
62
62
  throw new _common.InternalServerErrorException({
63
- message: `Failed to initialize email provider '${config.provider}'`,
63
+ message: `Email provider '${config.provider}' not initialized successfully: ${this.extractErrorMessage(error)}`,
64
64
  messageKey: _nestjsshared.SYSTEM_MESSAGES.SERVICE_NOT_AVAILABLE,
65
- messageParams: {
65
+ messageVariables: {
66
66
  provider: config.provider,
67
- error: this.extractErrorMessage(error)
67
+ available: _emailproviderregistry.EmailProviderRegistry.getAll().join(', ')
68
68
  }
69
69
  });
70
70
  }
@@ -8,8 +8,8 @@ Object.defineProperty(exports, "MailgunProvider", {
8
8
  return MailgunProvider;
9
9
  }
10
10
  });
11
- const _common = require("@nestjs/common");
12
11
  const _constants = require("@flusys/nestjs-shared/constants");
12
+ const _common = require("@nestjs/common");
13
13
  function _define_property(obj, key, value) {
14
14
  if (key in obj) {
15
15
  Object.defineProperty(obj, key, {
@@ -42,7 +42,10 @@ let MailgunProvider = class MailgunProvider {
42
42
  } catch {
43
43
  throw new _common.InternalServerErrorException({
44
44
  message: 'Mailgun initialization failed. Install: npm install mailgun.js form-data',
45
- messageKey: _constants.SYSTEM_MESSAGES.SDK_NOT_INSTALLED
45
+ messageKey: _constants.SYSTEM_MESSAGES.SDK_NOT_INSTALLED,
46
+ messageVariables: {
47
+ sdk: 'mailgun'
48
+ }
46
49
  });
47
50
  }
48
51
  }
@@ -8,8 +8,8 @@ Object.defineProperty(exports, "SendGridProvider", {
8
8
  return SendGridProvider;
9
9
  }
10
10
  });
11
- const _common = require("@nestjs/common");
12
11
  const _constants = require("@flusys/nestjs-shared/constants");
12
+ const _common = require("@nestjs/common");
13
13
  function _define_property(obj, key, value) {
14
14
  if (key in obj) {
15
15
  Object.defineProperty(obj, key, {
@@ -34,7 +34,10 @@ let SendGridProvider = class SendGridProvider {
34
34
  } catch {
35
35
  throw new _common.InternalServerErrorException({
36
36
  message: 'SendGrid initialization failed. Install: npm install @sendgrid/mail',
37
- messageKey: _constants.SYSTEM_MESSAGES.SDK_NOT_INSTALLED
37
+ messageKey: _constants.SYSTEM_MESSAGES.SDK_NOT_INSTALLED,
38
+ messageVariables: {
39
+ sdk: 'sendgrid'
40
+ }
38
41
  });
39
42
  }
40
43
  }
@@ -118,16 +118,6 @@ let EmailProviderConfigService = class EmailProviderConfigService extends _class
118
118
  }
119
119
  });
120
120
  }
121
- async getConfigByProvider(provider, user) {
122
- await this.ensureRepositoryInitialized();
123
- const where = (0, _utils.buildCompanyWhereCondition)({
124
- provider,
125
- isActive: true
126
- }, this.emailConfig.isCompanyFeatureEnabled(), user);
127
- return this.repository.find({
128
- where
129
- });
130
- }
131
121
  constructor(cacheManager, utilsService, emailConfig, dataSourceProvider){
132
122
  super('emailConfig', null, cacheManager, utilsService, EmailProviderConfigService.name, true, 'email'), _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;
133
123
  }
@@ -54,7 +54,6 @@ const DEFAULT_SELECT_FIELDS = [
54
54
  'schemaVersion',
55
55
  'isActive',
56
56
  'isHtml',
57
- 'metadata',
58
57
  'createdAt',
59
58
  'updatedAt'
60
59
  ];
@@ -114,18 +113,6 @@ let EmailTemplateService = class EmailTemplateService extends _classes.RequestSc
114
113
  where
115
114
  });
116
115
  }
117
- async getActiveTemplates(user) {
118
- await this.ensureRepositoryInitialized();
119
- const where = (0, _utils.buildCompanyWhereCondition)({
120
- isActive: true
121
- }, this.emailConfig.isCompanyFeatureEnabled(), user);
122
- return this.repository.find({
123
- where,
124
- order: {
125
- name: 'ASC'
126
- }
127
- });
128
- }
129
116
  // ─── Private Helpers ────────────────────────────────────────────────────────
130
117
  async incrementSchemaVersionIfChanged(dto, entity) {
131
118
  const updateDto = dto;
@@ -1,36 +1,10 @@
1
- export declare const EMAIL_CONFIG_MESSAGES: {
2
- readonly CREATE_SUCCESS: "email.config.create.success";
3
- readonly CREATE_MANY_SUCCESS: "email.config.create.many.success";
4
- readonly GET_SUCCESS: "email.config.get.success";
5
- readonly GET_ALL_SUCCESS: "email.config.get.all.success";
6
- readonly UPDATE_SUCCESS: "email.config.update.success";
7
- readonly UPDATE_MANY_SUCCESS: "email.config.update.many.success";
8
- readonly DELETE_SUCCESS: "email.config.delete.success";
9
- readonly RESTORE_SUCCESS: "email.config.restore.success";
10
- readonly NOT_FOUND: "email.config.not.found";
11
- readonly ACTIVE_SUCCESS: "email.config.active.success";
12
- readonly TEST_SUCCESS: "email.config.test.success";
13
- readonly TEST_FAILED: "email.config.test.failed";
14
- };
15
1
  export declare const EMAIL_TEMPLATE_MESSAGES: {
16
- readonly CREATE_SUCCESS: "email.template.create.success";
17
- readonly CREATE_MANY_SUCCESS: "email.template.create.many.success";
18
2
  readonly GET_SUCCESS: "email.template.get.success";
19
- readonly GET_ALL_SUCCESS: "email.template.get.all.success";
20
- readonly UPDATE_SUCCESS: "email.template.update.success";
21
- readonly UPDATE_MANY_SUCCESS: "email.template.update.many.success";
22
- readonly DELETE_SUCCESS: "email.template.delete.success";
23
- readonly RESTORE_SUCCESS: "email.template.restore.success";
24
3
  readonly NOT_FOUND: "email.template.not.found";
25
- readonly PREVIEW_SUCCESS: "email.template.preview.success";
26
4
  };
27
5
  export declare const EMAIL_SEND_MESSAGES: {
28
6
  readonly SUCCESS: "email.send.success";
29
7
  readonly FAILED: "email.send.failed";
30
- readonly QUEUED: "email.send.queued";
31
- readonly TEMPLATE_SUCCESS: "email.send.template.success";
32
- readonly BULK_SUCCESS: "email.send.bulk.success";
33
- readonly TEST_SUCCESS: "email.send.test.success";
34
8
  readonly CONFIG_NOT_FOUND: "email.send.config.not.found";
35
9
  readonly CONFIG_INACTIVE: "email.send.config.inactive";
36
10
  readonly CONFIG_DEFAULT_NOT_FOUND: "email.send.config.default.not.found";
@@ -38,45 +12,3 @@ export declare const EMAIL_SEND_MESSAGES: {
38
12
  readonly TEMPLATE_INACTIVE: "email.send.template.inactive";
39
13
  readonly TEMPLATE_ID_OR_SLUG_REQUIRED: "email.send.template.id.or.slug.required";
40
14
  };
41
- export declare const EMAIL_MODULE_MESSAGES: {
42
- readonly EMAIL_CONFIG: {
43
- readonly CREATE_SUCCESS: "email.config.create.success";
44
- readonly CREATE_MANY_SUCCESS: "email.config.create.many.success";
45
- readonly GET_SUCCESS: "email.config.get.success";
46
- readonly GET_ALL_SUCCESS: "email.config.get.all.success";
47
- readonly UPDATE_SUCCESS: "email.config.update.success";
48
- readonly UPDATE_MANY_SUCCESS: "email.config.update.many.success";
49
- readonly DELETE_SUCCESS: "email.config.delete.success";
50
- readonly RESTORE_SUCCESS: "email.config.restore.success";
51
- readonly NOT_FOUND: "email.config.not.found";
52
- readonly ACTIVE_SUCCESS: "email.config.active.success";
53
- readonly TEST_SUCCESS: "email.config.test.success";
54
- readonly TEST_FAILED: "email.config.test.failed";
55
- };
56
- readonly EMAIL_TEMPLATE: {
57
- readonly CREATE_SUCCESS: "email.template.create.success";
58
- readonly CREATE_MANY_SUCCESS: "email.template.create.many.success";
59
- readonly GET_SUCCESS: "email.template.get.success";
60
- readonly GET_ALL_SUCCESS: "email.template.get.all.success";
61
- readonly UPDATE_SUCCESS: "email.template.update.success";
62
- readonly UPDATE_MANY_SUCCESS: "email.template.update.many.success";
63
- readonly DELETE_SUCCESS: "email.template.delete.success";
64
- readonly RESTORE_SUCCESS: "email.template.restore.success";
65
- readonly NOT_FOUND: "email.template.not.found";
66
- readonly PREVIEW_SUCCESS: "email.template.preview.success";
67
- };
68
- readonly EMAIL_SEND: {
69
- readonly SUCCESS: "email.send.success";
70
- readonly FAILED: "email.send.failed";
71
- readonly QUEUED: "email.send.queued";
72
- readonly TEMPLATE_SUCCESS: "email.send.template.success";
73
- readonly BULK_SUCCESS: "email.send.bulk.success";
74
- readonly TEST_SUCCESS: "email.send.test.success";
75
- readonly CONFIG_NOT_FOUND: "email.send.config.not.found";
76
- readonly CONFIG_INACTIVE: "email.send.config.inactive";
77
- readonly CONFIG_DEFAULT_NOT_FOUND: "email.send.config.default.not.found";
78
- readonly TEMPLATE_NOT_FOUND: "email.send.template.not.found";
79
- readonly TEMPLATE_INACTIVE: "email.send.template.inactive";
80
- readonly TEMPLATE_ID_OR_SLUG_REQUIRED: "email.send.template.id.or.slug.required";
81
- };
82
- };
@@ -9,7 +9,6 @@ export declare class CreateEmailTemplateDto {
9
9
  textContent?: string;
10
10
  isActive?: boolean;
11
11
  isHtml?: boolean;
12
- metadata?: Record<string, unknown>;
13
12
  }
14
13
  declare const UpdateEmailTemplateDto_base: import("@nestjs/common").Type<Partial<CreateEmailTemplateDto>>;
15
14
  export declare class UpdateEmailTemplateDto extends UpdateEmailTemplateDto_base {
@@ -26,6 +25,5 @@ export declare class EmailTemplateResponseDto extends IdentityResponseDto {
26
25
  schemaVersion: number;
27
26
  isActive: boolean;
28
27
  isHtml: boolean;
29
- metadata: Record<string, unknown> | null;
30
28
  }
31
29
  export {};
@@ -10,5 +10,4 @@ export declare class EmailTemplate extends Identity {
10
10
  schemaVersion: number;
11
11
  isActive: boolean;
12
12
  isHtml: boolean;
13
- metadata: Record<string, unknown> | null;
14
13
  }
@@ -1,37 +1,11 @@
1
1
  // ==================== EMAIL MODULE MESSAGE KEYS ====================
2
- export const EMAIL_CONFIG_MESSAGES = {
3
- CREATE_SUCCESS: 'email.config.create.success',
4
- CREATE_MANY_SUCCESS: 'email.config.create.many.success',
5
- GET_SUCCESS: 'email.config.get.success',
6
- GET_ALL_SUCCESS: 'email.config.get.all.success',
7
- UPDATE_SUCCESS: 'email.config.update.success',
8
- UPDATE_MANY_SUCCESS: 'email.config.update.many.success',
9
- DELETE_SUCCESS: 'email.config.delete.success',
10
- RESTORE_SUCCESS: 'email.config.restore.success',
11
- NOT_FOUND: 'email.config.not.found',
12
- ACTIVE_SUCCESS: 'email.config.active.success',
13
- TEST_SUCCESS: 'email.config.test.success',
14
- TEST_FAILED: 'email.config.test.failed'
15
- };
16
2
  export const EMAIL_TEMPLATE_MESSAGES = {
17
- CREATE_SUCCESS: 'email.template.create.success',
18
- CREATE_MANY_SUCCESS: 'email.template.create.many.success',
19
3
  GET_SUCCESS: 'email.template.get.success',
20
- GET_ALL_SUCCESS: 'email.template.get.all.success',
21
- UPDATE_SUCCESS: 'email.template.update.success',
22
- UPDATE_MANY_SUCCESS: 'email.template.update.many.success',
23
- DELETE_SUCCESS: 'email.template.delete.success',
24
- RESTORE_SUCCESS: 'email.template.restore.success',
25
- NOT_FOUND: 'email.template.not.found',
26
- PREVIEW_SUCCESS: 'email.template.preview.success'
4
+ NOT_FOUND: 'email.template.not.found'
27
5
  };
28
6
  export const EMAIL_SEND_MESSAGES = {
29
7
  SUCCESS: 'email.send.success',
30
8
  FAILED: 'email.send.failed',
31
- QUEUED: 'email.send.queued',
32
- TEMPLATE_SUCCESS: 'email.send.template.success',
33
- BULK_SUCCESS: 'email.send.bulk.success',
34
- TEST_SUCCESS: 'email.send.test.success',
35
9
  CONFIG_NOT_FOUND: 'email.send.config.not.found',
36
10
  CONFIG_INACTIVE: 'email.send.config.inactive',
37
11
  CONFIG_DEFAULT_NOT_FOUND: 'email.send.config.default.not.found',
@@ -39,9 +13,3 @@ export const EMAIL_SEND_MESSAGES = {
39
13
  TEMPLATE_INACTIVE: 'email.send.template.inactive',
40
14
  TEMPLATE_ID_OR_SLUG_REQUIRED: 'email.send.template.id.or.slug.required'
41
15
  };
42
- // Aggregated export for backward compatibility
43
- export const EMAIL_MODULE_MESSAGES = {
44
- EMAIL_CONFIG: EMAIL_CONFIG_MESSAGES,
45
- EMAIL_TEMPLATE: EMAIL_TEMPLATE_MESSAGES,
46
- EMAIL_SEND: EMAIL_SEND_MESSAGES
47
- };
@@ -26,16 +26,16 @@ function _ts_param(paramIndex, decorator) {
26
26
  };
27
27
  }
28
28
  import { createApiController, EMAIL_TEMPLATE_PERMISSIONS } from '@flusys/nestjs-shared/classes';
29
- import { EMAIL_TEMPLATE_MESSAGES } from '../config';
30
29
  import { CurrentUser, RequirePermission } from '@flusys/nestjs-shared/decorators';
31
30
  import { JwtAuthGuard } from '@flusys/nestjs-shared/guards';
32
31
  import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
33
- import { Body, Controller, Inject, Post, UseGuards } from '@nestjs/common';
32
+ import { Body, Controller, Inject, NotFoundException, Post, UseGuards } from '@nestjs/common';
34
33
  import { ApiBearerAuth, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
34
+ import { EMAIL_TEMPLATE_MESSAGES } from '../config';
35
35
  import { CreateEmailTemplateDto, EmailTemplateResponseDto, UpdateEmailTemplateDto } from '../dtos';
36
36
  import { EmailTemplateService } from '../services';
37
37
  export class EmailTemplateController extends createApiController(CreateEmailTemplateDto, UpdateEmailTemplateDto, EmailTemplateResponseDto, {
38
- entityName: 'emailTemplate',
38
+ entityName: 'email.template',
39
39
  security: {
40
40
  insert: {
41
41
  level: 'permission',
@@ -83,11 +83,17 @@ export class EmailTemplateController extends createApiController(CreateEmailTemp
83
83
  }) {
84
84
  async getBySlug(body, user) {
85
85
  const data = await this.emailTemplateService.findBySlug(body.slug, user);
86
+ if (!data) {
87
+ throw new NotFoundException({
88
+ message: 'Email template not found',
89
+ messageKey: EMAIL_TEMPLATE_MESSAGES.NOT_FOUND
90
+ });
91
+ }
86
92
  return {
87
93
  success: true,
88
94
  message: 'Template retrieved',
89
95
  messageKey: EMAIL_TEMPLATE_MESSAGES.GET_SUCCESS,
90
- data: data ?? undefined
96
+ data
91
97
  };
92
98
  }
93
99
  constructor(emailTemplateService){
@@ -12,7 +12,8 @@
12
12
  ]
13
13
  }
14
14
  ];
15
- function buildDescription(enableCompanyFeature) {
15
+ function buildDescription(enableCompanyFeature, isMultiTenant) {
16
+ const multiTenantNote = isMultiTenant ? `\n> **Multi-Tenant Mode**: Include \`x-tenant-id\` header to target a specific tenant database.\n` : '';
16
17
  const companyConfigs = enableCompanyFeature ? '\n- **Company-level email configs**' : '';
17
18
  const companyIsolation = enableCompanyFeature ? '\n- **Company isolation**' : '';
18
19
  const multiTenantSection = enableCompanyFeature ? `
@@ -25,7 +26,7 @@ All queries automatically filter by current user's company context.
25
26
  ` : '';
26
27
  return `
27
28
  # Email Management API
28
-
29
+ ${multiTenantNote}
29
30
  Complete email management system${enableCompanyFeature ? ' with multi-tenant and company support' : ''}.
30
31
 
31
32
  ## Features
@@ -95,9 +96,10 @@ All email endpoints are prefixed with \`/email\`:
95
96
  * Use this with setupSwaggerDocs() from @flusys/nestjs-core
96
97
  */ export function emailSwaggerConfig(bootstrapConfig) {
97
98
  const enableCompanyFeature = bootstrapConfig?.enableCompanyFeature ?? true;
99
+ const isMultiTenant = bootstrapConfig?.databaseMode === 'multi-tenant';
98
100
  return {
99
101
  title: 'Email API',
100
- description: buildDescription(enableCompanyFeature),
102
+ description: buildDescription(enableCompanyFeature, isMultiTenant),
101
103
  version: '1.0',
102
104
  path: 'api/docs/email',
103
105
  bearerAuth: true,
@@ -34,7 +34,6 @@ export class CreateEmailTemplateDto {
34
34
  _define_property(this, "textContent", void 0);
35
35
  _define_property(this, "isActive", void 0);
36
36
  _define_property(this, "isHtml", void 0);
37
- _define_property(this, "metadata", void 0);
38
37
  }
39
38
  }
40
39
  _ts_decorate([
@@ -118,18 +117,6 @@ _ts_decorate([
118
117
  IsOptional(),
119
118
  _ts_metadata("design:type", Boolean)
120
119
  ], CreateEmailTemplateDto.prototype, "isHtml", void 0);
121
- _ts_decorate([
122
- ApiPropertyOptional({
123
- type: 'object',
124
- additionalProperties: true,
125
- example: {
126
- category: 'onboarding'
127
- }
128
- }),
129
- IsObject(),
130
- IsOptional(),
131
- _ts_metadata("design:type", typeof Record === "undefined" ? Object : Record)
132
- ], CreateEmailTemplateDto.prototype, "metadata", void 0);
133
120
  export class UpdateEmailTemplateDto extends PartialType(CreateEmailTemplateDto) {
134
121
  constructor(...args){
135
122
  super(...args), _define_property(this, "id", void 0);
@@ -145,7 +132,7 @@ _ts_decorate([
145
132
  ], UpdateEmailTemplateDto.prototype, "id", void 0);
146
133
  export class EmailTemplateResponseDto extends IdentityResponseDto {
147
134
  constructor(...args){
148
- super(...args), _define_property(this, "name", void 0), _define_property(this, "slug", void 0), _define_property(this, "description", void 0), _define_property(this, "subject", void 0), _define_property(this, "schema", void 0), _define_property(this, "htmlContent", void 0), _define_property(this, "textContent", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "isActive", void 0), _define_property(this, "isHtml", void 0), _define_property(this, "metadata", void 0);
135
+ super(...args), _define_property(this, "name", void 0), _define_property(this, "slug", void 0), _define_property(this, "description", void 0), _define_property(this, "subject", void 0), _define_property(this, "schema", void 0), _define_property(this, "htmlContent", void 0), _define_property(this, "textContent", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "isActive", void 0), _define_property(this, "isHtml", void 0);
149
136
  }
150
137
  }
151
138
  _ts_decorate([
@@ -191,10 +178,3 @@ _ts_decorate([
191
178
  ApiProperty(),
192
179
  _ts_metadata("design:type", Boolean)
193
180
  ], EmailTemplateResponseDto.prototype, "isHtml", void 0);
194
- _ts_decorate([
195
- ApiPropertyOptional({
196
- type: 'object',
197
- additionalProperties: true
198
- }),
199
- _ts_metadata("design:type", Object)
200
- ], EmailTemplateResponseDto.prototype, "metadata", void 0);
@@ -20,6 +20,7 @@ function _ts_decorate(decorators, target, key, desc) {
20
20
  function _ts_metadata(k, v) {
21
21
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
22
22
  }
23
+ import { getJsonColumnType } from '@flusys/nestjs-shared';
23
24
  import { Identity } from '@flusys/nestjs-shared/entities';
24
25
  import { Column, Entity, Index } from 'typeorm';
25
26
  export class EmailConfig extends Identity {
@@ -45,7 +46,7 @@ _ts_decorate([
45
46
  ], EmailConfig.prototype, "provider", void 0);
46
47
  _ts_decorate([
47
48
  Column({
48
- type: 'json',
49
+ type: getJsonColumnType(),
49
50
  nullable: false
50
51
  }),
51
52
  _ts_metadata("design:type", typeof Record === "undefined" ? Object : Record)
@@ -20,11 +20,12 @@ function _ts_decorate(decorators, target, key, desc) {
20
20
  function _ts_metadata(k, v) {
21
21
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
22
22
  }
23
+ import { getJsonColumnType } from '@flusys/nestjs-shared';
23
24
  import { Identity } from '@flusys/nestjs-shared/entities';
24
25
  import { Column, Entity, Index } from 'typeorm';
25
26
  export class EmailTemplate extends Identity {
26
27
  constructor(...args){
27
- super(...args), _define_property(this, "name", void 0), _define_property(this, "slug", void 0), _define_property(this, "description", void 0), _define_property(this, "subject", void 0), _define_property(this, "schema", void 0), _define_property(this, "htmlContent", void 0), _define_property(this, "textContent", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "isActive", void 0), _define_property(this, "isHtml", void 0), _define_property(this, "metadata", void 0);
28
+ super(...args), _define_property(this, "name", void 0), _define_property(this, "slug", void 0), _define_property(this, "description", void 0), _define_property(this, "subject", void 0), _define_property(this, "schema", void 0), _define_property(this, "htmlContent", void 0), _define_property(this, "textContent", void 0), _define_property(this, "schemaVersion", void 0), _define_property(this, "isActive", void 0), _define_property(this, "isHtml", void 0);
28
29
  }
29
30
  }
30
31
  _ts_decorate([
@@ -61,7 +62,7 @@ _ts_decorate([
61
62
  ], EmailTemplate.prototype, "subject", void 0);
62
63
  _ts_decorate([
63
64
  Column({
64
- type: 'json',
65
+ type: getJsonColumnType(),
65
66
  nullable: false
66
67
  }),
67
68
  _ts_metadata("design:type", typeof Record === "undefined" ? Object : Record)
@@ -107,12 +108,6 @@ _ts_decorate([
107
108
  }),
108
109
  _ts_metadata("design:type", Boolean)
109
110
  ], EmailTemplate.prototype, "isHtml", void 0);
110
- _ts_decorate([
111
- Column('simple-json', {
112
- nullable: true
113
- }),
114
- _ts_metadata("design:type", Object)
115
- ], EmailTemplate.prototype, "metadata", void 0);
116
111
  EmailTemplate = _ts_decorate([
117
112
  Entity({
118
113
  name: 'email_template'
@@ -21,9 +21,9 @@ function _ts_metadata(k, v) {
21
21
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
22
22
  }
23
23
  import { LogAction, SYSTEM_MESSAGES } from '@flusys/nestjs-shared';
24
- import { EMAIL_SEND_MESSAGES } from '../config';
25
24
  import { Injectable, InternalServerErrorException, NotFoundException } from '@nestjs/common';
26
25
  import { createHash } from 'crypto';
26
+ import { EMAIL_SEND_MESSAGES } from '../config';
27
27
  import { IEmailProviderConfig } from '../interfaces';
28
28
  import { EmailProviderRegistry } from './email-provider.registry';
29
29
  export class EmailFactoryService {
@@ -37,7 +37,7 @@ export class EmailFactoryService {
37
37
  throw new NotFoundException({
38
38
  message: `Email provider '${config.provider}' is not registered`,
39
39
  messageKey: EMAIL_SEND_MESSAGES.CONFIG_NOT_FOUND,
40
- messageParams: {
40
+ messageVariables: {
41
41
  provider: config.provider,
42
42
  available: EmailProviderRegistry.getAll().join(', ')
43
43
  }
@@ -50,11 +50,11 @@ export class EmailFactoryService {
50
50
  return instance;
51
51
  } catch (error) {
52
52
  throw new InternalServerErrorException({
53
- message: `Failed to initialize email provider '${config.provider}'`,
53
+ message: `Email provider '${config.provider}' not initialized successfully: ${this.extractErrorMessage(error)}`,
54
54
  messageKey: SYSTEM_MESSAGES.SERVICE_NOT_AVAILABLE,
55
- messageParams: {
55
+ messageVariables: {
56
56
  provider: config.provider,
57
- error: this.extractErrorMessage(error)
57
+ available: EmailProviderRegistry.getAll().join(', ')
58
58
  }
59
59
  });
60
60
  }
@@ -11,8 +11,8 @@ function _define_property(obj, key, value) {
11
11
  }
12
12
  return obj;
13
13
  }
14
- import { InternalServerErrorException } from '@nestjs/common';
15
14
  import { SYSTEM_MESSAGES } from '@flusys/nestjs-shared/constants';
15
+ import { InternalServerErrorException } from '@nestjs/common';
16
16
  const MAILGUN_API_URL = 'https://api.mailgun.net';
17
17
  const MAILGUN_EU_API_URL = 'https://api.eu.mailgun.net';
18
18
  export class MailgunProvider {
@@ -32,7 +32,10 @@ export class MailgunProvider {
32
32
  } catch {
33
33
  throw new InternalServerErrorException({
34
34
  message: 'Mailgun initialization failed. Install: npm install mailgun.js form-data',
35
- messageKey: SYSTEM_MESSAGES.SDK_NOT_INSTALLED
35
+ messageKey: SYSTEM_MESSAGES.SDK_NOT_INSTALLED,
36
+ messageVariables: {
37
+ sdk: 'mailgun'
38
+ }
36
39
  });
37
40
  }
38
41
  }