@arkstack/notifications 0.3.17

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Toneflix Technologies Limited
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # @arkstack/notifications
2
+
3
+ Framework-neutral notifications for Arkstack applications.
4
+
5
+ ```ts
6
+ import { Notification } from '@arkstack/notifications';
7
+
8
+ await Notification.mail()
9
+ .recipient({ 'ada@example.com': 'Ada Lovelace' })
10
+ .subject('Welcome, {name}')
11
+ .data({ name: 'Ada' })
12
+ .send('Hello {name}, thanks for joining.');
13
+
14
+ await Notification.sms()
15
+ .recipient('+2348012345678')
16
+ .send('Your code is {code}', undefined, undefined, { code: '123456' });
17
+
18
+ await Notification.db()
19
+ .recipient(user)
20
+ .send('Your payout has settled', 'Payout settled');
21
+ ```
22
+
23
+ Apps using database notifications should provide a `UserNotification` model backed by a `user_notifications` table. The starter templates include this model and migration.
24
+
25
+ ## Config
26
+
27
+ ```ts
28
+ export default () => ({
29
+ default_driver: 'mail',
30
+ drivers: {
31
+ mail: {
32
+ transport: 'smtp',
33
+ from: env('SMTP_FROM_ADDRESS', 'no-reply@example.com'),
34
+ },
35
+ sms: {
36
+ transport: 'africastalking',
37
+ from: env('SMS_FROM'),
38
+ },
39
+ db: {
40
+ table: 'user_notifications',
41
+ },
42
+ },
43
+ transports: {
44
+ smtp: {
45
+ host: env('SMTP_HOST', 'localhost'),
46
+ port: env('SMTP_PORT', 1025),
47
+ },
48
+ africastalking: {
49
+ username: env('AFRICASTALKING_USERNAME', 'sandbox'),
50
+ apiKey: env('AFRICASTALKING_API_KEY', 'sandbox'),
51
+ },
52
+ twilio: {
53
+ accountSid: env('TWILIO_ACCOUNT_SID'),
54
+ authToken: env('TWILIO_AUTH_TOKEN'),
55
+ from: env('TWILIO_FROM'),
56
+ },
57
+ },
58
+ });
59
+ ```
60
+
61
+ `default_driver` selects the notification channel used by `Notification.channel()`. `drivers.sms.transport` selects the SMS provider transport, either `africastalking` or `twilio`.
@@ -0,0 +1,188 @@
1
+ import * as arkormx from "arkormx";
2
+ import { Model } from "arkormx";
3
+ import { Transporter } from "nodemailer";
4
+ import * as twilio_lib_rest_api_v2010_account_message0 from "twilio/lib/rest/api/v2010/account/message";
5
+
6
+ //#region src/Contracts/UserNotification.d.ts
7
+ declare abstract class UserNotification extends Model {
8
+ id: number | string;
9
+ userId: number | string;
10
+ type: DbNotificationType | null;
11
+ title: string;
12
+ description: string;
13
+ actionText: string | null;
14
+ actionLink: string | null;
15
+ meta: NotificationData | null;
16
+ readAt: Date | null;
17
+ createdAt: Date;
18
+ updatedAt: Date;
19
+ protected static table?: string | undefined;
20
+ protected casts: {
21
+ readonly meta: "json";
22
+ };
23
+ }
24
+ //#endregion
25
+ //#region src/types.d.ts
26
+ type NotificationRecipient = string | string[];
27
+ type MailRecipientAddress = Record<string, string>;
28
+ type MailRecipient = string | MailRecipientAddress | Array<string | MailRecipientAddress>;
29
+ type NotificationData = Record<string, unknown>;
30
+ type SmsDriverName = 'africastalking' | 'twilio';
31
+ type NotificationChannel = 'mail' | 'sms' | 'db';
32
+ type NotificationUser = {
33
+ id: string | number;
34
+ email?: string | null;
35
+ phone?: string | null;
36
+ };
37
+ type MailDriverOptions = {
38
+ transport?: string;
39
+ host?: string;
40
+ port?: number;
41
+ secure?: boolean;
42
+ user?: string;
43
+ pass?: string;
44
+ from?: string;
45
+ testAddress?: string;
46
+ };
47
+ type SmsDriverOptions = {
48
+ transport?: SmsDriverName;
49
+ from?: string;
50
+ africastalking?: {
51
+ username?: string;
52
+ apiKey?: string;
53
+ senderId?: string;
54
+ };
55
+ twilio?: {
56
+ accountSid?: string;
57
+ authToken?: string;
58
+ from?: string;
59
+ };
60
+ };
61
+ type DbNotificationType = 'transaction' | 'pocket' | 'family' | 'security' | 'promo' | 'bill' | 'goal' | string;
62
+ type DbNotificationPayload = {
63
+ type?: DbNotificationType | null;
64
+ title: string;
65
+ description: string;
66
+ actionText?: string | null;
67
+ actionLink?: string | null;
68
+ meta?: NotificationData | null;
69
+ };
70
+ type DriverResult = unknown;
71
+ type NotificationDriverMap = {
72
+ mail: DriverResult;
73
+ sms: DriverResult;
74
+ db: UserNotification;
75
+ };
76
+ //#endregion
77
+ //#region src/Contracts/NotificationContract.d.ts
78
+ declare abstract class NotificationContract<TResult = DriverResult> {
79
+ protected contextData: NotificationData;
80
+ abstract send(message: string, subject?: string, recipient?: NotificationRecipient, data?: NotificationData): Promise<TResult>;
81
+ abstract from(from: string): this;
82
+ abstract subject(subject: string): this;
83
+ abstract recipient(recipient: NotificationRecipient): this;
84
+ data(data: NotificationData): this;
85
+ protected mergeData(data?: NotificationData): {
86
+ year: number;
87
+ };
88
+ }
89
+ //#endregion
90
+ //#region src/drivers/DbNotification.d.ts
91
+ declare class DbNotification extends NotificationContract<UserNotification> {
92
+ private user?;
93
+ private payload;
94
+ from(_from: string): this;
95
+ subject(subject: string): this;
96
+ recipient(recipient: NotificationRecipient | NotificationUser): this;
97
+ type(type: DbNotificationPayload['type']): this;
98
+ action(text?: string | null, link?: string | null): this;
99
+ meta(meta?: NotificationData | null): this;
100
+ create(user: NotificationUser, payload: DbNotificationPayload): Promise<UserNotification & arkormx.Model<any, any>>;
101
+ send(message: string, subject?: string, _recipient?: NotificationRecipient, data?: NotificationData): Promise<UserNotification & arkormx.Model<any, any>>;
102
+ }
103
+ //#endregion
104
+ //#region src/drivers/MailNotification.d.ts
105
+ declare class MailNotification extends NotificationContract {
106
+ driver: Transporter;
107
+ private fromAddress?;
108
+ private subjectLine?;
109
+ private recipients?;
110
+ static defaultHtmlTemplate: string;
111
+ constructor(options?: MailDriverOptions);
112
+ from(from: string): this;
113
+ subject(subject: string): this;
114
+ recipient(recipient: MailRecipient): this;
115
+ send(message: string, subject?: string, recipient?: MailRecipient, data?: NotificationData): Promise<any>;
116
+ private resolveRecipients;
117
+ private normalizeRecipient;
118
+ }
119
+ //#endregion
120
+ //#region src/drivers/sms/AfricasTalkingSmsDriver.d.ts
121
+ declare class AfricasTalkingSmsDriver {
122
+ private driver;
123
+ private senderId?;
124
+ constructor(options?: SmsDriverOptions['africastalking']);
125
+ send(message: string, recipient: NotificationRecipient, data?: NotificationData): Promise<unknown>;
126
+ }
127
+ //#endregion
128
+ //#region src/drivers/sms/TwilioSmsDriver.d.ts
129
+ declare class TwilioSmsDriver {
130
+ private client;
131
+ private fromNumber;
132
+ constructor(options?: SmsDriverOptions['twilio']);
133
+ send(message: string, recipient: NotificationRecipient, data?: NotificationData): Promise<twilio_lib_rest_api_v2010_account_message0.MessageInstance[]>;
134
+ }
135
+ //#endregion
136
+ //#region src/drivers/SmsNotification.d.ts
137
+ type SmsProvider = AfricasTalkingSmsDriver | TwilioSmsDriver;
138
+ declare class SmsNotification extends NotificationContract {
139
+ driver: SmsProvider;
140
+ private recipients?;
141
+ private fromValue?;
142
+ constructor(options?: SmsDriverOptions);
143
+ from(from: string): this;
144
+ subject(_subject: string): this;
145
+ recipient(recipient: NotificationRecipient): this;
146
+ send(message: string, _subject?: string, recipient?: NotificationRecipient, data?: NotificationData): Promise<unknown>;
147
+ }
148
+ //#endregion
149
+ //#region src/Contracts/Maps.d.ts
150
+ type DriverMap = {
151
+ mail: MailNotification;
152
+ email: MailNotification;
153
+ sms: SmsNotification;
154
+ db: DbNotification;
155
+ };
156
+ //#endregion
157
+ //#region src/Notification.d.ts
158
+ declare class Notification<D extends keyof DriverMap = keyof DriverMap> {
159
+ private driver;
160
+ constructor(driver: D, options?: MailDriverOptions | SmsDriverOptions);
161
+ static mail(options?: MailDriverOptions): MailNotification;
162
+ static email(options?: MailDriverOptions): MailNotification;
163
+ static sms(options?: SmsDriverOptions): SmsNotification;
164
+ static db(): DbNotification;
165
+ static channel(channel?: NotificationChannel | 'email', options?: MailDriverOptions | SmsDriverOptions): MailNotification | SmsNotification | DbNotification;
166
+ prepare(recipient?: null | MailRecipient | NotificationRecipient | NotificationUser, data?: NotificationData): DriverMap[D];
167
+ private static createDriver;
168
+ }
169
+ //#endregion
170
+ //#region src/UserNotificationCenter.d.ts
171
+ declare class UserNotificationCenter {
172
+ private static getModel;
173
+ static create(user: NotificationUser, payload: DbNotificationPayload): Promise<UserNotification & arkormx.Model<any, any>>;
174
+ static forUser(user: NotificationUser): Promise<arkormx.ArkormCollection<UserNotification & arkormx.Model<any, any>, (UserNotification & arkormx.Model<any, any>)[]>>;
175
+ static unreadForUser(user: NotificationUser): Promise<arkormx.ArkormCollection<UserNotification & arkormx.Model<any, any>, (UserNotification & arkormx.Model<any, any>)[]>>;
176
+ static markRead(notification: UserNotification | UserNotification['id']): Promise<void>;
177
+ static markAllRead(user: NotificationUser): Promise<void>;
178
+ static delete(notification: UserNotification | UserNotification['id']): Promise<void>;
179
+ }
180
+ //#endregion
181
+ //#region src/config.d.ts
182
+ declare const notificationConfig: <T = unknown>(key: string, defaultValue: T) => T;
183
+ //#endregion
184
+ //#region src/utils/template.d.ts
185
+ declare const interpolate: (value: string, data?: NotificationData) => string;
186
+ //#endregion
187
+ export { AfricasTalkingSmsDriver, DbNotification, DbNotificationPayload, DbNotificationType, DriverResult, MailDriverOptions, MailNotification, MailRecipient, MailRecipientAddress, Notification, NotificationChannel, NotificationContract, NotificationData, NotificationDriverMap, NotificationRecipient, NotificationUser, SmsDriverName, SmsDriverOptions, SmsNotification, TwilioSmsDriver, UserNotification, UserNotificationCenter, interpolate, notificationConfig };
188
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/Contracts/UserNotification.ts","../src/types.ts","../src/Contracts/NotificationContract.ts","../src/drivers/DbNotification.ts","../src/drivers/MailNotification.ts","../src/drivers/sms/AfricasTalkingSmsDriver.ts","../src/drivers/sms/TwilioSmsDriver.ts","../src/drivers/SmsNotification.ts","../src/Contracts/Maps.ts","../src/Notification.ts","../src/UserNotificationCenter.ts","../src/config.ts","../src/utils/template.ts"],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,387 @@
1
+ import { config, env, getModel } from "@arkstack/common";
2
+ import { Model } from "arkormx";
3
+ import nodemailer from "nodemailer";
4
+ import africastalking from "africastalking";
5
+ import twilio from "twilio";
6
+
7
+ //#region src/Contracts/NotificationContract.ts
8
+ var NotificationContract = class {
9
+ contextData = {};
10
+ data(data) {
11
+ this.contextData = data;
12
+ return this;
13
+ }
14
+ mergeData(data) {
15
+ return {
16
+ ...this.contextData,
17
+ ...data,
18
+ year: (/* @__PURE__ */ new Date()).getFullYear()
19
+ };
20
+ }
21
+ };
22
+
23
+ //#endregion
24
+ //#region src/Contracts/UserNotification.ts
25
+ var UserNotification = class extends Model {
26
+ static table = "user_notifications";
27
+ casts = { meta: "json" };
28
+ };
29
+
30
+ //#endregion
31
+ //#region src/UserNotificationCenter.ts
32
+ var UserNotificationCenter = class {
33
+ static async getModel() {
34
+ return await getModel("UserNotification");
35
+ }
36
+ static async create(user, payload) {
37
+ return await (await this.getModel()).query().create({
38
+ userId: user.id,
39
+ type: payload.type ?? null,
40
+ title: payload.title,
41
+ description: payload.description,
42
+ actionText: payload.actionText ?? null,
43
+ actionLink: payload.actionLink ?? null,
44
+ meta: payload.meta ?? null
45
+ });
46
+ }
47
+ static async forUser(user) {
48
+ return await (await this.getModel()).query().where({ userId: user.id }).get();
49
+ }
50
+ static async unreadForUser(user) {
51
+ return await (await this.getModel()).query().where({
52
+ userId: user.id,
53
+ readAt: null
54
+ }).get();
55
+ }
56
+ static async markRead(notification) {
57
+ const Model = await this.getModel();
58
+ const id = notification instanceof UserNotification ? notification.id : notification;
59
+ const readAt = /* @__PURE__ */ new Date();
60
+ await Model.query().where({ id }).update({ readAt });
61
+ if (notification instanceof UserNotification) notification.readAt = readAt;
62
+ }
63
+ static async markAllRead(user) {
64
+ await (await this.getModel()).query().where({
65
+ userId: user.id,
66
+ readAt: null
67
+ }).update({ readAt: /* @__PURE__ */ new Date() });
68
+ }
69
+ static async delete(notification) {
70
+ const Model = await this.getModel();
71
+ const id = notification instanceof UserNotification ? notification.id : notification;
72
+ await Model.query().where({ id }).delete();
73
+ }
74
+ };
75
+
76
+ //#endregion
77
+ //#region src/utils/template.ts
78
+ const interpolate = (value, data = {}) => {
79
+ return value.replace(/\{([^{}]+)\}/g, (match, key) => {
80
+ const replacement = data[key.trim()];
81
+ return replacement === void 0 || replacement === null ? match : String(replacement);
82
+ });
83
+ };
84
+
85
+ //#endregion
86
+ //#region src/drivers/DbNotification.ts
87
+ var DbNotification = class extends NotificationContract {
88
+ user;
89
+ payload = {};
90
+ from(_from) {
91
+ return this;
92
+ }
93
+ subject(subject) {
94
+ this.payload.title = subject;
95
+ return this;
96
+ }
97
+ recipient(recipient) {
98
+ if (typeof recipient === "object" && !Array.isArray(recipient) && "id" in recipient) {
99
+ this.user = recipient;
100
+ return this;
101
+ }
102
+ throw new Error("Database notifications require a user recipient");
103
+ }
104
+ type(type) {
105
+ this.payload.type = type;
106
+ return this;
107
+ }
108
+ action(text, link) {
109
+ this.payload.actionText = text;
110
+ this.payload.actionLink = link;
111
+ return this;
112
+ }
113
+ meta(meta) {
114
+ this.payload.meta = meta;
115
+ return this;
116
+ }
117
+ async create(user, payload) {
118
+ await getModel("UserNotification");
119
+ return await UserNotificationCenter.create(user, payload);
120
+ }
121
+ async send(message, subject, _recipient, data) {
122
+ if (!this.user) throw new Error("No user recipient provided for database notification");
123
+ const mergedData = this.mergeData(data);
124
+ return await this.create(this.user, {
125
+ type: this.payload.type ?? null,
126
+ title: interpolate(subject ?? this.payload.title ?? "", mergedData),
127
+ description: interpolate(message, mergedData),
128
+ actionText: this.payload.actionText ?? null,
129
+ actionLink: this.payload.actionLink ?? null,
130
+ meta: this.payload.meta ?? null
131
+ });
132
+ }
133
+ };
134
+
135
+ //#endregion
136
+ //#region src/config.ts
137
+ const notificationConfig = (key, defaultValue) => {
138
+ try {
139
+ return config(`notifications.${key}`, defaultValue);
140
+ } catch {
141
+ return defaultValue;
142
+ }
143
+ };
144
+
145
+ //#endregion
146
+ //#region src/drivers/MailNotification.ts
147
+ var MailNotification = class MailNotification extends NotificationContract {
148
+ driver;
149
+ fromAddress;
150
+ subjectLine;
151
+ recipients;
152
+ static defaultHtmlTemplate = [
153
+ "<!doctype html>",
154
+ "<html>",
155
+ "<body style=\"font-family:Arial,sans-serif;line-height:1.5;color:#111827\">",
156
+ "<h2>{subject}</h2>",
157
+ "<div>{message}</div>",
158
+ "<p style=\"color:#6b7280;font-size:12px\">&copy; {year} {app_name}</p>",
159
+ "</body>",
160
+ "</html>"
161
+ ].join("");
162
+ constructor(options = {}) {
163
+ super();
164
+ const driverConfig = notificationConfig("drivers.mail", {});
165
+ const transportConfig = notificationConfig(`transports.${options.transport ?? driverConfig.transport ?? "smtp"}`, {});
166
+ const legacyMailConfig = notificationConfig("mail", {});
167
+ const smtpConfig = {
168
+ ...notificationConfig("smtp", {}),
169
+ ...legacyMailConfig.smtp ?? {},
170
+ ...transportConfig
171
+ };
172
+ const host = options.host ?? smtpConfig.host ?? env("SMTP_HOST", "localhost");
173
+ const port = options.port ?? smtpConfig.port ?? env("SMTP_PORT", 1025);
174
+ const secure = options.secure ?? smtpConfig.secure ?? env("SMTP_SECURE", false);
175
+ const user = options.user ?? smtpConfig.auth?.user ?? smtpConfig.user ?? env("SMTP_USERNAME", "");
176
+ const pass = options.pass ?? smtpConfig.auth?.pass ?? smtpConfig.pass ?? env("SMTP_PASSWORD", "");
177
+ this.fromAddress = options.from ?? driverConfig.from ?? legacyMailConfig.from ?? smtpConfig.from ?? env("SMTP_FROM_ADDRESS", "no-reply@example.com");
178
+ this.driver = nodemailer.createTransport({
179
+ host,
180
+ port: Number(port),
181
+ secure: Boolean(secure),
182
+ auth: user || pass ? {
183
+ user,
184
+ pass
185
+ } : void 0
186
+ });
187
+ }
188
+ from(from) {
189
+ this.fromAddress = from;
190
+ return this;
191
+ }
192
+ subject(subject) {
193
+ this.subjectLine = subject;
194
+ return this;
195
+ }
196
+ recipient(recipient) {
197
+ this.recipients = recipient;
198
+ return this;
199
+ }
200
+ async send(message, subject, recipient, data) {
201
+ const mergedData = {
202
+ app_name: env("APP_NAME", "Arkstack"),
203
+ ...this.mergeData(data)
204
+ };
205
+ const resolvedSubject = interpolate(subject ?? this.subjectLine ?? "", mergedData);
206
+ const resolvedMessage = interpolate(message, mergedData);
207
+ const to = this.resolveRecipients(recipient);
208
+ if (to.length < 1) throw new Error("No recipient provided for mail notification");
209
+ return await this.driver.sendMail({
210
+ to,
211
+ subject: resolvedSubject,
212
+ from: this.fromAddress,
213
+ text: resolvedMessage.replace(/<\/?[^>]+(>|$)/g, ""),
214
+ html: interpolate(MailNotification.defaultHtmlTemplate, {
215
+ ...mergedData,
216
+ message: resolvedMessage,
217
+ subject: resolvedSubject
218
+ })
219
+ });
220
+ }
221
+ resolveRecipients(recipient) {
222
+ const recipients = recipient ?? this.recipients;
223
+ const resolved = (Array.isArray(recipients) ? [...recipients] : recipients ? [recipients] : []).flatMap((recipient) => this.normalizeRecipient(recipient));
224
+ const driverConfig = notificationConfig("drivers.mail", {});
225
+ const transportConfig = notificationConfig(`transports.${driverConfig.transport ?? "smtp"}`, {});
226
+ const testAddress = driverConfig.testAddress ?? driverConfig.test_address ?? transportConfig.testAddress ?? transportConfig.test_address ?? env("SMTP_TEST_ADDRESS");
227
+ if (env("NODE_ENV") !== "production" && testAddress) resolved.push(testAddress);
228
+ return resolved;
229
+ }
230
+ normalizeRecipient(recipient) {
231
+ if (typeof recipient === "string") return [recipient];
232
+ return Object.entries(recipient).map(([address, name]) => ({
233
+ address,
234
+ name
235
+ }));
236
+ }
237
+ };
238
+
239
+ //#endregion
240
+ //#region src/drivers/sms/AfricasTalkingSmsDriver.ts
241
+ var AfricasTalkingSmsDriver = class {
242
+ driver;
243
+ senderId;
244
+ constructor(options = {}) {
245
+ const username = options.username ?? env("AFRICASTALKING_USERNAME", "sandbox");
246
+ const apiKey = options.apiKey ?? env("AFRICASTALKING_API_KEY", "sandbox");
247
+ this.senderId = options.senderId ?? env("AFRICASTALKING_SENDER_ID", env("SMS_FROM", "Arkstack"));
248
+ this.driver = africastalking({
249
+ username,
250
+ apiKey
251
+ }).SMS;
252
+ }
253
+ async send(message, recipient, data = {}) {
254
+ const recipients = Array.isArray(recipient) ? recipient : [recipient];
255
+ const resolvedMessage = interpolate(message, data);
256
+ if (recipients.length > 1) return await this.driver.sendBulk({
257
+ to: recipients,
258
+ from: this.senderId,
259
+ message: resolvedMessage
260
+ });
261
+ return await this.driver.send({
262
+ to: recipients[0],
263
+ from: this.senderId,
264
+ message: resolvedMessage
265
+ });
266
+ }
267
+ };
268
+
269
+ //#endregion
270
+ //#region src/drivers/sms/TwilioSmsDriver.ts
271
+ var TwilioSmsDriver = class {
272
+ client;
273
+ fromNumber;
274
+ constructor(options = {}) {
275
+ const accountSid = options.accountSid ?? env("TWILIO_ACCOUNT_SID", "");
276
+ const authToken = options.authToken ?? env("TWILIO_AUTH_TOKEN", "");
277
+ this.fromNumber = options.from ?? env("TWILIO_FROM", env("SMS_FROM", ""));
278
+ this.client = twilio(accountSid, authToken);
279
+ }
280
+ async send(message, recipient, data = {}) {
281
+ const recipients = Array.isArray(recipient) ? recipient : [recipient];
282
+ const resolvedMessage = interpolate(message, data);
283
+ return await Promise.all(recipients.map(async (to) => await this.client.messages.create({
284
+ body: resolvedMessage,
285
+ from: this.fromNumber,
286
+ to
287
+ })));
288
+ }
289
+ };
290
+
291
+ //#endregion
292
+ //#region src/drivers/SmsNotification.ts
293
+ var SmsNotification = class extends NotificationContract {
294
+ driver;
295
+ recipients;
296
+ fromValue;
297
+ constructor(options = {}) {
298
+ super();
299
+ const driverConfig = notificationConfig("drivers.sms", {});
300
+ const transport = options.transport ?? driverConfig.transport ?? "twilio";
301
+ const transportConfig = notificationConfig(`transports.${transport}`, {});
302
+ const legacySmsConfig = notificationConfig("sms", {});
303
+ const from = options.from ?? driverConfig.from ?? legacySmsConfig.from;
304
+ this.fromValue = from;
305
+ this.driver = transport === "twilio" ? new TwilioSmsDriver({
306
+ ...legacySmsConfig.twilio,
307
+ ...transportConfig,
308
+ ...options.twilio,
309
+ from: options.twilio?.from ?? transportConfig.from ?? legacySmsConfig.twilio?.from ?? from
310
+ }) : new AfricasTalkingSmsDriver({
311
+ ...legacySmsConfig.africastalking,
312
+ ...transportConfig,
313
+ ...options.africastalking,
314
+ senderId: options.africastalking?.senderId ?? transportConfig.senderId ?? legacySmsConfig.africastalking?.senderId ?? from
315
+ });
316
+ }
317
+ from(from) {
318
+ this.fromValue = from;
319
+ return this;
320
+ }
321
+ subject(_subject) {
322
+ return this;
323
+ }
324
+ recipient(recipient) {
325
+ this.recipients = recipient;
326
+ return this;
327
+ }
328
+ async send(message, _subject, recipient, data) {
329
+ const resolvedRecipient = recipient ?? this.recipients;
330
+ if (!resolvedRecipient) throw new Error("No recipient provided for SMS notification");
331
+ return await this.driver.send(message, resolvedRecipient, {
332
+ app_name: env("APP_NAME", "Arkstack"),
333
+ from: this.fromValue,
334
+ ...this.mergeData(data)
335
+ });
336
+ }
337
+ };
338
+
339
+ //#endregion
340
+ //#region src/Notification.ts
341
+ var Notification = class Notification {
342
+ driver;
343
+ constructor(driver, options = {}) {
344
+ this.driver = Notification.createDriver(driver, options);
345
+ }
346
+ static mail(options) {
347
+ return new MailNotification(options);
348
+ }
349
+ static email(options) {
350
+ return this.mail(options);
351
+ }
352
+ static sms(options) {
353
+ return new SmsNotification(options);
354
+ }
355
+ static db() {
356
+ return new DbNotification();
357
+ }
358
+ static channel(channel, options) {
359
+ return Notification.createDriver(channel ?? notificationConfig("default_driver", "mail"), options);
360
+ }
361
+ prepare(recipient, data = {}) {
362
+ this.driver.data(data);
363
+ if (recipient && typeof recipient === "object" && !Array.isArray(recipient) && "id" in recipient) {
364
+ if (this.driver instanceof MailNotification) {
365
+ if (recipient.email) this.driver.recipient(recipient.email);
366
+ } else if (this.driver instanceof SmsNotification) {
367
+ if (recipient.phone) this.driver.recipient(recipient.phone);
368
+ } else this.driver.recipient(recipient);
369
+ return this.driver;
370
+ }
371
+ if (recipient) this.driver.recipient(recipient);
372
+ return this.driver;
373
+ }
374
+ static createDriver(driver, options = {}) {
375
+ switch (driver) {
376
+ case "mail":
377
+ case "email": return new MailNotification(options);
378
+ case "sms": return new SmsNotification(options);
379
+ case "db": return new DbNotification();
380
+ default: throw new Error(`Unsupported notification driver: ${driver}`);
381
+ }
382
+ }
383
+ };
384
+
385
+ //#endregion
386
+ export { AfricasTalkingSmsDriver, DbNotification, MailNotification, Notification, NotificationContract, SmsNotification, TwilioSmsDriver, UserNotification, UserNotificationCenter, interpolate, notificationConfig };
387
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
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\">&copy; {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(MailNotification.defaultHtmlTemplate, {\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":"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"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@arkstack/notifications",
3
+ "version": "0.3.17",
4
+ "type": "module",
5
+ "description": "Notification package for Arkstack applications, providing mail, SMS, and database notification drivers.",
6
+ "homepage": "https://arkstack.toneflix.net",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/arkstack-hq/arkstack.git",
10
+ "directory": "packages/notifications"
11
+ },
12
+ "keywords": [
13
+ "notifications",
14
+ "mail",
15
+ "email",
16
+ "sms",
17
+ "twilio",
18
+ "africastalking",
19
+ "database",
20
+ "arkstack"
21
+ ],
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "exports": {
29
+ ".": "./dist/index.js",
30
+ "./package.json": "./package.json"
31
+ },
32
+ "dependencies": {
33
+ "africastalking": "^0.8.0",
34
+ "nodemailer": "^8.0.7",
35
+ "twilio": "^6.0.0",
36
+ "@arkstack/common": "^0.3.17"
37
+ },
38
+ "peerDependencies": {
39
+ "arkormx": "^2.0.7"
40
+ },
41
+ "devDependencies": {
42
+ "@types/nodemailer": "^7.0.11"
43
+ },
44
+ "scripts": {
45
+ "build": "tsdown --config-loader unconfig",
46
+ "test": "vitest",
47
+ "version:patch": "pnpm version patch"
48
+ }
49
+ }