@arkstack/notifications 0.5.2 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -3
- package/dist/index.d.ts +129 -22
- package/dist/index.js +152 -59
- package/package.json +6 -4
- package/resources/views/mail.edge +10 -0
- package/dist/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# @arkstack/notifications
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@arkstack/notifications)
|
|
4
|
+
|
|
3
5
|
Framework-agnostic notification module for Arkstack and Nodejs, providing support for multi-channel notification delivery.
|
|
4
6
|
|
|
5
7
|
```ts
|
|
@@ -30,7 +32,7 @@ export default () => ({
|
|
|
30
32
|
drivers: {
|
|
31
33
|
mail: {
|
|
32
34
|
transport: 'smtp',
|
|
33
|
-
from: env('
|
|
35
|
+
from: env('MAIL_FROM_ADDRESS', 'no-reply@example.com'),
|
|
34
36
|
},
|
|
35
37
|
sms: {
|
|
36
38
|
transport: 'africastalking',
|
|
@@ -42,8 +44,8 @@ export default () => ({
|
|
|
42
44
|
},
|
|
43
45
|
transports: {
|
|
44
46
|
smtp: {
|
|
45
|
-
host: env('
|
|
46
|
-
port: env('
|
|
47
|
+
host: env('MAIL_HOST', 'localhost'),
|
|
48
|
+
port: env('MAIL_PORT', 1025),
|
|
47
49
|
},
|
|
48
50
|
africastalking: {
|
|
49
51
|
username: env('AFRICASTALKING_USERNAME', 'sandbox'),
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Model } from "arkormx";
|
|
1
|
+
import { DotPath, DotPathValue, MergedConfig } from "@arkstack/common";
|
|
3
2
|
import { Transporter } from "nodemailer";
|
|
3
|
+
import { Model } from "@arkstack/database";
|
|
4
|
+
import { User } from "@app/models/User";
|
|
5
|
+
import { User as User$1 } from "@arkstack/auth";
|
|
4
6
|
import * as _$twilio_lib_rest_api_v2010_account_message0 from "twilio/lib/rest/api/v2010/account/message.js";
|
|
7
|
+
import * as _$arkormx from "arkormx";
|
|
5
8
|
|
|
6
9
|
//#region src/Contracts/UserNotification.d.ts
|
|
7
10
|
declare abstract class UserNotification extends Model {
|
|
8
|
-
|
|
9
|
-
userId: number | string;
|
|
11
|
+
[key: string]: any;
|
|
10
12
|
type: DbNotificationType | null;
|
|
11
13
|
title: string;
|
|
12
14
|
description: string;
|
|
@@ -29,13 +31,8 @@ type MailRecipient = string | MailRecipientAddress | Array<string | MailRecipien
|
|
|
29
31
|
type NotificationData = Record<string, unknown>;
|
|
30
32
|
type SmsDriverName = 'africastalking' | 'twilio';
|
|
31
33
|
type NotificationChannel = 'mail' | 'sms' | 'db';
|
|
32
|
-
type NotificationUser = {
|
|
33
|
-
id: string | number;
|
|
34
|
-
email?: string | null;
|
|
35
|
-
phone?: string | null;
|
|
36
|
-
};
|
|
37
34
|
type MailDriverOptions = {
|
|
38
|
-
transport?:
|
|
35
|
+
transport?: 'africastalking' | 'twilio' | 'file' | 'smtp';
|
|
39
36
|
host?: string;
|
|
40
37
|
port?: number;
|
|
41
38
|
secure?: boolean;
|
|
@@ -43,6 +40,7 @@ type MailDriverOptions = {
|
|
|
43
40
|
pass?: string;
|
|
44
41
|
from?: string;
|
|
45
42
|
testAddress?: string;
|
|
43
|
+
directory?: string;
|
|
46
44
|
};
|
|
47
45
|
type SmsDriverOptions = {
|
|
48
46
|
transport?: SmsDriverName;
|
|
@@ -73,6 +71,64 @@ type NotificationDriverMap = {
|
|
|
73
71
|
sms: DriverResult;
|
|
74
72
|
db: UserNotification;
|
|
75
73
|
};
|
|
74
|
+
interface NotificationConfig {
|
|
75
|
+
default_driver: 'mail' | 'sms' | 'db';
|
|
76
|
+
drivers: {
|
|
77
|
+
mail: {
|
|
78
|
+
transport: 'smtp' | 'file';
|
|
79
|
+
from: string;
|
|
80
|
+
test_address: string;
|
|
81
|
+
};
|
|
82
|
+
sms: {
|
|
83
|
+
transport: 'africastalking' | 'twillio';
|
|
84
|
+
from: string;
|
|
85
|
+
};
|
|
86
|
+
db: {
|
|
87
|
+
table: string;
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
transports: {
|
|
91
|
+
smtp: {
|
|
92
|
+
host: string;
|
|
93
|
+
port: number;
|
|
94
|
+
secure: boolean;
|
|
95
|
+
auth: {
|
|
96
|
+
user: string;
|
|
97
|
+
pass: string;
|
|
98
|
+
};
|
|
99
|
+
user?: string;
|
|
100
|
+
pass?: string;
|
|
101
|
+
test_address?: string;
|
|
102
|
+
} | {
|
|
103
|
+
host: string;
|
|
104
|
+
port: number;
|
|
105
|
+
secure: boolean;
|
|
106
|
+
auth?: {
|
|
107
|
+
user: string;
|
|
108
|
+
pass: string;
|
|
109
|
+
};
|
|
110
|
+
user: string;
|
|
111
|
+
pass: string;
|
|
112
|
+
test_address?: string;
|
|
113
|
+
};
|
|
114
|
+
file: {
|
|
115
|
+
directory: string;
|
|
116
|
+
from?: string;
|
|
117
|
+
test_address?: string;
|
|
118
|
+
};
|
|
119
|
+
africastalking: {
|
|
120
|
+
username: string;
|
|
121
|
+
apiKey: string;
|
|
122
|
+
senderId: string;
|
|
123
|
+
};
|
|
124
|
+
twilio: {
|
|
125
|
+
accountSid: string;
|
|
126
|
+
authToken: string;
|
|
127
|
+
from: string;
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
type MergedTransportConfig = MergedConfig<NotificationConfig['transports'][NonNullable<MailDriverOptions['transport']>]>;
|
|
76
132
|
//#endregion
|
|
77
133
|
//#region src/Contracts/NotificationContract.d.ts
|
|
78
134
|
declare abstract class NotificationContract<TResult = DriverResult> {
|
|
@@ -93,12 +149,12 @@ declare class DbNotification extends NotificationContract<UserNotification> {
|
|
|
93
149
|
private payload;
|
|
94
150
|
from(_from: string): this;
|
|
95
151
|
subject(subject: string): this;
|
|
96
|
-
recipient(recipient: NotificationRecipient |
|
|
152
|
+
recipient(recipient: NotificationRecipient | User): this;
|
|
97
153
|
type(type: DbNotificationPayload['type']): this;
|
|
98
154
|
action(text?: string | null, link?: string | null): this;
|
|
99
155
|
meta(meta?: NotificationData | null): this;
|
|
100
|
-
create(user:
|
|
101
|
-
send(message: string, subject?: string, _recipient?: NotificationRecipient, data?: NotificationData): Promise<UserNotification
|
|
156
|
+
create(user: User, payload: DbNotificationPayload): Promise<UserNotification>;
|
|
157
|
+
send(message: string, subject?: string, _recipient?: NotificationRecipient, data?: NotificationData): Promise<UserNotification>;
|
|
102
158
|
}
|
|
103
159
|
//#endregion
|
|
104
160
|
//#region src/drivers/MailNotification.d.ts
|
|
@@ -107,12 +163,64 @@ declare class MailNotification extends NotificationContract {
|
|
|
107
163
|
private fromAddress?;
|
|
108
164
|
private subjectLine?;
|
|
109
165
|
private recipients?;
|
|
110
|
-
|
|
166
|
+
private ViewName;
|
|
167
|
+
private htmlTemplate?;
|
|
168
|
+
private textTemplate?;
|
|
169
|
+
private fileDirectory?;
|
|
111
170
|
constructor(options?: MailDriverOptions);
|
|
112
171
|
from(from: string): this;
|
|
172
|
+
/**
|
|
173
|
+
* The email subject
|
|
174
|
+
*
|
|
175
|
+
* @param subject
|
|
176
|
+
* @returns
|
|
177
|
+
*/
|
|
113
178
|
subject(subject: string): this;
|
|
179
|
+
/**
|
|
180
|
+
* Set email the notification recipeint
|
|
181
|
+
*
|
|
182
|
+
* @param recipient string or array of email addresses
|
|
183
|
+
* @returns
|
|
184
|
+
*/
|
|
114
185
|
recipient(recipient: MailRecipient): this;
|
|
186
|
+
/**
|
|
187
|
+
* Set email the notification view name
|
|
188
|
+
*
|
|
189
|
+
* @param view view name
|
|
190
|
+
* @returns
|
|
191
|
+
*/
|
|
192
|
+
view(view: string): this;
|
|
193
|
+
/**
|
|
194
|
+
* Set email the notification html template
|
|
195
|
+
*
|
|
196
|
+
* @param content view name
|
|
197
|
+
* @returns
|
|
198
|
+
*/
|
|
199
|
+
html(content: string): this;
|
|
200
|
+
/**
|
|
201
|
+
* Set email the notification text template
|
|
202
|
+
*
|
|
203
|
+
* @param content view name
|
|
204
|
+
* @returns
|
|
205
|
+
*/
|
|
206
|
+
text(content: string): this;
|
|
207
|
+
/**
|
|
208
|
+
* Prepare a notification to be sent.
|
|
209
|
+
*
|
|
210
|
+
* @param user The recipient user(s) for the notification.
|
|
211
|
+
*/
|
|
212
|
+
prepare(user?: null | string | string[] | User$1, data?: Record<string, any>): this;
|
|
213
|
+
/**
|
|
214
|
+
* Send a notification to the specified recipient(s) with the given message.
|
|
215
|
+
*
|
|
216
|
+
* @param message The message content to be sent to the recipient(s).
|
|
217
|
+
* @param subject The message subject to be sent to the recipient(s).
|
|
218
|
+
* @param recipient An array of recipient identifiers
|
|
219
|
+
* @param data Additioal context data
|
|
220
|
+
* @returns
|
|
221
|
+
*/
|
|
115
222
|
send(message: string, subject?: string, recipient?: MailRecipient, data?: NotificationData): Promise<any>;
|
|
223
|
+
private storeFileMail;
|
|
116
224
|
private resolveRecipients;
|
|
117
225
|
private normalizeRecipient;
|
|
118
226
|
}
|
|
@@ -163,26 +271,25 @@ declare class Notification<D extends keyof DriverMap = keyof DriverMap> {
|
|
|
163
271
|
static sms(options?: SmsDriverOptions): SmsNotification;
|
|
164
272
|
static db(): DbNotification;
|
|
165
273
|
static channel(channel?: NotificationChannel | 'email', options?: MailDriverOptions | SmsDriverOptions): MailNotification | SmsNotification | DbNotification;
|
|
166
|
-
prepare(recipient?: null | MailRecipient | NotificationRecipient |
|
|
274
|
+
prepare(recipient?: null | MailRecipient | NotificationRecipient | User, data?: NotificationData): DriverMap[D];
|
|
167
275
|
private static createDriver;
|
|
168
276
|
}
|
|
169
277
|
//#endregion
|
|
170
278
|
//#region src/UserNotificationCenter.d.ts
|
|
171
279
|
declare class UserNotificationCenter {
|
|
172
280
|
private static getModel;
|
|
173
|
-
static create(user:
|
|
174
|
-
static forUser(user:
|
|
175
|
-
static unreadForUser(user:
|
|
281
|
+
static create(user: User, payload: DbNotificationPayload): Promise<UserNotification>;
|
|
282
|
+
static forUser(user: User): Promise<_$arkormx.ArkormCollection<UserNotification, UserNotification[]>>;
|
|
283
|
+
static unreadForUser(user: User): Promise<_$arkormx.ArkormCollection<UserNotification, UserNotification[]>>;
|
|
176
284
|
static markRead(notification: UserNotification | UserNotification['id']): Promise<void>;
|
|
177
|
-
static markAllRead(user:
|
|
285
|
+
static markAllRead(user: User): Promise<void>;
|
|
178
286
|
static delete(notification: UserNotification | UserNotification['id']): Promise<void>;
|
|
179
287
|
}
|
|
180
288
|
//#endregion
|
|
181
289
|
//#region src/config.d.ts
|
|
182
|
-
declare const
|
|
290
|
+
declare const configure: <T extends DotPath<NotificationConfig>>(key: T, defaultValue: unknown) => DotPathValue<NotificationConfig, T>;
|
|
183
291
|
//#endregion
|
|
184
292
|
//#region src/utils/template.d.ts
|
|
185
293
|
declare const interpolate: (value: string, data?: NotificationData) => string;
|
|
186
294
|
//#endregion
|
|
187
|
-
export { AfricasTalkingSmsDriver, DbNotification, DbNotificationPayload, DbNotificationType, DriverResult, MailDriverOptions, MailNotification, MailRecipient, MailRecipientAddress, Notification, NotificationChannel, NotificationContract, NotificationData, NotificationDriverMap, NotificationRecipient,
|
|
188
|
-
//# sourceMappingURL=index.d.ts.map
|
|
295
|
+
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 };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { config, env, getModel } from "@arkstack/common";
|
|
2
|
-
import {
|
|
2
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
3
4
|
import nodemailer from "nodemailer";
|
|
5
|
+
import { Arkstack } from "@arkstack/contract";
|
|
4
6
|
import africastalking from "africastalking";
|
|
5
7
|
import twilio from "twilio";
|
|
8
|
+
import { Model } from "@arkstack/database";
|
|
6
9
|
//#region src/Contracts/NotificationContract.ts
|
|
7
10
|
var NotificationContract = class {
|
|
8
11
|
contextData = {};
|
|
@@ -19,12 +22,6 @@ var NotificationContract = class {
|
|
|
19
22
|
}
|
|
20
23
|
};
|
|
21
24
|
//#endregion
|
|
22
|
-
//#region src/Contracts/UserNotification.ts
|
|
23
|
-
var UserNotification = class extends Model {
|
|
24
|
-
static table = "user_notifications";
|
|
25
|
-
casts = { meta: "json" };
|
|
26
|
-
};
|
|
27
|
-
//#endregion
|
|
28
25
|
//#region src/UserNotificationCenter.ts
|
|
29
26
|
var UserNotificationCenter = class {
|
|
30
27
|
static async getModel() {
|
|
@@ -52,10 +49,10 @@ var UserNotificationCenter = class {
|
|
|
52
49
|
}
|
|
53
50
|
static async markRead(notification) {
|
|
54
51
|
const Model = await this.getModel();
|
|
55
|
-
const id = notification
|
|
52
|
+
const id = typeof notification === "object" ? notification.id : notification;
|
|
56
53
|
const readAt = /* @__PURE__ */ new Date();
|
|
57
54
|
await Model.query().where({ id }).update({ readAt });
|
|
58
|
-
if (notification
|
|
55
|
+
if (typeof notification === "object") notification.readAt = readAt;
|
|
59
56
|
}
|
|
60
57
|
static async markAllRead(user) {
|
|
61
58
|
await (await this.getModel()).query().where({
|
|
@@ -65,7 +62,7 @@ var UserNotificationCenter = class {
|
|
|
65
62
|
}
|
|
66
63
|
static async delete(notification) {
|
|
67
64
|
const Model = await this.getModel();
|
|
68
|
-
const id = notification
|
|
65
|
+
const id = typeof notification === "object" ? notification.id : notification;
|
|
69
66
|
await Model.query().where({ id }).delete();
|
|
70
67
|
}
|
|
71
68
|
};
|
|
@@ -128,7 +125,7 @@ var DbNotification = class extends NotificationContract {
|
|
|
128
125
|
};
|
|
129
126
|
//#endregion
|
|
130
127
|
//#region src/config.ts
|
|
131
|
-
const
|
|
128
|
+
const configure = (key, defaultValue) => {
|
|
132
129
|
try {
|
|
133
130
|
return config(`notifications.${key}`, defaultValue);
|
|
134
131
|
} catch {
|
|
@@ -142,32 +139,30 @@ var MailNotification = class extends NotificationContract {
|
|
|
142
139
|
fromAddress;
|
|
143
140
|
subjectLine;
|
|
144
141
|
recipients;
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
"<h2>{subject}</h2>",
|
|
150
|
-
"<div>{message}</div>",
|
|
151
|
-
"<p style=\"color:#6b7280;font-size:12px\">© {year} {app_name}</p>",
|
|
152
|
-
"</body>",
|
|
153
|
-
"</html>"
|
|
154
|
-
].join("");
|
|
142
|
+
ViewName = "~arkstack/notifications.mail";
|
|
143
|
+
htmlTemplate;
|
|
144
|
+
textTemplate;
|
|
145
|
+
fileDirectory;
|
|
155
146
|
constructor(options = {}) {
|
|
156
147
|
super();
|
|
157
|
-
const
|
|
158
|
-
const
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
const
|
|
170
|
-
|
|
148
|
+
const driver = configure("drivers.mail", {});
|
|
149
|
+
const trpt = driver.transport ?? "smtp";
|
|
150
|
+
const transport = configure(`transports.${trpt}`, {});
|
|
151
|
+
if (trpt === "file") {
|
|
152
|
+
this.fileDirectory = options.directory ?? transport.directory ?? env("MAIL_FILE_PATH", join(Arkstack.rootDir(), "./storage/framework/mails"));
|
|
153
|
+
this.fromAddress = options.from ?? driver.from ?? transport.from ?? env("MAIL_FROM_ADDRESS", "no-reply@example.com");
|
|
154
|
+
this.driver = nodemailer.createTransport({
|
|
155
|
+
streamTransport: true,
|
|
156
|
+
buffer: true
|
|
157
|
+
});
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
const host = options.host ?? transport.host ?? env("MAIL_HOST", "localhost");
|
|
161
|
+
const port = options.port ?? transport.port ?? env("MAIL_PORT", 1025);
|
|
162
|
+
const secure = options.secure ?? transport.secure ?? env("MAIL_SECURE", false);
|
|
163
|
+
const user = options.user ?? transport.auth?.user ?? transport.user ?? env("MAIL_USERNAME", "");
|
|
164
|
+
const pass = options.pass ?? transport.auth?.pass ?? transport.pass ?? env("MAIL_PASSWORD", "");
|
|
165
|
+
this.fromAddress = options.from ?? driver.from ?? transport.from ?? env("MAIL_FROM_ADDRESS", "no-reply@example.com");
|
|
171
166
|
this.driver = nodemailer.createTransport({
|
|
172
167
|
host,
|
|
173
168
|
port: Number(port),
|
|
@@ -182,41 +177,138 @@ var MailNotification = class extends NotificationContract {
|
|
|
182
177
|
this.fromAddress = from;
|
|
183
178
|
return this;
|
|
184
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* The email subject
|
|
182
|
+
*
|
|
183
|
+
* @param subject
|
|
184
|
+
* @returns
|
|
185
|
+
*/
|
|
185
186
|
subject(subject) {
|
|
186
187
|
this.subjectLine = subject;
|
|
187
188
|
return this;
|
|
188
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* Set email the notification recipeint
|
|
192
|
+
*
|
|
193
|
+
* @param recipient string or array of email addresses
|
|
194
|
+
* @returns
|
|
195
|
+
*/
|
|
189
196
|
recipient(recipient) {
|
|
190
197
|
this.recipients = recipient;
|
|
191
198
|
return this;
|
|
192
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* Set email the notification view name
|
|
202
|
+
*
|
|
203
|
+
* @param view view name
|
|
204
|
+
* @returns
|
|
205
|
+
*/
|
|
206
|
+
view(view) {
|
|
207
|
+
this.ViewName = view;
|
|
208
|
+
return this;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Set email the notification html template
|
|
212
|
+
*
|
|
213
|
+
* @param content view name
|
|
214
|
+
* @returns
|
|
215
|
+
*/
|
|
216
|
+
html(content) {
|
|
217
|
+
this.htmlTemplate = content;
|
|
218
|
+
return this;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Set email the notification text template
|
|
222
|
+
*
|
|
223
|
+
* @param content view name
|
|
224
|
+
* @returns
|
|
225
|
+
*/
|
|
226
|
+
text(content) {
|
|
227
|
+
this.textTemplate = content;
|
|
228
|
+
return this;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Prepare a notification to be sent.
|
|
232
|
+
*
|
|
233
|
+
* @param user The recipient user(s) for the notification.
|
|
234
|
+
*/
|
|
235
|
+
prepare(user, data = {}) {
|
|
236
|
+
this.data(data);
|
|
237
|
+
if (user && typeof user === "object" && !Array.isArray(user)) user = user.email;
|
|
238
|
+
if (user) this.recipient(user);
|
|
239
|
+
return this;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Send a notification to the specified recipient(s) with the given message.
|
|
243
|
+
*
|
|
244
|
+
* @param message The message content to be sent to the recipient(s).
|
|
245
|
+
* @param subject The message subject to be sent to the recipient(s).
|
|
246
|
+
* @param recipient An array of recipient identifiers
|
|
247
|
+
* @param data Additioal context data
|
|
248
|
+
* @returns
|
|
249
|
+
*/
|
|
193
250
|
async send(message, subject, recipient, data) {
|
|
194
251
|
const mergedData = {
|
|
195
|
-
app_name:
|
|
252
|
+
app_name: config("app.name", "Arkstack"),
|
|
196
253
|
...this.mergeData(data)
|
|
197
254
|
};
|
|
198
255
|
const resolvedSubject = interpolate(subject ?? this.subjectLine ?? "", mergedData);
|
|
199
256
|
const resolvedMessage = interpolate(message, mergedData);
|
|
200
257
|
const to = this.resolveRecipients(recipient);
|
|
201
258
|
if (to.length < 1) throw new Error("No recipient provided for mail notification");
|
|
202
|
-
|
|
259
|
+
const templateData = {
|
|
260
|
+
...mergedData,
|
|
261
|
+
message: resolvedMessage,
|
|
262
|
+
subject: resolvedSubject
|
|
263
|
+
};
|
|
264
|
+
const textMessage = resolvedMessage.replace(/<\/?[^>]+(>|$)/g, "");
|
|
265
|
+
const payload = {
|
|
203
266
|
to,
|
|
204
267
|
subject: resolvedSubject,
|
|
205
268
|
from: this.fromAddress,
|
|
206
|
-
text:
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
269
|
+
text: interpolate(this.textTemplate ?? textMessage, {
|
|
270
|
+
...templateData,
|
|
271
|
+
message: textMessage
|
|
272
|
+
}),
|
|
273
|
+
html: this.htmlTemplate ? interpolate(this.htmlTemplate, templateData) : await globalThis.view(this.ViewName, templateData)
|
|
274
|
+
};
|
|
275
|
+
const result = await this.driver.sendMail(payload);
|
|
276
|
+
if (this.fileDirectory) await this.storeFileMail(payload, result);
|
|
277
|
+
return result;
|
|
278
|
+
}
|
|
279
|
+
async storeFileMail(payload, result) {
|
|
280
|
+
const now = /* @__PURE__ */ new Date();
|
|
281
|
+
const date = now.toISOString().slice(0, 10);
|
|
282
|
+
const directory = join(this.fileDirectory, date);
|
|
283
|
+
const id = String(result.messageId || now.getTime()).replace(/[^a-zA-Z0-9_.-]/g, "-");
|
|
284
|
+
const path = join(directory, now.getTime() + "-" + id + ".json");
|
|
285
|
+
const message = result.message;
|
|
286
|
+
await mkdir(directory, { recursive: true });
|
|
287
|
+
await writeFile(path, JSON.stringify({
|
|
288
|
+
id: result.messageId,
|
|
289
|
+
date: now.toISOString(),
|
|
290
|
+
envelope: result.envelope,
|
|
291
|
+
accepted: result.accepted,
|
|
292
|
+
rejected: result.rejected,
|
|
293
|
+
pending: result.pending,
|
|
294
|
+
response: result.response,
|
|
295
|
+
message: {
|
|
296
|
+
from: payload.from,
|
|
297
|
+
to: payload.to,
|
|
298
|
+
subject: payload.subject,
|
|
299
|
+
text: payload.text,
|
|
300
|
+
html: payload.html,
|
|
301
|
+
raw: Buffer.isBuffer(message) ? message.toString("utf8") : String(message ?? "")
|
|
302
|
+
}
|
|
303
|
+
}, null, 2), "utf8");
|
|
304
|
+
return path;
|
|
213
305
|
}
|
|
214
306
|
resolveRecipients(recipient) {
|
|
215
307
|
const recipients = recipient ?? this.recipients;
|
|
216
308
|
const resolved = (Array.isArray(recipients) ? [...recipients] : recipients ? [recipients] : []).flatMap((recipient) => this.normalizeRecipient(recipient));
|
|
217
|
-
const
|
|
218
|
-
const
|
|
219
|
-
const testAddress =
|
|
309
|
+
const driver = configure("drivers.mail", {});
|
|
310
|
+
const transport = configure(`transports.${driver.transport ?? "smtp"}`, {});
|
|
311
|
+
const testAddress = driver.test_address ?? driver.test_address ?? transport.test_address ?? transport.test_address ?? env("MAIL_TEST_ADDRESS");
|
|
220
312
|
if (env("NODE_ENV") !== "production" && testAddress) resolved.push(testAddress);
|
|
221
313
|
return resolved;
|
|
222
314
|
}
|
|
@@ -286,22 +378,19 @@ var SmsNotification = class extends NotificationContract {
|
|
|
286
378
|
fromValue;
|
|
287
379
|
constructor(options = {}) {
|
|
288
380
|
super();
|
|
289
|
-
const driverConfig =
|
|
381
|
+
const driverConfig = configure("drivers.sms", {});
|
|
290
382
|
const transport = options.transport ?? driverConfig.transport ?? "twilio";
|
|
291
|
-
const transportConfig =
|
|
292
|
-
const
|
|
293
|
-
const from = options.from ?? driverConfig.from ?? legacySmsConfig.from;
|
|
383
|
+
const transportConfig = configure(`transports.${transport}`, {});
|
|
384
|
+
const from = options.from ?? driverConfig.from;
|
|
294
385
|
this.fromValue = from;
|
|
295
386
|
this.driver = transport === "twilio" ? new TwilioSmsDriver({
|
|
296
|
-
...legacySmsConfig.twilio,
|
|
297
387
|
...transportConfig,
|
|
298
388
|
...options.twilio,
|
|
299
|
-
from: options.twilio?.from ?? transportConfig.from ??
|
|
389
|
+
from: options.twilio?.from ?? transportConfig.from ?? from
|
|
300
390
|
}) : new AfricasTalkingSmsDriver({
|
|
301
|
-
...legacySmsConfig.africastalking,
|
|
302
391
|
...transportConfig,
|
|
303
392
|
...options.africastalking,
|
|
304
|
-
senderId: options.africastalking?.senderId ?? transportConfig.senderId ??
|
|
393
|
+
senderId: options.africastalking?.senderId ?? transportConfig.senderId ?? from
|
|
305
394
|
});
|
|
306
395
|
}
|
|
307
396
|
from(from) {
|
|
@@ -345,7 +434,7 @@ var Notification = class Notification {
|
|
|
345
434
|
return new DbNotification();
|
|
346
435
|
}
|
|
347
436
|
static channel(channel, options) {
|
|
348
|
-
return Notification.createDriver(channel ??
|
|
437
|
+
return Notification.createDriver(channel ?? configure("default_driver", "mail"), options);
|
|
349
438
|
}
|
|
350
439
|
prepare(recipient, data = {}) {
|
|
351
440
|
this.driver.data(data);
|
|
@@ -371,6 +460,10 @@ var Notification = class Notification {
|
|
|
371
460
|
}
|
|
372
461
|
};
|
|
373
462
|
//#endregion
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
463
|
+
//#region src/Contracts/UserNotification.ts
|
|
464
|
+
var UserNotification = class extends Model {
|
|
465
|
+
static table = "user_notifications";
|
|
466
|
+
casts = { meta: "json" };
|
|
467
|
+
};
|
|
468
|
+
//#endregion
|
|
469
|
+
export { AfricasTalkingSmsDriver, DbNotification, MailNotification, Notification, NotificationContract, SmsNotification, TwilioSmsDriver, UserNotification, UserNotificationCenter, configure, interpolate };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arkstack/notifications",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
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",
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
"arkstack"
|
|
21
21
|
],
|
|
22
22
|
"files": [
|
|
23
|
-
"dist"
|
|
23
|
+
"dist",
|
|
24
|
+
"resources"
|
|
24
25
|
],
|
|
25
26
|
"publishConfig": {
|
|
26
27
|
"access": "public"
|
|
@@ -33,10 +34,11 @@
|
|
|
33
34
|
"africastalking": "^0.8.0",
|
|
34
35
|
"nodemailer": "^8.0.7",
|
|
35
36
|
"twilio": "^6.0.0",
|
|
36
|
-
"@arkstack/common": "^0.5.
|
|
37
|
+
"@arkstack/common": "^0.5.3"
|
|
37
38
|
},
|
|
38
39
|
"peerDependencies": {
|
|
39
|
-
"@arkstack/database": "^0.5.
|
|
40
|
+
"@arkstack/database": "^0.5.3",
|
|
41
|
+
"@arkstack/contract": "^0.5.3"
|
|
40
42
|
},
|
|
41
43
|
"devDependencies": {
|
|
42
44
|
"@types/nodemailer": "^7.0.11"
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/Contracts/NotificationContract.ts","../src/Contracts/UserNotification.ts","../src/UserNotificationCenter.ts","../src/utils/template.ts","../src/drivers/DbNotification.ts","../src/config.ts","../src/drivers/MailNotification.ts","../src/drivers/sms/AfricasTalkingSmsDriver.ts","../src/drivers/sms/TwilioSmsDriver.ts","../src/drivers/SmsNotification.ts","../src/Notification.ts"],"sourcesContent":["import type { DriverResult, NotificationData, NotificationRecipient } from '../types'\n\nexport abstract class NotificationContract<TResult = DriverResult> {\n protected contextData: NotificationData = {}\n\n abstract send (\n message: string,\n subject?: string,\n recipient?: NotificationRecipient,\n data?: NotificationData\n ): Promise<TResult>\n\n abstract from (from: string): this\n abstract subject (subject: string): this\n abstract recipient (recipient: NotificationRecipient): this\n\n data (data: NotificationData): this {\n this.contextData = data\n\n return this\n }\n\n protected mergeData (data?: NotificationData) {\n return {\n ...this.contextData,\n ...data,\n year: new Date().getFullYear(),\n }\n }\n}\n","import { Model } from 'arkormx'\n\nimport type { DbNotificationType, NotificationData } from '../types'\n\nexport abstract class UserNotification extends Model {\n declare id: number | string\n declare userId: number | string\n declare type: DbNotificationType | null\n declare title: string\n declare description: string\n declare actionText: string | null\n declare actionLink: string | null\n declare meta: NotificationData | null\n declare readAt: Date | null\n declare createdAt: Date\n declare updatedAt: Date\n\n protected static table?: string | undefined = 'user_notifications'\n\n protected casts = {\n meta: 'json',\n } as const\n}\n","import { getModel } from '@arkstack/common'\n\nimport { UserNotification } from './Contracts/UserNotification'\nimport type { DbNotificationPayload, NotificationUser } from './types'\n\nexport class UserNotificationCenter {\n private static async getModel () {\n return await getModel<typeof UserNotification>('UserNotification')\n }\n\n static async create (user: NotificationUser, payload: DbNotificationPayload) {\n const Model = await this.getModel()\n\n return await Model.query().create({\n userId: user.id,\n type: payload.type ?? null,\n title: payload.title,\n description: payload.description,\n actionText: payload.actionText ?? null,\n actionLink: payload.actionLink ?? null,\n meta: payload.meta ?? null,\n })\n }\n\n static async forUser (user: NotificationUser) {\n const Model = await this.getModel()\n\n return await Model.query().where({ userId: user.id }).get()\n }\n\n static async unreadForUser (user: NotificationUser) {\n const Model = await this.getModel()\n\n return await Model.query().where({ userId: user.id, readAt: null }).get()\n }\n\n static async markRead (notification: UserNotification | UserNotification['id']) {\n const Model = await this.getModel()\n const id = notification instanceof UserNotification ? notification.id : notification\n const readAt = new Date()\n\n await Model.query().where({ id }).update({ readAt })\n\n if (notification instanceof UserNotification) {\n notification.readAt = readAt\n }\n }\n\n static async markAllRead (user: NotificationUser) {\n const Model = await this.getModel()\n\n await Model.query().where({ userId: user.id, readAt: null }).update({ readAt: new Date() })\n }\n\n static async delete (notification: UserNotification | UserNotification['id']) {\n const Model = await this.getModel()\n const id = notification instanceof UserNotification ? notification.id : notification\n\n await Model.query().where({ id }).delete()\n }\n}\n","import type { NotificationData } from '../types'\n\nexport const interpolate = (value: string, data: NotificationData = {}) => {\n return value.replace(/\\{([^{}]+)\\}/g, (match, key) => {\n const replacement = data[key.trim()]\n\n return replacement === undefined || replacement === null ? match : String(replacement)\n })\n}\n","import type { DbNotificationPayload, NotificationData, NotificationRecipient, NotificationUser } from '../types'\n\nimport { NotificationContract } from '../Contracts/NotificationContract'\nimport { UserNotification } from '../Contracts/UserNotification'\nimport { UserNotificationCenter } from '../UserNotificationCenter'\nimport { getModel } from '@arkstack/common'\nimport { interpolate } from '../utils/template'\n\nexport class DbNotification extends NotificationContract<UserNotification> {\n private user?: NotificationUser\n private payload: Partial<DbNotificationPayload> = {}\n\n from (_from: string): this {\n return this\n }\n\n subject (subject: string): this {\n this.payload.title = subject\n\n return this\n }\n\n recipient (recipient: NotificationRecipient | NotificationUser): this {\n if (typeof recipient === 'object' && !Array.isArray(recipient) && 'id' in recipient) {\n this.user = recipient\n\n return this\n }\n\n throw new Error('Database notifications require a user recipient')\n }\n\n type (type: DbNotificationPayload['type']): this {\n this.payload.type = type\n\n return this\n }\n\n action (text?: string | null, link?: string | null): this {\n this.payload.actionText = text\n this.payload.actionLink = link\n\n return this\n }\n\n meta (meta?: NotificationData | null): this {\n this.payload.meta = meta\n\n return this\n }\n\n async create (user: NotificationUser, payload: DbNotificationPayload) {\n await getModel<typeof UserNotification>('UserNotification')\n\n return await UserNotificationCenter.create(user, payload)\n }\n\n async send (\n message: string,\n subject?: string,\n _recipient?: NotificationRecipient,\n data?: NotificationData\n ) {\n if (!this.user) {\n throw new Error('No user recipient provided for database notification')\n }\n\n const mergedData = this.mergeData(data)\n\n return await this.create(this.user, {\n type: this.payload.type ?? null,\n title: interpolate(subject ?? this.payload.title ?? '', mergedData),\n description: interpolate(message, mergedData),\n actionText: this.payload.actionText ?? null,\n actionLink: this.payload.actionLink ?? null,\n meta: this.payload.meta ?? null,\n })\n }\n}\n","import { config } from '@arkstack/common'\n\nexport const notificationConfig = <T = unknown> (key: string, defaultValue: T): T => {\n try {\n return config(`notifications.${key}`, defaultValue) as T\n } catch {\n return defaultValue\n }\n}\n","import { env } from '@arkstack/common'\nimport nodemailer, { type Transporter } from 'nodemailer'\n\nimport { NotificationContract } from '../Contracts/NotificationContract'\nimport { interpolate } from '../utils/template'\nimport { notificationConfig } from '../config'\nimport type { MailDriverOptions, MailRecipient, MailRecipientAddress, NotificationData } from '../types'\n\nexport class MailNotification extends NotificationContract {\n driver: Transporter\n private fromAddress?: string\n private subjectLine?: string\n private recipients?: MailRecipient\n static defaultHtmlTemplate = [\n '<!doctype html>',\n '<html>',\n '<body style=\"font-family:Arial,sans-serif;line-height:1.5;color:#111827\">',\n '<h2>{subject}</h2>',\n '<div>{message}</div>',\n '<p style=\"color:#6b7280;font-size:12px\">© {year} {app_name}</p>',\n '</body>',\n '</html>',\n ].join('')\n\n constructor(options: MailDriverOptions = {}) {\n super()\n\n const driverConfig = notificationConfig<Record<string, any>>('drivers.mail', {})\n const transport = options.transport ?? driverConfig.transport ?? 'smtp'\n const transportConfig = notificationConfig<Record<string, any>>(`transports.${transport}`, {})\n const legacyMailConfig = notificationConfig<Record<string, any>>('mail', {})\n const legacySmtpConfig = notificationConfig<Record<string, any>>('smtp', {})\n const smtpConfig = {\n ...legacySmtpConfig,\n ...(legacyMailConfig.smtp ?? {}),\n ...transportConfig,\n }\n const host = options.host ?? smtpConfig.host ?? env('SMTP_HOST', 'localhost')\n const port = options.port ?? smtpConfig.port ?? env('SMTP_PORT', 1025)\n const secure = options.secure ?? smtpConfig.secure ?? env('SMTP_SECURE', false)\n const user = options.user ?? smtpConfig.auth?.user ?? smtpConfig.user ?? env('SMTP_USERNAME', '')\n const pass = options.pass ?? smtpConfig.auth?.pass ?? smtpConfig.pass ?? env('SMTP_PASSWORD', '')\n\n this.fromAddress = options.from ?? driverConfig.from ?? legacyMailConfig.from ?? smtpConfig.from ?? env('SMTP_FROM_ADDRESS', 'no-reply@example.com')\n this.driver = nodemailer.createTransport({\n host,\n port: Number(port),\n secure: Boolean(secure),\n auth: user || pass ? { user, pass } : undefined,\n })\n }\n\n from (from: string): this {\n this.fromAddress = from\n\n return this\n }\n\n subject (subject: string): this {\n this.subjectLine = subject\n\n return this\n }\n\n recipient (recipient: MailRecipient): this {\n this.recipients = recipient\n\n return this\n }\n\n async send (\n message: string,\n subject?: string,\n recipient?: MailRecipient,\n data?: NotificationData\n ) {\n const mergedData = {\n app_name: env('APP_NAME', 'Arkstack'),\n ...this.mergeData(data),\n }\n const resolvedSubject = interpolate(subject ?? this.subjectLine ?? '', mergedData)\n const resolvedMessage = interpolate(message, mergedData)\n const to = this.resolveRecipients(recipient)\n\n if (to.length < 1) {\n throw new Error('No recipient provided for mail notification')\n }\n\n return await this.driver.sendMail({\n to: to as never,\n subject: resolvedSubject,\n from: this.fromAddress,\n text: resolvedMessage.replace(/<\\/?[^>]+(>|$)/g, ''),\n html: interpolate(await globalThis.view('~arkstack/notifications.mail', {\n ...mergedData,\n message: resolvedMessage,\n subject: resolvedSubject,\n })),\n })\n }\n\n private resolveRecipients (recipient?: MailRecipient) {\n const recipients = recipient ?? this.recipients\n const resolved = (Array.isArray(recipients)\n ? [...recipients]\n : recipients\n ? [recipients]\n : []\n ).flatMap(recipient => this.normalizeRecipient(recipient) as unknown)\n\n const driverConfig = notificationConfig<Record<string, any>>('drivers.mail', {})\n const transport = driverConfig.transport ?? 'smtp'\n const transportConfig = notificationConfig<Record<string, any>>(`transports.${transport}`, {})\n const testAddress = driverConfig.testAddress\n ?? driverConfig.test_address\n ?? transportConfig.testAddress\n ?? transportConfig.test_address\n ?? env<string | undefined>('SMTP_TEST_ADDRESS')\n\n if (env('NODE_ENV') !== 'production' && testAddress) {\n resolved.push(testAddress)\n }\n\n return resolved\n }\n\n private normalizeRecipient (recipient: string | MailRecipientAddress) {\n if (typeof recipient === 'string') {\n return [recipient]\n }\n\n return Object.entries(recipient).map(([address, name]) => ({ address, name }))\n }\n}\n","import { env } from '@arkstack/common'\nimport africastalking from 'africastalking'\n\nimport { interpolate } from '../../utils/template'\nimport type { NotificationData, NotificationRecipient, SmsDriverOptions } from '../../types'\n\nexport class AfricasTalkingSmsDriver {\n private driver: {\n send: (payload: { to: string; from?: string; message: string }) => Promise<unknown>\n sendBulk: (payload: { to: string[]; from?: string; message: string }) => Promise<unknown>\n }\n private senderId?: string\n\n constructor(options: SmsDriverOptions['africastalking'] = {}) {\n const username = options.username ?? env('AFRICASTALKING_USERNAME', 'sandbox')\n const apiKey = options.apiKey ?? env('AFRICASTALKING_API_KEY', 'sandbox')\n\n this.senderId = options.senderId ?? env('AFRICASTALKING_SENDER_ID', env('SMS_FROM', 'Arkstack'))\n this.driver = (africastalking as (config: { username: string; apiKey: string }) => {\n SMS: AfricasTalkingSmsDriver['driver']\n })({ username, apiKey }).SMS\n }\n\n async send (message: string, recipient: NotificationRecipient, data: NotificationData = {}) {\n const recipients = Array.isArray(recipient) ? recipient : [recipient]\n const resolvedMessage = interpolate(message, data)\n\n if (recipients.length > 1) {\n return await this.driver.sendBulk({\n to: recipients,\n from: this.senderId,\n message: resolvedMessage,\n })\n }\n\n return await this.driver.send({\n to: recipients[0],\n from: this.senderId,\n message: resolvedMessage,\n })\n }\n}\n","import type { NotificationData, NotificationRecipient, SmsDriverOptions } from '../../types'\n\nimport { env } from '@arkstack/common'\nimport { interpolate } from '../../utils/template'\nimport twilio from 'twilio'\n\nexport class TwilioSmsDriver {\n private client: ReturnType<typeof twilio>\n private fromNumber: string\n\n constructor(options: SmsDriverOptions['twilio'] = {}) {\n const accountSid = options.accountSid ?? env('TWILIO_ACCOUNT_SID', '')\n const authToken = options.authToken ?? env('TWILIO_AUTH_TOKEN', '')\n\n this.fromNumber = options.from ?? env('TWILIO_FROM', env('SMS_FROM', ''))\n this.client = twilio(accountSid, authToken)\n }\n\n async send (message: string, recipient: NotificationRecipient, data: NotificationData = {}) {\n const recipients = Array.isArray(recipient) ? recipient : [recipient]\n const resolvedMessage = interpolate(message, data)\n\n return await Promise.all(recipients.map(async to => await this.client.messages.create({\n body: resolvedMessage,\n from: this.fromNumber,\n to,\n })))\n }\n}\n","import type { NotificationData, NotificationRecipient, SmsDriverOptions } from '../types'\n\nimport { AfricasTalkingSmsDriver } from './sms/AfricasTalkingSmsDriver'\nimport { NotificationContract } from '../Contracts/NotificationContract'\nimport { TwilioSmsDriver } from './sms/TwilioSmsDriver'\nimport { env } from '@arkstack/common'\nimport { notificationConfig } from '../config'\n\ntype SmsProvider = AfricasTalkingSmsDriver | TwilioSmsDriver\n\nexport class SmsNotification extends NotificationContract {\n driver: SmsProvider\n private recipients?: NotificationRecipient\n private fromValue?: string\n\n constructor(options: SmsDriverOptions = {}) {\n super()\n\n const driverConfig = notificationConfig<SmsDriverOptions>('drivers.sms', {})\n const transport = options.transport ?? driverConfig.transport ?? 'twilio'\n const transportConfig = notificationConfig<Record<string, any>>(`transports.${transport}`, {})\n const legacySmsConfig = notificationConfig<SmsDriverOptions>('sms', {})\n const from = options.from ?? driverConfig.from ?? legacySmsConfig.from\n\n this.fromValue = from\n this.driver = transport === 'twilio'\n ? new TwilioSmsDriver({\n ...legacySmsConfig.twilio,\n ...transportConfig,\n ...options.twilio,\n from: options.twilio?.from ?? transportConfig.from ?? legacySmsConfig.twilio?.from ?? from,\n })\n : new AfricasTalkingSmsDriver({\n ...legacySmsConfig.africastalking,\n ...transportConfig,\n ...options.africastalking,\n senderId: options.africastalking?.senderId ?? transportConfig.senderId ?? legacySmsConfig.africastalking?.senderId ?? from,\n })\n }\n\n from (from: string): this {\n this.fromValue = from\n\n return this\n }\n\n subject (_subject: string): this {\n return this\n }\n\n recipient (recipient: NotificationRecipient): this {\n this.recipients = recipient\n\n return this\n }\n\n async send (\n message: string,\n _subject?: string,\n recipient?: NotificationRecipient,\n data?: NotificationData\n ) {\n const resolvedRecipient = recipient ?? this.recipients\n\n if (!resolvedRecipient) {\n throw new Error('No recipient provided for SMS notification')\n }\n\n return await this.driver.send(message, resolvedRecipient, {\n app_name: env('APP_NAME', 'Arkstack'),\n from: this.fromValue,\n ...this.mergeData(data),\n })\n }\n}\n","import type { MailDriverOptions, MailRecipient, NotificationChannel, NotificationData, NotificationRecipient, NotificationUser, SmsDriverOptions } from './types'\n\nimport { DbNotification } from './drivers/DbNotification'\nimport { DriverMap } from './Contracts/Maps'\nimport { MailNotification } from './drivers/MailNotification'\nimport { SmsNotification } from './drivers/SmsNotification'\nimport { notificationConfig } from './config'\n\nexport class Notification<D extends keyof DriverMap = keyof DriverMap> {\n private driver: DriverMap[D]\n\n constructor(driver: D, options: MailDriverOptions | SmsDriverOptions = {}) {\n this.driver = Notification.createDriver(driver, options) as DriverMap[D]\n }\n\n static mail (options?: MailDriverOptions) {\n return new MailNotification(options)\n }\n\n static email (options?: MailDriverOptions) {\n return this.mail(options)\n }\n\n static sms (options?: SmsDriverOptions) {\n return new SmsNotification(options)\n }\n\n static db () {\n return new DbNotification()\n }\n\n static channel (\n channel?: NotificationChannel | 'email',\n options?: MailDriverOptions | SmsDriverOptions\n ) {\n return Notification.createDriver(channel ?? notificationConfig<NotificationChannel>('default_driver', 'mail'), options)\n }\n\n prepare (\n recipient?: null | MailRecipient | NotificationRecipient | NotificationUser,\n data: NotificationData = {}\n ) {\n this.driver.data(data)\n\n if (recipient && typeof recipient === 'object' && !Array.isArray(recipient) && 'id' in recipient) {\n if (this.driver instanceof MailNotification) {\n if (recipient.email) {\n this.driver.recipient(recipient.email)\n }\n } else if (this.driver instanceof SmsNotification) {\n if (recipient.phone) {\n this.driver.recipient(recipient.phone)\n }\n } else {\n this.driver.recipient(recipient as never)\n }\n\n return this.driver\n }\n\n if (recipient) {\n this.driver.recipient(recipient as NotificationRecipient)\n }\n\n return this.driver\n }\n\n private static createDriver (\n driver: NotificationChannel | 'email',\n options: MailDriverOptions | SmsDriverOptions = {}\n ) {\n switch (driver) {\n case 'mail':\n case 'email':\n return new MailNotification(options as MailDriverOptions)\n case 'sms':\n return new SmsNotification(options as SmsDriverOptions)\n case 'db':\n return new DbNotification()\n default:\n throw new Error(`Unsupported notification driver: ${driver}`)\n }\n }\n}\n"],"mappings":";;;;;;AAEA,IAAsB,uBAAtB,MAAmE;CAC/D,cAA0C,EAAE;CAa5C,KAAM,MAA8B;EAChC,KAAK,cAAc;EAEnB,OAAO;;CAGX,UAAqB,MAAyB;EAC1C,OAAO;GACH,GAAG,KAAK;GACR,GAAG;GACH,uBAAM,IAAI,MAAM,EAAC,aAAa;GACjC;;;;;ACvBT,IAAsB,mBAAtB,cAA+C,MAAM;CAajD,OAAiB,QAA6B;CAE9C,QAAkB,EACd,MAAM,QACT;;;;AChBL,IAAa,yBAAb,MAAoC;CAChC,aAAqB,WAAY;EAC7B,OAAO,MAAM,SAAkC,mBAAmB;;CAGtE,aAAa,OAAQ,MAAwB,SAAgC;EAGzE,OAAO,OAAM,MAFO,KAAK,UAAU,EAEhB,OAAO,CAAC,OAAO;GAC9B,QAAQ,KAAK;GACb,MAAM,QAAQ,QAAQ;GACtB,OAAO,QAAQ;GACf,aAAa,QAAQ;GACrB,YAAY,QAAQ,cAAc;GAClC,YAAY,QAAQ,cAAc;GAClC,MAAM,QAAQ,QAAQ;GACzB,CAAC;;CAGN,aAAa,QAAS,MAAwB;EAG1C,OAAO,OAAM,MAFO,KAAK,UAAU,EAEhB,OAAO,CAAC,MAAM,EAAE,QAAQ,KAAK,IAAI,CAAC,CAAC,KAAK;;CAG/D,aAAa,cAAe,MAAwB;EAGhD,OAAO,OAAM,MAFO,KAAK,UAAU,EAEhB,OAAO,CAAC,MAAM;GAAE,QAAQ,KAAK;GAAI,QAAQ;GAAM,CAAC,CAAC,KAAK;;CAG7E,aAAa,SAAU,cAAyD;EAC5E,MAAM,QAAQ,MAAM,KAAK,UAAU;EACnC,MAAM,KAAK,wBAAwB,mBAAmB,aAAa,KAAK;EACxE,MAAM,yBAAS,IAAI,MAAM;EAEzB,MAAM,MAAM,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC;EAEpD,IAAI,wBAAwB,kBACxB,aAAa,SAAS;;CAI9B,aAAa,YAAa,MAAwB;EAG9C,OAAM,MAFc,KAAK,UAAU,EAEvB,OAAO,CAAC,MAAM;GAAE,QAAQ,KAAK;GAAI,QAAQ;GAAM,CAAC,CAAC,OAAO,EAAE,wBAAQ,IAAI,MAAM,EAAE,CAAC;;CAG/F,aAAa,OAAQ,cAAyD;EAC1E,MAAM,QAAQ,MAAM,KAAK,UAAU;EACnC,MAAM,KAAK,wBAAwB,mBAAmB,aAAa,KAAK;EAExE,MAAM,MAAM,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,QAAQ;;;;;ACxDlD,MAAa,eAAe,OAAe,OAAyB,EAAE,KAAK;CACvE,OAAO,MAAM,QAAQ,kBAAkB,OAAO,QAAQ;EAClD,MAAM,cAAc,KAAK,IAAI,MAAM;EAEnC,OAAO,gBAAgB,KAAA,KAAa,gBAAgB,OAAO,QAAQ,OAAO,YAAY;GACxF;;;;ACCN,IAAa,iBAAb,cAAoC,qBAAuC;CACvE;CACA,UAAkD,EAAE;CAEpD,KAAM,OAAqB;EACvB,OAAO;;CAGX,QAAS,SAAuB;EAC5B,KAAK,QAAQ,QAAQ;EAErB,OAAO;;CAGX,UAAW,WAA2D;EAClE,IAAI,OAAO,cAAc,YAAY,CAAC,MAAM,QAAQ,UAAU,IAAI,QAAQ,WAAW;GACjF,KAAK,OAAO;GAEZ,OAAO;;EAGX,MAAM,IAAI,MAAM,kDAAkD;;CAGtE,KAAM,MAA2C;EAC7C,KAAK,QAAQ,OAAO;EAEpB,OAAO;;CAGX,OAAQ,MAAsB,MAA4B;EACtD,KAAK,QAAQ,aAAa;EAC1B,KAAK,QAAQ,aAAa;EAE1B,OAAO;;CAGX,KAAM,MAAsC;EACxC,KAAK,QAAQ,OAAO;EAEpB,OAAO;;CAGX,MAAM,OAAQ,MAAwB,SAAgC;EAClE,MAAM,SAAkC,mBAAmB;EAE3D,OAAO,MAAM,uBAAuB,OAAO,MAAM,QAAQ;;CAG7D,MAAM,KACF,SACA,SACA,YACA,MACF;EACE,IAAI,CAAC,KAAK,MACN,MAAM,IAAI,MAAM,uDAAuD;EAG3E,MAAM,aAAa,KAAK,UAAU,KAAK;EAEvC,OAAO,MAAM,KAAK,OAAO,KAAK,MAAM;GAChC,MAAM,KAAK,QAAQ,QAAQ;GAC3B,OAAO,YAAY,WAAW,KAAK,QAAQ,SAAS,IAAI,WAAW;GACnE,aAAa,YAAY,SAAS,WAAW;GAC7C,YAAY,KAAK,QAAQ,cAAc;GACvC,YAAY,KAAK,QAAQ,cAAc;GACvC,MAAM,KAAK,QAAQ,QAAQ;GAC9B,CAAC;;;;;AC1EV,MAAa,sBAAoC,KAAa,iBAAuB;CACjF,IAAI;EACA,OAAO,OAAO,iBAAiB,OAAO,aAAa;SAC/C;EACJ,OAAO;;;;;ACEf,IAAa,mBAAb,cAAsC,qBAAqB;CACvD;CACA;CACA;CACA;CACA,OAAO,sBAAsB;EACzB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACH,CAAC,KAAK,GAAG;CAEV,YAAY,UAA6B,EAAE,EAAE;EACzC,OAAO;EAEP,MAAM,eAAe,mBAAwC,gBAAgB,EAAE,CAAC;EAEhF,MAAM,kBAAkB,mBAAwC,cAD9C,QAAQ,aAAa,aAAa,aAAa,UAC0B,EAAE,CAAC;EAC9F,MAAM,mBAAmB,mBAAwC,QAAQ,EAAE,CAAC;EAE5E,MAAM,aAAa;GACf,GAFqB,mBAAwC,QAAQ,EAAE,CAEpD;GACnB,GAAI,iBAAiB,QAAQ,EAAE;GAC/B,GAAG;GACN;EACD,MAAM,OAAO,QAAQ,QAAQ,WAAW,QAAQ,IAAI,aAAa,YAAY;EAC7E,MAAM,OAAO,QAAQ,QAAQ,WAAW,QAAQ,IAAI,aAAa,KAAK;EACtE,MAAM,SAAS,QAAQ,UAAU,WAAW,UAAU,IAAI,eAAe,MAAM;EAC/E,MAAM,OAAO,QAAQ,QAAQ,WAAW,MAAM,QAAQ,WAAW,QAAQ,IAAI,iBAAiB,GAAG;EACjG,MAAM,OAAO,QAAQ,QAAQ,WAAW,MAAM,QAAQ,WAAW,QAAQ,IAAI,iBAAiB,GAAG;EAEjG,KAAK,cAAc,QAAQ,QAAQ,aAAa,QAAQ,iBAAiB,QAAQ,WAAW,QAAQ,IAAI,qBAAqB,uBAAuB;EACpJ,KAAK,SAAS,WAAW,gBAAgB;GACrC;GACA,MAAM,OAAO,KAAK;GAClB,QAAQ,QAAQ,OAAO;GACvB,MAAM,QAAQ,OAAO;IAAE;IAAM;IAAM,GAAG,KAAA;GACzC,CAAC;;CAGN,KAAM,MAAoB;EACtB,KAAK,cAAc;EAEnB,OAAO;;CAGX,QAAS,SAAuB;EAC5B,KAAK,cAAc;EAEnB,OAAO;;CAGX,UAAW,WAAgC;EACvC,KAAK,aAAa;EAElB,OAAO;;CAGX,MAAM,KACF,SACA,SACA,WACA,MACF;EACE,MAAM,aAAa;GACf,UAAU,IAAI,YAAY,WAAW;GACrC,GAAG,KAAK,UAAU,KAAK;GAC1B;EACD,MAAM,kBAAkB,YAAY,WAAW,KAAK,eAAe,IAAI,WAAW;EAClF,MAAM,kBAAkB,YAAY,SAAS,WAAW;EACxD,MAAM,KAAK,KAAK,kBAAkB,UAAU;EAE5C,IAAI,GAAG,SAAS,GACZ,MAAM,IAAI,MAAM,8CAA8C;EAGlE,OAAO,MAAM,KAAK,OAAO,SAAS;GAC1B;GACJ,SAAS;GACT,MAAM,KAAK;GACX,MAAM,gBAAgB,QAAQ,mBAAmB,GAAG;GACpD,MAAM,YAAY,MAAM,WAAW,KAAK,gCAAgC;IACpE,GAAG;IACH,SAAS;IACT,SAAS;IACZ,CAAC,CAAC;GACN,CAAC;;CAGN,kBAA2B,WAA2B;EAClD,MAAM,aAAa,aAAa,KAAK;EACrC,MAAM,YAAY,MAAM,QAAQ,WAAW,GACrC,CAAC,GAAG,WAAW,GACf,aACI,CAAC,WAAW,GACZ,EAAE,EACV,SAAQ,cAAa,KAAK,mBAAmB,UAAU,CAAY;EAErE,MAAM,eAAe,mBAAwC,gBAAgB,EAAE,CAAC;EAEhF,MAAM,kBAAkB,mBAAwC,cAD9C,aAAa,aAAa,UAC+C,EAAE,CAAC;EAC9F,MAAM,cAAc,aAAa,eAC1B,aAAa,gBACb,gBAAgB,eAChB,gBAAgB,gBAChB,IAAwB,oBAAoB;EAEnD,IAAI,IAAI,WAAW,KAAK,gBAAgB,aACpC,SAAS,KAAK,YAAY;EAG9B,OAAO;;CAGX,mBAA4B,WAA0C;EAClE,IAAI,OAAO,cAAc,UACrB,OAAO,CAAC,UAAU;EAGtB,OAAO,OAAO,QAAQ,UAAU,CAAC,KAAK,CAAC,SAAS,WAAW;GAAE;GAAS;GAAM,EAAE;;;;;AC7HtF,IAAa,0BAAb,MAAqC;CACjC;CAIA;CAEA,YAAY,UAA8C,EAAE,EAAE;EAC1D,MAAM,WAAW,QAAQ,YAAY,IAAI,2BAA2B,UAAU;EAC9E,MAAM,SAAS,QAAQ,UAAU,IAAI,0BAA0B,UAAU;EAEzE,KAAK,WAAW,QAAQ,YAAY,IAAI,4BAA4B,IAAI,YAAY,WAAW,CAAC;EAChG,KAAK,SAAU,eAEZ;GAAE;GAAU;GAAQ,CAAC,CAAC;;CAG7B,MAAM,KAAM,SAAiB,WAAkC,OAAyB,EAAE,EAAE;EACxF,MAAM,aAAa,MAAM,QAAQ,UAAU,GAAG,YAAY,CAAC,UAAU;EACrE,MAAM,kBAAkB,YAAY,SAAS,KAAK;EAElD,IAAI,WAAW,SAAS,GACpB,OAAO,MAAM,KAAK,OAAO,SAAS;GAC9B,IAAI;GACJ,MAAM,KAAK;GACX,SAAS;GACZ,CAAC;EAGN,OAAO,MAAM,KAAK,OAAO,KAAK;GAC1B,IAAI,WAAW;GACf,MAAM,KAAK;GACX,SAAS;GACZ,CAAC;;;;;ACjCV,IAAa,kBAAb,MAA6B;CACzB;CACA;CAEA,YAAY,UAAsC,EAAE,EAAE;EAClD,MAAM,aAAa,QAAQ,cAAc,IAAI,sBAAsB,GAAG;EACtE,MAAM,YAAY,QAAQ,aAAa,IAAI,qBAAqB,GAAG;EAEnE,KAAK,aAAa,QAAQ,QAAQ,IAAI,eAAe,IAAI,YAAY,GAAG,CAAC;EACzE,KAAK,SAAS,OAAO,YAAY,UAAU;;CAG/C,MAAM,KAAM,SAAiB,WAAkC,OAAyB,EAAE,EAAE;EACxF,MAAM,aAAa,MAAM,QAAQ,UAAU,GAAG,YAAY,CAAC,UAAU;EACrE,MAAM,kBAAkB,YAAY,SAAS,KAAK;EAElD,OAAO,MAAM,QAAQ,IAAI,WAAW,IAAI,OAAM,OAAM,MAAM,KAAK,OAAO,SAAS,OAAO;GAClF,MAAM;GACN,MAAM,KAAK;GACX;GACH,CAAC,CAAC,CAAC;;;;;AChBZ,IAAa,kBAAb,cAAqC,qBAAqB;CACtD;CACA;CACA;CAEA,YAAY,UAA4B,EAAE,EAAE;EACxC,OAAO;EAEP,MAAM,eAAe,mBAAqC,eAAe,EAAE,CAAC;EAC5E,MAAM,YAAY,QAAQ,aAAa,aAAa,aAAa;EACjE,MAAM,kBAAkB,mBAAwC,cAAc,aAAa,EAAE,CAAC;EAC9F,MAAM,kBAAkB,mBAAqC,OAAO,EAAE,CAAC;EACvE,MAAM,OAAO,QAAQ,QAAQ,aAAa,QAAQ,gBAAgB;EAElE,KAAK,YAAY;EACjB,KAAK,SAAS,cAAc,WACtB,IAAI,gBAAgB;GAClB,GAAG,gBAAgB;GACnB,GAAG;GACH,GAAG,QAAQ;GACX,MAAM,QAAQ,QAAQ,QAAQ,gBAAgB,QAAQ,gBAAgB,QAAQ,QAAQ;GACzF,CAAC,GACA,IAAI,wBAAwB;GAC1B,GAAG,gBAAgB;GACnB,GAAG;GACH,GAAG,QAAQ;GACX,UAAU,QAAQ,gBAAgB,YAAY,gBAAgB,YAAY,gBAAgB,gBAAgB,YAAY;GACzH,CAAC;;CAGV,KAAM,MAAoB;EACtB,KAAK,YAAY;EAEjB,OAAO;;CAGX,QAAS,UAAwB;EAC7B,OAAO;;CAGX,UAAW,WAAwC;EAC/C,KAAK,aAAa;EAElB,OAAO;;CAGX,MAAM,KACF,SACA,UACA,WACA,MACF;EACE,MAAM,oBAAoB,aAAa,KAAK;EAE5C,IAAI,CAAC,mBACD,MAAM,IAAI,MAAM,6CAA6C;EAGjE,OAAO,MAAM,KAAK,OAAO,KAAK,SAAS,mBAAmB;GACtD,UAAU,IAAI,YAAY,WAAW;GACrC,MAAM,KAAK;GACX,GAAG,KAAK,UAAU,KAAK;GAC1B,CAAC;;;;;AChEV,IAAa,eAAb,MAAa,aAA0D;CACnE;CAEA,YAAY,QAAW,UAAgD,EAAE,EAAE;EACvE,KAAK,SAAS,aAAa,aAAa,QAAQ,QAAQ;;CAG5D,OAAO,KAAM,SAA6B;EACtC,OAAO,IAAI,iBAAiB,QAAQ;;CAGxC,OAAO,MAAO,SAA6B;EACvC,OAAO,KAAK,KAAK,QAAQ;;CAG7B,OAAO,IAAK,SAA4B;EACpC,OAAO,IAAI,gBAAgB,QAAQ;;CAGvC,OAAO,KAAM;EACT,OAAO,IAAI,gBAAgB;;CAG/B,OAAO,QACH,SACA,SACF;EACE,OAAO,aAAa,aAAa,WAAW,mBAAwC,kBAAkB,OAAO,EAAE,QAAQ;;CAG3H,QACI,WACA,OAAyB,EAAE,EAC7B;EACE,KAAK,OAAO,KAAK,KAAK;EAEtB,IAAI,aAAa,OAAO,cAAc,YAAY,CAAC,MAAM,QAAQ,UAAU,IAAI,QAAQ,WAAW;GAC9F,IAAI,KAAK,kBAAkB;QACnB,UAAU,OACV,KAAK,OAAO,UAAU,UAAU,MAAM;UAEvC,IAAI,KAAK,kBAAkB;QAC1B,UAAU,OACV,KAAK,OAAO,UAAU,UAAU,MAAM;UAG1C,KAAK,OAAO,UAAU,UAAmB;GAG7C,OAAO,KAAK;;EAGhB,IAAI,WACA,KAAK,OAAO,UAAU,UAAmC;EAG7D,OAAO,KAAK;;CAGhB,OAAe,aACX,QACA,UAAgD,EAAE,EACpD;EACE,QAAQ,QAAR;GACI,KAAK;GACL,KAAK,SACD,OAAO,IAAI,iBAAiB,QAA6B;GAC7D,KAAK,OACD,OAAO,IAAI,gBAAgB,QAA4B;GAC3D,KAAK,MACD,OAAO,IAAI,gBAAgB;GAC/B,SACI,MAAM,IAAI,MAAM,oCAAoC,SAAS"}
|