@gravito/flare 3.0.3 → 4.0.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 +199 -128
- package/README.zh-TW.md +126 -11
- package/dist/index.cjs +1700 -160
- package/dist/index.d.cts +1553 -91
- package/dist/index.d.ts +1553 -91
- package/dist/index.js +1690 -159
- package/package.json +9 -6
package/README.md
CHANGED
|
@@ -2,15 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
> Lightweight, high-performance notifications for Gravito with multi-channel delivery (mail, database, broadcast, Slack, SMS).
|
|
4
4
|
|
|
5
|
-
**Status**:
|
|
5
|
+
**Status**: v3.4.0 - Production ready with advanced features (Retries, Metrics, Batching, Timeout, Rate Limiting, Preference Driver).
|
|
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
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
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 and timeout protection
|
|
13
|
+
- **Observability**: Comprehensive metrics with Prometheus support
|
|
14
|
+
- **Developer Experience**: Strong typing, lifecycle hooks, and template system
|
|
15
|
+
- **Queue support**: Works with `@gravito/stream` for async delivery with Lazy Loading
|
|
16
|
+
- **Rate Limiting**: Channel-level rate limiting with Token Bucket algorithm
|
|
17
|
+
- **Preference Driver**: User notification preferences with automatic channel filtering
|
|
18
|
+
- **Middleware System**: Extensible middleware chain for custom notification processing
|
|
14
19
|
|
|
15
20
|
## Installation
|
|
16
21
|
|
|
@@ -20,208 +25,274 @@ bun add @gravito/flare
|
|
|
20
25
|
|
|
21
26
|
## Quick Start
|
|
22
27
|
|
|
23
|
-
### 1.
|
|
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
|
|
28
|
+
### 1. Configure OrbitFlare
|
|
60
29
|
|
|
61
30
|
```typescript
|
|
62
31
|
import { PlanetCore } from '@gravito/core'
|
|
63
32
|
import { OrbitFlare } from '@gravito/flare'
|
|
64
|
-
import { OrbitSignal } from '@gravito/signal'
|
|
65
|
-
import { OrbitStream } from '@gravito/stream'
|
|
66
33
|
|
|
67
34
|
const core = await PlanetCore.boot({
|
|
68
35
|
orbits: [
|
|
69
|
-
OrbitSignal.configure({ /* ... */ }),
|
|
70
|
-
OrbitStream.configure({ /* ... */ }),
|
|
71
36
|
OrbitFlare.configure({
|
|
72
37
|
enableMail: true,
|
|
73
38
|
enableDatabase: true,
|
|
74
|
-
enableBroadcast: true,
|
|
75
39
|
channels: {
|
|
76
|
-
slack: {
|
|
77
|
-
|
|
78
|
-
|
|
40
|
+
slack: { webhookUrl: process.env.SLACK_WEBHOOK_URL },
|
|
41
|
+
sms: {
|
|
42
|
+
provider: 'aws-sns', // or 'twilio'
|
|
43
|
+
region: 'us-east-1'
|
|
44
|
+
}
|
|
79
45
|
},
|
|
46
|
+
// Optional: Global retry policy
|
|
47
|
+
retry: {
|
|
48
|
+
maxAttempts: 3,
|
|
49
|
+
backoff: 'exponential',
|
|
50
|
+
baseDelay: 1000
|
|
51
|
+
}
|
|
80
52
|
}),
|
|
81
53
|
],
|
|
82
54
|
})
|
|
83
55
|
```
|
|
84
56
|
|
|
85
|
-
###
|
|
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
|
|
57
|
+
### 2. Create a notification
|
|
95
58
|
|
|
96
59
|
```typescript
|
|
97
|
-
import { Notification
|
|
60
|
+
import { Notification } from '@gravito/flare'
|
|
61
|
+
import type { MailMessage, Notifiable } from '@gravito/flare'
|
|
98
62
|
|
|
99
|
-
class
|
|
100
|
-
|
|
101
|
-
|
|
63
|
+
class WelcomeNotification extends Notification {
|
|
64
|
+
constructor(private name: string) {
|
|
65
|
+
super()
|
|
66
|
+
}
|
|
102
67
|
|
|
103
68
|
via(user: Notifiable): string[] {
|
|
104
|
-
return ['mail']
|
|
69
|
+
return ['mail', 'database']
|
|
105
70
|
}
|
|
106
71
|
|
|
107
72
|
toMail(user: Notifiable): MailMessage {
|
|
108
73
|
return {
|
|
109
74
|
subject: 'Welcome!',
|
|
110
|
-
to: user.email,
|
|
111
75
|
view: 'emails.welcome',
|
|
76
|
+
data: { name: this.name },
|
|
77
|
+
to: user.email,
|
|
112
78
|
}
|
|
113
79
|
}
|
|
114
|
-
}
|
|
115
80
|
|
|
116
|
-
|
|
81
|
+
// Define per-notification retry logic
|
|
82
|
+
retry = {
|
|
83
|
+
maxAttempts: 5,
|
|
84
|
+
backoff: 'linear' as const
|
|
85
|
+
}
|
|
86
|
+
}
|
|
117
87
|
```
|
|
118
88
|
|
|
119
|
-
|
|
89
|
+
### 3. Send a notification
|
|
120
90
|
|
|
121
|
-
|
|
91
|
+
```typescript
|
|
92
|
+
const notifications = c.get('notifications') as NotificationManager
|
|
122
93
|
|
|
123
|
-
|
|
94
|
+
// Simple send
|
|
95
|
+
const result = await notifications.send(user, new WelcomeNotification('Alice'))
|
|
124
96
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
return ['mail']
|
|
97
|
+
if (result.failed.length > 0) {
|
|
98
|
+
console.error('Some channels failed:', result.failed)
|
|
128
99
|
}
|
|
129
100
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
101
|
+
// Batch send (high performance)
|
|
102
|
+
await notifications.sendBatch(users, new SystemUpdateNotification())
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Advanced Features
|
|
106
|
+
|
|
107
|
+
### Retries
|
|
108
|
+
Configure retries globally or per-notification:
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
// Per-notification
|
|
112
|
+
class CriticalAlert extends Notification {
|
|
113
|
+
shouldRetry(attempt: number, error: Error): boolean {
|
|
114
|
+
return attempt < 5 && isRetryable(error)
|
|
136
115
|
}
|
|
137
116
|
}
|
|
138
117
|
```
|
|
139
118
|
|
|
140
|
-
###
|
|
119
|
+
### Metrics
|
|
120
|
+
Enable metrics to track success rates and latency:
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
const metrics = new NotificationMetricsCollector()
|
|
124
|
+
notifications.setMetricsCollector(metrics)
|
|
125
|
+
|
|
126
|
+
// Export to Prometheus
|
|
127
|
+
const promData = toPrometheusFormat(metrics.getSummary())
|
|
128
|
+
```
|
|
141
129
|
|
|
142
|
-
|
|
130
|
+
### Hooks
|
|
131
|
+
Listen to lifecycle events:
|
|
143
132
|
|
|
144
133
|
```typescript
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
134
|
+
notifications.on('notification:failed', ({ notification, error }) => {
|
|
135
|
+
logger.error('Notification failed completely', error)
|
|
136
|
+
})
|
|
137
|
+
```
|
|
148
138
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
139
|
+
### Templates
|
|
140
|
+
Use `TemplatedNotification` for consistent messaging:
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
class OrderShipped extends TemplatedNotification {
|
|
144
|
+
constructor(order: Order) {
|
|
145
|
+
super('order-shipped', { orderId: order.id })
|
|
153
146
|
}
|
|
154
147
|
}
|
|
155
148
|
```
|
|
156
149
|
|
|
157
|
-
###
|
|
158
|
-
|
|
159
|
-
Requires `@gravito/radiance`:
|
|
150
|
+
### Timeout Protection (v3.4.0)
|
|
151
|
+
All channels support timeout configuration to prevent slow responses from blocking notifications:
|
|
160
152
|
|
|
161
153
|
```typescript
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
154
|
+
OrbitFlare.configure({
|
|
155
|
+
channels: {
|
|
156
|
+
slack: {
|
|
157
|
+
webhookUrl: process.env.SLACK_WEBHOOK_URL,
|
|
158
|
+
timeout: 5000, // 5 秒超時
|
|
159
|
+
onTimeout: (channel, notification) => {
|
|
160
|
+
console.error(`Timeout: ${channel}`)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Rate Limiting (v3.4.0)
|
|
168
|
+
Protect downstream services with channel-level rate limiting:
|
|
165
169
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
+
```typescript
|
|
171
|
+
import { RateLimitMiddleware } from '@gravito/flare'
|
|
172
|
+
|
|
173
|
+
const rateLimiter = new RateLimitMiddleware({
|
|
174
|
+
email: {
|
|
175
|
+
maxPerSecond: 10,
|
|
176
|
+
maxPerMinute: 100,
|
|
177
|
+
maxPerHour: 1000
|
|
178
|
+
},
|
|
179
|
+
sms: {
|
|
180
|
+
maxPerSecond: 5
|
|
170
181
|
}
|
|
171
|
-
}
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
notifications.use(rateLimiter)
|
|
185
|
+
|
|
186
|
+
// 檢查狀態
|
|
187
|
+
const status = rateLimiter.getStatus('email')
|
|
188
|
+
console.log(`剩餘: ${status.second}/10`)
|
|
172
189
|
```
|
|
173
190
|
|
|
174
|
-
###
|
|
191
|
+
### Lazy Loading for Queue (v3.4.0)
|
|
192
|
+
Optimize queue serialization with Lazy Loading pattern:
|
|
175
193
|
|
|
176
194
|
```typescript
|
|
177
|
-
|
|
178
|
-
return ['slack']
|
|
179
|
-
}
|
|
195
|
+
import { LazyNotification } from '@gravito/flare'
|
|
180
196
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
197
|
+
class OrderConfirmation extends LazyNotification<Order> {
|
|
198
|
+
constructor(private orderId: string) {
|
|
199
|
+
super()
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
protected async loadData(notifiable: Notifiable): Promise<Order> {
|
|
203
|
+
return await db.orders.find(this.orderId)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
via(user: Notifiable): string[] {
|
|
207
|
+
return ['mail', 'database']
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async toMail(user: Notifiable): Promise<MailMessage> {
|
|
211
|
+
const order = await this.ensureLoaded(user)
|
|
212
|
+
return {
|
|
213
|
+
subject: `訂單確認 #${order.id}`,
|
|
214
|
+
view: 'emails.order-confirmation',
|
|
215
|
+
data: { order },
|
|
216
|
+
to: user.email,
|
|
217
|
+
}
|
|
185
218
|
}
|
|
186
219
|
}
|
|
187
220
|
```
|
|
188
221
|
|
|
189
|
-
###
|
|
222
|
+
### User Preferences (v3.4.0)
|
|
223
|
+
Respect user notification preferences automatically:
|
|
190
224
|
|
|
191
225
|
```typescript
|
|
192
|
-
|
|
193
|
-
return ['sms']
|
|
194
|
-
}
|
|
226
|
+
import { PreferenceMiddleware } from '@gravito/flare'
|
|
195
227
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
228
|
+
// 方式 1: 在 OrbitFlare 配置中啟用
|
|
229
|
+
OrbitFlare.configure({
|
|
230
|
+
enablePreference: true
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
// 方式 2: 使用自定義偏好提供者
|
|
234
|
+
const preferenceMiddleware = new PreferenceMiddleware({
|
|
235
|
+
async getUserPreferences(notifiable) {
|
|
236
|
+
const prefs = await db.userPreferences.find(notifiable.id)
|
|
237
|
+
return {
|
|
238
|
+
enabledChannels: prefs.enabledChannels,
|
|
239
|
+
disabledChannels: prefs.disabledChannels,
|
|
240
|
+
disabledNotifications: prefs.disabledNotifications
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
notifications.use(preferenceMiddleware)
|
|
246
|
+
|
|
247
|
+
// 方式 3: 在 Notifiable 物件中實作
|
|
248
|
+
class User implements Notifiable {
|
|
249
|
+
async getNotificationPreferences() {
|
|
250
|
+
return {
|
|
251
|
+
enabledChannels: ['email', 'slack'],
|
|
252
|
+
disabledChannels: ['sms']
|
|
253
|
+
}
|
|
200
254
|
}
|
|
201
255
|
}
|
|
202
256
|
```
|
|
203
257
|
|
|
204
|
-
|
|
258
|
+
### Middleware Chain (v3.4.0)
|
|
259
|
+
Combine multiple middleware for powerful notification processing:
|
|
205
260
|
|
|
206
|
-
|
|
261
|
+
```typescript
|
|
262
|
+
import { RateLimitMiddleware, PreferenceMiddleware } from '@gravito/flare'
|
|
207
263
|
|
|
208
|
-
|
|
264
|
+
// 建立中介層
|
|
265
|
+
const rateLimiter = new RateLimitMiddleware({ /* ... */ })
|
|
266
|
+
const preferenceFilter = new PreferenceMiddleware({ /* ... */ })
|
|
209
267
|
|
|
210
|
-
|
|
268
|
+
// 註冊中介層(執行順序:由內而外)
|
|
269
|
+
notifications
|
|
270
|
+
.use(rateLimiter) // 先限流
|
|
271
|
+
.use(preferenceFilter) // 後過濾
|
|
211
272
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
273
|
+
// 或在 OrbitFlare 配置中一次註冊
|
|
274
|
+
OrbitFlare.configure({
|
|
275
|
+
middleware: [rateLimiter, preferenceFilter]
|
|
276
|
+
})
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## API Reference
|
|
218
280
|
|
|
219
281
|
### NotificationManager
|
|
220
282
|
|
|
221
283
|
#### Methods
|
|
222
284
|
|
|
223
|
-
- `send(notifiable: Notifiable, notification: Notification): Promise<
|
|
224
|
-
- `
|
|
285
|
+
- `send(notifiable: Notifiable, notification: Notification, options?: SendOptions): Promise<NotificationResult>`
|
|
286
|
+
- `sendBatch(notifiables: Notifiable[], notification: Notification): Promise<BatchResult>`
|
|
287
|
+
- `sendBatchStream(iterator: AsyncIterator<Notifiable>, notification: Notification): Promise<BatchResult>`
|
|
288
|
+
|
|
289
|
+
### Notification
|
|
290
|
+
|
|
291
|
+
#### Methods
|
|
292
|
+
|
|
293
|
+
- `via(notifiable: Notifiable): string[]` - Choose delivery channels
|
|
294
|
+
- `toMail`, `toDatabase`, `toBroadcast`, `toSlack`, `toSms` - Channel payloads
|
|
295
|
+
- `shouldRetry(attempt: number, error: Error): boolean` - Custom retry logic
|
|
225
296
|
|
|
226
297
|
## License
|
|
227
298
|
|
package/README.zh-TW.md
CHANGED
|
@@ -1,35 +1,150 @@
|
|
|
1
|
-
# @gravito/flare
|
|
1
|
+
# @gravito/flare 🌌
|
|
2
2
|
|
|
3
|
-
> Gravito
|
|
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
|
|
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:
|
|
25
|
-
view: 'emails.
|
|
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
|
-
|
|
34
|
-
|
|
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
|