@gravito/signal 3.0.4 → 3.1.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.
Files changed (124) hide show
  1. package/README.md +26 -15
  2. package/dist/Mailable.d.ts +453 -0
  3. package/dist/OrbitSignal.d.ts +267 -0
  4. package/{src/Queueable.ts → dist/Queueable.d.ts} +1 -1
  5. package/{src/TypedMailable.ts → dist/TypedMailable.d.ts} +12 -13
  6. package/dist/dev/DevMailbox.d.ts +79 -0
  7. package/dist/dev/DevServer.d.ts +39 -0
  8. package/dist/dev/storage/FileMailboxStorage.d.ts +16 -0
  9. package/dist/dev/storage/MailboxStorage.d.ts +14 -0
  10. package/dist/dev/storage/MemoryMailboxStorage.d.ts +13 -0
  11. package/dist/dev/ui/mailbox.d.ts +11 -0
  12. package/dist/dev/ui/preview.d.ts +11 -0
  13. package/dist/dev/ui/shared.d.ts +15 -0
  14. package/dist/errors.d.ts +58 -0
  15. package/{src/events.ts → dist/events.d.ts} +20 -29
  16. package/dist/{lib-HJTRWKU5.mjs → index.cjs} +4687 -10983
  17. package/dist/index.d.ts +303 -1874
  18. package/dist/index.js +317 -45939
  19. package/dist/index.mjs +59748 -27
  20. package/dist/renderers/HtmlRenderer.d.ts +34 -0
  21. package/dist/renderers/MjmlRenderer.d.ts +41 -0
  22. package/dist/renderers/ReactMjmlRenderer.d.ts +38 -0
  23. package/dist/renderers/ReactRenderer.d.ts +46 -0
  24. package/{src/renderers/Renderer.ts → dist/renderers/Renderer.d.ts} +23 -24
  25. package/dist/renderers/TemplateRenderer.d.ts +55 -0
  26. package/dist/renderers/VueMjmlRenderer.d.ts +39 -0
  27. package/dist/renderers/VueRenderer.d.ts +47 -0
  28. package/dist/renderers/mjml-templates.d.ts +11 -0
  29. package/dist/transports/BaseTransport.d.ts +111 -0
  30. package/dist/transports/LogTransport.d.ts +42 -0
  31. package/dist/transports/MemoryTransport.d.ts +51 -0
  32. package/dist/transports/SesTransport.d.ts +79 -0
  33. package/dist/transports/SmtpTransport.d.ts +124 -0
  34. package/dist/transports/Transport.d.ts +44 -0
  35. package/dist/types.d.ts +294 -0
  36. package/{src/utils/html.ts → dist/utils/html.d.ts} +1 -15
  37. package/dist/webhooks/SendGridWebhookDriver.d.ts +45 -0
  38. package/dist/webhooks/SesWebhookDriver.d.ts +23 -0
  39. package/package.json +20 -8
  40. package/CHANGELOG.md +0 -74
  41. package/dist/MjmlRenderer-IUH663FT.mjs +0 -8
  42. package/dist/ReactMjmlRenderer-C3P5YO5L.mjs +0 -8
  43. package/dist/ReactRenderer-24SQ4KRU.mjs +0 -27
  44. package/dist/ReactRenderer-2JFLRVST.mjs +0 -45
  45. package/dist/ReactRenderer-CMCAOEPH.mjs +0 -28
  46. package/dist/ReactRenderer-KYNA4WKE.mjs +0 -28
  47. package/dist/ReactRenderer-LYEOSYFS.mjs +0 -28
  48. package/dist/ReactRenderer-V54CUUEI.mjs +0 -45
  49. package/dist/VueMjmlRenderer-4F4CXHDB.mjs +0 -8
  50. package/dist/VueMjmlRenderer-5WZR4CQG.mjs +0 -8
  51. package/dist/VueMjmlRenderer-U5YMWI44.mjs +0 -8
  52. package/dist/VueRenderer-3YBRQXME.mjs +0 -48
  53. package/dist/VueRenderer-46JGXTJ2.mjs +0 -48
  54. package/dist/VueRenderer-5KWD4R3C.mjs +0 -48
  55. package/dist/VueRenderer-C23U4O5E.mjs +0 -48
  56. package/dist/VueRenderer-DWTCD2RF.mjs +0 -31
  57. package/dist/VueRenderer-IIR5SYTM.mjs +0 -31
  58. package/dist/VueRenderer-LEVDFLHP.mjs +0 -31
  59. package/dist/VueRenderer-RNHSCCRI.mjs +0 -48
  60. package/dist/VueRenderer-SUP66ISX.mjs +0 -29
  61. package/dist/chunk-3WOR3XSL.mjs +0 -82
  62. package/dist/chunk-DBFIVHHG.mjs +0 -79
  63. package/dist/chunk-EBO3CZXG.mjs +0 -15
  64. package/dist/chunk-HEBXNMVQ.mjs +0 -48
  65. package/dist/chunk-KB7IDDBT.mjs +0 -82
  66. package/dist/chunk-LZL5UUPC.mjs +0 -82
  67. package/dist/chunk-W6LXIJKK.mjs +0 -57
  68. package/dist/chunk-XBIVBJS2.mjs +0 -8
  69. package/dist/index.d.mts +0 -2115
  70. package/dist/server-renderer-4IM3P5XZ.mjs +0 -37183
  71. package/dist/server-renderer-4W4FI7YG.mjs +0 -37269
  72. package/dist/server-renderer-7KWFSTPV.mjs +0 -37193
  73. package/dist/server-renderer-S5FPSTJ2.mjs +0 -37183
  74. package/dist/server-renderer-X5LUFVWT.mjs +0 -37193
  75. package/doc/OPTIMIZATION_PLAN.md +0 -496
  76. package/scripts/check-coverage.ts +0 -64
  77. package/src/Mailable.ts +0 -674
  78. package/src/OrbitSignal.ts +0 -451
  79. package/src/dev/DevMailbox.ts +0 -146
  80. package/src/dev/DevServer.ts +0 -192
  81. package/src/dev/storage/FileMailboxStorage.ts +0 -66
  82. package/src/dev/storage/MailboxStorage.ts +0 -15
  83. package/src/dev/storage/MemoryMailboxStorage.ts +0 -36
  84. package/src/dev/ui/mailbox.ts +0 -77
  85. package/src/dev/ui/preview.ts +0 -103
  86. package/src/dev/ui/shared.ts +0 -60
  87. package/src/errors.ts +0 -69
  88. package/src/index.ts +0 -41
  89. package/src/renderers/HtmlRenderer.ts +0 -41
  90. package/src/renderers/MjmlRenderer.ts +0 -73
  91. package/src/renderers/ReactMjmlRenderer.ts +0 -94
  92. package/src/renderers/ReactRenderer.ts +0 -66
  93. package/src/renderers/TemplateRenderer.ts +0 -84
  94. package/src/renderers/VueMjmlRenderer.ts +0 -99
  95. package/src/renderers/VueRenderer.ts +0 -71
  96. package/src/renderers/mjml-templates.ts +0 -50
  97. package/src/transports/BaseTransport.ts +0 -148
  98. package/src/transports/LogTransport.ts +0 -55
  99. package/src/transports/MemoryTransport.ts +0 -55
  100. package/src/transports/SesTransport.ts +0 -129
  101. package/src/transports/SmtpTransport.ts +0 -184
  102. package/src/transports/Transport.ts +0 -45
  103. package/src/types.ts +0 -309
  104. package/src/webhooks/SendGridWebhookDriver.ts +0 -80
  105. package/src/webhooks/SesWebhookDriver.ts +0 -44
  106. package/tests/DevMailbox.test.ts +0 -54
  107. package/tests/FileMailboxStorage.test.ts +0 -56
  108. package/tests/MjmlLayout.test.ts +0 -28
  109. package/tests/MjmlRenderer.test.ts +0 -53
  110. package/tests/OrbitSignalWebhook.test.ts +0 -56
  111. package/tests/ReactMjmlRenderer.test.ts +0 -33
  112. package/tests/SendGridWebhookDriver.test.ts +0 -69
  113. package/tests/SesWebhookDriver.test.ts +0 -46
  114. package/tests/VueMjmlRenderer.test.ts +0 -35
  115. package/tests/dev-server.test.ts +0 -66
  116. package/tests/log-transport.test.ts +0 -21
  117. package/tests/mailable-extra.test.ts +0 -68
  118. package/tests/mailable.test.ts +0 -77
  119. package/tests/orbit-signal.test.ts +0 -43
  120. package/tests/renderers.test.ts +0 -58
  121. package/tests/template-renderer.test.ts +0 -24
  122. package/tests/transports.test.ts +0 -52
  123. package/tests/ui.test.ts +0 -37
  124. package/tsconfig.json +0 -14
package/dist/index.d.mts DELETED
@@ -1,2115 +0,0 @@
1
- import { Queueable } from '@gravito/stream';
2
- export { Queueable } from '@gravito/stream';
3
- import { GravitoContext, GravitoOrbit, PlanetCore } from '@gravito/core';
4
-
5
- /**
6
- * Interface for email transport mechanisms.
7
- *
8
- * Transports are responsible for the final delivery of an email message to its destination,
9
- * whether it's a real SMTP server, a cloud service like AWS SES, or a local log for development.
10
- * This abstraction allows the core mail service to remain agnostic of the delivery method.
11
- *
12
- * @example
13
- * ```typescript
14
- * class CustomTransport implements Transport {
15
- * async send(message: Message): Promise<void> {
16
- * // Implementation logic to deliver the message
17
- * console.log(`Sending email to ${message.to[0].address}`);
18
- * }
19
- * }
20
- * ```
21
- *
22
- * @public
23
- */
24
- interface Transport {
25
- /**
26
- * Send the given message using the underlying transport mechanism.
27
- *
28
- * This method handles the actual communication with the delivery service.
29
- * Implementations should handle connection management and protocol-specific logic.
30
- *
31
- * @param message - The finalized message object containing recipients, subject, and content.
32
- * @returns A promise that resolves when the message has been successfully handed off to the transport.
33
- * @throws {MailTransportError} If the delivery fails after all internal retry attempts.
34
- *
35
- * @example
36
- * ```typescript
37
- * const transport: Transport = new LogTransport();
38
- * await transport.send({
39
- * from: { address: 'sender@example.com' },
40
- * to: [{ address: 'receiver@example.com' }],
41
- * subject: 'Hello',
42
- * html: '<p>World</p>'
43
- * });
44
- * ```
45
- */
46
- send(message: Message): Promise<void>;
47
- }
48
-
49
- /**
50
- * Interface for Webhook Drivers.
51
- */
52
- interface WebhookDriver {
53
- handle(c: GravitoContext): Promise<{
54
- event: string;
55
- payload: any;
56
- }[] | null>;
57
- }
58
-
59
- /**
60
- * Representation of an email address with optional display name.
61
- *
62
- * Defines the structure for email addresses used throughout the mail system.
63
- * Supports both simple string addresses and formatted addresses with display names.
64
- *
65
- * @example
66
- * ```typescript
67
- * // Simple address
68
- * const addr1: Address = { address: 'user@example.com' }
69
- *
70
- * // Address with display name
71
- * const addr2: Address = {
72
- * name: 'John Doe',
73
- * address: 'john@example.com'
74
- * }
75
- * ```
76
- *
77
- * @see {@link Envelope} For the email envelope structure
78
- * @see {@link Message} For the complete message structure
79
- *
80
- * @public
81
- * @since 3.0.0
82
- */
83
- interface Address {
84
- /** The display name of the recipient/sender, e.g., "John Doe". */
85
- name?: string;
86
- /** The actual email address string. */
87
- address: string;
88
- }
89
- /**
90
- * Configuration for an email attachment.
91
- *
92
- * Defines file attachments for email messages. Supports both regular attachments
93
- * and inline attachments (e.g., embedded images referenced via Content-ID).
94
- *
95
- * @example
96
- * ```typescript
97
- * // Regular file attachment
98
- * const attachment: Attachment = {
99
- * filename: 'document.pdf',
100
- * content: Buffer.from('...'),
101
- * contentType: 'application/pdf'
102
- * }
103
- *
104
- * // Inline image attachment
105
- * const inlineImage: Attachment = {
106
- * filename: 'logo.png',
107
- * content: Buffer.from('...'),
108
- * contentType: 'image/png',
109
- * cid: 'logo@example.com' // Reference in HTML: <img src="cid:logo@example.com">
110
- * }
111
- * ```
112
- *
113
- * @see {@link Envelope} For adding attachments to emails
114
- *
115
- * @public
116
- * @since 3.0.0
117
- */
118
- interface Attachment {
119
- /** The filename of the attachment. */
120
- filename: string;
121
- /** The content of the attachment as a string or Buffer. */
122
- content: string | Buffer;
123
- /** Optional MIME type of the content. */
124
- contentType?: string;
125
- /** Optional Content-ID for referencing within HTML content (inline images). */
126
- cid?: string;
127
- /** Optional content encoding. */
128
- encoding?: string;
129
- }
130
- /**
131
- * The envelope containing metadata for an email message.
132
- *
133
- * Used during the construction phase of a Mailable. All fields are optional
134
- * at this stage and will be validated when converting to a Message.
135
- *
136
- * @example
137
- * ```typescript
138
- * const envelope: Envelope = {
139
- * from: { name: 'App', address: 'noreply@app.com' },
140
- * to: [{ address: 'user@example.com' }],
141
- * subject: 'Welcome!',
142
- * priority: 'high',
143
- * replyTo: { address: 'support@app.com' }
144
- * }
145
- * ```
146
- *
147
- * @see {@link Mailable} For building envelopes fluently
148
- * @see {@link Message} For the validated, finalized message structure
149
- *
150
- * @public
151
- * @since 3.0.0
152
- */
153
- interface Envelope {
154
- /** The sender's address. */
155
- from?: Address | undefined;
156
- /** Primary recipients. */
157
- to?: Address[] | undefined;
158
- /** Carbon copy recipients. */
159
- cc?: Address[] | undefined;
160
- /** Blind carbon copy recipients. */
161
- bcc?: Address[] | undefined;
162
- /** Reply-to address. */
163
- replyTo?: Address | undefined;
164
- /** Email subject line. */
165
- subject?: string | undefined;
166
- /** Importance level of the email. */
167
- priority?: 'high' | 'normal' | 'low' | undefined;
168
- /** List of file attachments. */
169
- attachments?: Attachment[] | undefined;
170
- }
171
- /**
172
- * A fully finalized email message ready to be sent by a transport.
173
- *
174
- * Requires mandatory fields that were optional in the Envelope.
175
- * This structure is passed to Transport implementations for actual delivery.
176
- *
177
- * @example
178
- * ```typescript
179
- * const message: Message = {
180
- * from: { name: 'App', address: 'noreply@app.com' },
181
- * to: [{ address: 'user@example.com' }],
182
- * subject: 'Welcome to our service',
183
- * html: '<h1>Welcome!</h1><p>Thanks for joining.</p>',
184
- * text: 'Welcome! Thanks for joining.',
185
- * priority: 'normal',
186
- * headers: { 'X-Custom-Header': 'value' }
187
- * }
188
- * ```
189
- *
190
- * @see {@link Envelope} For the construction phase structure
191
- * @see {@link Transport} For implementations that send messages
192
- *
193
- * @public
194
- * @since 3.0.0
195
- */
196
- interface Message extends Envelope {
197
- /** The mandatory sender's address. */
198
- from: Address;
199
- /** At least one recipient is required. */
200
- to: Address[];
201
- /** Mandatory subject. */
202
- subject: string;
203
- /** The rendered HTML body content. */
204
- html: string;
205
- /** Optional rendered plain text body content. */
206
- text?: string;
207
- /** Custom SMTP headers. */
208
- headers?: Record<string, string>;
209
- }
210
- /**
211
- * Global configuration options for OrbitSignal and Mailable instances.
212
- *
213
- * Configures the mail service behavior, transport mechanism, development tools,
214
- * and internationalization support.
215
- *
216
- * @example
217
- * ```typescript
218
- * import { OrbitSignal, SmtpTransport } from '@gravito/signal'
219
- *
220
- * const config: MailConfig = {
221
- * from: { name: 'My App', address: 'noreply@myapp.com' },
222
- * transport: new SmtpTransport({
223
- * host: 'smtp.mailtrap.io',
224
- * port: 2525,
225
- * auth: { user: 'user', pass: 'pass' }
226
- * }),
227
- * devMode: process.env.NODE_ENV === 'development',
228
- * viewsDir: './src/emails',
229
- * devUiPrefix: '/__mail',
230
- * translator: (key, replace, locale) => i18n.t(key, { ...replace, locale })
231
- * }
232
- *
233
- * const mail = new OrbitSignal(config)
234
- * ```
235
- *
236
- * @see {@link OrbitSignal} For the mail service implementation
237
- * @see {@link Transport} For available transport options
238
- *
239
- * @public
240
- * @since 3.0.0
241
- */
242
- interface MailConfig {
243
- /**
244
- * Default sender address used if not specified in the Mailable.
245
- *
246
- * @example
247
- * ```typescript
248
- * from: { name: 'My App', address: 'noreply@myapp.com' }
249
- * ```
250
- */
251
- from?: Address;
252
- /**
253
- * The transport mechanism used to send emails (e.g., SMTP, SES, Log).
254
- *
255
- * @example
256
- * ```typescript
257
- * import { SmtpTransport } from '@gravito/signal'
258
- * transport: new SmtpTransport({ host: 'smtp.example.com', port: 587 })
259
- * ```
260
- */
261
- transport?: Transport;
262
- /**
263
- * Enable development mode.
264
- * When true, emails are intercepted by the DevMailbox instead of being sent.
265
- *
266
- * @default false
267
- * @example
268
- * ```typescript
269
- * devMode: process.env.NODE_ENV === 'development'
270
- * ```
271
- */
272
- devMode?: boolean | undefined;
273
- /**
274
- * Directory where email templates are located for use with OrbitPrism.
275
- *
276
- * @default "src/emails"
277
- * @example
278
- * ```typescript
279
- * viewsDir: './resources/views/emails'
280
- * ```
281
- */
282
- viewsDir?: string | undefined;
283
- /**
284
- * URL prefix for the Mail Dev UI.
285
- *
286
- * @default "/__mail"
287
- * @example
288
- * ```typescript
289
- * devUiPrefix: '/dev/mailbox'
290
- * ```
291
- */
292
- devUiPrefix?: string | undefined;
293
- /**
294
- * Whether to allow access to the Mail Dev UI in production environments.
295
- *
296
- * @default false
297
- * @example
298
- * ```typescript
299
- * devUiAllowInProduction: process.env.ALLOW_MAIL_UI === 'true'
300
- * ```
301
- */
302
- devUiAllowInProduction?: boolean | undefined;
303
- /**
304
- * Authorization gate for the Mail Dev UI.
305
- * Should return true to allow access to the UI.
306
- *
307
- * @example
308
- * ```typescript
309
- * devUiGate: async (ctx) => {
310
- * const user = await ctx.get('auth').user()
311
- * return user?.role === 'admin'
312
- * }
313
- * ```
314
- */
315
- devUiGate?: ((ctx: GravitoContext) => boolean | Promise<boolean>) | undefined;
316
- /**
317
- * Translation function for internationalization within emails.
318
- *
319
- * @example
320
- * ```typescript
321
- * translator: (key, replace, locale) => {
322
- * return i18n.t(key, { ...replace, locale: locale || 'en' })
323
- * }
324
- * ```
325
- */
326
- translator?: ((key: string, replace?: Record<string, unknown>, locale?: string) => string) | undefined;
327
- /**
328
- * URL prefix for Webhook endpoints.
329
- */
330
- webhookPrefix?: string | undefined;
331
- /**
332
- * Dictionary of registered webhook drivers.
333
- */
334
- webhookDrivers?: Record<string, WebhookDriver> | undefined;
335
- }
336
-
337
- /**
338
- * Interface for DevMailbox storage engines.
339
- */
340
- interface MailboxStorage {
341
- /** Retrieve all entries. */
342
- all(): Promise<MailboxEntry[]>;
343
- /** Add a single entry. */
344
- push(entry: MailboxEntry): Promise<void>;
345
- /** Trim entries to a specific count. */
346
- trim(max: number): Promise<void>;
347
- clear(): Promise<void>;
348
- delete?(id: string): Promise<boolean>;
349
- }
350
-
351
- /**
352
- * Entry structure for messages stored in DevMailbox.
353
- */
354
- interface MailboxEntry {
355
- /** Unique identifier for the entry. */
356
- id: string;
357
- /** The email envelope metadata. */
358
- envelope: any;
359
- /** The rendered HTML content. */
360
- html: string;
361
- /** Optional plain text content. */
362
- text?: string;
363
- /** Timestamp when the message was captured. */
364
- sentAt: Date;
365
- }
366
- /**
367
- * Capture and store emails during development for preview and testing.
368
- *
369
- * Supports different storage engines (Memory, FileSystem) and implements
370
- * capacity limits via a Ring Buffer strategy.
371
- *
372
- * @example
373
- * ```typescript
374
- * // Default memory mailbox
375
- * const mailbox = new DevMailbox()
376
- *
377
- * // Persistent file mailbox
378
- * const storage = new FileMailboxStorage('./storage/mail')
379
- * const persistentMailbox = new DevMailbox(100, storage)
380
- * ```
381
- *
382
- * @since 3.0.0
383
- * @public
384
- */
385
- declare class DevMailbox {
386
- private storage;
387
- private _maxEntries;
388
- /**
389
- * Creates an instance of DevMailbox.
390
- *
391
- * @param maxEntries - Maximum number of emails to store (default: 50)
392
- * @param storage - Optional custom storage engine (defaults to Memory)
393
- */
394
- constructor(maxEntries?: number, storage?: MailboxStorage);
395
- /**
396
- * Adds a new message to the mailbox.
397
- *
398
- * If the mailbox exceeds the maximum capacity, the oldest messages are removed.
399
- */
400
- add(message: Message): Promise<MailboxEntry>;
401
- /**
402
- * Sets the maximum number of emails to store.
403
- *
404
- * If the current mailbox exceeds the new capacity, the oldest messages are removed.
405
- */
406
- setMaxEntries(count: number): Promise<void>;
407
- /**
408
- * Returns the maximum capacity of the mailbox.
409
- */
410
- get maxEntries(): number;
411
- /**
412
- * Lists all messages in the mailbox.
413
- */
414
- list(): Promise<MailboxEntry[]>;
415
- /**
416
- * Retrieves a specific message by ID.
417
- */
418
- get(id: string): Promise<MailboxEntry | undefined>;
419
- /**
420
- * Deletes a specific message by ID.
421
- */
422
- delete(id: string): Promise<boolean>;
423
- /**
424
- * Clears all messages from the mailbox.
425
- */
426
- clear(): Promise<void>;
427
- }
428
-
429
- /**
430
- * Mail transport error codes.
431
- *
432
- * Categorizes common failure modes in the mail delivery process to allow
433
- * for programmatic handling (e.g., retries on rate limits).
434
- *
435
- * @public
436
- * @since 3.1.0
437
- */
438
- declare enum MailErrorCode {
439
- /** Connection to mail server failed */
440
- CONNECTION_FAILED = "CONNECTION_FAILED",
441
- /** Authentication with mail server failed */
442
- AUTH_FAILED = "AUTH_FAILED",
443
- /** One or more recipients were rejected by the server */
444
- RECIPIENT_REJECTED = "RECIPIENT_REJECTED",
445
- /** The message was rejected by the server */
446
- MESSAGE_REJECTED = "MESSAGE_REJECTED",
447
- /** Rate limit exceeded */
448
- RATE_LIMIT = "RATE_LIMIT",
449
- /** Unknown or unclassified error */
450
- UNKNOWN = "UNKNOWN"
451
- }
452
- /**
453
- * Error class for mail transport failures.
454
- *
455
- * Provides structured error information for mail sending failures,
456
- * including error codes and original cause tracking for debugging.
457
- *
458
- * @example
459
- * ```typescript
460
- * throw new MailTransportError(
461
- * 'Failed to connect to SMTP server',
462
- * MailErrorCode.CONNECTION_FAILED,
463
- * originalError
464
- * )
465
- * ```
466
- *
467
- * @public
468
- * @since 3.1.0
469
- */
470
- declare class MailTransportError extends Error {
471
- readonly code: MailErrorCode;
472
- readonly cause?: Error | undefined;
473
- /**
474
- * Create a new mail transport error.
475
- *
476
- * @param message - Human-readable error message
477
- * @param code - Categorized error code
478
- * @param cause - Original error that caused this failure
479
- *
480
- * @example
481
- * ```typescript
482
- * const error = new MailTransportError('Auth failed', MailErrorCode.AUTH_FAILED);
483
- * ```
484
- */
485
- constructor(message: string, code: MailErrorCode, cause?: Error | undefined);
486
- }
487
-
488
- /**
489
- * Result of a content rendering operation.
490
- *
491
- * This interface defines the structure of the output produced by any renderer.
492
- * It ensures consistency across different rendering strategies (HTML, React, Vue, etc.),
493
- * providing both the final HTML for the email body and an optional plain text version
494
- * for clients that do not support HTML.
495
- *
496
- * @example
497
- * ```typescript
498
- * const result: RenderResult = {
499
- * html: '<html><body><h1>Hello</h1></body></html>',
500
- * text: 'Hello'
501
- * };
502
- * ```
503
- *
504
- * @public
505
- * @since 3.0.0
506
- */
507
- interface RenderResult {
508
- /**
509
- * The rendered HTML string.
510
- *
511
- * This is the primary content used for the email body.
512
- */
513
- html: string;
514
- /**
515
- * Optional rendered plain text string.
516
- *
517
- * Used as a fallback for email clients that cannot display HTML or for accessibility.
518
- */
519
- text?: string;
520
- }
521
- /**
522
- * Interface for email content renderers.
523
- *
524
- * Renderers are responsible for transforming various input formats (raw HTML,
525
- * templates, or UI components) into a standardized {@link RenderResult}.
526
- * This abstraction allows the mail system to support multiple view engines
527
- * and frameworks interchangeably.
528
- *
529
- * @example
530
- * ```typescript
531
- * class MyRenderer implements Renderer {
532
- * async render(data: Record<string, unknown>): Promise<RenderResult> {
533
- * return { html: `<div>${data.name}</div>`, text: String(data.name) };
534
- * }
535
- * }
536
- * ```
537
- *
538
- * @public
539
- * @since 3.0.0
540
- */
541
- interface Renderer {
542
- /**
543
- * Render the content into HTML and optionally plain text.
544
- *
545
- * This method performs the actual transformation of the source content
546
- * using the provided data context.
547
- *
548
- * @param data - The data context for rendering.
549
- * @returns A promise resolving to the rendered content.
550
- * @throws {Error} If rendering fails due to syntax errors or missing dependencies.
551
- */
552
- render(data: Record<string, unknown>): Promise<RenderResult>;
553
- }
554
-
555
- type ComponentType = any;
556
- /**
557
- * Base class for all mailable messages.
558
- *
559
- * @description
560
- * Mailable provides a fluent API to build email envelopes and render content
561
- * using multiple engines: HTML, Prism templates, React, and Vue components.
562
- *
563
- * @architecture
564
- * ```
565
- * Mailable
566
- * ├── Envelope (from, to, subject, cc, bcc, attachments)
567
- * ├── Renderer (HtmlRenderer | TemplateRenderer | ReactRenderer | VueRenderer)
568
- * └── Queueable (queue support interface)
569
- * ```
570
- *
571
- * @lifecycle
572
- * 1. Create Mailable subclass
573
- * 2. Implement build() method to configure envelope and content
574
- * 3. Call send() to send immediately, or queue() for background processing
575
- * 4. OrbitSignal calls buildEnvelope() → renderContent() → transport.send()
576
- *
577
- * @example
578
- * ```typescript
579
- * import { Mailable } from '@gravito/signal'
580
- *
581
- * class WelcomeEmail extends Mailable {
582
- * constructor(private user: User) {
583
- * super()
584
- * }
585
- *
586
- * build() {
587
- * return this
588
- * .to(this.user.email)
589
- * .subject('Welcome!')
590
- * .view('emails/welcome', { name: this.user.name })
591
- * }
592
- * }
593
- *
594
- * // Send immediately
595
- * await mail.send(new WelcomeEmail(user))
596
- *
597
- * // Queue for background processing
598
- * await new WelcomeEmail(user).onQueue('emails').queue()
599
- * ```
600
- *
601
- * @see {@link OrbitSignal} Mail service orchestrator
602
- * @see {@link Renderer} Content rendering interface
603
- * @see {@link Envelope} Email metadata structure
604
- * @see {@link Queueable} Queue integration interface
605
- *
606
- * @public
607
- * @since 3.0.0
608
- */
609
- declare abstract class Mailable implements Queueable {
610
- protected envelope: Partial<Envelope>;
611
- protected renderer?: Renderer;
612
- private rendererResolver?;
613
- protected renderData: Record<string, unknown>;
614
- protected config?: MailConfig;
615
- /**
616
- * Set the sender address for the email.
617
- *
618
- * This defines the "From" field in the email envelope. If not called, the default
619
- * sender from the mail configuration will be used.
620
- *
621
- * @param address - The email address or address object containing name and address.
622
- * @returns The current mailable instance for chaining.
623
- *
624
- * @example
625
- * ```typescript
626
- * mailable.from('admin@example.com')
627
- * mailable.from({ name: 'Support', address: 'support@example.com' })
628
- * ```
629
- */
630
- from(address: string | Address): this;
631
- /**
632
- * Set the primary recipient(s) for the email.
633
- *
634
- * Configures the "To" field. Supports single or multiple recipients in various formats.
635
- *
636
- * @param address - A single email string, an address object, or an array of either.
637
- * @returns The current mailable instance for chaining.
638
- *
639
- * @example
640
- * ```typescript
641
- * mailable.to('user@example.com')
642
- * mailable.to(['a@example.com', 'b@example.com'])
643
- * mailable.to({ name: 'John', address: 'john@example.com' })
644
- * ```
645
- */
646
- to(address: string | Address | (string | Address)[]): this;
647
- /**
648
- * Set the carbon copy (CC) recipient(s).
649
- *
650
- * Adds recipients to the "Cc" field of the email.
651
- *
652
- * @param address - A single email string, an address object, or an array of either.
653
- * @returns The current mailable instance for chaining.
654
- *
655
- * @example
656
- * ```typescript
657
- * mailable.cc('manager@example.com')
658
- * ```
659
- */
660
- cc(address: string | Address | (string | Address)[]): this;
661
- /**
662
- * Set the blind carbon copy (BCC) recipient(s).
663
- *
664
- * Adds recipients to the "Bcc" field. These recipients are hidden from others.
665
- *
666
- * @param address - A single email string, an address object, or an array of either.
667
- * @returns The current mailable instance for chaining.
668
- *
669
- * @example
670
- * ```typescript
671
- * mailable.bcc('audit@example.com')
672
- * ```
673
- */
674
- bcc(address: string | Address | (string | Address)[]): this;
675
- /**
676
- * Set the reply-to address.
677
- *
678
- * Specifies where replies to this email should be directed.
679
- *
680
- * @param address - The email address or address object for replies.
681
- * @returns The current mailable instance for chaining.
682
- *
683
- * @example
684
- * ```typescript
685
- * mailable.replyTo('no-reply@example.com')
686
- * ```
687
- */
688
- replyTo(address: string | Address): this;
689
- /**
690
- * Set the subject line for the email.
691
- *
692
- * Defines the text that appears in the recipient's inbox subject field.
693
- *
694
- * @param subject - The subject text.
695
- * @returns The current mailable instance for chaining.
696
- *
697
- * @example
698
- * ```typescript
699
- * mailable.subject('Your Order Confirmation')
700
- * ```
701
- */
702
- subject(subject: string): this;
703
- /**
704
- * Set the email priority.
705
- *
706
- * Hints to the email client how urgent this message is.
707
- *
708
- * @param level - The priority level: 'high', 'normal', or 'low'.
709
- * @returns The current mailable instance for chaining.
710
- *
711
- * @example
712
- * ```typescript
713
- * mailable.emailPriority('high')
714
- * ```
715
- */
716
- emailPriority(level: 'high' | 'normal' | 'low'): this;
717
- /**
718
- * Attach a file to the email.
719
- *
720
- * Adds a file attachment to the message. Can be called multiple times for multiple files.
721
- *
722
- * @param attachment - The attachment configuration including path, content, or filename.
723
- * @returns The current mailable instance for chaining.
724
- *
725
- * @example
726
- * ```typescript
727
- * mailable.attach({
728
- * filename: 'invoice.pdf',
729
- * path: './storage/invoices/123.pdf'
730
- * })
731
- * ```
732
- */
733
- attach(attachment: Attachment): this;
734
- /**
735
- * Set the content using a raw HTML string.
736
- *
737
- * Use this for simple emails where a full template engine is not required.
738
- *
739
- * @param content - The raw HTML content.
740
- * @returns The current mailable instance for chaining.
741
- *
742
- * @example
743
- * ```typescript
744
- * mailable.html('<h1>Hello</h1><p>Welcome to our platform.</p>')
745
- * ```
746
- */
747
- html(content: string): this;
748
- /**
749
- * Set the content using an OrbitPrism template.
750
- *
751
- * Renders a template file with the provided data. This is the recommended way
752
- * to build complex, data-driven emails.
753
- *
754
- * @param template - The template name or path relative to the configured views directory.
755
- * @param data - The data object to be injected into the template.
756
- * @returns The current mailable instance for chaining.
757
- *
758
- * @example
759
- * ```typescript
760
- * mailable.view('emails.welcome', { name: 'Alice' })
761
- * ```
762
- */
763
- view(template: string, data?: Record<string, unknown>): this;
764
- /**
765
- * Set the content using a React component.
766
- *
767
- * Leverages React's component model for email design. The renderer is loaded
768
- * dynamically to keep the core package lightweight.
769
- *
770
- * @param component - The React component class or function.
771
- * @param props - The properties to pass to the component.
772
- * @param deps - Optional React/ReactDOMServer overrides for custom environments.
773
- * @returns The current mailable instance for chaining.
774
- *
775
- * @example
776
- * ```typescript
777
- * mailable.react(WelcomeEmailComponent, { name: 'Alice' })
778
- * ```
779
- */
780
- react<P extends object>(component: ComponentType, props?: P, deps?: {
781
- createElement?: (...args: any[]) => any;
782
- renderToStaticMarkup?: (element: any) => string;
783
- }): this;
784
- /**
785
- * Set the content using a Vue component.
786
- *
787
- * Leverages Vue's component model for email design. The renderer is loaded
788
- * dynamically to keep the core package lightweight.
789
- *
790
- * @param component - The Vue component object.
791
- * @param props - The properties to pass to the component.
792
- * @param deps - Optional Vue/VueServerRenderer overrides for custom environments.
793
- * @returns The current mailable instance for chaining.
794
- *
795
- * @example
796
- * ```typescript
797
- * mailable.vue(WelcomeEmailComponent, { name: 'Alice' })
798
- * ```
799
- */
800
- vue<P extends object>(component: ComponentType, props?: P, deps?: {
801
- createSSRApp?: (...args: any[]) => any;
802
- h?: (...args: any[]) => any;
803
- renderToString?: (app: any) => Promise<string>;
804
- }): this;
805
- /**
806
- * Set the content using an MJML markup string.
807
- *
808
- * MJML ensures responsive email compatibility across various clients.
809
- *
810
- * @param content - The MJML markup string or inner content.
811
- * @param options - MJML transformation options.
812
- * @param options.layout - Optional full MJML layout string. Use '{{content}}' as placeholder.
813
- * @returns The current mailable instance for chaining.
814
- *
815
- * @example
816
- * ```typescript
817
- * mailable.mjml('<mj-text>Hello</mj-text>', {
818
- * layout: '<mjml><mj-body>{{content}}</mj-body></mjml>'
819
- * })
820
- * ```
821
- */
822
- mjml(content: string, options?: Record<string, any> & {
823
- layout?: string;
824
- }): this;
825
- /**
826
- * Set the content using a React component that outputs MJML.
827
- *
828
- * @param component - The React component.
829
- * @param props - Component properties.
830
- * @param options - MJML options.
831
- * @returns The current mailable instance for chaining.
832
- */
833
- mjmlReact<P extends object>(component: ComponentType, props?: P, options?: Record<string, any>): this;
834
- /**
835
- * Set the content using a Vue component that outputs MJML.
836
- *
837
- * @param component - The Vue component.
838
- * @param props - Component properties.
839
- * @param options - MJML options.
840
- * @returns The current mailable instance for chaining.
841
- */
842
- mjmlVue<P extends object>(component: ComponentType, props?: P, options?: Record<string, any>): this;
843
- /**
844
- * Configure the mailable's envelope and content.
845
- *
846
- * This abstract method must be implemented by subclasses to define the email's
847
- * recipients, subject, and body using the fluent API.
848
- *
849
- * @returns The current mailable instance.
850
- *
851
- * @example
852
- * ```typescript
853
- * build() {
854
- * return this.to('user@example.com').subject('Hi').html('...')
855
- * }
856
- * ```
857
- */
858
- abstract build(): this;
859
- /** The name of the queue to push this mailable to. */
860
- queueName?: string;
861
- /** The connection name for the queue. */
862
- connectionName?: string;
863
- /** Delay in seconds before the message is sent. */
864
- delaySeconds?: number;
865
- /** Priority of the message in the queue. */
866
- priority?: number | string;
867
- /**
868
- * Set the target queue for background processing.
869
- *
870
- * @param queue - The name of the queue.
871
- * @returns The current mailable instance for chaining.
872
- *
873
- * @example
874
- * ```typescript
875
- * mailable.onQueue('notifications')
876
- * ```
877
- */
878
- onQueue(queue: string): this;
879
- /**
880
- * Set the queue connection to be used.
881
- *
882
- * @param connection - The name of the connection (e.g., 'redis', 'sqs').
883
- * @returns The current mailable instance for chaining.
884
- *
885
- * @example
886
- * ```typescript
887
- * mailable.onConnection('redis')
888
- * ```
889
- */
890
- onConnection(connection: string): this;
891
- /**
892
- * Set a delay for the queued message.
893
- *
894
- * The message will remain in the queue and only be processed after the delay.
895
- *
896
- * @param seconds - The delay in seconds.
897
- * @returns The current mailable instance for chaining.
898
- *
899
- * @example
900
- * ```typescript
901
- * mailable.delay(3600) // Delay for 1 hour
902
- * ```
903
- */
904
- delay(seconds: number): this;
905
- /**
906
- * Set the priority for the queued message.
907
- *
908
- * Higher priority messages are typically processed before lower priority ones.
909
- *
910
- * @param priority - The priority value (numeric or string).
911
- * @returns The current mailable instance for chaining.
912
- *
913
- * @example
914
- * ```typescript
915
- * mailable.withPriority(10)
916
- * ```
917
- */
918
- withPriority(priority: string | number): this;
919
- /**
920
- * Push the mailable onto the configured queue.
921
- *
922
- * Automatically resolves the mail service from the Gravito container and
923
- * dispatches this mailable for background processing.
924
- *
925
- * @returns A promise that resolves when the mailable is queued.
926
- *
927
- * @example
928
- * ```typescript
929
- * await new WelcomeEmail(user).queue()
930
- * ```
931
- */
932
- queue(): Promise<void>;
933
- protected currentLocale?: string;
934
- protected translator?: (key: string, replace?: Record<string, unknown>, locale?: string) => string;
935
- /**
936
- * Set the locale for the email content.
937
- *
938
- * Used by the translator to resolve localized strings in templates or components.
939
- *
940
- * @param locale - The locale identifier (e.g., 'en-US', 'fr').
941
- * @returns The current mailable instance for chaining.
942
- *
943
- * @example
944
- * ```typescript
945
- * mailable.locale('es')
946
- * ```
947
- */
948
- locale(locale: string): this;
949
- /**
950
- * Internal: Set the translator function (called by OrbitSignal)
951
- * @internal
952
- */
953
- setTranslator(translator: (key: string, replace?: Record<string, unknown>, locale?: string) => string): void;
954
- /**
955
- * Translate a key into a localized string.
956
- *
957
- * Uses the configured translator and current locale to resolve the key.
958
- *
959
- * @param key - The translation key.
960
- * @param replace - Key-value pairs for string interpolation.
961
- * @returns The translated string, or the key itself if no translator is available.
962
- *
963
- * @example
964
- * ```typescript
965
- * const text = mailable.t('messages.welcome', { name: 'Alice' })
966
- * ```
967
- */
968
- t(key: string, replace?: Record<string, unknown>): string;
969
- /**
970
- * Compile the final email envelope.
971
- *
972
- * Merges mailable-specific settings with global configuration defaults.
973
- * This is called internally by the mail service before sending.
974
- *
975
- * @param configPromise - The mail configuration or a promise resolving to it.
976
- * @returns The fully constructed envelope.
977
- *
978
- * @example
979
- * ```typescript
980
- * const envelope = await mailable.buildEnvelope(config)
981
- * ```
982
- */
983
- buildEnvelope(configPromise: MailConfig | Promise<MailConfig>): Promise<Envelope>;
984
- /**
985
- * Render the email content to HTML and plain text.
986
- *
987
- * Executes the chosen renderer (HTML, Template, React, or Vue) with the
988
- * provided data and i18n helpers.
989
- *
990
- * @returns The rendered HTML and optional plain text content.
991
- * @throws {Error} If no renderer has been specified.
992
- *
993
- * @example
994
- * ```typescript
995
- * const { html } = await mailable.renderContent()
996
- * ```
997
- */
998
- renderContent(): Promise<{
999
- html: string;
1000
- text?: string;
1001
- }>;
1002
- private normalizeAddressArray;
1003
- }
1004
-
1005
- /**
1006
- * Mail event types.
1007
- *
1008
- * Defines the available lifecycle hooks for the mail service.
1009
- *
1010
- * @public
1011
- * @since 3.1.0
1012
- */
1013
- type MailEventType = 'beforeSend' | 'afterSend' | 'sendFailed' | 'beforeRender' | 'afterRender' | 'webhookReceived';
1014
- /**
1015
- * Mail lifecycle event.
1016
- *
1017
- * Emitted at key points during email sending lifecycle.
1018
- * Used for logging, analytics, or custom processing.
1019
- *
1020
- * @example
1021
- * ```typescript
1022
- * mail.on('afterSend', async (event) => {
1023
- * console.log('Email sent to:', event.message?.to)
1024
- * })
1025
- * ```
1026
- *
1027
- * @public
1028
- * @since 3.1.0
1029
- */
1030
- interface MailEvent {
1031
- /** Type of event */
1032
- type: MailEventType;
1033
- /** Mailable instance that triggered the event */
1034
- mailable: Mailable;
1035
- /** Finalized message (available for send events) */
1036
- message?: Message;
1037
- /** Error that occurred (available for sendFailed event) */
1038
- error?: Error;
1039
- /** Timestamp when event occurred */
1040
- timestamp: Date;
1041
- /** Webhook payload (available for webhookReceived event) */
1042
- webhook?: {
1043
- driver: string;
1044
- event: string;
1045
- payload: any;
1046
- };
1047
- }
1048
- /**
1049
- * Mail event handler function.
1050
- *
1051
- * Defines the signature for functions that subscribe to mail events.
1052
- *
1053
- * @param event - The mail event object
1054
- *
1055
- * @example
1056
- * ```typescript
1057
- * const handler: MailEventHandler = (event) => {
1058
- * console.log(`Event ${event.type} triggered`);
1059
- * };
1060
- * ```
1061
- *
1062
- * @public
1063
- * @since 3.1.0
1064
- */
1065
- type MailEventHandler = (event: MailEvent) => void | Promise<void>;
1066
-
1067
- /**
1068
- * OrbitSignal - Mail service orbit for Gravito framework.
1069
- *
1070
- * @description
1071
- * A production-ready email service providing multi-transport support, automatic retry,
1072
- * event-driven lifecycle hooks, and development tooling. Integrates seamlessly with
1073
- * Gravito's orbit system and queue infrastructure.
1074
- *
1075
- * @architecture
1076
- * ```
1077
- * OrbitSignal
1078
- * ├── Configuration (MailConfig)
1079
- * │ ├── transport: Transport (SMTP, SES, Log, Memory)
1080
- * │ ├── from: Default sender
1081
- * │ ├── devMode: Development interception
1082
- * │ └── translator: i18n support
1083
- * ├── Lifecycle Events
1084
- * │ ├── beforeRender → afterRender
1085
- * │ ├── beforeSend → afterSend
1086
- * │ └── sendFailed (on error)
1087
- * ├── Transport Layer
1088
- * │ ├── BaseTransport (retry, backoff)
1089
- * │ ├── SmtpTransport (connection pooling)
1090
- * │ ├── SesTransport (AWS SES)
1091
- * │ ├── LogTransport (console output)
1092
- * │ └── MemoryTransport (dev mode)
1093
- * └── Dev Tools
1094
- * ├── DevMailbox (in-memory storage)
1095
- * └── DevServer (preview UI at /__mail)
1096
- * ```
1097
- *
1098
- * @example
1099
- * **Basic SMTP Configuration**
1100
- * ```typescript
1101
- * import { OrbitSignal, SmtpTransport } from '@gravito/signal'
1102
- *
1103
- * const mail = new OrbitSignal({
1104
- * transport: new SmtpTransport({
1105
- * host: 'smtp.mailtrap.io',
1106
- * port: 2525,
1107
- * auth: { user: 'username', pass: 'password' }
1108
- * }),
1109
- * from: { name: 'My App', address: 'noreply@myapp.com' }
1110
- * })
1111
- *
1112
- * mail.install(core)
1113
- * ```
1114
- *
1115
- * @example
1116
- * **AWS SES with Retry Configuration**
1117
- * ```typescript
1118
- * import { OrbitSignal, SesTransport } from '@gravito/signal'
1119
- *
1120
- * const mail = new OrbitSignal({
1121
- * transport: new SesTransport({
1122
- * region: 'us-east-1',
1123
- * retries: 3,
1124
- * retryDelay: 1000,
1125
- * retryMultiplier: 2
1126
- * }),
1127
- * from: { name: 'Production App', address: 'noreply@example.com' }
1128
- * })
1129
- * ```
1130
- *
1131
- * @example
1132
- * **Development Mode with Preview UI**
1133
- * ```typescript
1134
- * const mail = new OrbitSignal({
1135
- * devMode: process.env.NODE_ENV === 'development',
1136
- * devUiPrefix: '/__mail',
1137
- * from: { name: 'Dev App', address: 'dev@localhost' }
1138
- * })
1139
- *
1140
- * // All emails intercepted to memory, view at http://localhost:3000/__mail
1141
- * ```
1142
- *
1143
- * @example
1144
- * **Event-Driven Analytics & Error Handling**
1145
- * ```typescript
1146
- * const mail = new OrbitSignal({ ... })
1147
- *
1148
- * // Track successful sends
1149
- * mail.on('afterSend', async (event) => {
1150
- * await analytics.track('email_sent', {
1151
- * to: event.message?.to,
1152
- * subject: event.message?.subject,
1153
- * timestamp: event.timestamp
1154
- * })
1155
- * })
1156
- *
1157
- * // Log failures for monitoring
1158
- * mail.on('sendFailed', async (event) => {
1159
- * logger.error('Email send failed', {
1160
- * error: event.error?.message,
1161
- * mailable: event.mailable.constructor.name
1162
- * })
1163
- * await sentry.captureException(event.error)
1164
- * })
1165
- * ```
1166
- *
1167
- * @example
1168
- * **SMTP with Connection Pooling**
1169
- * ```typescript
1170
- * const mail = new OrbitSignal({
1171
- * transport: new SmtpTransport({
1172
- * host: 'smtp.gmail.com',
1173
- * port: 465,
1174
- * secure: true,
1175
- * auth: { user: 'user@gmail.com', pass: 'app-password' },
1176
- * poolSize: 5,
1177
- * maxIdleTime: 30000
1178
- * })
1179
- * })
1180
- *
1181
- * // Graceful shutdown
1182
- * process.on('SIGTERM', async () => {
1183
- * await mail.config.transport?.close?.()
1184
- * })
1185
- * ```
1186
- *
1187
- * @example
1188
- * **Usage in Route Handlers**
1189
- * ```typescript
1190
- * // Injected automatically into GravitoContext
1191
- * app.post('/register', async (c) => {
1192
- * const user = await createUser(c.req.json())
1193
- *
1194
- * await c.get('mail').send(new WelcomeEmail(user))
1195
- *
1196
- * return c.json({ success: true })
1197
- * })
1198
- * ```
1199
- *
1200
- * @example
1201
- * **Queue Integration for Background Processing**
1202
- * ```typescript
1203
- * // Requires @gravito/stream
1204
- * const email = new WelcomeEmail(user)
1205
- * .onQueue('emails')
1206
- * .delay(60)
1207
- *
1208
- * await email.queue()
1209
- * ```
1210
- *
1211
- * @example
1212
- * **Error Handling Best Practices**
1213
- * ```typescript
1214
- * try {
1215
- * await mail.send(new InvoiceEmail(order))
1216
- * } catch (error) {
1217
- * if (error instanceof MailTransportError) {
1218
- * switch (error.code) {
1219
- * case MailErrorCode.RATE_LIMIT:
1220
- * await queue.pushDelayed(email, 300)
1221
- * break
1222
- * case MailErrorCode.RECIPIENT_REJECTED:
1223
- * await markUserEmailInvalid(user.id)
1224
- * break
1225
- * default:
1226
- * throw error
1227
- * }
1228
- * }
1229
- * }
1230
- * ```
1231
- *
1232
- * @see {@link Mailable} Base class for email definitions
1233
- * @see {@link TypedMailable} Strongly-typed mailable with generic data
1234
- * @see {@link Transport} Transport interface
1235
- * @see {@link BaseTransport} Retry-enabled base transport
1236
- * @see {@link MailConfig} Configuration interface
1237
- * @see {@link MailEvent} Event types
1238
- * @see {@link MailTransportError} Error handling
1239
- *
1240
- * @since 3.0.0
1241
- * @public
1242
- */
1243
- declare class OrbitSignal implements GravitoOrbit {
1244
- private config;
1245
- private devMailbox?;
1246
- private core?;
1247
- private eventHandlers;
1248
- constructor(config?: MailConfig);
1249
- /**
1250
- * Install the orbit into PlanetCore.
1251
- *
1252
- * Registers the mail service in the IoC container and sets up development
1253
- * tools if enabled. It also injects the service into the GravitoContext
1254
- * for easy access in route handlers.
1255
- *
1256
- * @param core - The PlanetCore instance to install into
1257
- *
1258
- * @example
1259
- * ```typescript
1260
- * const mail = new OrbitSignal(config);
1261
- * mail.install(core);
1262
- * ```
1263
- */
1264
- install(core: PlanetCore): void;
1265
- /**
1266
- * Internal: Handle processed webhook.
1267
- */
1268
- private handleWebhook;
1269
- /**
1270
- * Send a mailable instance immediately.
1271
- *
1272
- * Orchestrates the full email sending lifecycle: building the envelope,
1273
- * rendering content, emitting events, and delivering via the configured transport.
1274
- *
1275
- * @param mailable - The email definition to send
1276
- * @throws {Error} If mandatory fields (from, to) are missing or transport fails
1277
- *
1278
- * @example
1279
- * ```typescript
1280
- * await mail.send(new WelcomeEmail(user));
1281
- * ```
1282
- */
1283
- send(mailable: Mailable): Promise<void>;
1284
- /**
1285
- * Queue a mailable instance for background processing.
1286
- *
1287
- * Attempts to use the 'queue' service (OrbitStream) if available in the
1288
- * container. Falls back to immediate sending if no queue service is found.
1289
- *
1290
- * @param mailable - The email definition to queue
1291
- *
1292
- * @example
1293
- * ```typescript
1294
- * await mail.queue(new WelcomeEmail(user));
1295
- * ```
1296
- */
1297
- queue(mailable: Mailable): Promise<void>;
1298
- /**
1299
- * Register an event handler.
1300
- *
1301
- * @description
1302
- * Subscribe to mail lifecycle events for logging, analytics, or custom processing.
1303
- *
1304
- * @param event - The event type to listen for
1305
- * @param handler - The handler function to execute
1306
- * @returns This instance for method chaining
1307
- *
1308
- * @example
1309
- * ```typescript
1310
- * mail.on('afterSend', async (event) => {
1311
- * await analytics.track('email_sent', {
1312
- * to: event.message?.to,
1313
- * subject: event.message?.subject
1314
- * })
1315
- * })
1316
- * ```
1317
- *
1318
- * @public
1319
- * @since 3.1.0
1320
- */
1321
- on(event: MailEventType, handler: MailEventHandler): this;
1322
- private emit;
1323
- }
1324
- declare module '@gravito/core' {
1325
- interface GravitoVariables {
1326
- /** Mail service for sending emails */
1327
- mail?: OrbitSignal;
1328
- }
1329
- }
1330
-
1331
- /**
1332
- * Renderer for plain HTML content.
1333
- *
1334
- * The simplest renderer - accepts raw HTML strings and automatically generates
1335
- * a plain text version by stripping HTML tags. Ideal for pre-rendered HTML or
1336
- * when using external HTML generation libraries.
1337
- *
1338
- * @example
1339
- * ```typescript
1340
- * const renderer = new HtmlRenderer('<h1>Hello</h1>');
1341
- * const result = await renderer.render();
1342
- * // result.html: '<h1>Hello</h1>'
1343
- * // result.text: 'Hello'
1344
- * ```
1345
- *
1346
- * @public
1347
- * @since 3.0.0
1348
- */
1349
- declare class HtmlRenderer implements Renderer {
1350
- private content;
1351
- /**
1352
- * Creates an instance of HtmlRenderer.
1353
- *
1354
- * @param content - The raw HTML string to be rendered.
1355
- */
1356
- constructor(content: string);
1357
- /**
1358
- * Returns the original HTML and a stripped plain text version.
1359
- *
1360
- * @returns A promise resolving to the rendered content.
1361
- */
1362
- render(): Promise<RenderResult>;
1363
- }
1364
-
1365
- /**
1366
- * Renderer for MJML-based emails.
1367
- *
1368
- * MJML is a markup language designed to reduce the pain of coding a responsive email.
1369
- * This renderer lazily loads the `mjml` package to keep the core lightweight.
1370
- *
1371
- * @example
1372
- * ```typescript
1373
- * const renderer = new MjmlRenderer('<mjml><mj-body>...</mj-body></mjml>');
1374
- * const result = await renderer.render();
1375
- * ```
1376
- *
1377
- * @public
1378
- * @since 1.1.0
1379
- */
1380
- declare class MjmlRenderer implements Renderer {
1381
- private content;
1382
- private options;
1383
- private deps;
1384
- /**
1385
- * Creates an instance of MjmlRenderer.
1386
- *
1387
- * @param content - The MJML markup string to be rendered.
1388
- * @param options - Optional MJML transformation options.
1389
- * @param deps - Optional dependency injection for testing.
1390
- */
1391
- constructor(content: string, options?: Record<string, any>, deps?: {
1392
- mjml2html?: (mjml: string, options?: any) => any;
1393
- });
1394
- /**
1395
- * Renders the MJML content to static HTML.
1396
- *
1397
- * This method performs a dynamic import of `mjml` to ensure it's only
1398
- * loaded if this renderer is actually used.
1399
- *
1400
- * @returns A promise resolving to the rendered content.
1401
- * @throws {Error} If MJML dependencies cannot be loaded or rendering fails.
1402
- */
1403
- render(): Promise<RenderResult>;
1404
- }
1405
-
1406
- /**
1407
- * Base layout for MJML emails.
1408
- * Includes common head styles and responsive settings.
1409
- *
1410
- * Placeholder: {{content}}
1411
- */
1412
- declare const baseLayout: string;
1413
- /**
1414
- * A simple transactional component layout.
1415
- */
1416
- declare const transactionLayout = "\n<mj-section background-color=\"#ffffff\" padding-top=\"0px\">\n <mj-column>\n {{content}}\n </mj-column>\n</mj-section>\n";
1417
-
1418
- /**
1419
- * Renderer for React component-based MJML emails.
1420
- *
1421
- * Renders React components to MJML string using SSR, then converts
1422
- * the MJML to responsive HTML.
1423
- *
1424
- * @typeParam P - Props type for the React component.
1425
- * @public
1426
- * @since 1.1.0
1427
- */
1428
- declare class ReactMjmlRenderer<P extends object = object> implements Renderer {
1429
- private component;
1430
- private props?;
1431
- private options;
1432
- private deps;
1433
- /**
1434
- * Creates an instance of ReactMjmlRenderer.
1435
- *
1436
- * @param component - The React component to render.
1437
- * @param props - Initial props for the component.
1438
- * @param options - Optional MJML transformation options.
1439
- * @param deps - Optional dependency injection for testing.
1440
- */
1441
- constructor(component: any, props?: P | undefined, options?: Record<string, any>, deps?: {
1442
- createElement?: (...args: any[]) => any;
1443
- renderToStaticMarkup?: (element: any) => string;
1444
- mjml2html?: (mjml: string, options?: any) => any;
1445
- });
1446
- /**
1447
- * Renders the React component to a static HTML string via MJML.
1448
- *
1449
- * @param data - Runtime data to be merged with initial props.
1450
- * @returns A promise resolving to the rendered content.
1451
- * @throws {Error} If MJML rendering fails.
1452
- */
1453
- render(data: Record<string, unknown>): Promise<RenderResult>;
1454
- }
1455
-
1456
- /**
1457
- * Renderer for template-based emails using Gravito Prism.
1458
- *
1459
- * Renders email templates from the filesystem using the Prism template engine.
1460
- * It uses a static cache for the template engine to avoid redundant initialization
1461
- * costs when rendering multiple emails from the same directory.
1462
- *
1463
- * @example
1464
- * ```typescript
1465
- * const renderer = new TemplateRenderer('welcome', './src/emails');
1466
- * const result = await renderer.render({ name: 'John' });
1467
- * ```
1468
- *
1469
- * @public
1470
- * @since 3.0.0
1471
- */
1472
- declare class TemplateRenderer implements Renderer {
1473
- private template;
1474
- private viewsDir;
1475
- private static engineCache;
1476
- /**
1477
- * Creates an instance of TemplateRenderer.
1478
- *
1479
- * @param templateName - The name of the template file (without extension).
1480
- * @param viewsDir - The directory containing template files. Defaults to `src/emails`.
1481
- */
1482
- constructor(templateName: string, viewsDir?: string);
1483
- /**
1484
- * Renders the template with the provided data.
1485
- *
1486
- * This method lazily loads `@gravito/prism` to ensure the core package
1487
- * remains lightweight for users who don't need template rendering.
1488
- *
1489
- * @param data - The data context for template interpolation.
1490
- * @returns A promise resolving to the rendered content.
1491
- * @throws {Error} If the template engine fails to load or rendering fails.
1492
- */
1493
- render(data: Record<string, unknown>): Promise<RenderResult>;
1494
- /**
1495
- * Clear template engine cache.
1496
- *
1497
- * Useful in development environments to force recompilation of templates
1498
- * after they have been modified on disk.
1499
- *
1500
- * @example
1501
- * ```typescript
1502
- * TemplateRenderer.clearCache();
1503
- * ```
1504
- *
1505
- * @public
1506
- * @since 3.1.0
1507
- */
1508
- static clearCache(): void;
1509
- }
1510
-
1511
- /**
1512
- * Renderer for Vue component-based MJML emails.
1513
- *
1514
- * Renders Vue 3 components to MJML string using SSR, then converts
1515
- * the MJML to responsive HTML.
1516
- *
1517
- * @typeParam P - Props type for the Vue component.
1518
- * @public
1519
- * @since 1.1.0
1520
- */
1521
- declare class VueMjmlRenderer<P extends object = object> implements Renderer {
1522
- private component;
1523
- private props?;
1524
- private options;
1525
- private deps;
1526
- /**
1527
- * Creates an instance of VueMjmlRenderer.
1528
- *
1529
- * @param component - The Vue component to render.
1530
- * @param props - Initial props for the component.
1531
- * @param options - Optional MJML transformation options.
1532
- * @param deps - Optional dependency injection for testing.
1533
- */
1534
- constructor(component: any, props?: P | undefined, options?: Record<string, any>, deps?: {
1535
- createSSRApp?: (...args: any[]) => any;
1536
- h?: (...args: any[]) => any;
1537
- renderToString?: (app: any) => Promise<string>;
1538
- mjml2html?: (mjml: string, options?: any) => any;
1539
- });
1540
- /**
1541
- * Renders the Vue component to a static HTML string via MJML.
1542
- *
1543
- * @param data - Runtime data to be merged with initial props.
1544
- * @returns A promise resolving to the rendered content.
1545
- * @throws {Error} If MJML rendering fails.
1546
- */
1547
- render(data: Record<string, unknown>): Promise<RenderResult>;
1548
- }
1549
-
1550
- /**
1551
- * Abstract base class for strongly-typed Mailable messages.
1552
- *
1553
- * @description
1554
- * TypedMailable extends the base Mailable class to provide compile-time type safety
1555
- * for email data props. This ensures that the data passed to templates, React, or Vue
1556
- * components is correctly typed and validated at build time.
1557
- *
1558
- * @typeParam TData - The shape of data required by this mailable's template/component.
1559
- * Must extend Record<string, unknown>.
1560
- *
1561
- * @example
1562
- * ```typescript
1563
- * import { TypedMailable } from '@gravito/signal'
1564
- *
1565
- * // Define the data interface
1566
- * interface WelcomeData {
1567
- * name: string
1568
- * email: string
1569
- * activationUrl: string
1570
- * }
1571
- *
1572
- * // Create strongly-typed mailable
1573
- * class WelcomeEmail extends TypedMailable<WelcomeData> {
1574
- * protected data: WelcomeData
1575
- *
1576
- * constructor(data: WelcomeData) {
1577
- * super()
1578
- * this.data = data
1579
- * }
1580
- *
1581
- * build() {
1582
- * return this
1583
- * .to(this.data.email)
1584
- * .subject('Welcome to Gravito!')
1585
- * .view('emails/welcome', this.data) // Type-safe: compiler ensures WelcomeData matches template
1586
- * }
1587
- * }
1588
- *
1589
- * // Usage - compiler enforces correct data shape
1590
- * const email = new WelcomeEmail({
1591
- * name: 'Alice',
1592
- * email: 'alice@example.com',
1593
- * activationUrl: 'https://app.com/activate?token=abc123'
1594
- * })
1595
- *
1596
- * await mail.send(email)
1597
- * ```
1598
- *
1599
- * @example
1600
- * ```typescript
1601
- * // With React components
1602
- * interface InvoiceData {
1603
- * invoiceNumber: string
1604
- * amount: number
1605
- * dueDate: Date
1606
- * items: Array<{ name: string; price: number }>
1607
- * }
1608
- *
1609
- * class InvoiceEmail extends TypedMailable<InvoiceData> {
1610
- * protected data: InvoiceData
1611
- *
1612
- * constructor(data: InvoiceData) {
1613
- * super()
1614
- * this.data = data
1615
- * }
1616
- *
1617
- * build() {
1618
- * return this
1619
- * .to('billing@example.com')
1620
- * .subject(`Invoice ${this.data.invoiceNumber}`)
1621
- * .react(InvoiceComponent, this.data) // Type-safe props
1622
- * }
1623
- * }
1624
- * ```
1625
- *
1626
- * @see {@link Mailable} Base mailable class
1627
- * @see {@link OrbitSignal} Mail service orchestrator
1628
- *
1629
- * @public
1630
- * @since 3.0.0
1631
- */
1632
- declare abstract class TypedMailable<TData extends Record<string, unknown>> extends Mailable {
1633
- /**
1634
- * The strongly-typed data for this mailable.
1635
- *
1636
- * This property holds the data that will be passed to the template or component
1637
- * during rendering. By defining it as an abstract property with the generic
1638
- * type TData, we force subclasses to provide a concrete, type-safe implementation.
1639
- *
1640
- * @protected
1641
- */
1642
- protected abstract data: TData;
1643
- }
1644
-
1645
- /**
1646
- * Transport retry configuration options.
1647
- *
1648
- * Defines the behavior of the automatic retry mechanism, including the number of attempts
1649
- * and the timing between them using exponential backoff.
1650
- *
1651
- * @example
1652
- * ```typescript
1653
- * const options: TransportOptions = {
1654
- * maxRetries: 5,
1655
- * retryDelay: 500,
1656
- * backoffMultiplier: 3
1657
- * };
1658
- * ```
1659
- *
1660
- * @public
1661
- */
1662
- interface TransportOptions {
1663
- /**
1664
- * Maximum number of retry attempts before giving up.
1665
- * Set to 0 to disable retries.
1666
- */
1667
- maxRetries?: number;
1668
- /**
1669
- * Initial delay in milliseconds before the first retry attempt.
1670
- */
1671
- retryDelay?: number;
1672
- /**
1673
- * Multiplier applied to the delay after each failed attempt.
1674
- * Used to implement exponential backoff to avoid overwhelming the service.
1675
- */
1676
- backoffMultiplier?: number;
1677
- }
1678
- /**
1679
- * Base transport class with automatic retry mechanism.
1680
- *
1681
- * This abstract class provides a robust foundation for all transport implementations by
1682
- * handling transient failures through an exponential backoff retry strategy. It ensures
1683
- * that temporary network issues or service rate limits do not immediately fail the email delivery.
1684
- *
1685
- * The retry mechanism works as follows:
1686
- * 1. Attempt to send the message via `doSend()`.
1687
- * 2. If it fails, wait for `retryDelay` milliseconds.
1688
- * 3. Increment the delay by `backoffMultiplier` for the next attempt.
1689
- * 4. Repeat until success or `maxRetries` is reached.
1690
- *
1691
- * @example
1692
- * ```typescript
1693
- * class MyTransport extends BaseTransport {
1694
- * constructor() {
1695
- * super({ maxRetries: 3, retryDelay: 1000 })
1696
- * }
1697
- *
1698
- * protected async doSend(message: Message): Promise<void> {
1699
- * // Actual implementation of the sending logic
1700
- * // If this throws, BaseTransport will catch and retry
1701
- * }
1702
- * }
1703
- * ```
1704
- *
1705
- * @public
1706
- */
1707
- declare abstract class BaseTransport implements Transport {
1708
- protected options: Required<TransportOptions>;
1709
- /**
1710
- * Initializes the transport with retry options.
1711
- *
1712
- * @param options - Configuration for the retry mechanism.
1713
- */
1714
- constructor(options?: TransportOptions);
1715
- /**
1716
- * Orchestrates the message delivery with retry logic.
1717
- *
1718
- * This method wraps the concrete `doSend` implementation in a retry loop.
1719
- * It tracks the last error encountered to provide context if all retries fail.
1720
- *
1721
- * @param message - The message to be delivered.
1722
- * @returns A promise that resolves when the message is successfully sent.
1723
- * @throws {MailTransportError} If the message cannot be sent after the maximum number of retries.
1724
- *
1725
- * @example
1726
- * ```typescript
1727
- * const transport = new SmtpTransport(config);
1728
- * try {
1729
- * await transport.send(message);
1730
- * } catch (error) {
1731
- * console.error('Failed to send email after retries', error);
1732
- * }
1733
- * ```
1734
- */
1735
- send(message: Message): Promise<void>;
1736
- /**
1737
- * Actual transport implementation to be provided by subclasses.
1738
- *
1739
- * This method should contain the protocol-specific logic for delivering the message.
1740
- * It will be automatically retried by the `send` method if it throws an error.
1741
- *
1742
- * @param message - The message to send.
1743
- * @returns A promise that resolves when the delivery is successful.
1744
- * @throws {Error} Any error encountered during delivery, which will trigger a retry.
1745
- */
1746
- protected abstract doSend(message: Message): Promise<void>;
1747
- /**
1748
- * Utility method to pause execution for a given duration.
1749
- *
1750
- * @param ms - Milliseconds to sleep.
1751
- * @returns A promise that resolves after the delay.
1752
- */
1753
- private sleep;
1754
- }
1755
-
1756
- /**
1757
- * Log transport for development and testing.
1758
- *
1759
- * This transport outputs email details directly to the console instead of performing
1760
- * actual delivery. It is essential for local development to avoid sending real emails
1761
- * while still being able to verify the content, recipients, and subject of outgoing mail.
1762
- *
1763
- * @example
1764
- * ```typescript
1765
- * import { LogTransport } from '@gravito/signal';
1766
- *
1767
- * const transport = new LogTransport();
1768
- * await transport.send({
1769
- * from: { address: 'dev@localhost' },
1770
- * to: [{ address: 'user@example.com' }],
1771
- * subject: 'Test Email',
1772
- * html: '<h1>Hello</h1>'
1773
- * });
1774
- * ```
1775
- *
1776
- * @public
1777
- */
1778
- declare class LogTransport implements Transport {
1779
- /**
1780
- * Outputs the message details to the system console.
1781
- *
1782
- * Formats the email metadata (From, To, Subject) and content size into a readable
1783
- * block in the console output.
1784
- *
1785
- * @param message - The message to log.
1786
- * @returns A promise that resolves immediately after logging.
1787
- *
1788
- * @example
1789
- * ```typescript
1790
- * const transport = new LogTransport();
1791
- * await transport.send(message);
1792
- * // Console: 📧 [OrbitSignal] Email Sent (Simulated)...
1793
- * ```
1794
- */
1795
- send(message: Message): Promise<void>;
1796
- }
1797
-
1798
- /**
1799
- * Memory transport for development mode.
1800
- *
1801
- * This transport captures outgoing emails and stores them in an in-memory mailbox.
1802
- * It is primarily used by the Gravito Dev UI to provide a live preview of emails
1803
- * during development without requiring an external mail server.
1804
- *
1805
- * @example
1806
- * ```typescript
1807
- * import { DevMailbox, MemoryTransport } from '@gravito/signal';
1808
- *
1809
- * const mailbox = new DevMailbox();
1810
- * const transport = new MemoryTransport(mailbox);
1811
- * await transport.send(message);
1812
- *
1813
- * console.log(mailbox.getAll().length); // 1
1814
- * ```
1815
- *
1816
- * @public
1817
- */
1818
- declare class MemoryTransport implements Transport {
1819
- private mailbox;
1820
- /**
1821
- * Creates a new MemoryTransport instance.
1822
- *
1823
- * @param mailbox - The in-memory storage where messages will be collected.
1824
- */
1825
- constructor(mailbox: DevMailbox);
1826
- /**
1827
- * Stores the message in the associated mailbox.
1828
- *
1829
- * The message is added to the internal list of the `DevMailbox` instance,
1830
- * making it available for retrieval by the Dev UI or test assertions.
1831
- *
1832
- * @param message - The message to store.
1833
- * @returns A promise that resolves once the message is added to the mailbox.
1834
- *
1835
- * @example
1836
- * ```typescript
1837
- * await transport.send({
1838
- * from: { address: 'dev@localhost' },
1839
- * to: [{ address: 'test@example.com' }],
1840
- * subject: 'Memory Test',
1841
- * html: '<p>Stored in memory</p>'
1842
- * });
1843
- * ```
1844
- */
1845
- send(message: Message): Promise<void>;
1846
- }
1847
-
1848
- /**
1849
- * Configuration for AWS SES email transport.
1850
- *
1851
- * Defines the AWS region and credentials required to communicate with the
1852
- * Amazon Simple Email Service API.
1853
- *
1854
- * @example
1855
- * ```typescript
1856
- * const config: SesConfig = {
1857
- * region: 'us-east-1',
1858
- * accessKeyId: 'AKIA...',
1859
- * secretAccessKey: 'wJalr...',
1860
- * maxRetries: 5
1861
- * };
1862
- * ```
1863
- *
1864
- * @public
1865
- */
1866
- interface SesConfig extends TransportOptions {
1867
- /** AWS region where the SES service is hosted (e.g., 'us-east-1'). */
1868
- region: string;
1869
- /** AWS access key ID. If omitted, the SDK will attempt to use default credential providers. */
1870
- accessKeyId?: string;
1871
- /** AWS secret access key. Required if accessKeyId is provided. */
1872
- secretAccessKey?: string;
1873
- }
1874
- /**
1875
- * AWS SES (Simple Email Service) transport with automatic retry.
1876
- *
1877
- * This transport delivers emails via the Amazon SES API. It requires the
1878
- * `@aws-sdk/client-ses` package to be installed as a dependency. It provides
1879
- * a reliable way to send high volumes of email using AWS infrastructure and
1880
- * includes automatic retry logic for transient API errors.
1881
- *
1882
- * @example
1883
- * ```typescript
1884
- * import { SesTransport } from '@gravito/signal';
1885
- *
1886
- * const transport = new SesTransport({
1887
- * region: 'us-west-2'
1888
- * });
1889
- *
1890
- * await transport.send(message);
1891
- * ```
1892
- *
1893
- * @public
1894
- */
1895
- declare class SesTransport extends BaseTransport {
1896
- private transporter;
1897
- /**
1898
- * Initializes the SES transport with the provided configuration.
1899
- *
1900
- * Configures the AWS SES client and wraps it in a nodemailer transporter
1901
- * for consistent message handling.
1902
- *
1903
- * @param config - AWS SES connection and retry configuration.
1904
- */
1905
- constructor(config: SesConfig);
1906
- /**
1907
- * Internal method to perform the actual SES delivery.
1908
- *
1909
- * Converts the generic `Message` object into a raw email format and sends it
1910
- * via the SES `SendRawEmail` API.
1911
- *
1912
- * @param message - The message to deliver.
1913
- * @returns A promise that resolves when SES accepts the message for delivery.
1914
- * @throws {Error} If the SES API returns an error or connection fails.
1915
- */
1916
- protected doSend(message: Message): Promise<void>;
1917
- /**
1918
- * Formats an Address object into a standard RFC 822 string.
1919
- *
1920
- * @param addr - The address object to format.
1921
- * @returns A string in the format "Name <email@example.com>" or just "email@example.com".
1922
- */
1923
- private formatAddress;
1924
- }
1925
-
1926
- /**
1927
- * Configuration for SMTP email transport.
1928
- *
1929
- * Defines the connection parameters, authentication, and pooling settings for
1930
- * communicating with an SMTP server.
1931
- *
1932
- * @example
1933
- * ```typescript
1934
- * const config: SmtpConfig = {
1935
- * host: 'smtp.mailtrap.io',
1936
- * port: 2525,
1937
- * auth: { user: 'username', pass: 'password' },
1938
- * poolSize: 10
1939
- * };
1940
- * ```
1941
- *
1942
- * @public
1943
- */
1944
- interface SmtpConfig extends TransportOptions {
1945
- /** SMTP server hostname or IP address. */
1946
- host: string;
1947
- /** SMTP server port (typically 25, 465, or 587). */
1948
- port: number;
1949
- /** Whether to use a secure TLS/SSL connection. Should be true for port 465. */
1950
- secure?: boolean;
1951
- /** Authentication credentials for the SMTP server. */
1952
- auth?: {
1953
- /** SMTP username. */
1954
- user: string;
1955
- /** SMTP password. */
1956
- pass: string;
1957
- };
1958
- /** TLS specific options for the connection. */
1959
- tls?: {
1960
- /** Whether to reject unauthorized certificates (useful for self-signed certs). */
1961
- rejectUnauthorized?: boolean;
1962
- /** Specific cipher suite to use for the connection. */
1963
- ciphers?: string;
1964
- };
1965
- /** Number of concurrent connections to maintain in the pool. */
1966
- poolSize?: number;
1967
- /** Maximum time in milliseconds a connection can remain idle before being closed. */
1968
- maxIdleTime?: number;
1969
- }
1970
- /**
1971
- * SMTP email transport with connection pooling and automatic retry.
1972
- *
1973
- * This transport uses the standard SMTP protocol to deliver emails. It leverages
1974
- * `nodemailer` for robust protocol implementation and includes built-in support
1975
- * for connection pooling to improve performance when sending multiple emails.
1976
- * It inherits automatic retry logic from `BaseTransport`.
1977
- *
1978
- * @example
1979
- * ```typescript
1980
- * import { SmtpTransport } from '@gravito/signal';
1981
- *
1982
- * const transport = new SmtpTransport({
1983
- * host: 'smtp.example.com',
1984
- * port: 587,
1985
- * auth: { user: 'user', pass: 'pass' }
1986
- * });
1987
- *
1988
- * await transport.send(message);
1989
- * ```
1990
- *
1991
- * @public
1992
- */
1993
- declare class SmtpTransport extends BaseTransport {
1994
- private transporter;
1995
- /**
1996
- * Initializes the SMTP transport with the provided configuration.
1997
- *
1998
- * Sets up the underlying nodemailer transporter with connection pooling enabled.
1999
- *
2000
- * @param config - SMTP connection and retry configuration.
2001
- */
2002
- constructor(config: SmtpConfig);
2003
- /**
2004
- * Internal method to perform the actual SMTP delivery.
2005
- *
2006
- * Maps the generic `Message` object to the format expected by nodemailer.
2007
- *
2008
- * @param message - The message to deliver.
2009
- * @returns A promise that resolves when the SMTP server accepts the message.
2010
- * @throws {Error} If the SMTP server rejects the message or connection fails.
2011
- */
2012
- protected doSend(message: Message): Promise<void>;
2013
- /**
2014
- * Gracefully shuts down the transport and closes all pooled connections.
2015
- *
2016
- * This should be called during application shutdown to ensure no resources are leaked.
2017
- *
2018
- * @returns A promise that resolves when all connections are closed.
2019
- *
2020
- * @example
2021
- * ```typescript
2022
- * await transport.close();
2023
- * ```
2024
- */
2025
- close(): Promise<void>;
2026
- /**
2027
- * Verifies the SMTP connection and authentication.
2028
- *
2029
- * Useful for health checks or validating configuration during startup.
2030
- *
2031
- * @returns A promise that resolves to true if the connection is valid, false otherwise.
2032
- *
2033
- * @example
2034
- * ```typescript
2035
- * const isValid = await transport.verify();
2036
- * if (!isValid) throw new Error('SMTP configuration is invalid');
2037
- * ```
2038
- */
2039
- verify(): Promise<boolean>;
2040
- /**
2041
- * Formats an Address object into a standard RFC 822 string.
2042
- *
2043
- * @param addr - The address object to format.
2044
- * @returns A string in the format "Name <email@example.com>" or just "email@example.com".
2045
- */
2046
- private formatAddress;
2047
- }
2048
-
2049
- /**
2050
- * Configuration for SendGrid Webhook Driver.
2051
- */
2052
- interface SendGridWebhookConfig {
2053
- /**
2054
- * Public key or Verification Secret for signature validation.
2055
- * If provided, all requests will be validated.
2056
- */
2057
- publicKey?: string;
2058
- }
2059
- /**
2060
- * SendGrid Webhook Driver.
2061
- *
2062
- * Handles Event Webhooks from SendGrid (delivered, bounced, opened, clicked, etc.).
2063
- *
2064
- * @see https://docs.sendgrid.com/for-developers/tracking-events/event-webhook
2065
- * @public
2066
- * @since 1.1.0
2067
- */
2068
- declare class SendGridWebhookDriver implements WebhookDriver {
2069
- private config;
2070
- constructor(config?: SendGridWebhookConfig);
2071
- /**
2072
- * Handles the SendGrid webhook request.
2073
- */
2074
- handle(c: GravitoContext): Promise<{
2075
- event: string;
2076
- payload: any;
2077
- }[] | null>;
2078
- /**
2079
- * Verifies the SendGrid webhook signature.
2080
- *
2081
- * @param payload - Raw request body string.
2082
- * @param signature - Signature from X-Twilio-Email-Event-Webhook-Signature header.
2083
- * @param timestamp - Timestamp from X-Twilio-Email-Event-Webhook-Timestamp header.
2084
- * @returns True if signature is valid.
2085
- *
2086
- * @remarks
2087
- * Real SendGrid validation uses Elliptic Curve (ECDSA).
2088
- * This is a placeholder for the logic structure.
2089
- */
2090
- private verifySignature;
2091
- }
2092
-
2093
- /**
2094
- * AWS SES Webhook Driver.
2095
- *
2096
- * Handles SES Notifications via Amazon SNS (Complaints, Bounces, Deliveries).
2097
- *
2098
- * @see https://docs.aws.amazon.com/ses/latest/dg/monitor-sending-activity-using-notifications.html
2099
- * @public
2100
- * @since 1.1.0
2101
- */
2102
- declare class SesWebhookDriver implements WebhookDriver {
2103
- /**
2104
- * Handles the AWS SES/SNS webhook request.
2105
- *
2106
- * @param c - The Gravito request context.
2107
- * @returns Array of processed events or null if ignored.
2108
- */
2109
- handle(c: GravitoContext): Promise<{
2110
- event: string;
2111
- payload: any;
2112
- }[] | null>;
2113
- }
2114
-
2115
- export { type Address, type Attachment, BaseTransport, DevMailbox, type Envelope, HtmlRenderer, LogTransport, type MailConfig, MailErrorCode, type MailEvent, type MailEventHandler, type MailEventType, MailTransportError, Mailable, type MailboxEntry, MemoryTransport, type Message, MjmlRenderer, OrbitSignal, ReactMjmlRenderer, type RenderResult, type Renderer, type SendGridWebhookConfig, SendGridWebhookDriver, SesTransport, SesWebhookDriver, SmtpTransport, TemplateRenderer, type Transport, type TransportOptions, TypedMailable, VueMjmlRenderer, baseLayout, transactionLayout };