@arkstack/notifications 0.16.5 → 0.16.7
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 +166 -5
- package/dist/index.js +222 -1
- package/package.json +14 -4
package/dist/index.d.ts
CHANGED
|
@@ -28,7 +28,8 @@ type MailRecipientAddress = Record<string, string>;
|
|
|
28
28
|
type MailRecipient = string | MailRecipientAddress | Array<string | MailRecipientAddress>;
|
|
29
29
|
type NotificationData = Record<string, unknown>;
|
|
30
30
|
type SmsDriverName = 'africastalking' | 'twilio';
|
|
31
|
-
type
|
|
31
|
+
type RealtimeDriverName = 'pusher' | 'firebase';
|
|
32
|
+
type NotificationChannel = 'mail' | 'sms' | 'db' | 'realtime';
|
|
32
33
|
type MailDriverOptions = {
|
|
33
34
|
transport?: 'africastalking' | 'twilio' | 'file' | 'smtp';
|
|
34
35
|
host?: string;
|
|
@@ -54,6 +55,45 @@ type SmsDriverOptions = {
|
|
|
54
55
|
from?: string;
|
|
55
56
|
};
|
|
56
57
|
};
|
|
58
|
+
type PusherTransportConfig = {
|
|
59
|
+
app_id?: string;
|
|
60
|
+
key?: string;
|
|
61
|
+
secret?: string;
|
|
62
|
+
cluster?: string;
|
|
63
|
+
use_tls?: boolean;
|
|
64
|
+
};
|
|
65
|
+
type FirebaseTransportConfig = {
|
|
66
|
+
project_id?: string;
|
|
67
|
+
client_email?: string;
|
|
68
|
+
private_key?: string;
|
|
69
|
+
};
|
|
70
|
+
type RealtimeDriverOptions = {
|
|
71
|
+
transport?: RealtimeDriverName; /** Channel/topic to broadcast on. Defaults to `${channel_prefix}${user.id}`. */
|
|
72
|
+
channel?: string; /** Event name clients subscribe to. Defaults to config `event` or `notification`. */
|
|
73
|
+
event?: string; /** Also persist the notification to the database (requires a User recipient). */
|
|
74
|
+
store?: boolean;
|
|
75
|
+
pusher?: PusherTransportConfig;
|
|
76
|
+
firebase?: FirebaseTransportConfig;
|
|
77
|
+
};
|
|
78
|
+
/** The notification payload delivered to realtime clients. */
|
|
79
|
+
type RealtimeNotificationPayload = {
|
|
80
|
+
id: string;
|
|
81
|
+
type: DbNotificationType | null;
|
|
82
|
+
title: string;
|
|
83
|
+
description: string;
|
|
84
|
+
actionText?: string | null;
|
|
85
|
+
actionLink?: string | null;
|
|
86
|
+
meta?: NotificationData | null;
|
|
87
|
+
read_at: string | null;
|
|
88
|
+
created_at: string;
|
|
89
|
+
};
|
|
90
|
+
/** The result of a realtime broadcast (plus the stored record when `store` is on). */
|
|
91
|
+
type RealtimeBroadcastResult = {
|
|
92
|
+
channel: string;
|
|
93
|
+
event: string;
|
|
94
|
+
payload: RealtimeNotificationPayload;
|
|
95
|
+
stored?: UserNotification;
|
|
96
|
+
};
|
|
57
97
|
type DbNotificationType = 'transaction' | 'pocket' | 'family' | 'security' | 'promo' | 'bill' | 'goal' | string;
|
|
58
98
|
type DbNotificationPayload = {
|
|
59
99
|
type?: DbNotificationType | null;
|
|
@@ -68,13 +108,17 @@ type NotificationDriverMap = {
|
|
|
68
108
|
mail: DriverResult;
|
|
69
109
|
sms: DriverResult;
|
|
70
110
|
db: UserNotification;
|
|
111
|
+
realtime: RealtimeBroadcastResult;
|
|
71
112
|
};
|
|
72
113
|
interface NotificationConfig {
|
|
73
114
|
default_driver: 'mail' | 'sms' | 'db';
|
|
74
115
|
drivers: {
|
|
75
116
|
mail: {
|
|
76
117
|
transport: 'smtp' | 'file';
|
|
77
|
-
from: string
|
|
118
|
+
from: string | {
|
|
119
|
+
name: string;
|
|
120
|
+
address: string;
|
|
121
|
+
};
|
|
78
122
|
test_address: string;
|
|
79
123
|
};
|
|
80
124
|
sms: {
|
|
@@ -84,6 +128,12 @@ interface NotificationConfig {
|
|
|
84
128
|
db: {
|
|
85
129
|
table: string;
|
|
86
130
|
};
|
|
131
|
+
realtime?: {
|
|
132
|
+
transport: RealtimeDriverName; /** Prefix for the per-user channel/topic (default `user.`). */
|
|
133
|
+
channel_prefix?: string; /** Event name clients subscribe to (default `notification`). */
|
|
134
|
+
event?: string; /** Persist broadcasts to the database by default. */
|
|
135
|
+
store?: boolean;
|
|
136
|
+
};
|
|
87
137
|
};
|
|
88
138
|
transports: {
|
|
89
139
|
smtp: {
|
|
@@ -124,6 +174,18 @@ interface NotificationConfig {
|
|
|
124
174
|
authToken: string;
|
|
125
175
|
from: string;
|
|
126
176
|
};
|
|
177
|
+
pusher?: {
|
|
178
|
+
app_id: string;
|
|
179
|
+
key: string;
|
|
180
|
+
secret: string;
|
|
181
|
+
cluster: string;
|
|
182
|
+
use_tls?: boolean;
|
|
183
|
+
};
|
|
184
|
+
firebase?: {
|
|
185
|
+
project_id: string;
|
|
186
|
+
client_email: string;
|
|
187
|
+
private_key: string;
|
|
188
|
+
};
|
|
127
189
|
};
|
|
128
190
|
}
|
|
129
191
|
type MergedTransportConfig = MergedConfig<NotificationConfig['transports'][NonNullable<MailDriverOptions['transport']>]>;
|
|
@@ -223,6 +285,70 @@ declare class MailNotification extends NotificationContract {
|
|
|
223
285
|
private normalizeRecipient;
|
|
224
286
|
}
|
|
225
287
|
//#endregion
|
|
288
|
+
//#region src/Contracts/RealtimeDriver.d.ts
|
|
289
|
+
/**
|
|
290
|
+
* A realtime transport (Pusher, Firebase, …) broadcasts a notification payload
|
|
291
|
+
* to a channel/topic that connected clients subscribe to.
|
|
292
|
+
*/
|
|
293
|
+
interface RealtimeDriver {
|
|
294
|
+
broadcast(channel: string, event: string, payload: RealtimeNotificationPayload): Promise<unknown>;
|
|
295
|
+
}
|
|
296
|
+
//#endregion
|
|
297
|
+
//#region src/drivers/RealtimeNotification.d.ts
|
|
298
|
+
/**
|
|
299
|
+
* Broadcasts a notification to connected clients over a realtime transport
|
|
300
|
+
* (Pusher or Firebase). The notification is delivered on a per-user channel and,
|
|
301
|
+
* when `store` is enabled, is also persisted so the client can load history.
|
|
302
|
+
*/
|
|
303
|
+
declare class RealtimeNotification extends NotificationContract<RealtimeBroadcastResult> {
|
|
304
|
+
/**
|
|
305
|
+
* The underlying transport; assignable so tests can inject a fake.
|
|
306
|
+
*/
|
|
307
|
+
driver: RealtimeDriver;
|
|
308
|
+
private user?;
|
|
309
|
+
private channelName?;
|
|
310
|
+
private eventName;
|
|
311
|
+
private channelPrefix;
|
|
312
|
+
private shouldStore;
|
|
313
|
+
private payload;
|
|
314
|
+
constructor(options?: RealtimeDriverOptions);
|
|
315
|
+
from(_from: string): this;
|
|
316
|
+
subject(subject: string): this;
|
|
317
|
+
/**
|
|
318
|
+
* Set the recipient: a `User` (derives the channel) or an explicit channel string.
|
|
319
|
+
*
|
|
320
|
+
* @param recipient
|
|
321
|
+
* @returns
|
|
322
|
+
*/
|
|
323
|
+
recipient(recipient: NotificationRecipient | User): this;
|
|
324
|
+
/**
|
|
325
|
+
* Broadcast on an explicit channel/topic instead of the per-user default.
|
|
326
|
+
*
|
|
327
|
+
* @param channel
|
|
328
|
+
* @returns
|
|
329
|
+
*/
|
|
330
|
+
channel(channel: string): this;
|
|
331
|
+
/**
|
|
332
|
+
* The event name clients subscribe to (default `notification`).
|
|
333
|
+
*
|
|
334
|
+
* @param channel
|
|
335
|
+
* @returns
|
|
336
|
+
*/
|
|
337
|
+
event(event: string): this;
|
|
338
|
+
/**
|
|
339
|
+
* Also persist the notification (requires a `User` recipient).
|
|
340
|
+
*
|
|
341
|
+
* @param channel
|
|
342
|
+
* @returns
|
|
343
|
+
*/
|
|
344
|
+
store(store?: boolean): this;
|
|
345
|
+
type(type: DbNotificationType | null): this;
|
|
346
|
+
action(text?: string | null, link?: string | null): this;
|
|
347
|
+
meta(meta?: NotificationData | null): this;
|
|
348
|
+
private resolveChannel;
|
|
349
|
+
send(message: string, subject?: string, _recipient?: NotificationRecipient, data?: NotificationData): Promise<RealtimeBroadcastResult>;
|
|
350
|
+
}
|
|
351
|
+
//#endregion
|
|
226
352
|
//#region src/drivers/sms/AfricasTalkingSmsDriver.d.ts
|
|
227
353
|
declare class AfricasTalkingSmsDriver {
|
|
228
354
|
private driver;
|
|
@@ -258,17 +384,20 @@ type DriverMap = {
|
|
|
258
384
|
email: MailNotification;
|
|
259
385
|
sms: SmsNotification;
|
|
260
386
|
db: DbNotification;
|
|
387
|
+
realtime: RealtimeNotification;
|
|
261
388
|
};
|
|
262
389
|
//#endregion
|
|
263
390
|
//#region src/Notification.d.ts
|
|
391
|
+
type DriverOptions = MailDriverOptions | SmsDriverOptions | RealtimeDriverOptions;
|
|
264
392
|
declare class Notification<D extends keyof DriverMap = keyof DriverMap> {
|
|
265
393
|
private driver;
|
|
266
|
-
constructor(driver: D, options?:
|
|
394
|
+
constructor(driver: D, options?: DriverOptions);
|
|
267
395
|
static mail(options?: MailDriverOptions): MailNotification;
|
|
268
396
|
static email(options?: MailDriverOptions): MailNotification;
|
|
269
397
|
static sms(options?: SmsDriverOptions): SmsNotification;
|
|
270
398
|
static db(): DbNotification;
|
|
271
|
-
static
|
|
399
|
+
static realtime(options?: RealtimeDriverOptions): RealtimeNotification;
|
|
400
|
+
static channel(channel?: NotificationChannel | 'email', options?: DriverOptions): MailNotification | SmsNotification | DbNotification | RealtimeNotification;
|
|
272
401
|
prepare(recipient?: null | MailRecipient | NotificationRecipient | User, data?: NotificationData): DriverMap[D];
|
|
273
402
|
private static createDriver;
|
|
274
403
|
}
|
|
@@ -287,7 +416,39 @@ declare class UserNotificationCenter {
|
|
|
287
416
|
//#region src/config.d.ts
|
|
288
417
|
declare const configure: <T extends DotPath<NotificationConfig>>(key: T, defaultValue: unknown) => DotPathValue<NotificationConfig, T>;
|
|
289
418
|
//#endregion
|
|
419
|
+
//#region src/drivers/realtime/PusherRealtimeDriver.d.ts
|
|
420
|
+
/**
|
|
421
|
+
* Broadcasts notifications over [Pusher Channels](https://pusher.com/channels).
|
|
422
|
+
*
|
|
423
|
+
* The `pusher` server SDK is an optional peer dependency, imported lazily so the
|
|
424
|
+
* package installs without it; it is only required when this transport is used.
|
|
425
|
+
*/
|
|
426
|
+
declare class PusherRealtimeDriver implements RealtimeDriver {
|
|
427
|
+
private options;
|
|
428
|
+
private clientPromise?;
|
|
429
|
+
constructor(options?: PusherTransportConfig);
|
|
430
|
+
private client;
|
|
431
|
+
broadcast(channel: string, event: string, payload: RealtimeNotificationPayload): Promise<unknown>;
|
|
432
|
+
}
|
|
433
|
+
//#endregion
|
|
434
|
+
//#region src/drivers/realtime/FirebaseRealtimeDriver.d.ts
|
|
435
|
+
/**
|
|
436
|
+
* Broadcasts notifications over [Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging)
|
|
437
|
+
* topics (the channel name maps to an FCM topic).
|
|
438
|
+
*
|
|
439
|
+
* `firebase-admin` is an optional peer dependency, imported lazily so the
|
|
440
|
+
* package installs without it; it is only required when this transport is used.
|
|
441
|
+
* FCM data values must be strings, so the payload is JSON-encoded.
|
|
442
|
+
*/
|
|
443
|
+
declare class FirebaseRealtimeDriver implements RealtimeDriver {
|
|
444
|
+
private options;
|
|
445
|
+
private messagingPromise?;
|
|
446
|
+
constructor(options?: FirebaseTransportConfig);
|
|
447
|
+
private messaging;
|
|
448
|
+
broadcast(channel: string, event: string, payload: RealtimeNotificationPayload): Promise<string>;
|
|
449
|
+
}
|
|
450
|
+
//#endregion
|
|
290
451
|
//#region src/utils/template.d.ts
|
|
291
452
|
declare const interpolate: (value: string, data?: NotificationData) => string;
|
|
292
453
|
//#endregion
|
|
293
|
-
export { AfricasTalkingSmsDriver, DbNotification, DbNotificationPayload, DbNotificationType, DriverResult, MailDriverOptions, MailNotification, MailRecipient, MailRecipientAddress, MergedTransportConfig, Notification, NotificationChannel, NotificationConfig, NotificationContract, NotificationData, NotificationDriverMap, NotificationRecipient, SmsDriverName, SmsDriverOptions, SmsNotification, TwilioSmsDriver, UserNotification, UserNotificationCenter, configure, interpolate };
|
|
454
|
+
export { AfricasTalkingSmsDriver, DbNotification, DbNotificationPayload, DbNotificationType, DriverResult, 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 };
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { mkdir, writeFile } from "node:fs/promises";
|
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import nodemailer from "nodemailer";
|
|
5
5
|
import { Arkstack } from "@arkstack/contract";
|
|
6
|
+
import { randomUUID } from "node:crypto";
|
|
6
7
|
import africastalking from "africastalking";
|
|
7
8
|
import twilio from "twilio";
|
|
8
9
|
import { Model } from "@arkstack/database";
|
|
@@ -321,6 +322,222 @@ var MailNotification = class extends NotificationContract {
|
|
|
321
322
|
}
|
|
322
323
|
};
|
|
323
324
|
//#endregion
|
|
325
|
+
//#region src/drivers/realtime/FirebaseRealtimeDriver.ts
|
|
326
|
+
/**
|
|
327
|
+
* Broadcasts notifications over [Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging)
|
|
328
|
+
* topics (the channel name maps to an FCM topic).
|
|
329
|
+
*
|
|
330
|
+
* `firebase-admin` is an optional peer dependency, imported lazily so the
|
|
331
|
+
* package installs without it; it is only required when this transport is used.
|
|
332
|
+
* FCM data values must be strings, so the payload is JSON-encoded.
|
|
333
|
+
*/
|
|
334
|
+
var FirebaseRealtimeDriver = class {
|
|
335
|
+
options;
|
|
336
|
+
messagingPromise;
|
|
337
|
+
constructor(options = {}) {
|
|
338
|
+
this.options = options;
|
|
339
|
+
}
|
|
340
|
+
messaging() {
|
|
341
|
+
this.messagingPromise ??= (async () => {
|
|
342
|
+
const [app, messaging] = await Promise.all([import("firebase-admin/app"), import("firebase-admin/messaging")]).catch(() => {
|
|
343
|
+
throw new Error("The \"firebase-admin\" package is required for the Firebase realtime transport. Install it with `npm i firebase-admin`.");
|
|
344
|
+
});
|
|
345
|
+
const credential = app.cert({
|
|
346
|
+
projectId: this.options.project_id ?? env("FIREBASE_PROJECT_ID", ""),
|
|
347
|
+
clientEmail: this.options.client_email ?? env("FIREBASE_CLIENT_EMAIL", ""),
|
|
348
|
+
privateKey: (this.options.private_key ?? env("FIREBASE_PRIVATE_KEY", ""))?.replace(/\\n/g, "\n")
|
|
349
|
+
});
|
|
350
|
+
const name = "arkstack-realtime";
|
|
351
|
+
const instance = app.getApps().find((a) => a.name === name) ?? app.initializeApp({ credential }, name);
|
|
352
|
+
return messaging.getMessaging(instance);
|
|
353
|
+
})();
|
|
354
|
+
return this.messagingPromise;
|
|
355
|
+
}
|
|
356
|
+
async broadcast(channel, event, payload) {
|
|
357
|
+
const messaging = await this.messaging();
|
|
358
|
+
const topic = channel.replace(/[^a-zA-Z0-9-_.~%]/g, "_");
|
|
359
|
+
return await messaging.send({
|
|
360
|
+
topic,
|
|
361
|
+
data: {
|
|
362
|
+
event,
|
|
363
|
+
payload: JSON.stringify(payload)
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
//#endregion
|
|
369
|
+
//#region src/drivers/realtime/PusherRealtimeDriver.ts
|
|
370
|
+
/**
|
|
371
|
+
* Broadcasts notifications over [Pusher Channels](https://pusher.com/channels).
|
|
372
|
+
*
|
|
373
|
+
* The `pusher` server SDK is an optional peer dependency, imported lazily so the
|
|
374
|
+
* package installs without it; it is only required when this transport is used.
|
|
375
|
+
*/
|
|
376
|
+
var PusherRealtimeDriver = class {
|
|
377
|
+
options;
|
|
378
|
+
clientPromise;
|
|
379
|
+
constructor(options = {}) {
|
|
380
|
+
this.options = options;
|
|
381
|
+
}
|
|
382
|
+
client() {
|
|
383
|
+
this.clientPromise ??= (async () => {
|
|
384
|
+
const mod = await import("pusher").catch(() => {
|
|
385
|
+
throw new Error("The \"pusher\" package is required for the Pusher realtime transport. Install it with `npm i pusher`.");
|
|
386
|
+
});
|
|
387
|
+
return new (mod.default ?? mod)({
|
|
388
|
+
appId: this.options.app_id ?? env("PUSHER_APP_ID", ""),
|
|
389
|
+
key: this.options.key ?? env("PUSHER_KEY", ""),
|
|
390
|
+
secret: this.options.secret ?? env("PUSHER_SECRET", ""),
|
|
391
|
+
cluster: this.options.cluster ?? env("PUSHER_CLUSTER", "mt1"),
|
|
392
|
+
useTLS: this.options.use_tls ?? true
|
|
393
|
+
});
|
|
394
|
+
})();
|
|
395
|
+
return this.clientPromise;
|
|
396
|
+
}
|
|
397
|
+
async broadcast(channel, event, payload) {
|
|
398
|
+
return await (await this.client()).trigger(channel, event, payload);
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
//#endregion
|
|
402
|
+
//#region src/drivers/RealtimeNotification.ts
|
|
403
|
+
/**
|
|
404
|
+
* Broadcasts a notification to connected clients over a realtime transport
|
|
405
|
+
* (Pusher or Firebase). The notification is delivered on a per-user channel and,
|
|
406
|
+
* when `store` is enabled, is also persisted so the client can load history.
|
|
407
|
+
*/
|
|
408
|
+
var RealtimeNotification = class extends NotificationContract {
|
|
409
|
+
/**
|
|
410
|
+
* The underlying transport; assignable so tests can inject a fake.
|
|
411
|
+
*/
|
|
412
|
+
driver;
|
|
413
|
+
user;
|
|
414
|
+
channelName;
|
|
415
|
+
eventName;
|
|
416
|
+
channelPrefix;
|
|
417
|
+
shouldStore;
|
|
418
|
+
payload = {};
|
|
419
|
+
constructor(options = {}) {
|
|
420
|
+
super();
|
|
421
|
+
const driverConfig = configure("drivers.realtime", {});
|
|
422
|
+
const transport = options.transport ?? driverConfig?.transport ?? "pusher";
|
|
423
|
+
const transportConfig = configure(`transports.${transport}`, {});
|
|
424
|
+
this.channelName = options.channel;
|
|
425
|
+
this.eventName = options.event ?? driverConfig?.event ?? "notification";
|
|
426
|
+
this.channelPrefix = driverConfig?.channel_prefix ?? "user.";
|
|
427
|
+
this.shouldStore = options.store ?? driverConfig?.store ?? false;
|
|
428
|
+
this.driver = transport === "firebase" ? new FirebaseRealtimeDriver({
|
|
429
|
+
...transportConfig,
|
|
430
|
+
...options.firebase
|
|
431
|
+
}) : new PusherRealtimeDriver({
|
|
432
|
+
...transportConfig,
|
|
433
|
+
...options.pusher
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
from(_from) {
|
|
437
|
+
return this;
|
|
438
|
+
}
|
|
439
|
+
subject(subject) {
|
|
440
|
+
this.payload.title = subject;
|
|
441
|
+
return this;
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Set the recipient: a `User` (derives the channel) or an explicit channel string.
|
|
445
|
+
*
|
|
446
|
+
* @param recipient
|
|
447
|
+
* @returns
|
|
448
|
+
*/
|
|
449
|
+
recipient(recipient) {
|
|
450
|
+
if (typeof recipient === "object" && !Array.isArray(recipient) && "id" in recipient) {
|
|
451
|
+
this.user = recipient;
|
|
452
|
+
return this;
|
|
453
|
+
}
|
|
454
|
+
if (typeof recipient === "string") {
|
|
455
|
+
this.channelName = recipient;
|
|
456
|
+
return this;
|
|
457
|
+
}
|
|
458
|
+
throw new Error("Realtime notifications require a user recipient or a channel name");
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Broadcast on an explicit channel/topic instead of the per-user default.
|
|
462
|
+
*
|
|
463
|
+
* @param channel
|
|
464
|
+
* @returns
|
|
465
|
+
*/
|
|
466
|
+
channel(channel) {
|
|
467
|
+
this.channelName = channel;
|
|
468
|
+
return this;
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* The event name clients subscribe to (default `notification`).
|
|
472
|
+
*
|
|
473
|
+
* @param channel
|
|
474
|
+
* @returns
|
|
475
|
+
*/
|
|
476
|
+
event(event) {
|
|
477
|
+
this.eventName = event;
|
|
478
|
+
return this;
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Also persist the notification (requires a `User` recipient).
|
|
482
|
+
*
|
|
483
|
+
* @param channel
|
|
484
|
+
* @returns
|
|
485
|
+
*/
|
|
486
|
+
store(store = true) {
|
|
487
|
+
this.shouldStore = store;
|
|
488
|
+
return this;
|
|
489
|
+
}
|
|
490
|
+
type(type) {
|
|
491
|
+
this.payload.type = type;
|
|
492
|
+
return this;
|
|
493
|
+
}
|
|
494
|
+
action(text, link) {
|
|
495
|
+
this.payload.actionText = text;
|
|
496
|
+
this.payload.actionLink = link;
|
|
497
|
+
return this;
|
|
498
|
+
}
|
|
499
|
+
meta(meta) {
|
|
500
|
+
this.payload.meta = meta;
|
|
501
|
+
return this;
|
|
502
|
+
}
|
|
503
|
+
resolveChannel() {
|
|
504
|
+
if (this.channelName) return this.channelName;
|
|
505
|
+
if (this.user) return `${this.channelPrefix}${this.user.id}`;
|
|
506
|
+
throw new Error("No channel resolved for realtime notification (provide a user or channel)");
|
|
507
|
+
}
|
|
508
|
+
async send(message, subject, _recipient, data) {
|
|
509
|
+
const channel = this.resolveChannel();
|
|
510
|
+
const mergedData = this.mergeData(data);
|
|
511
|
+
const base = {
|
|
512
|
+
type: this.payload.type ?? null,
|
|
513
|
+
title: interpolate(subject ?? this.payload.title ?? "", mergedData),
|
|
514
|
+
description: interpolate(message, mergedData),
|
|
515
|
+
actionText: this.payload.actionText ?? null,
|
|
516
|
+
actionLink: this.payload.actionLink ?? null,
|
|
517
|
+
meta: this.payload.meta ?? null
|
|
518
|
+
};
|
|
519
|
+
const stored = this.shouldStore && this.user ? await UserNotificationCenter.create(this.user, base) : void 0;
|
|
520
|
+
const payload = {
|
|
521
|
+
id: stored ? String(stored.id) : randomUUID(),
|
|
522
|
+
type: base.type ?? null,
|
|
523
|
+
title: base.title,
|
|
524
|
+
description: base.description,
|
|
525
|
+
actionText: base.actionText ?? null,
|
|
526
|
+
actionLink: base.actionLink ?? null,
|
|
527
|
+
meta: base.meta ?? null,
|
|
528
|
+
read_at: stored?.readAt ? new Date(stored.readAt).toISOString() : null,
|
|
529
|
+
created_at: stored?.createdAt ? new Date(stored.createdAt).toISOString() : (/* @__PURE__ */ new Date()).toISOString()
|
|
530
|
+
};
|
|
531
|
+
await this.driver.broadcast(channel, this.eventName, payload);
|
|
532
|
+
return {
|
|
533
|
+
channel,
|
|
534
|
+
event: this.eventName,
|
|
535
|
+
payload,
|
|
536
|
+
stored
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
//#endregion
|
|
324
541
|
//#region src/drivers/sms/AfricasTalkingSmsDriver.ts
|
|
325
542
|
var AfricasTalkingSmsDriver = class {
|
|
326
543
|
driver;
|
|
@@ -433,6 +650,9 @@ var Notification = class Notification {
|
|
|
433
650
|
static db() {
|
|
434
651
|
return new DbNotification();
|
|
435
652
|
}
|
|
653
|
+
static realtime(options) {
|
|
654
|
+
return new RealtimeNotification(options);
|
|
655
|
+
}
|
|
436
656
|
static channel(channel, options) {
|
|
437
657
|
return Notification.createDriver(channel ?? configure("default_driver", "mail"), options);
|
|
438
658
|
}
|
|
@@ -455,6 +675,7 @@ var Notification = class Notification {
|
|
|
455
675
|
case "email": return new MailNotification(options);
|
|
456
676
|
case "sms": return new SmsNotification(options);
|
|
457
677
|
case "db": return new DbNotification();
|
|
678
|
+
case "realtime": return new RealtimeNotification(options);
|
|
458
679
|
default: throw new Error(`Unsupported notification driver: ${driver}`);
|
|
459
680
|
}
|
|
460
681
|
}
|
|
@@ -466,4 +687,4 @@ var UserNotification = class extends Model {
|
|
|
466
687
|
casts = { meta: "json" };
|
|
467
688
|
};
|
|
468
689
|
//#endregion
|
|
469
|
-
export { AfricasTalkingSmsDriver, DbNotification, MailNotification, Notification, NotificationContract, SmsNotification, TwilioSmsDriver, UserNotification, UserNotificationCenter, configure, interpolate };
|
|
690
|
+
export { AfricasTalkingSmsDriver, DbNotification, FirebaseRealtimeDriver, MailNotification, Notification, NotificationContract, PusherRealtimeDriver, RealtimeNotification, SmsNotification, TwilioSmsDriver, UserNotification, UserNotificationCenter, configure, interpolate };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arkstack/notifications",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.7",
|
|
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,11 +34,21 @@
|
|
|
34
34
|
"africastalking": "^0.8.0",
|
|
35
35
|
"nodemailer": "^8.0.7",
|
|
36
36
|
"twilio": "^6.0.0",
|
|
37
|
-
"@arkstack/common": "^0.16.
|
|
37
|
+
"@arkstack/common": "^0.16.7"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
|
-
"
|
|
41
|
-
"
|
|
40
|
+
"pusher": "^5.2.0",
|
|
41
|
+
"firebase-admin": "^13.0.0",
|
|
42
|
+
"@arkstack/database": "^0.16.7",
|
|
43
|
+
"@arkstack/contract": "^0.16.7"
|
|
44
|
+
},
|
|
45
|
+
"peerDependenciesMeta": {
|
|
46
|
+
"pusher": {
|
|
47
|
+
"optional": true
|
|
48
|
+
},
|
|
49
|
+
"firebase-admin": {
|
|
50
|
+
"optional": true
|
|
51
|
+
}
|
|
42
52
|
},
|
|
43
53
|
"devDependencies": {
|
|
44
54
|
"@types/nodemailer": "^7.0.11"
|