@arkstack/notifications 0.17.8 → 0.17.9

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.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { DotPath, DotPathValue, MergedConfig } from "@arkstack/common";
2
- import { Transporter } from "nodemailer";
2
+ import { Transport, Transporter } from "nodemailer";
3
3
  import { Model } from "@arkstack/database";
4
4
  import { Logger } from "nodemailer/lib/shared/index.js";
5
5
  import { User } from "@app/models/User";
@@ -83,8 +83,8 @@ type FirebaseTransportConfig = {
83
83
  app_name?: string;
84
84
  admin_sdk_path?: string;
85
85
  };
86
- type RealtimeDriverOptions = {
87
- transport?: RealtimeDriverName; /** Channel/topic to broadcast on. Defaults to `${channel_prefix}${user.id}`. */
86
+ type RealtimeDriverOptions<T extends RealtimeDriverName = RealtimeDriverName> = {
87
+ transport?: T; /** Channel/topic to broadcast on. Defaults to `${channel_prefix}${user.id}`. */
88
88
  channel?: string; /** Event name clients subscribe to. Defaults to config `event` or `notification`. */
89
89
  event?: string; /** Also persist the notification to the database (requires a User recipient). */
90
90
  store?: boolean;
@@ -126,11 +126,11 @@ type NotificationDriverMap = {
126
126
  db: UserNotification;
127
127
  realtime: RealtimeBroadcastResult;
128
128
  };
129
- interface NotificationConfig {
129
+ interface NotificationConfig<T = any> {
130
130
  default_driver: 'mail' | 'sms' | 'db';
131
131
  drivers: {
132
132
  mail: {
133
- transport: 'smtp' | 'file' | 'sendmail' | 'ses';
133
+ transport: 'smtp' | 'file' | 'sendmail' | 'ses' | Transport<T>;
134
134
  from: string | {
135
135
  name: string;
136
136
  address: string;
@@ -223,6 +223,9 @@ interface NotificationConfig {
223
223
  };
224
224
  }
225
225
  type MergedTransportConfig = MergedConfig<Required<NotificationConfig['transports']>[NonNullable<MailDriverOptions['transport']>]>;
226
+ type MailNotificationOptions = MailDriverOptions & {
227
+ transport?: MailDriverOptions['transport'] | Transport;
228
+ };
226
229
  //#endregion
227
230
  //#region src/Contracts/NotificationContract.d.ts
228
231
  declare abstract class NotificationContract<TResult = DriverResult> {
@@ -281,7 +284,7 @@ declare class MailNotification extends NotificationContract {
281
284
  private htmlTemplate?;
282
285
  private textTemplate?;
283
286
  private fileDirectory?;
284
- constructor(options?: MailDriverOptions);
287
+ constructor(options?: MailNotificationOptions);
285
288
  /**
286
289
  * Prepare the mail driver so we can use it to relay the message
287
290
  */
@@ -343,6 +346,56 @@ declare class MailNotification extends NotificationContract {
343
346
  private normalizeRecipient;
344
347
  }
345
348
  //#endregion
349
+ //#region src/drivers/realtime/FirebaseRealtimeDriver.d.ts
350
+ /**
351
+ * The outcome of a token multicast: totals plus the tokens FCM rejected as dead.
352
+ */
353
+ interface FirebaseMulticastResult {
354
+ successCount: number;
355
+ failureCount: number;
356
+ /**
357
+ * Tokens FCM reported as unregistered/invalid — delete these from your store.
358
+ */
359
+ invalidTokens: string[];
360
+ }
361
+ /**
362
+ * Broadcasts notifications over [Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging).
363
+ * A single channel maps to an FCM topic; an array of channels is treated as
364
+ * device registration tokens and delivered via a multicast send (chunked to
365
+ * FCM's 500-token limit), returning the tokens that should be pruned.
366
+ *
367
+ * `firebase-admin` is an optional peer dependency, imported lazily so the
368
+ * package installs without it; it is only required when this transport is used.
369
+ * FCM data values must be strings, so the payload is JSON-encoded.
370
+ */
371
+ declare class FirebaseRealtimeDriver implements RealtimeDriver {
372
+ private options;
373
+ private messagingPromise?;
374
+ constructor(options?: FirebaseTransportConfig);
375
+ private messaging;
376
+ broadcast(channel: string | string[], event: string, payload: RealtimeNotificationPayload): Promise<string | FirebaseMulticastResult>;
377
+ /**
378
+ * Send to many device tokens at once, chunked to FCM's 500-token limit, and
379
+ * collect the tokens FCM rejects as dead so the caller can prune them.
380
+ */
381
+ private multicast;
382
+ }
383
+ //#endregion
384
+ //#region src/drivers/realtime/PusherRealtimeDriver.d.ts
385
+ /**
386
+ * Broadcasts notifications over [Pusher Channels](https://pusher.com/channels).
387
+ *
388
+ * The `pusher` server SDK is an optional peer dependency, imported lazily so the
389
+ * package installs without it; it is only required when this transport is used.
390
+ */
391
+ declare class PusherRealtimeDriver implements RealtimeDriver {
392
+ private options;
393
+ private clientPromise?;
394
+ constructor(options?: PusherTransportConfig);
395
+ private client;
396
+ broadcast(channel: string | string[], event: string, payload: RealtimeNotificationPayload): Promise<unknown>;
397
+ }
398
+ //#endregion
346
399
  //#region src/Contracts/RealtimeDriver.d.ts
347
400
  /**
348
401
  * A realtime transport (Pusher, Firebase, …) broadcasts a notification payload
@@ -355,6 +408,7 @@ declare class MailNotification extends NotificationContract {
355
408
  interface RealtimeDriver {
356
409
  broadcast(channel: string | string[], event: string, payload: RealtimeNotificationPayload): Promise<unknown>;
357
410
  }
411
+ type RealtimeNotificationDriver<T extends RealtimeDriverName> = T extends 'firebase' ? FirebaseRealtimeDriver : T extends 'firebase' ? PusherRealtimeDriver : RealtimeDriver;
358
412
  //#endregion
359
413
  //#region src/drivers/RealtimeNotification.d.ts
360
414
  /**
@@ -362,20 +416,28 @@ interface RealtimeDriver {
362
416
  * (Pusher or Firebase). The notification is delivered on a per-user channel and,
363
417
  * when `store` is enabled, is also persisted so the client can load history.
364
418
  */
365
- declare class RealtimeNotification extends NotificationContract<RealtimeBroadcastResult> {
419
+ declare class RealtimeNotification<T extends RealtimeDriverName = RealtimeDriverName> extends NotificationContract<RealtimeBroadcastResult> {
366
420
  /**
367
421
  * The underlying transport; assignable so tests can inject a fake.
368
422
  */
369
- driver: RealtimeDriver;
423
+ driver: RealtimeNotificationDriver<T>;
370
424
  private user?;
371
425
  private channelName?;
372
426
  private eventName;
373
427
  private channelPrefix;
374
428
  private shouldStore;
375
429
  private payload;
376
- constructor(options?: RealtimeDriverOptions);
377
- from(_from: string): this;
430
+ constructor(options?: RealtimeDriverOptions<T>);
431
+ from(_: string): this;
378
432
  subject(subject: string): this;
433
+ /**
434
+ * Overide the default transport
435
+ *
436
+ * @param transport
437
+ * @param options
438
+ * @returns
439
+ */
440
+ transport(transport: T, options?: RealtimeDriverOptions[T]): this;
379
441
  /**
380
442
  * Set the recipient: a `User` (derives the channel), an explicit channel
381
443
  * string, or an array of channels (Pusher) / device tokens (Firebase).
@@ -464,16 +526,66 @@ type DriverMap = {
464
526
  };
465
527
  //#endregion
466
528
  //#region src/Notification.d.ts
467
- type DriverOptions = MailDriverOptions | SmsDriverOptions | RealtimeDriverOptions;
468
529
  declare class Notification<D extends keyof DriverMap = keyof DriverMap> {
469
530
  private driver;
470
- constructor(driver: D, options?: DriverOptions);
531
+ constructor(driver: 'sms', options?: SmsDriverOptions);
532
+ constructor(driver: 'realtime', options?: RealtimeDriverOptions);
533
+ constructor(driver: 'mail' | 'email', options?: MailDriverOptions);
534
+ constructor(driver: 'db');
535
+ /**
536
+ * Send an email notification
537
+ *
538
+ * @param options
539
+ * @returns
540
+ */
471
541
  static mail(options?: MailDriverOptions): MailNotification;
542
+ /**
543
+ * Send an email notification
544
+ *
545
+ * @param options
546
+ * @alias {@link mail}
547
+ * @returns
548
+ */
472
549
  static email(options?: MailDriverOptions): MailNotification;
550
+ /**
551
+ * Send an sms notification
552
+ *
553
+ * @param options
554
+ * @returns
555
+ */
473
556
  static sms(options?: SmsDriverOptions): SmsNotification;
557
+ /**
558
+ * Send a database notification
559
+ *
560
+ * @param options
561
+ * @returns
562
+ */
474
563
  static db(): DbNotification;
475
- static realtime(options?: RealtimeDriverOptions): RealtimeNotification;
476
- static channel(channel?: NotificationChannel | 'email', options?: DriverOptions): MailNotification | SmsNotification | DbNotification | RealtimeNotification;
564
+ /**
565
+ * Send a realtime notification
566
+ *
567
+ * @param options
568
+ * @returns
569
+ */
570
+ static realtime(options?: RealtimeDriverOptions): RealtimeNotification<RealtimeDriverName>;
571
+ /**
572
+ * Use a specific channel to send this notification
573
+ *
574
+ * @param channel
575
+ * @param options
576
+ */
577
+ static channel(channel: 'sms', options?: SmsDriverOptions): SmsNotification;
578
+ static channel(channel: 'realtime', options?: RealtimeDriverOptions): RealtimeNotification;
579
+ static channel(channel: 'mail' | 'email', options?: MailDriverOptions): MailNotification;
580
+ static channel(channel: 'db'): DbNotification;
581
+ static channel(): MailNotification | SmsNotification | DbNotification | RealtimeNotification;
582
+ /**
583
+ * Prepare the notification
584
+ *
585
+ * @param recipient
586
+ * @param data
587
+ * @returns
588
+ */
477
589
  prepare(recipient?: null | MailRecipient | NotificationRecipient | User, data?: NotificationData): DriverMap[D];
478
590
  private static createDriver;
479
591
  }
@@ -533,57 +645,7 @@ declare class UserNotificationCenter {
533
645
  //#region src/config.d.ts
534
646
  declare const configure: <T extends DotPath<NotificationConfig>>(key: T, defaultValue: unknown) => DotPathValue<NotificationConfig, T>;
535
647
  //#endregion
536
- //#region src/drivers/realtime/PusherRealtimeDriver.d.ts
537
- /**
538
- * Broadcasts notifications over [Pusher Channels](https://pusher.com/channels).
539
- *
540
- * The `pusher` server SDK is an optional peer dependency, imported lazily so the
541
- * package installs without it; it is only required when this transport is used.
542
- */
543
- declare class PusherRealtimeDriver implements RealtimeDriver {
544
- private options;
545
- private clientPromise?;
546
- constructor(options?: PusherTransportConfig);
547
- private client;
548
- broadcast(channel: string | string[], event: string, payload: RealtimeNotificationPayload): Promise<unknown>;
549
- }
550
- //#endregion
551
- //#region src/drivers/realtime/FirebaseRealtimeDriver.d.ts
552
- /**
553
- * The outcome of a token multicast: totals plus the tokens FCM rejected as dead.
554
- */
555
- interface FirebaseMulticastResult {
556
- successCount: number;
557
- failureCount: number;
558
- /**
559
- * Tokens FCM reported as unregistered/invalid — delete these from your store.
560
- */
561
- invalidTokens: string[];
562
- }
563
- /**
564
- * Broadcasts notifications over [Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging).
565
- * A single channel maps to an FCM topic; an array of channels is treated as
566
- * device registration tokens and delivered via a multicast send (chunked to
567
- * FCM's 500-token limit), returning the tokens that should be pruned.
568
- *
569
- * `firebase-admin` is an optional peer dependency, imported lazily so the
570
- * package installs without it; it is only required when this transport is used.
571
- * FCM data values must be strings, so the payload is JSON-encoded.
572
- */
573
- declare class FirebaseRealtimeDriver implements RealtimeDriver {
574
- private options;
575
- private messagingPromise?;
576
- constructor(options?: FirebaseTransportConfig);
577
- private messaging;
578
- broadcast(channel: string | string[], event: string, payload: RealtimeNotificationPayload): Promise<string | FirebaseMulticastResult>;
579
- /**
580
- * Send to many device tokens at once, chunked to FCM's 500-token limit, and
581
- * collect the tokens FCM rejects as dead so the caller can prune them.
582
- */
583
- private multicast;
584
- }
585
- //#endregion
586
648
  //#region src/utils/template.d.ts
587
649
  declare const interpolate: (value: string, data?: NotificationData) => string;
588
650
  //#endregion
589
- export { AfricasTalkingSmsDriver, DbNotification, DbNotificationPayload, DbNotificationType, DriverResult, FirebaseMulticastResult, FirebaseRealtimeDriver, FirebaseTransportConfig, MailDriverOptions, MailNotification, MailRecipient, MailRecipientAddress, MergedTransportConfig, Notification, NotificationChannel, NotificationConfig, NotificationContract, NotificationData, NotificationDriverMap, NotificationRecipient, PusherRealtimeDriver, PusherTransportConfig, RealtimeBroadcastResult, RealtimeDriver, RealtimeDriverName, RealtimeDriverOptions, RealtimeNotification, RealtimeNotificationPayload, SmsDriverName, SmsDriverOptions, SmsNotification, TwilioSmsDriver, UserNotification, UserNotificationCenter, configure, interpolate };
651
+ export { AfricasTalkingSmsDriver, DbNotification, DbNotificationPayload, DbNotificationType, DriverResult, FirebaseMulticastResult, FirebaseRealtimeDriver, FirebaseTransportConfig, MailDriverOptions, MailNotification, MailNotificationOptions, MailRecipient, MailRecipientAddress, MergedTransportConfig, Notification, NotificationChannel, NotificationConfig, NotificationContract, NotificationData, NotificationDriverMap, NotificationRecipient, PusherRealtimeDriver, PusherTransportConfig, RealtimeBroadcastResult, RealtimeDriver, RealtimeDriverName, RealtimeDriverOptions, RealtimeNotification, RealtimeNotificationDriver, RealtimeNotificationPayload, SmsDriverName, SmsDriverOptions, SmsNotification, TwilioSmsDriver, UserNotification, UserNotificationCenter, configure, interpolate };
package/dist/index.js CHANGED
@@ -222,6 +222,10 @@ var MailNotification = class extends NotificationContract {
222
222
  * Prepare the mail driver so we can use it to relay the message
223
223
  */
224
224
  async prepareDriver() {
225
+ if (typeof this.transport !== "string") {
226
+ this.driver = nodemailer.createTransport(this.transport);
227
+ return;
228
+ }
225
229
  const options = this.options;
226
230
  const transport = configure(`transports.${this.transport}`, {});
227
231
  /**
@@ -422,7 +426,8 @@ var MailNotification = class extends NotificationContract {
422
426
  const recipients = recipient ?? this.recipients;
423
427
  const resolved = (Array.isArray(recipients) ? [...recipients] : recipients ? [recipients] : []).flatMap((recipient) => this.normalizeRecipient(recipient));
424
428
  const driver = configure("drivers.mail", {});
425
- const transport = configure(`transports.${driver.transport ?? "smtp"}`, {});
429
+ const trpt = driver.transport ?? "smtp";
430
+ const transport = typeof trpt === "string" ? configure(`transports.${trpt}`, {}) : { test_address: "" };
426
431
  const testAddress = driver.test_address ?? driver.test_address ?? transport.test_address ?? transport.test_address ?? env("MAIL_TEST_ADDRESS");
427
432
  if (env("NODE_ENV") !== "production" && testAddress) resolved.push(testAddress);
428
433
  return resolved;
@@ -591,7 +596,7 @@ var RealtimeNotification = class extends NotificationContract {
591
596
  ...options.pusher
592
597
  });
593
598
  }
594
- from(_from) {
599
+ from(_) {
595
600
  return this;
596
601
  }
597
602
  subject(subject) {
@@ -599,6 +604,24 @@ var RealtimeNotification = class extends NotificationContract {
599
604
  return this;
600
605
  }
601
606
  /**
607
+ * Overide the default transport
608
+ *
609
+ * @param transport
610
+ * @param options
611
+ * @returns
612
+ */
613
+ transport(transport, options) {
614
+ const transportConfig = configure(`transports.${transport}`, {});
615
+ this.driver = transport === "firebase" ? new FirebaseRealtimeDriver({
616
+ ...transportConfig,
617
+ ...options
618
+ }) : new PusherRealtimeDriver({
619
+ ...transportConfig,
620
+ ...options
621
+ });
622
+ return this;
623
+ }
624
+ /**
602
625
  * Set the recipient: a `User` (derives the channel), an explicit channel
603
626
  * string, or an array of channels (Pusher) / device tokens (Firebase).
604
627
  *
@@ -804,24 +827,63 @@ var Notification = class Notification {
804
827
  constructor(driver, options = {}) {
805
828
  this.driver = Notification.createDriver(driver, options);
806
829
  }
830
+ /**
831
+ * Send an email notification
832
+ *
833
+ * @param options
834
+ * @returns
835
+ */
807
836
  static mail(options) {
808
837
  return new MailNotification(options);
809
838
  }
839
+ /**
840
+ * Send an email notification
841
+ *
842
+ * @param options
843
+ * @alias {@link mail}
844
+ * @returns
845
+ */
810
846
  static email(options) {
811
847
  return this.mail(options);
812
848
  }
849
+ /**
850
+ * Send an sms notification
851
+ *
852
+ * @param options
853
+ * @returns
854
+ */
813
855
  static sms(options) {
814
856
  return new SmsNotification(options);
815
857
  }
858
+ /**
859
+ * Send a database notification
860
+ *
861
+ * @param options
862
+ * @returns
863
+ */
816
864
  static db() {
817
865
  return new DbNotification();
818
866
  }
867
+ /**
868
+ * Send a realtime notification
869
+ *
870
+ * @param options
871
+ * @returns
872
+ */
819
873
  static realtime(options) {
820
874
  return new RealtimeNotification(options);
821
875
  }
822
876
  static channel(channel, options) {
823
- return Notification.createDriver(channel ?? configure("default_driver", "mail"), options);
877
+ channel ??= configure("default_driver", "mail");
878
+ return Notification.createDriver(channel, options);
824
879
  }
880
+ /**
881
+ * Prepare the notification
882
+ *
883
+ * @param recipient
884
+ * @param data
885
+ * @returns
886
+ */
825
887
  prepare(recipient, data = {}) {
826
888
  this.driver.data(data);
827
889
  if (recipient && typeof recipient === "object" && !Array.isArray(recipient) && typeof recipient.id !== "undefined") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkstack/notifications",
3
- "version": "0.17.8",
3
+ "version": "0.17.9",
4
4
  "type": "module",
5
5
  "description": "Framework-agnostic notification module for Arkstack and Nodejs, providing support for multi-channel notification delivery.",
6
6
  "homepage": "https://arkstack.toneflix.net/guide/notifications",
@@ -34,14 +34,14 @@
34
34
  "africastalking": "^0.8.0",
35
35
  "nodemailer": "^8.0.7",
36
36
  "twilio": "^6.0.0",
37
- "@arkstack/common": "^0.17.8"
37
+ "@arkstack/common": "^0.17.9"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "@kanun-hq/plugin-phone": "^0.1.8",
41
41
  "firebase-admin": "^13.0.0",
42
42
  "pusher": "^5.2.0",
43
- "@arkstack/contract": "^0.17.8",
44
- "@arkstack/database": "^0.17.8"
43
+ "@arkstack/contract": "^0.17.9",
44
+ "@arkstack/database": "^0.17.9"
45
45
  },
46
46
  "peerDependenciesMeta": {
47
47
  "pusher": {