@brilab-mailer/core 0.2.1 → 0.2.2

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.
package/cjs/index.js ADDED
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./lib/mailer.service.js"), exports);
18
+ __exportStar(require("./lib/mailer.module.js"), exports);
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MailerSender = void 0;
4
+ const contracts_1 = require("@brilab-mailer/contracts");
5
+ const template_context_index = 1;
6
+ class MailerSender extends contracts_1.MailerMessagesBuilder {
7
+ _send;
8
+ _render;
9
+ _templateParams = null;
10
+ constructor(_send, _render) {
11
+ super();
12
+ this._send = _send;
13
+ this._render = _render;
14
+ }
15
+ useTemplate(...params) {
16
+ if (!this._render) {
17
+ throw new Error('[MailerSender] Templater client is not available');
18
+ }
19
+ const prevParams = this._templateParams || ['__no_key__', undefined, undefined];
20
+ const prevCtx = prevParams[template_context_index] || {};
21
+ const currCtx = params[template_context_index] || {};
22
+ params[template_context_index] = { ...prevCtx, ...currCtx };
23
+ this._templateParams = params;
24
+ return this;
25
+ }
26
+ addTemplateContext(context) {
27
+ if (!this._render) {
28
+ throw new Error('[MailerSender] Templater client is not available');
29
+ }
30
+ const params = this._templateParams || ['__no_key__', undefined, undefined];
31
+ params[template_context_index] = { ...(params[template_context_index] || {}), ...context, };
32
+ this._templateParams = params;
33
+ return this;
34
+ }
35
+ async send() {
36
+ if (this._templateParams && this._render) {
37
+ const draft = this.generateDraft() || {};
38
+ const ctx = this._templateParams[1] || {};
39
+ this._templateParams[1] = {
40
+ subject: draft.subject,
41
+ ...ctx,
42
+ };
43
+ const html = await this._render(...this._templateParams);
44
+ this.setHtml(html);
45
+ }
46
+ const resolved = this.prepare();
47
+ return this._send(resolved);
48
+ }
49
+ }
50
+ exports.MailerSender = MailerSender;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveMailerOptions = exports.MAILER_RETRY_BACKOFF_MS_DEFAULT = exports.MAILER_RETRY_ATTEMPTS_DEFAULT = void 0;
4
+ exports.MAILER_RETRY_ATTEMPTS_DEFAULT = 3;
5
+ exports.MAILER_RETRY_BACKOFF_MS_DEFAULT = [500, 1000, 2000];
6
+ /**
7
+ * Resolves retry options from the values the application passes in, falling
8
+ * back to defaults. The library never reads process env itself — the host app
9
+ * resolves everything (from its own NestJS config) and passes it through
10
+ * `register({ options })` / `registerAsync(useFactory -> { options })`.
11
+ */
12
+ const resolveMailerOptions = (overrides) => ({
13
+ maxAttempts: overrides?.maxAttempts ?? exports.MAILER_RETRY_ATTEMPTS_DEFAULT,
14
+ backoffMs: overrides?.backoffMs ?? exports.MAILER_RETRY_BACKOFF_MS_DEFAULT,
15
+ });
16
+ exports.resolveMailerOptions = resolveMailerOptions;
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ 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;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var MailerModule_1;
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.MailerModule = void 0;
11
+ const common_1 = require("@nestjs/common");
12
+ const contracts_1 = require("@brilab-mailer/contracts");
13
+ const mailer_service_js_1 = require("./mailer.service.js");
14
+ const mailer_constants_js_1 = require("./mailer.constants.js");
15
+ let MailerModule = MailerModule_1 = class MailerModule {
16
+ static register(params) {
17
+ if (!params?.providerClass) {
18
+ throw new Error('[MailerModule] providerClass is required. ' +
19
+ 'Example: MailerModule.register({ providerClass: MailtrapApiProvider, templateEngineClass: HandlebarsTemplateEngine })');
20
+ }
21
+ return {
22
+ module: MailerModule_1,
23
+ imports: [],
24
+ providers: [
25
+ {
26
+ provide: contracts_1.MAILER_OPTIONS,
27
+ useValue: (0, mailer_constants_js_1.resolveMailerOptions)(params.options),
28
+ },
29
+ {
30
+ provide: contracts_1.MAILER_PROVIDER,
31
+ useClass: params.providerClass,
32
+ },
33
+ {
34
+ provide: contracts_1.MAILER_PROVIDER_OPTIONS,
35
+ useValue: params.providerOptions || {},
36
+ },
37
+ {
38
+ provide: contracts_1.MAILER_PROVIDER_NATIVE_CLIENT,
39
+ useFactory: (provider) => provider?.getClient?.(),
40
+ inject: [contracts_1.MAILER_PROVIDER],
41
+ },
42
+ ...(params.templateEngineClass
43
+ ? [
44
+ {
45
+ provide: contracts_1.MAILER_TEMPLATE_ENGINE,
46
+ useClass: params.templateEngineClass,
47
+ },
48
+ {
49
+ provide: contracts_1.MAILER_TEMPLATE_ENGINE_OPTIONS,
50
+ useValue: params.templateEngineOptions || {},
51
+ },
52
+ ]
53
+ : []),
54
+ mailer_service_js_1.MailerService,
55
+ ],
56
+ exports: [
57
+ mailer_service_js_1.MailerService,
58
+ contracts_1.MAILER_OPTIONS,
59
+ contracts_1.MAILER_PROVIDER_OPTIONS,
60
+ contracts_1.MAILER_PROVIDER,
61
+ contracts_1.MAILER_PROVIDER_NATIVE_CLIENT,
62
+ ]
63
+ };
64
+ }
65
+ static registerAsync(params) {
66
+ if (!params?.providerClass) {
67
+ throw new Error('[MailerModule.registerAsync] providerClass is required.');
68
+ }
69
+ if (!params?.useFactory) {
70
+ throw new Error('[MailerModule.registerAsync] useFactory is required.');
71
+ }
72
+ return {
73
+ module: MailerModule_1,
74
+ imports: [...(params.imports || [])],
75
+ providers: [
76
+ {
77
+ provide: contracts_1.MAILER_ASYNC,
78
+ useFactory: params.useFactory,
79
+ inject: params.inject || [],
80
+ },
81
+ {
82
+ provide: contracts_1.MAILER_OPTIONS,
83
+ useFactory: (asyncCfg) => (0, mailer_constants_js_1.resolveMailerOptions)(asyncCfg?.options),
84
+ inject: [contracts_1.MAILER_ASYNC],
85
+ },
86
+ {
87
+ provide: contracts_1.MAILER_PROVIDER,
88
+ useClass: params.providerClass,
89
+ },
90
+ {
91
+ provide: contracts_1.MAILER_PROVIDER_OPTIONS,
92
+ useFactory: (asyncCfg) => asyncCfg?.providerOptions || {},
93
+ inject: [contracts_1.MAILER_ASYNC],
94
+ },
95
+ {
96
+ provide: contracts_1.MAILER_PROVIDER_NATIVE_CLIENT,
97
+ useFactory: (provider) => provider?.getClient?.(),
98
+ inject: [contracts_1.MAILER_PROVIDER],
99
+ },
100
+ ...(params.templateEngineClass
101
+ ? [
102
+ {
103
+ provide: contracts_1.MAILER_TEMPLATE_ENGINE,
104
+ useClass: params.templateEngineClass,
105
+ },
106
+ {
107
+ provide: contracts_1.MAILER_TEMPLATE_ENGINE_OPTIONS,
108
+ useFactory: (asyncCfg) => asyncCfg?.templateEngineOptions || {},
109
+ inject: [contracts_1.MAILER_ASYNC],
110
+ },
111
+ ]
112
+ : []),
113
+ mailer_service_js_1.MailerService,
114
+ ],
115
+ exports: [
116
+ mailer_service_js_1.MailerService,
117
+ contracts_1.MAILER_ASYNC,
118
+ contracts_1.MAILER_OPTIONS,
119
+ contracts_1.MAILER_PROVIDER_OPTIONS,
120
+ contracts_1.MAILER_PROVIDER,
121
+ contracts_1.MAILER_PROVIDER_NATIVE_CLIENT,
122
+ ]
123
+ };
124
+ }
125
+ };
126
+ exports.MailerModule = MailerModule;
127
+ exports.MailerModule = MailerModule = MailerModule_1 = __decorate([
128
+ (0, common_1.Global)(),
129
+ (0, common_1.Module)({})
130
+ ], MailerModule);
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ 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;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.MailerService = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const contracts_1 = require("@brilab-mailer/contracts");
18
+ const node_crypto_1 = require("node:crypto");
19
+ const mailer_sender_js_1 = require("./mailer-sender.js");
20
+ let MailerService = class MailerService {
21
+ options;
22
+ provider;
23
+ native_client;
24
+ _templater;
25
+ constructor(options, provider, native_client, _templater) {
26
+ this.options = options;
27
+ this.provider = provider;
28
+ this.native_client = native_client;
29
+ this._templater = _templater;
30
+ }
31
+ get nativeClient() {
32
+ const injected = this.native_client;
33
+ if (injected)
34
+ return injected;
35
+ const fromProvider = this.provider.getClient?.();
36
+ if (fromProvider)
37
+ return fromProvider;
38
+ throw new Error('[MailerService] Native client is not available');
39
+ }
40
+ get templater() {
41
+ const tmp = this._templater;
42
+ if (!tmp || !('render' in tmp))
43
+ throw new Error('[MailerService] Templater client is not available');
44
+ return tmp;
45
+ }
46
+ async send(resolved) {
47
+ const payload = this.provider.createPayload(resolved);
48
+ // One stable key per logical send so the retry loop can't duplicate
49
+ // emails on providers that honor idempotency (e.g. Resend).
50
+ const options = {
51
+ idempotencyKey: resolved.idempotencyKey ?? (0, node_crypto_1.randomUUID)(),
52
+ };
53
+ return this.withRetry(() => this.provider.send(payload, options));
54
+ }
55
+ sender() {
56
+ return new mailer_sender_js_1.MailerSender(this.send.bind(this), this._templater?.render?.bind(this._templater));
57
+ }
58
+ async withRetry(fn) {
59
+ const { backoffMs } = this.options;
60
+ const maxAttempts = Math.max(1, this.options.maxAttempts);
61
+ let lastError;
62
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
63
+ try {
64
+ return await fn();
65
+ }
66
+ catch (err) {
67
+ lastError = err;
68
+ // Permanent failures (e.g. 4xx validation) are not worth retrying.
69
+ if (err instanceof contracts_1.MailerSendError && !err.retryable)
70
+ break;
71
+ const isLast = attempt >= maxAttempts - 1;
72
+ if (isLast)
73
+ break;
74
+ const delay = backoffMs.length
75
+ ? backoffMs[Math.min(attempt, backoffMs.length - 1)]
76
+ : 0;
77
+ if (delay > 0)
78
+ await new Promise((res) => setTimeout(res, delay));
79
+ }
80
+ }
81
+ throw lastError;
82
+ }
83
+ };
84
+ exports.MailerService = MailerService;
85
+ exports.MailerService = MailerService = __decorate([
86
+ (0, common_1.Injectable)(),
87
+ __param(0, (0, common_1.Inject)(contracts_1.MAILER_OPTIONS)),
88
+ __param(1, (0, common_1.Inject)(contracts_1.MAILER_PROVIDER)),
89
+ __param(2, (0, common_1.Optional)()),
90
+ __param(2, (0, common_1.Inject)(contracts_1.MAILER_PROVIDER_NATIVE_CLIENT)),
91
+ __param(3, (0, common_1.Optional)()),
92
+ __param(3, (0, common_1.Inject)(contracts_1.MAILER_TEMPLATE_ENGINE)),
93
+ __metadata("design:paramtypes", [Object, Object, Object, Object])
94
+ ], MailerService);
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@brilab-mailer/core",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "author": "Bohdan Radchenko <radchenkobs@gmail.com>",
5
5
  "type": "module",
6
- "main": "./index.js",
6
+ "main": "./cjs/index.js",
7
7
  "module": "./index.js",
8
8
  "types": "./index.d.ts",
9
9
  "exports": {
@@ -11,7 +11,7 @@
11
11
  ".": {
12
12
  "types": "./index.d.ts",
13
13
  "import": "./index.js",
14
- "default": "./index.js"
14
+ "require": "./cjs/index.js"
15
15
  }
16
16
  },
17
17
  "files": [
@@ -27,6 +27,6 @@
27
27
  "@nestjs/common": "^10.0.0"
28
28
  },
29
29
  "dependencies": {
30
- "@brilab-mailer/contracts": "^0.2.1"
30
+ "@brilab-mailer/contracts": "^0.2.2"
31
31
  }
32
32
  }