@skoolite/notify-hub 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1080 @@
1
+ import { CountryCode } from 'libphonenumber-js';
2
+
3
+ /**
4
+ * Notification channels supported by NotifyHub
5
+ */
6
+ type Channel = 'sms' | 'whatsapp' | 'email';
7
+ /**
8
+ * Message delivery status
9
+ */
10
+ type MessageStatus = 'queued' | 'sent' | 'delivered' | 'read' | 'failed' | 'undelivered' | 'unknown';
11
+ /**
12
+ * Result of sending a notification
13
+ */
14
+ interface SendResult {
15
+ /** Whether the send operation succeeded */
16
+ success: boolean;
17
+ /** Provider-specific message ID */
18
+ messageId?: string;
19
+ /** Channel used for sending */
20
+ channel: Channel;
21
+ /** Current message status */
22
+ status: MessageStatus;
23
+ /** Provider that was used */
24
+ provider: string;
25
+ /** Error details if failed */
26
+ error?: NotifyError;
27
+ /** Cost information if available */
28
+ cost?: Cost;
29
+ /** Timestamp of the send operation */
30
+ timestamp: Date;
31
+ /** Additional metadata */
32
+ metadata?: Record<string, unknown>;
33
+ }
34
+ /**
35
+ * Error information
36
+ */
37
+ interface NotifyError {
38
+ /** Error code from provider or internal */
39
+ code: string;
40
+ /** Human-readable error message */
41
+ message: string;
42
+ /** Whether this error is retriable */
43
+ retriable: boolean;
44
+ /** Original error from provider */
45
+ originalError?: unknown;
46
+ }
47
+ /**
48
+ * Cost information for a message
49
+ */
50
+ interface Cost {
51
+ /** Amount in the smallest currency unit */
52
+ amount: number;
53
+ /** Currency code (e.g., 'USD', 'PKR') */
54
+ currency: string;
55
+ }
56
+ /**
57
+ * Result of bulk sending operation
58
+ */
59
+ interface BulkResult {
60
+ /** Individual results for each message */
61
+ results: SendResult[];
62
+ /** Summary statistics */
63
+ summary: BulkSummary;
64
+ }
65
+ /**
66
+ * Summary of bulk operation
67
+ */
68
+ interface BulkSummary {
69
+ /** Total messages attempted */
70
+ total: number;
71
+ /** Successfully sent count */
72
+ sent: number;
73
+ /** Failed count */
74
+ failed: number;
75
+ /** Total cost if available */
76
+ cost?: Cost;
77
+ /** Duration in milliseconds */
78
+ durationMs: number;
79
+ }
80
+ /**
81
+ * Options for bulk sending
82
+ */
83
+ interface BulkOptions {
84
+ /** Rate limiting configuration */
85
+ rateLimit?: RateLimitConfig;
86
+ /** Progress callback */
87
+ onProgress?: (sent: number, total: number) => void;
88
+ /** Whether to stop on first error */
89
+ stopOnError?: boolean;
90
+ /** Maximum concurrent sends */
91
+ concurrency?: number;
92
+ }
93
+ /**
94
+ * Rate limiting configuration
95
+ */
96
+ interface RateLimitConfig {
97
+ /** Maximum messages per second */
98
+ messagesPerSecond: number;
99
+ }
100
+ /**
101
+ * Base provider interface
102
+ */
103
+ interface BaseProvider {
104
+ /** Provider name */
105
+ readonly name: string;
106
+ /** Initialize the provider */
107
+ initialize?(): Promise<void>;
108
+ /** Cleanup resources */
109
+ destroy?(): Promise<void>;
110
+ }
111
+ /**
112
+ * SMS provider interface
113
+ */
114
+ interface SmsProvider extends BaseProvider {
115
+ /**
116
+ * Send an SMS message
117
+ * @param to Phone number in E.164 format
118
+ * @param message Message content
119
+ * @param options Additional options
120
+ */
121
+ send(to: string, message: string, options?: SmsOptions): Promise<SendResult>;
122
+ /**
123
+ * Get delivery status of a message
124
+ * @param messageId Provider-specific message ID
125
+ */
126
+ getStatus?(messageId: string): Promise<MessageStatus>;
127
+ /**
128
+ * Send bulk SMS messages
129
+ * @param messages Array of messages to send
130
+ * @param options Bulk options
131
+ */
132
+ sendBulk?(messages: SmsMessage[], options?: BulkOptions): Promise<BulkResult>;
133
+ }
134
+ /**
135
+ * SMS message for bulk sending
136
+ */
137
+ interface SmsMessage {
138
+ /** Phone number in E.164 format */
139
+ to: string;
140
+ /** Message content */
141
+ message: string;
142
+ /** Additional metadata */
143
+ metadata?: Record<string, unknown>;
144
+ }
145
+ /**
146
+ * SMS sending options
147
+ */
148
+ interface SmsOptions {
149
+ /** Sender ID or phone number */
150
+ from?: string;
151
+ /** Additional metadata */
152
+ metadata?: Record<string, unknown>;
153
+ }
154
+ /**
155
+ * WhatsApp provider interface
156
+ */
157
+ interface WhatsAppProvider extends BaseProvider {
158
+ /**
159
+ * Send a text message (within 24hr window)
160
+ * @param to Phone number in E.164 format
161
+ * @param message Message content
162
+ */
163
+ sendText(to: string, message: string, options?: WhatsAppOptions): Promise<SendResult>;
164
+ /**
165
+ * Send a template message
166
+ * @param to Phone number in E.164 format
167
+ * @param template Template configuration
168
+ */
169
+ sendTemplate(to: string, template: WhatsAppTemplate, options?: WhatsAppOptions): Promise<SendResult>;
170
+ /**
171
+ * Get delivery status of a message
172
+ * @param messageId Provider-specific message ID
173
+ */
174
+ getStatus?(messageId: string): Promise<MessageStatus>;
175
+ }
176
+ /**
177
+ * WhatsApp template configuration
178
+ */
179
+ interface WhatsAppTemplate {
180
+ /** Template name as registered with Meta */
181
+ name: string;
182
+ /** Template language code (e.g., 'en', 'en_US') */
183
+ language: string;
184
+ /** Template variables (positional or named) */
185
+ variables?: Record<string, string> | string[];
186
+ /** Header parameters */
187
+ header?: WhatsAppTemplateHeader;
188
+ /** Button parameters */
189
+ buttons?: WhatsAppTemplateButton[];
190
+ }
191
+ /**
192
+ * WhatsApp template header
193
+ */
194
+ interface WhatsAppTemplateHeader {
195
+ type: 'text' | 'image' | 'document' | 'video';
196
+ /** URL for media types */
197
+ url?: string;
198
+ /** Text for text type */
199
+ text?: string;
200
+ }
201
+ /**
202
+ * WhatsApp template button
203
+ */
204
+ interface WhatsAppTemplateButton {
205
+ type: 'url' | 'quick_reply';
206
+ index: number;
207
+ payload?: string;
208
+ }
209
+ /**
210
+ * WhatsApp sending options
211
+ */
212
+ interface WhatsAppOptions {
213
+ /** Additional metadata */
214
+ metadata?: Record<string, unknown>;
215
+ }
216
+ /**
217
+ * WhatsApp message for bulk sending
218
+ */
219
+ interface WhatsAppMessage {
220
+ /** Phone number in E.164 format */
221
+ to: string;
222
+ /** Text message (for text type) */
223
+ message?: string;
224
+ /** Template configuration (for template type) */
225
+ template?: WhatsAppTemplate;
226
+ /** Additional metadata */
227
+ metadata?: Record<string, unknown>;
228
+ }
229
+ /**
230
+ * Email provider interface
231
+ */
232
+ interface EmailProvider extends BaseProvider {
233
+ /**
234
+ * Send an email
235
+ * @param to Recipient email address
236
+ * @param email Email content
237
+ */
238
+ send(to: string, email: EmailMessage, options?: EmailOptions): Promise<SendResult>;
239
+ /**
240
+ * Send to multiple recipients
241
+ * @param messages Array of email messages
242
+ * @param options Bulk options
243
+ */
244
+ sendBulk?(messages: EmailMessageWithRecipient[], options?: BulkOptions): Promise<BulkResult>;
245
+ }
246
+ /**
247
+ * Email message content
248
+ */
249
+ interface EmailMessage {
250
+ /** Email subject */
251
+ subject: string;
252
+ /** Plain text body */
253
+ body?: string;
254
+ /** HTML body */
255
+ html?: string;
256
+ /** Attachments */
257
+ attachments?: EmailAttachment[];
258
+ }
259
+ /**
260
+ * Email message with recipient for bulk sending
261
+ */
262
+ interface EmailMessageWithRecipient extends EmailMessage {
263
+ /** Recipient email address */
264
+ to: string;
265
+ /** Additional metadata */
266
+ metadata?: Record<string, unknown>;
267
+ }
268
+ /**
269
+ * Email attachment
270
+ */
271
+ interface EmailAttachment {
272
+ /** Attachment filename */
273
+ filename: string;
274
+ /** Content as Buffer or base64 string */
275
+ content: Buffer | string;
276
+ /** MIME type */
277
+ contentType: string;
278
+ }
279
+ /**
280
+ * Email sending options
281
+ */
282
+ interface EmailOptions {
283
+ /** From address override */
284
+ from?: string;
285
+ /** From name override */
286
+ fromName?: string;
287
+ /** Reply-to address */
288
+ replyTo?: string;
289
+ /** CC recipients */
290
+ cc?: string[];
291
+ /** BCC recipients */
292
+ bcc?: string[];
293
+ /** Additional metadata */
294
+ metadata?: Record<string, unknown>;
295
+ }
296
+ /**
297
+ * Twilio SMS provider configuration
298
+ */
299
+ interface TwilioConfig {
300
+ /** Twilio Account SID */
301
+ accountSid: string;
302
+ /** Twilio Auth Token */
303
+ authToken: string;
304
+ /** Default from phone number */
305
+ fromNumber: string;
306
+ /** Messaging Service SID (optional, for advanced features) */
307
+ messagingServiceSid?: string;
308
+ }
309
+ /**
310
+ * Local Pakistan SMS provider configuration
311
+ */
312
+ interface LocalSmsConfig {
313
+ /** Provider name: telenor, jazz, zong */
314
+ provider: 'telenor' | 'jazz' | 'zong';
315
+ /** API key or username */
316
+ apiKey: string;
317
+ /** API secret or password */
318
+ apiSecret?: string;
319
+ /** Sender ID */
320
+ senderId: string;
321
+ /** Base URL override */
322
+ baseUrl?: string;
323
+ }
324
+ /**
325
+ * Meta WhatsApp Cloud API configuration
326
+ */
327
+ interface MetaWhatsAppConfig {
328
+ /** Access token from Meta */
329
+ accessToken: string;
330
+ /** Phone Number ID */
331
+ phoneNumberId: string;
332
+ /** Business Account ID */
333
+ businessAccountId?: string;
334
+ /** API version (default: v18.0) */
335
+ apiVersion?: string;
336
+ /** Webhook verify token */
337
+ webhookVerifyToken?: string;
338
+ }
339
+ /**
340
+ * AWS SES email provider configuration
341
+ */
342
+ interface SesConfig {
343
+ /** AWS region */
344
+ region: string;
345
+ /** Default from address */
346
+ fromAddress: string;
347
+ /** Default from name */
348
+ fromName?: string;
349
+ /** AWS credentials (optional, will use default credential chain) */
350
+ credentials?: {
351
+ accessKeyId: string;
352
+ secretAccessKey: string;
353
+ };
354
+ }
355
+ /**
356
+ * Provider-specific configuration union
357
+ */
358
+ type SmsProviderConfig = {
359
+ provider: 'twilio';
360
+ config: TwilioConfig;
361
+ } | {
362
+ provider: 'local';
363
+ config: LocalSmsConfig;
364
+ } | {
365
+ provider: 'custom';
366
+ instance: SmsProvider;
367
+ };
368
+ type WhatsAppProviderConfig = {
369
+ provider: 'meta';
370
+ config: MetaWhatsAppConfig;
371
+ } | {
372
+ provider: 'custom';
373
+ instance: WhatsAppProvider;
374
+ };
375
+ type EmailProviderConfig = {
376
+ provider: 'ses';
377
+ config: SesConfig;
378
+ } | {
379
+ provider: 'custom';
380
+ instance: EmailProvider;
381
+ };
382
+ /**
383
+ * Routing configuration for smart provider selection
384
+ */
385
+ interface RoutingConfig {
386
+ /** Phone prefix to provider mapping (e.g., '+92': 'primary') */
387
+ [prefix: string]: 'primary' | 'fallback';
388
+ }
389
+ /**
390
+ * SMS channel configuration
391
+ */
392
+ interface SmsChannelConfig {
393
+ /** Primary provider */
394
+ primary: SmsProviderConfig;
395
+ /** Fallback provider (optional) */
396
+ fallback?: SmsProviderConfig;
397
+ /** Routing rules */
398
+ routing?: RoutingConfig;
399
+ }
400
+ /**
401
+ * Retry configuration
402
+ */
403
+ interface RetryConfig {
404
+ /** Maximum number of retry attempts */
405
+ maxAttempts: number;
406
+ /** Initial backoff in milliseconds */
407
+ backoffMs: number;
408
+ /** Backoff multiplier for exponential backoff */
409
+ backoffMultiplier: number;
410
+ /** Maximum backoff in milliseconds */
411
+ maxBackoffMs?: number;
412
+ /** Add jitter to backoff */
413
+ jitter?: boolean;
414
+ }
415
+ /**
416
+ * Logger interface (compatible with console, winston, pino)
417
+ */
418
+ interface Logger {
419
+ debug(message: string, ...args: unknown[]): void;
420
+ info(message: string, ...args: unknown[]): void;
421
+ warn(message: string, ...args: unknown[]): void;
422
+ error(message: string, ...args: unknown[]): void;
423
+ }
424
+ /**
425
+ * Main NotifyHub configuration
426
+ */
427
+ interface NotifyHubConfig {
428
+ /** Default channel for notifications */
429
+ defaultChannel?: Channel;
430
+ /** SMS configuration */
431
+ sms?: SmsChannelConfig;
432
+ /** WhatsApp configuration */
433
+ whatsapp?: WhatsAppProviderConfig;
434
+ /** Email configuration */
435
+ email?: EmailProviderConfig;
436
+ /** Retry configuration */
437
+ retry?: RetryConfig;
438
+ /** Logger instance */
439
+ logger?: Logger;
440
+ }
441
+ /**
442
+ * Generic webhook event
443
+ */
444
+ interface WebhookEvent {
445
+ /** Event type */
446
+ type: 'status' | 'message';
447
+ /** Provider-specific message ID */
448
+ messageId: string;
449
+ /** Channel */
450
+ channel: Channel;
451
+ /** Timestamp */
452
+ timestamp: Date;
453
+ /** Provider name */
454
+ provider: string;
455
+ }
456
+ /**
457
+ * Delivery status webhook event
458
+ */
459
+ interface StatusWebhookEvent extends WebhookEvent {
460
+ type: 'status';
461
+ /** New status */
462
+ status: MessageStatus;
463
+ /** Recipient phone/email */
464
+ to: string;
465
+ /** Error info if failed */
466
+ error?: NotifyError;
467
+ }
468
+ /**
469
+ * Incoming message webhook event
470
+ */
471
+ interface IncomingMessageEvent extends WebhookEvent {
472
+ type: 'message';
473
+ /** Sender phone/email */
474
+ from: string;
475
+ /** Message content */
476
+ message?: string;
477
+ /** Media URL if present */
478
+ mediaUrl?: string;
479
+ /** Media type */
480
+ mediaType?: string;
481
+ }
482
+ /**
483
+ * Webhook handler interface
484
+ */
485
+ interface WebhookHandler<T = unknown> {
486
+ /**
487
+ * Verify webhook signature
488
+ * @param body Raw request body
489
+ * @param headers Request headers
490
+ */
491
+ verify(body: unknown, headers: Record<string, string>): boolean;
492
+ /**
493
+ * Parse webhook payload
494
+ * @param body Request body
495
+ */
496
+ parse(body: T): WebhookEvent[];
497
+ /**
498
+ * Handle verification challenge (for WhatsApp)
499
+ * @param verifyToken Token from query params
500
+ * @param challenge Challenge string
501
+ */
502
+ verifyChallenge?(verifyToken: string, challenge: string): string | null;
503
+ }
504
+ /**
505
+ * Generic notification for the send() method
506
+ */
507
+ interface Notification {
508
+ /** Channel to use */
509
+ channel: Channel;
510
+ /** Recipient (phone or email) */
511
+ to: string;
512
+ /** Message content (for SMS and WhatsApp text) */
513
+ message?: string;
514
+ /** Template (for WhatsApp template messages) */
515
+ template?: WhatsAppTemplate;
516
+ /** Email content */
517
+ email?: EmailMessage;
518
+ /** Additional metadata */
519
+ metadata?: Record<string, unknown>;
520
+ }
521
+
522
+ /**
523
+ * NotifyHub - Multi-channel notification hub
524
+ *
525
+ * @example
526
+ * ```typescript
527
+ * const notifyHub = new NotifyHub({
528
+ * sms: {
529
+ * primary: {
530
+ * provider: 'twilio',
531
+ * config: {
532
+ * accountSid: 'xxx',
533
+ * authToken: 'xxx',
534
+ * fromNumber: '+1234567890',
535
+ * },
536
+ * },
537
+ * },
538
+ * });
539
+ *
540
+ * await notifyHub.sms('+923001234567', 'Hello!');
541
+ * ```
542
+ */
543
+ declare class NotifyHub {
544
+ private readonly config;
545
+ private readonly logger;
546
+ private readonly retryConfig;
547
+ private primarySmsProvider?;
548
+ private fallbackSmsProvider?;
549
+ private whatsappProvider?;
550
+ private emailProvider?;
551
+ private initialized;
552
+ constructor(config: NotifyHubConfig);
553
+ /**
554
+ * Initialize all configured providers
555
+ */
556
+ initialize(): Promise<void>;
557
+ /**
558
+ * Create an SMS provider from configuration
559
+ */
560
+ private createSmsProvider;
561
+ /**
562
+ * Create a WhatsApp provider from configuration
563
+ */
564
+ private createWhatsAppProvider;
565
+ /**
566
+ * Create an Email provider from configuration
567
+ */
568
+ private createEmailProvider;
569
+ /**
570
+ * Ensure NotifyHub is initialized
571
+ */
572
+ private ensureInitialized;
573
+ /**
574
+ * Get the appropriate SMS provider based on phone number
575
+ */
576
+ private getSmsProvider;
577
+ /**
578
+ * Send an SMS message
579
+ * @param to Phone number in any format (will be converted to E.164)
580
+ * @param message Message content
581
+ * @param options Additional options
582
+ */
583
+ sms(to: string, message: string, options?: SmsOptions): Promise<SendResult>;
584
+ /**
585
+ * Send bulk SMS messages
586
+ */
587
+ bulkSms(messages: SmsMessage[], options?: BulkOptions): Promise<BulkResult>;
588
+ /**
589
+ * Get SMS delivery status
590
+ */
591
+ getSmsStatus(messageId: string): Promise<MessageStatus>;
592
+ /**
593
+ * Send a WhatsApp text message (within 24hr window)
594
+ */
595
+ whatsapp(to: string, message: string, options?: WhatsAppOptions): Promise<SendResult>;
596
+ /**
597
+ * Send a WhatsApp template message
598
+ */
599
+ whatsappTemplate(to: string, template: WhatsAppTemplate, options?: WhatsAppOptions): Promise<SendResult>;
600
+ /**
601
+ * Send bulk WhatsApp messages
602
+ */
603
+ bulkWhatsApp(messages: WhatsAppMessage[], options?: BulkOptions): Promise<BulkResult>;
604
+ /**
605
+ * Send an email
606
+ */
607
+ email(to: string, email: EmailMessage, options?: EmailOptions): Promise<SendResult>;
608
+ /**
609
+ * Send bulk emails
610
+ */
611
+ bulkEmail(messages: EmailMessageWithRecipient[], options?: BulkOptions): Promise<BulkResult>;
612
+ /**
613
+ * Send a notification using the specified channel
614
+ */
615
+ send(notification: Notification): Promise<SendResult>;
616
+ /**
617
+ * Cleanup and destroy all providers
618
+ */
619
+ destroy(): Promise<void>;
620
+ }
621
+
622
+ /**
623
+ * Twilio SMS provider implementation
624
+ */
625
+ declare class TwilioSmsProvider implements SmsProvider {
626
+ readonly name = "twilio";
627
+ private client;
628
+ private readonly config;
629
+ private readonly logger?;
630
+ private readonly retryConfig;
631
+ constructor(config: TwilioConfig, options?: {
632
+ logger?: Logger;
633
+ retryConfig?: RetryConfig;
634
+ });
635
+ /**
636
+ * Initialize the Twilio client
637
+ */
638
+ initialize(): Promise<void>;
639
+ /**
640
+ * Ensure client is initialized
641
+ */
642
+ private ensureClient;
643
+ /**
644
+ * Send an SMS message
645
+ */
646
+ send(to: string, message: string, options?: SmsOptions): Promise<SendResult>;
647
+ /**
648
+ * Get delivery status of a message
649
+ */
650
+ getStatus(messageId: string): Promise<MessageStatus>;
651
+ /**
652
+ * Send bulk SMS messages
653
+ */
654
+ sendBulk(messages: SmsMessage[], options?: BulkOptions): Promise<BulkResult>;
655
+ /**
656
+ * Cleanup resources
657
+ */
658
+ destroy(): Promise<void>;
659
+ }
660
+
661
+ /**
662
+ * Abstract base class for Pakistan local SMS providers
663
+ * Each provider (Telenor, Jazz, Zong) extends this class
664
+ */
665
+ declare abstract class BaseLocalSmsProvider implements SmsProvider {
666
+ abstract readonly name: string;
667
+ protected readonly config: LocalSmsConfig;
668
+ protected readonly logger?: Logger;
669
+ protected readonly retryConfig: RetryConfig;
670
+ protected abstract readonly baseUrl: string;
671
+ constructor(config: LocalSmsConfig, options?: {
672
+ logger?: Logger;
673
+ retryConfig?: RetryConfig;
674
+ });
675
+ /**
676
+ * Initialize the provider
677
+ */
678
+ initialize(): Promise<void>;
679
+ /**
680
+ * Format phone number for local provider
681
+ * Pakistan providers typically want: 923001234567 (no + prefix)
682
+ */
683
+ protected formatPhoneNumber(phone: string): string | null;
684
+ /**
685
+ * Make API request to the provider
686
+ * Each provider implements this differently
687
+ */
688
+ protected abstract makeRequest(to: string, message: string): Promise<{
689
+ success: boolean;
690
+ messageId?: string;
691
+ error?: string;
692
+ }>;
693
+ /**
694
+ * Send an SMS message
695
+ */
696
+ send(to: string, message: string, options?: SmsOptions): Promise<SendResult>;
697
+ /**
698
+ * Get delivery status (most local providers don't support this)
699
+ */
700
+ getStatus(_messageId: string): Promise<MessageStatus>;
701
+ /**
702
+ * Send bulk SMS messages
703
+ */
704
+ sendBulk(messages: SmsMessage[], options?: BulkOptions): Promise<BulkResult>;
705
+ /**
706
+ * Cleanup resources
707
+ */
708
+ destroy(): Promise<void>;
709
+ }
710
+
711
+ /**
712
+ * Telenor Pakistan SMS provider
713
+ *
714
+ * API Documentation: Contact Telenor Pakistan for API access
715
+ *
716
+ * Note: This is a simplified implementation. Actual Telenor API
717
+ * may have different endpoints and authentication methods.
718
+ */
719
+ declare class TelenorSmsProvider extends BaseLocalSmsProvider {
720
+ readonly name = "telenor";
721
+ protected readonly baseUrl: string;
722
+ constructor(config: LocalSmsConfig, options?: {
723
+ logger?: Logger;
724
+ retryConfig?: RetryConfig;
725
+ });
726
+ /**
727
+ * Make API request to Telenor
728
+ */
729
+ protected makeRequest(to: string, message: string): Promise<{
730
+ success: boolean;
731
+ messageId?: string;
732
+ error?: string;
733
+ }>;
734
+ }
735
+
736
+ /**
737
+ * Jazz (Mobilink) Pakistan SMS provider
738
+ *
739
+ * API Documentation: Contact Jazz Pakistan for API access
740
+ *
741
+ * Note: This is a simplified implementation. Actual Jazz API
742
+ * may have different endpoints and authentication methods.
743
+ */
744
+ declare class JazzSmsProvider extends BaseLocalSmsProvider {
745
+ readonly name = "jazz";
746
+ protected readonly baseUrl: string;
747
+ constructor(config: LocalSmsConfig, options?: {
748
+ logger?: Logger;
749
+ retryConfig?: RetryConfig;
750
+ });
751
+ /**
752
+ * Make API request to Jazz
753
+ */
754
+ protected makeRequest(to: string, message: string): Promise<{
755
+ success: boolean;
756
+ messageId?: string;
757
+ error?: string;
758
+ }>;
759
+ }
760
+
761
+ /**
762
+ * Zong Pakistan SMS provider
763
+ *
764
+ * API Documentation: Contact Zong Pakistan for API access
765
+ *
766
+ * Note: This is a simplified implementation. Actual Zong API
767
+ * may have different endpoints and authentication methods.
768
+ */
769
+ declare class ZongSmsProvider extends BaseLocalSmsProvider {
770
+ readonly name = "zong";
771
+ protected readonly baseUrl: string;
772
+ constructor(config: LocalSmsConfig, options?: {
773
+ logger?: Logger;
774
+ retryConfig?: RetryConfig;
775
+ });
776
+ /**
777
+ * Make API request to Zong
778
+ */
779
+ protected makeRequest(to: string, message: string): Promise<{
780
+ success: boolean;
781
+ messageId?: string;
782
+ error?: string;
783
+ }>;
784
+ }
785
+
786
+ /**
787
+ * Meta WhatsApp Cloud API provider implementation
788
+ * @see https://developers.facebook.com/docs/whatsapp/cloud-api
789
+ */
790
+ declare class MetaWhatsAppProvider implements WhatsAppProvider {
791
+ readonly name = "meta";
792
+ private readonly config;
793
+ private readonly logger?;
794
+ private readonly retryConfig;
795
+ private readonly apiVersion;
796
+ private readonly baseUrl;
797
+ constructor(config: MetaWhatsAppConfig, options?: {
798
+ logger?: Logger;
799
+ retryConfig?: RetryConfig;
800
+ });
801
+ /**
802
+ * Initialize the provider (no-op for Meta, just validates config)
803
+ */
804
+ initialize(): Promise<void>;
805
+ /**
806
+ * Make an API request to Meta WhatsApp Cloud API
807
+ */
808
+ private makeRequest;
809
+ /**
810
+ * Send a text message (within 24hr conversation window)
811
+ */
812
+ sendText(to: string, message: string, options?: WhatsAppOptions): Promise<SendResult>;
813
+ /**
814
+ * Send a template message (works outside 24hr window)
815
+ */
816
+ sendTemplate(to: string, template: WhatsAppTemplate, options?: WhatsAppOptions): Promise<SendResult>;
817
+ /**
818
+ * Get delivery status of a message
819
+ * Note: Meta doesn't have a direct status lookup API - statuses come via webhooks
820
+ */
821
+ getStatus(_messageId: string): Promise<MessageStatus>;
822
+ /**
823
+ * Cleanup resources (no-op for Meta)
824
+ */
825
+ destroy(): Promise<void>;
826
+ }
827
+
828
+ /**
829
+ * Twilio webhook payload for message status updates
830
+ */
831
+ interface TwilioStatusPayload {
832
+ MessageSid: string;
833
+ MessageStatus: string;
834
+ To: string;
835
+ From?: string;
836
+ ErrorCode?: string;
837
+ ErrorMessage?: string;
838
+ AccountSid?: string;
839
+ ApiVersion?: string;
840
+ }
841
+ /**
842
+ * Twilio webhook payload for incoming messages
843
+ */
844
+ interface TwilioIncomingPayload {
845
+ MessageSid: string;
846
+ Body: string;
847
+ From: string;
848
+ To: string;
849
+ NumMedia?: string;
850
+ MediaUrl0?: string;
851
+ MediaContentType0?: string;
852
+ AccountSid?: string;
853
+ }
854
+ /**
855
+ * Twilio webhook handler
856
+ */
857
+ declare class TwilioWebhookHandler implements WebhookHandler<TwilioStatusPayload | TwilioIncomingPayload> {
858
+ private readonly authToken;
859
+ constructor(authToken: string);
860
+ /**
861
+ * Verify Twilio webhook signature
862
+ * @see https://www.twilio.com/docs/usage/webhooks/webhooks-security
863
+ */
864
+ verify(body: unknown, headers: Record<string, string>): boolean;
865
+ /**
866
+ * Parse Twilio webhook payload
867
+ */
868
+ parse(body: TwilioStatusPayload | TwilioIncomingPayload): WebhookEvent[];
869
+ }
870
+ /**
871
+ * Create a Twilio webhook handler
872
+ */
873
+ declare function createTwilioWebhookHandler(authToken: string): TwilioWebhookHandler;
874
+
875
+ /**
876
+ * Meta WhatsApp webhook payload structure
877
+ * @see https://developers.facebook.com/docs/whatsapp/cloud-api/webhooks/components
878
+ */
879
+ interface MetaWebhookPayload {
880
+ object: 'whatsapp_business_account';
881
+ entry: Array<{
882
+ id: string;
883
+ changes: Array<{
884
+ value: {
885
+ messaging_product: 'whatsapp';
886
+ metadata: {
887
+ display_phone_number: string;
888
+ phone_number_id: string;
889
+ };
890
+ contacts?: Array<{
891
+ profile: {
892
+ name: string;
893
+ };
894
+ wa_id: string;
895
+ }>;
896
+ messages?: Array<{
897
+ from: string;
898
+ id: string;
899
+ timestamp: string;
900
+ type: 'text' | 'image' | 'document' | 'audio' | 'video' | 'sticker' | 'location' | 'contacts' | 'button' | 'interactive';
901
+ text?: {
902
+ body: string;
903
+ };
904
+ image?: {
905
+ id: string;
906
+ mime_type: string;
907
+ sha256: string;
908
+ };
909
+ document?: {
910
+ id: string;
911
+ mime_type: string;
912
+ sha256: string;
913
+ filename?: string;
914
+ };
915
+ audio?: {
916
+ id: string;
917
+ mime_type: string;
918
+ };
919
+ video?: {
920
+ id: string;
921
+ mime_type: string;
922
+ };
923
+ button?: {
924
+ text: string;
925
+ payload: string;
926
+ };
927
+ interactive?: {
928
+ type: string;
929
+ button_reply?: {
930
+ id: string;
931
+ title: string;
932
+ };
933
+ list_reply?: {
934
+ id: string;
935
+ title: string;
936
+ };
937
+ };
938
+ }>;
939
+ statuses?: Array<{
940
+ id: string;
941
+ status: 'sent' | 'delivered' | 'read' | 'failed';
942
+ timestamp: string;
943
+ recipient_id: string;
944
+ errors?: Array<{
945
+ code: number;
946
+ title: string;
947
+ message?: string;
948
+ error_data?: {
949
+ details: string;
950
+ };
951
+ }>;
952
+ }>;
953
+ };
954
+ field: 'messages';
955
+ }>;
956
+ }>;
957
+ }
958
+ /**
959
+ * Meta WhatsApp Cloud API webhook handler
960
+ */
961
+ declare class WhatsAppWebhookHandler implements WebhookHandler<MetaWebhookPayload> {
962
+ private readonly appSecret;
963
+ private readonly verifyToken;
964
+ constructor(appSecret: string, verifyToken: string);
965
+ /**
966
+ * Verify WhatsApp webhook challenge (for initial setup)
967
+ */
968
+ verifyChallenge(verifyToken: string, challenge: string): string | null;
969
+ /**
970
+ * Verify Meta webhook signature
971
+ * @see https://developers.facebook.com/docs/graph-api/webhooks/getting-started#verification-requests
972
+ */
973
+ verify(body: unknown, headers: Record<string, string>): boolean;
974
+ /**
975
+ * Parse Meta WhatsApp webhook payload
976
+ */
977
+ parse(body: MetaWebhookPayload): WebhookEvent[];
978
+ }
979
+ /**
980
+ * Create a WhatsApp webhook handler
981
+ */
982
+ declare function createWhatsAppWebhookHandler(appSecret: string, verifyToken: string): WhatsAppWebhookHandler;
983
+
984
+ /**
985
+ * Default retry configuration
986
+ */
987
+ declare const DEFAULT_RETRY_CONFIG: RetryConfig;
988
+ /**
989
+ * Check if an error is retriable
990
+ */
991
+ declare function isRetriableError(error: unknown): boolean;
992
+ /**
993
+ * Calculate backoff delay with optional jitter
994
+ */
995
+ declare function calculateBackoff(attempt: number, config: RetryConfig): number;
996
+ /**
997
+ * Retry result containing the value or error
998
+ */
999
+ interface RetryResult<T> {
1000
+ success: boolean;
1001
+ value?: T;
1002
+ error?: Error;
1003
+ attempts: number;
1004
+ totalDurationMs: number;
1005
+ }
1006
+ /**
1007
+ * Execute a function with retries
1008
+ * @param fn Function to execute
1009
+ * @param config Retry configuration
1010
+ * @param shouldRetry Optional custom retry predicate
1011
+ */
1012
+ declare function withRetry<T>(fn: () => Promise<T>, config?: RetryConfig, shouldRetry?: (error: unknown) => boolean): Promise<RetryResult<T>>;
1013
+ /**
1014
+ * Create a NotifyError from an unknown error
1015
+ */
1016
+ declare function createNotifyError(error: unknown, defaultCode?: string): NotifyError;
1017
+
1018
+ /**
1019
+ * Phone number validation result
1020
+ */
1021
+ interface PhoneValidationResult {
1022
+ isValid: boolean;
1023
+ e164?: string;
1024
+ countryCode?: string;
1025
+ nationalNumber?: string;
1026
+ error?: string;
1027
+ }
1028
+ /**
1029
+ * Validate and parse a phone number to E.164 format
1030
+ * @param phone Phone number in any format
1031
+ * @param defaultCountry Default country code for numbers without country prefix
1032
+ */
1033
+ declare function validatePhoneNumber(phone: string, defaultCountry?: CountryCode): PhoneValidationResult;
1034
+ /**
1035
+ * Clean a phone number by removing common formatting characters
1036
+ */
1037
+ declare function cleanPhoneNumber(phone: string): string;
1038
+ /**
1039
+ * Format phone number to E.164 format
1040
+ * @param phone Phone number in any format
1041
+ * @param defaultCountry Default country code
1042
+ * @returns E.164 formatted number or null if invalid
1043
+ */
1044
+ declare function toE164(phone: string, defaultCountry?: CountryCode): string | null;
1045
+ /**
1046
+ * Check if a phone number belongs to a specific country
1047
+ * @param phone Phone number in E.164 format
1048
+ * @param countryCode Two-letter country code
1049
+ */
1050
+ declare function isCountry(phone: string, countryCode: CountryCode): boolean;
1051
+ /**
1052
+ * Get the country code from a phone number
1053
+ * @param phone Phone number in E.164 format
1054
+ */
1055
+ declare function getCountryCode(phone: string): string | null;
1056
+ /**
1057
+ * Get the calling code (e.g., +92 for Pakistan)
1058
+ * @param phone Phone number in E.164 format
1059
+ */
1060
+ declare function getCallingCode(phone: string): string | null;
1061
+ /**
1062
+ * Check if a phone number is a Pakistan mobile number
1063
+ * Pakistan mobile numbers start with 03xx
1064
+ */
1065
+ declare function isPakistanMobile(phone: string): boolean;
1066
+ /**
1067
+ * Get the Pakistan mobile network from a phone number
1068
+ * @param phone Phone number
1069
+ * @returns Network name or null if not a Pakistan mobile
1070
+ */
1071
+ declare function getPakistanNetwork(phone: string): 'jazz' | 'telenor' | 'zong' | 'ufone' | null;
1072
+ /**
1073
+ * Determine the best provider for a phone number based on prefix
1074
+ * @param phone Phone number in E.164 format
1075
+ * @param routing Routing configuration
1076
+ * @returns 'primary' or 'fallback'
1077
+ */
1078
+ declare function routeByPrefix(phone: string, routing: Record<string, 'primary' | 'fallback'>): 'primary' | 'fallback';
1079
+
1080
+ export { BaseLocalSmsProvider, type BaseProvider, type BulkOptions, type BulkResult, type BulkSummary, type Channel, type Cost, DEFAULT_RETRY_CONFIG, type EmailAttachment, type EmailMessage, type EmailMessageWithRecipient, type EmailOptions, type EmailProvider, type EmailProviderConfig, type IncomingMessageEvent, JazzSmsProvider, type LocalSmsConfig, type Logger, type MessageStatus, type MetaWhatsAppConfig, MetaWhatsAppProvider, type Notification, type NotifyError, NotifyHub, type NotifyHubConfig, type RateLimitConfig, type RetryConfig, type RoutingConfig, type SendResult, type SesConfig, type SmsChannelConfig, type SmsMessage, type SmsOptions, type SmsProvider, type SmsProviderConfig, type StatusWebhookEvent, TelenorSmsProvider, type TwilioConfig, TwilioSmsProvider, TwilioWebhookHandler, type WebhookEvent, type WebhookHandler, type WhatsAppMessage, type WhatsAppOptions, type WhatsAppProvider, type WhatsAppProviderConfig, type WhatsAppTemplate, type WhatsAppTemplateButton, type WhatsAppTemplateHeader, WhatsAppWebhookHandler, ZongSmsProvider, calculateBackoff, cleanPhoneNumber, createNotifyError, createTwilioWebhookHandler, createWhatsAppWebhookHandler, getCallingCode, getCountryCode, getPakistanNetwork, isCountry, isPakistanMobile, isRetriableError, routeByPrefix, toE164, validatePhoneNumber, withRetry };