@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.
- package/CHANGELOG.md +16 -0
- package/README.md +99 -59
- package/README.zh-TW.md +140 -9
- package/build.ts +133 -0
- package/dist/Mailable.d.ts +453 -0
- package/dist/OrbitSignal.d.ts +267 -0
- package/dist/Queueable.d.ts +9 -0
- package/dist/TypedMailable.d.ts +95 -0
- package/dist/dev/DevMailbox.d.ts +79 -0
- package/dist/dev/DevServer.d.ts +39 -0
- package/dist/dev/storage/FileMailboxStorage.d.ts +16 -0
- package/dist/dev/storage/MailboxStorage.d.ts +14 -0
- package/dist/dev/storage/MemoryMailboxStorage.d.ts +13 -0
- package/dist/dev/ui/mailbox.d.ts +11 -0
- package/dist/dev/ui/preview.d.ts +11 -0
- package/dist/dev/ui/shared.d.ts +15 -0
- package/dist/errors.d.ts +58 -0
- package/dist/events.d.ts +63 -0
- package/dist/index.cjs +88291 -0
- package/dist/index.cjs.map +712 -0
- package/dist/index.d.ts +31 -643
- package/dist/index.mjs +87748 -335
- package/dist/index.mjs.map +710 -0
- package/dist/renderers/HtmlRenderer.d.ts +34 -0
- package/dist/renderers/MjmlRenderer.d.ts +41 -0
- package/dist/renderers/ReactMjmlRenderer.d.ts +38 -0
- package/dist/renderers/ReactRenderer.d.ts +46 -0
- package/dist/renderers/Renderer.d.ts +66 -0
- package/dist/renderers/TemplateRenderer.d.ts +55 -0
- package/dist/renderers/VueMjmlRenderer.d.ts +39 -0
- package/dist/renderers/VueRenderer.d.ts +47 -0
- package/dist/renderers/mjml-templates.d.ts +11 -0
- package/dist/transports/BaseTransport.d.ts +111 -0
- package/dist/transports/LogTransport.d.ts +42 -0
- package/dist/transports/MemoryTransport.d.ts +51 -0
- package/dist/transports/SesTransport.d.ts +79 -0
- package/dist/transports/SmtpTransport.d.ts +124 -0
- package/dist/transports/Transport.d.ts +44 -0
- package/dist/types.d.ts +294 -0
- package/dist/utils/html.d.ts +29 -0
- package/dist/webhooks/SendGridWebhookDriver.d.ts +45 -0
- package/dist/webhooks/SesWebhookDriver.d.ts +23 -0
- package/doc/ADVANCED_RENDERING.md +71 -0
- package/doc/DISTRIBUTED_MESSAGING.md +79 -0
- package/doc/OPTIMIZATION_PLAN.md +496 -0
- package/package.json +14 -11
- package/package.json.bak +75 -0
- package/scripts/check-coverage.ts +64 -0
- package/src/Mailable.ts +340 -44
- package/src/OrbitSignal.ts +350 -50
- package/src/TypedMailable.ts +96 -0
- package/src/dev/DevMailbox.ts +89 -33
- package/src/dev/DevServer.ts +14 -14
- package/src/dev/storage/FileMailboxStorage.ts +66 -0
- package/src/dev/storage/MailboxStorage.ts +15 -0
- package/src/dev/storage/MemoryMailboxStorage.ts +36 -0
- package/src/dev/ui/mailbox.ts +1 -1
- package/src/dev/ui/preview.ts +4 -4
- package/src/errors.ts +69 -0
- package/src/events.ts +72 -0
- package/src/index.ts +20 -1
- package/src/renderers/HtmlRenderer.ts +20 -18
- package/src/renderers/MjmlRenderer.ts +73 -0
- package/src/renderers/ReactMjmlRenderer.ts +94 -0
- package/src/renderers/ReactRenderer.ts +26 -21
- package/src/renderers/Renderer.ts +43 -3
- package/src/renderers/TemplateRenderer.ts +48 -15
- package/src/renderers/VueMjmlRenderer.ts +99 -0
- package/src/renderers/VueRenderer.ts +26 -21
- package/src/renderers/mjml-templates.ts +50 -0
- package/src/transports/BaseTransport.ts +148 -0
- package/src/transports/LogTransport.ts +28 -6
- package/src/transports/MemoryTransport.ts +34 -6
- package/src/transports/SesTransport.ts +62 -17
- package/src/transports/SmtpTransport.ts +123 -27
- package/src/transports/Transport.ts +33 -4
- package/src/types.ts +172 -3
- package/src/utils/html.ts +43 -0
- package/src/webhooks/SendGridWebhookDriver.ts +80 -0
- package/src/webhooks/SesWebhookDriver.ts +44 -0
- package/tests/DevMailbox.test.ts +54 -0
- package/tests/FileMailboxStorage.test.ts +56 -0
- package/tests/MjmlLayout.test.ts +28 -0
- package/tests/MjmlRenderer.test.ts +53 -0
- package/tests/OrbitSignalWebhook.test.ts +56 -0
- package/tests/ReactMjmlRenderer.test.ts +33 -0
- package/tests/SendGridWebhookDriver.test.ts +69 -0
- package/tests/SesWebhookDriver.test.ts +46 -0
- package/tests/VueMjmlRenderer.test.ts +35 -0
- package/tests/dev-server.test.ts +1 -1
- package/tests/transports.test.ts +3 -3
- package/tsconfig.build.json +24 -0
- package/tsconfig.json +8 -25
- package/dist/OrbitMail-2Z7ZTKYA.mjs +0 -7
- package/dist/OrbitMail-BGV32HWN.mjs +0 -7
- package/dist/OrbitMail-FUYZQSAV.mjs +0 -7
- package/dist/OrbitMail-NAPCRK7B.mjs +0 -7
- package/dist/OrbitMail-REGJ276B.mjs +0 -7
- package/dist/OrbitMail-TCFBJWDT.mjs +0 -7
- package/dist/OrbitMail-XZZW6U4N.mjs +0 -7
- package/dist/OrbitSignal-IPSA2CDO.mjs +0 -7
- package/dist/OrbitSignal-MABW4DDW.mjs +0 -7
- package/dist/OrbitSignal-QSW5VQ5M.mjs +0 -7
- package/dist/OrbitSignal-R22QHWAA.mjs +0 -7
- package/dist/OrbitSignal-ZKKMEC27.mjs +0 -7
- package/dist/ReactRenderer-24SQ4KRU.mjs +0 -27
- package/dist/ReactRenderer-CMCAOEPH.mjs +0 -28
- package/dist/ReactRenderer-KYNA4WKE.mjs +0 -28
- package/dist/ReactRenderer-L5INVYKT.mjs +0 -27
- package/dist/VueRenderer-DWTCD2RF.mjs +0 -31
- package/dist/VueRenderer-IIR5SYTM.mjs +0 -31
- package/dist/VueRenderer-S65ZARRI.mjs +0 -37129
- package/dist/VueRenderer-SUP66ISX.mjs +0 -29
- package/dist/VueRenderer-Z5PRVBNH.mjs +0 -37298
- package/dist/chunk-3U2CYJO5.mjs +0 -367
- package/dist/chunk-3XFC4T6M.mjs +0 -392
- package/dist/chunk-456QRYFW.mjs +0 -401
- package/dist/chunk-6DZX6EAA.mjs +0 -37
- package/dist/chunk-DT3R2TNV.mjs +0 -367
- package/dist/chunk-EBO3CZXG.mjs +0 -15
- package/dist/chunk-F6MVTUCT.mjs +0 -421
- package/dist/chunk-GADWIVC4.mjs +0 -400
- package/dist/chunk-HHKFAMSE.mjs +0 -380
- package/dist/chunk-NEQCQSZI.mjs +0 -406
- package/dist/chunk-OKRNL6PN.mjs +0 -400
- package/dist/chunk-ULN3GMY2.mjs +0 -367
- package/dist/chunk-XAWO7RSP.mjs +0 -398
- package/dist/chunk-YLVDJSED.mjs +0 -431
- package/dist/index.d.mts +0 -644
- package/dist/index.js +0 -38251
- 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
|
+
}
|