@gravito/signal 3.0.3 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +99 -59
  3. package/README.zh-TW.md +140 -9
  4. package/build.ts +133 -0
  5. package/dist/Mailable.d.ts +453 -0
  6. package/dist/OrbitSignal.d.ts +267 -0
  7. package/dist/Queueable.d.ts +9 -0
  8. package/dist/TypedMailable.d.ts +95 -0
  9. package/dist/dev/DevMailbox.d.ts +79 -0
  10. package/dist/dev/DevServer.d.ts +39 -0
  11. package/dist/dev/storage/FileMailboxStorage.d.ts +16 -0
  12. package/dist/dev/storage/MailboxStorage.d.ts +14 -0
  13. package/dist/dev/storage/MemoryMailboxStorage.d.ts +13 -0
  14. package/dist/dev/ui/mailbox.d.ts +11 -0
  15. package/dist/dev/ui/preview.d.ts +11 -0
  16. package/dist/dev/ui/shared.d.ts +15 -0
  17. package/dist/errors.d.ts +58 -0
  18. package/dist/events.d.ts +63 -0
  19. package/dist/index.cjs +88291 -0
  20. package/dist/index.cjs.map +712 -0
  21. package/dist/index.d.ts +31 -643
  22. package/dist/index.mjs +87748 -335
  23. package/dist/index.mjs.map +710 -0
  24. package/dist/renderers/HtmlRenderer.d.ts +34 -0
  25. package/dist/renderers/MjmlRenderer.d.ts +41 -0
  26. package/dist/renderers/ReactMjmlRenderer.d.ts +38 -0
  27. package/dist/renderers/ReactRenderer.d.ts +46 -0
  28. package/dist/renderers/Renderer.d.ts +66 -0
  29. package/dist/renderers/TemplateRenderer.d.ts +55 -0
  30. package/dist/renderers/VueMjmlRenderer.d.ts +39 -0
  31. package/dist/renderers/VueRenderer.d.ts +47 -0
  32. package/dist/renderers/mjml-templates.d.ts +11 -0
  33. package/dist/transports/BaseTransport.d.ts +111 -0
  34. package/dist/transports/LogTransport.d.ts +42 -0
  35. package/dist/transports/MemoryTransport.d.ts +51 -0
  36. package/dist/transports/SesTransport.d.ts +79 -0
  37. package/dist/transports/SmtpTransport.d.ts +124 -0
  38. package/dist/transports/Transport.d.ts +44 -0
  39. package/dist/types.d.ts +294 -0
  40. package/dist/utils/html.d.ts +29 -0
  41. package/dist/webhooks/SendGridWebhookDriver.d.ts +45 -0
  42. package/dist/webhooks/SesWebhookDriver.d.ts +23 -0
  43. package/doc/ADVANCED_RENDERING.md +71 -0
  44. package/doc/DISTRIBUTED_MESSAGING.md +79 -0
  45. package/doc/OPTIMIZATION_PLAN.md +496 -0
  46. package/package.json +14 -11
  47. package/package.json.bak +75 -0
  48. package/scripts/check-coverage.ts +64 -0
  49. package/src/Mailable.ts +340 -44
  50. package/src/OrbitSignal.ts +350 -50
  51. package/src/TypedMailable.ts +96 -0
  52. package/src/dev/DevMailbox.ts +89 -33
  53. package/src/dev/DevServer.ts +14 -14
  54. package/src/dev/storage/FileMailboxStorage.ts +66 -0
  55. package/src/dev/storage/MailboxStorage.ts +15 -0
  56. package/src/dev/storage/MemoryMailboxStorage.ts +36 -0
  57. package/src/dev/ui/mailbox.ts +1 -1
  58. package/src/dev/ui/preview.ts +4 -4
  59. package/src/errors.ts +69 -0
  60. package/src/events.ts +72 -0
  61. package/src/index.ts +20 -1
  62. package/src/renderers/HtmlRenderer.ts +20 -18
  63. package/src/renderers/MjmlRenderer.ts +73 -0
  64. package/src/renderers/ReactMjmlRenderer.ts +94 -0
  65. package/src/renderers/ReactRenderer.ts +26 -21
  66. package/src/renderers/Renderer.ts +43 -3
  67. package/src/renderers/TemplateRenderer.ts +48 -15
  68. package/src/renderers/VueMjmlRenderer.ts +99 -0
  69. package/src/renderers/VueRenderer.ts +26 -21
  70. package/src/renderers/mjml-templates.ts +50 -0
  71. package/src/transports/BaseTransport.ts +148 -0
  72. package/src/transports/LogTransport.ts +28 -6
  73. package/src/transports/MemoryTransport.ts +34 -6
  74. package/src/transports/SesTransport.ts +62 -17
  75. package/src/transports/SmtpTransport.ts +123 -27
  76. package/src/transports/Transport.ts +33 -4
  77. package/src/types.ts +172 -3
  78. package/src/utils/html.ts +43 -0
  79. package/src/webhooks/SendGridWebhookDriver.ts +80 -0
  80. package/src/webhooks/SesWebhookDriver.ts +44 -0
  81. package/tests/DevMailbox.test.ts +54 -0
  82. package/tests/FileMailboxStorage.test.ts +56 -0
  83. package/tests/MjmlLayout.test.ts +28 -0
  84. package/tests/MjmlRenderer.test.ts +53 -0
  85. package/tests/OrbitSignalWebhook.test.ts +56 -0
  86. package/tests/ReactMjmlRenderer.test.ts +33 -0
  87. package/tests/SendGridWebhookDriver.test.ts +69 -0
  88. package/tests/SesWebhookDriver.test.ts +46 -0
  89. package/tests/VueMjmlRenderer.test.ts +35 -0
  90. package/tests/dev-server.test.ts +1 -1
  91. package/tests/transports.test.ts +3 -3
  92. package/tsconfig.build.json +24 -0
  93. package/tsconfig.json +8 -25
  94. package/dist/OrbitMail-2Z7ZTKYA.mjs +0 -7
  95. package/dist/OrbitMail-BGV32HWN.mjs +0 -7
  96. package/dist/OrbitMail-FUYZQSAV.mjs +0 -7
  97. package/dist/OrbitMail-NAPCRK7B.mjs +0 -7
  98. package/dist/OrbitMail-REGJ276B.mjs +0 -7
  99. package/dist/OrbitMail-TCFBJWDT.mjs +0 -7
  100. package/dist/OrbitMail-XZZW6U4N.mjs +0 -7
  101. package/dist/OrbitSignal-IPSA2CDO.mjs +0 -7
  102. package/dist/OrbitSignal-MABW4DDW.mjs +0 -7
  103. package/dist/OrbitSignal-QSW5VQ5M.mjs +0 -7
  104. package/dist/OrbitSignal-R22QHWAA.mjs +0 -7
  105. package/dist/OrbitSignal-ZKKMEC27.mjs +0 -7
  106. package/dist/ReactRenderer-24SQ4KRU.mjs +0 -27
  107. package/dist/ReactRenderer-CMCAOEPH.mjs +0 -28
  108. package/dist/ReactRenderer-KYNA4WKE.mjs +0 -28
  109. package/dist/ReactRenderer-L5INVYKT.mjs +0 -27
  110. package/dist/VueRenderer-DWTCD2RF.mjs +0 -31
  111. package/dist/VueRenderer-IIR5SYTM.mjs +0 -31
  112. package/dist/VueRenderer-S65ZARRI.mjs +0 -37129
  113. package/dist/VueRenderer-SUP66ISX.mjs +0 -29
  114. package/dist/VueRenderer-Z5PRVBNH.mjs +0 -37298
  115. package/dist/chunk-3U2CYJO5.mjs +0 -367
  116. package/dist/chunk-3XFC4T6M.mjs +0 -392
  117. package/dist/chunk-456QRYFW.mjs +0 -401
  118. package/dist/chunk-6DZX6EAA.mjs +0 -37
  119. package/dist/chunk-DT3R2TNV.mjs +0 -367
  120. package/dist/chunk-EBO3CZXG.mjs +0 -15
  121. package/dist/chunk-F6MVTUCT.mjs +0 -421
  122. package/dist/chunk-GADWIVC4.mjs +0 -400
  123. package/dist/chunk-HHKFAMSE.mjs +0 -380
  124. package/dist/chunk-NEQCQSZI.mjs +0 -406
  125. package/dist/chunk-OKRNL6PN.mjs +0 -400
  126. package/dist/chunk-ULN3GMY2.mjs +0 -367
  127. package/dist/chunk-XAWO7RSP.mjs +0 -398
  128. package/dist/chunk-YLVDJSED.mjs +0 -431
  129. package/dist/index.d.mts +0 -644
  130. package/dist/index.js +0 -38251
  131. package/dist/server-renderer-4W4FI7YG.mjs +0 -37269
@@ -0,0 +1,453 @@
1
+ import type { Queueable } from '@gravito/stream';
2
+ import type { Renderer } from './renderers/Renderer';
3
+ import type { Address, Attachment, Envelope, MailConfig } from './types';
4
+ type ComponentType = any;
5
+ /**
6
+ * Base class for all mailable messages.
7
+ *
8
+ * @description
9
+ * Mailable provides a fluent API to build email envelopes and render content
10
+ * using multiple engines: HTML, Prism templates, React, and Vue components.
11
+ *
12
+ * @architecture
13
+ * ```
14
+ * Mailable
15
+ * ├── Envelope (from, to, subject, cc, bcc, attachments)
16
+ * ├── Renderer (HtmlRenderer | TemplateRenderer | ReactRenderer | VueRenderer)
17
+ * └── Queueable (queue support interface)
18
+ * ```
19
+ *
20
+ * @lifecycle
21
+ * 1. Create Mailable subclass
22
+ * 2. Implement build() method to configure envelope and content
23
+ * 3. Call send() to send immediately, or queue() for background processing
24
+ * 4. OrbitSignal calls buildEnvelope() → renderContent() → transport.send()
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * import { Mailable } from '@gravito/signal'
29
+ *
30
+ * class WelcomeEmail extends Mailable {
31
+ * constructor(private user: User) {
32
+ * super()
33
+ * }
34
+ *
35
+ * build() {
36
+ * return this
37
+ * .to(this.user.email)
38
+ * .subject('Welcome!')
39
+ * .view('emails/welcome', { name: this.user.name })
40
+ * }
41
+ * }
42
+ *
43
+ * // Send immediately
44
+ * await mail.send(new WelcomeEmail(user))
45
+ *
46
+ * // Queue for background processing
47
+ * await new WelcomeEmail(user).onQueue('emails').queue()
48
+ * ```
49
+ *
50
+ * @see {@link OrbitSignal} Mail service orchestrator
51
+ * @see {@link Renderer} Content rendering interface
52
+ * @see {@link Envelope} Email metadata structure
53
+ * @see {@link Queueable} Queue integration interface
54
+ *
55
+ * @public
56
+ * @since 3.0.0
57
+ */
58
+ export declare abstract class Mailable implements Queueable {
59
+ protected envelope: Partial<Envelope>;
60
+ protected renderer?: Renderer;
61
+ private rendererResolver?;
62
+ protected renderData: Record<string, unknown>;
63
+ protected config?: MailConfig;
64
+ /**
65
+ * Set the sender address for the email.
66
+ *
67
+ * This defines the "From" field in the email envelope. If not called, the default
68
+ * sender from the mail configuration will be used.
69
+ *
70
+ * @param address - The email address or address object containing name and address.
71
+ * @returns The current mailable instance for chaining.
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * mailable.from('admin@example.com')
76
+ * mailable.from({ name: 'Support', address: 'support@example.com' })
77
+ * ```
78
+ */
79
+ from(address: string | Address): this;
80
+ /**
81
+ * Set the primary recipient(s) for the email.
82
+ *
83
+ * Configures the "To" field. Supports single or multiple recipients in various formats.
84
+ *
85
+ * @param address - A single email string, an address object, or an array of either.
86
+ * @returns The current mailable instance for chaining.
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * mailable.to('user@example.com')
91
+ * mailable.to(['a@example.com', 'b@example.com'])
92
+ * mailable.to({ name: 'John', address: 'john@example.com' })
93
+ * ```
94
+ */
95
+ to(address: string | Address | (string | Address)[]): this;
96
+ /**
97
+ * Set the carbon copy (CC) recipient(s).
98
+ *
99
+ * Adds recipients to the "Cc" field of the email.
100
+ *
101
+ * @param address - A single email string, an address object, or an array of either.
102
+ * @returns The current mailable instance for chaining.
103
+ *
104
+ * @example
105
+ * ```typescript
106
+ * mailable.cc('manager@example.com')
107
+ * ```
108
+ */
109
+ cc(address: string | Address | (string | Address)[]): this;
110
+ /**
111
+ * Set the blind carbon copy (BCC) recipient(s).
112
+ *
113
+ * Adds recipients to the "Bcc" field. These recipients are hidden from others.
114
+ *
115
+ * @param address - A single email string, an address object, or an array of either.
116
+ * @returns The current mailable instance for chaining.
117
+ *
118
+ * @example
119
+ * ```typescript
120
+ * mailable.bcc('audit@example.com')
121
+ * ```
122
+ */
123
+ bcc(address: string | Address | (string | Address)[]): this;
124
+ /**
125
+ * Set the reply-to address.
126
+ *
127
+ * Specifies where replies to this email should be directed.
128
+ *
129
+ * @param address - The email address or address object for replies.
130
+ * @returns The current mailable instance for chaining.
131
+ *
132
+ * @example
133
+ * ```typescript
134
+ * mailable.replyTo('no-reply@example.com')
135
+ * ```
136
+ */
137
+ replyTo(address: string | Address): this;
138
+ /**
139
+ * Set the subject line for the email.
140
+ *
141
+ * Defines the text that appears in the recipient's inbox subject field.
142
+ *
143
+ * @param subject - The subject text.
144
+ * @returns The current mailable instance for chaining.
145
+ *
146
+ * @example
147
+ * ```typescript
148
+ * mailable.subject('Your Order Confirmation')
149
+ * ```
150
+ */
151
+ subject(subject: string): this;
152
+ /**
153
+ * Set the email priority.
154
+ *
155
+ * Hints to the email client how urgent this message is.
156
+ *
157
+ * @param level - The priority level: 'high', 'normal', or 'low'.
158
+ * @returns The current mailable instance for chaining.
159
+ *
160
+ * @example
161
+ * ```typescript
162
+ * mailable.emailPriority('high')
163
+ * ```
164
+ */
165
+ emailPriority(level: 'high' | 'normal' | 'low'): this;
166
+ /**
167
+ * Attach a file to the email.
168
+ *
169
+ * Adds a file attachment to the message. Can be called multiple times for multiple files.
170
+ *
171
+ * @param attachment - The attachment configuration including path, content, or filename.
172
+ * @returns The current mailable instance for chaining.
173
+ *
174
+ * @example
175
+ * ```typescript
176
+ * mailable.attach({
177
+ * filename: 'invoice.pdf',
178
+ * path: './storage/invoices/123.pdf'
179
+ * })
180
+ * ```
181
+ */
182
+ attach(attachment: Attachment): this;
183
+ /**
184
+ * Set the content using a raw HTML string.
185
+ *
186
+ * Use this for simple emails where a full template engine is not required.
187
+ *
188
+ * @param content - The raw HTML content.
189
+ * @returns The current mailable instance for chaining.
190
+ *
191
+ * @example
192
+ * ```typescript
193
+ * mailable.html('<h1>Hello</h1><p>Welcome to our platform.</p>')
194
+ * ```
195
+ */
196
+ html(content: string): this;
197
+ /**
198
+ * Set the content using an OrbitPrism template.
199
+ *
200
+ * Renders a template file with the provided data. This is the recommended way
201
+ * to build complex, data-driven emails.
202
+ *
203
+ * @param template - The template name or path relative to the configured views directory.
204
+ * @param data - The data object to be injected into the template.
205
+ * @returns The current mailable instance for chaining.
206
+ *
207
+ * @example
208
+ * ```typescript
209
+ * mailable.view('emails.welcome', { name: 'Alice' })
210
+ * ```
211
+ */
212
+ view(template: string, data?: Record<string, unknown>): this;
213
+ /**
214
+ * Set the content using a React component.
215
+ *
216
+ * Leverages React's component model for email design. The renderer is loaded
217
+ * dynamically to keep the core package lightweight.
218
+ *
219
+ * @param component - The React component class or function.
220
+ * @param props - The properties to pass to the component.
221
+ * @param deps - Optional React/ReactDOMServer overrides for custom environments.
222
+ * @returns The current mailable instance for chaining.
223
+ *
224
+ * @example
225
+ * ```typescript
226
+ * mailable.react(WelcomeEmailComponent, { name: 'Alice' })
227
+ * ```
228
+ */
229
+ react<P extends object>(component: ComponentType, props?: P, deps?: {
230
+ createElement?: (...args: any[]) => any;
231
+ renderToStaticMarkup?: (element: any) => string;
232
+ }): this;
233
+ /**
234
+ * Set the content using a Vue component.
235
+ *
236
+ * Leverages Vue's component model for email design. The renderer is loaded
237
+ * dynamically to keep the core package lightweight.
238
+ *
239
+ * @param component - The Vue component object.
240
+ * @param props - The properties to pass to the component.
241
+ * @param deps - Optional Vue/VueServerRenderer overrides for custom environments.
242
+ * @returns The current mailable instance for chaining.
243
+ *
244
+ * @example
245
+ * ```typescript
246
+ * mailable.vue(WelcomeEmailComponent, { name: 'Alice' })
247
+ * ```
248
+ */
249
+ vue<P extends object>(component: ComponentType, props?: P, deps?: {
250
+ createSSRApp?: (...args: any[]) => any;
251
+ h?: (...args: any[]) => any;
252
+ renderToString?: (app: any) => Promise<string>;
253
+ }): this;
254
+ /**
255
+ * Set the content using an MJML markup string.
256
+ *
257
+ * MJML ensures responsive email compatibility across various clients.
258
+ *
259
+ * @param content - The MJML markup string or inner content.
260
+ * @param options - MJML transformation options.
261
+ * @param options.layout - Optional full MJML layout string. Use '{{content}}' as placeholder.
262
+ * @returns The current mailable instance for chaining.
263
+ *
264
+ * @example
265
+ * ```typescript
266
+ * mailable.mjml('<mj-text>Hello</mj-text>', {
267
+ * layout: '<mjml><mj-body>{{content}}</mj-body></mjml>'
268
+ * })
269
+ * ```
270
+ */
271
+ mjml(content: string, options?: Record<string, any> & {
272
+ layout?: string;
273
+ }): this;
274
+ /**
275
+ * Set the content using a React component that outputs MJML.
276
+ *
277
+ * @param component - The React component.
278
+ * @param props - Component properties.
279
+ * @param options - MJML options.
280
+ * @returns The current mailable instance for chaining.
281
+ */
282
+ mjmlReact<P extends object>(component: ComponentType, props?: P, options?: Record<string, any>): this;
283
+ /**
284
+ * Set the content using a Vue component that outputs MJML.
285
+ *
286
+ * @param component - The Vue component.
287
+ * @param props - Component properties.
288
+ * @param options - MJML options.
289
+ * @returns The current mailable instance for chaining.
290
+ */
291
+ mjmlVue<P extends object>(component: ComponentType, props?: P, options?: Record<string, any>): this;
292
+ /**
293
+ * Configure the mailable's envelope and content.
294
+ *
295
+ * This abstract method must be implemented by subclasses to define the email's
296
+ * recipients, subject, and body using the fluent API.
297
+ *
298
+ * @returns The current mailable instance.
299
+ *
300
+ * @example
301
+ * ```typescript
302
+ * build() {
303
+ * return this.to('user@example.com').subject('Hi').html('...')
304
+ * }
305
+ * ```
306
+ */
307
+ abstract build(): this;
308
+ /** The name of the queue to push this mailable to. */
309
+ queueName?: string;
310
+ /** The connection name for the queue. */
311
+ connectionName?: string;
312
+ /** Delay in seconds before the message is sent. */
313
+ delaySeconds?: number;
314
+ /** Priority of the message in the queue. */
315
+ priority?: number | string;
316
+ /**
317
+ * Set the target queue for background processing.
318
+ *
319
+ * @param queue - The name of the queue.
320
+ * @returns The current mailable instance for chaining.
321
+ *
322
+ * @example
323
+ * ```typescript
324
+ * mailable.onQueue('notifications')
325
+ * ```
326
+ */
327
+ onQueue(queue: string): this;
328
+ /**
329
+ * Set the queue connection to be used.
330
+ *
331
+ * @param connection - The name of the connection (e.g., 'redis', 'sqs').
332
+ * @returns The current mailable instance for chaining.
333
+ *
334
+ * @example
335
+ * ```typescript
336
+ * mailable.onConnection('redis')
337
+ * ```
338
+ */
339
+ onConnection(connection: string): this;
340
+ /**
341
+ * Set a delay for the queued message.
342
+ *
343
+ * The message will remain in the queue and only be processed after the delay.
344
+ *
345
+ * @param seconds - The delay in seconds.
346
+ * @returns The current mailable instance for chaining.
347
+ *
348
+ * @example
349
+ * ```typescript
350
+ * mailable.delay(3600) // Delay for 1 hour
351
+ * ```
352
+ */
353
+ delay(seconds: number): this;
354
+ /**
355
+ * Set the priority for the queued message.
356
+ *
357
+ * Higher priority messages are typically processed before lower priority ones.
358
+ *
359
+ * @param priority - The priority value (numeric or string).
360
+ * @returns The current mailable instance for chaining.
361
+ *
362
+ * @example
363
+ * ```typescript
364
+ * mailable.withPriority(10)
365
+ * ```
366
+ */
367
+ withPriority(priority: string | number): this;
368
+ /**
369
+ * Push the mailable onto the configured queue.
370
+ *
371
+ * Automatically resolves the mail service from the Gravito container and
372
+ * dispatches this mailable for background processing.
373
+ *
374
+ * @returns A promise that resolves when the mailable is queued.
375
+ *
376
+ * @example
377
+ * ```typescript
378
+ * await new WelcomeEmail(user).queue()
379
+ * ```
380
+ */
381
+ queue(): Promise<void>;
382
+ protected currentLocale?: string;
383
+ protected translator?: (key: string, replace?: Record<string, unknown>, locale?: string) => string;
384
+ /**
385
+ * Set the locale for the email content.
386
+ *
387
+ * Used by the translator to resolve localized strings in templates or components.
388
+ *
389
+ * @param locale - The locale identifier (e.g., 'en-US', 'fr').
390
+ * @returns The current mailable instance for chaining.
391
+ *
392
+ * @example
393
+ * ```typescript
394
+ * mailable.locale('es')
395
+ * ```
396
+ */
397
+ locale(locale: string): this;
398
+ /**
399
+ * Internal: Set the translator function (called by OrbitSignal)
400
+ * @internal
401
+ */
402
+ setTranslator(translator: (key: string, replace?: Record<string, unknown>, locale?: string) => string): void;
403
+ /**
404
+ * Translate a key into a localized string.
405
+ *
406
+ * Uses the configured translator and current locale to resolve the key.
407
+ *
408
+ * @param key - The translation key.
409
+ * @param replace - Key-value pairs for string interpolation.
410
+ * @returns The translated string, or the key itself if no translator is available.
411
+ *
412
+ * @example
413
+ * ```typescript
414
+ * const text = mailable.t('messages.welcome', { name: 'Alice' })
415
+ * ```
416
+ */
417
+ t(key: string, replace?: Record<string, unknown>): string;
418
+ /**
419
+ * Compile the final email envelope.
420
+ *
421
+ * Merges mailable-specific settings with global configuration defaults.
422
+ * This is called internally by the mail service before sending.
423
+ *
424
+ * @param configPromise - The mail configuration or a promise resolving to it.
425
+ * @returns The fully constructed envelope.
426
+ *
427
+ * @example
428
+ * ```typescript
429
+ * const envelope = await mailable.buildEnvelope(config)
430
+ * ```
431
+ */
432
+ buildEnvelope(configPromise: MailConfig | Promise<MailConfig>): Promise<Envelope>;
433
+ /**
434
+ * Render the email content to HTML and plain text.
435
+ *
436
+ * Executes the chosen renderer (HTML, Template, React, or Vue) with the
437
+ * provided data and i18n helpers.
438
+ *
439
+ * @returns The rendered HTML and optional plain text content.
440
+ * @throws {Error} If no renderer has been specified.
441
+ *
442
+ * @example
443
+ * ```typescript
444
+ * const { html } = await mailable.renderContent()
445
+ * ```
446
+ */
447
+ renderContent(): Promise<{
448
+ html: string;
449
+ text?: string;
450
+ }>;
451
+ private normalizeAddressArray;
452
+ }
453
+ export {};
@@ -0,0 +1,267 @@
1
+ import type { GravitoOrbit, PlanetCore } from '@gravito/core';
2
+ import type { MailEventHandler, MailEventType } from './events';
3
+ import type { Mailable } from './Mailable';
4
+ import type { MailConfig } from './types';
5
+ /**
6
+ * OrbitSignal - Mail service orbit for Gravito framework.
7
+ *
8
+ * @description
9
+ * A production-ready email service providing multi-transport support, automatic retry,
10
+ * event-driven lifecycle hooks, and development tooling. Integrates seamlessly with
11
+ * Gravito's orbit system and queue infrastructure.
12
+ *
13
+ * @architecture
14
+ * ```
15
+ * OrbitSignal
16
+ * ├── Configuration (MailConfig)
17
+ * │ ├── transport: Transport (SMTP, SES, Log, Memory)
18
+ * │ ├── from: Default sender
19
+ * │ ├── devMode: Development interception
20
+ * │ └── translator: i18n support
21
+ * ├── Lifecycle Events
22
+ * │ ├── beforeRender → afterRender
23
+ * │ ├── beforeSend → afterSend
24
+ * │ └── sendFailed (on error)
25
+ * ├── Transport Layer
26
+ * │ ├── BaseTransport (retry, backoff)
27
+ * │ ├── SmtpTransport (connection pooling)
28
+ * │ ├── SesTransport (AWS SES)
29
+ * │ ├── LogTransport (console output)
30
+ * │ └── MemoryTransport (dev mode)
31
+ * └── Dev Tools
32
+ * ├── DevMailbox (in-memory storage)
33
+ * └── DevServer (preview UI at /__mail)
34
+ * ```
35
+ *
36
+ * @example
37
+ * **Basic SMTP Configuration**
38
+ * ```typescript
39
+ * import { OrbitSignal, SmtpTransport } from '@gravito/signal'
40
+ *
41
+ * const mail = new OrbitSignal({
42
+ * transport: new SmtpTransport({
43
+ * host: 'smtp.mailtrap.io',
44
+ * port: 2525,
45
+ * auth: { user: 'username', pass: 'password' }
46
+ * }),
47
+ * from: { name: 'My App', address: 'noreply@myapp.com' }
48
+ * })
49
+ *
50
+ * mail.install(core)
51
+ * ```
52
+ *
53
+ * @example
54
+ * **AWS SES with Retry Configuration**
55
+ * ```typescript
56
+ * import { OrbitSignal, SesTransport } from '@gravito/signal'
57
+ *
58
+ * const mail = new OrbitSignal({
59
+ * transport: new SesTransport({
60
+ * region: 'us-east-1',
61
+ * retries: 3,
62
+ * retryDelay: 1000,
63
+ * retryMultiplier: 2
64
+ * }),
65
+ * from: { name: 'Production App', address: 'noreply@example.com' }
66
+ * })
67
+ * ```
68
+ *
69
+ * @example
70
+ * **Development Mode with Preview UI**
71
+ * ```typescript
72
+ * const mail = new OrbitSignal({
73
+ * devMode: process.env.NODE_ENV === 'development',
74
+ * devUiPrefix: '/__mail',
75
+ * from: { name: 'Dev App', address: 'dev@localhost' }
76
+ * })
77
+ *
78
+ * // All emails intercepted to memory, view at http://localhost:3000/__mail
79
+ * ```
80
+ *
81
+ * @example
82
+ * **Event-Driven Analytics & Error Handling**
83
+ * ```typescript
84
+ * const mail = new OrbitSignal({ ... })
85
+ *
86
+ * // Track successful sends
87
+ * mail.on('afterSend', async (event) => {
88
+ * await analytics.track('email_sent', {
89
+ * to: event.message?.to,
90
+ * subject: event.message?.subject,
91
+ * timestamp: event.timestamp
92
+ * })
93
+ * })
94
+ *
95
+ * // Log failures for monitoring
96
+ * mail.on('sendFailed', async (event) => {
97
+ * logger.error('Email send failed', {
98
+ * error: event.error?.message,
99
+ * mailable: event.mailable.constructor.name
100
+ * })
101
+ * await sentry.captureException(event.error)
102
+ * })
103
+ * ```
104
+ *
105
+ * @example
106
+ * **SMTP with Connection Pooling**
107
+ * ```typescript
108
+ * const mail = new OrbitSignal({
109
+ * transport: new SmtpTransport({
110
+ * host: 'smtp.gmail.com',
111
+ * port: 465,
112
+ * secure: true,
113
+ * auth: { user: 'user@gmail.com', pass: 'app-password' },
114
+ * poolSize: 5,
115
+ * maxIdleTime: 30000
116
+ * })
117
+ * })
118
+ *
119
+ * // Graceful shutdown
120
+ * process.on('SIGTERM', async () => {
121
+ * await mail.config.transport?.close?.()
122
+ * })
123
+ * ```
124
+ *
125
+ * @example
126
+ * **Usage in Route Handlers**
127
+ * ```typescript
128
+ * // Injected automatically into GravitoContext
129
+ * app.post('/register', async (c) => {
130
+ * const user = await createUser(c.req.json())
131
+ *
132
+ * await c.get('mail').send(new WelcomeEmail(user))
133
+ *
134
+ * return c.json({ success: true })
135
+ * })
136
+ * ```
137
+ *
138
+ * @example
139
+ * **Queue Integration for Background Processing**
140
+ * ```typescript
141
+ * // Requires @gravito/stream
142
+ * const email = new WelcomeEmail(user)
143
+ * .onQueue('emails')
144
+ * .delay(60)
145
+ *
146
+ * await email.queue()
147
+ * ```
148
+ *
149
+ * @example
150
+ * **Error Handling Best Practices**
151
+ * ```typescript
152
+ * try {
153
+ * await mail.send(new InvoiceEmail(order))
154
+ * } catch (error) {
155
+ * if (error instanceof MailTransportError) {
156
+ * switch (error.code) {
157
+ * case MailErrorCode.RATE_LIMIT:
158
+ * await queue.pushDelayed(email, 300)
159
+ * break
160
+ * case MailErrorCode.RECIPIENT_REJECTED:
161
+ * await markUserEmailInvalid(user.id)
162
+ * break
163
+ * default:
164
+ * throw error
165
+ * }
166
+ * }
167
+ * }
168
+ * ```
169
+ *
170
+ * @see {@link Mailable} Base class for email definitions
171
+ * @see {@link TypedMailable} Strongly-typed mailable with generic data
172
+ * @see {@link Transport} Transport interface
173
+ * @see {@link BaseTransport} Retry-enabled base transport
174
+ * @see {@link MailConfig} Configuration interface
175
+ * @see {@link MailEvent} Event types
176
+ * @see {@link MailTransportError} Error handling
177
+ *
178
+ * @since 3.0.0
179
+ * @public
180
+ */
181
+ export declare class OrbitSignal implements GravitoOrbit {
182
+ private config;
183
+ private devMailbox?;
184
+ private core?;
185
+ private eventHandlers;
186
+ constructor(config?: MailConfig);
187
+ /**
188
+ * Install the orbit into PlanetCore.
189
+ *
190
+ * Registers the mail service in the IoC container and sets up development
191
+ * tools if enabled. It also injects the service into the GravitoContext
192
+ * for easy access in route handlers.
193
+ *
194
+ * @param core - The PlanetCore instance to install into
195
+ *
196
+ * @example
197
+ * ```typescript
198
+ * const mail = new OrbitSignal(config);
199
+ * mail.install(core);
200
+ * ```
201
+ */
202
+ install(core: PlanetCore): void;
203
+ /**
204
+ * Internal: Handle processed webhook.
205
+ */
206
+ private handleWebhook;
207
+ /**
208
+ * Send a mailable instance immediately.
209
+ *
210
+ * Orchestrates the full email sending lifecycle: building the envelope,
211
+ * rendering content, emitting events, and delivering via the configured transport.
212
+ *
213
+ * @param mailable - The email definition to send
214
+ * @throws {Error} If mandatory fields (from, to) are missing or transport fails
215
+ *
216
+ * @example
217
+ * ```typescript
218
+ * await mail.send(new WelcomeEmail(user));
219
+ * ```
220
+ */
221
+ send(mailable: Mailable): Promise<void>;
222
+ /**
223
+ * Queue a mailable instance for background processing.
224
+ *
225
+ * Attempts to use the 'queue' service (OrbitStream) if available in the
226
+ * container. Falls back to immediate sending if no queue service is found.
227
+ *
228
+ * @param mailable - The email definition to queue
229
+ *
230
+ * @example
231
+ * ```typescript
232
+ * await mail.queue(new WelcomeEmail(user));
233
+ * ```
234
+ */
235
+ queue(mailable: Mailable): Promise<void>;
236
+ /**
237
+ * Register an event handler.
238
+ *
239
+ * @description
240
+ * Subscribe to mail lifecycle events for logging, analytics, or custom processing.
241
+ *
242
+ * @param event - The event type to listen for
243
+ * @param handler - The handler function to execute
244
+ * @returns This instance for method chaining
245
+ *
246
+ * @example
247
+ * ```typescript
248
+ * mail.on('afterSend', async (event) => {
249
+ * await analytics.track('email_sent', {
250
+ * to: event.message?.to,
251
+ * subject: event.message?.subject
252
+ * })
253
+ * })
254
+ * ```
255
+ *
256
+ * @public
257
+ * @since 3.1.0
258
+ */
259
+ on(event: MailEventType, handler: MailEventHandler): this;
260
+ private emit;
261
+ }
262
+ declare module '@gravito/core' {
263
+ interface GravitoVariables {
264
+ /** Mail service for sending emails */
265
+ mail?: OrbitSignal;
266
+ }
267
+ }