@venizia/ignis-docs 0.2.0 → 0.2.1-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.
- package/README.md +14 -14
- package/content/best-practices/api-usage-examples.md +39 -19
- package/content/best-practices/architectural-patterns.md +24 -13
- package/content/best-practices/architecture-decisions.md +29 -16
- package/content/best-practices/code-style-standards/advanced-patterns.md +43 -31
- package/content/best-practices/code-style-standards/constants-configuration.md +19 -4
- package/content/best-practices/code-style-standards/control-flow.md +33 -1
- package/content/best-practices/code-style-standards/documentation.md +28 -8
- package/content/best-practices/code-style-standards/function-patterns.md +15 -4
- package/content/best-practices/code-style-standards/index.md +7 -2
- package/content/best-practices/code-style-standards/naming-conventions.md +27 -3
- package/content/best-practices/code-style-standards/route-definitions.md +9 -5
- package/content/best-practices/code-style-standards/tooling.md +14 -1
- package/content/best-practices/code-style-standards/type-safety.md +39 -6
- package/content/best-practices/common-pitfalls.md +59 -35
- package/content/best-practices/contribution-workflow.md +8 -4
- package/content/best-practices/data-modeling.md +78 -62
- package/content/best-practices/deployment-strategies.md +56 -19
- package/content/best-practices/error-handling.md +247 -153
- package/content/best-practices/index.md +6 -0
- package/content/best-practices/performance-optimization.md +26 -13
- package/content/best-practices/security-guidelines.md +35 -9
- package/content/best-practices/testing-strategies.md +7 -2
- package/content/best-practices/troubleshooting-tips.md +27 -17
- package/content/extensions/components/api-reference.md +109 -323
- package/content/extensions/components/authentication/api.md +489 -602
- package/content/extensions/components/authentication/errors.md +135 -498
- package/content/extensions/components/authentication/index.md +89 -801
- package/content/extensions/components/authentication/usage.md +231 -955
- package/content/extensions/components/authorization/api.md +991 -644
- package/content/extensions/components/authorization/errors.md +204 -208
- package/content/extensions/components/authorization/getting-started.md +227 -0
- package/content/extensions/components/authorization/index.md +88 -795
- package/content/extensions/components/authorization/usage.md +219 -528
- package/content/extensions/components/health-check.md +77 -243
- package/content/extensions/components/index.md +24 -90
- package/content/extensions/components/mail/api.md +553 -285
- package/content/extensions/components/mail/errors.md +76 -62
- package/content/extensions/components/mail/index.md +111 -463
- package/content/extensions/components/mail/usage.md +139 -173
- package/content/extensions/components/request-tracker.md +70 -173
- package/content/extensions/components/socket-io/api.md +462 -785
- package/content/extensions/components/socket-io/errors.md +49 -51
- package/content/extensions/components/socket-io/index.md +69 -372
- package/content/extensions/components/socket-io/usage.md +212 -105
- package/content/extensions/components/static-asset/api.md +461 -141
- package/content/extensions/components/static-asset/errors.md +121 -53
- package/content/extensions/components/static-asset/index.md +84 -606
- package/content/extensions/components/static-asset/usage.md +184 -299
- package/content/extensions/components/template/index.md +3 -3
- package/content/extensions/components/websocket/api.md +311 -404
- package/content/extensions/components/websocket/errors.md +47 -56
- package/content/extensions/components/websocket/index.md +75 -407
- package/content/extensions/components/websocket/usage.md +120 -338
- package/content/extensions/helpers/cron/index.md +52 -160
- package/content/extensions/helpers/crypto/index.md +67 -480
- package/content/extensions/helpers/crypto/reference.md +528 -0
- package/content/extensions/helpers/env/index.md +64 -178
- package/content/extensions/helpers/error/index.md +286 -196
- package/content/extensions/helpers/index.md +61 -47
- package/content/extensions/helpers/inversion/index.md +76 -550
- package/content/extensions/helpers/inversion/reference.md +530 -0
- package/content/extensions/helpers/kafka/admin.md +23 -3
- package/content/extensions/helpers/kafka/compile-binary.md +83 -52
- package/content/extensions/helpers/kafka/consumer.md +65 -28
- package/content/extensions/helpers/kafka/examples.md +46 -253
- package/content/extensions/helpers/kafka/index.md +55 -617
- package/content/extensions/helpers/kafka/producer.md +156 -22
- package/content/extensions/helpers/kafka/schema-registry.md +59 -79
- package/content/extensions/helpers/logger/hf-logger.md +220 -0
- package/content/extensions/helpers/logger/index.md +78 -552
- package/content/extensions/helpers/logger/pino.md +105 -0
- package/content/extensions/helpers/logger/reference.md +937 -0
- package/content/extensions/helpers/network/api.md +276 -195
- package/content/extensions/helpers/network/index.md +87 -524
- package/content/extensions/helpers/queue/index.md +80 -897
- package/content/extensions/helpers/queue/reference.md +494 -0
- package/content/extensions/helpers/redis/index.md +86 -640
- package/content/extensions/helpers/redis/reference.md +784 -0
- package/content/extensions/helpers/secrets/index.md +136 -0
- package/content/extensions/helpers/socket-io/api.md +325 -204
- package/content/extensions/helpers/socket-io/index.md +79 -429
- package/content/extensions/helpers/storage/api.md +584 -464
- package/content/extensions/helpers/storage/index.md +80 -573
- package/content/extensions/helpers/types/index.md +75 -495
- package/content/extensions/helpers/types/reference.md +689 -0
- package/content/extensions/helpers/uid/index.md +176 -189
- package/content/extensions/helpers/websocket/api.md +366 -214
- package/content/extensions/helpers/websocket/index.md +68 -503
- package/content/extensions/helpers/worker-thread/index.md +62 -396
- package/content/extensions/helpers/worker-thread/reference.md +428 -0
- package/content/extensions/index.md +38 -39
- package/content/extensions/src-details/mcp-server.md +96 -548
- package/content/guides/core-concepts/persistent/datasources.md +2 -2
- package/content/guides/core-concepts/persistent/index.md +5 -1
- package/content/guides/core-concepts/persistent/models.md +1 -1
- package/content/guides/core-concepts/persistent/pglite.md +218 -0
- package/content/guides/core-concepts/persistent/postgres-drivers.md +21 -15
- package/content/guides/core-concepts/persistent/search-meilisearch.md +22 -12
- package/content/guides/core-concepts/persistent/search-typesense.md +28 -16
- package/content/guides/core-concepts/persistent/sqlite.md +296 -0
- package/content/guides/core-concepts/persistent/transactions.md +12 -11
- package/content/guides/core-concepts/secrets-vault.md +177 -0
- package/content/guides/core-concepts/services.md +1 -1
- package/content/guides/get-started/5-minute-quickstart.md +59 -206
- package/content/guides/get-started/philosophy.md +135 -670
- package/content/guides/get-started/setup.md +53 -74
- package/content/guides/migrations/redis-helpers-migration.md +5 -4
- package/content/guides/migrations/scoped-rbac-migration.md +5 -5
- package/content/guides/migrations/unified-connectors-migration.md +8 -7
- package/content/guides/tutorials/ecommerce-api.md +3 -8
- package/content/guides/tutorials/realtime-chat.md +1 -1
- package/content/references/base/application.md +64 -22
- package/content/references/base/components.md +3 -3
- package/content/references/base/connectors.md +79 -136
- package/content/references/base/controllers.md +12 -12
- package/content/references/base/datasources-reference.md +600 -0
- package/content/references/base/datasources.md +84 -444
- package/content/references/base/dependency-injection.md +25 -46
- package/content/references/base/filter-system/application-usage.md +95 -123
- package/content/references/base/filter-system/array-operators.md +33 -43
- package/content/references/base/filter-system/comparison-operators.md +55 -63
- package/content/references/base/filter-system/default-filter.md +144 -350
- package/content/references/base/filter-system/fields-order-pagination.md +116 -148
- package/content/references/base/filter-system/index.md +114 -253
- package/content/references/base/filter-system/json-filtering.md +52 -181
- package/content/references/base/filter-system/list-operators.md +28 -44
- package/content/references/base/filter-system/logical-operators.md +69 -114
- package/content/references/base/filter-system/null-operators.md +41 -98
- package/content/references/base/filter-system/pattern-matching.md +48 -51
- package/content/references/base/filter-system/quick-reference.md +93 -196
- package/content/references/base/filter-system/range-operators.md +22 -38
- package/content/references/base/filter-system/tips.md +70 -133
- package/content/references/base/filter-system/use-cases.md +173 -232
- package/content/references/base/grpc-controllers.md +53 -17
- package/content/references/base/index.md +5 -3
- package/content/references/base/middlewares.md +43 -28
- package/content/references/base/models-reference.md +886 -0
- package/content/references/base/models.md +81 -1452
- package/content/references/base/providers.md +8 -8
- package/content/references/base/repositories/advanced.md +281 -419
- package/content/references/base/repositories/index.md +84 -644
- package/content/references/base/repositories/mixins.md +25 -21
- package/content/references/base/repositories/relations.md +194 -375
- package/content/references/base/repositories/soft-deletable.md +67 -55
- package/content/references/base/secrets.md +267 -0
- package/content/references/base/services.md +8 -6
- package/content/references/configuration/environment-variables.md +73 -21
- package/content/references/configuration/index.md +51 -31
- package/content/references/index.md +1 -1
- package/content/references/quick-reference.md +3 -16
- package/content/references/utilities/crypto.md +35 -76
- package/content/references/utilities/date.md +33 -73
- package/content/references/utilities/duration.md +85 -0
- package/content/references/utilities/index.md +6 -2
- package/content/references/utilities/jsx-reference.md +298 -0
- package/content/references/utilities/jsx.md +82 -525
- package/content/references/utilities/module.md +81 -61
- package/content/references/utilities/parse.md +34 -64
- package/content/references/utilities/performance.md +33 -58
- package/content/references/utilities/promise.md +28 -62
- package/content/references/utilities/request.md +58 -218
- package/content/references/utilities/retry.md +139 -0
- package/content/references/utilities/schema.md +43 -137
- package/content/references/utilities/statuses-reference.md +361 -0
- package/content/references/utilities/statuses.md +63 -667
- package/dist/mcp-server/index.js +0 -0
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.js +3 -3
- package/dist/mcp-server/tools/github/search-code.tool.js +1 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.js +1 -1
- package/dist/mcp-server/tools/github/view-source-file.tool.js +1 -1
- package/package.json +24 -23
|
@@ -1,534 +1,182 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|------|-------|
|
|
9
|
-
| **Package** | `@venizia/ignis` |
|
|
10
|
-
| **Class** | `MailComponent` |
|
|
11
|
-
| **Runtimes** | Both |
|
|
12
|
-
|
|
13
|
-
### Key Components
|
|
14
|
-
|
|
15
|
-
| Component | Purpose |
|
|
16
|
-
| --------- | ------- |
|
|
17
|
-
| **MailComponent** | Main component registering mail services, transporters, and executors |
|
|
18
|
-
| **MailService** | Core service for sending emails, batch emails, and template-based emails |
|
|
19
|
-
| **TemplateEngineService** | Simple template engine with <code v-pre>{{variable}}</code> syntax |
|
|
20
|
-
| **NodemailerTransportHelper** | Nodemailer-based email transport implementation |
|
|
21
|
-
| **MailgunTransportHelper** | Mailgun API-based email transport implementation |
|
|
22
|
-
| **DirectMailExecutorHelper** | Execute email sending immediately without queue |
|
|
23
|
-
| **InternalQueueMailExecutorHelper** | Queue emails using in-memory queue |
|
|
24
|
-
| **BullMQMailExecutorHelper** | Queue emails using BullMQ for distributed processing |
|
|
25
|
-
| **MailTransportProvider** | Factory provider that creates transport instances based on configuration |
|
|
26
|
-
| **MailQueueExecutorProvider** | Factory provider that creates queue executor instances based on configuration |
|
|
27
|
-
| **NumericCodeGenerator** | Generates cryptographically random numeric verification codes |
|
|
28
|
-
| **RandomTokenGenerator** | Generates cryptographically random base64url tokens |
|
|
29
|
-
| **DefaultVerificationDataGenerator** | Composes code + token generators into full verification data objects |
|
|
30
|
-
|
|
31
|
-
### Transport Providers
|
|
32
|
-
|
|
33
|
-
| Provider | Value | When to Use |
|
|
34
|
-
| -------- | ----- | ----------- |
|
|
35
|
-
| **Nodemailer** | `MailProviders.NODEMAILER` | SMTP-based email sending (Gmail, SendGrid, etc.) |
|
|
36
|
-
| **Mailgun** | `MailProviders.MAILGUN` | Mailgun API for transactional emails |
|
|
37
|
-
| **Custom** | `MailProviders.CUSTOM` | Custom transport implementation |
|
|
38
|
-
|
|
39
|
-
### Queue Executor Types
|
|
40
|
-
|
|
41
|
-
| Type | Value | When to Use |
|
|
42
|
-
| ---- | ----- | ----------- |
|
|
43
|
-
| **Direct** | `'direct'` | No queue, send immediately |
|
|
44
|
-
| **Internal Queue** | `'internal-queue'` | In-memory queue for simple use cases |
|
|
45
|
-
| **BullMQ** | `'bullmq'` | Redis-backed queue for distributed systems |
|
|
46
|
-
|
|
47
|
-
#### Import Paths
|
|
48
|
-
```typescript
|
|
49
|
-
import {
|
|
50
|
-
MailComponent,
|
|
51
|
-
MailKeys,
|
|
52
|
-
MailProviders,
|
|
53
|
-
MailErrorCodes,
|
|
54
|
-
MailDefaults,
|
|
55
|
-
MailQueueExecutorTypes,
|
|
56
|
-
BullMQExecutorModes,
|
|
57
|
-
MailService,
|
|
58
|
-
TemplateEngineService,
|
|
59
|
-
NumericCodeGenerator,
|
|
60
|
-
RandomTokenGenerator,
|
|
61
|
-
DefaultVerificationDataGenerator,
|
|
62
|
-
MailTransportProvider,
|
|
63
|
-
MailQueueExecutorProvider,
|
|
64
|
-
} from '@venizia/ignis/mail';
|
|
65
|
-
|
|
66
|
-
import type {
|
|
67
|
-
TMailOptions,
|
|
68
|
-
IBaseMailOptions,
|
|
69
|
-
INodemailerMailOptions,
|
|
70
|
-
IMailgunMailOptions,
|
|
71
|
-
ICustomMailOptions,
|
|
72
|
-
IGenericMailOptions,
|
|
73
|
-
IMailService,
|
|
74
|
-
IMailTemplateEngine,
|
|
75
|
-
IMailMessage,
|
|
76
|
-
IMailSendResult,
|
|
77
|
-
IMailTransport,
|
|
78
|
-
IMailAttachment,
|
|
79
|
-
IMailQueueExecutor,
|
|
80
|
-
IMailQueueExecutorConfig,
|
|
81
|
-
IMailQueueOptions,
|
|
82
|
-
IMailQueueResult,
|
|
83
|
-
IMailProcessorResult,
|
|
84
|
-
ITemplate,
|
|
85
|
-
IVerificationCodeGenerator,
|
|
86
|
-
IVerificationTokenGenerator,
|
|
87
|
-
IVerificationDataGenerator,
|
|
88
|
-
IVerificationData,
|
|
89
|
-
IVerificationGenerationOptions,
|
|
90
|
-
TMailProvider,
|
|
91
|
-
TNodemailerConfig,
|
|
92
|
-
TMailgunConfig,
|
|
93
|
-
} from '@venizia/ignis/mail';
|
|
94
|
-
```
|
|
1
|
+
---
|
|
2
|
+
title: Mail Component
|
|
3
|
+
description: Send email through pluggable transports (Nodemailer, Mailgun, custom) with templates, batch sending, and a pluggable queue executor
|
|
4
|
+
difficulty: intermediate
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Mail Component
|
|
95
8
|
|
|
96
|
-
|
|
9
|
+
`MailComponent` wires a pluggable email transport (Nodemailer, Mailgun, or your own) into `MailService`. It adds template rendering, batch sending, and an independent queue executor for verification-code/token flows.
|
|
97
10
|
|
|
98
|
-
|
|
11
|
+
## In one example
|
|
99
12
|
|
|
100
|
-
|
|
13
|
+
Bind `MailKeys.MAIL_OPTIONS`, register `MailComponent`, then inject `IMailService` anywhere to send:
|
|
101
14
|
|
|
102
15
|
```typescript
|
|
103
|
-
|
|
104
|
-
import {
|
|
105
|
-
BaseApplication,
|
|
106
|
-
BaseComponent,
|
|
107
|
-
Binding,
|
|
108
|
-
CoreBindings,
|
|
109
|
-
inject,
|
|
110
|
-
} from '@venizia/ignis';
|
|
111
|
-
import { applicationEnvironment, toBoolean } from '@venizia/ignis-helpers';
|
|
16
|
+
import { BaseApplication, ValueOrPromise } from '@venizia/ignis';
|
|
112
17
|
import { MailComponent, MailKeys, MailProviders } from '@venizia/ignis/mail';
|
|
113
18
|
|
|
114
|
-
export class
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
key: MailKeys.MAIL_OPTIONS,
|
|
126
|
-
}).toValue({
|
|
127
|
-
provider: MailProviders.NODEMAILER,
|
|
128
|
-
from: 'noreply@example.com',
|
|
129
|
-
fromName: 'Example App',
|
|
130
|
-
config: {
|
|
131
|
-
host: applicationEnvironment.get<string>('APP_ENV_MAIL_HOST') ?? 'smtp.gmail.com',
|
|
132
|
-
port: +(applicationEnvironment.get<number>('APP_ENV_MAIL_PORT') ?? 465),
|
|
133
|
-
secure: toBoolean(applicationEnvironment.get<boolean>('APP_ENV_MAIL_SECURE') ?? true),
|
|
134
|
-
auth: {
|
|
135
|
-
type: 'oauth2',
|
|
136
|
-
user: applicationEnvironment.get<string>('APP_ENV_MAIL_USER'),
|
|
137
|
-
clientId: applicationEnvironment.get<string>('APP_ENV_MAIL_CLIENT_ID'),
|
|
138
|
-
clientSecret: applicationEnvironment.get<string>('APP_ENV_MAIL_CLIENT_SECRET'),
|
|
139
|
-
refreshToken: applicationEnvironment.get<string>('APP_ENV_MAIL_REFRESH_TOKEN'),
|
|
140
|
-
},
|
|
141
|
-
},
|
|
142
|
-
}),
|
|
143
|
-
// Configure queue executor
|
|
144
|
-
[MailKeys.MAIL_QUEUE_EXECUTOR_CONFIG]: Binding.bind({
|
|
145
|
-
key: MailKeys.MAIL_QUEUE_EXECUTOR_CONFIG,
|
|
146
|
-
}).toValue({
|
|
147
|
-
type: 'internal-queue',
|
|
148
|
-
internalQueue: {
|
|
149
|
-
identifier: 'mail-internal-queue',
|
|
150
|
-
},
|
|
151
|
-
}),
|
|
19
|
+
export class Application extends BaseApplication {
|
|
20
|
+
preConfigure(): ValueOrPromise<void> {
|
|
21
|
+
// MAIL_OPTIONS is the only binding MailComponent requires
|
|
22
|
+
this.bind({ key: MailKeys.MAIL_OPTIONS }).toValue({
|
|
23
|
+
provider: MailProviders.NODEMAILER,
|
|
24
|
+
from: 'noreply@example.com',
|
|
25
|
+
config: {
|
|
26
|
+
host: 'smtp.gmail.com',
|
|
27
|
+
port: 465,
|
|
28
|
+
secure: true,
|
|
29
|
+
auth: { user: process.env.APP_ENV_MAIL_USER, pass: process.env.APP_ENV_MAIL_PASS },
|
|
152
30
|
},
|
|
153
31
|
});
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
override async binding(): Promise<void> {
|
|
157
|
-
this.logger.info('[binding] Binding mail component...');
|
|
158
32
|
|
|
159
|
-
|
|
160
|
-
this.application.component(MailComponent);
|
|
161
|
-
|
|
162
|
-
this.logger.info('[binding] Mail component initialized successfully');
|
|
33
|
+
this.component(MailComponent);
|
|
163
34
|
}
|
|
164
35
|
}
|
|
165
36
|
```
|
|
166
37
|
|
|
167
|
-
### Step 2: Register Component
|
|
168
|
-
|
|
169
38
|
```typescript
|
|
170
|
-
|
|
171
|
-
import {
|
|
172
|
-
import { NodemailerComponent } from './components/mail/component';
|
|
39
|
+
import { BaseService, inject } from '@venizia/ignis';
|
|
40
|
+
import { MailKeys, type IMailService } from '@venizia/ignis/mail';
|
|
173
41
|
|
|
174
|
-
export class
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
42
|
+
export class UserService extends BaseService {
|
|
43
|
+
constructor(@inject({ key: MailKeys.MAIL_SERVICE }) private mailService: IMailService) {
|
|
44
|
+
super({ scope: UserService.name });
|
|
45
|
+
}
|
|
178
46
|
|
|
179
|
-
|
|
47
|
+
async sendWelcomeEmail(email: string) {
|
|
48
|
+
return this.mailService.send({ to: email, subject: 'Welcome!', html: '<h1>Welcome!</h1>' });
|
|
180
49
|
}
|
|
181
50
|
}
|
|
182
51
|
```
|
|
183
52
|
|
|
184
|
-
|
|
53
|
+
`MailKeys.MAIL_QUEUE_EXECUTOR_CONFIG` is optional -- omit it and `MailComponent` binds a `direct` executor (no queue) by default.
|
|
185
54
|
|
|
186
|
-
|
|
55
|
+
## How it works
|
|
187
56
|
|
|
188
|
-
|
|
57
|
+
- **One required binding.** `MailComponent.binding()` throws `Mail options not configured` if `MailKeys.MAIL_OPTIONS` is not bound before registration. Every other binding is optional, with a working default: queue executor config, verification generators, and more.
|
|
189
58
|
|
|
190
|
-
**
|
|
59
|
+
- **Transport is a discriminated union.** `TMailOptions.provider` picks the transport class:
|
|
191
60
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
config: {
|
|
198
|
-
host: 'smtp.gmail.com',
|
|
199
|
-
port: 465,
|
|
200
|
-
secure: true,
|
|
201
|
-
auth: {
|
|
202
|
-
user: 'your-email@gmail.com',
|
|
203
|
-
pass: 'your-app-password',
|
|
204
|
-
},
|
|
205
|
-
},
|
|
206
|
-
}
|
|
207
|
-
```
|
|
61
|
+
| `provider` | Class |
|
|
62
|
+
|---|---|
|
|
63
|
+
| `nodemailer` | `NodemailerTransportHelper` |
|
|
64
|
+
| `mailgun` | `MailgunTransportHelper` |
|
|
65
|
+
| `custom` | Your own object, implementing `IMailTransport` (`send()` + `verify()`) |
|
|
208
66
|
|
|
209
|
-
|
|
67
|
+
`MailTransportProvider` is the factory that switches on the provider. It throws for an unsupported provider string.
|
|
210
68
|
|
|
211
|
-
|
|
212
|
-
// Simple SMTP Authentication (e.g., Gmail with app password)
|
|
213
|
-
this.bind<TMailOptions>({ key: MailKeys.MAIL_OPTIONS }).toValue({
|
|
214
|
-
provider: 'nodemailer',
|
|
215
|
-
from: 'noreply@example.com',
|
|
216
|
-
fromName: 'My App',
|
|
217
|
-
config: {
|
|
218
|
-
host: 'smtp.gmail.com',
|
|
219
|
-
port: 465,
|
|
220
|
-
secure: true,
|
|
221
|
-
auth: {
|
|
222
|
-
user: process.env.APP_ENV_MAIL_USER,
|
|
223
|
-
pass: process.env.APP_ENV_MAIL_PASS,
|
|
224
|
-
},
|
|
225
|
-
},
|
|
226
|
-
});
|
|
227
|
-
```
|
|
69
|
+
- **`MailService` is the one sending entry point.** `send()`, `sendBatch()`, `sendTemplate()`, and `verify()` all validate first, then call the transport directly, then normalize failures into `MailErrorCodes`:
|
|
228
70
|
|
|
229
|
-
|
|
71
|
+
| Case | Result |
|
|
72
|
+
|---|---|
|
|
73
|
+
| Validation error | Passes through unchanged as `400` |
|
|
74
|
+
| Transport throws | Wrapped as `SEND_FAILED` (`500`) |
|
|
75
|
+
| Nodemailer / Mailgun transport | Never throws - returns `{ success: false, error }` instead |
|
|
230
76
|
|
|
231
|
-
|
|
232
|
-
{
|
|
233
|
-
provider: MailProviders.MAILGUN,
|
|
234
|
-
from: 'noreply@example.com',
|
|
235
|
-
fromName: 'Example App',
|
|
236
|
-
config: {
|
|
237
|
-
apiKey: process.env.MAILGUN_API_KEY,
|
|
238
|
-
domain: 'mg.example.com',
|
|
239
|
-
host: 'api.eu.mailgun.net', // Optional: EU region
|
|
240
|
-
},
|
|
241
|
-
}
|
|
242
|
-
```
|
|
77
|
+
- **The queue executor is a separate subsystem, not a mail queue.** `IMailQueueExecutor` (`direct` / `internal-queue` / `bullmq`) exposes only `enqueueVerificationEmail()` and `setProcessor()`, and never touches `MailService`. Call `setProcessor()` before `enqueueVerificationEmail()`, with your own function - typically one wrapping `mailService.send()`.
|
|
243
78
|
|
|
244
|
-
**
|
|
79
|
+
- **Templates are a simple substitution engine.** `TemplateEngineService` stores templates in an in-memory `Map`. It replaces <code v-pre>{{variable}}</code> placeholders, with dot-notation for nested values. A missing value is logged and left as the literal placeholder text, not blanked out.
|
|
245
80
|
|
|
246
|
-
|
|
81
|
+
- **Startup logging never leaks credentials.** `MailComponent` logs only `mailOptions.provider` and `queueExecutorConfig.type`. It never logs the SMTP password, OAuth2 secret, API key, or Redis password nested inside them.
|
|
247
82
|
|
|
248
|
-
|
|
249
|
-
{
|
|
250
|
-
provider: 'sendgrid',
|
|
251
|
-
from: 'noreply@example.com',
|
|
252
|
-
config: {
|
|
253
|
-
apiKey: process.env.SENDGRID_API_KEY,
|
|
254
|
-
// Any key-value pairs accepted
|
|
255
|
-
},
|
|
256
|
-
}
|
|
257
|
-
```
|
|
83
|
+
## Common tasks
|
|
258
84
|
|
|
259
|
-
|
|
260
|
-
> The `IGenericMailOptions` variant will fall through to the `default` case in `MailTransportProvider` and throw `Unsupported mail provider: <provider>` unless the transport provider is replaced with a custom one that handles the provider string. This variant exists for extensibility -- you must bind a custom `MailTransportProvider` that knows how to handle your provider string.
|
|
85
|
+
### Send an email
|
|
261
86
|
|
|
262
|
-
|
|
87
|
+
Inject `IMailService` via `MailKeys.MAIL_SERVICE` and call `send()`.
|
|
263
88
|
|
|
264
89
|
```typescript
|
|
265
|
-
{
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
port: +(applicationEnvironment.get<number>('APP_ENV_MAIL_PORT') ?? 465),
|
|
272
|
-
secure: toBoolean(applicationEnvironment.get<boolean>('APP_ENV_MAIL_SECURE') ?? true),
|
|
273
|
-
auth: {
|
|
274
|
-
type: 'oauth2',
|
|
275
|
-
user: applicationEnvironment.get<string>('APP_ENV_MAIL_USER'),
|
|
276
|
-
clientId: applicationEnvironment.get<string>('APP_ENV_MAIL_CLIENT_ID'),
|
|
277
|
-
clientSecret: applicationEnvironment.get<string>('APP_ENV_MAIL_CLIENT_SECRET'),
|
|
278
|
-
refreshToken: applicationEnvironment.get<string>('APP_ENV_MAIL_REFRESH_TOKEN'),
|
|
279
|
-
},
|
|
280
|
-
},
|
|
281
|
-
}
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
**Example `.env` file for Nodemailer with OAuth2:**
|
|
285
|
-
|
|
286
|
-
```
|
|
287
|
-
APP_ENV_MAIL_HOST=smtp.gmail.com
|
|
288
|
-
APP_ENV_MAIL_PORT=465
|
|
289
|
-
APP_ENV_MAIL_SECURE=true
|
|
290
|
-
APP_ENV_MAIL_USER=your-email@gmail.com
|
|
291
|
-
APP_ENV_MAIL_CLIENT_ID=your-oauth2-client-id
|
|
292
|
-
APP_ENV_MAIL_CLIENT_SECRET=your-oauth2-client-secret
|
|
293
|
-
APP_ENV_MAIL_REFRESH_TOKEN=your-oauth2-refresh-token
|
|
90
|
+
const result = await this.mailService.send({
|
|
91
|
+
to: 'user@example.com',
|
|
92
|
+
subject: 'Welcome!',
|
|
93
|
+
html: '<h1>Welcome!</h1>',
|
|
94
|
+
text: 'Welcome!',
|
|
95
|
+
});
|
|
294
96
|
```
|
|
295
97
|
|
|
296
|
-
|
|
297
|
-
> For Gmail OAuth2, follow [Google's OAuth2 setup guide](https://developers.google.com/gmail/api/auth/web-server) to obtain client ID, secret, and refresh token.
|
|
298
|
-
|
|
299
|
-
### Queue Executor Options
|
|
300
|
-
|
|
301
|
-
The `IMailQueueExecutorConfig` configuration determines how emails are queued and processed.
|
|
98
|
+
### Send a batch of emails
|
|
302
99
|
|
|
303
|
-
|
|
100
|
+
`sendBatch()` runs each message through `send()` with bounded concurrency (default `5`).
|
|
304
101
|
|
|
305
102
|
```typescript
|
|
306
|
-
{
|
|
307
|
-
type: 'direct',
|
|
308
|
-
}
|
|
103
|
+
const results = await this.mailService.sendBatch(messages, { concurrency: 5 });
|
|
309
104
|
```
|
|
310
105
|
|
|
311
|
-
|
|
106
|
+
### Send a registered template
|
|
107
|
+
|
|
108
|
+
Register a template on `IMailTemplateEngine`, then send it through `IMailService`.
|
|
312
109
|
|
|
313
110
|
```typescript
|
|
314
|
-
{
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
111
|
+
this.templateEngine.registerTemplate({
|
|
112
|
+
name: 'welcome-email',
|
|
113
|
+
content: '<h1>Welcome {{userName}}!</h1>',
|
|
114
|
+
options: { subject: 'Welcome to {{appName}}' },
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
await this.mailService.sendTemplate({
|
|
118
|
+
templateName: 'welcome-email',
|
|
119
|
+
data: { userName: 'Jane', appName: 'My App' },
|
|
120
|
+
recipients: 'user@example.com',
|
|
121
|
+
});
|
|
320
122
|
```
|
|
321
123
|
|
|
322
|
-
|
|
124
|
+
### Switch to Mailgun
|
|
125
|
+
|
|
126
|
+
`config` must carry `username`, `key`, and `domain` -- the transport validates them eagerly, on construction.
|
|
323
127
|
|
|
324
128
|
```typescript
|
|
325
129
|
{
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
host: 'localhost',
|
|
330
|
-
port: 6379,
|
|
331
|
-
password: 'your-redis-password',
|
|
332
|
-
},
|
|
333
|
-
queue: {
|
|
334
|
-
identifier: 'mail-queue',
|
|
335
|
-
name: 'mail-queue',
|
|
336
|
-
},
|
|
337
|
-
mode: 'both', // 'queue-only', 'worker-only', or 'both'
|
|
338
|
-
},
|
|
130
|
+
provider: MailProviders.MAILGUN,
|
|
131
|
+
from: 'noreply@example.com',
|
|
132
|
+
config: { username: 'api', key: process.env.MAILGUN_API_KEY, domain: 'mg.example.com' },
|
|
339
133
|
}
|
|
340
134
|
```
|
|
341
135
|
|
|
342
|
-
|
|
343
|
-
> - **`'queue-only'`** -- Only enqueues jobs, does not process them (useful for web servers that offload to workers)
|
|
344
|
-
> - **`'worker-only'`** -- Only processes jobs, does not enqueue (useful for dedicated worker processes)
|
|
345
|
-
> - **`'both'`** -- Both enqueues and processes jobs (simplest setup for single-instance apps)
|
|
346
|
-
|
|
347
|
-
> [!NOTE]
|
|
348
|
-
> Choose the right queue executor for your environment:
|
|
349
|
-
> - **`direct`** -- Development or low-volume applications. No queueing overhead.
|
|
350
|
-
> - **`internal-queue`** -- Single-instance applications with moderate volume. In-memory queue with retry support.
|
|
351
|
-
> - **`bullmq`** -- Distributed systems or high-volume applications. Redis-backed with configurable concurrency, priority, and backoff.
|
|
136
|
+
### Queue verification emails
|
|
352
137
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
The `BullMQMailExecutorHelper` supports dynamic worker scaling at runtime. Workers can be added and removed without restarting the application:
|
|
138
|
+
Get the queue executor instance, register a processor, then enqueue.
|
|
356
139
|
|
|
357
140
|
```typescript
|
|
358
|
-
const executor = this.application.get<
|
|
141
|
+
const executor = this.application.get<IMailQueueExecutor>({
|
|
359
142
|
key: MailKeys.MAIL_QUEUE_EXECUTOR_INSTANCE,
|
|
360
143
|
});
|
|
361
144
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
concurrency: 10,
|
|
366
|
-
lockDuration: 60000, // 60 seconds
|
|
145
|
+
executor.setProcessor(async email => {
|
|
146
|
+
await this.mailService.send({ to: email, subject: 'Verify', html: '...' });
|
|
147
|
+
return { success: true, message: 'Sent', expiresInMinutes: 10 };
|
|
367
148
|
});
|
|
368
149
|
|
|
369
|
-
|
|
370
|
-
const count = executor.getWorkerCount(); // e.g. 2
|
|
371
|
-
|
|
372
|
-
// Check current mode
|
|
373
|
-
const mode = executor.getMode(); // e.g. 'both'
|
|
374
|
-
|
|
375
|
-
// Remove a specific worker by index
|
|
376
|
-
await executor.removeWorker(1);
|
|
377
|
-
|
|
378
|
-
// Remove all workers
|
|
379
|
-
await executor.clearWorkers();
|
|
150
|
+
await executor.enqueueVerificationEmail('user@example.com');
|
|
380
151
|
```
|
|
381
152
|
|
|
382
|
-
|
|
153
|
+
### Generate a verification code and token
|
|
383
154
|
|
|
384
|
-
|
|
385
|
-
await executor.setProcessor(
|
|
386
|
-
async (email: string) => {
|
|
387
|
-
// your processing logic
|
|
388
|
-
return { success: true, message: 'Sent', expiresInMinutes: 10 };
|
|
389
|
-
},
|
|
390
|
-
{
|
|
391
|
-
numberOfWorkers: 3, // Spawn 3 workers (default: 1)
|
|
392
|
-
concurrencyPerWorker: 10, // Each worker handles 10 concurrent jobs (default: 5)
|
|
393
|
-
lockDuration: 60000, // Job lock duration in ms (default: 30000)
|
|
394
|
-
},
|
|
395
|
-
);
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
#### Full Transport Options Interface
|
|
399
|
-
|
|
400
|
-
The `TMailOptions` union type has four variants. All extend `IBaseMailOptions`:
|
|
155
|
+
`MAIL_VERIFICATION_DATA_GENERATOR` composes a numeric code and a base64url token in one call.
|
|
401
156
|
|
|
402
157
|
```typescript
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
provider: 'nodemailer';
|
|
410
|
-
config: TNodemailerConfig; // SMTPTransport | SMTPTransport.Options | string
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
interface IMailgunMailOptions extends IBaseMailOptions {
|
|
414
|
-
provider: 'mailgun';
|
|
415
|
-
config: TMailgunConfig; // { domain: string; [key: string]: any }
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
interface ICustomMailOptions extends IBaseMailOptions {
|
|
419
|
-
provider: 'custom';
|
|
420
|
-
config: IMailTransport; // Must implement send() and verify()
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
interface IGenericMailOptions extends IBaseMailOptions {
|
|
424
|
-
provider: string;
|
|
425
|
-
config: Record<string, AnyType>;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
type TMailOptions =
|
|
429
|
-
| INodemailerMailOptions
|
|
430
|
-
| IMailgunMailOptions
|
|
431
|
-
| ICustomMailOptions
|
|
432
|
-
| IGenericMailOptions;
|
|
158
|
+
const data = this.verificationGenerator.generateVerificationData({
|
|
159
|
+
codeLength: 6,
|
|
160
|
+
tokenBytes: 32,
|
|
161
|
+
codeExpiryMinutes: 10,
|
|
162
|
+
tokenExpiryHours: 24,
|
|
163
|
+
});
|
|
433
164
|
```
|
|
434
165
|
|
|
435
|
-
|
|
436
|
-
```typescript
|
|
437
|
-
interface IMailQueueExecutorConfig {
|
|
438
|
-
type: TConstValue<typeof MailQueueExecutorTypes>; // 'direct' | 'internal-queue' | 'bullmq'
|
|
439
|
-
internalQueue?: {
|
|
440
|
-
identifier: string;
|
|
441
|
-
};
|
|
442
|
-
bullmq?: {
|
|
443
|
-
redis: IRedisHelperOptions;
|
|
444
|
-
queue: {
|
|
445
|
-
identifier: string;
|
|
446
|
-
name: string;
|
|
447
|
-
};
|
|
448
|
-
mode: TConstValue<typeof BullMQExecutorModes>; // REQUIRED: 'queue-only' | 'worker-only' | 'both'
|
|
449
|
-
};
|
|
450
|
-
}
|
|
451
|
-
```
|
|
166
|
+
## See also
|
|
452
167
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
-
|
|
458
|
-
-
|
|
459
|
-
- TLS/SSL connections
|
|
460
|
-
- Custom SMTP headers
|
|
461
|
-
- Connection pooling
|
|
462
|
-
- Attachment handling (file path, buffer, stream)
|
|
463
|
-
- HTML and plain text content
|
|
464
|
-
- SMTP connection verification via `verify()` method
|
|
465
|
-
- Peer dependency validation via `validateModule()` (requires `nodemailer` to be installed)
|
|
466
|
-
|
|
467
|
-
#### Mailgun Transport Capabilities
|
|
468
|
-
- US and EU regional endpoints
|
|
469
|
-
- API key authentication
|
|
470
|
-
- HTML and plain text emails
|
|
471
|
-
- Inline attachments with CID
|
|
472
|
-
- Custom headers (auto-prefixed with `h:`)
|
|
473
|
-
- Batch sending via Mailgun's API
|
|
474
|
-
- Test mode verification via `verify()` method (uses `o:testmode` flag)
|
|
475
|
-
- Peer dependency validation via `validateModule()` (requires `mailgun.js` to be installed)
|
|
476
|
-
|
|
477
|
-
### Constants
|
|
478
|
-
|
|
479
|
-
| Constant | Value | Description |
|
|
480
|
-
|----------|-------|-------------|
|
|
481
|
-
| `MailDefaults.BATCH_CONCURRENCY` | `5` | Default concurrent sends in batch |
|
|
482
|
-
| `MailQueueExecutorTypes.DIRECT` | `'direct'` | Immediate execution |
|
|
483
|
-
| `MailQueueExecutorTypes.INTERNAL_QUEUE` | `'internal-queue'` | In-memory queue |
|
|
484
|
-
| `MailQueueExecutorTypes.BULLMQ` | `'bullmq'` | Redis-backed queue |
|
|
485
|
-
| `BullMQExecutorModes.QUEUE_ONLY` | `'queue-only'` | Producer only (enqueue) |
|
|
486
|
-
| `BullMQExecutorModes.WORKER_ONLY` | `'worker-only'` | Consumer only (process) |
|
|
487
|
-
| `BullMQExecutorModes.BOTH` | `'both'` | Full duplex (produce + consume) |
|
|
488
|
-
|
|
489
|
-
#### MailErrorCodes
|
|
490
|
-
|
|
491
|
-
| Constant | Value | Description |
|
|
492
|
-
|----------|-------|-------------|
|
|
493
|
-
| `MailErrorCodes.INVALID_CONFIGURATION` | `'MAIL_INVALID_CONFIGURATION'` | Invalid or missing configuration (transport, template engine, subject, body) |
|
|
494
|
-
| `MailErrorCodes.SEND_FAILED` | `'MAIL_SEND_FAILED'` | Single email send failed |
|
|
495
|
-
| `MailErrorCodes.VERIFICATION_FAILED` | `'MAIL_VERIFICATION_FAILED'` | Transport connection verification failed |
|
|
496
|
-
| `MailErrorCodes.INVALID_RECIPIENT` | `'MAIL_INVALID_RECIPIENT'` | Missing or empty recipient address |
|
|
497
|
-
| `MailErrorCodes.BATCH_SEND_FAILED` | `'MAIL_BATCH_SEND_FAILED'` | Batch email operation failed |
|
|
498
|
-
| `MailErrorCodes.TEMPLATE_NOT_FOUND` | `'TEMPLATE_NOT_FOUND'` | Template name not found in registry |
|
|
499
|
-
|
|
500
|
-
#### MailQueueExecutorTypes Validation
|
|
501
|
-
|
|
502
|
-
Both `MailQueueExecutorTypes` and `BullMQExecutorModes` include a `SCHEME_SET` / `MODE_SET` and an `isValid()` static method for runtime validation:
|
|
168
|
+
- [Usage & Examples](./usage) -- sending, templates, queue executors, and verification generators
|
|
169
|
+
- [API Reference](./api) -- architecture, binding keys, interfaces, and internals
|
|
170
|
+
- [Error Reference](./errors) -- error codes and troubleshooting
|
|
171
|
+
- [Components Overview](/guides/core-concepts/components) -- component system basics
|
|
172
|
+
- [Queue Helper](/extensions/helpers/queue/) -- the in-memory/BullMQ primitives the queue executors are built on
|
|
173
|
+
- [Redis Helper](/extensions/helpers/redis/) -- `RedisSingleHelper`, required by the BullMQ queue executor
|
|
503
174
|
|
|
504
|
-
|
|
505
|
-
MailQueueExecutorTypes.isValid('bullmq'); // true
|
|
506
|
-
MailQueueExecutorTypes.isValid('unknown'); // false
|
|
507
|
-
BullMQExecutorModes.isValid('both'); // true
|
|
508
|
-
BullMQExecutorModes.isValid('invalid'); // false
|
|
509
|
-
```
|
|
175
|
+
**Files:**
|
|
510
176
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
| `@app/components/mail/service` | `MailKeys.MAIL_SERVICE` | `IMailService` | No | `MailService` (singleton) |
|
|
518
|
-
| `@app/components/mail/services/template-engine` | `MailKeys.MAIL_TEMPLATE_ENGINE` | `IMailTemplateEngine` | No | `TemplateEngineService` (singleton) |
|
|
519
|
-
| `@app/components/mail/transport-provider` | `MailKeys.MAIL_TRANSPORT_PROVIDER` | `TGetMailTransportFn` | No | `MailTransportProvider` (singleton) |
|
|
520
|
-
| `@app/components/mail/transport-instance` | `MailKeys.MAIL_TRANSPORT_INSTANCE` | `IMailTransport` | No | Created by component |
|
|
521
|
-
| `@app/components/mail/queue-executor-provider` | `MailKeys.MAIL_QUEUE_EXECUTOR_PROVIDER` | `TGetMailQueueExecutorFn` | No | `MailQueueExecutorProvider` (singleton) |
|
|
522
|
-
| `@app/components/mail/queue-executor-instance` | `MailKeys.MAIL_QUEUE_EXECUTOR_INSTANCE` | `IMailQueueExecutor` | No | Created by component |
|
|
523
|
-
| `@app/components/mail/verification/code-generator` | `MailKeys.MAIL_VERIFICATION_CODE_GENERATOR` | `IVerificationCodeGenerator` | No | `NumericCodeGenerator` |
|
|
524
|
-
| `@app/components/mail/verification/token-generator` | `MailKeys.MAIL_VERIFICATION_TOKEN_GENERATOR` | `IVerificationTokenGenerator` | No | `RandomTokenGenerator` |
|
|
525
|
-
| `@app/components/mail/verification/data-generator` | `MailKeys.MAIL_VERIFICATION_DATA_GENERATOR` | `IVerificationDataGenerator` | No | `DefaultVerificationDataGenerator` |
|
|
526
|
-
|
|
527
|
-
> [!IMPORTANT]
|
|
528
|
-
> Both `MailKeys.MAIL_OPTIONS` and `MailKeys.MAIL_QUEUE_EXECUTOR_CONFIG` must be bound before registering `MailComponent`. The component throws an error if `MAIL_OPTIONS` is not found.
|
|
529
|
-
|
|
530
|
-
## See Also
|
|
531
|
-
|
|
532
|
-
- [Usage & Examples](./usage) -- Sending emails, templates, queue executors, and verification
|
|
533
|
-
- [API Reference](./api) -- Architecture, interfaces, and internals
|
|
534
|
-
- [Error Reference](./errors) -- Error codes and troubleshooting
|
|
177
|
+
- [`packages/core-server/src/components/mail/component.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/component.ts) -- `MailComponent`
|
|
178
|
+
- [`packages/core-server/src/components/mail/services/mail.service.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/services/mail.service.ts) -- `MailService`
|
|
179
|
+
- [`packages/core-server/src/components/mail/services/template.service.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/services/template.service.ts) -- `TemplateEngineService`
|
|
180
|
+
- [`packages/core-server/src/components/mail/services/generator.service.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/services/generator.service.ts) -- verification generators
|
|
181
|
+
- [`packages/core-server/src/components/mail/common/keys.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/common/keys.ts) -- `MailKeys`
|
|
182
|
+
- [`packages/core-server/src/components/mail/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/common/types.ts) -- `TMailOptions`, `IMailMessage`, and every mail interface
|