@gravito/flare 3.3.0 → 4.0.1
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 +135 -3
- package/dist/index.cjs +1036 -97
- package/dist/index.d.cts +1250 -12
- package/dist/index.d.ts +1250 -12
- package/dist/index.js +1040 -97
- package/package.json +10 -8
package/dist/index.d.cts
CHANGED
|
@@ -4,6 +4,32 @@ import { PlanetCore, GravitoOrbit } from '@gravito/core';
|
|
|
4
4
|
* Notification system type definitions.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* 支援取消的發送選項
|
|
9
|
+
*
|
|
10
|
+
* 用於在發送通知時支援 AbortController 取消功能。
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const controller = new AbortController()
|
|
15
|
+
* setTimeout(() => controller.abort(), 5000)
|
|
16
|
+
*
|
|
17
|
+
* await channel.send(notification, notifiable, {
|
|
18
|
+
* signal: controller.signal
|
|
19
|
+
* })
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
interface AbortableSendOptions {
|
|
25
|
+
/**
|
|
26
|
+
* AbortSignal 用於取消請求
|
|
27
|
+
*
|
|
28
|
+
* 當 signal 被 abort 時,底層的網路請求(如 fetch)會被取消。
|
|
29
|
+
* 這對於實作 timeout 或使用者主動取消特別有用。
|
|
30
|
+
*/
|
|
31
|
+
signal?: AbortSignal;
|
|
32
|
+
}
|
|
7
33
|
/**
|
|
8
34
|
* Notification channel interface.
|
|
9
35
|
* @public
|
|
@@ -14,8 +40,9 @@ interface NotificationChannel {
|
|
|
14
40
|
*
|
|
15
41
|
* @param notification - The notification instance containing data.
|
|
16
42
|
* @param notifiable - The recipient of the notification.
|
|
43
|
+
* @param options - Optional abort options (v4.0.0+)
|
|
17
44
|
*/
|
|
18
|
-
send(notification: Notification, notifiable: Notifiable): Promise<void>;
|
|
45
|
+
send(notification: Notification, notifiable: Notifiable, options?: AbortableSendOptions): Promise<void>;
|
|
19
46
|
}
|
|
20
47
|
/**
|
|
21
48
|
* Interface for recipients that can receive notifications.
|
|
@@ -34,6 +61,18 @@ interface Notifiable {
|
|
|
34
61
|
* Optional list of preferred channels for this specific recipient.
|
|
35
62
|
*/
|
|
36
63
|
preferredNotificationChannels?(): string[];
|
|
64
|
+
/**
|
|
65
|
+
* Optional notification preferences for this specific recipient.
|
|
66
|
+
* 取得用戶的通知偏好設定,用於控制通知的發送行為。
|
|
67
|
+
*/
|
|
68
|
+
getNotificationPreferences?(): Promise<{
|
|
69
|
+
/** 啟用的通道列表(如果設定,則只允許這些通道) */
|
|
70
|
+
enabledChannels?: string[];
|
|
71
|
+
/** 禁用的通道列表(優先於 enabledChannels) */
|
|
72
|
+
disabledChannels?: string[];
|
|
73
|
+
/** 禁用的通知類型列表(Notification class names) */
|
|
74
|
+
disabledNotifications?: string[];
|
|
75
|
+
}>;
|
|
37
76
|
}
|
|
38
77
|
/**
|
|
39
78
|
* Payload for email notifications.
|
|
@@ -223,6 +262,48 @@ interface NotificationBatchCompletePayload {
|
|
|
223
262
|
failed: number;
|
|
224
263
|
duration: number;
|
|
225
264
|
}
|
|
265
|
+
/**
|
|
266
|
+
* Notification preference provider interface.
|
|
267
|
+
*
|
|
268
|
+
* 用於提供用戶通知偏好的介面。可以從資料庫、快取或其他來源載入用戶的偏好設定。
|
|
269
|
+
*
|
|
270
|
+
* @public
|
|
271
|
+
*/
|
|
272
|
+
interface NotificationPreference {
|
|
273
|
+
/**
|
|
274
|
+
* Get user notification preferences.
|
|
275
|
+
*
|
|
276
|
+
* 獲取用戶的通知偏好設定。
|
|
277
|
+
*
|
|
278
|
+
* @param notifiable - 接收通知的用戶
|
|
279
|
+
* @returns 用戶的通知偏好設定
|
|
280
|
+
*
|
|
281
|
+
* @example
|
|
282
|
+
* ```typescript
|
|
283
|
+
* class DatabasePreferenceProvider implements NotificationPreference {
|
|
284
|
+
* async getUserPreferences(notifiable: Notifiable) {
|
|
285
|
+
* const prefs = await db.query(
|
|
286
|
+
* 'SELECT * FROM user_preferences WHERE user_id = ?',
|
|
287
|
+
* [notifiable.getNotifiableId()]
|
|
288
|
+
* )
|
|
289
|
+
* return {
|
|
290
|
+
* enabledChannels: prefs.enabled_channels,
|
|
291
|
+
* disabledChannels: prefs.disabled_channels,
|
|
292
|
+
* disabledNotifications: prefs.disabled_notifications
|
|
293
|
+
* }
|
|
294
|
+
* }
|
|
295
|
+
* }
|
|
296
|
+
* ```
|
|
297
|
+
*/
|
|
298
|
+
getUserPreferences(notifiable: Notifiable): Promise<{
|
|
299
|
+
/** 啟用的通道列表(如果設定,則只允許這些通道) */
|
|
300
|
+
enabledChannels: string[];
|
|
301
|
+
/** 禁用的通道列表(優先於 enabledChannels) */
|
|
302
|
+
disabledChannels: string[];
|
|
303
|
+
/** 禁用的通知類型列表(Notification class names) */
|
|
304
|
+
disabledNotifications: string[];
|
|
305
|
+
}>;
|
|
306
|
+
}
|
|
226
307
|
|
|
227
308
|
/**
|
|
228
309
|
* Marker interface for notifications that should be queued.
|
|
@@ -295,6 +376,19 @@ declare abstract class Notification {
|
|
|
295
376
|
};
|
|
296
377
|
}
|
|
297
378
|
|
|
379
|
+
/**
|
|
380
|
+
* Broadcast channel 配置選項。
|
|
381
|
+
*/
|
|
382
|
+
interface BroadcastChannelConfig {
|
|
383
|
+
/**
|
|
384
|
+
* Timeout duration in milliseconds. Default: 10000ms (10s).
|
|
385
|
+
*/
|
|
386
|
+
timeout?: number;
|
|
387
|
+
/**
|
|
388
|
+
* Callback function triggered when a timeout occurs.
|
|
389
|
+
*/
|
|
390
|
+
onTimeout?: (channel: string, notification: Notification) => void;
|
|
391
|
+
}
|
|
298
392
|
/**
|
|
299
393
|
* Broadcast channel.
|
|
300
394
|
*
|
|
@@ -302,12 +396,27 @@ declare abstract class Notification {
|
|
|
302
396
|
*/
|
|
303
397
|
declare class BroadcastChannel implements NotificationChannel {
|
|
304
398
|
private broadcastService;
|
|
399
|
+
private config?;
|
|
400
|
+
private timeoutChannel;
|
|
305
401
|
constructor(broadcastService: {
|
|
306
402
|
broadcast(channel: string, event: string, data: Record<string, unknown>): Promise<void>;
|
|
307
|
-
});
|
|
308
|
-
send(notification: Notification, notifiable: Notifiable): Promise<void>;
|
|
403
|
+
}, config?: BroadcastChannelConfig | undefined);
|
|
404
|
+
send(notification: Notification, notifiable: Notifiable, options?: AbortableSendOptions): Promise<void>;
|
|
309
405
|
}
|
|
310
406
|
|
|
407
|
+
/**
|
|
408
|
+
* Database channel 配置選項。
|
|
409
|
+
*/
|
|
410
|
+
interface DatabaseChannelConfig {
|
|
411
|
+
/**
|
|
412
|
+
* Timeout duration in milliseconds. Default: 10000ms (10s).
|
|
413
|
+
*/
|
|
414
|
+
timeout?: number;
|
|
415
|
+
/**
|
|
416
|
+
* Callback function triggered when a timeout occurs.
|
|
417
|
+
*/
|
|
418
|
+
onTimeout?: (channel: string, notification: Notification) => void;
|
|
419
|
+
}
|
|
311
420
|
/**
|
|
312
421
|
* Database channel.
|
|
313
422
|
*
|
|
@@ -315,6 +424,8 @@ declare class BroadcastChannel implements NotificationChannel {
|
|
|
315
424
|
*/
|
|
316
425
|
declare class DatabaseChannel implements NotificationChannel {
|
|
317
426
|
private dbService;
|
|
427
|
+
private config?;
|
|
428
|
+
private timeoutChannel;
|
|
318
429
|
constructor(dbService: {
|
|
319
430
|
insertNotification(data: {
|
|
320
431
|
notifiableId: string | number;
|
|
@@ -322,10 +433,23 @@ declare class DatabaseChannel implements NotificationChannel {
|
|
|
322
433
|
type: string;
|
|
323
434
|
data: Record<string, unknown>;
|
|
324
435
|
}): Promise<void>;
|
|
325
|
-
});
|
|
326
|
-
send(notification: Notification, notifiable: Notifiable): Promise<void>;
|
|
436
|
+
}, config?: DatabaseChannelConfig | undefined);
|
|
437
|
+
send(notification: Notification, notifiable: Notifiable, options?: AbortableSendOptions): Promise<void>;
|
|
327
438
|
}
|
|
328
439
|
|
|
440
|
+
/**
|
|
441
|
+
* Mail channel 配置選項。
|
|
442
|
+
*/
|
|
443
|
+
interface MailChannelConfig {
|
|
444
|
+
/**
|
|
445
|
+
* Timeout duration in milliseconds. Default: 30000ms (30s).
|
|
446
|
+
*/
|
|
447
|
+
timeout?: number;
|
|
448
|
+
/**
|
|
449
|
+
* Callback function triggered when a timeout occurs.
|
|
450
|
+
*/
|
|
451
|
+
onTimeout?: (channel: string, notification: Notification) => void;
|
|
452
|
+
}
|
|
329
453
|
/**
|
|
330
454
|
* Mail channel.
|
|
331
455
|
*
|
|
@@ -333,10 +457,12 @@ declare class DatabaseChannel implements NotificationChannel {
|
|
|
333
457
|
*/
|
|
334
458
|
declare class MailChannel implements NotificationChannel {
|
|
335
459
|
private mailService;
|
|
460
|
+
private config?;
|
|
461
|
+
private timeoutChannel;
|
|
336
462
|
constructor(mailService: {
|
|
337
463
|
send(message: MailMessage): Promise<void>;
|
|
338
|
-
});
|
|
339
|
-
send(notification: Notification, notifiable: Notifiable): Promise<void>;
|
|
464
|
+
}, config?: MailChannelConfig | undefined);
|
|
465
|
+
send(notification: Notification, notifiable: Notifiable, options?: AbortableSendOptions): Promise<void>;
|
|
340
466
|
}
|
|
341
467
|
|
|
342
468
|
/**
|
|
@@ -345,6 +471,14 @@ declare class MailChannel implements NotificationChannel {
|
|
|
345
471
|
interface SlackChannelConfig {
|
|
346
472
|
webhookUrl: string;
|
|
347
473
|
defaultChannel?: string;
|
|
474
|
+
/**
|
|
475
|
+
* Timeout 時間(毫秒),預設 30000ms (30秒)。
|
|
476
|
+
*/
|
|
477
|
+
timeout?: number;
|
|
478
|
+
/**
|
|
479
|
+
* Timeout 發生時的回調函數。
|
|
480
|
+
*/
|
|
481
|
+
onTimeout?: (channel: string, notification: Notification) => void;
|
|
348
482
|
}
|
|
349
483
|
/**
|
|
350
484
|
* Slack channel.
|
|
@@ -353,8 +487,9 @@ interface SlackChannelConfig {
|
|
|
353
487
|
*/
|
|
354
488
|
declare class SlackChannel implements NotificationChannel {
|
|
355
489
|
private config;
|
|
490
|
+
private timeoutChannel;
|
|
356
491
|
constructor(config: SlackChannelConfig);
|
|
357
|
-
send(notification: Notification, notifiable: Notifiable): Promise<void>;
|
|
492
|
+
send(notification: Notification, notifiable: Notifiable, options?: AbortableSendOptions): Promise<void>;
|
|
358
493
|
}
|
|
359
494
|
|
|
360
495
|
/**
|
|
@@ -368,6 +503,14 @@ interface SmsChannelConfig {
|
|
|
368
503
|
region?: string;
|
|
369
504
|
accessKeyId?: string;
|
|
370
505
|
secretAccessKey?: string;
|
|
506
|
+
/**
|
|
507
|
+
* Timeout duration in milliseconds. Default: 30000ms (30s).
|
|
508
|
+
*/
|
|
509
|
+
timeout?: number;
|
|
510
|
+
/**
|
|
511
|
+
* Callback function triggered when a timeout occurs.
|
|
512
|
+
*/
|
|
513
|
+
onTimeout?: (channel: string, notification: Notification) => void;
|
|
371
514
|
}
|
|
372
515
|
/**
|
|
373
516
|
* SMS channel.
|
|
@@ -376,18 +519,94 @@ interface SmsChannelConfig {
|
|
|
376
519
|
*/
|
|
377
520
|
declare class SmsChannel implements NotificationChannel {
|
|
378
521
|
private config;
|
|
522
|
+
private timeoutChannel;
|
|
379
523
|
constructor(config: SmsChannelConfig);
|
|
380
|
-
send(notification: Notification, notifiable: Notifiable): Promise<void>;
|
|
524
|
+
send(notification: Notification, notifiable: Notifiable, options?: AbortableSendOptions): Promise<void>;
|
|
381
525
|
/**
|
|
382
|
-
* Send SMS via Twilio.
|
|
526
|
+
* Send SMS via Twilio with AbortSignal support.
|
|
383
527
|
*/
|
|
384
528
|
private sendViaTwilio;
|
|
385
529
|
/**
|
|
386
|
-
* Send SMS via AWS SNS.
|
|
530
|
+
* Send SMS via AWS SNS with AbortSignal support.
|
|
387
531
|
*/
|
|
388
532
|
private sendViaAwsSns;
|
|
389
533
|
}
|
|
390
534
|
|
|
535
|
+
/**
|
|
536
|
+
* Configuration options for TimeoutChannel.
|
|
537
|
+
*/
|
|
538
|
+
interface TimeoutConfig {
|
|
539
|
+
/**
|
|
540
|
+
* Timeout duration in milliseconds.
|
|
541
|
+
*/
|
|
542
|
+
timeout: number;
|
|
543
|
+
/**
|
|
544
|
+
* Optional callback function triggered when a timeout occurs.
|
|
545
|
+
*
|
|
546
|
+
* @param channel - The name of the channel that timed out.
|
|
547
|
+
* @param notification - The notification instance that was being sent.
|
|
548
|
+
*/
|
|
549
|
+
onTimeout?: (channel: string, notification: Notification) => void;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Exception thrown when a notification send operation exceeds the configured timeout.
|
|
553
|
+
*/
|
|
554
|
+
declare class TimeoutError extends Error {
|
|
555
|
+
constructor(message: string);
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Exception thrown when a request is aborted by an external AbortController signal.
|
|
559
|
+
*/
|
|
560
|
+
declare class AbortError extends Error {
|
|
561
|
+
constructor(message: string);
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Decorator for notification channels that adds timeout and cancellation support.
|
|
565
|
+
*
|
|
566
|
+
* Implements actual request cancellation using AbortController and Promise.race.
|
|
567
|
+
* Compatible with v4.0.0+ cancellation architecture.
|
|
568
|
+
*
|
|
569
|
+
* @example
|
|
570
|
+
* ```typescript
|
|
571
|
+
* const slackChannel = new SlackChannel(config);
|
|
572
|
+
* const timeoutChannel = new TimeoutChannel(slackChannel, {
|
|
573
|
+
* timeout: 5000,
|
|
574
|
+
* onTimeout: (channel, notification) => {
|
|
575
|
+
* console.error(`Channel ${channel} timed out`);
|
|
576
|
+
* }
|
|
577
|
+
* });
|
|
578
|
+
*
|
|
579
|
+
* // Send with timeout
|
|
580
|
+
* await timeoutChannel.send(notification, user);
|
|
581
|
+
*
|
|
582
|
+
* // Support external manual abort
|
|
583
|
+
* const controller = new AbortController();
|
|
584
|
+
* setTimeout(() => controller.abort(), 3000);
|
|
585
|
+
* await timeoutChannel.send(notification, user, { signal: controller.signal });
|
|
586
|
+
* ```
|
|
587
|
+
*
|
|
588
|
+
* @remarks
|
|
589
|
+
* In v4.0.0, this class uses AbortController to allow underlying fetch requests
|
|
590
|
+
* to be physically cancelled, while using Promise.race to ensure the timeout
|
|
591
|
+
* error is thrown immediately without waiting for the underlying request to finish.
|
|
592
|
+
*/
|
|
593
|
+
declare class TimeoutChannel implements NotificationChannel {
|
|
594
|
+
private inner;
|
|
595
|
+
private config;
|
|
596
|
+
constructor(inner: NotificationChannel, config: TimeoutConfig);
|
|
597
|
+
/**
|
|
598
|
+
* Sends a notification through the inner channel with a timeout guard.
|
|
599
|
+
*
|
|
600
|
+
* @param notification - The notification to send.
|
|
601
|
+
* @param notifiable - The recipient of the notification.
|
|
602
|
+
* @param options - Send options including an optional AbortSignal.
|
|
603
|
+
* @returns A promise that resolves when the notification is sent.
|
|
604
|
+
* @throws {TimeoutError} Thrown if the operation exceeds the configured timeout.
|
|
605
|
+
* @throws {AbortError} Thrown if the operation is aborted via the provided signal.
|
|
606
|
+
*/
|
|
607
|
+
send(notification: Notification, notifiable: Notifiable, options?: AbortableSendOptions): Promise<void>;
|
|
608
|
+
}
|
|
609
|
+
|
|
391
610
|
interface NotificationMetric {
|
|
392
611
|
notification: string;
|
|
393
612
|
channel: string;
|
|
@@ -428,6 +647,478 @@ declare class NotificationMetricsCollector {
|
|
|
428
647
|
|
|
429
648
|
declare function toPrometheusFormat(summary: MetricsSummary): string;
|
|
430
649
|
|
|
650
|
+
/**
|
|
651
|
+
* Middleware type definitions for notification channels.
|
|
652
|
+
*
|
|
653
|
+
* 中介層允許在通知發送前後執行自訂邏輯,例如:
|
|
654
|
+
* - 限流(Rate Limiting)
|
|
655
|
+
* - 日誌記錄
|
|
656
|
+
* - 資料轉換
|
|
657
|
+
* - 權限檢查
|
|
658
|
+
* - 錯誤處理
|
|
659
|
+
*
|
|
660
|
+
* @packageDocumentation
|
|
661
|
+
*/
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* 中介層優先級常數
|
|
665
|
+
*
|
|
666
|
+
* 提供預定義的優先級值,用於控制中介層的執行順序。
|
|
667
|
+
* 優先級越高(數字越大)越先執行。
|
|
668
|
+
*
|
|
669
|
+
* @example
|
|
670
|
+
* ```typescript
|
|
671
|
+
* const securityMiddleware: ChannelMiddleware = {
|
|
672
|
+
* name: 'security',
|
|
673
|
+
* priority: MiddlewarePriority.SECURITY, // 最高優先級,最先執行
|
|
674
|
+
* async handle(notification, notifiable, channel, next) {
|
|
675
|
+
* // 安全檢查...
|
|
676
|
+
* await next()
|
|
677
|
+
* }
|
|
678
|
+
* }
|
|
679
|
+
* ```
|
|
680
|
+
*
|
|
681
|
+
* @public
|
|
682
|
+
*/
|
|
683
|
+
declare const MiddlewarePriority: {
|
|
684
|
+
/** 最高優先級:安全檢查 (100) */
|
|
685
|
+
readonly SECURITY: 100;
|
|
686
|
+
/** 高優先級:限流 (80) */
|
|
687
|
+
readonly RATE_LIMIT: 80;
|
|
688
|
+
/** 中等優先級:驗證 (50) */
|
|
689
|
+
readonly VALIDATION: 50;
|
|
690
|
+
/** 預設優先級 (0) */
|
|
691
|
+
readonly DEFAULT: 0;
|
|
692
|
+
/** 低優先級:日誌記錄 (-50) */
|
|
693
|
+
readonly LOGGING: -50;
|
|
694
|
+
/** 最低優先級:監控 (-100) */
|
|
695
|
+
readonly MONITORING: -100;
|
|
696
|
+
};
|
|
697
|
+
/**
|
|
698
|
+
* 中介層優先級值型別
|
|
699
|
+
*
|
|
700
|
+
* @public
|
|
701
|
+
*/
|
|
702
|
+
type MiddlewarePriorityValue = (typeof MiddlewarePriority)[keyof typeof MiddlewarePriority];
|
|
703
|
+
/**
|
|
704
|
+
* Channel middleware interface.
|
|
705
|
+
*
|
|
706
|
+
* 中介層提供一個統一的擴展機制,允許在通知發送到特定通道時執行額外的邏輯。
|
|
707
|
+
* 中介層可以:
|
|
708
|
+
* - 在發送前檢查或修改通知
|
|
709
|
+
* - 決定是否允許發送(透過是否呼叫 next)
|
|
710
|
+
* - 在發送後執行清理或記錄操作
|
|
711
|
+
*
|
|
712
|
+
* @example
|
|
713
|
+
* ```typescript
|
|
714
|
+
* // 建立一個記錄中介層
|
|
715
|
+
* const loggingMiddleware: ChannelMiddleware = {
|
|
716
|
+
* name: 'logging',
|
|
717
|
+
* async handle(notification, notifiable, channel, next) {
|
|
718
|
+
* console.log(`Sending ${notification.constructor.name} via ${channel}`)
|
|
719
|
+
* await next()
|
|
720
|
+
* console.log(`Sent successfully`)
|
|
721
|
+
* }
|
|
722
|
+
* }
|
|
723
|
+
*
|
|
724
|
+
* // 註冊到 NotificationManager
|
|
725
|
+
* manager.use(loggingMiddleware)
|
|
726
|
+
* ```
|
|
727
|
+
*
|
|
728
|
+
* @public
|
|
729
|
+
*/
|
|
730
|
+
interface ChannelMiddleware {
|
|
731
|
+
/**
|
|
732
|
+
* Middleware name (for debugging and identification).
|
|
733
|
+
*
|
|
734
|
+
* 中介層名稱,用於除錯和識別。
|
|
735
|
+
*/
|
|
736
|
+
name: string;
|
|
737
|
+
/**
|
|
738
|
+
* Middleware priority (optional, default: 0).
|
|
739
|
+
*
|
|
740
|
+
* 中介層優先級,數字越大越先執行。
|
|
741
|
+
* 預設為 0。相同優先級的中介層按照註冊順序執行。
|
|
742
|
+
*
|
|
743
|
+
* @default 0
|
|
744
|
+
*
|
|
745
|
+
* @example
|
|
746
|
+
* ```typescript
|
|
747
|
+
* // 安全檢查應該最先執行
|
|
748
|
+
* const securityMiddleware: ChannelMiddleware = {
|
|
749
|
+
* name: 'security',
|
|
750
|
+
* priority: MiddlewarePriority.SECURITY, // 100
|
|
751
|
+
* async handle(notification, notifiable, channel, next) {
|
|
752
|
+
* // 檢查權限...
|
|
753
|
+
* await next()
|
|
754
|
+
* }
|
|
755
|
+
* }
|
|
756
|
+
*
|
|
757
|
+
* // 限流應該在安全檢查之後
|
|
758
|
+
* const rateLimitMiddleware: ChannelMiddleware = {
|
|
759
|
+
* name: 'rate-limit',
|
|
760
|
+
* priority: MiddlewarePriority.RATE_LIMIT, // 80
|
|
761
|
+
* async handle(notification, notifiable, channel, next) {
|
|
762
|
+
* // 檢查限流...
|
|
763
|
+
* await next()
|
|
764
|
+
* }
|
|
765
|
+
* }
|
|
766
|
+
*
|
|
767
|
+
* // 日誌記錄應該最後執行
|
|
768
|
+
* const loggingMiddleware: ChannelMiddleware = {
|
|
769
|
+
* name: 'logging',
|
|
770
|
+
* priority: MiddlewarePriority.LOGGING, // -50
|
|
771
|
+
* async handle(notification, notifiable, channel, next) {
|
|
772
|
+
* console.log('Sending...')
|
|
773
|
+
* await next()
|
|
774
|
+
* console.log('Sent!')
|
|
775
|
+
* }
|
|
776
|
+
* }
|
|
777
|
+
* ```
|
|
778
|
+
*/
|
|
779
|
+
priority?: number;
|
|
780
|
+
/**
|
|
781
|
+
* Handle the notification before it's sent to the channel.
|
|
782
|
+
*
|
|
783
|
+
* 處理通知發送請求。此方法會在通知發送到通道之前被呼叫。
|
|
784
|
+
*
|
|
785
|
+
* @param notification - The notification instance being sent
|
|
786
|
+
* @param notifiable - The recipient of the notification
|
|
787
|
+
* @param channel - The channel name (e.g., 'mail', 'sms')
|
|
788
|
+
* @param next - Call this function to continue the middleware chain and send the notification
|
|
789
|
+
*
|
|
790
|
+
* @throws {Error} 可以拋出錯誤來阻止通知發送
|
|
791
|
+
*
|
|
792
|
+
* @example
|
|
793
|
+
* ```typescript
|
|
794
|
+
* async handle(notification, notifiable, channel, next) {
|
|
795
|
+
* // 發送前的邏輯
|
|
796
|
+
* if (shouldBlock(channel)) {
|
|
797
|
+
* throw new Error('Channel blocked')
|
|
798
|
+
* }
|
|
799
|
+
*
|
|
800
|
+
* // 繼續執行
|
|
801
|
+
* await next()
|
|
802
|
+
*
|
|
803
|
+
* // 發送後的邏輯
|
|
804
|
+
* console.log('Sent successfully')
|
|
805
|
+
* }
|
|
806
|
+
* ```
|
|
807
|
+
*/
|
|
808
|
+
handle(notification: Notification, notifiable: Notifiable, channel: string, next: () => Promise<void>): Promise<void>;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
/**
|
|
812
|
+
* User preference middleware for notification channels.
|
|
813
|
+
*
|
|
814
|
+
* This middleware filters notification channels and notification types based on user settings,
|
|
815
|
+
* allowing users to customize how they receive notifications.
|
|
816
|
+
*
|
|
817
|
+
* @packageDocumentation
|
|
818
|
+
*/
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* User preference middleware for filtering notification channels.
|
|
822
|
+
*
|
|
823
|
+
* This middleware filters notifications based on user preferences, supporting:
|
|
824
|
+
* - Enabling specific channels (enabledChannels)
|
|
825
|
+
* - Disabling specific channels (disabledChannels, takes precedence over enabledChannels)
|
|
826
|
+
* - Disabling specific notification types (disabledNotifications)
|
|
827
|
+
*
|
|
828
|
+
* @example
|
|
829
|
+
* ```typescript
|
|
830
|
+
* // Using Notifiable preferences
|
|
831
|
+
* const middleware = new PreferenceMiddleware();
|
|
832
|
+
* manager.use(middleware);
|
|
833
|
+
*
|
|
834
|
+
* // Using custom preference provider
|
|
835
|
+
* const dbProvider: NotificationPreference = {
|
|
836
|
+
* async getUserPreferences(notifiable) {
|
|
837
|
+
* return await db.getUserPrefs(notifiable.getNotifiableId());
|
|
838
|
+
* }
|
|
839
|
+
* };
|
|
840
|
+
* const middleware = new PreferenceMiddleware(dbProvider);
|
|
841
|
+
* manager.use(middleware);
|
|
842
|
+
* ```
|
|
843
|
+
*
|
|
844
|
+
* @public
|
|
845
|
+
*/
|
|
846
|
+
declare class PreferenceMiddleware implements ChannelMiddleware {
|
|
847
|
+
private preferenceProvider?;
|
|
848
|
+
private logger?;
|
|
849
|
+
/**
|
|
850
|
+
* Middleware name.
|
|
851
|
+
*/
|
|
852
|
+
readonly name = "preference";
|
|
853
|
+
/**
|
|
854
|
+
* Middleware priority (medium priority for validation).
|
|
855
|
+
*/
|
|
856
|
+
readonly priority: 50;
|
|
857
|
+
/**
|
|
858
|
+
* Create a new PreferenceMiddleware instance.
|
|
859
|
+
*
|
|
860
|
+
* @param preferenceProvider - Optional preference provider; uses Notifiable method if not provided.
|
|
861
|
+
* @param logger - Optional logger instance for recording errors.
|
|
862
|
+
*
|
|
863
|
+
* @example
|
|
864
|
+
* ```typescript
|
|
865
|
+
* // Without provider (reads from Notifiable.getNotificationPreferences)
|
|
866
|
+
* const middleware = new PreferenceMiddleware();
|
|
867
|
+
*
|
|
868
|
+
* // Using database provider and logger
|
|
869
|
+
* const middleware = new PreferenceMiddleware(new DatabasePreferenceProvider(), logger);
|
|
870
|
+
* ```
|
|
871
|
+
*/
|
|
872
|
+
constructor(preferenceProvider?: NotificationPreference | undefined, logger?: {
|
|
873
|
+
error: (message: string, ...args: unknown[]) => void;
|
|
874
|
+
} | undefined);
|
|
875
|
+
/**
|
|
876
|
+
* Handle the notification and apply user preference filtering.
|
|
877
|
+
*
|
|
878
|
+
* Processes the notification and filters based on user preferences:
|
|
879
|
+
* 1. If notification type is in disabledNotifications, it is skipped.
|
|
880
|
+
* 2. If channel is in disabledChannels, it is skipped.
|
|
881
|
+
* 3. If enabledChannels is set, only channels in that list are allowed.
|
|
882
|
+
* 4. If preference loading fails, the notification is allowed as a fallback.
|
|
883
|
+
*
|
|
884
|
+
* @param notification - The notification to send.
|
|
885
|
+
* @param notifiable - The recipient.
|
|
886
|
+
* @param channel - The channel name.
|
|
887
|
+
* @param next - Callback to proceed to the next middleware or send operation.
|
|
888
|
+
* @returns A promise that resolves when processing is complete.
|
|
889
|
+
*/
|
|
890
|
+
handle(notification: Notification, notifiable: Notifiable, channel: string, next: () => Promise<void>): Promise<void>;
|
|
891
|
+
/**
|
|
892
|
+
* Get user preferences from Notifiable or custom provider.
|
|
893
|
+
*
|
|
894
|
+
* Priority: Notifiable.getNotificationPreferences > preferenceProvider.
|
|
895
|
+
*
|
|
896
|
+
* @param notifiable - The recipient.
|
|
897
|
+
* @returns The user preferences or null if not found.
|
|
898
|
+
*/
|
|
899
|
+
private getPreferences;
|
|
900
|
+
/**
|
|
901
|
+
* Check if notification type is disabled by user.
|
|
902
|
+
*
|
|
903
|
+
* @param notification - The notification instance.
|
|
904
|
+
* @param preferences - User preferences.
|
|
905
|
+
* @returns True if the notification is disabled.
|
|
906
|
+
*/
|
|
907
|
+
private isNotificationDisabled;
|
|
908
|
+
/**
|
|
909
|
+
* Check if channel is allowed by user preferences.
|
|
910
|
+
*
|
|
911
|
+
* Priority:
|
|
912
|
+
* 1. disabledChannels (if listed, it is denied)
|
|
913
|
+
* 2. enabledChannels (if set, only listed are allowed)
|
|
914
|
+
* 3. Allow all if neither are set.
|
|
915
|
+
*
|
|
916
|
+
* @param channel - The channel name.
|
|
917
|
+
* @param preferences - User preferences.
|
|
918
|
+
* @returns True if the channel is allowed.
|
|
919
|
+
*/
|
|
920
|
+
private isChannelAllowed;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
/**
|
|
924
|
+
* Rate limiting middleware for notification channels.
|
|
925
|
+
*
|
|
926
|
+
* 此中介層使用 Token Bucket 演算法對不同的通知通道進行限流,
|
|
927
|
+
* 防止短時間內發送過多通知,保護下游服務。
|
|
928
|
+
*
|
|
929
|
+
* @packageDocumentation
|
|
930
|
+
*/
|
|
931
|
+
|
|
932
|
+
/**
|
|
933
|
+
* Rate limit configuration for a specific channel.
|
|
934
|
+
*
|
|
935
|
+
* 通道限流配置,支援多個時間窗口的限流。
|
|
936
|
+
*
|
|
937
|
+
* @public
|
|
938
|
+
*/
|
|
939
|
+
interface ChannelRateLimitConfig {
|
|
940
|
+
/**
|
|
941
|
+
* Maximum requests per second.
|
|
942
|
+
* 每秒最大請求數
|
|
943
|
+
*/
|
|
944
|
+
maxPerSecond?: number;
|
|
945
|
+
/**
|
|
946
|
+
* Maximum requests per minute.
|
|
947
|
+
* 每分鐘最大請求數
|
|
948
|
+
*/
|
|
949
|
+
maxPerMinute?: number;
|
|
950
|
+
/**
|
|
951
|
+
* Maximum requests per hour.
|
|
952
|
+
* 每小時最大請求數
|
|
953
|
+
*/
|
|
954
|
+
maxPerHour?: number;
|
|
955
|
+
}
|
|
956
|
+
/**
|
|
957
|
+
* Rate limit configuration for all channels.
|
|
958
|
+
*
|
|
959
|
+
* 所有通道的限流配置,key 為通道名稱。
|
|
960
|
+
*
|
|
961
|
+
* @public
|
|
962
|
+
*/
|
|
963
|
+
interface RateLimitConfig {
|
|
964
|
+
[channel: string]: ChannelRateLimitConfig;
|
|
965
|
+
}
|
|
966
|
+
/**
|
|
967
|
+
* Cache store interface for rate limiting.
|
|
968
|
+
*
|
|
969
|
+
* 快取儲存介面,用於支援分散式限流。
|
|
970
|
+
* 預設使用記憶體儲存,可替換為 Redis 等分散式快取。
|
|
971
|
+
*
|
|
972
|
+
* @public
|
|
973
|
+
*/
|
|
974
|
+
interface CacheStore {
|
|
975
|
+
get<T>(key: string): Promise<T | null>;
|
|
976
|
+
put<T>(key: string, value: T, ttl: number): Promise<void>;
|
|
977
|
+
forget(key: string): Promise<void>;
|
|
978
|
+
}
|
|
979
|
+
/**
|
|
980
|
+
* Simple in-memory cache store implementation.
|
|
981
|
+
*
|
|
982
|
+
* 簡單的記憶體快取實作,用於單機環境。
|
|
983
|
+
* 生產環境建議使用 Redis 等分散式快取。
|
|
984
|
+
*
|
|
985
|
+
* @public
|
|
986
|
+
*/
|
|
987
|
+
declare class MemoryStore implements CacheStore {
|
|
988
|
+
private cache;
|
|
989
|
+
private cleanupInterval?;
|
|
990
|
+
constructor(cleanupIntervalMs?: number);
|
|
991
|
+
get<T>(key: string): Promise<T | null>;
|
|
992
|
+
put<T>(key: string, value: T, ttl: number): Promise<void>;
|
|
993
|
+
forget(key: string): Promise<void>;
|
|
994
|
+
/**
|
|
995
|
+
* 清理所有資源,停止清理計時器
|
|
996
|
+
*/
|
|
997
|
+
destroy(): void;
|
|
998
|
+
}
|
|
999
|
+
/**
|
|
1000
|
+
* Rate limiting middleware using Token Bucket algorithm.
|
|
1001
|
+
*
|
|
1002
|
+
* 此中介層為每個通道維護獨立的 Token Bucket,
|
|
1003
|
+
* 支援每秒、每分鐘、每小時三種時間窗口的限流。
|
|
1004
|
+
*
|
|
1005
|
+
* @example
|
|
1006
|
+
* ```typescript
|
|
1007
|
+
* const rateLimiter = new RateLimitMiddleware({
|
|
1008
|
+
* email: {
|
|
1009
|
+
* maxPerSecond: 10,
|
|
1010
|
+
* maxPerMinute: 100,
|
|
1011
|
+
* maxPerHour: 1000
|
|
1012
|
+
* },
|
|
1013
|
+
* sms: {
|
|
1014
|
+
* maxPerSecond: 5,
|
|
1015
|
+
* maxPerMinute: 50
|
|
1016
|
+
* }
|
|
1017
|
+
* })
|
|
1018
|
+
*
|
|
1019
|
+
* manager.use(rateLimiter)
|
|
1020
|
+
* ```
|
|
1021
|
+
*
|
|
1022
|
+
* @public
|
|
1023
|
+
*/
|
|
1024
|
+
declare class RateLimitMiddleware implements ChannelMiddleware {
|
|
1025
|
+
private config;
|
|
1026
|
+
/**
|
|
1027
|
+
* Middleware name.
|
|
1028
|
+
*/
|
|
1029
|
+
readonly name = "rate-limit";
|
|
1030
|
+
/**
|
|
1031
|
+
* Middleware priority (high priority, executes early in the chain).
|
|
1032
|
+
* 中介層優先級(高優先級,在鏈中較早執行)
|
|
1033
|
+
*/
|
|
1034
|
+
readonly priority: 80;
|
|
1035
|
+
/**
|
|
1036
|
+
* Token buckets for each channel and time window.
|
|
1037
|
+
* Key format: `{channel}:{window}` (e.g., 'email:second', 'sms:minute')
|
|
1038
|
+
*/
|
|
1039
|
+
private buckets;
|
|
1040
|
+
/**
|
|
1041
|
+
* Cache store for distributed rate limiting.
|
|
1042
|
+
* 分散式限流使用的快取儲存
|
|
1043
|
+
*/
|
|
1044
|
+
private store;
|
|
1045
|
+
/**
|
|
1046
|
+
* Create a new RateLimitMiddleware instance.
|
|
1047
|
+
*
|
|
1048
|
+
* @param config - Rate limit configuration for each channel
|
|
1049
|
+
* @param store - Optional cache store for distributed rate limiting
|
|
1050
|
+
*
|
|
1051
|
+
* @example
|
|
1052
|
+
* ```typescript
|
|
1053
|
+
* // 使用預設記憶體儲存
|
|
1054
|
+
* const middleware = new RateLimitMiddleware({
|
|
1055
|
+
* email: { maxPerSecond: 10 }
|
|
1056
|
+
* })
|
|
1057
|
+
*
|
|
1058
|
+
* // 使用 Redis 儲存(分散式環境)
|
|
1059
|
+
* const middleware = new RateLimitMiddleware({
|
|
1060
|
+
* email: { maxPerSecond: 10 }
|
|
1061
|
+
* }, redisStore)
|
|
1062
|
+
* ```
|
|
1063
|
+
*/
|
|
1064
|
+
constructor(config: RateLimitConfig, store?: CacheStore);
|
|
1065
|
+
/**
|
|
1066
|
+
* Initialize token buckets for all configured channels.
|
|
1067
|
+
*
|
|
1068
|
+
* 為所有配置的通道初始化 Token Bucket。
|
|
1069
|
+
*
|
|
1070
|
+
* @private
|
|
1071
|
+
*/
|
|
1072
|
+
private initializeBuckets;
|
|
1073
|
+
/**
|
|
1074
|
+
* Handle the notification and apply rate limiting.
|
|
1075
|
+
*
|
|
1076
|
+
* 處理通知並應用限流規則。如果超過任一時間窗口的限制,
|
|
1077
|
+
* 將拋出錯誤阻止通知發送。
|
|
1078
|
+
*
|
|
1079
|
+
* @param notification - The notification being sent
|
|
1080
|
+
* @param notifiable - The recipient
|
|
1081
|
+
* @param channel - The channel name
|
|
1082
|
+
* @param next - Continue to the next middleware or send the notification
|
|
1083
|
+
*
|
|
1084
|
+
* @throws {Error} 當超過限流時拋出錯誤
|
|
1085
|
+
*/
|
|
1086
|
+
handle(_notification: Notification, _notifiable: Notifiable, channel: string, next: () => Promise<void>): Promise<void>;
|
|
1087
|
+
/**
|
|
1088
|
+
* Get current rate limit status for a channel.
|
|
1089
|
+
*
|
|
1090
|
+
* 獲取指定通道的當前限流狀態(用於除錯和監控)。
|
|
1091
|
+
*
|
|
1092
|
+
* @param channel - The channel name
|
|
1093
|
+
* @returns Current token counts for each time window
|
|
1094
|
+
*
|
|
1095
|
+
* @example
|
|
1096
|
+
* ```typescript
|
|
1097
|
+
* const status = middleware.getStatus('email')
|
|
1098
|
+
* console.log(`Email remaining: ${status.second}/${config.email.maxPerSecond}`)
|
|
1099
|
+
* ```
|
|
1100
|
+
*/
|
|
1101
|
+
getStatus(channel: string): {
|
|
1102
|
+
second?: number;
|
|
1103
|
+
minute?: number;
|
|
1104
|
+
hour?: number;
|
|
1105
|
+
};
|
|
1106
|
+
/**
|
|
1107
|
+
* Reset rate limit for a specific channel.
|
|
1108
|
+
*
|
|
1109
|
+
* 重置指定通道的限流計數(用於測試或手動重置)。
|
|
1110
|
+
*
|
|
1111
|
+
* @param channel - The channel name to reset
|
|
1112
|
+
*
|
|
1113
|
+
* @example
|
|
1114
|
+
* ```typescript
|
|
1115
|
+
* // 在測試中重置限流
|
|
1116
|
+
* middleware.reset('email')
|
|
1117
|
+
* ```
|
|
1118
|
+
*/
|
|
1119
|
+
reset(channel: string): void;
|
|
1120
|
+
}
|
|
1121
|
+
|
|
431
1122
|
/**
|
|
432
1123
|
* Notification manager.
|
|
433
1124
|
*
|
|
@@ -439,10 +1130,22 @@ declare class NotificationManager {
|
|
|
439
1130
|
* Channel registry.
|
|
440
1131
|
*/
|
|
441
1132
|
private channels;
|
|
1133
|
+
/**
|
|
1134
|
+
* Middleware stack for intercepting channel sends.
|
|
1135
|
+
*/
|
|
1136
|
+
private middlewares;
|
|
1137
|
+
/**
|
|
1138
|
+
* Indicates whether the middleware stack needs re-sorting.
|
|
1139
|
+
*/
|
|
1140
|
+
private middlewaresDirty;
|
|
442
1141
|
/**
|
|
443
1142
|
* Queue manager (optional, injected by `orbit-queue`).
|
|
444
1143
|
*/
|
|
445
1144
|
private queueManager?;
|
|
1145
|
+
/**
|
|
1146
|
+
* Type-safe hook emitter for notification events.
|
|
1147
|
+
*/
|
|
1148
|
+
private hookEmitter;
|
|
446
1149
|
constructor(core: PlanetCore);
|
|
447
1150
|
private metrics?;
|
|
448
1151
|
/**
|
|
@@ -464,6 +1167,27 @@ declare class NotificationManager {
|
|
|
464
1167
|
* @param channel - The channel instance.
|
|
465
1168
|
*/
|
|
466
1169
|
channel(name: string, channel: NotificationChannel): void;
|
|
1170
|
+
/**
|
|
1171
|
+
* Register a middleware for intercepting channel sends.
|
|
1172
|
+
*
|
|
1173
|
+
* Middleware will be executed in the order they are registered.
|
|
1174
|
+
* Each middleware can modify, block, or monitor the notification flow.
|
|
1175
|
+
*
|
|
1176
|
+
* @param middleware - The middleware instance to register.
|
|
1177
|
+
*
|
|
1178
|
+
* @example
|
|
1179
|
+
* ```typescript
|
|
1180
|
+
* import { RateLimitMiddleware } from '@gravito/flare'
|
|
1181
|
+
*
|
|
1182
|
+
* const rateLimiter = new RateLimitMiddleware({
|
|
1183
|
+
* email: { maxPerSecond: 10 },
|
|
1184
|
+
* sms: { maxPerSecond: 5 }
|
|
1185
|
+
* })
|
|
1186
|
+
*
|
|
1187
|
+
* manager.use(rateLimiter)
|
|
1188
|
+
* ```
|
|
1189
|
+
*/
|
|
1190
|
+
use(middleware: ChannelMiddleware): void;
|
|
467
1191
|
/**
|
|
468
1192
|
* Register the queue manager (called by `orbit-queue`).
|
|
469
1193
|
*
|
|
@@ -518,6 +1242,30 @@ declare class NotificationManager {
|
|
|
518
1242
|
private processWithConcurrency;
|
|
519
1243
|
private sendToChannel;
|
|
520
1244
|
private executeChannelSend;
|
|
1245
|
+
/**
|
|
1246
|
+
* Retrieves the sorted list of middleware (Lazy sorting).
|
|
1247
|
+
*
|
|
1248
|
+
* Uses a lazy evaluation strategy: sorting only happens when needed to avoid
|
|
1249
|
+
* overhead on every `use()` call.
|
|
1250
|
+
* Sorting rules:
|
|
1251
|
+
* 1. Higher priority (larger number) executes first.
|
|
1252
|
+
* 2. Stable sort is maintained for identical priorities (registration order).
|
|
1253
|
+
*
|
|
1254
|
+
* @returns The sorted list of middleware.
|
|
1255
|
+
* @private
|
|
1256
|
+
*/
|
|
1257
|
+
private getSortedMiddlewares;
|
|
1258
|
+
/**
|
|
1259
|
+
* Execute middleware chain recursively.
|
|
1260
|
+
*
|
|
1261
|
+
* @param index - Current middleware index
|
|
1262
|
+
* @param notification - The notification being sent
|
|
1263
|
+
* @param notifiable - The recipient
|
|
1264
|
+
* @param channelName - The channel name
|
|
1265
|
+
* @param finalHandler - The final handler to execute (actual channel.send)
|
|
1266
|
+
* @private
|
|
1267
|
+
*/
|
|
1268
|
+
private executeMiddlewareChain;
|
|
521
1269
|
private getRetryConfig;
|
|
522
1270
|
/**
|
|
523
1271
|
* Serialize notification (for queuing).
|
|
@@ -545,6 +1293,12 @@ interface OrbitFlareOptions {
|
|
|
545
1293
|
enableSms?: boolean;
|
|
546
1294
|
/** Custom channel configuration records for flexible extension. */
|
|
547
1295
|
channels?: Record<string, unknown>;
|
|
1296
|
+
/** Channel middleware to apply to all notifications. */
|
|
1297
|
+
middleware?: ChannelMiddleware[];
|
|
1298
|
+
/** Custom notification preference provider. */
|
|
1299
|
+
preferenceProvider?: NotificationPreference;
|
|
1300
|
+
/** Enable automatic preference filtering middleware (default: false). */
|
|
1301
|
+
enablePreference?: boolean;
|
|
548
1302
|
}
|
|
549
1303
|
/**
|
|
550
1304
|
* OrbitFlare is the official notification orbit for Gravito.
|
|
@@ -588,6 +1342,7 @@ declare class OrbitFlare implements GravitoOrbit {
|
|
|
588
1342
|
private setupSlackChannel;
|
|
589
1343
|
private setupSmsChannel;
|
|
590
1344
|
private setupQueueIntegration;
|
|
1345
|
+
private setupMiddleware;
|
|
591
1346
|
private isMailService;
|
|
592
1347
|
private isDatabaseService;
|
|
593
1348
|
private isBroadcastService;
|
|
@@ -628,4 +1383,487 @@ declare abstract class TemplatedNotification extends Notification {
|
|
|
628
1383
|
private getRecipientEmail;
|
|
629
1384
|
}
|
|
630
1385
|
|
|
631
|
-
|
|
1386
|
+
/**
|
|
1387
|
+
* FlareHooks 型別定義
|
|
1388
|
+
*
|
|
1389
|
+
* 提供型別安全的 hook 事件系統,包含所有通知相關的 hook 事件和 payload 型別。
|
|
1390
|
+
*
|
|
1391
|
+
* @packageDocumentation
|
|
1392
|
+
*/
|
|
1393
|
+
|
|
1394
|
+
/**
|
|
1395
|
+
* FlareHooks 事件名稱列舉
|
|
1396
|
+
*
|
|
1397
|
+
* 包含所有通知系統支援的 hook 事件。
|
|
1398
|
+
*
|
|
1399
|
+
* @public
|
|
1400
|
+
*/
|
|
1401
|
+
type FlareHookEvent = 'notification:sending' | 'notification:queued' | 'notification:sent' | 'notification:channel:sending' | 'notification:channel:sent' | 'notification:channel:failed' | 'notification:channel:retry' | 'notification:batch:start' | 'notification:batch:complete';
|
|
1402
|
+
/**
|
|
1403
|
+
* 各 hook 事件的 Payload 型別映射
|
|
1404
|
+
*
|
|
1405
|
+
* 定義每個 hook 事件對應的 payload 結構,提供完整的型別安全。
|
|
1406
|
+
*
|
|
1407
|
+
* @example
|
|
1408
|
+
* ```typescript
|
|
1409
|
+
* // 監聽通知發送事件
|
|
1410
|
+
* hooks.on('notification:sending', (payload: FlareHookPayloads['notification:sending']) => {
|
|
1411
|
+
* console.log(`Sending ${payload.notification.constructor.name} to ${payload.notifiable.getNotifiableId()}`)
|
|
1412
|
+
* })
|
|
1413
|
+
* ```
|
|
1414
|
+
*
|
|
1415
|
+
* @public
|
|
1416
|
+
*/
|
|
1417
|
+
interface FlareHookPayloads {
|
|
1418
|
+
/**
|
|
1419
|
+
* 通知開始發送前觸發
|
|
1420
|
+
*/
|
|
1421
|
+
'notification:sending': {
|
|
1422
|
+
/** 要發送的通知實例 */
|
|
1423
|
+
notification: Notification;
|
|
1424
|
+
/** 接收通知的對象 */
|
|
1425
|
+
notifiable: Notifiable;
|
|
1426
|
+
/** 要發送的通道列表 */
|
|
1427
|
+
channels: string[];
|
|
1428
|
+
};
|
|
1429
|
+
/**
|
|
1430
|
+
* 通知被加入佇列時觸發
|
|
1431
|
+
*/
|
|
1432
|
+
'notification:queued': {
|
|
1433
|
+
/** 要發送的通知實例 */
|
|
1434
|
+
notification: Notification;
|
|
1435
|
+
/** 接收通知的對象 */
|
|
1436
|
+
notifiable: Notifiable;
|
|
1437
|
+
/** 要發送的通道列表 */
|
|
1438
|
+
channels: string[];
|
|
1439
|
+
};
|
|
1440
|
+
/**
|
|
1441
|
+
* 通知發送完成後觸發
|
|
1442
|
+
*/
|
|
1443
|
+
'notification:sent': {
|
|
1444
|
+
/** 已發送的通知實例 */
|
|
1445
|
+
notification: Notification;
|
|
1446
|
+
/** 接收通知的對象 */
|
|
1447
|
+
notifiable: Notifiable;
|
|
1448
|
+
/** 各通道的發送結果 */
|
|
1449
|
+
results: SendResult[];
|
|
1450
|
+
/** 是否所有通道都發送成功 */
|
|
1451
|
+
allSuccess: boolean;
|
|
1452
|
+
/** 總執行時間(毫秒) */
|
|
1453
|
+
totalDuration: number;
|
|
1454
|
+
};
|
|
1455
|
+
/**
|
|
1456
|
+
* 通道開始發送前觸發
|
|
1457
|
+
*/
|
|
1458
|
+
'notification:channel:sending': {
|
|
1459
|
+
/** 要發送的通知實例 */
|
|
1460
|
+
notification: Notification;
|
|
1461
|
+
/** 接收通知的對象 */
|
|
1462
|
+
notifiable: Notifiable;
|
|
1463
|
+
/** 通道名稱 */
|
|
1464
|
+
channel: string;
|
|
1465
|
+
};
|
|
1466
|
+
/**
|
|
1467
|
+
* 通道發送成功後觸發
|
|
1468
|
+
*/
|
|
1469
|
+
'notification:channel:sent': {
|
|
1470
|
+
/** 已發送的通知實例 */
|
|
1471
|
+
notification: Notification;
|
|
1472
|
+
/** 接收通知的對象 */
|
|
1473
|
+
notifiable: Notifiable;
|
|
1474
|
+
/** 通道名稱 */
|
|
1475
|
+
channel: string;
|
|
1476
|
+
/** 發送耗時(毫秒) */
|
|
1477
|
+
duration: number;
|
|
1478
|
+
};
|
|
1479
|
+
/**
|
|
1480
|
+
* 通道發送失敗時觸發
|
|
1481
|
+
*/
|
|
1482
|
+
'notification:channel:failed': {
|
|
1483
|
+
/** 發送失敗的通知實例 */
|
|
1484
|
+
notification: Notification;
|
|
1485
|
+
/** 接收通知的對象 */
|
|
1486
|
+
notifiable: Notifiable;
|
|
1487
|
+
/** 通道名稱 */
|
|
1488
|
+
channel: string;
|
|
1489
|
+
/** 錯誤物件 */
|
|
1490
|
+
error: Error;
|
|
1491
|
+
/** 發送耗時(毫秒) */
|
|
1492
|
+
duration: number;
|
|
1493
|
+
};
|
|
1494
|
+
/**
|
|
1495
|
+
* 通道重試時觸發
|
|
1496
|
+
*/
|
|
1497
|
+
'notification:channel:retry': {
|
|
1498
|
+
/** 要重試的通知實例 */
|
|
1499
|
+
notification: Notification;
|
|
1500
|
+
/** 接收通知的對象 */
|
|
1501
|
+
notifiable: Notifiable;
|
|
1502
|
+
/** 通道名稱 */
|
|
1503
|
+
channel: string;
|
|
1504
|
+
/** 錯誤物件 */
|
|
1505
|
+
error: Error;
|
|
1506
|
+
/** 當前重試次數 */
|
|
1507
|
+
attempt: number;
|
|
1508
|
+
/** 下次重試延遲(毫秒) */
|
|
1509
|
+
nextDelay: number;
|
|
1510
|
+
};
|
|
1511
|
+
/**
|
|
1512
|
+
* 批次發送開始時觸發
|
|
1513
|
+
*/
|
|
1514
|
+
'notification:batch:start': {
|
|
1515
|
+
/** 要發送的通知實例 */
|
|
1516
|
+
notification: Notification;
|
|
1517
|
+
/** 接收者數量 */
|
|
1518
|
+
count: number;
|
|
1519
|
+
};
|
|
1520
|
+
/**
|
|
1521
|
+
* 批次發送完成時觸發
|
|
1522
|
+
*/
|
|
1523
|
+
'notification:batch:complete': {
|
|
1524
|
+
/** 已發送的通知實例 */
|
|
1525
|
+
notification: Notification;
|
|
1526
|
+
/** 總接收者數量 */
|
|
1527
|
+
total: number;
|
|
1528
|
+
/** 成功數量 */
|
|
1529
|
+
success: number;
|
|
1530
|
+
/** 失敗數量 */
|
|
1531
|
+
failed: number;
|
|
1532
|
+
/** 總執行時間(毫秒) */
|
|
1533
|
+
duration: number;
|
|
1534
|
+
};
|
|
1535
|
+
}
|
|
1536
|
+
/**
|
|
1537
|
+
* FlareHooks 介面
|
|
1538
|
+
*
|
|
1539
|
+
* 提供型別安全的 hook 系統介面,用於發送和監聽通知事件。
|
|
1540
|
+
*
|
|
1541
|
+
* @remarks
|
|
1542
|
+
* 此介面主要用於型別檢查,實際的 hook 系統由 @gravito/core 提供。
|
|
1543
|
+
*
|
|
1544
|
+
* @example
|
|
1545
|
+
* ```typescript
|
|
1546
|
+
* // 發送型別安全的 hook 事件
|
|
1547
|
+
* const emitter = createHookEmitter(core)
|
|
1548
|
+
* await emitter.emit('notification:sending', {
|
|
1549
|
+
* notification,
|
|
1550
|
+
* notifiable,
|
|
1551
|
+
* channels: ['mail', 'sms']
|
|
1552
|
+
* })
|
|
1553
|
+
* ```
|
|
1554
|
+
*
|
|
1555
|
+
* @public
|
|
1556
|
+
*/
|
|
1557
|
+
interface FlareHooks {
|
|
1558
|
+
/**
|
|
1559
|
+
* 發送 hook 事件
|
|
1560
|
+
*
|
|
1561
|
+
* @param event - 事件名稱
|
|
1562
|
+
* @param payload - 事件 payload,型別由事件名稱決定
|
|
1563
|
+
*/
|
|
1564
|
+
emit<E extends FlareHookEvent>(event: E, payload: FlareHookPayloads[E]): Promise<void>;
|
|
1565
|
+
/**
|
|
1566
|
+
* 監聽 hook 事件
|
|
1567
|
+
*
|
|
1568
|
+
* @param event - 事件名稱
|
|
1569
|
+
* @param handler - 事件處理函數
|
|
1570
|
+
*/
|
|
1571
|
+
on<E extends FlareHookEvent>(event: E, handler: (payload: FlareHookPayloads[E]) => void): void;
|
|
1572
|
+
/**
|
|
1573
|
+
* 移除 hook 事件監聽器
|
|
1574
|
+
*
|
|
1575
|
+
* @param event - 事件名稱
|
|
1576
|
+
* @param handler - 要移除的事件處理函數
|
|
1577
|
+
*/
|
|
1578
|
+
off<E extends FlareHookEvent>(event: E, handler: (payload: FlareHookPayloads[E]) => void): void;
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
/**
|
|
1582
|
+
* Hook Emitter 輔助工具
|
|
1583
|
+
*
|
|
1584
|
+
* 提供型別安全的 hook emit 功能,封裝底層 @gravito/core 的 hooks 系統。
|
|
1585
|
+
*
|
|
1586
|
+
* @packageDocumentation
|
|
1587
|
+
*/
|
|
1588
|
+
|
|
1589
|
+
/**
|
|
1590
|
+
* 型別安全的 Hook Emitter
|
|
1591
|
+
*
|
|
1592
|
+
* 封裝 PlanetCore 的 hooks.emit,提供完整的型別檢查和 IntelliSense 支援。
|
|
1593
|
+
*
|
|
1594
|
+
* @public
|
|
1595
|
+
*/
|
|
1596
|
+
interface HookEmitter {
|
|
1597
|
+
/**
|
|
1598
|
+
* 發送 hook 事件
|
|
1599
|
+
*
|
|
1600
|
+
* @param event - 事件名稱
|
|
1601
|
+
* @param payload - 事件 payload,型別由事件名稱決定
|
|
1602
|
+
* @returns Promise,在所有監聽器執行完成後 resolve
|
|
1603
|
+
*
|
|
1604
|
+
* @example
|
|
1605
|
+
* ```typescript
|
|
1606
|
+
* const emitter = createHookEmitter(core)
|
|
1607
|
+
* await emitter.emit('notification:sending', {
|
|
1608
|
+
* notification,
|
|
1609
|
+
* notifiable,
|
|
1610
|
+
* channels: ['mail', 'sms']
|
|
1611
|
+
* })
|
|
1612
|
+
* ```
|
|
1613
|
+
*/
|
|
1614
|
+
emit<E extends FlareHookEvent>(event: E, payload: FlareHookPayloads[E]): Promise<void>;
|
|
1615
|
+
}
|
|
1616
|
+
/**
|
|
1617
|
+
* 建立型別安全的 hook emitter
|
|
1618
|
+
*
|
|
1619
|
+
* 將 PlanetCore 的 hooks 系統包裝成型別安全的 emitter,
|
|
1620
|
+
* 避免在 NotificationManager 中使用 `any` 型別斷言。
|
|
1621
|
+
*
|
|
1622
|
+
* @param core - PlanetCore 實例
|
|
1623
|
+
* @returns 型別安全的 HookEmitter 實例
|
|
1624
|
+
*
|
|
1625
|
+
* @example
|
|
1626
|
+
* ```typescript
|
|
1627
|
+
* export class NotificationManager {
|
|
1628
|
+
* private hookEmitter: HookEmitter
|
|
1629
|
+
*
|
|
1630
|
+
* constructor(private core: PlanetCore) {
|
|
1631
|
+
* this.hookEmitter = createHookEmitter(core)
|
|
1632
|
+
* }
|
|
1633
|
+
*
|
|
1634
|
+
* async send(notifiable: Notifiable, notification: Notification) {
|
|
1635
|
+
* await this.hookEmitter.emit('notification:sending', {
|
|
1636
|
+
* notification,
|
|
1637
|
+
* notifiable,
|
|
1638
|
+
* channels: notification.via(notifiable)
|
|
1639
|
+
* })
|
|
1640
|
+
* // ...
|
|
1641
|
+
* }
|
|
1642
|
+
* }
|
|
1643
|
+
* ```
|
|
1644
|
+
*
|
|
1645
|
+
* @public
|
|
1646
|
+
*/
|
|
1647
|
+
declare function createHookEmitter(core: PlanetCore): HookEmitter;
|
|
1648
|
+
|
|
1649
|
+
/**
|
|
1650
|
+
* Lazy Loading 通知基類
|
|
1651
|
+
*
|
|
1652
|
+
* 用於處理包含大量資料或需要資料庫查詢的通知。
|
|
1653
|
+
* 只儲存識別符 (ID),在需要時才載入完整資料。
|
|
1654
|
+
*
|
|
1655
|
+
* @typeParam TData - 載入的資料型別
|
|
1656
|
+
*
|
|
1657
|
+
* @example
|
|
1658
|
+
* ```typescript
|
|
1659
|
+
* class InvoicePaidNotification extends LazyNotification<Invoice> {
|
|
1660
|
+
* constructor(private invoiceId: string) {
|
|
1661
|
+
* super()
|
|
1662
|
+
* }
|
|
1663
|
+
*
|
|
1664
|
+
* protected async loadData(notifiable: Notifiable): Promise<Invoice> {
|
|
1665
|
+
* return await db.invoices.findById(this.invoiceId)
|
|
1666
|
+
* }
|
|
1667
|
+
*
|
|
1668
|
+
* toMail(notifiable: Notifiable): MailMessage {
|
|
1669
|
+
* const invoice = this.getCached()
|
|
1670
|
+
* if (!invoice) {
|
|
1671
|
+
* throw new Error('Invoice data not loaded')
|
|
1672
|
+
* }
|
|
1673
|
+
* return {
|
|
1674
|
+
* subject: `Invoice #${invoice.number} paid`,
|
|
1675
|
+
* text: `Amount: ${invoice.amount}`
|
|
1676
|
+
* }
|
|
1677
|
+
* }
|
|
1678
|
+
* }
|
|
1679
|
+
* ```
|
|
1680
|
+
*/
|
|
1681
|
+
declare abstract class LazyNotification<TData> extends Notification {
|
|
1682
|
+
/**
|
|
1683
|
+
* 快取的資料
|
|
1684
|
+
*/
|
|
1685
|
+
private _cachedData?;
|
|
1686
|
+
/**
|
|
1687
|
+
* 載入資料的抽象方法(由子類實作)
|
|
1688
|
+
*
|
|
1689
|
+
* @param notifiable - 通知接收者
|
|
1690
|
+
* @returns 載入的資料
|
|
1691
|
+
*/
|
|
1692
|
+
protected abstract loadData(notifiable: Notifiable): Promise<TData>;
|
|
1693
|
+
/**
|
|
1694
|
+
* 取得快取的資料
|
|
1695
|
+
*
|
|
1696
|
+
* @returns 快取的資料,如果尚未載入則回傳 undefined
|
|
1697
|
+
*/
|
|
1698
|
+
protected getCached(): TData | undefined;
|
|
1699
|
+
/**
|
|
1700
|
+
* 設定快取資料
|
|
1701
|
+
*
|
|
1702
|
+
* @param data - 要快取的資料
|
|
1703
|
+
*/
|
|
1704
|
+
protected setCached(data: TData): void;
|
|
1705
|
+
/**
|
|
1706
|
+
* 檢查資料是否已載入
|
|
1707
|
+
*
|
|
1708
|
+
* @returns 如果資料已快取則回傳 true
|
|
1709
|
+
*/
|
|
1710
|
+
protected isLoaded(): boolean;
|
|
1711
|
+
/**
|
|
1712
|
+
* 清除快取
|
|
1713
|
+
*/
|
|
1714
|
+
protected clearCache(): void;
|
|
1715
|
+
/**
|
|
1716
|
+
* 載入資料並快取(如果尚未載入)
|
|
1717
|
+
*
|
|
1718
|
+
* @param notifiable - 通知接收者
|
|
1719
|
+
* @returns 載入的資料
|
|
1720
|
+
*/
|
|
1721
|
+
protected ensureLoaded(notifiable: Notifiable): Promise<TData>;
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
/**
|
|
1725
|
+
* Deep serialize object, handling special types.
|
|
1726
|
+
*/
|
|
1727
|
+
declare function deepSerialize(obj: unknown, seen?: WeakSet<WeakKey>): unknown;
|
|
1728
|
+
/**
|
|
1729
|
+
* Deserialize object, restoring special types.
|
|
1730
|
+
*/
|
|
1731
|
+
declare function deepDeserialize(obj: unknown): unknown;
|
|
1732
|
+
|
|
1733
|
+
/**
|
|
1734
|
+
* 序列化檢查結果介面
|
|
1735
|
+
*/
|
|
1736
|
+
interface SerializationCheckResult {
|
|
1737
|
+
/** 是否可安全序列化 */
|
|
1738
|
+
serializable: boolean;
|
|
1739
|
+
/** 有問題的屬性路徑列表 */
|
|
1740
|
+
problematicPaths: string[];
|
|
1741
|
+
/** 警告訊息列表 */
|
|
1742
|
+
warnings: string[];
|
|
1743
|
+
}
|
|
1744
|
+
/**
|
|
1745
|
+
* 檢查物件是否可安全序列化
|
|
1746
|
+
*
|
|
1747
|
+
* @param obj - 要檢查的物件
|
|
1748
|
+
* @param path - 當前路徑(用於巢狀物件追蹤)
|
|
1749
|
+
* @returns 序列化檢查結果
|
|
1750
|
+
*
|
|
1751
|
+
* @example
|
|
1752
|
+
* ```typescript
|
|
1753
|
+
* const result = checkSerializable({ name: 'test', fn: () => {} })
|
|
1754
|
+
* console.log(result.serializable) // false
|
|
1755
|
+
* console.log(result.problematicPaths) // ['fn']
|
|
1756
|
+
* ```
|
|
1757
|
+
*/
|
|
1758
|
+
declare function checkSerializable(obj: unknown, path?: string): SerializationCheckResult;
|
|
1759
|
+
/**
|
|
1760
|
+
* 斷言物件可序列化,不可序列化時拋出錯誤
|
|
1761
|
+
*
|
|
1762
|
+
* @param obj - 要檢查的物件
|
|
1763
|
+
* @throws {Error} 當物件不可序列化時
|
|
1764
|
+
*
|
|
1765
|
+
* @example
|
|
1766
|
+
* ```typescript
|
|
1767
|
+
* assertSerializable({ name: 'test' }) // OK
|
|
1768
|
+
* assertSerializable({ fn: () => {} }) // 拋出錯誤
|
|
1769
|
+
* ```
|
|
1770
|
+
*/
|
|
1771
|
+
declare function assertSerializable(obj: unknown): void;
|
|
1772
|
+
|
|
1773
|
+
/**
|
|
1774
|
+
* Simple Token Bucket algorithm for rate limiting.
|
|
1775
|
+
*
|
|
1776
|
+
* Token Bucket 是一種常用的限流演算法,用於控制請求頻率。
|
|
1777
|
+
* 它透過一個固定容量的桶來存儲 tokens,並以固定速率補充。
|
|
1778
|
+
* 每個請求需要消耗一個或多個 tokens,當桶內 tokens 不足時請求被拒絕。
|
|
1779
|
+
*
|
|
1780
|
+
* @example
|
|
1781
|
+
* ```typescript
|
|
1782
|
+
* // 創建一個容量為 10,每秒補充 5 個 tokens 的桶
|
|
1783
|
+
* const bucket = new TokenBucket(10, 5)
|
|
1784
|
+
*
|
|
1785
|
+
* // 嘗試消耗 1 個 token
|
|
1786
|
+
* if (bucket.tryConsume()) {
|
|
1787
|
+
* // 請求被允許
|
|
1788
|
+
* } else {
|
|
1789
|
+
* // 請求被限流
|
|
1790
|
+
* }
|
|
1791
|
+
* ```
|
|
1792
|
+
*
|
|
1793
|
+
* @public
|
|
1794
|
+
*/
|
|
1795
|
+
declare class TokenBucket {
|
|
1796
|
+
private capacity;
|
|
1797
|
+
private refillRate;
|
|
1798
|
+
/**
|
|
1799
|
+
* 當前可用的 tokens 數量
|
|
1800
|
+
*/
|
|
1801
|
+
private tokens;
|
|
1802
|
+
/**
|
|
1803
|
+
* 上次補充 tokens 的時間戳(毫秒)
|
|
1804
|
+
*/
|
|
1805
|
+
private lastRefill;
|
|
1806
|
+
/**
|
|
1807
|
+
* 創建一個新的 TokenBucket 實例
|
|
1808
|
+
*
|
|
1809
|
+
* @param capacity - 桶的最大容量(tokens 上限)
|
|
1810
|
+
* @param refillRate - 每秒補充的 tokens 數量
|
|
1811
|
+
*
|
|
1812
|
+
* @example
|
|
1813
|
+
* ```typescript
|
|
1814
|
+
* // 每秒最多 100 個請求
|
|
1815
|
+
* const bucket = new TokenBucket(100, 100)
|
|
1816
|
+
* ```
|
|
1817
|
+
*/
|
|
1818
|
+
constructor(capacity: number, refillRate: number);
|
|
1819
|
+
/**
|
|
1820
|
+
* 嘗試從桶中消耗指定數量的 tokens
|
|
1821
|
+
*
|
|
1822
|
+
* 此方法會先執行 token 補充,然後檢查是否有足夠的 tokens。
|
|
1823
|
+
* 如果有足夠的 tokens,則消耗並返回 true;否則返回 false 且不消耗。
|
|
1824
|
+
*
|
|
1825
|
+
* @param tokens - 要消耗的 tokens 數量(預設為 1)
|
|
1826
|
+
* @returns 如果成功消耗則返回 true,否則返回 false
|
|
1827
|
+
*
|
|
1828
|
+
* @example
|
|
1829
|
+
* ```typescript
|
|
1830
|
+
* const bucket = new TokenBucket(10, 1)
|
|
1831
|
+
*
|
|
1832
|
+
* // 嘗試消耗 1 個 token
|
|
1833
|
+
* if (bucket.tryConsume()) {
|
|
1834
|
+
* console.log('請求被允許')
|
|
1835
|
+
* }
|
|
1836
|
+
*
|
|
1837
|
+
* // 嘗試消耗 3 個 tokens
|
|
1838
|
+
* if (bucket.tryConsume(3)) {
|
|
1839
|
+
* console.log('批次請求被允許')
|
|
1840
|
+
* }
|
|
1841
|
+
* ```
|
|
1842
|
+
*/
|
|
1843
|
+
tryConsume(tokens?: number): boolean;
|
|
1844
|
+
/**
|
|
1845
|
+
* 獲取當前可用的 tokens 數量
|
|
1846
|
+
*
|
|
1847
|
+
* 此方法會先執行補充操作,然後返回當前的 tokens 數量。
|
|
1848
|
+
*
|
|
1849
|
+
* @returns 當前可用的 tokens 數量
|
|
1850
|
+
*
|
|
1851
|
+
* @example
|
|
1852
|
+
* ```typescript
|
|
1853
|
+
* const bucket = new TokenBucket(10, 1)
|
|
1854
|
+
* console.log(`剩餘 ${bucket.getTokens()} 個 tokens`)
|
|
1855
|
+
* ```
|
|
1856
|
+
*/
|
|
1857
|
+
getTokens(): number;
|
|
1858
|
+
/**
|
|
1859
|
+
* 根據經過的時間補充 tokens
|
|
1860
|
+
*
|
|
1861
|
+
* 此方法計算自上次補充以來經過的時間,並根據 refillRate 補充相應數量的 tokens。
|
|
1862
|
+
* tokens 數量不會超過容量上限。
|
|
1863
|
+
*
|
|
1864
|
+
* @private
|
|
1865
|
+
*/
|
|
1866
|
+
private refill;
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
export { AbortError, type BatchResult, BroadcastChannel, type BroadcastNotification, type CacheStore, type ChannelFailurePayload, type ChannelHookPayload, type ChannelMiddleware, type ChannelRateLimitConfig, type ChannelSuccessPayload, DatabaseChannel, type DatabaseNotification, type FlareHookEvent, type FlareHookPayloads, type FlareHooks, type HookEmitter, LazyNotification, MailChannel, type MailChannelConfig, type MailMessage, type MailTemplate, MemoryStore, type MetricsSummary, MiddlewarePriority, type MiddlewarePriorityValue, type Notifiable, Notification, type NotificationBatchCompletePayload, type NotificationBatchStartPayload, type NotificationChannel, type NotificationCompletePayload, type NotificationHookPayload, NotificationManager, type NotificationMetric, NotificationMetricsCollector, type NotificationPreference, type NotificationResult, OrbitFlare, type OrbitFlareOptions, PreferenceMiddleware, type RateLimitConfig, RateLimitMiddleware, type RetryConfig, type SendOptions, type SendResult, type SerializationCheckResult, type ShouldQueue, type ShouldRetry, SlackChannel, type SlackChannelConfig, type SlackMessage, type SlackTemplate, SmsChannel, type SmsChannelConfig, type SmsMessage, type TemplateData, TemplatedNotification, TimeoutChannel, type TimeoutConfig, TimeoutError, TokenBucket, assertSerializable, checkSerializable, createHookEmitter, deepDeserialize, deepSerialize, toPrometheusFormat };
|