@flusys/nestjs-email 7.1.0 → 8.0.0-beta.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 (159) hide show
  1. package/config/index.d.ts +3 -3
  2. package/controllers/email-config.controller.d.ts +2 -2
  3. package/controllers/email-send.controller.d.ts +3 -3
  4. package/controllers/email-template.controller.d.ts +4 -4
  5. package/controllers/index.d.ts +3 -3
  6. package/docs/email-swagger.config.d.ts +2 -2
  7. package/docs/index.d.ts +1 -1
  8. package/dtos/email-config.dto.d.ts +1 -1
  9. package/dtos/email-send.dto.d.ts +1 -1
  10. package/dtos/index.d.ts +3 -3
  11. package/entities/email-config-with-company.entity.d.ts +1 -1
  12. package/entities/email-template-with-company.entity.d.ts +1 -1
  13. package/entities/index.d.ts +10 -10
  14. package/enums/index.d.ts +1 -1
  15. package/fesm/261.js +799 -0
  16. package/fesm/493.js +1723 -0
  17. package/fesm/chunks/99.js +12 -0
  18. package/fesm/config/index.js +104 -3
  19. package/fesm/controllers/index.js +396 -3
  20. package/fesm/docs/index.js +134 -1
  21. package/fesm/dtos/index.js +22 -3
  22. package/fesm/entities/index.js +409 -13
  23. package/fesm/enums/index.js +37 -1
  24. package/fesm/index.js +762 -10
  25. package/fesm/interfaces/index.js +18 -4
  26. package/fesm/modules/index.js +541 -1
  27. package/fesm/providers/index.js +523 -5
  28. package/fesm/runtime.js +134 -0
  29. package/fesm/services/index.js +17 -5
  30. package/index.d.ts +10 -10
  31. package/interfaces/email-config.interface.d.ts +2 -2
  32. package/interfaces/email-module-options.interface.d.ts +3 -3
  33. package/interfaces/email-template.interface.d.ts +1 -1
  34. package/interfaces/index.d.ts +4 -4
  35. package/modules/email.module.d.ts +2 -2
  36. package/modules/index.d.ts +1 -1
  37. package/package.json +27 -38
  38. package/providers/email-factory.service.d.ts +2 -2
  39. package/providers/email-provider.registry.d.ts +2 -2
  40. package/providers/index.d.ts +5 -5
  41. package/providers/mailgun-provider.d.ts +1 -1
  42. package/providers/sendgrid-provider.d.ts +1 -1
  43. package/providers/smtp-provider.d.ts +1 -1
  44. package/services/email-config.service.d.ts +3 -3
  45. package/services/email-datasource.provider.d.ts +3 -3
  46. package/services/email-provider-config.service.d.ts +7 -7
  47. package/services/email-send.service.d.ts +7 -7
  48. package/services/email-template.service.d.ts +6 -6
  49. package/services/index.d.ts +5 -5
  50. package/utils/index.d.ts +1 -1
  51. package/cjs/config/email.constants.js +0 -22
  52. package/cjs/config/event-actions.js +0 -34
  53. package/cjs/config/index.js +0 -20
  54. package/cjs/config/message-keys.js +0 -39
  55. package/cjs/controllers/email-config.controller.js +0 -111
  56. package/cjs/controllers/email-config.controller.spec.js +0 -85
  57. package/cjs/controllers/email-send.controller.js +0 -128
  58. package/cjs/controllers/email-send.controller.spec.js +0 -139
  59. package/cjs/controllers/email-template.controller.js +0 -142
  60. package/cjs/controllers/email-template.controller.spec.js +0 -89
  61. package/cjs/controllers/index.js +0 -20
  62. package/cjs/docs/email-swagger.config.js +0 -116
  63. package/cjs/docs/email-swagger.config.spec.js +0 -62
  64. package/cjs/docs/index.js +0 -11
  65. package/cjs/dtos/email-config.dto.js +0 -212
  66. package/cjs/dtos/email-send.dto.js +0 -354
  67. package/cjs/dtos/email-template.dto.js +0 -252
  68. package/cjs/dtos/index.js +0 -20
  69. package/cjs/entities/email-config-with-company.entity.js +0 -63
  70. package/cjs/entities/email-config.entity.js +0 -114
  71. package/cjs/entities/email-template-with-company.entity.js +0 -65
  72. package/cjs/entities/email-template.entity.js +0 -136
  73. package/cjs/entities/index.js +0 -56
  74. package/cjs/entities/index.spec.js +0 -18
  75. package/cjs/enums/email-provider-type.enum.js +0 -18
  76. package/cjs/enums/index.js +0 -18
  77. package/cjs/index.js +0 -28
  78. package/cjs/interfaces/email-config.interface.js +0 -4
  79. package/cjs/interfaces/email-module-options.interface.js +0 -4
  80. package/cjs/interfaces/email-provider.interface.js +0 -4
  81. package/cjs/interfaces/email-template.interface.js +0 -4
  82. package/cjs/interfaces/index.js +0 -21
  83. package/cjs/modules/email.module.js +0 -122
  84. package/cjs/modules/email.module.spec.js +0 -142
  85. package/cjs/modules/index.js +0 -18
  86. package/cjs/providers/email-factory.service.js +0 -113
  87. package/cjs/providers/email-factory.service.spec.js +0 -242
  88. package/cjs/providers/email-provider.registry.js +0 -41
  89. package/cjs/providers/email-provider.registry.spec.js +0 -58
  90. package/cjs/providers/index.js +0 -22
  91. package/cjs/providers/mailgun-provider.js +0 -119
  92. package/cjs/providers/mailgun-provider.spec.js +0 -244
  93. package/cjs/providers/sendgrid-provider.js +0 -129
  94. package/cjs/providers/sendgrid-provider.spec.js +0 -346
  95. package/cjs/providers/smtp-provider.js +0 -164
  96. package/cjs/providers/smtp-provider.spec.js +0 -327
  97. package/cjs/services/email-config.service.js +0 -71
  98. package/cjs/services/email-config.service.spec.js +0 -69
  99. package/cjs/services/email-datasource.provider.js +0 -84
  100. package/cjs/services/email-datasource.provider.spec.js +0 -135
  101. package/cjs/services/email-provider-config.service.js +0 -159
  102. package/cjs/services/email-provider-config.service.spec.js +0 -269
  103. package/cjs/services/email-send.service.js +0 -315
  104. package/cjs/services/email-send.service.spec.js +0 -614
  105. package/cjs/services/email-template.service.js +0 -144
  106. package/cjs/services/email-template.service.spec.js +0 -261
  107. package/cjs/services/index.js +0 -22
  108. package/cjs/utils/email-templates.util.js +0 -64
  109. package/cjs/utils/email-templates.util.spec.js +0 -61
  110. package/cjs/utils/index.js +0 -18
  111. package/fesm/config/email.constants.js +0 -4
  112. package/fesm/config/event-actions.js +0 -13
  113. package/fesm/config/message-keys.js +0 -18
  114. package/fesm/controllers/email-config.controller.js +0 -101
  115. package/fesm/controllers/email-config.controller.spec.js +0 -81
  116. package/fesm/controllers/email-send.controller.js +0 -118
  117. package/fesm/controllers/email-send.controller.spec.js +0 -135
  118. package/fesm/controllers/email-template.controller.js +0 -132
  119. package/fesm/controllers/email-template.controller.spec.js +0 -85
  120. package/fesm/docs/email-swagger.config.js +0 -109
  121. package/fesm/docs/email-swagger.config.spec.js +0 -58
  122. package/fesm/dtos/email-config.dto.js +0 -191
  123. package/fesm/dtos/email-send.dto.js +0 -324
  124. package/fesm/dtos/email-template.dto.js +0 -231
  125. package/fesm/entities/email-config-with-company.entity.js +0 -53
  126. package/fesm/entities/email-config.entity.js +0 -104
  127. package/fesm/entities/email-template-with-company.entity.js +0 -55
  128. package/fesm/entities/email-template.entity.js +0 -126
  129. package/fesm/entities/index.spec.js +0 -14
  130. package/fesm/enums/email-provider-type.enum.js +0 -8
  131. package/fesm/interfaces/email-config.interface.js +0 -1
  132. package/fesm/interfaces/email-module-options.interface.js +0 -1
  133. package/fesm/interfaces/email-provider.interface.js +0 -1
  134. package/fesm/interfaces/email-template.interface.js +0 -1
  135. package/fesm/modules/email.module.js +0 -112
  136. package/fesm/modules/email.module.spec.js +0 -138
  137. package/fesm/providers/email-factory.service.js +0 -103
  138. package/fesm/providers/email-factory.service.spec.js +0 -238
  139. package/fesm/providers/email-provider.registry.js +0 -31
  140. package/fesm/providers/email-provider.registry.spec.js +0 -54
  141. package/fesm/providers/mailgun-provider.js +0 -109
  142. package/fesm/providers/mailgun-provider.spec.js +0 -240
  143. package/fesm/providers/sendgrid-provider.js +0 -119
  144. package/fesm/providers/sendgrid-provider.spec.js +0 -342
  145. package/fesm/providers/smtp-provider.js +0 -113
  146. package/fesm/providers/smtp-provider.spec.js +0 -282
  147. package/fesm/services/email-config.service.js +0 -61
  148. package/fesm/services/email-config.service.spec.js +0 -65
  149. package/fesm/services/email-datasource.provider.js +0 -74
  150. package/fesm/services/email-datasource.provider.spec.js +0 -131
  151. package/fesm/services/email-provider-config.service.js +0 -149
  152. package/fesm/services/email-provider-config.service.spec.js +0 -265
  153. package/fesm/services/email-send.service.js +0 -305
  154. package/fesm/services/email-send.service.spec.js +0 -610
  155. package/fesm/services/email-template.service.js +0 -134
  156. package/fesm/services/email-template.service.spec.js +0 -257
  157. package/fesm/utils/email-templates.util.js +0 -47
  158. package/fesm/utils/email-templates.util.spec.js +0 -57
  159. package/fesm/utils/index.js +0 -1
@@ -1,142 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- const _emailmodule = require("./email.module");
6
- const _emailconstants = require("../config/email.constants");
7
- const _controllers = require("../controllers");
8
- function _define_property(obj, key, value) {
9
- if (key in obj) {
10
- Object.defineProperty(obj, key, {
11
- value: value,
12
- enumerable: true,
13
- configurable: true,
14
- writable: true
15
- });
16
- } else {
17
- obj[key] = value;
18
- }
19
- return obj;
20
- }
21
- function providerTokens(providers) {
22
- return providers.map((p)=>typeof p === 'function' ? p : p.provide);
23
- }
24
- describe('EmailModule', ()=>{
25
- describe('forRoot', ()=>{
26
- it('should default to a non-global module with all controllers registered', ()=>{
27
- const dynamicModule = _emailmodule.EmailModule.forRoot({});
28
- expect(dynamicModule.module).toBe(_emailmodule.EmailModule);
29
- expect(dynamicModule.global).toBe(false);
30
- expect(dynamicModule.controllers).toEqual([
31
- _controllers.EmailConfigController,
32
- _controllers.EmailTemplateController,
33
- _controllers.EmailSendController
34
- ]);
35
- });
36
- it('should respect global: true', ()=>{
37
- expect(_emailmodule.EmailModule.forRoot({
38
- global: true
39
- }).global).toBe(true);
40
- });
41
- it('should register no controllers when includeController is false', ()=>{
42
- expect(_emailmodule.EmailModule.forRoot({
43
- includeController: false
44
- }).controllers).toEqual([]);
45
- });
46
- it('should register a EMAIL_MODULE_OPTIONS provider carrying the given options', ()=>{
47
- const options = {
48
- bootstrapAppConfig: {
49
- enableCompanyFeature: true
50
- }
51
- };
52
- const dynamicModule = _emailmodule.EmailModule.forRoot(options);
53
- const provider = dynamicModule.providers.find((p)=>p.provide === _emailconstants.EMAIL_MODULE_OPTIONS);
54
- expect(provider.useValue).toBe(options);
55
- });
56
- it('should always export the same fixed set of services', ()=>{
57
- expect(_emailmodule.EmailModule.forRoot({}).exports).toHaveLength(6);
58
- });
59
- });
60
- describe('forRootAsync', ()=>{
61
- it('should forward external imports alongside CacheModule/UtilsModule', ()=>{
62
- let FakeImportedModule = class FakeImportedModule {
63
- };
64
- const dynamicModule = _emailmodule.EmailModule.forRootAsync({
65
- bootstrapAppConfig: {},
66
- imports: [
67
- FakeImportedModule
68
- ]
69
- });
70
- expect(dynamicModule.imports).toEqual(expect.arrayContaining([
71
- FakeImportedModule
72
- ]));
73
- });
74
- it('useFactory: builds an EMAIL_MODULE_OPTIONS provider that merges resolved config into the static options', async ()=>{
75
- const useFactory = jest.fn().mockResolvedValue({
76
- defaultFrom: 'noreply@flusys.io'
77
- });
78
- const dynamicModule = _emailmodule.EmailModule.forRootAsync({
79
- bootstrapAppConfig: {},
80
- useFactory,
81
- inject: [
82
- 'SOME_TOKEN'
83
- ]
84
- });
85
- const provider = dynamicModule.providers.find((p)=>p.provide === _emailconstants.EMAIL_MODULE_OPTIONS);
86
- expect(provider.inject).toEqual([
87
- 'SOME_TOKEN'
88
- ]);
89
- const resolved = await provider.useFactory('injected');
90
- expect(useFactory).toHaveBeenCalledWith('injected');
91
- expect(resolved.config).toEqual({
92
- defaultFrom: 'noreply@flusys.io'
93
- });
94
- });
95
- it('useClass: registers both the class provider and an options provider calling createEmailOptions()', async ()=>{
96
- let MyOptionsFactory = class MyOptionsFactory {
97
- constructor(){
98
- _define_property(this, "createEmailOptions", jest.fn().mockResolvedValue({
99
- defaultFrom: 'from-class@flusys.io'
100
- }));
101
- }
102
- };
103
- const dynamicModule = _emailmodule.EmailModule.forRootAsync({
104
- bootstrapAppConfig: {},
105
- useClass: MyOptionsFactory
106
- });
107
- const classProvider = dynamicModule.providers.find((p)=>p.provide === MyOptionsFactory);
108
- expect(classProvider.useClass).toBe(MyOptionsFactory);
109
- const optionsProvider = dynamicModule.providers.find((p)=>p.provide === _emailconstants.EMAIL_MODULE_OPTIONS);
110
- const instance = new MyOptionsFactory();
111
- const resolved = await optionsProvider.useFactory(instance);
112
- expect(instance.createEmailOptions).toHaveBeenCalled();
113
- expect(resolved.config).toEqual({
114
- defaultFrom: 'from-class@flusys.io'
115
- });
116
- });
117
- it('useExisting: registers a single options provider without a duplicate class registration', async ()=>{
118
- let MyOptionsFactory = class MyOptionsFactory {
119
- constructor(){
120
- _define_property(this, "createEmailOptions", jest.fn().mockResolvedValue({
121
- defaultFrom: 'from-existing@flusys.io'
122
- }));
123
- }
124
- };
125
- const dynamicModule = _emailmodule.EmailModule.forRootAsync({
126
- bootstrapAppConfig: {},
127
- useExisting: MyOptionsFactory
128
- });
129
- expect(dynamicModule.providers.filter((p)=>p.provide === MyOptionsFactory)).toHaveLength(0);
130
- const optionsProvider = dynamicModule.providers.find((p)=>p.provide === _emailconstants.EMAIL_MODULE_OPTIONS);
131
- expect(optionsProvider.inject).toEqual([
132
- MyOptionsFactory
133
- ]);
134
- });
135
- it('should register no EMAIL_MODULE_OPTIONS provider when neither useFactory, useClass, nor useExisting is given', ()=>{
136
- const dynamicModule = _emailmodule.EmailModule.forRootAsync({
137
- bootstrapAppConfig: {}
138
- });
139
- expect(providerTokens(dynamicModule.providers)).not.toContain(_emailconstants.EMAIL_MODULE_OPTIONS);
140
- });
141
- });
142
- });
@@ -1,18 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- _export_star(require("./email.module"), exports);
6
- function _export_star(from, to) {
7
- Object.keys(from).forEach(function(k) {
8
- if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
9
- Object.defineProperty(to, k, {
10
- enumerable: true,
11
- get: function() {
12
- return from[k];
13
- }
14
- });
15
- }
16
- });
17
- return from;
18
- }
@@ -1,113 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "EmailFactoryService", {
6
- enumerable: true,
7
- get: function() {
8
- return EmailFactoryService;
9
- }
10
- });
11
- const _nestjsshared = require("@flusys/nestjs-shared");
12
- const _common = require("@nestjs/common");
13
- const _crypto = require("crypto");
14
- const _config = require("../config");
15
- const _interfaces = require("../interfaces");
16
- const _emailproviderregistry = require("./email-provider.registry");
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
- let EmailFactoryService = class EmailFactoryService {
40
- // ─── Public API ─────────────────────────────────────────────────────────────
41
- async createProvider(config) {
42
- const cacheKey = this.generateCacheKey(config);
43
- const cached = this.providerCache.get(cacheKey);
44
- if (cached) return cached;
45
- const ProviderClass = _emailproviderregistry.EmailProviderRegistry.get(config.provider);
46
- if (!ProviderClass) {
47
- throw new _common.NotFoundException({
48
- message: `Email provider '${config.provider}' is not registered`,
49
- messageKey: _config.EMAIL_SEND_MESSAGES.CONFIG_NOT_FOUND,
50
- messageVariables: {
51
- provider: config.provider,
52
- available: _emailproviderregistry.EmailProviderRegistry.getAll().join(', ')
53
- }
54
- });
55
- }
56
- try {
57
- const instance = new ProviderClass();
58
- await instance.initialize?.(config.config);
59
- this.providerCache.set(cacheKey, instance);
60
- return instance;
61
- } catch (error) {
62
- throw new _common.InternalServerErrorException({
63
- message: `Email provider '${config.provider}' not initialized successfully: ${this.extractErrorMessage(error)}`,
64
- messageKey: _nestjsshared.SYSTEM_MESSAGES.SERVICE_NOT_AVAILABLE,
65
- messageVariables: {
66
- provider: config.provider,
67
- available: _emailproviderregistry.EmailProviderRegistry.getAll().join(', ')
68
- }
69
- });
70
- }
71
- }
72
- // ─── Lifecycle ──────────────────────────────────────────────────────────────
73
- async onModuleDestroy() {
74
- const closePromises = Array.from(this.providerCache.entries()).map(([, provider])=>this.closeProvider(provider));
75
- await Promise.allSettled(closePromises);
76
- this.providerCache.clear();
77
- }
78
- // ─── Private Helpers ────────────────────────────────────────────────────────
79
- generateCacheKey(config) {
80
- const sortedKeys = Object.keys(config.config || {}).sort();
81
- const configString = JSON.stringify(config.config, sortedKeys);
82
- const hash = (0, _crypto.createHash)('sha256').update(configString).digest('hex').substring(0, 16);
83
- return `${config.provider}-${hash}`;
84
- }
85
- async closeProvider(provider) {
86
- if (!provider.close) return;
87
- try {
88
- await provider.close();
89
- } catch {
90
- // Silent failure
91
- }
92
- }
93
- extractErrorMessage(error) {
94
- return error instanceof Error ? error.message : 'Unknown error';
95
- }
96
- constructor(){
97
- _define_property(this, "providerCache", new Map());
98
- }
99
- };
100
- _ts_decorate([
101
- (0, _nestjsshared.LogAction)({
102
- action: 'email.createProvider',
103
- module: 'email'
104
- }),
105
- _ts_metadata("design:type", Function),
106
- _ts_metadata("design:paramtypes", [
107
- typeof _interfaces.IEmailProviderConfig === "undefined" ? Object : _interfaces.IEmailProviderConfig
108
- ]),
109
- _ts_metadata("design:returntype", Promise)
110
- ], EmailFactoryService.prototype, "createProvider", null);
111
- EmailFactoryService = _ts_decorate([
112
- (0, _common.Injectable)()
113
- ], EmailFactoryService);
@@ -1,242 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- const _common = require("@nestjs/common");
6
- const _emailfactoryservice = require("./email-factory.service");
7
- const _emailproviderregistry = require("./email-provider.registry");
8
- function _define_property(obj, key, value) {
9
- if (key in obj) {
10
- Object.defineProperty(obj, key, {
11
- value: value,
12
- enumerable: true,
13
- configurable: true,
14
- writable: true
15
- });
16
- } else {
17
- obj[key] = value;
18
- }
19
- return obj;
20
- }
21
- let FakeSuccessProvider = class FakeSuccessProvider {
22
- async initialize(_config) {
23
- FakeSuccessProvider.initializeCalls += 1;
24
- }
25
- async sendEmail(_options) {
26
- return {
27
- success: true
28
- };
29
- }
30
- async sendBulkEmails(_options) {
31
- return [];
32
- }
33
- async healthCheck() {
34
- return true;
35
- }
36
- async close() {
37
- this.closeCalled = true;
38
- }
39
- constructor(){
40
- _define_property(this, "closeCalled", false);
41
- FakeSuccessProvider.instances.push(this);
42
- }
43
- };
44
- _define_property(FakeSuccessProvider, "initializeCalls", 0);
45
- _define_property(FakeSuccessProvider, "instances", []);
46
- let FakeFailingInitProvider = class FakeFailingInitProvider {
47
- async initialize(_config) {
48
- throw new Error('boom during init');
49
- }
50
- async sendEmail(_options) {
51
- return {
52
- success: true
53
- };
54
- }
55
- async sendBulkEmails(_options) {
56
- return [];
57
- }
58
- async healthCheck() {
59
- return true;
60
- }
61
- };
62
- let FakeNoInitializeProvider = class FakeNoInitializeProvider {
63
- async sendEmail(_options) {
64
- return {
65
- success: true
66
- };
67
- }
68
- async sendBulkEmails(_options) {
69
- return [];
70
- }
71
- async healthCheck() {
72
- return true;
73
- }
74
- };
75
- describe('EmailFactoryService', ()=>{
76
- let service;
77
- beforeEach(()=>{
78
- service = new _emailfactoryservice.EmailFactoryService();
79
- _emailproviderregistry.EmailProviderRegistry.clear();
80
- FakeSuccessProvider.initializeCalls = 0;
81
- FakeSuccessProvider.instances = [];
82
- });
83
- afterEach(()=>{
84
- _emailproviderregistry.EmailProviderRegistry.clear();
85
- });
86
- describe('createProvider', ()=>{
87
- it('throws NotFoundException when the provider is not registered', async ()=>{
88
- const config = {
89
- provider: 'unknown',
90
- config: {}
91
- };
92
- await expect(service.createProvider(config)).rejects.toThrow(_common.NotFoundException);
93
- });
94
- it('throws NotFoundException with the config-not-found messageKey and available list', async ()=>{
95
- _emailproviderregistry.EmailProviderRegistry.register('smtp', FakeSuccessProvider);
96
- const config = {
97
- provider: 'unknown',
98
- config: {}
99
- };
100
- try {
101
- await service.createProvider(config);
102
- fail('expected createProvider to throw');
103
- } catch (error) {
104
- expect(error).toBeInstanceOf(_common.NotFoundException);
105
- expect(error.getResponse()).toEqual(expect.objectContaining({
106
- messageKey: 'email.send.config.not.found'
107
- }));
108
- }
109
- });
110
- it('instantiates and initializes the provider on cache miss', async ()=>{
111
- _emailproviderregistry.EmailProviderRegistry.register('smtp', FakeSuccessProvider);
112
- const config = {
113
- provider: 'smtp',
114
- config: {
115
- host: 'localhost'
116
- }
117
- };
118
- const provider = await service.createProvider(config);
119
- expect(provider).toBeInstanceOf(FakeSuccessProvider);
120
- expect(FakeSuccessProvider.initializeCalls).toBe(1);
121
- });
122
- it('returns the cached provider instance for an identical config (no re-initialization)', async ()=>{
123
- _emailproviderregistry.EmailProviderRegistry.register('smtp', FakeSuccessProvider);
124
- const config = {
125
- provider: 'smtp',
126
- config: {
127
- host: 'localhost'
128
- }
129
- };
130
- const first = await service.createProvider(config);
131
- const second = await service.createProvider(config);
132
- expect(second).toBe(first);
133
- expect(FakeSuccessProvider.initializeCalls).toBe(1);
134
- });
135
- it('creates a distinct cached instance for a different config on the same provider', async ()=>{
136
- _emailproviderregistry.EmailProviderRegistry.register('smtp', FakeSuccessProvider);
137
- const first = await service.createProvider({
138
- provider: 'smtp',
139
- config: {
140
- host: 'a'
141
- }
142
- });
143
- const second = await service.createProvider({
144
- provider: 'smtp',
145
- config: {
146
- host: 'b'
147
- }
148
- });
149
- expect(second).not.toBe(first);
150
- expect(FakeSuccessProvider.initializeCalls).toBe(2);
151
- });
152
- it('is insensitive to key ordering when hashing the config for the cache key', async ()=>{
153
- _emailproviderregistry.EmailProviderRegistry.register('smtp', FakeSuccessProvider);
154
- const first = await service.createProvider({
155
- provider: 'smtp',
156
- config: {
157
- a: 1,
158
- b: 2
159
- }
160
- });
161
- const second = await service.createProvider({
162
- provider: 'smtp',
163
- config: {
164
- b: 2,
165
- a: 1
166
- }
167
- });
168
- expect(second).toBe(first);
169
- expect(FakeSuccessProvider.initializeCalls).toBe(1);
170
- });
171
- it('does not call initialize when the provider class has no initialize method', async ()=>{
172
- _emailproviderregistry.EmailProviderRegistry.register('smtp', FakeNoInitializeProvider);
173
- const config = {
174
- provider: 'smtp',
175
- config: {}
176
- };
177
- const provider = await service.createProvider(config);
178
- expect(provider).toBeInstanceOf(FakeNoInitializeProvider);
179
- });
180
- it('wraps initialize() failures in InternalServerErrorException with SDK_NOT_INSTALLED messageKey', async ()=>{
181
- _emailproviderregistry.EmailProviderRegistry.register('mailgun', FakeFailingInitProvider);
182
- const config = {
183
- provider: 'mailgun',
184
- config: {}
185
- };
186
- try {
187
- await service.createProvider(config);
188
- fail('expected createProvider to throw');
189
- } catch (error) {
190
- expect(error).toBeInstanceOf(_common.InternalServerErrorException);
191
- expect(error.getResponse()).toEqual(expect.objectContaining({
192
- messageKey: 'system.service.not.available'
193
- }));
194
- expect(error.getResponse().message).toContain('boom during init');
195
- }
196
- });
197
- it('does not cache a provider that failed to initialize', async ()=>{
198
- _emailproviderregistry.EmailProviderRegistry.register('mailgun', FakeFailingInitProvider);
199
- const config = {
200
- provider: 'mailgun',
201
- config: {}
202
- };
203
- await expect(service.createProvider(config)).rejects.toThrow();
204
- // second attempt should also go through the (still failing) initialization path
205
- await expect(service.createProvider(config)).rejects.toThrow();
206
- });
207
- });
208
- describe('onModuleDestroy', ()=>{
209
- it('closes every cached provider and clears the cache', async ()=>{
210
- _emailproviderregistry.EmailProviderRegistry.register('smtp', FakeSuccessProvider);
211
- const provider = await service.createProvider({
212
- provider: 'smtp',
213
- config: {}
214
- });
215
- await service.onModuleDestroy();
216
- expect(provider.closeCalled).toBe(true);
217
- // cache cleared -> a subsequent createProvider call re-initializes
218
- _emailproviderregistry.EmailProviderRegistry.register('smtp', FakeSuccessProvider);
219
- await service.createProvider({
220
- provider: 'smtp',
221
- config: {}
222
- });
223
- expect(FakeSuccessProvider.initializeCalls).toBe(2);
224
- });
225
- it('does not throw when a provider close() call rejects', async ()=>{
226
- let FakeThrowingCloseProvider = class FakeThrowingCloseProvider extends FakeSuccessProvider {
227
- async close() {
228
- throw new Error('close failed');
229
- }
230
- };
231
- _emailproviderregistry.EmailProviderRegistry.register('smtp', FakeThrowingCloseProvider);
232
- await service.createProvider({
233
- provider: 'smtp',
234
- config: {}
235
- });
236
- await expect(service.onModuleDestroy()).resolves.toBeUndefined();
237
- });
238
- it('is a no-op when nothing has been cached', async ()=>{
239
- await expect(service.onModuleDestroy()).resolves.toBeUndefined();
240
- });
241
- });
242
- });
@@ -1,41 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "EmailProviderRegistry", {
6
- enumerable: true,
7
- get: function() {
8
- return EmailProviderRegistry;
9
- }
10
- });
11
- function _define_property(obj, key, value) {
12
- if (key in obj) {
13
- Object.defineProperty(obj, key, {
14
- value: value,
15
- enumerable: true,
16
- configurable: true,
17
- writable: true
18
- });
19
- } else {
20
- obj[key] = value;
21
- }
22
- return obj;
23
- }
24
- let EmailProviderRegistry = class EmailProviderRegistry {
25
- static register(providerName, providerClass) {
26
- this.providers.set(providerName.toLowerCase(), providerClass);
27
- }
28
- static get(providerName) {
29
- return this.providers.get(providerName.toLowerCase());
30
- }
31
- static has(providerName) {
32
- return this.providers.has(providerName.toLowerCase());
33
- }
34
- static getAll() {
35
- return Array.from(this.providers.keys());
36
- }
37
- static clear() {
38
- this.providers.clear();
39
- }
40
- };
41
- _define_property(EmailProviderRegistry, "providers", new Map());
@@ -1,58 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- const _emailproviderregistry = require("./email-provider.registry");
6
- let FakeProvider = class FakeProvider {
7
- async sendEmail(_options) {
8
- return {
9
- success: true
10
- };
11
- }
12
- async sendBulkEmails(_options) {
13
- return [];
14
- }
15
- async healthCheck() {
16
- return true;
17
- }
18
- };
19
- describe('EmailProviderRegistry', ()=>{
20
- afterEach(()=>{
21
- _emailproviderregistry.EmailProviderRegistry.clear();
22
- });
23
- it('registers and retrieves a provider by exact name', ()=>{
24
- _emailproviderregistry.EmailProviderRegistry.register('smtp', FakeProvider);
25
- expect(_emailproviderregistry.EmailProviderRegistry.get('smtp')).toBe(FakeProvider);
26
- });
27
- it('normalizes provider names to lowercase on register and lookup', ()=>{
28
- _emailproviderregistry.EmailProviderRegistry.register('SendGrid', FakeProvider);
29
- expect(_emailproviderregistry.EmailProviderRegistry.get('sendgrid')).toBe(FakeProvider);
30
- expect(_emailproviderregistry.EmailProviderRegistry.get('SENDGRID')).toBe(FakeProvider);
31
- expect(_emailproviderregistry.EmailProviderRegistry.has('sendgrid')).toBe(true);
32
- });
33
- it('returns undefined for an unregistered provider', ()=>{
34
- expect(_emailproviderregistry.EmailProviderRegistry.get('unknown-provider')).toBeUndefined();
35
- expect(_emailproviderregistry.EmailProviderRegistry.has('unknown-provider')).toBe(false);
36
- });
37
- it('lists all registered provider names', ()=>{
38
- _emailproviderregistry.EmailProviderRegistry.register('smtp', FakeProvider);
39
- _emailproviderregistry.EmailProviderRegistry.register('mailgun', FakeProvider);
40
- expect(_emailproviderregistry.EmailProviderRegistry.getAll().sort()).toEqual([
41
- 'mailgun',
42
- 'smtp'
43
- ]);
44
- });
45
- it('clears all registered providers', ()=>{
46
- _emailproviderregistry.EmailProviderRegistry.register('smtp', FakeProvider);
47
- _emailproviderregistry.EmailProviderRegistry.clear();
48
- expect(_emailproviderregistry.EmailProviderRegistry.getAll()).toEqual([]);
49
- expect(_emailproviderregistry.EmailProviderRegistry.has('smtp')).toBe(false);
50
- });
51
- it('overwrites a previously registered provider for the same name', ()=>{
52
- let OtherProvider = class OtherProvider extends FakeProvider {
53
- };
54
- _emailproviderregistry.EmailProviderRegistry.register('smtp', FakeProvider);
55
- _emailproviderregistry.EmailProviderRegistry.register('smtp', OtherProvider);
56
- expect(_emailproviderregistry.EmailProviderRegistry.get('smtp')).toBe(OtherProvider);
57
- });
58
- });
@@ -1,22 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- _export_star(require("./email-provider.registry"), exports);
6
- _export_star(require("./email-factory.service"), exports);
7
- _export_star(require("./smtp-provider"), exports);
8
- _export_star(require("./sendgrid-provider"), exports);
9
- _export_star(require("./mailgun-provider"), exports);
10
- function _export_star(from, to) {
11
- Object.keys(from).forEach(function(k) {
12
- if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
13
- Object.defineProperty(to, k, {
14
- enumerable: true,
15
- get: function() {
16
- return from[k];
17
- }
18
- });
19
- }
20
- });
21
- return from;
22
- }