@gravito/flare 3.0.1 → 3.3.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/README.md CHANGED
@@ -2,15 +2,17 @@
2
2
 
3
3
  > Lightweight, high-performance notifications for Gravito with multi-channel delivery (mail, database, broadcast, Slack, SMS).
4
4
 
5
- **Status**: v0.1.0 - core features complete with multiple channel support.
5
+ **Status**: v3.3.0 - Production ready with advanced features (Retries, Metrics, Batching).
6
6
 
7
7
  ## Features
8
8
 
9
9
  - **Zero runtime overhead**: Pure type wrappers that delegate to channel drivers
10
- - **Multi-channel delivery**: Mail, database, broadcast, Slack, SMS
11
- - **Modular by design**: Install only the channels you need
10
+ - **Multi-channel delivery**: Mail, database, broadcast, Slack, SMS (Twilio & AWS SNS)
11
+ - **High Performance**: Parallel channel execution and batch sending capabilities
12
+ - **Reliability**: Built-in retry mechanism with exponential backoff
13
+ - **Observability**: Comprehensive metrics with Prometheus support
14
+ - **Developer Experience**: Strong typing, lifecycle hooks, and template system
12
15
  - **Queue support**: Works with `@gravito/stream` for async delivery
13
- - **AI-friendly**: Strong typing, clear JSDoc, and predictable APIs
14
16
 
15
17
  ## Installation
16
18
 
@@ -20,208 +22,145 @@ bun add @gravito/flare
20
22
 
21
23
  ## Quick Start
22
24
 
23
- ### 1. Create a notification
24
-
25
- ```typescript
26
- import { Notification } from '@gravito/flare'
27
- import type { MailMessage, DatabaseNotification, Notifiable } from '@gravito/flare'
28
-
29
- class InvoicePaid extends Notification {
30
- constructor(private invoice: Invoice) {
31
- super()
32
- }
33
-
34
- via(user: Notifiable): string[] {
35
- return ['mail', 'database']
36
- }
37
-
38
- toMail(user: Notifiable): MailMessage {
39
- return {
40
- subject: 'Invoice Paid',
41
- view: 'emails.invoice-paid',
42
- data: { invoice: this.invoice },
43
- to: user.email,
44
- }
45
- }
46
-
47
- toDatabase(user: Notifiable): DatabaseNotification {
48
- return {
49
- type: 'invoice-paid',
50
- data: {
51
- invoice_id: this.invoice.id,
52
- amount: this.invoice.amount,
53
- },
54
- }
55
- }
56
- }
57
- ```
58
-
59
- ### 2. Configure OrbitFlare
25
+ ### 1. Configure OrbitFlare
60
26
 
61
27
  ```typescript
62
28
  import { PlanetCore } from '@gravito/core'
63
29
  import { OrbitFlare } from '@gravito/flare'
64
- import { OrbitSignal } from '@gravito/signal'
65
- import { OrbitStream } from '@gravito/stream'
66
30
 
67
31
  const core = await PlanetCore.boot({
68
32
  orbits: [
69
- OrbitSignal.configure({ /* ... */ }),
70
- OrbitStream.configure({ /* ... */ }),
71
33
  OrbitFlare.configure({
72
34
  enableMail: true,
73
35
  enableDatabase: true,
74
- enableBroadcast: true,
75
36
  channels: {
76
- slack: {
77
- webhookUrl: 'https://hooks.slack.com/services/...',
78
- },
37
+ slack: { webhookUrl: process.env.SLACK_WEBHOOK_URL },
38
+ sms: {
39
+ provider: 'aws-sns', // or 'twilio'
40
+ region: 'us-east-1'
41
+ }
79
42
  },
43
+ // Optional: Global retry policy
44
+ retry: {
45
+ maxAttempts: 3,
46
+ backoff: 'exponential',
47
+ baseDelay: 1000
48
+ }
80
49
  }),
81
50
  ],
82
51
  })
83
52
  ```
84
53
 
85
- ### 3. Send a notification
86
-
87
- ```typescript
88
- // In a controller
89
- const notifications = c.get('notifications') as NotificationManager
90
-
91
- await notifications.send(user, new InvoicePaid(invoice))
92
- ```
93
-
94
- ## Queueing Notifications
54
+ ### 2. Create a notification
95
55
 
96
56
  ```typescript
97
- import { Notification, ShouldQueue } from '@gravito/flare'
57
+ import { Notification } from '@gravito/flare'
58
+ import type { MailMessage, Notifiable } from '@gravito/flare'
98
59
 
99
- class SendEmailNotification extends Notification implements ShouldQueue {
100
- queue = 'notifications'
101
- delay = 60 // delay by 60 seconds
60
+ class WelcomeNotification extends Notification {
61
+ constructor(private name: string) {
62
+ super()
63
+ }
102
64
 
103
65
  via(user: Notifiable): string[] {
104
- return ['mail']
66
+ return ['mail', 'database']
105
67
  }
106
68
 
107
69
  toMail(user: Notifiable): MailMessage {
108
70
  return {
109
71
  subject: 'Welcome!',
110
- to: user.email,
111
72
  view: 'emails.welcome',
73
+ data: { name: this.name },
74
+ to: user.email,
112
75
  }
113
76
  }
114
- }
115
77
 
116
- await notifications.send(user, new SendEmailNotification())
78
+ // Define per-notification retry logic
79
+ retry = {
80
+ maxAttempts: 5,
81
+ backoff: 'linear' as const
82
+ }
83
+ }
117
84
  ```
118
85
 
119
- ## Channels
86
+ ### 3. Send a notification
120
87
 
121
- ### Mail
88
+ ```typescript
89
+ const notifications = c.get('notifications') as NotificationManager
122
90
 
123
- Requires `@gravito/signal`:
91
+ // Simple send
92
+ const result = await notifications.send(user, new WelcomeNotification('Alice'))
124
93
 
125
- ```typescript
126
- via(user: Notifiable): string[] {
127
- return ['mail']
94
+ if (result.failed.length > 0) {
95
+ console.error('Some channels failed:', result.failed)
128
96
  }
129
97
 
130
- toMail(user: Notifiable): MailMessage {
131
- return {
132
- subject: 'Subject',
133
- view: 'emails.template',
134
- data: { /* ... */ },
135
- to: user.email,
136
- }
137
- }
98
+ // Batch send (high performance)
99
+ await notifications.sendBatch(users, new SystemUpdateNotification())
138
100
  ```
139
101
 
140
- ### Database
102
+ ## Advanced Features
141
103
 
142
- Requires database support:
104
+ ### Retries
105
+ Configure retries globally or per-notification:
143
106
 
144
107
  ```typescript
145
- via(user: Notifiable): string[] {
146
- return ['database']
147
- }
148
-
149
- toDatabase(user: Notifiable): DatabaseNotification {
150
- return {
151
- type: 'notification-type',
152
- data: { /* ... */ },
108
+ // Per-notification
109
+ class CriticalAlert extends Notification {
110
+ shouldRetry(attempt: number, error: Error): boolean {
111
+ return attempt < 5 && isRetryable(error)
153
112
  }
154
113
  }
155
114
  ```
156
115
 
157
- ### Broadcast
158
-
159
- Requires `@gravito/radiance`:
116
+ ### Metrics
117
+ Enable metrics to track success rates and latency:
160
118
 
161
119
  ```typescript
162
- via(user: Notifiable): string[] {
163
- return ['broadcast']
164
- }
120
+ const metrics = new NotificationMetricsCollector()
121
+ notifications.setMetricsCollector(metrics)
165
122
 
166
- toBroadcast(user: Notifiable): BroadcastNotification {
167
- return {
168
- type: 'notification-type',
169
- data: { /* ... */ },
170
- }
171
- }
123
+ // Export to Prometheus
124
+ const promData = toPrometheusFormat(metrics.getSummary())
172
125
  ```
173
126
 
174
- ### Slack
127
+ ### Hooks
128
+ Listen to lifecycle events:
175
129
 
176
130
  ```typescript
177
- via(user: Notifiable): string[] {
178
- return ['slack']
179
- }
180
-
181
- toSlack(user: Notifiable): SlackMessage {
182
- return {
183
- text: 'Notification message',
184
- channel: '#notifications',
185
- }
186
- }
131
+ notifications.on('notification:failed', ({ notification, error }) => {
132
+ logger.error('Notification failed completely', error)
133
+ })
187
134
  ```
188
135
 
189
- ### SMS
136
+ ### Templates
137
+ Use `TemplatedNotification` for consistent messaging:
190
138
 
191
139
  ```typescript
192
- via(user: Notifiable): string[] {
193
- return ['sms']
194
- }
195
-
196
- toSms(user: Notifiable): SmsMessage {
197
- return {
198
- to: user.phone,
199
- message: 'Notification message',
140
+ class OrderShipped extends TemplatedNotification {
141
+ constructor(order: Order) {
142
+ super('order-shipped', { orderId: order.id })
200
143
  }
201
144
  }
202
145
  ```
203
146
 
204
147
  ## API Reference
205
148
 
206
- ### Notification
207
-
208
- Every notification should extend `Notification`.
149
+ ### NotificationManager
209
150
 
210
151
  #### Methods
211
152
 
212
- - `via(notifiable: Notifiable): string[]` - Choose delivery channels (required)
213
- - `toMail(notifiable: Notifiable): MailMessage` - Mail payload (optional)
214
- - `toDatabase(notifiable: Notifiable): DatabaseNotification` - Database payload (optional)
215
- - `toBroadcast(notifiable: Notifiable): BroadcastNotification` - Broadcast payload (optional)
216
- - `toSlack(notifiable: Notifiable): SlackMessage` - Slack payload (optional)
217
- - `toSms(notifiable: Notifiable): SmsMessage` - SMS payload (optional)
153
+ - `send(notifiable: Notifiable, notification: Notification, options?: SendOptions): Promise<NotificationResult>`
154
+ - `sendBatch(notifiables: Notifiable[], notification: Notification): Promise<BatchResult>`
155
+ - `sendBatchStream(iterator: AsyncIterator<Notifiable>, notification: Notification): Promise<BatchResult>`
218
156
 
219
- ### NotificationManager
157
+ ### Notification
220
158
 
221
159
  #### Methods
222
160
 
223
- - `send(notifiable: Notifiable, notification: Notification): Promise<void>` - Send notification
224
- - `channel(name: string, channel: NotificationChannel): void` - Register a custom channel
161
+ - `via(notifiable: Notifiable): string[]` - Choose delivery channels
162
+ - `toMail`, `toDatabase`, `toBroadcast`, `toSlack`, `toSms` - Channel payloads
163
+ - `shouldRetry(attempt: number, error: Error): boolean` - Custom retry logic
225
164
 
226
165
  ## License
227
166
 
package/README.zh-TW.md CHANGED
@@ -1,35 +1,150 @@
1
- # @gravito/flare
1
+ # @gravito/flare 🌌
2
2
 
3
- > Gravito 的通知模組,支援郵件、資料庫、廣播、Slack、SMS 等多種通道。
3
+ > 輕量化、高效能的 Gravito 通知引擎,支援多通路發送(郵件、資料庫、廣播、Slack、SMS)。
4
4
 
5
- ## 安裝
5
+ `@gravito/flare` 是 Gravito 框架官方提供的通知引擎。它提供了一套簡潔且具表現力的 API,讓開發者能夠輕鬆地透過多種通路發送通知,並原生支援背景隊列處理。
6
+
7
+ **狀態**: v1.0.0 - 生產環境可用。
8
+
9
+ ## 🌟 核心特性
10
+
11
+ - **零執行負擔 (Zero Runtime Overhead)**:純 TypeScript 實作,直接委派給高效的通路驅動程式。
12
+ - **多通路支援**:單一通知可同時透過多個通路(Mail, DB, Slack 等)發送。
13
+ - **背景隊列支援**:與 `@gravito/stream` (OrbitStream) 無縫整合,處理高流量通知發送而不阻塞請求。
14
+ - **類型安全 (Type-Safe)**:為每個通路提供嚴格的訊息結構定義,確保資料完整性。
15
+ - **易於擴充**:可輕鬆註冊自定義的通知通路。
16
+ - **Galaxy 架構相容**:設計為標準的 Gravito Orbit,支援零配置整合。
17
+
18
+ ## 📦 安裝
6
19
 
7
20
  ```bash
8
21
  bun add @gravito/flare
9
22
  ```
10
23
 
11
- ## 快速開始
24
+ ## 🚀 快速上手
25
+
26
+ ### 1. 定義您的通知
27
+
28
+ 建立一個繼承自 `Notification` 的類別。實作 `via` 方法來指定發送通路,以及實作 `to[Channel]` 方法來定義發送內容。
12
29
 
13
30
  ```typescript
14
31
  import { Notification } from '@gravito/flare'
15
- import type { MailMessage, Notifiable } from '@gravito/flare'
32
+ import type { MailMessage, DatabaseNotification, Notifiable } from '@gravito/flare'
16
33
 
17
- class WelcomeUser extends Notification {
34
+ class OrderShipped extends Notification {
35
+ constructor(private order: any) {
36
+ super()
37
+ }
38
+
39
+ // 指定發送通路
18
40
  via(user: Notifiable): string[] {
19
- return ['mail']
41
+ return ['mail', 'database']
20
42
  }
21
43
 
44
+ // 郵件內容
22
45
  toMail(user: Notifiable): MailMessage {
23
46
  return {
24
- subject: 'Welcome!',
25
- view: 'emails.welcome',
47
+ subject: `訂單 #${this.order.id} 已出貨!`,
48
+ view: 'emails.order-shipped',
49
+ data: { order: this.order },
26
50
  to: user.email,
27
51
  }
28
52
  }
53
+
54
+ // 資料庫通知內容
55
+ toDatabase(user: Notifiable): DatabaseNotification {
56
+ return {
57
+ type: 'order_shipped',
58
+ data: {
59
+ order_id: this.order.id,
60
+ tracking_number: this.order.tracking,
61
+ },
62
+ }
63
+ }
29
64
  }
30
65
  ```
31
66
 
67
+ ### 2. 配置 OrbitFlare
68
+
69
+ 在 `PlanetCore` 啟動程序中註冊 `OrbitFlare`。
70
+
71
+ ```typescript
72
+ import { PlanetCore } from '@gravito/core'
73
+ import { OrbitFlare } from '@gravito/flare'
74
+
75
+ const core = await PlanetCore.boot({
76
+ orbits: [
77
+ OrbitFlare.configure({
78
+ enableMail: true,
79
+ enableDatabase: true,
80
+ channels: {
81
+ slack: {
82
+ webhookUrl: process.env.SLACK_WEBHOOK_URL,
83
+ },
84
+ },
85
+ }),
86
+ ],
87
+ })
88
+ ```
89
+
90
+ ### 3. 發送通知
91
+
92
+ 透過核心容器或上下文變數取得 `notifications` 管理器。
93
+
94
+ ```typescript
95
+ // 在業務邏輯或控制器中
96
+ const notifications = core.container.make('notifications')
97
+
98
+ await notifications.send(user, new OrderShipped(order))
99
+ ```
100
+
101
+ ## ⏳ 非同步隊列
102
+
103
+ 若要將通知放入背景發送,只需在通知類別中實作 `ShouldQueue` 介面。
104
+
32
105
  ```typescript
33
- const notifications = c.get('notifications')
34
- await notifications.send(user, new WelcomeUser())
106
+ import { Notification, ShouldQueue } from '@gravito/flare'
107
+
108
+ class WeeklyReport extends Notification implements ShouldQueue {
109
+ queue = 'notifications' // 可選:指定隊列名稱
110
+ delay = 3600 // 可選:延遲秒數
111
+
112
+ via(user: Notifiable): string[] {
113
+ return ['mail']
114
+ }
115
+
116
+ // ... toMail 實作
117
+ }
35
118
  ```
119
+
120
+ ## 🛠️ 支援的通路
121
+
122
+ | 通路 | 依賴模組 | 描述 |
123
+ |---|---|---|
124
+ | **Mail** | `@gravito/signal` | 透過配置的郵件驅動發送電子郵件。 |
125
+ | **Database** | `@gravito/atlas` | 將通知儲存至 `notifications` 資料表。 |
126
+ | **Broadcast**| `@gravito/radiance`| 透過 WebSockets 推送即時更新。 |
127
+ | **Slack** | 無 | 透過 Webhooks 發送訊息至 Slack。 |
128
+ | **SMS** | 供應商配置 | 透過配置的簡訊供應商發送簡訊。 |
129
+
130
+ ## 🧩 API 參考
131
+
132
+ ### `Notification` 基礎類別
133
+ - `via(notifiable)`:回傳通路名稱陣列。
134
+ - `toMail(notifiable)`:回傳 `MailMessage`。
135
+ - `toDatabase(notifiable)`:回傳 `DatabaseNotification`。
136
+ - `toBroadcast(notifiable)`:回傳 `BroadcastNotification`。
137
+ - `toSlack(notifiable)`:回傳 `SlackMessage`。
138
+ - `toSms(notifiable)`:回傳 `SmsMessage`。
139
+
140
+ ### `NotificationManager`
141
+ - `send(notifiable, notification)`:將通知發送至所有指定的通路。
142
+ - `channel(name, implementation)`:註冊自定義的發送通路。
143
+
144
+ ## 🤝 參與貢獻
145
+
146
+ 我們歡迎任何形式的貢獻!詳細資訊請參閱 [貢獻指南](../../CONTRIBUTING.md)。
147
+
148
+ ## 📄 開源授權
149
+
150
+ MIT © Carl Lee