@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 +21 -0
- package/README.md +61 -0
- package/dist/index.d.ts +188 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +387 -0
- package/dist/index.js.map +1 -0
- package/package.json +49 -0
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`.
|
package/dist/index.d.ts
ADDED
|
@@ -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\">© {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\">© {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
|
+
}
|