@application-kit/mailer 0.0.0-stage → 0.1.0

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 (177) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +21 -0
  3. package/README.md +74 -2
  4. package/dist/cjs/application/errors/index.d.ts +1 -0
  5. package/dist/cjs/application/errors/index.js +17 -0
  6. package/dist/cjs/application/errors/send-email.error.d.ts +8 -0
  7. package/dist/cjs/application/errors/send-email.error.js +12 -0
  8. package/dist/cjs/application/index.d.ts +3 -0
  9. package/dist/cjs/application/index.js +19 -0
  10. package/dist/cjs/application/ports/email-sender.interface.d.ts +14 -0
  11. package/dist/cjs/application/ports/email-sender.interface.js +2 -0
  12. package/dist/cjs/application/ports/email-subscriptions.interface.d.ts +10 -0
  13. package/dist/cjs/application/ports/email-subscriptions.interface.js +2 -0
  14. package/dist/cjs/application/ports/email-template-catalog.interface.d.ts +8 -0
  15. package/dist/cjs/application/ports/email-template-catalog.interface.js +2 -0
  16. package/dist/cjs/application/ports/email-template-renderer.interface.d.ts +9 -0
  17. package/dist/cjs/application/ports/email-template-renderer.interface.js +2 -0
  18. package/dist/cjs/application/ports/index.d.ts +7 -0
  19. package/dist/cjs/application/ports/index.js +23 -0
  20. package/dist/cjs/application/ports/mailer-logger.interface.d.ts +5 -0
  21. package/dist/cjs/application/ports/mailer-logger.interface.js +2 -0
  22. package/dist/cjs/application/ports/mailer.interface.d.ts +9 -0
  23. package/dist/cjs/application/ports/mailer.interface.js +2 -0
  24. package/dist/cjs/application/ports/sent-email-log.interface.d.ts +4 -0
  25. package/dist/cjs/application/ports/sent-email-log.interface.js +2 -0
  26. package/dist/cjs/application/services/email-dispatcher.service.d.ts +12 -0
  27. package/dist/cjs/application/services/email-dispatcher.service.js +56 -0
  28. package/dist/cjs/application/services/email-idempotency-key.service.d.ts +4 -0
  29. package/dist/cjs/application/services/email-idempotency-key.service.js +24 -0
  30. package/dist/cjs/application/services/email-sender.service.d.ts +17 -0
  31. package/dist/cjs/application/services/email-sender.service.js +69 -0
  32. package/dist/cjs/application/services/index.d.ts +3 -0
  33. package/dist/cjs/application/services/index.js +19 -0
  34. package/dist/cjs/configs/envs/index.d.ts +1 -0
  35. package/dist/cjs/configs/envs/index.js +17 -0
  36. package/dist/cjs/configs/envs/mailer.environment.d.ts +7 -0
  37. package/dist/cjs/configs/envs/mailer.environment.js +48 -0
  38. package/dist/cjs/configs/index.d.ts +2 -0
  39. package/dist/cjs/configs/index.js +18 -0
  40. package/dist/cjs/configs/mailer.config.d.ts +15 -0
  41. package/dist/cjs/configs/mailer.config.js +41 -0
  42. package/dist/cjs/constants.d.ts +7 -0
  43. package/dist/cjs/constants.js +10 -0
  44. package/dist/cjs/index.d.ts +6 -0
  45. package/dist/cjs/index.js +22 -0
  46. package/dist/cjs/infrastructure/adapters/index.d.ts +3 -0
  47. package/dist/cjs/infrastructure/adapters/index.js +19 -0
  48. package/dist/cjs/infrastructure/adapters/interpolating-email-template-renderer.d.ts +7 -0
  49. package/dist/cjs/infrastructure/adapters/interpolating-email-template-renderer.js +52 -0
  50. package/dist/cjs/infrastructure/adapters/json-mailer.adapter.d.ts +7 -0
  51. package/dist/cjs/infrastructure/adapters/json-mailer.adapter.js +28 -0
  52. package/dist/cjs/infrastructure/adapters/smtp-mailer.adapter.d.ts +8 -0
  53. package/dist/cjs/infrastructure/adapters/smtp-mailer.adapter.js +44 -0
  54. package/dist/cjs/infrastructure/database/index.d.ts +1 -0
  55. package/dist/cjs/infrastructure/database/index.js +17 -0
  56. package/dist/cjs/infrastructure/database/typeorm/entities/index.d.ts +1 -0
  57. package/dist/cjs/infrastructure/database/typeorm/entities/index.js +17 -0
  58. package/dist/cjs/infrastructure/database/typeorm/entities/sent-email.entity.d.ts +4 -0
  59. package/dist/cjs/infrastructure/database/typeorm/entities/sent-email.entity.js +30 -0
  60. package/dist/cjs/infrastructure/database/typeorm/index.d.ts +3 -0
  61. package/dist/cjs/infrastructure/database/typeorm/index.js +19 -0
  62. package/dist/cjs/infrastructure/database/typeorm/migrations/add-sent-emails.migration.d.ts +6 -0
  63. package/dist/cjs/infrastructure/database/typeorm/migrations/add-sent-emails.migration.js +13 -0
  64. package/dist/cjs/infrastructure/database/typeorm/migrations/index.d.ts +1 -0
  65. package/dist/cjs/infrastructure/database/typeorm/migrations/index.js +17 -0
  66. package/dist/cjs/infrastructure/database/typeorm/repositories/index.d.ts +1 -0
  67. package/dist/cjs/infrastructure/database/typeorm/repositories/index.js +17 -0
  68. package/dist/cjs/infrastructure/database/typeorm/repositories/sent-email-log.repository.d.ts +9 -0
  69. package/dist/cjs/infrastructure/database/typeorm/repositories/sent-email-log.repository.js +44 -0
  70. package/dist/cjs/infrastructure/index.d.ts +2 -0
  71. package/dist/cjs/infrastructure/index.js +18 -0
  72. package/dist/cjs/mailer-logger.d.ts +5 -0
  73. package/dist/cjs/mailer-logger.js +59 -0
  74. package/dist/cjs/mailer.module.d.ts +9 -0
  75. package/dist/cjs/mailer.module.js +55 -0
  76. package/dist/cjs/package.json +3 -0
  77. package/dist/cjs/testing/email-sender.fake.d.ts +7 -0
  78. package/dist/cjs/testing/email-sender.fake.js +15 -0
  79. package/dist/cjs/testing/email-subscriptions.fake.d.ts +6 -0
  80. package/dist/cjs/testing/email-subscriptions.fake.js +15 -0
  81. package/dist/cjs/testing/email-template-catalog.fake.d.ts +11 -0
  82. package/dist/cjs/testing/email-template-catalog.fake.js +15 -0
  83. package/dist/cjs/testing/email-template-renderer.fake.d.ts +12 -0
  84. package/dist/cjs/testing/email-template-renderer.fake.js +19 -0
  85. package/dist/cjs/testing/index.d.ts +6 -0
  86. package/dist/cjs/testing/index.js +22 -0
  87. package/dist/cjs/testing/mailer.fake.d.ts +8 -0
  88. package/dist/cjs/testing/mailer.fake.js +21 -0
  89. package/dist/cjs/testing/sent-email-log.fake.d.ts +8 -0
  90. package/dist/cjs/testing/sent-email-log.fake.js +26 -0
  91. package/dist/esm/application/errors/index.d.ts +1 -0
  92. package/dist/esm/application/errors/index.js +1 -0
  93. package/dist/esm/application/errors/send-email.error.d.ts +8 -0
  94. package/dist/esm/application/errors/send-email.error.js +8 -0
  95. package/dist/esm/application/index.d.ts +3 -0
  96. package/dist/esm/application/index.js +3 -0
  97. package/dist/esm/application/ports/email-sender.interface.d.ts +14 -0
  98. package/dist/esm/application/ports/email-sender.interface.js +1 -0
  99. package/dist/esm/application/ports/email-subscriptions.interface.d.ts +10 -0
  100. package/dist/esm/application/ports/email-subscriptions.interface.js +1 -0
  101. package/dist/esm/application/ports/email-template-catalog.interface.d.ts +8 -0
  102. package/dist/esm/application/ports/email-template-catalog.interface.js +1 -0
  103. package/dist/esm/application/ports/email-template-renderer.interface.d.ts +9 -0
  104. package/dist/esm/application/ports/email-template-renderer.interface.js +1 -0
  105. package/dist/esm/application/ports/index.d.ts +7 -0
  106. package/dist/esm/application/ports/index.js +7 -0
  107. package/dist/esm/application/ports/mailer-logger.interface.d.ts +5 -0
  108. package/dist/esm/application/ports/mailer-logger.interface.js +1 -0
  109. package/dist/esm/application/ports/mailer.interface.d.ts +9 -0
  110. package/dist/esm/application/ports/mailer.interface.js +1 -0
  111. package/dist/esm/application/ports/sent-email-log.interface.d.ts +4 -0
  112. package/dist/esm/application/ports/sent-email-log.interface.js +1 -0
  113. package/dist/esm/application/services/email-dispatcher.service.d.ts +12 -0
  114. package/dist/esm/application/services/email-dispatcher.service.js +53 -0
  115. package/dist/esm/application/services/email-idempotency-key.service.d.ts +4 -0
  116. package/dist/esm/application/services/email-idempotency-key.service.js +21 -0
  117. package/dist/esm/application/services/email-sender.service.d.ts +17 -0
  118. package/dist/esm/application/services/email-sender.service.js +66 -0
  119. package/dist/esm/application/services/index.d.ts +3 -0
  120. package/dist/esm/application/services/index.js +3 -0
  121. package/dist/esm/configs/envs/index.d.ts +1 -0
  122. package/dist/esm/configs/envs/index.js +1 -0
  123. package/dist/esm/configs/envs/mailer.environment.d.ts +7 -0
  124. package/dist/esm/configs/envs/mailer.environment.js +44 -0
  125. package/dist/esm/configs/index.d.ts +2 -0
  126. package/dist/esm/configs/index.js +2 -0
  127. package/dist/esm/configs/mailer.config.d.ts +15 -0
  128. package/dist/esm/configs/mailer.config.js +38 -0
  129. package/dist/esm/constants.d.ts +7 -0
  130. package/dist/esm/constants.js +7 -0
  131. package/dist/esm/index.d.ts +6 -0
  132. package/dist/esm/index.js +6 -0
  133. package/dist/esm/infrastructure/adapters/index.d.ts +3 -0
  134. package/dist/esm/infrastructure/adapters/index.js +3 -0
  135. package/dist/esm/infrastructure/adapters/interpolating-email-template-renderer.d.ts +7 -0
  136. package/dist/esm/infrastructure/adapters/interpolating-email-template-renderer.js +49 -0
  137. package/dist/esm/infrastructure/adapters/json-mailer.adapter.d.ts +7 -0
  138. package/dist/esm/infrastructure/adapters/json-mailer.adapter.js +25 -0
  139. package/dist/esm/infrastructure/adapters/smtp-mailer.adapter.d.ts +8 -0
  140. package/dist/esm/infrastructure/adapters/smtp-mailer.adapter.js +41 -0
  141. package/dist/esm/infrastructure/database/index.d.ts +1 -0
  142. package/dist/esm/infrastructure/database/index.js +1 -0
  143. package/dist/esm/infrastructure/database/typeorm/entities/index.d.ts +1 -0
  144. package/dist/esm/infrastructure/database/typeorm/entities/index.js +1 -0
  145. package/dist/esm/infrastructure/database/typeorm/entities/sent-email.entity.d.ts +4 -0
  146. package/dist/esm/infrastructure/database/typeorm/entities/sent-email.entity.js +27 -0
  147. package/dist/esm/infrastructure/database/typeorm/index.d.ts +3 -0
  148. package/dist/esm/infrastructure/database/typeorm/index.js +3 -0
  149. package/dist/esm/infrastructure/database/typeorm/migrations/add-sent-emails.migration.d.ts +6 -0
  150. package/dist/esm/infrastructure/database/typeorm/migrations/add-sent-emails.migration.js +9 -0
  151. package/dist/esm/infrastructure/database/typeorm/migrations/index.d.ts +1 -0
  152. package/dist/esm/infrastructure/database/typeorm/migrations/index.js +1 -0
  153. package/dist/esm/infrastructure/database/typeorm/repositories/index.d.ts +1 -0
  154. package/dist/esm/infrastructure/database/typeorm/repositories/index.js +1 -0
  155. package/dist/esm/infrastructure/database/typeorm/repositories/sent-email-log.repository.d.ts +9 -0
  156. package/dist/esm/infrastructure/database/typeorm/repositories/sent-email-log.repository.js +41 -0
  157. package/dist/esm/infrastructure/index.d.ts +2 -0
  158. package/dist/esm/infrastructure/index.js +2 -0
  159. package/dist/esm/mailer-logger.d.ts +5 -0
  160. package/dist/esm/mailer-logger.js +23 -0
  161. package/dist/esm/mailer.module.d.ts +9 -0
  162. package/dist/esm/mailer.module.js +52 -0
  163. package/dist/esm/testing/email-sender.fake.d.ts +7 -0
  164. package/dist/esm/testing/email-sender.fake.js +11 -0
  165. package/dist/esm/testing/email-subscriptions.fake.d.ts +6 -0
  166. package/dist/esm/testing/email-subscriptions.fake.js +11 -0
  167. package/dist/esm/testing/email-template-catalog.fake.d.ts +11 -0
  168. package/dist/esm/testing/email-template-catalog.fake.js +11 -0
  169. package/dist/esm/testing/email-template-renderer.fake.d.ts +12 -0
  170. package/dist/esm/testing/email-template-renderer.fake.js +15 -0
  171. package/dist/esm/testing/index.d.ts +6 -0
  172. package/dist/esm/testing/index.js +6 -0
  173. package/dist/esm/testing/mailer.fake.d.ts +8 -0
  174. package/dist/esm/testing/mailer.fake.js +17 -0
  175. package/dist/esm/testing/sent-email-log.fake.d.ts +8 -0
  176. package/dist/esm/testing/sent-email-log.fake.js +22 -0
  177. package/package.json +96 -3
@@ -0,0 +1,44 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Expose, Type } from 'class-transformer';
11
+ import { IsNumber, IsString } from 'class-validator';
12
+ export class MailerEnvironment {
13
+ MAIL_FROM = 'no-reply@localhost';
14
+ MAIL_SMTP_HOST = '';
15
+ MAIL_SMTP_PASSWORD = '';
16
+ MAIL_SMTP_PORT = 587;
17
+ MAIL_SMTP_USER = '';
18
+ }
19
+ __decorate([
20
+ Expose(),
21
+ IsString(),
22
+ __metadata("design:type", Object)
23
+ ], MailerEnvironment.prototype, "MAIL_FROM", void 0);
24
+ __decorate([
25
+ Expose(),
26
+ IsString(),
27
+ __metadata("design:type", Object)
28
+ ], MailerEnvironment.prototype, "MAIL_SMTP_HOST", void 0);
29
+ __decorate([
30
+ Expose(),
31
+ IsString(),
32
+ __metadata("design:type", Object)
33
+ ], MailerEnvironment.prototype, "MAIL_SMTP_PASSWORD", void 0);
34
+ __decorate([
35
+ Expose(),
36
+ IsNumber(),
37
+ Type(() => Number),
38
+ __metadata("design:type", Object)
39
+ ], MailerEnvironment.prototype, "MAIL_SMTP_PORT", void 0);
40
+ __decorate([
41
+ Expose(),
42
+ IsString(),
43
+ __metadata("design:type", Object)
44
+ ], MailerEnvironment.prototype, "MAIL_SMTP_USER", void 0);
@@ -0,0 +1,2 @@
1
+ export * from './envs/index.js';
2
+ export * from './mailer.config.js';
@@ -0,0 +1,2 @@
1
+ export * from './envs/index.js';
2
+ export * from './mailer.config.js';
@@ -0,0 +1,15 @@
1
+ import { MailerEnvironment } from './envs/mailer.environment.js';
2
+ export interface SmtpSettingsInterface {
3
+ readonly host: string;
4
+ readonly password: string;
5
+ readonly port: number;
6
+ readonly secure: boolean;
7
+ readonly user: string;
8
+ }
9
+ export declare class MailerConfig {
10
+ private readonly environment;
11
+ get from(): string;
12
+ get isSmtpConfigured(): boolean;
13
+ get smtp(): SmtpSettingsInterface;
14
+ constructor(environment: MailerEnvironment);
15
+ }
@@ -0,0 +1,38 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Injectable } from '@nestjs/common';
11
+ import { MailerEnvironment } from './envs/mailer.environment.js';
12
+ const IMPLICIT_TLS_PORT = 465;
13
+ let MailerConfig = class MailerConfig {
14
+ environment;
15
+ get from() {
16
+ return this.environment.MAIL_FROM;
17
+ }
18
+ get isSmtpConfigured() {
19
+ return this.environment.MAIL_SMTP_HOST !== '';
20
+ }
21
+ get smtp() {
22
+ return {
23
+ host: this.environment.MAIL_SMTP_HOST,
24
+ password: this.environment.MAIL_SMTP_PASSWORD,
25
+ port: this.environment.MAIL_SMTP_PORT,
26
+ secure: this.environment.MAIL_SMTP_PORT === IMPLICIT_TLS_PORT,
27
+ user: this.environment.MAIL_SMTP_USER,
28
+ };
29
+ }
30
+ constructor(environment) {
31
+ this.environment = environment;
32
+ }
33
+ };
34
+ MailerConfig = __decorate([
35
+ Injectable(),
36
+ __metadata("design:paramtypes", [MailerEnvironment])
37
+ ], MailerConfig);
38
+ export { MailerConfig };
@@ -0,0 +1,7 @@
1
+ export declare const EMAIL_SENDER_PORT: unique symbol;
2
+ export declare const EMAIL_TEMPLATE_RENDERER_PORT: unique symbol;
3
+ export declare const MAILER_PORT: unique symbol;
4
+ export declare const SENT_EMAIL_LOG_PORT: unique symbol;
5
+ export declare const EMAIL_SUBSCRIPTIONS_PORT: unique symbol;
6
+ export declare const EMAIL_TEMPLATE_CATALOG_PORT: unique symbol;
7
+ export declare const MAILER_LOGGER: unique symbol;
@@ -0,0 +1,7 @@
1
+ export const EMAIL_SENDER_PORT = Symbol('EMAIL_SENDER_PORT');
2
+ export const EMAIL_TEMPLATE_RENDERER_PORT = Symbol('EMAIL_TEMPLATE_RENDERER_PORT');
3
+ export const MAILER_PORT = Symbol('MAILER_PORT');
4
+ export const SENT_EMAIL_LOG_PORT = Symbol('SENT_EMAIL_LOG_PORT');
5
+ export const EMAIL_SUBSCRIPTIONS_PORT = Symbol('EMAIL_SUBSCRIPTIONS_PORT');
6
+ export const EMAIL_TEMPLATE_CATALOG_PORT = Symbol('EMAIL_TEMPLATE_CATALOG_PORT');
7
+ export const MAILER_LOGGER = Symbol('MAILER_LOGGER');
@@ -0,0 +1,6 @@
1
+ export * from './application/index.js';
2
+ export * from './configs/index.js';
3
+ export * from './infrastructure/index.js';
4
+ export * from './constants.js';
5
+ export * from './mailer-logger.js';
6
+ export * from './mailer.module.js';
@@ -0,0 +1,6 @@
1
+ export * from './application/index.js';
2
+ export * from './configs/index.js';
3
+ export * from './infrastructure/index.js';
4
+ export * from './constants.js';
5
+ export * from './mailer-logger.js';
6
+ export * from './mailer.module.js';
@@ -0,0 +1,3 @@
1
+ export * from './interpolating-email-template-renderer.js';
2
+ export * from './json-mailer.adapter.js';
3
+ export * from './smtp-mailer.adapter.js';
@@ -0,0 +1,3 @@
1
+ export * from './interpolating-email-template-renderer.js';
2
+ export * from './json-mailer.adapter.js';
3
+ export * from './smtp-mailer.adapter.js';
@@ -0,0 +1,7 @@
1
+ import type { EmailTemplateCatalogInterface } from '../../application/ports/email-template-catalog.interface.js';
2
+ import type { EmailTemplateParameters, EmailTemplateRendererInterface, RenderedEmailInterface } from '../../application/ports/email-template-renderer.interface.js';
3
+ export declare class InterpolatingEmailTemplateRenderer implements EmailTemplateRendererInterface {
4
+ private readonly catalog;
5
+ constructor(catalog: EmailTemplateCatalogInterface);
6
+ render(name: string, locale: string, parameters: EmailTemplateParameters): RenderedEmailInterface;
7
+ }
@@ -0,0 +1,49 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ import { Inject, Injectable } from '@nestjs/common';
14
+ import { EMAIL_TEMPLATE_CATALOG_PORT } from '../../constants.js';
15
+ const PLACEHOLDER_PATTERN = /\{(?<parameter>\w+)\}/gu;
16
+ const keepAsIs = (value) => value;
17
+ const escapeHtml = (value) => value
18
+ .replaceAll('&', '&amp;')
19
+ .replaceAll('"', '&quot;')
20
+ .replaceAll('\'', '&#39;')
21
+ .replaceAll('<', '&lt;')
22
+ .replaceAll('>', '&gt;');
23
+ const interpolate = (template, parameters, transform) => template.replaceAll(PLACEHOLDER_PATTERN, (placeholder, name) => {
24
+ const value = parameters[name];
25
+ if (value === undefined) {
26
+ return placeholder;
27
+ }
28
+ return transform(value);
29
+ });
30
+ let InterpolatingEmailTemplateRenderer = class InterpolatingEmailTemplateRenderer {
31
+ catalog;
32
+ constructor(catalog) {
33
+ this.catalog = catalog;
34
+ }
35
+ render(name, locale, parameters) {
36
+ const template = this.catalog.get(name, locale);
37
+ return {
38
+ html: interpolate(template.html, parameters, escapeHtml),
39
+ subject: interpolate(template.subject, parameters, keepAsIs),
40
+ text: interpolate(template.text, parameters, keepAsIs),
41
+ };
42
+ }
43
+ };
44
+ InterpolatingEmailTemplateRenderer = __decorate([
45
+ Injectable(),
46
+ __param(0, Inject(EMAIL_TEMPLATE_CATALOG_PORT)),
47
+ __metadata("design:paramtypes", [Object])
48
+ ], InterpolatingEmailTemplateRenderer);
49
+ export { InterpolatingEmailTemplateRenderer };
@@ -0,0 +1,7 @@
1
+ import type { MailerLoggerInterface } from '../../application/ports/mailer-logger.interface.js';
2
+ import type { MailerInterface, MailerMessageInterface } from '../../application/ports/mailer.interface.js';
3
+ export declare class JsonMailerAdapter implements MailerInterface {
4
+ private readonly logger;
5
+ constructor(logger: MailerLoggerInterface);
6
+ send(message: MailerMessageInterface): Promise<void>;
7
+ }
@@ -0,0 +1,25 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Injectable } from '@nestjs/common';
11
+ let JsonMailerAdapter = class JsonMailerAdapter {
12
+ logger;
13
+ constructor(logger) {
14
+ this.logger = logger;
15
+ }
16
+ async send(message) {
17
+ this.logger.warn({ html: message.html, subject: message.subject, text: message.text, to: message.to }, 'Email dumped to the log: SMTP is not configured');
18
+ await Promise.resolve();
19
+ }
20
+ };
21
+ JsonMailerAdapter = __decorate([
22
+ Injectable(),
23
+ __metadata("design:paramtypes", [Object])
24
+ ], JsonMailerAdapter);
25
+ export { JsonMailerAdapter };
@@ -0,0 +1,8 @@
1
+ import type { MailerInterface, MailerMessageInterface } from '../../application/ports/mailer.interface.js';
2
+ import { MailerConfig } from '../../configs/mailer.config.js';
3
+ export declare class SmtpMailerAdapter implements MailerInterface {
4
+ private readonly config;
5
+ private readonly transporter;
6
+ constructor(config: MailerConfig);
7
+ send(message: MailerMessageInterface): Promise<void>;
8
+ }
@@ -0,0 +1,41 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Injectable } from '@nestjs/common';
11
+ import { createTransport } from 'nodemailer';
12
+ import { MailerConfig } from '../../configs/mailer.config.js';
13
+ let SmtpMailerAdapter = class SmtpMailerAdapter {
14
+ config;
15
+ transporter;
16
+ constructor(config) {
17
+ this.config = config;
18
+ const { host, password, port, secure, user } = config.smtp;
19
+ this.transporter = createTransport({
20
+ auth: user === '' ? undefined : { pass: password, user },
21
+ host,
22
+ port,
23
+ requireTLS: true,
24
+ secure,
25
+ });
26
+ }
27
+ async send(message) {
28
+ await this.transporter.sendMail({
29
+ from: this.config.from,
30
+ html: message.html,
31
+ subject: message.subject,
32
+ text: message.text,
33
+ to: message.to,
34
+ });
35
+ }
36
+ };
37
+ SmtpMailerAdapter = __decorate([
38
+ Injectable(),
39
+ __metadata("design:paramtypes", [MailerConfig])
40
+ ], SmtpMailerAdapter);
41
+ export { SmtpMailerAdapter };
@@ -0,0 +1 @@
1
+ export * from './typeorm/index.js';
@@ -0,0 +1 @@
1
+ export * from './typeorm/index.js';
@@ -0,0 +1 @@
1
+ export * from './sent-email.entity.js';
@@ -0,0 +1 @@
1
+ export * from './sent-email.entity.js';
@@ -0,0 +1,4 @@
1
+ export declare class SentEmailEntity {
2
+ idempotencyKey: string;
3
+ sentAt: Date;
4
+ }
@@ -0,0 +1,27 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { CreateDateColumn, Entity, PrimaryColumn } from 'typeorm';
11
+ import { EMAIL_IDEMPOTENCY_KEY_MAX_LENGTH, } from '../../../../application/services/email-idempotency-key.service.js';
12
+ let SentEmailEntity = class SentEmailEntity {
13
+ idempotencyKey;
14
+ sentAt;
15
+ };
16
+ __decorate([
17
+ PrimaryColumn({ length: EMAIL_IDEMPOTENCY_KEY_MAX_LENGTH, type: 'varchar' }),
18
+ __metadata("design:type", String)
19
+ ], SentEmailEntity.prototype, "idempotencyKey", void 0);
20
+ __decorate([
21
+ CreateDateColumn({ type: 'timestamp without time zone' }),
22
+ __metadata("design:type", Date)
23
+ ], SentEmailEntity.prototype, "sentAt", void 0);
24
+ SentEmailEntity = __decorate([
25
+ Entity()
26
+ ], SentEmailEntity);
27
+ export { SentEmailEntity };
@@ -0,0 +1,3 @@
1
+ export * from './entities/index.js';
2
+ export * from './migrations/index.js';
3
+ export * from './repositories/index.js';
@@ -0,0 +1,3 @@
1
+ export * from './entities/index.js';
2
+ export * from './migrations/index.js';
3
+ export * from './repositories/index.js';
@@ -0,0 +1,6 @@
1
+ import type { MigrationInterface, QueryRunner } from 'typeorm';
2
+ export declare class AddSentEmails1790231050588 implements MigrationInterface {
3
+ name: string;
4
+ down(queryRunner: QueryRunner): Promise<void>;
5
+ up(queryRunner: QueryRunner): Promise<void>;
6
+ }
@@ -0,0 +1,9 @@
1
+ export class AddSentEmails1790231050588 {
2
+ name = 'AddSentEmails1790231050588';
3
+ async down(queryRunner) {
4
+ await queryRunner.query(`DROP TABLE "sent_emails"`);
5
+ }
6
+ async up(queryRunner) {
7
+ await queryRunner.query(`CREATE TABLE "sent_emails" ("idempotency_key" character varying(128) NOT NULL, "sent_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_5940884b20d8dacfb3fba3e01bb" PRIMARY KEY ("idempotency_key"))`);
8
+ }
9
+ }
@@ -0,0 +1 @@
1
+ export * from './add-sent-emails.migration.js';
@@ -0,0 +1 @@
1
+ export * from './add-sent-emails.migration.js';
@@ -0,0 +1 @@
1
+ export * from './sent-email-log.repository.js';
@@ -0,0 +1 @@
1
+ export * from './sent-email-log.repository.js';
@@ -0,0 +1,9 @@
1
+ import { Repository } from 'typeorm';
2
+ import { SentEmailLogInterface } from '../../../../application/ports/sent-email-log.interface.js';
3
+ import { SentEmailEntity } from '../entities/sent-email.entity.js';
4
+ export declare class SentEmailLogRepository implements SentEmailLogInterface {
5
+ private readonly repository;
6
+ constructor(repository: Repository<SentEmailEntity>);
7
+ claim(key: string): Promise<boolean>;
8
+ release(key: string): Promise<void>;
9
+ }
@@ -0,0 +1,41 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ import { Injectable } from '@nestjs/common';
14
+ import { InjectRepository } from '@nestjs/typeorm';
15
+ import { Repository } from 'typeorm';
16
+ import { SentEmailEntity } from '../entities/sent-email.entity.js';
17
+ let SentEmailLogRepository = class SentEmailLogRepository {
18
+ repository;
19
+ constructor(repository) {
20
+ this.repository = repository;
21
+ }
22
+ async claim(key) {
23
+ const inserted = await this.repository
24
+ .createQueryBuilder()
25
+ .insert()
26
+ .into(SentEmailEntity)
27
+ .values({ idempotencyKey: key })
28
+ .orIgnore()
29
+ .execute();
30
+ return inserted.identifiers.length > 0;
31
+ }
32
+ async release(key) {
33
+ await this.repository.delete({ idempotencyKey: key });
34
+ }
35
+ };
36
+ SentEmailLogRepository = __decorate([
37
+ Injectable(),
38
+ __param(0, InjectRepository(SentEmailEntity)),
39
+ __metadata("design:paramtypes", [Repository])
40
+ ], SentEmailLogRepository);
41
+ export { SentEmailLogRepository };
@@ -0,0 +1,2 @@
1
+ export * from './adapters/index.js';
2
+ export * from './database/index.js';
@@ -0,0 +1,2 @@
1
+ export * from './adapters/index.js';
2
+ export * from './database/index.js';
@@ -0,0 +1,5 @@
1
+ import * as nestjsPino from 'nestjs-pino';
2
+ import type { MailerLoggerInterface } from './application/ports/mailer-logger.interface.js';
3
+ export declare class MailerLogger extends nestjsPino.PinoLogger implements MailerLoggerInterface {
4
+ constructor(options: nestjsPino.Params);
5
+ }
@@ -0,0 +1,23 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var MailerLogger_1;
11
+ import { Injectable } from '@nestjs/common';
12
+ import * as nestjsPino from 'nestjs-pino';
13
+ let MailerLogger = MailerLogger_1 = class MailerLogger extends nestjsPino.PinoLogger {
14
+ constructor(options) {
15
+ super(options);
16
+ this.setContext(MailerLogger_1.name);
17
+ }
18
+ };
19
+ MailerLogger = MailerLogger_1 = __decorate([
20
+ Injectable(),
21
+ __metadata("design:paramtypes", [Object])
22
+ ], MailerLogger);
23
+ export { MailerLogger };
@@ -0,0 +1,9 @@
1
+ import type { DynamicModule, Type } from '@nestjs/common';
2
+ import type { EmailTemplateCatalogInterface } from './application/ports/email-template-catalog.interface.js';
3
+ export interface MailerModuleOptionsInterface {
4
+ readonly subscriptions: Type;
5
+ readonly templates: Type<EmailTemplateCatalogInterface>;
6
+ }
7
+ export declare class MailerModule {
8
+ static register(options: MailerModuleOptionsInterface): DynamicModule;
9
+ }
@@ -0,0 +1,52 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { ConfigsModule } from '@libs-for-dev/nestjs-config-module';
8
+ import { Module } from '@nestjs/common';
9
+ import { TypeOrmModule } from '@nestjs/typeorm';
10
+ import { EmailDispatcherService } from './application/services/email-dispatcher.service.js';
11
+ import { EmailIdempotencyKeyService } from './application/services/email-idempotency-key.service.js';
12
+ import { EmailSenderService } from './application/services/email-sender.service.js';
13
+ import { MailerEnvironment } from './configs/envs/mailer.environment.js';
14
+ import { MailerConfig } from './configs/mailer.config.js';
15
+ import { EMAIL_SENDER_PORT, EMAIL_TEMPLATE_CATALOG_PORT, EMAIL_TEMPLATE_RENDERER_PORT, MAILER_LOGGER, MAILER_PORT, SENT_EMAIL_LOG_PORT, } from './constants.js';
16
+ import { InterpolatingEmailTemplateRenderer } from './infrastructure/adapters/interpolating-email-template-renderer.js';
17
+ import { JsonMailerAdapter } from './infrastructure/adapters/json-mailer.adapter.js';
18
+ import { SmtpMailerAdapter } from './infrastructure/adapters/smtp-mailer.adapter.js';
19
+ import { SentEmailEntity } from './infrastructure/database/typeorm/entities/sent-email.entity.js';
20
+ import { SentEmailLogRepository } from './infrastructure/database/typeorm/repositories/sent-email-log.repository.js';
21
+ const selectMailer = (config, logger) => (config.isSmtpConfigured
22
+ ? new SmtpMailerAdapter(config)
23
+ : new JsonMailerAdapter(logger));
24
+ const mailerByConfig = {
25
+ inject: [MailerConfig, MAILER_LOGGER],
26
+ provide: MAILER_PORT,
27
+ useFactory: selectMailer,
28
+ };
29
+ let MailerModule = class MailerModule {
30
+ static register(options) {
31
+ return {
32
+ imports: [ConfigsModule.forFeature([MailerConfig], [MailerEnvironment]), options.subscriptions],
33
+ module: this,
34
+ providers: [{ provide: EMAIL_TEMPLATE_CATALOG_PORT, useClass: options.templates }],
35
+ };
36
+ }
37
+ };
38
+ MailerModule = __decorate([
39
+ Module({
40
+ exports: [EmailDispatcherService],
41
+ imports: [TypeOrmModule.forFeature([SentEmailEntity])],
42
+ providers: [
43
+ { provide: EMAIL_SENDER_PORT, useClass: EmailSenderService },
44
+ { provide: EMAIL_TEMPLATE_RENDERER_PORT, useClass: InterpolatingEmailTemplateRenderer },
45
+ { provide: SENT_EMAIL_LOG_PORT, useClass: SentEmailLogRepository },
46
+ EmailDispatcherService,
47
+ EmailIdempotencyKeyService,
48
+ mailerByConfig,
49
+ ],
50
+ })
51
+ ], MailerModule);
52
+ export { MailerModule };
@@ -0,0 +1,7 @@
1
+ import type { EmailSenderInterface, SendEmailRequestInterface, SendEmailResult } from '../application/ports/email-sender.interface.js';
2
+ export declare class FakeEmailSender implements EmailSenderInterface {
3
+ result: SendEmailResult;
4
+ readonly resultByTemplate: Map<string, SendEmailResult>;
5
+ readonly sent: SendEmailRequestInterface[];
6
+ send(request: SendEmailRequestInterface): Promise<SendEmailResult>;
7
+ }
@@ -0,0 +1,11 @@
1
+ import { Ok } from 'oxide.ts';
2
+ export class FakeEmailSender {
3
+ result = Ok(true);
4
+ resultByTemplate = new Map();
5
+ sent = [];
6
+ async send(request) {
7
+ await Promise.resolve();
8
+ this.sent.push(request);
9
+ return this.resultByTemplate.get(request.template) ?? this.result;
10
+ }
11
+ }
@@ -0,0 +1,6 @@
1
+ import type { EmailSubscriptionInterface, EmailSubscriptionsInterface } from '../application/ports/email-subscriptions.interface.js';
2
+ export declare class FakeEmailSubscriptions implements EmailSubscriptionsInterface {
3
+ private readonly unsubscribed;
4
+ isSubscribed(subscription: EmailSubscriptionInterface): Promise<boolean>;
5
+ unsubscribe(subscription: EmailSubscriptionInterface): void;
6
+ }
@@ -0,0 +1,11 @@
1
+ const keyOf = ({ accountId, category }) => `${accountId}:${category}`;
2
+ export class FakeEmailSubscriptions {
3
+ unsubscribed = new Set();
4
+ async isSubscribed(subscription) {
5
+ await Promise.resolve();
6
+ return !this.unsubscribed.has(keyOf(subscription));
7
+ }
8
+ unsubscribe(subscription) {
9
+ this.unsubscribed.add(keyOf(subscription));
10
+ }
11
+ }
@@ -0,0 +1,11 @@
1
+ import type { EmailTemplateCatalogInterface, EmailTemplateInterface } from '../application/ports/email-template-catalog.interface.js';
2
+ export interface EmailTemplateRequestInterface {
3
+ readonly locale: string;
4
+ readonly name: string;
5
+ }
6
+ export declare class FakeEmailTemplateCatalog implements EmailTemplateCatalogInterface {
7
+ readonly requests: EmailTemplateRequestInterface[];
8
+ private template;
9
+ get(name: string, locale: string): EmailTemplateInterface;
10
+ returns(template: EmailTemplateInterface): void;
11
+ }
@@ -0,0 +1,11 @@
1
+ export class FakeEmailTemplateCatalog {
2
+ requests = [];
3
+ template = { html: '<p>{name}</p>', subject: 'subject', text: '{name}' };
4
+ get(name, locale) {
5
+ this.requests.push({ locale, name });
6
+ return this.template;
7
+ }
8
+ returns(template) {
9
+ this.template = template;
10
+ }
11
+ }
@@ -0,0 +1,12 @@
1
+ import type { EmailTemplateParameters, EmailTemplateRendererInterface, RenderedEmailInterface } from '../application/ports/email-template-renderer.interface.js';
2
+ export interface EmailRenderRequestInterface {
3
+ readonly locale: string;
4
+ readonly name: string;
5
+ readonly parameters: EmailTemplateParameters;
6
+ }
7
+ export declare class FakeEmailTemplateRenderer implements EmailTemplateRendererInterface {
8
+ readonly requests: EmailRenderRequestInterface[];
9
+ private rendered;
10
+ render(name: string, locale: string, parameters: EmailTemplateParameters): RenderedEmailInterface;
11
+ returns(rendered: RenderedEmailInterface): void;
12
+ }