@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/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
- export { type BatchResult, BroadcastChannel, type BroadcastNotification, type ChannelFailurePayload, type ChannelHookPayload, type ChannelSuccessPayload, DatabaseChannel, type DatabaseNotification, MailChannel, type MailMessage, type MailTemplate, type MetricsSummary, type Notifiable, Notification, type NotificationBatchCompletePayload, type NotificationBatchStartPayload, type NotificationChannel, type NotificationCompletePayload, type NotificationHookPayload, NotificationManager, type NotificationMetric, NotificationMetricsCollector, type NotificationResult, OrbitFlare, type OrbitFlareOptions, type RetryConfig, type SendOptions, type SendResult, type ShouldQueue, type ShouldRetry, SlackChannel, type SlackChannelConfig, type SlackMessage, type SlackTemplate, SmsChannel, type SmsChannelConfig, type SmsMessage, type TemplateData, TemplatedNotification, toPrometheusFormat };
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 };