@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.
- package/README.md +26 -15
- package/dist/Mailable.d.ts +453 -0
- package/dist/OrbitSignal.d.ts +267 -0
- package/{src/Queueable.ts → dist/Queueable.d.ts} +1 -1
- package/{src/TypedMailable.ts → dist/TypedMailable.d.ts} +12 -13
- 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/{src/events.ts → dist/events.d.ts} +20 -29
- package/dist/{lib-HJTRWKU5.mjs → index.cjs} +4687 -10983
- package/dist/index.d.ts +303 -1874
- package/dist/index.js +317 -45939
- package/dist/index.mjs +59748 -27
- 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/{src/renderers/Renderer.ts → dist/renderers/Renderer.d.ts} +23 -24
- 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/{src/utils/html.ts → dist/utils/html.d.ts} +1 -15
- package/dist/webhooks/SendGridWebhookDriver.d.ts +45 -0
- package/dist/webhooks/SesWebhookDriver.d.ts +23 -0
- package/package.json +20 -8
- package/CHANGELOG.md +0 -74
- package/dist/MjmlRenderer-IUH663FT.mjs +0 -8
- package/dist/ReactMjmlRenderer-C3P5YO5L.mjs +0 -8
- package/dist/ReactRenderer-24SQ4KRU.mjs +0 -27
- package/dist/ReactRenderer-2JFLRVST.mjs +0 -45
- package/dist/ReactRenderer-CMCAOEPH.mjs +0 -28
- package/dist/ReactRenderer-KYNA4WKE.mjs +0 -28
- package/dist/ReactRenderer-LYEOSYFS.mjs +0 -28
- package/dist/ReactRenderer-V54CUUEI.mjs +0 -45
- package/dist/VueMjmlRenderer-4F4CXHDB.mjs +0 -8
- package/dist/VueMjmlRenderer-5WZR4CQG.mjs +0 -8
- package/dist/VueMjmlRenderer-U5YMWI44.mjs +0 -8
- package/dist/VueRenderer-3YBRQXME.mjs +0 -48
- package/dist/VueRenderer-46JGXTJ2.mjs +0 -48
- package/dist/VueRenderer-5KWD4R3C.mjs +0 -48
- package/dist/VueRenderer-C23U4O5E.mjs +0 -48
- package/dist/VueRenderer-DWTCD2RF.mjs +0 -31
- package/dist/VueRenderer-IIR5SYTM.mjs +0 -31
- package/dist/VueRenderer-LEVDFLHP.mjs +0 -31
- package/dist/VueRenderer-RNHSCCRI.mjs +0 -48
- package/dist/VueRenderer-SUP66ISX.mjs +0 -29
- package/dist/chunk-3WOR3XSL.mjs +0 -82
- package/dist/chunk-DBFIVHHG.mjs +0 -79
- package/dist/chunk-EBO3CZXG.mjs +0 -15
- package/dist/chunk-HEBXNMVQ.mjs +0 -48
- package/dist/chunk-KB7IDDBT.mjs +0 -82
- package/dist/chunk-LZL5UUPC.mjs +0 -82
- package/dist/chunk-W6LXIJKK.mjs +0 -57
- package/dist/chunk-XBIVBJS2.mjs +0 -8
- package/dist/index.d.mts +0 -2115
- package/dist/server-renderer-4IM3P5XZ.mjs +0 -37183
- package/dist/server-renderer-4W4FI7YG.mjs +0 -37269
- package/dist/server-renderer-7KWFSTPV.mjs +0 -37193
- package/dist/server-renderer-S5FPSTJ2.mjs +0 -37183
- package/dist/server-renderer-X5LUFVWT.mjs +0 -37193
- package/doc/OPTIMIZATION_PLAN.md +0 -496
- package/scripts/check-coverage.ts +0 -64
- package/src/Mailable.ts +0 -674
- package/src/OrbitSignal.ts +0 -451
- package/src/dev/DevMailbox.ts +0 -146
- package/src/dev/DevServer.ts +0 -192
- package/src/dev/storage/FileMailboxStorage.ts +0 -66
- package/src/dev/storage/MailboxStorage.ts +0 -15
- package/src/dev/storage/MemoryMailboxStorage.ts +0 -36
- package/src/dev/ui/mailbox.ts +0 -77
- package/src/dev/ui/preview.ts +0 -103
- package/src/dev/ui/shared.ts +0 -60
- package/src/errors.ts +0 -69
- package/src/index.ts +0 -41
- package/src/renderers/HtmlRenderer.ts +0 -41
- package/src/renderers/MjmlRenderer.ts +0 -73
- package/src/renderers/ReactMjmlRenderer.ts +0 -94
- package/src/renderers/ReactRenderer.ts +0 -66
- package/src/renderers/TemplateRenderer.ts +0 -84
- package/src/renderers/VueMjmlRenderer.ts +0 -99
- package/src/renderers/VueRenderer.ts +0 -71
- package/src/renderers/mjml-templates.ts +0 -50
- package/src/transports/BaseTransport.ts +0 -148
- package/src/transports/LogTransport.ts +0 -55
- package/src/transports/MemoryTransport.ts +0 -55
- package/src/transports/SesTransport.ts +0 -129
- package/src/transports/SmtpTransport.ts +0 -184
- package/src/transports/Transport.ts +0 -45
- package/src/types.ts +0 -309
- package/src/webhooks/SendGridWebhookDriver.ts +0 -80
- package/src/webhooks/SesWebhookDriver.ts +0 -44
- package/tests/DevMailbox.test.ts +0 -54
- package/tests/FileMailboxStorage.test.ts +0 -56
- package/tests/MjmlLayout.test.ts +0 -28
- package/tests/MjmlRenderer.test.ts +0 -53
- package/tests/OrbitSignalWebhook.test.ts +0 -56
- package/tests/ReactMjmlRenderer.test.ts +0 -33
- package/tests/SendGridWebhookDriver.test.ts +0 -69
- package/tests/SesWebhookDriver.test.ts +0 -46
- package/tests/VueMjmlRenderer.test.ts +0 -35
- package/tests/dev-server.test.ts +0 -66
- package/tests/log-transport.test.ts +0 -21
- package/tests/mailable-extra.test.ts +0 -68
- package/tests/mailable.test.ts +0 -77
- package/tests/orbit-signal.test.ts +0 -43
- package/tests/renderers.test.ts +0 -58
- package/tests/template-renderer.test.ts +0 -24
- package/tests/transports.test.ts +0 -52
- package/tests/ui.test.ts +0 -37
- package/tsconfig.json +0 -14
|
@@ -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
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { Mailable } from './Mailable'
|
|
2
|
-
|
|
1
|
+
import { Mailable } from './Mailable';
|
|
3
2
|
/**
|
|
4
3
|
* Abstract base class for strongly-typed Mailable messages.
|
|
5
4
|
*
|
|
@@ -82,15 +81,15 @@ import { Mailable } from './Mailable'
|
|
|
82
81
|
* @public
|
|
83
82
|
* @since 3.0.0
|
|
84
83
|
*/
|
|
85
|
-
export abstract class TypedMailable<TData extends Record<string, unknown>> extends Mailable {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
84
|
+
export declare abstract class TypedMailable<TData extends Record<string, unknown>> extends Mailable {
|
|
85
|
+
/**
|
|
86
|
+
* The strongly-typed data for this mailable.
|
|
87
|
+
*
|
|
88
|
+
* This property holds the data that will be passed to the template or component
|
|
89
|
+
* during rendering. By defining it as an abstract property with the generic
|
|
90
|
+
* type TData, we force subclasses to provide a concrete, type-safe implementation.
|
|
91
|
+
*
|
|
92
|
+
* @protected
|
|
93
|
+
*/
|
|
94
|
+
protected abstract data: TData;
|
|
96
95
|
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { Message } from '../types';
|
|
2
|
+
import type { MailboxStorage } from './storage/MailboxStorage';
|
|
3
|
+
/**
|
|
4
|
+
* Entry structure for messages stored in DevMailbox.
|
|
5
|
+
*/
|
|
6
|
+
export interface MailboxEntry {
|
|
7
|
+
/** Unique identifier for the entry. */
|
|
8
|
+
id: string;
|
|
9
|
+
/** The email envelope metadata. */
|
|
10
|
+
envelope: any;
|
|
11
|
+
/** The rendered HTML content. */
|
|
12
|
+
html: string;
|
|
13
|
+
/** Optional plain text content. */
|
|
14
|
+
text?: string;
|
|
15
|
+
/** Timestamp when the message was captured. */
|
|
16
|
+
sentAt: Date;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Capture and store emails during development for preview and testing.
|
|
20
|
+
*
|
|
21
|
+
* Supports different storage engines (Memory, FileSystem) and implements
|
|
22
|
+
* capacity limits via a Ring Buffer strategy.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* // Default memory mailbox
|
|
27
|
+
* const mailbox = new DevMailbox()
|
|
28
|
+
*
|
|
29
|
+
* // Persistent file mailbox
|
|
30
|
+
* const storage = new FileMailboxStorage('./storage/mail')
|
|
31
|
+
* const persistentMailbox = new DevMailbox(100, storage)
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @since 3.0.0
|
|
35
|
+
* @public
|
|
36
|
+
*/
|
|
37
|
+
export declare class DevMailbox {
|
|
38
|
+
private storage;
|
|
39
|
+
private _maxEntries;
|
|
40
|
+
/**
|
|
41
|
+
* Creates an instance of DevMailbox.
|
|
42
|
+
*
|
|
43
|
+
* @param maxEntries - Maximum number of emails to store (default: 50)
|
|
44
|
+
* @param storage - Optional custom storage engine (defaults to Memory)
|
|
45
|
+
*/
|
|
46
|
+
constructor(maxEntries?: number, storage?: MailboxStorage);
|
|
47
|
+
/**
|
|
48
|
+
* Adds a new message to the mailbox.
|
|
49
|
+
*
|
|
50
|
+
* If the mailbox exceeds the maximum capacity, the oldest messages are removed.
|
|
51
|
+
*/
|
|
52
|
+
add(message: Message): Promise<MailboxEntry>;
|
|
53
|
+
/**
|
|
54
|
+
* Sets the maximum number of emails to store.
|
|
55
|
+
*
|
|
56
|
+
* If the current mailbox exceeds the new capacity, the oldest messages are removed.
|
|
57
|
+
*/
|
|
58
|
+
setMaxEntries(count: number): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Returns the maximum capacity of the mailbox.
|
|
61
|
+
*/
|
|
62
|
+
get maxEntries(): number;
|
|
63
|
+
/**
|
|
64
|
+
* Lists all messages in the mailbox.
|
|
65
|
+
*/
|
|
66
|
+
list(): Promise<MailboxEntry[]>;
|
|
67
|
+
/**
|
|
68
|
+
* Retrieves a specific message by ID.
|
|
69
|
+
*/
|
|
70
|
+
get(id: string): Promise<MailboxEntry | undefined>;
|
|
71
|
+
/**
|
|
72
|
+
* Deletes a specific message by ID.
|
|
73
|
+
*/
|
|
74
|
+
delete(id: string): Promise<boolean>;
|
|
75
|
+
/**
|
|
76
|
+
* Clears all messages from the mailbox.
|
|
77
|
+
*/
|
|
78
|
+
clear(): Promise<void>;
|
|
79
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { GravitoContext, PlanetCore } from '@gravito/core';
|
|
2
|
+
import type { DevMailbox } from './DevMailbox';
|
|
3
|
+
/**
|
|
4
|
+
* Configuration options for the development mail server.
|
|
5
|
+
*
|
|
6
|
+
* @public
|
|
7
|
+
*/
|
|
8
|
+
export type DevServerOptions = {
|
|
9
|
+
/** Allow access in production environment (use with caution) */
|
|
10
|
+
allowInProduction?: boolean;
|
|
11
|
+
/** Custom gate function to control access to the dev UI */
|
|
12
|
+
gate?: (c: GravitoContext) => boolean | Promise<boolean>;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Development mail server for previewing captured emails.
|
|
16
|
+
*
|
|
17
|
+
* Provides a web UI at the configured base path (default: `/__mail`)
|
|
18
|
+
* to view, preview, and manage emails captured during development.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* const mailbox = new DevMailbox()
|
|
23
|
+
* const devServer = new DevServer(mailbox, '/__mail', {
|
|
24
|
+
* gate: (c) => c.get('user')?.isAdmin
|
|
25
|
+
* })
|
|
26
|
+
* devServer.register(core)
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @since 3.0.0
|
|
30
|
+
* @public
|
|
31
|
+
*/
|
|
32
|
+
export declare class DevServer {
|
|
33
|
+
private mailbox;
|
|
34
|
+
private base;
|
|
35
|
+
private options?;
|
|
36
|
+
constructor(mailbox: DevMailbox, base?: string, options?: DevServerOptions);
|
|
37
|
+
private canAccess;
|
|
38
|
+
register(core: PlanetCore): void;
|
|
39
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { MailboxEntry } from '../DevMailbox';
|
|
2
|
+
import type { MailboxStorage } from './MailboxStorage';
|
|
3
|
+
/**
|
|
4
|
+
* File-based storage for DevMailbox (Persistence).
|
|
5
|
+
* Stores emails as JSON in a specified directory.
|
|
6
|
+
*/
|
|
7
|
+
export declare class FileMailboxStorage implements MailboxStorage {
|
|
8
|
+
private filePath;
|
|
9
|
+
constructor(storageDir: string);
|
|
10
|
+
all(): Promise<MailboxEntry[]>;
|
|
11
|
+
push(entry: MailboxEntry): Promise<void>;
|
|
12
|
+
trim(max: number): Promise<void>;
|
|
13
|
+
clear(): Promise<void>;
|
|
14
|
+
delete(id: string): Promise<boolean>;
|
|
15
|
+
private save;
|
|
16
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { MailboxEntry } from '../DevMailbox';
|
|
2
|
+
/**
|
|
3
|
+
* Interface for DevMailbox storage engines.
|
|
4
|
+
*/
|
|
5
|
+
export interface MailboxStorage {
|
|
6
|
+
/** Retrieve all entries. */
|
|
7
|
+
all(): Promise<MailboxEntry[]>;
|
|
8
|
+
/** Add a single entry. */
|
|
9
|
+
push(entry: MailboxEntry): Promise<void>;
|
|
10
|
+
/** Trim entries to a specific count. */
|
|
11
|
+
trim(max: number): Promise<void>;
|
|
12
|
+
clear(): Promise<void>;
|
|
13
|
+
delete?(id: string): Promise<boolean>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { MailboxEntry } from '../DevMailbox';
|
|
2
|
+
import type { MailboxStorage } from './MailboxStorage';
|
|
3
|
+
/**
|
|
4
|
+
* Memory-based storage for DevMailbox (Default).
|
|
5
|
+
*/
|
|
6
|
+
export declare class MemoryMailboxStorage implements MailboxStorage {
|
|
7
|
+
private entries;
|
|
8
|
+
all(): Promise<MailboxEntry[]>;
|
|
9
|
+
push(entry: MailboxEntry): Promise<void>;
|
|
10
|
+
trim(max: number): Promise<void>;
|
|
11
|
+
clear(): Promise<void>;
|
|
12
|
+
delete(id: string): Promise<boolean>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { MailboxEntry } from '../DevMailbox';
|
|
2
|
+
/**
|
|
3
|
+
* Generates the HTML for the mailbox list view.
|
|
4
|
+
*
|
|
5
|
+
* @param entries - Array of mailbox entries to display
|
|
6
|
+
* @param prefix - Base URL prefix for the dev server
|
|
7
|
+
* @returns HTML string for the mailbox UI
|
|
8
|
+
*
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export declare function getMailboxHtml(entries: MailboxEntry[], prefix: string): string;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { MailboxEntry } from '../DevMailbox';
|
|
2
|
+
/**
|
|
3
|
+
* Generates the HTML for the email preview page.
|
|
4
|
+
*
|
|
5
|
+
* @param entry - Mailbox entry to preview
|
|
6
|
+
* @param prefix - Base URL prefix for the dev server
|
|
7
|
+
* @returns HTML string for the preview UI
|
|
8
|
+
*
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export declare function getPreviewHtml(entry: MailboxEntry, prefix: string): string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSS styles for the development mail UI.
|
|
3
|
+
* @internal
|
|
4
|
+
*/
|
|
5
|
+
export declare const styles = "\n:root {\n --primary: #6366f1;\n --primary-dark: #4f46e5;\n --bg-dark: #0f172a;\n --bg-card: #1e293b;\n --text: #f1f5f9;\n --text-muted: #94a3b8;\n --border: #334155;\n --danger: #ef4444;\n}\nbody { background: var(--bg-dark); color: var(--text); font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif; margin: 0; padding: 20px; }\n.container { max-width: 1000px; margin: 0 auto; }\n.header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }\n.title { font-size: 24px; font-weight: bold; display: flex; align-items: center; gap: 10px; }\n.card { background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }\n.btn { background: var(--border); color: var(--text); border: none; padding: 8px 16px; border-radius: 6px; cursor: pointer; text-decoration: none; font-size: 14px; transition: 0.2s; }\n.btn:hover { background: var(--bg-card-hover); }\n.btn-primary { background: var(--primary); color: white; }\n.btn-primary:hover { background: var(--primary-dark); }\n.btn-danger { background: var(--danger); color: white; }\n.list-item { padding: 16px; border-bottom: 1px solid var(--border); display: flex; flex-direction: column; gap: 4px; text-decoration: none; color: inherit; transition: background 0.2s; }\n.list-item:last-child { border-bottom: none; }\n.list-item:hover { background: #334155; }\n.meta { display: flex; justify-content: space-between; font-size: 14px; color: var(--text-muted); }\n.subject { font-weight: 600; font-size: 16px; }\n.from { color: #cbd5e1; }\n.badge { background: #475569; padding: 2px 6px; border-radius: 4px; font-size: 12px; }\n.badge-high { background: #dc2626; color: white; }\n.empty { padding: 40px; text-align: center; color: var(--text-muted); }\n";
|
|
6
|
+
/**
|
|
7
|
+
* HTML layout wrapper for dev mail UI pages.
|
|
8
|
+
*
|
|
9
|
+
* @param title - Page title
|
|
10
|
+
* @param content - HTML content to inject
|
|
11
|
+
* @returns Complete HTML document
|
|
12
|
+
*
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
export declare const layout: (title: string, content: string) => string;
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mail transport error codes.
|
|
3
|
+
*
|
|
4
|
+
* Categorizes common failure modes in the mail delivery process to allow
|
|
5
|
+
* for programmatic handling (e.g., retries on rate limits).
|
|
6
|
+
*
|
|
7
|
+
* @public
|
|
8
|
+
* @since 3.1.0
|
|
9
|
+
*/
|
|
10
|
+
export declare enum MailErrorCode {
|
|
11
|
+
/** Connection to mail server failed */
|
|
12
|
+
CONNECTION_FAILED = "CONNECTION_FAILED",
|
|
13
|
+
/** Authentication with mail server failed */
|
|
14
|
+
AUTH_FAILED = "AUTH_FAILED",
|
|
15
|
+
/** One or more recipients were rejected by the server */
|
|
16
|
+
RECIPIENT_REJECTED = "RECIPIENT_REJECTED",
|
|
17
|
+
/** The message was rejected by the server */
|
|
18
|
+
MESSAGE_REJECTED = "MESSAGE_REJECTED",
|
|
19
|
+
/** Rate limit exceeded */
|
|
20
|
+
RATE_LIMIT = "RATE_LIMIT",
|
|
21
|
+
/** Unknown or unclassified error */
|
|
22
|
+
UNKNOWN = "UNKNOWN"
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Error class for mail transport failures.
|
|
26
|
+
*
|
|
27
|
+
* Provides structured error information for mail sending failures,
|
|
28
|
+
* including error codes and original cause tracking for debugging.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* throw new MailTransportError(
|
|
33
|
+
* 'Failed to connect to SMTP server',
|
|
34
|
+
* MailErrorCode.CONNECTION_FAILED,
|
|
35
|
+
* originalError
|
|
36
|
+
* )
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @public
|
|
40
|
+
* @since 3.1.0
|
|
41
|
+
*/
|
|
42
|
+
export declare class MailTransportError extends Error {
|
|
43
|
+
readonly code: MailErrorCode;
|
|
44
|
+
readonly cause?: Error;
|
|
45
|
+
/**
|
|
46
|
+
* Create a new mail transport error.
|
|
47
|
+
*
|
|
48
|
+
* @param message - Human-readable error message
|
|
49
|
+
* @param code - Categorized error code
|
|
50
|
+
* @param cause - Original error that caused this failure
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* const error = new MailTransportError('Auth failed', MailErrorCode.AUTH_FAILED);
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
constructor(message: string, code: MailErrorCode, cause?: Error);
|
|
58
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type { Mailable } from './Mailable'
|
|
2
|
-
import type { Message } from './types'
|
|
3
|
-
|
|
1
|
+
import type { Mailable } from './Mailable';
|
|
2
|
+
import type { Message } from './types';
|
|
4
3
|
/**
|
|
5
4
|
* Mail event types.
|
|
6
5
|
*
|
|
@@ -9,14 +8,7 @@ import type { Message } from './types'
|
|
|
9
8
|
* @public
|
|
10
9
|
* @since 3.1.0
|
|
11
10
|
*/
|
|
12
|
-
export type MailEventType =
|
|
13
|
-
| 'beforeSend'
|
|
14
|
-
| 'afterSend'
|
|
15
|
-
| 'sendFailed'
|
|
16
|
-
| 'beforeRender'
|
|
17
|
-
| 'afterRender'
|
|
18
|
-
| 'webhookReceived'
|
|
19
|
-
|
|
11
|
+
export type MailEventType = 'beforeSend' | 'afterSend' | 'sendFailed' | 'beforeRender' | 'afterRender' | 'webhookReceived';
|
|
20
12
|
/**
|
|
21
13
|
* Mail lifecycle event.
|
|
22
14
|
*
|
|
@@ -34,24 +26,23 @@ export type MailEventType =
|
|
|
34
26
|
* @since 3.1.0
|
|
35
27
|
*/
|
|
36
28
|
export interface MailEvent {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
29
|
+
/** Type of event */
|
|
30
|
+
type: MailEventType;
|
|
31
|
+
/** Mailable instance that triggered the event */
|
|
32
|
+
mailable: Mailable;
|
|
33
|
+
/** Finalized message (available for send events) */
|
|
34
|
+
message?: Message;
|
|
35
|
+
/** Error that occurred (available for sendFailed event) */
|
|
36
|
+
error?: Error;
|
|
37
|
+
/** Timestamp when event occurred */
|
|
38
|
+
timestamp: Date;
|
|
39
|
+
/** Webhook payload (available for webhookReceived event) */
|
|
40
|
+
webhook?: {
|
|
41
|
+
driver: string;
|
|
42
|
+
event: string;
|
|
43
|
+
payload: any;
|
|
44
|
+
};
|
|
53
45
|
}
|
|
54
|
-
|
|
55
46
|
/**
|
|
56
47
|
* Mail event handler function.
|
|
57
48
|
*
|
|
@@ -69,4 +60,4 @@ export interface MailEvent {
|
|
|
69
60
|
* @public
|
|
70
61
|
* @since 3.1.0
|
|
71
62
|
*/
|
|
72
|
-
export type MailEventHandler = (event: MailEvent) => void | Promise<void
|
|
63
|
+
export type MailEventHandler = (event: MailEvent) => void | Promise<void>;
|