@venizia/ignis-docs 0.2.1-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/content/best-practices/architectural-patterns.md +3 -3
- package/content/best-practices/code-style-standards/naming-conventions.md +1 -1
- package/content/best-practices/contribution-workflow.md +2 -2
- package/content/best-practices/error-handling.md +94 -89
- package/content/best-practices/security-guidelines.md +5 -5
- package/content/extensions/components/api-reference.md +22 -21
- package/content/extensions/components/authentication/api.md +64 -28
- package/content/extensions/components/authentication/errors.md +19 -5
- package/content/extensions/components/authentication/index.md +19 -18
- package/content/extensions/components/authentication/usage.md +55 -30
- package/content/extensions/components/authorization/api.md +351 -84
- package/content/extensions/components/authorization/errors.md +51 -17
- package/content/extensions/components/authorization/getting-started.md +227 -0
- package/content/extensions/components/authorization/index.md +24 -16
- package/content/extensions/components/authorization/usage.md +45 -21
- package/content/extensions/components/health-check.md +15 -9
- package/content/extensions/components/index.md +24 -90
- package/content/extensions/components/mail/api.md +105 -54
- package/content/extensions/components/mail/errors.md +12 -10
- package/content/extensions/components/mail/index.md +32 -13
- package/content/extensions/components/mail/usage.md +26 -18
- package/content/extensions/components/request-tracker.md +18 -14
- package/content/extensions/components/socket-io/api.md +377 -882
- package/content/extensions/components/socket-io/errors.md +49 -51
- package/content/extensions/components/socket-io/index.md +72 -88
- package/content/extensions/components/socket-io/usage.md +107 -117
- package/content/extensions/components/static-asset/api.md +83 -31
- package/content/extensions/components/static-asset/errors.md +18 -7
- package/content/extensions/components/static-asset/index.md +18 -11
- package/content/extensions/components/static-asset/usage.md +11 -6
- package/content/extensions/components/template/index.md +3 -3
- package/content/extensions/components/websocket/api.md +58 -27
- package/content/extensions/components/websocket/errors.md +3 -3
- package/content/extensions/components/websocket/index.md +8 -7
- package/content/extensions/components/websocket/usage.md +21 -8
- package/content/extensions/helpers/cron/index.md +8 -7
- package/content/extensions/helpers/crypto/index.md +16 -8
- package/content/extensions/helpers/crypto/reference.md +96 -24
- package/content/extensions/helpers/env/index.md +14 -10
- package/content/extensions/helpers/error/index.md +99 -23
- package/content/extensions/helpers/index.md +61 -47
- package/content/extensions/helpers/inversion/index.md +23 -6
- package/content/extensions/helpers/inversion/reference.md +30 -22
- package/content/extensions/helpers/kafka/admin.md +3 -2
- package/content/extensions/helpers/kafka/compile-binary.md +69 -44
- package/content/extensions/helpers/kafka/consumer.md +24 -21
- package/content/extensions/helpers/kafka/examples.md +22 -234
- package/content/extensions/helpers/kafka/index.md +30 -62
- package/content/extensions/helpers/kafka/producer.md +31 -26
- package/content/extensions/helpers/kafka/schema-registry.md +19 -14
- package/content/extensions/helpers/logger/hf-logger.md +49 -22
- package/content/extensions/helpers/logger/index.md +37 -12
- package/content/extensions/helpers/logger/pino.md +31 -11
- package/content/extensions/helpers/logger/reference.md +243 -52
- package/content/extensions/helpers/network/api.md +65 -30
- package/content/extensions/helpers/network/index.md +32 -11
- package/content/extensions/helpers/queue/index.md +17 -6
- package/content/extensions/helpers/queue/reference.md +52 -25
- package/content/extensions/helpers/redis/index.md +29 -11
- package/content/extensions/helpers/redis/reference.md +85 -28
- package/content/extensions/helpers/secrets/index.md +82 -12
- package/content/extensions/helpers/socket-io/api.md +40 -21
- package/content/extensions/helpers/socket-io/index.md +26 -10
- package/content/extensions/helpers/storage/api.md +42 -24
- package/content/extensions/helpers/storage/index.md +10 -7
- package/content/extensions/helpers/types/index.md +20 -7
- package/content/extensions/helpers/types/reference.md +53 -14
- package/content/extensions/helpers/uid/index.md +166 -10
- package/content/extensions/helpers/websocket/api.md +52 -13
- package/content/extensions/helpers/websocket/index.md +7 -4
- package/content/extensions/helpers/worker-thread/index.md +9 -5
- package/content/extensions/helpers/worker-thread/reference.md +20 -20
- 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/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 +26 -14
- package/content/guides/core-concepts/persistent/sqlite.md +296 -0
- package/content/guides/core-concepts/persistent/transactions.md +12 -11
- 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 +4 -3
- package/content/guides/migrations/scoped-rbac-migration.md +5 -5
- package/content/guides/migrations/unified-connectors-migration.md +7 -6
- package/content/guides/tutorials/realtime-chat.md +1 -1
- package/content/references/base/application.md +63 -21
- package/content/references/base/components.md +3 -3
- package/content/references/base/connectors.md +14 -14
- package/content/references/base/controllers.md +12 -12
- package/content/references/base/datasources-reference.md +32 -31
- package/content/references/base/datasources.md +6 -6
- package/content/references/base/dependency-injection.md +12 -11
- package/content/references/base/filter-system/application-usage.md +54 -30
- package/content/references/base/filter-system/array-operators.md +24 -46
- package/content/references/base/filter-system/comparison-operators.md +47 -67
- package/content/references/base/filter-system/default-filter.md +59 -53
- package/content/references/base/filter-system/fields-order-pagination.md +92 -146
- package/content/references/base/filter-system/index.md +25 -13
- package/content/references/base/filter-system/json-filtering.md +45 -184
- package/content/references/base/filter-system/list-operators.md +23 -53
- package/content/references/base/filter-system/logical-operators.md +63 -121
- package/content/references/base/filter-system/null-operators.md +34 -104
- package/content/references/base/filter-system/pattern-matching.md +40 -55
- package/content/references/base/filter-system/quick-reference.md +86 -198
- package/content/references/base/filter-system/range-operators.md +18 -46
- package/content/references/base/filter-system/tips.md +6 -6
- package/content/references/base/filter-system/use-cases.md +33 -15
- package/content/references/base/grpc-controllers.md +53 -17
- package/content/references/base/index.md +5 -3
- package/content/references/base/middlewares.md +11 -10
- package/content/references/base/models-reference.md +17 -17
- package/content/references/base/models.md +4 -3
- package/content/references/base/providers.md +8 -8
- package/content/references/base/repositories/advanced.md +224 -326
- package/content/references/base/repositories/index.md +19 -6
- package/content/references/base/repositories/mixins.md +5 -5
- package/content/references/base/repositories/relations.md +160 -293
- package/content/references/base/repositories/soft-deletable.md +16 -6
- package/content/references/base/secrets.md +17 -13
- package/content/references/base/services.md +6 -4
- package/content/references/configuration/environment-variables.md +31 -23
- package/content/references/configuration/index.md +6 -4
- package/content/references/index.md +1 -1
- package/content/references/utilities/duration.md +85 -0
- package/content/references/utilities/index.md +5 -1
- package/content/references/utilities/jsx-reference.md +11 -11
- package/content/references/utilities/jsx.md +2 -2
- package/content/references/utilities/module.md +78 -25
- package/content/references/utilities/request.md +2 -1
- package/content/references/utilities/retry.md +139 -0
- package/content/references/utilities/schema.md +2 -2
- package/content/references/utilities/statuses-reference.md +4 -4
- package/content/references/utilities/statuses.md +5 -5
- 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 +17 -16
|
@@ -10,22 +10,22 @@ Every binding key, configuration variant, interface, and internal mechanism of `
|
|
|
10
10
|
|
|
11
11
|
**Files:**
|
|
12
12
|
|
|
13
|
-
- [`packages/core/src/components/mail/component.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/component.ts)
|
|
14
|
-
- [`packages/core/src/components/mail/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/common/types.ts)
|
|
15
|
-
- [`packages/core/src/components/mail/common/constants.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/common/constants.ts)
|
|
16
|
-
- [`packages/core/src/components/mail/common/keys.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/common/keys.ts)
|
|
17
|
-
- [`packages/core/src/components/mail/services/mail.service.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/services/mail.service.ts)
|
|
18
|
-
- [`packages/core/src/components/mail/services/template.service.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/services/template.service.ts)
|
|
19
|
-
- [`packages/core/src/components/mail/services/generator.service.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/services/generator.service.ts)
|
|
20
|
-
- [`packages/core/src/components/mail/providers/mail-transporter.provider.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/providers/mail-transporter.provider.ts)
|
|
21
|
-
- [`packages/core/src/components/mail/providers/mail-queue-executor.provider.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/providers/mail-queue-executor.provider.ts)
|
|
22
|
-
- [`packages/core/src/components/mail/helpers/transporters/nodemail-transporter.helper.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/helpers/transporters/nodemail-transporter.helper.ts)
|
|
23
|
-
- [`packages/core/src/components/mail/helpers/transporters/mailgun-transporter.helper.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/helpers/transporters/mailgun-transporter.helper.ts)
|
|
24
|
-
- [`packages/core/src/components/mail/helpers/executors/direct-executor.helper.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/helpers/executors/direct-executor.helper.ts)
|
|
25
|
-
- [`packages/core/src/components/mail/helpers/executors/internal-queue-executor.helper.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/helpers/executors/internal-queue-executor.helper.ts)
|
|
26
|
-
- [`packages/core/src/components/mail/helpers/executors/bull-mq-executor.helper.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/helpers/executors/bull-mq-executor.helper.ts)
|
|
27
|
-
- [`packages/core/src/components/mail/utilities/type.utility.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/utilities/type.utility.ts)
|
|
28
|
-
- [`packages/core/src/components/mail/utilities/verification.utility.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/utilities/verification.utility.ts)
|
|
13
|
+
- [`packages/core-server/src/components/mail/component.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/component.ts)
|
|
14
|
+
- [`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)
|
|
15
|
+
- [`packages/core-server/src/components/mail/common/constants.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/common/constants.ts)
|
|
16
|
+
- [`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)
|
|
17
|
+
- [`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)
|
|
18
|
+
- [`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)
|
|
19
|
+
- [`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)
|
|
20
|
+
- [`packages/core-server/src/components/mail/providers/mail-transporter.provider.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/providers/mail-transporter.provider.ts)
|
|
21
|
+
- [`packages/core-server/src/components/mail/providers/mail-queue-executor.provider.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/providers/mail-queue-executor.provider.ts)
|
|
22
|
+
- [`packages/core-server/src/components/mail/helpers/transporters/nodemail-transporter.helper.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/helpers/transporters/nodemail-transporter.helper.ts)
|
|
23
|
+
- [`packages/core-server/src/components/mail/helpers/transporters/mailgun-transporter.helper.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/helpers/transporters/mailgun-transporter.helper.ts)
|
|
24
|
+
- [`packages/core-server/src/components/mail/helpers/executors/direct-executor.helper.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/helpers/executors/direct-executor.helper.ts)
|
|
25
|
+
- [`packages/core-server/src/components/mail/helpers/executors/internal-queue-executor.helper.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/helpers/executors/internal-queue-executor.helper.ts)
|
|
26
|
+
- [`packages/core-server/src/components/mail/helpers/executors/bull-mq-executor.helper.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/helpers/executors/bull-mq-executor.helper.ts)
|
|
27
|
+
- [`packages/core-server/src/components/mail/utilities/type.utility.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/utilities/type.utility.ts)
|
|
28
|
+
- [`packages/core-server/src/components/mail/utilities/verification.utility.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/utilities/verification.utility.ts)
|
|
29
29
|
|
|
30
30
|
## Quick reference
|
|
31
31
|
|
|
@@ -141,9 +141,9 @@ import type {
|
|
|
141
141
|
└─────────────────────────────────────────────────┘
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
-
`MailService` and the queue executor are **independent** consumers of the transport/config
|
|
144
|
+
`MailService` and the queue executor are **independent** consumers of the transport/config. `IMailQueueExecutor` never calls `MailService`. See [How it works](./#how-it-works) on the Overview for that distinction.
|
|
145
145
|
|
|
146
|
-
**Source:** [`component.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/component.ts)
|
|
146
|
+
**Source:** [`component.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/component.ts)
|
|
147
147
|
|
|
148
148
|
## Binding keys
|
|
149
149
|
|
|
@@ -164,7 +164,7 @@ import type {
|
|
|
164
164
|
> [!IMPORTANT]
|
|
165
165
|
> `MailKeys.MAIL_OPTIONS` is the only binding `MailComponent` requires. It throws `Mail options not configured` in `binding()` if the key is not bound. `MailKeys.MAIL_QUEUE_EXECUTOR_CONFIG` is read with `isOptional: true` -- when it is not bound, `createAndBindInstances()` falls back to `{ type: MailQueueExecutorTypes.DIRECT }` rather than failing startup.
|
|
166
166
|
|
|
167
|
-
**Source:** [`common/keys.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/common/keys.ts)
|
|
167
|
+
**Source:** [`common/keys.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/common/keys.ts)
|
|
168
168
|
|
|
169
169
|
## Configuration
|
|
170
170
|
|
|
@@ -181,11 +181,13 @@ interface IBaseMailOptions {
|
|
|
181
181
|
interface INodemailerMailOptions extends IBaseMailOptions {
|
|
182
182
|
provider: 'nodemailer';
|
|
183
183
|
config: TNodemailerConfig; // SMTPTransport | SMTPTransport.Options | string
|
|
184
|
+
module?: TNodemailerModule; // the peer itself; see "Peer dependency loading"
|
|
184
185
|
}
|
|
185
186
|
|
|
186
187
|
interface IMailgunMailOptions extends IBaseMailOptions {
|
|
187
188
|
provider: 'mailgun';
|
|
188
189
|
config: TMailgunConfig; // AnyType & { domain: string } -- also requires username, key at runtime
|
|
190
|
+
module?: TMailgunModule; // the peer itself; see "Peer dependency loading"
|
|
189
191
|
}
|
|
190
192
|
|
|
191
193
|
interface ICustomMailOptions extends IBaseMailOptions {
|
|
@@ -243,7 +245,7 @@ type TMailOptions =
|
|
|
243
245
|
}
|
|
244
246
|
```
|
|
245
247
|
|
|
246
|
-
`APP_ENV_MAIL_*` is an app-level convention, not a framework-defined env var
|
|
248
|
+
`APP_ENV_MAIL_*` is an app-level convention, not a framework-defined env var. `applicationEnvironment.get()` reads whatever variables your wrapper component chooses to look up. A matching `.env`:
|
|
247
249
|
|
|
248
250
|
```
|
|
249
251
|
APP_ENV_MAIL_HOST=smtp.gmail.com
|
|
@@ -275,7 +277,7 @@ APP_ENV_MAIL_REFRESH_TOKEN=your-oauth2-refresh-token
|
|
|
275
277
|
```
|
|
276
278
|
|
|
277
279
|
> [!IMPORTANT]
|
|
278
|
-
> `MailgunTransportHelper` validates `username`, `key`, and `domain` on construction
|
|
280
|
+
> `MailgunTransportHelper` validates `username`, `key`, and `domain` on construction. It throws `Invalid Mailgun configuration | Missing required keys: <keys>` if any is missing. This check runs even though `TMailgunConfig`'s only *typed* requirement is `domain` - `username` and `key` are checked at runtime, not by the type.
|
|
279
281
|
|
|
280
282
|
**Custom transport:**
|
|
281
283
|
|
|
@@ -298,7 +300,7 @@ APP_ENV_MAIL_REFRESH_TOKEN=your-oauth2-refresh-token
|
|
|
298
300
|
```
|
|
299
301
|
|
|
300
302
|
> [!WARNING]
|
|
301
|
-
> `IGenericMailOptions` falls through to the `default` case in `MailTransportProvider` and throws `Unsupported mail provider: <provider
|
|
303
|
+
> `IGenericMailOptions` falls through to the `default` case in `MailTransportProvider` and throws `Unsupported mail provider: <provider>`. The framework's built-in provider does not handle it. `IGenericMailOptions` exists only so you can bind a **custom** `MailTransportProvider` that recognizes the provider string.
|
|
302
304
|
|
|
303
305
|
### Queue executor options (`IMailQueueExecutorConfig`)
|
|
304
306
|
|
|
@@ -334,10 +336,15 @@ interface IMailQueueExecutorConfig {
|
|
|
334
336
|
}
|
|
335
337
|
```
|
|
336
338
|
|
|
337
|
-
|
|
338
|
-
> Choosing an executor: **`direct`** for development or low-volume apps (no queueing overhead); **`internal-queue`** for single-instance apps with moderate volume (in-memory, with retry); **`bullmq`** for distributed or high-volume systems (Redis-backed, configurable concurrency/priority/backoff).
|
|
339
|
+
**Choosing an executor:**
|
|
339
340
|
|
|
340
|
-
|
|
341
|
+
| Executor | Use when | Why |
|
|
342
|
+
|---|---|---|
|
|
343
|
+
| `direct` | Development or low-volume apps | No queueing overhead |
|
|
344
|
+
| `internal-queue` | Single-instance apps, moderate volume | In-memory, with retry |
|
|
345
|
+
| `bullmq` | Distributed or high-volume systems | Redis-backed, configurable concurrency/priority/backoff |
|
|
346
|
+
|
|
347
|
+
**Source:** [`common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/common/types.ts)
|
|
341
348
|
|
|
342
349
|
### Constants
|
|
343
350
|
|
|
@@ -375,7 +382,7 @@ Built through `MessageCode.build()`, so every value is lower-case (`ApplicationE
|
|
|
375
382
|
| `MailErrorCodes.BATCH_SEND_FAILED` | `'core.mail.batch_send_failed'` | Batch email operation failed |
|
|
376
383
|
| `MailErrorCodes.TEMPLATE_NOT_FOUND` | `'core.mail.template_not_found'` | Template name not found in registry |
|
|
377
384
|
|
|
378
|
-
**Source:** [`common/constants.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/common/constants.ts)
|
|
385
|
+
**Source:** [`common/constants.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/common/constants.ts)
|
|
379
386
|
|
|
380
387
|
## `IMailService` interface
|
|
381
388
|
|
|
@@ -405,7 +412,8 @@ interface IMailService {
|
|
|
405
412
|
2. Merges `message.from` with `getDefaultFrom()` if unset.
|
|
406
413
|
3. Delegates to `transport.send()`.
|
|
407
414
|
4. Returns `{ success, messageId, error? }`.
|
|
408
|
-
5. If the transport throws and the error is **not** already an `ApplicationError`, it is caught and re-thrown as `MailErrorCodes.SEND_FAILED` (500).
|
|
415
|
+
5. If the transport throws, and the error is **not** already an `ApplicationError`, it is caught and re-thrown as `MailErrorCodes.SEND_FAILED` (500).
|
|
416
|
+
6. An `ApplicationError` thrown earlier in the same `try` block - for example, from `validateMessage()` - is re-thrown as-is, unchanged.
|
|
409
417
|
|
|
410
418
|
**`sendBatch(messages, options?)`**
|
|
411
419
|
|
|
@@ -435,7 +443,7 @@ Delegates to `transport.verify()`. If the transport throws, wraps it as `MailErr
|
|
|
435
443
|
- Else if `options.fromName` is unset, returns `options.from` as-is.
|
|
436
444
|
- Else returns `"${fromName}" <${from}>`.
|
|
437
445
|
|
|
438
|
-
**Source:** [`services/mail.service.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/services/mail.service.ts)
|
|
446
|
+
**Source:** [`services/mail.service.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/services/mail.service.ts)
|
|
439
447
|
|
|
440
448
|
## `IMailMessage` interface
|
|
441
449
|
|
|
@@ -483,7 +491,7 @@ interface IMailAttachment {
|
|
|
483
491
|
- Inline image: `{ filename: 'logo.png', path: '...', cid: 'logo' }`
|
|
484
492
|
- Mailgun maps each attachment to `{ filename, data: att.path ?? att.content ?? Buffer.from('') }`.
|
|
485
493
|
|
|
486
|
-
**Source:** [`common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/common/types.ts)
|
|
494
|
+
**Source:** [`common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/common/types.ts)
|
|
487
495
|
|
|
488
496
|
## `IMailTemplateEngine` interface
|
|
489
497
|
|
|
@@ -511,7 +519,7 @@ interface IMailTemplateEngine {
|
|
|
511
519
|
}
|
|
512
520
|
```
|
|
513
521
|
|
|
514
|
-
`TemplateEngineService` also exposes `clearTemplates(): void
|
|
522
|
+
`TemplateEngineService` also exposes `clearTemplates(): void`. It resets the registry, but it is **not** part of the `IMailTemplateEngine` interface - you can only reach it when you hold the concrete class, not the interface type.
|
|
515
523
|
|
|
516
524
|
| Method | Behavior |
|
|
517
525
|
|--------|----------|
|
|
@@ -535,7 +543,7 @@ interface ITemplate {
|
|
|
535
543
|
|
|
536
544
|
The `render` field supports a custom per-template render function, though the built-in `TemplateEngineService` always uses `content` + `renderSimpleTemplate()` instead.
|
|
537
545
|
|
|
538
|
-
**Source:** [`services/template.service.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/services/template.service.ts)
|
|
546
|
+
**Source:** [`services/template.service.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/services/template.service.ts)
|
|
539
547
|
|
|
540
548
|
## Transport layer
|
|
541
549
|
|
|
@@ -568,25 +576,42 @@ interface IMailTransport {
|
|
|
568
576
|
|
|
569
577
|
### Peer dependency loading
|
|
570
578
|
|
|
571
|
-
|
|
579
|
+
Pass the peer yourself through `module`, or let the transport find it. With `module` set, the transport uses it as-is; without it, the transport falls back to `ModuleUtility.loadSync({ module })` from the client-factory seam `configure()` calls. A missing package then throws the framework's install hint - `[ModuleUtility.loadSync] nodemailer is required. Please install 'nodemailer'` - not Node's raw `Cannot find module`.
|
|
580
|
+
|
|
581
|
+
That fallback keeps the specifier invisible to `Bun.build`. Importing `@venizia/ignis/mail` for the Nodemailer transport no longer drags `mailgun.js` into your bundle, and the reverse holds too.
|
|
582
|
+
|
|
583
|
+
**A compiled application must pass `module`.** A `bun build --compile` binary ships without `node_modules`, so the runtime lookup has nothing to resolve against and the component throws that install hint at boot - with the peer sitting in `package.json`, which is no help because nothing put it inside the binary. The static import is what embeds it:
|
|
584
|
+
|
|
585
|
+
```typescript
|
|
586
|
+
import * as nodemailer from 'nodemailer';
|
|
587
|
+
|
|
588
|
+
this.bind({ key: MailKeys.MAIL_OPTIONS }).toValue({
|
|
589
|
+
provider: MailProviders.NODEMAILER,
|
|
590
|
+
config: { host, port, secure, auth },
|
|
591
|
+
module: nodemailer,
|
|
592
|
+
});
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
`module` is typed as the shape the transport calls (`createTransport` for Nodemailer, a constructor for Mailgun), so handing over the wrong thing is a compile error rather than a boot crash. Prefer it over [`ModuleUtility.register`](/references/utilities/module#compiled-binaries): the dependency arrives where it is used and cannot be defeated by binding order. Every IGNIS component that reaches an optional peer now takes one of these options - the [table in the module reference](/references/utilities/module#compiled-binaries) lists them.
|
|
572
596
|
|
|
573
597
|
**Nodemailer (`NodemailerTransportHelper`, extends `BaseHelper`):**
|
|
574
598
|
|
|
575
599
|
- `configure()` builds the transporter via `nodemailer.createTransport(config)`.
|
|
576
|
-
- `send()` maps `IMailMessage` fields to Nodemailer's mail options, joining array recipients with `', '`.
|
|
577
|
-
- `verify()` delegates to `transporter.verify()` (SMTP handshake).
|
|
600
|
+
- `send()` maps `IMailMessage` fields to Nodemailer's mail options, joining array recipients with `', '`. It catches transport errors and returns `{ success: false, error }` - it never throws.
|
|
601
|
+
- `verify()` delegates to `transporter.verify()` (SMTP handshake). It catches errors and returns `false` - it never throws.
|
|
578
602
|
- `close()` calls `transporter.close()`.
|
|
579
603
|
|
|
580
604
|
**Mailgun (`MailgunTransportHelper`, extends `BaseHelper`):**
|
|
581
605
|
|
|
582
|
-
- `configure()` calls `validateConfig()` **before** building the client
|
|
583
|
-
- `send()` converts `IMailMessage` to Mailgun's format: `to` is coerced to an array, `replyTo` becomes `h:Reply-To`, every custom header is prefixed `h:`. Attachments map to `{ filename, data: path ?? content ?? Buffer.from('') }`.
|
|
584
|
-
-
|
|
585
|
-
-
|
|
606
|
+
- `configure()` calls `validateConfig()` **before** building the client. `username`, `key`, and `domain` must all be present in `config`, or it throws `Invalid Mailgun configuration | Missing required keys: <keys>` (`INVALID_CONFIGURATION`, 500). This check runs even though `TMailgunConfig`'s type only requires `domain`.
|
|
607
|
+
- `send()` converts `IMailMessage` to Mailgun's format: `to` is coerced to an array, `replyTo` becomes `h:Reply-To`, and every custom header is prefixed `h:`. Attachments map to `{ filename, data: path ?? content ?? Buffer.from('') }`.
|
|
608
|
+
- It catches send errors and returns `{ success: false, error }` - it never throws.
|
|
609
|
+
- `verify()` sends a test message to `verify@<domain>` with `o:testmode: 'yes'`, since Mailgun has no dedicated verify endpoint. It catches errors and returns `false` - it never throws.
|
|
610
|
+
- No `close()` - the HTTP API is stateless.
|
|
586
611
|
|
|
587
612
|
**Custom transport:** set `provider: MailProviders.CUSTOM` and pass an object implementing `IMailTransport` as `config`. Useful for SendGrid, AWS SES, or a custom SMTP relay that the framework does not ship a helper for.
|
|
588
613
|
|
|
589
|
-
**Source:** [`helpers/transporters/`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/helpers/transporters)
|
|
614
|
+
**Source:** [`helpers/transporters/`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/helpers/transporters)
|
|
590
615
|
|
|
591
616
|
## Queue executor implementations
|
|
592
617
|
|
|
@@ -599,28 +624,54 @@ interface IMailQueueExecutor {
|
|
|
599
624
|
}
|
|
600
625
|
```
|
|
601
626
|
|
|
602
|
-
**`DirectMailExecutorHelper`**
|
|
627
|
+
**`DirectMailExecutorHelper`** extends `BaseHelper`. It calls the processor immediately, with no queue, and returns `{ queued: false, message: 'Email sent immediately (no queue)', result }`. If `enqueueVerificationEmail()` runs before `setProcessor()`, it throws `MailExecutorErrors.PROCESSOR_NOT_SET`.
|
|
603
628
|
|
|
604
|
-
**`InternalQueueMailExecutorHelper`**
|
|
629
|
+
**`InternalQueueMailExecutorHelper`** extends `BaseHelper` (constructor takes `IInternalQueueMailExecutorOpts`). It wraps `SequentialQueueHelper<IQueueJobPayload>` from `@venizia/ignis-helpers`, with `autoDispatch: true`.
|
|
605
630
|
|
|
606
631
|
- Job IDs: `job_<counter>_<timestamp>`.
|
|
607
632
|
- `options.delay > 0` schedules the enqueue itself via `setTimeout`, tracked in an internal `delayedJobs: Map<string, NodeJS.Timeout>`.
|
|
608
|
-
- Retry: on a thrown error or `{ success: false }` from the processor, retries up to `options.attempts ?? 3` times
|
|
609
|
-
|
|
633
|
+
- Retry: on a thrown error, or `{ success: false }` from the processor, it retries up to `options.attempts ?? 3` times using `calculateBackoff()`:
|
|
634
|
+
|
|
635
|
+
| `backoff` config | Delay |
|
|
636
|
+
|---|---|
|
|
637
|
+
| Not set | `1000ms` fixed |
|
|
638
|
+
| `type: 'fixed'` | the raw `delay` |
|
|
639
|
+
| `type: 'exponential'` | `delay * 2 ** (attempt - 1)` |
|
|
640
|
+
|
|
641
|
+
- `close()` clears every pending delayed/retry `setTimeout`. Without that cleanup, a live timer keeps the event loop open past shutdown.
|
|
610
642
|
- No persistence across restarts.
|
|
611
643
|
|
|
612
|
-
**`BullMQMailExecutorHelper`**
|
|
644
|
+
**`BullMQMailExecutorHelper`** extends `BaseHelper` (constructor takes `IBullMQMailExecutorOpts`). It wraps `BullMQHelper` (`@venizia/ignis-helpers/bullmq`) and a `RedisSingleHelper` connection.
|
|
613
645
|
|
|
614
646
|
| Mode | Queue created | Workers created | Can enqueue | Can process |
|
|
615
647
|
|------|----------------|------------------|-------------|-------------|
|
|
616
|
-
| `'queue-only'` | Yes | No (`setProcessor()` skips worker creation, logs a warning) | Yes
|
|
648
|
+
| `'queue-only'` | Yes | No (`setProcessor()` skips worker creation, logs a warning) | Yes - processor not required | No |
|
|
617
649
|
| `'worker-only'` | No | Yes | No (throws) | Yes |
|
|
618
|
-
| `'both'` | Yes | Yes | Yes
|
|
650
|
+
| `'both'` | Yes | Yes | Yes - processor required | Yes |
|
|
651
|
+
|
|
652
|
+
`setProcessor(processor, opts?)` is `async`. It clears all existing workers, then creates `opts?.numberOfWorkers ?? 1` workers, each with `concurrencyPerWorker ?? 5` and `lockDuration ?? 30000`ms. In `queue-only` mode it stores the processor and returns without creating any worker.
|
|
653
|
+
|
|
654
|
+
`enqueueVerificationEmail()` throws in three cases:
|
|
655
|
+
|
|
656
|
+
| Condition | Throws |
|
|
657
|
+
|---|---|
|
|
658
|
+
| Mode is `worker-only` | `Cannot enqueue jobs in worker-only mode...` |
|
|
659
|
+
| Queue was never created (should not happen in a queue-enabled mode) | `Queue helper not initialized...` |
|
|
660
|
+
| No processor set, and `mode !== 'queue-only'` | `PROCESSOR_NOT_SET` |
|
|
661
|
+
|
|
662
|
+
Its enqueue options: `attempts: options?.attempts ?? 3`, `backoff: { type: options?.backoff?.type ?? 'exponential', delay: options?.backoff?.delay ?? 1000 }`, `removeOnComplete: true`, `removeOnFail: false`.
|
|
663
|
+
|
|
664
|
+
**Dynamic workers** - manage the worker pool without a restart:
|
|
665
|
+
|
|
666
|
+
| Method | Behavior |
|
|
667
|
+
|---|---|
|
|
668
|
+
| `addWorker(opts)` | Requires a processor set first. Takes a unique identifier, default concurrency `5`, default lock duration `30000`ms |
|
|
669
|
+
| `removeWorker(index)` | Closes the worker, then splices it out. Returns `false` if `index` is out of range |
|
|
670
|
+
| `clearWorkers()` | Closes and empties every worker. Called internally by `setProcessor()` |
|
|
671
|
+
| `getWorkerCount()` | Returns the current worker count |
|
|
672
|
+
| `getMode()` | Returns the executor's `BullMQExecutorModes` value |
|
|
619
673
|
|
|
620
|
-
|
|
621
|
-
- `enqueueVerificationEmail()` throws `Cannot enqueue jobs in worker-only mode...` in `worker-only` mode; throws `Queue helper not initialized...` if the queue was never created (should not happen in a queue-enabled mode); throws `PROCESSOR_NOT_SET` only when `mode !== 'queue-only'` and no processor is set. Enqueue options: `attempts: options?.attempts ?? 3`, `backoff: { type: options?.backoff?.type ?? 'exponential', delay: options?.backoff?.delay ?? 1000 }`, `removeOnComplete: true`, `removeOnFail: false`.
|
|
622
|
-
- **Dynamic workers:** `addWorker(opts)` (requires a processor, unique identifier, default concurrency `5`, default lock duration `30000`ms), `removeWorker(index)` (closes then splices, returns `false` if out of range), `clearWorkers()` (closes and empties, called internally by `setProcessor()`), `getWorkerCount()`, `getMode()`.
|
|
623
|
-
- `close()` tears down workers, then the queue, then the Redis connection -- every step runs even if an earlier one failed, and all failures are collected into one thrown error at the end.
|
|
674
|
+
`close()` tears down workers, then the queue, then the Redis connection. Every step runs even if an earlier one failed, and every failure is collected into one thrown error at the end.
|
|
624
675
|
|
|
625
676
|
```typescript
|
|
626
677
|
interface IBullMQMailExecutorOpts {
|
|
@@ -630,7 +681,7 @@ interface IBullMQMailExecutorOpts {
|
|
|
630
681
|
}
|
|
631
682
|
```
|
|
632
683
|
|
|
633
|
-
**Source:** [`helpers/executors/`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/helpers/executors)
|
|
684
|
+
**Source:** [`helpers/executors/`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/helpers/executors)
|
|
634
685
|
|
|
635
686
|
## Additional interfaces
|
|
636
687
|
|
|
@@ -694,7 +745,7 @@ interface IInternalQueueMailExecutorOpts {
|
|
|
694
745
|
}
|
|
695
746
|
```
|
|
696
747
|
|
|
697
|
-
**Source:** [`common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/common/types.ts)
|
|
748
|
+
**Source:** [`common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/common/types.ts)
|
|
698
749
|
|
|
699
750
|
## Utility functions
|
|
700
751
|
|
|
@@ -709,9 +760,9 @@ function getExpiryTimeInHours(hours: number): Date; // Date `hours` hours fr
|
|
|
709
760
|
```
|
|
710
761
|
|
|
711
762
|
- `isMailTransport()` checks that `send` and `verify` are functions, and that `close` is either a function or `undefined`.
|
|
712
|
-
- `isValidMailOptions()` checks that `provider` is a string and `config` is truthy
|
|
763
|
+
- `isValidMailOptions()` checks that `provider` is a string and `config` is truthy. It does not validate the shape of `config` against the specific provider.
|
|
713
764
|
|
|
714
|
-
**Source:** [`utilities/`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/utilities)
|
|
765
|
+
**Source:** [`utilities/`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core-server/src/components/mail/utilities)
|
|
715
766
|
|
|
716
767
|
## See also
|
|
717
768
|
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
# Mail
|
|
1
|
+
# Mail - Error Reference & Troubleshooting
|
|
2
2
|
|
|
3
3
|
> Complete error code reference and troubleshooting guide for the Mail component.
|
|
4
4
|
|
|
5
5
|
## Error reference
|
|
6
6
|
|
|
7
|
-
All errors are created via `getError()`. Only errors that
|
|
7
|
+
All errors are created via `getError()`. Only errors that carry a status and a code reach you as an `ApplicationError` with those fields; the rows marked `--` throw a plain error with only a `message`. Read an error's code at `error.normalized.code` - there is no flat `error.messageCode`.
|
|
8
|
+
|
|
9
|
+
The 4xx rows below come from the `MailErrors` catalog, which holds the status and the code together so two throw sites cannot disagree. The 5xx rows stay codeless by design - a delivery failure is not something a caller can act on.
|
|
8
10
|
|
|
9
11
|
### `MailService` errors
|
|
10
12
|
|
|
@@ -19,7 +21,7 @@ All errors are created via `getError()`. Only errors that pass `statusCode`/`mes
|
|
|
19
21
|
| Transport throws during `verify()` | 500 | `core.mail.verification_failed` | `Mail transport verification failed: <error>` |
|
|
20
22
|
|
|
21
23
|
> [!NOTE]
|
|
22
|
-
> "Transport throws during `send()`/`verify()`" only fires for a **custom** transport. The built-in `NodemailerTransportHelper` and `MailgunTransportHelper` never throw from `send()` or `verify()
|
|
24
|
+
> "Transport throws during `send()`/`verify()`" only fires for a **custom** transport. The built-in `NodemailerTransportHelper` and `MailgunTransportHelper` never throw from `send()` or `verify()`. They catch internally and return `{ success: false, error }` (or `false` for `verify()`). A 400 validation error raised by `validateMessage()` is re-thrown unchanged, not wrapped as `SEND_FAILED`.
|
|
23
25
|
|
|
24
26
|
### `MailComponent` errors
|
|
25
27
|
|
|
@@ -43,7 +45,7 @@ All errors are created via `getError()`. Only errors that pass `statusCode`/`mes
|
|
|
43
45
|
|-----------|--------|-----------|---------|
|
|
44
46
|
| `config` is missing `username`, `key`, or `domain` | 500 | `core.mail.invalid_configuration` | `Invalid Mailgun configuration \| Missing required keys: <keys>` |
|
|
45
47
|
|
|
46
|
-
This check runs on `configure()`, one layer deeper than `MailTransportProvider`'s type guard
|
|
48
|
+
This check runs on `configure()`, one layer deeper than `MailTransportProvider`'s type guard. A `config` object that passes the provider's guard - it merely has *a* `config` property - can still fail this one if it is missing the specific keys Mailgun's client needs.
|
|
47
49
|
|
|
48
50
|
### `MailQueueExecutorProvider` errors
|
|
49
51
|
|
|
@@ -99,7 +101,7 @@ config: { username: 'api', key: process.env.MAILGUN_API_KEY, domain: 'mg.example
|
|
|
99
101
|
|
|
100
102
|
### `core.mail.template_not_found` from `sendTemplate()`
|
|
101
103
|
|
|
102
|
-
- **Cause.** The template name was never registered via `templateEngine.registerTemplate()
|
|
104
|
+
- **Cause.** The template name was never registered via `templateEngine.registerTemplate()`. This often happens because a database-backed sync runs after the first `sendTemplate()` call, not before it.
|
|
103
105
|
- **Fix.** Register the template first:
|
|
104
106
|
|
|
105
107
|
```typescript
|
|
@@ -111,7 +113,7 @@ this.templateEngine.registerTemplate({
|
|
|
111
113
|
|
|
112
114
|
### Emails silently fail with `success: false`
|
|
113
115
|
|
|
114
|
-
- **Cause.** The transport connection is misconfigured
|
|
116
|
+
- **Cause.** The transport connection is misconfigured: wrong credentials, a blocked port, or an expired OAuth2 token. `MailService.send()` never throws for a built-in transport's connection failure - it returns `{ success: false, error }`.
|
|
115
117
|
- **Fix.** Check `result.error` for the underlying transport error, and verify the connection at startup:
|
|
116
118
|
|
|
117
119
|
```typescript
|
|
@@ -139,7 +141,7 @@ if (!isConnected) {
|
|
|
139
141
|
|
|
140
142
|
### Template placeholders show up literally in the output
|
|
141
143
|
|
|
142
|
-
- **Cause.** The `data` object passed to `render()`/`sendTemplate()` is missing a <code v-pre>{{key}}</code> the template uses. Without `requireValidate: true`, the engine preserves the original placeholder text
|
|
144
|
+
- **Cause.** The `data` object passed to `render()`/`sendTemplate()` is missing a <code v-pre>{{key}}</code> the template uses. Without `requireValidate: true`, the engine preserves the original placeholder text. It does **not** replace a missing value with an empty string.
|
|
143
145
|
- **Fix.** Check what is missing before rendering, or fail loudly instead:
|
|
144
146
|
|
|
145
147
|
```typescript
|
|
@@ -159,7 +161,7 @@ const html = this.templateEngine.render({
|
|
|
159
161
|
|
|
160
162
|
### "Processor not set. Call setProcessor() first."
|
|
161
163
|
|
|
162
|
-
- **Cause.** `enqueueVerificationEmail()` was called before `setProcessor()`. Direct and Internal Queue always require
|
|
164
|
+
- **Cause.** `enqueueVerificationEmail()` was called before `setProcessor()`. Direct and Internal Queue always require a processor first. BullMQ requires one too, except in `'queue-only'` mode, where enqueueing does not need a processor.
|
|
163
165
|
- **Fix.** Register a processor before enqueuing:
|
|
164
166
|
|
|
165
167
|
```typescript
|
|
@@ -176,10 +178,10 @@ executor.setProcessor(async (email: string) => {
|
|
|
176
178
|
|
|
177
179
|
### Startup logs and credentials
|
|
178
180
|
|
|
179
|
-
`MailComponent.createAndBindInstances()` logs only `mailOptions.provider` and `queueExecutorConfig.type
|
|
181
|
+
`MailComponent.createAndBindInstances()` logs only `mailOptions.provider` and `queueExecutorConfig.type`, at `info` level. It never logs the full config object, by design. That keeps SMTP passwords, OAuth2 secrets, Mailgun API keys, and Redis passwords out of the log - at least through the component itself.
|
|
180
182
|
|
|
181
183
|
> [!WARNING]
|
|
182
|
-
> That guarantee is scoped to `MailComponent`'s own logging. If your wrapper component
|
|
184
|
+
> That guarantee is scoped to `MailComponent`'s own logging. If your wrapper component or any other code logs the `TMailOptions`/`IMailQueueExecutorConfig` object directly - for example, `logger.info('%j', mailOptions)` while debugging - you reintroduce the leak yourself. Log individual safe fields instead of the whole object.
|
|
183
185
|
|
|
184
186
|
## See also
|
|
185
187
|
|
|
@@ -6,7 +6,7 @@ difficulty: intermediate
|
|
|
6
6
|
|
|
7
7
|
# Mail Component
|
|
8
8
|
|
|
9
|
-
`MailComponent` wires a pluggable email transport (Nodemailer, Mailgun, or your own) into `MailService
|
|
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.
|
|
10
10
|
|
|
11
11
|
## In one example
|
|
12
12
|
|
|
@@ -54,12 +54,31 @@ export class UserService extends BaseService {
|
|
|
54
54
|
|
|
55
55
|
## How it works
|
|
56
56
|
|
|
57
|
-
- **One required binding.** `MailComponent.binding()` throws `Mail options not configured` if `MailKeys.MAIL_OPTIONS` is not bound before registration. Every other binding
|
|
58
|
-
|
|
59
|
-
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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.
|
|
58
|
+
|
|
59
|
+
- **Transport is a discriminated union.** `TMailOptions.provider` picks the transport class:
|
|
60
|
+
|
|
61
|
+
| `provider` | Class |
|
|
62
|
+
|---|---|
|
|
63
|
+
| `nodemailer` | `NodemailerTransportHelper` |
|
|
64
|
+
| `mailgun` | `MailgunTransportHelper` |
|
|
65
|
+
| `custom` | Your own object, implementing `IMailTransport` (`send()` + `verify()`) |
|
|
66
|
+
|
|
67
|
+
`MailTransportProvider` is the factory that switches on the provider. It throws for an unsupported provider string.
|
|
68
|
+
|
|
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`:
|
|
70
|
+
|
|
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 |
|
|
76
|
+
|
|
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()`.
|
|
78
|
+
|
|
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.
|
|
80
|
+
|
|
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.
|
|
63
82
|
|
|
64
83
|
## Common tasks
|
|
65
84
|
|
|
@@ -155,9 +174,9 @@ const data = this.verificationGenerator.generateVerificationData({
|
|
|
155
174
|
|
|
156
175
|
**Files:**
|
|
157
176
|
|
|
158
|
-
- [`packages/core/src/components/mail/component.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/component.ts) -- `MailComponent`
|
|
159
|
-
- [`packages/core/src/components/mail/services/mail.service.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/services/mail.service.ts) -- `MailService`
|
|
160
|
-
- [`packages/core/src/components/mail/services/template.service.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/services/template.service.ts) -- `TemplateEngineService`
|
|
161
|
-
- [`packages/core/src/components/mail/services/generator.service.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/services/generator.service.ts) -- verification generators
|
|
162
|
-
- [`packages/core/src/components/mail/common/keys.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/common/keys.ts) -- `MailKeys`
|
|
163
|
-
- [`packages/core/src/components/mail/common/types.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/core/src/components/mail/common/types.ts) -- `TMailOptions`, `IMailMessage`, and every mail interface
|
|
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
|