@gravito/signal 3.0.0 → 3.0.3

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/dist/index.d.ts CHANGED
@@ -2,96 +2,178 @@ import { Queueable } from '@gravito/stream';
2
2
  export { Queueable } from '@gravito/stream';
3
3
  import { GravitoContext, GravitoOrbit, PlanetCore } from '@gravito/core';
4
4
 
5
- declare module '@gravito/core' {
6
- interface GravitoVariables {
7
- /** Mail service for sending emails */
8
- mail?: {
9
- send: (mailable: any) => Promise<void>;
10
- queue: (mailable: any) => Promise<void>;
11
- };
12
- }
13
- }
14
-
5
+ /**
6
+ * Interface for email transport mechanisms (SMTP, SES, etc.).
7
+ *
8
+ * @public
9
+ * @since 3.0.0
10
+ */
15
11
  interface Transport {
16
12
  /**
17
- * Send the given message
13
+ * Send the given message using the underlying transport.
14
+ *
15
+ * @param message - The finalized message to send.
18
16
  */
19
17
  send(message: Message): Promise<void>;
20
18
  }
21
19
 
20
+ /**
21
+ * Representation of an email address with optional display name.
22
+ *
23
+ * @public
24
+ * @since 3.0.0
25
+ */
22
26
  interface Address {
27
+ /** The display name of the recipient/sender, e.g., "John Doe". */
23
28
  name?: string;
29
+ /** The actual email address string. */
24
30
  address: string;
25
31
  }
32
+ /**
33
+ * Configuration for an email attachment.
34
+ *
35
+ * @public
36
+ * @since 3.0.0
37
+ */
26
38
  interface Attachment {
39
+ /** The filename of the attachment. */
27
40
  filename: string;
41
+ /** The content of the attachment as a string or Buffer. */
28
42
  content: string | Buffer;
43
+ /** Optional MIME type of the content. */
29
44
  contentType?: string;
45
+ /** Optional Content-ID for referencing within HTML content (inline images). */
30
46
  cid?: string;
47
+ /** Optional content encoding. */
31
48
  encoding?: string;
32
49
  }
50
+ /**
51
+ * The envelope containing metadata for an email message.
52
+ *
53
+ * Used during the construction phase of a Mailable.
54
+ *
55
+ * @public
56
+ * @since 3.0.0
57
+ */
33
58
  interface Envelope {
59
+ /** The sender's address. */
34
60
  from?: Address | undefined;
61
+ /** Primary recipients. */
35
62
  to?: Address[] | undefined;
63
+ /** Carbon copy recipients. */
36
64
  cc?: Address[] | undefined;
65
+ /** Blind carbon copy recipients. */
37
66
  bcc?: Address[] | undefined;
67
+ /** Reply-to address. */
38
68
  replyTo?: Address | undefined;
69
+ /** Email subject line. */
39
70
  subject?: string | undefined;
71
+ /** Importance level of the email. */
40
72
  priority?: 'high' | 'normal' | 'low' | undefined;
73
+ /** List of file attachments. */
41
74
  attachments?: Attachment[] | undefined;
42
75
  }
76
+ /**
77
+ * A fully finalized email message ready to be sent by a transport.
78
+ *
79
+ * Requires mandatory fields that were optional in the Envelope.
80
+ *
81
+ * @public
82
+ * @since 3.0.0
83
+ */
43
84
  interface Message extends Envelope {
85
+ /** The mandatory sender's address. */
44
86
  from: Address;
87
+ /** At least one recipient is required. */
45
88
  to: Address[];
89
+ /** Mandatory subject. */
46
90
  subject: string;
91
+ /** The rendered HTML body content. */
47
92
  html: string;
93
+ /** Optional rendered plain text body content. */
48
94
  text?: string;
95
+ /** Custom SMTP headers. */
49
96
  headers?: Record<string, string>;
50
97
  }
98
+ /**
99
+ * Global configuration options for OrbitSignal and Mailable instances.
100
+ *
101
+ * @public
102
+ * @since 3.0.0
103
+ */
51
104
  interface MailConfig {
52
105
  /**
53
- * Default sender address
106
+ * Default sender address used if not specified in the Mailable.
54
107
  */
55
108
  from?: Address;
56
109
  /**
57
- * The transport mechanism used to send emails
110
+ * The transport mechanism used to send emails (e.g., SMTP, SES, Log).
58
111
  */
59
112
  transport?: Transport;
60
113
  /**
61
- * Enable development mode (intercepts emails)
114
+ * Enable development mode.
115
+ * When true, emails are intercepted by the DevMailbox instead of being sent.
62
116
  */
63
117
  devMode?: boolean | undefined;
64
118
  /**
65
- * Directory where email templates are located (for OrbitPrism)
119
+ * Directory where email templates are located for use with OrbitPrism.
66
120
  * Default: src/emails
67
121
  */
68
122
  viewsDir?: string | undefined;
69
123
  /**
70
- * URL prefix for Dev UI
124
+ * URL prefix for the Mail Dev UI.
71
125
  * Default: /__mail
72
126
  */
73
127
  devUiPrefix?: string | undefined;
74
128
  /**
75
- * Allow Dev UI in production. Default: false.
129
+ * Whether to allow access to the Mail Dev UI in production environments.
130
+ * @default false
76
131
  */
77
132
  devUiAllowInProduction?: boolean | undefined;
78
133
  /**
79
- * Gate access to Dev UI (required in production unless allowInProduction is true).
134
+ * Authorization gate for the Mail Dev UI.
135
+ * Should return true to allow access to the UI.
80
136
  */
81
137
  devUiGate?: ((ctx: GravitoContext) => boolean | Promise<boolean>) | undefined;
82
138
  /**
83
- * Translation function for i18n support
139
+ * Translation function for internationalization within emails.
84
140
  */
85
141
  translator?: ((key: string, replace?: Record<string, unknown>, locale?: string) => string) | undefined;
86
142
  }
87
143
 
144
+ /**
145
+ * Represents a captured email in the development mailbox.
146
+ *
147
+ * @public
148
+ */
88
149
  interface MailboxEntry {
150
+ /** Unique identifier for the email */
89
151
  id: string;
152
+ /** Email envelope information (from, to, subject, etc.) */
90
153
  envelope: Envelope;
154
+ /** HTML content of the email */
91
155
  html: string;
156
+ /** Plain text content of the email (optional) */
92
157
  text?: string;
158
+ /** Timestamp when the email was captured */
93
159
  sentAt: Date;
94
160
  }
161
+ /**
162
+ * In-memory mailbox for capturing emails during development.
163
+ *
164
+ * Stores up to 50 recent emails and provides methods to list,
165
+ * retrieve, and delete captured messages.
166
+ *
167
+ * @example
168
+ * ```typescript
169
+ * const mailbox = new DevMailbox()
170
+ * mailbox.add(message)
171
+ * const emails = mailbox.list()
172
+ * ```
173
+ *
174
+ * @since 3.0.0
175
+ * @public
176
+ */
95
177
  declare class DevMailbox {
96
178
  private entries;
97
179
  private maxEntries;
@@ -102,45 +184,129 @@ declare class DevMailbox {
102
184
  clear(): void;
103
185
  }
104
186
 
187
+ /**
188
+ * Result of a content rendering operation.
189
+ *
190
+ * @public
191
+ * @since 3.0.0
192
+ */
105
193
  interface RenderResult {
194
+ /** Rendered HTML string. */
106
195
  html: string;
196
+ /** Optional rendered plain text string. */
107
197
  text?: string;
108
198
  }
199
+ /**
200
+ * Interface for email content renderers (HTML, Template, React, Vue).
201
+ *
202
+ * @public
203
+ * @since 3.0.0
204
+ */
109
205
  interface Renderer {
110
206
  /**
111
- * Render the content into HTML and optionally plain text
207
+ * Render the content into HTML and optionally plain text.
208
+ *
209
+ * @param data - The data context for rendering.
112
210
  */
113
211
  render(data: Record<string, unknown>): Promise<RenderResult>;
114
212
  }
115
213
 
116
214
  type ComponentType = any;
215
+ /**
216
+ * Base class for all mailable messages.
217
+ *
218
+ * Provides a fluent API for building email envelopes and rendering content
219
+ * using various engines (raw HTML, Prism templates, React, or Vue).
220
+ *
221
+ * @example
222
+ * ```typescript
223
+ * class WelcomeMail extends Mailable {
224
+ * build() {
225
+ * return this.subject('Welcome!')
226
+ * .view('emails.welcome', { name: 'John' });
227
+ * }
228
+ * }
229
+ *
230
+ * await new WelcomeMail().to('john@example.com').send();
231
+ * ```
232
+ *
233
+ * @public
234
+ * @since 3.0.0
235
+ */
117
236
  declare abstract class Mailable implements Queueable {
118
237
  protected envelope: Partial<Envelope>;
119
238
  protected renderer?: Renderer;
120
239
  private rendererResolver?;
121
240
  protected renderData: Record<string, unknown>;
122
241
  protected config?: MailConfig;
242
+ /**
243
+ * Set the sender address for the email.
244
+ *
245
+ * @param address - Email address or Address object.
246
+ */
123
247
  from(address: string | Address): this;
248
+ /**
249
+ * Set the primary recipient(s) for the email.
250
+ *
251
+ * @param address - Single address, address object, or array of either.
252
+ */
124
253
  to(address: string | Address | (string | Address)[]): this;
254
+ /**
255
+ * Set the carbon copy (CC) recipient(s).
256
+ *
257
+ * @param address - Single address, address object, or array of either.
258
+ */
125
259
  cc(address: string | Address | (string | Address)[]): this;
260
+ /**
261
+ * Set the blind carbon copy (BCC) recipient(s).
262
+ *
263
+ * @param address - Single address, address object, or array of either.
264
+ */
126
265
  bcc(address: string | Address | (string | Address)[]): this;
266
+ /**
267
+ * Set the reply-to address.
268
+ *
269
+ * @param address - Email address or Address object.
270
+ */
127
271
  replyTo(address: string | Address): this;
272
+ /**
273
+ * Set the subject line for the email.
274
+ *
275
+ * @param subject - The email subject.
276
+ */
128
277
  subject(subject: string): this;
278
+ /**
279
+ * Set the email priority.
280
+ *
281
+ * @param level - Priority level ('high', 'normal', or 'low').
282
+ */
129
283
  emailPriority(level: 'high' | 'normal' | 'low'): this;
284
+ /**
285
+ * Attach a file to the email.
286
+ *
287
+ * @param attachment - Attachment configuration object.
288
+ */
130
289
  attach(attachment: Attachment): this;
131
290
  /**
132
291
  * Set the content using raw HTML string.
292
+ *
293
+ * @param content - The HTML content string.
133
294
  */
134
295
  html(content: string): this;
135
296
  /**
136
297
  * Set the content using an OrbitPrism template.
137
- * @param template Template name (relative to viewsDir/emails)
138
- * @param data Data to pass to the template
298
+ *
299
+ * @param template - Template name (relative to viewsDir/emails).
300
+ * @param data - Optional data to pass to the template.
139
301
  */
140
302
  view(template: string, data?: Record<string, unknown>): this;
141
303
  /**
142
304
  * Set the content using a React component.
143
305
  * Dynamically imports ReactRenderer to avoid hard dependency errors if React is not installed.
306
+ *
307
+ * @param component - The React component to render.
308
+ * @param props - Optional props for the component.
309
+ * @param deps - Optional dependencies (React, ReactDOMServer) if not globally available.
144
310
  */
145
311
  react<P extends object>(component: ComponentType, props?: P, deps?: {
146
312
  createElement?: (...args: any[]) => any;
@@ -149,6 +315,10 @@ declare abstract class Mailable implements Queueable {
149
315
  /**
150
316
  * Set the content using a Vue component.
151
317
  * Dynamically imports VueRenderer to avoid hard dependency errors if Vue is not installed.
318
+ *
319
+ * @param component - The Vue component to render.
320
+ * @param props - Optional props for the component.
321
+ * @param deps - Optional dependencies (Vue, VueServerRenderer) if not globally available.
152
322
  */
153
323
  vue<P extends object>(component: ComponentType, props?: P, deps?: {
154
324
  createSSRApp?: (...args: any[]) => any;
@@ -157,40 +327,67 @@ declare abstract class Mailable implements Queueable {
157
327
  }): this;
158
328
  /**
159
329
  * Setup the mailable. This is where you call from(), to(), view(), etc.
330
+ * This method must be implemented by concrete classes.
160
331
  */
161
332
  abstract build(): this;
333
+ /** The name of the queue to push this mailable to. */
162
334
  queueName?: string;
335
+ /** The connection name for the queue. */
163
336
  connectionName?: string;
337
+ /** Delay in seconds before the message is sent. */
164
338
  delaySeconds?: number;
339
+ /** Priority of the message in the queue. */
165
340
  priority?: number | string;
341
+ /**
342
+ * Set the queue name for this mailable.
343
+ */
166
344
  onQueue(queue: string): this;
345
+ /**
346
+ * Set the connection name for this mailable.
347
+ */
167
348
  onConnection(connection: string): this;
349
+ /**
350
+ * Set a delay for the queued mailable.
351
+ */
168
352
  delay(seconds: number): this;
353
+ /**
354
+ * Set the priority for the queued mailable.
355
+ */
169
356
  withPriority(priority: string | number): this;
170
357
  /**
171
358
  * Queue the mailable for sending.
359
+ * Attempts to resolve the mail service from the PlanetCore container.
172
360
  */
173
361
  queue(): Promise<void>;
174
362
  protected currentLocale?: string;
175
363
  protected translator?: (key: string, replace?: Record<string, unknown>, locale?: string) => string;
176
364
  /**
177
365
  * Set the locale for the message.
366
+ *
367
+ * @param locale - Valid locale string (e.g., 'en', 'zh-TW').
178
368
  */
179
369
  locale(locale: string): this;
180
370
  /**
181
371
  * Internal: Set the translator function (called by OrbitSignal)
372
+ * @internal
182
373
  */
183
374
  setTranslator(translator: (key: string, replace?: Record<string, unknown>, locale?: string) => string): void;
184
375
  /**
185
376
  * Translate a string using the configured translator.
377
+ *
378
+ * @param key - Translation key.
379
+ * @param replace - Interpolation variables.
380
+ * @returns Translated string or the key if translator is missing.
186
381
  */
187
382
  t(key: string, replace?: Record<string, unknown>): string;
188
383
  /**
189
384
  * Compile the envelope based on config defaults and mailable settings.
385
+ * Called by OrbitSignal before rendering/sending.
190
386
  */
191
387
  buildEnvelope(configPromise: MailConfig | Promise<MailConfig>): Promise<Envelope>;
192
388
  /**
193
- * execute the renderer
389
+ * Execute the renderer and produce HTML/Text content.
390
+ * @returns Object containing rendered html and optional text content.
194
391
  */
195
392
  renderContent(): Promise<{
196
393
  html: string;
@@ -199,6 +396,37 @@ declare abstract class Mailable implements Queueable {
199
396
  private normalizeAddressArray;
200
397
  }
201
398
 
399
+ /**
400
+ * OrbitSignal - Mail service orbit for Gravito framework.
401
+ *
402
+ * Provides email sending capabilities with support for multiple transports,
403
+ * development mode with email preview UI, and queue integration.
404
+ *
405
+ * @example
406
+ * ```typescript
407
+ * import { OrbitSignal } from '@gravito/signal'
408
+ * import { SmtpTransport } from '@gravito/signal'
409
+ *
410
+ * const app = new Application({
411
+ * orbits: [
412
+ * new OrbitSignal({
413
+ * transport: new SmtpTransport({
414
+ * host: 'smtp.example.com',
415
+ * port: 587,
416
+ * auth: { user: 'user', pass: 'pass' }
417
+ * }),
418
+ * from: { name: 'App', email: 'noreply@example.com' }
419
+ * })
420
+ * ]
421
+ * })
422
+ *
423
+ * // In route handler
424
+ * await c.get('mail').send(new WelcomeEmail(user))
425
+ * ```
426
+ *
427
+ * @since 3.0.0
428
+ * @public
429
+ */
202
430
  declare class OrbitSignal implements GravitoOrbit {
203
431
  private config;
204
432
  private devMailbox?;
@@ -212,10 +440,6 @@ declare class OrbitSignal implements GravitoOrbit {
212
440
  install(core: PlanetCore): void;
213
441
  /**
214
442
  * Send a mailable instance
215
- *
216
- * @param mailable - The mailable object to send.
217
- * @returns A promise that resolves when the email is sent.
218
- * @throws {Error} If the message is missing "from" or "to" addresses, or if no transport is configured.
219
443
  */
220
444
  send(mailable: Mailable): Promise<void>;
221
445
  /**
@@ -223,7 +447,30 @@ declare class OrbitSignal implements GravitoOrbit {
223
447
  */
224
448
  queue(mailable: Mailable): Promise<void>;
225
449
  }
450
+ declare module '@gravito/core' {
451
+ interface GravitoVariables {
452
+ /** Mail service for sending emails */
453
+ mail?: OrbitSignal;
454
+ }
455
+ }
226
456
 
457
+ /**
458
+ * Renderer for plain HTML content.
459
+ *
460
+ * Renders static HTML strings and automatically generates
461
+ * a plain text version by stripping HTML tags.
462
+ *
463
+ * @example
464
+ * ```typescript
465
+ * const renderer = new HtmlRenderer('<h1>Hello</h1><p>World</p>')
466
+ * const { html, text } = await renderer.render()
467
+ * // html: '<h1>Hello</h1><p>World</p>'
468
+ * // text: 'Hello World'
469
+ * ```
470
+ *
471
+ * @since 3.0.0
472
+ * @public
473
+ */
227
474
  declare class HtmlRenderer implements Renderer {
228
475
  private content;
229
476
  constructor(content: string);
@@ -231,6 +478,21 @@ declare class HtmlRenderer implements Renderer {
231
478
  private stripHtml;
232
479
  }
233
480
 
481
+ /**
482
+ * Renderer for template-based emails using Gravito Prism.
483
+ *
484
+ * Renders email templates from the filesystem using the Prism
485
+ * template engine with support for data binding and layouts.
486
+ *
487
+ * @example
488
+ * ```typescript
489
+ * const renderer = new TemplateRenderer('welcome', './src/emails')
490
+ * const { html, text } = await renderer.render({ name: 'John' })
491
+ * ```
492
+ *
493
+ * @since 3.0.0
494
+ * @public
495
+ */
234
496
  declare class TemplateRenderer implements Renderer {
235
497
  private template;
236
498
  private viewsDir;
@@ -239,21 +501,81 @@ declare class TemplateRenderer implements Renderer {
239
501
  private stripHtml;
240
502
  }
241
503
 
504
+ /**
505
+ * Log transport for development and testing.
506
+ *
507
+ * Logs email details to the console instead of sending them.
508
+ * Useful for debugging and local development.
509
+ *
510
+ * @example
511
+ * ```typescript
512
+ * const transport = new LogTransport()
513
+ * await transport.send(message)
514
+ * // Outputs email details to console
515
+ * ```
516
+ *
517
+ * @since 3.0.0
518
+ * @public
519
+ */
242
520
  declare class LogTransport implements Transport {
243
521
  send(message: Message): Promise<void>;
244
522
  }
245
523
 
524
+ /**
525
+ * Memory transport for development mode.
526
+ *
527
+ * Captures emails to an in-memory mailbox instead of sending them.
528
+ * Used automatically when `devMode` is enabled in OrbitSignal.
529
+ *
530
+ * @example
531
+ * ```typescript
532
+ * const mailbox = new DevMailbox()
533
+ * const transport = new MemoryTransport(mailbox)
534
+ * await transport.send(message)
535
+ * ```
536
+ *
537
+ * @since 3.0.0
538
+ * @public
539
+ */
246
540
  declare class MemoryTransport implements Transport {
247
541
  private mailbox;
248
542
  constructor(mailbox: DevMailbox);
249
543
  send(message: Message): Promise<void>;
250
544
  }
251
545
 
546
+ /**
547
+ * Configuration for AWS SES email transport.
548
+ *
549
+ * @public
550
+ * @since 3.0.0
551
+ */
252
552
  interface SesConfig {
553
+ /** AWS region (e.g., 'us-east-1') */
253
554
  region: string;
555
+ /** AWS access key ID (optional, uses default credentials if not provided) */
254
556
  accessKeyId?: string;
557
+ /** AWS secret access key (optional, uses default credentials if not provided) */
255
558
  secretAccessKey?: string;
256
559
  }
560
+ /**
561
+ * AWS SES (Simple Email Service) transport.
562
+ *
563
+ * Sends emails using Amazon SES with support for attachments,
564
+ * HTML/text content, and all standard email features.
565
+ *
566
+ * @example
567
+ * ```typescript
568
+ * const transport = new SesTransport({
569
+ * region: 'us-east-1',
570
+ * accessKeyId: process.env.AWS_ACCESS_KEY_ID,
571
+ * secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
572
+ * })
573
+ * await transport.send(message)
574
+ * ```
575
+ *
576
+ * @since 3.0.0
577
+ * @public
578
+ */
257
579
  declare class SesTransport implements Transport {
258
580
  private transporter;
259
581
  constructor(config: SesConfig);
@@ -261,19 +583,57 @@ declare class SesTransport implements Transport {
261
583
  private formatAddress;
262
584
  }
263
585
 
586
+ /**
587
+ * Configuration for SMTP email transport.
588
+ *
589
+ * @public
590
+ * @since 3.0.0
591
+ */
264
592
  interface SmtpConfig {
593
+ /** SMTP server hostname */
265
594
  host: string;
595
+ /** SMTP server port (typically 25, 465, or 587) */
266
596
  port: number;
597
+ /** Use TLS/SSL connection (true for port 465) */
267
598
  secure?: boolean;
599
+ /** Authentication credentials */
268
600
  auth?: {
601
+ /** SMTP username */
269
602
  user: string;
603
+ /** SMTP password */
270
604
  pass: string;
271
605
  };
606
+ /** TLS options */
272
607
  tls?: {
608
+ /** Reject unauthorized certificates */
273
609
  rejectUnauthorized?: boolean;
610
+ /** Cipher suite */
274
611
  ciphers?: string;
275
612
  };
276
613
  }
614
+ /**
615
+ * SMTP email transport.
616
+ *
617
+ * Sends emails using standard SMTP protocol with support for
618
+ * authentication, TLS/SSL, attachments, and all email features.
619
+ *
620
+ * @example
621
+ * ```typescript
622
+ * const transport = new SmtpTransport({
623
+ * host: 'smtp.gmail.com',
624
+ * port: 587,
625
+ * secure: false,
626
+ * auth: {
627
+ * user: 'user@gmail.com',
628
+ * pass: 'app-password'
629
+ * }
630
+ * })
631
+ * await transport.send(message)
632
+ * ```
633
+ *
634
+ * @since 3.0.0
635
+ * @public
636
+ */
277
637
  declare class SmtpTransport implements Transport {
278
638
  private transporter;
279
639
  constructor(config: SmtpConfig);