@arkstack/notifications 0.17.3 → 0.17.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { DotPath, DotPathValue, MergedConfig } from "@arkstack/common";
2
2
  import { Transporter } from "nodemailer";
3
3
  import { Model } from "@arkstack/database";
4
+ import { Logger } from "nodemailer/lib/shared/index.js";
4
5
  import { User } from "@app/models/User";
5
6
  import { User as User$1 } from "@arkstack/auth";
6
7
  import { PhoneNumber } from "@kanun-hq/plugin-phone";
@@ -33,15 +34,26 @@ type SmsDriverName = 'africastalking' | 'twilio';
33
34
  type RealtimeDriverName = 'pusher' | 'firebase';
34
35
  type NotificationChannel = 'mail' | 'sms' | 'db' | 'realtime';
35
36
  type MailDriverOptions = {
36
- transport?: 'africastalking' | 'twilio' | 'file' | 'smtp';
37
+ transport?: 'file' | 'smtp' | 'sendmail' | 'ses';
38
+ url?: string;
37
39
  host?: string;
38
40
  port?: number;
39
- secure?: boolean;
40
41
  user?: string;
41
42
  pass?: string;
42
43
  from?: string;
43
- testAddress?: string;
44
+ debug?: boolean;
45
+ logger?: boolean | Logger;
46
+ secure?: boolean;
47
+ service?: string;
48
+ sesRegion?: string;
44
49
  directory?: string;
50
+ ignoreTLS?: boolean;
51
+ requireTLS?: boolean;
52
+ authMethod?: 'PLAIN' | 'LOGIN' | 'CRAM-MD5';
53
+ testAddress?: string;
54
+ sendmailArgs?: string[];
55
+ sendmailPath?: string;
56
+ transactionLog?: boolean;
45
57
  };
46
58
  type SmsDriverOptions = {
47
59
  transport?: SmsDriverName;
@@ -118,7 +130,7 @@ interface NotificationConfig {
118
130
  default_driver: 'mail' | 'sms' | 'db';
119
131
  drivers: {
120
132
  mail: {
121
- transport: 'smtp' | 'file';
133
+ transport: 'smtp' | 'file' | 'sendmail' | 'ses';
122
134
  from: string | {
123
135
  name: string;
124
136
  address: string;
@@ -140,28 +152,42 @@ interface NotificationConfig {
140
152
  };
141
153
  };
142
154
  transports: {
143
- smtp: {
155
+ smtp: ({
144
156
  host: string;
145
157
  port: number;
146
158
  secure: boolean;
159
+ debug?: boolean;
160
+ logger?: boolean | Logger;
161
+ service?: string;
162
+ ignore_tls?: boolean;
163
+ require_tls?: boolean;
164
+ auth_method?: 'PLAIN' | 'LOGIN' | 'CRAM-MD5';
165
+ test_address?: string;
166
+ transaction_log?: boolean;
167
+ } & ({
147
168
  auth: {
148
169
  user: string;
149
170
  pass: string;
150
171
  };
151
172
  user?: string;
152
173
  pass?: string;
153
- test_address?: string;
154
174
  } | {
155
- host: string;
156
- port: number;
157
- secure: boolean;
158
175
  auth?: {
159
176
  user: string;
160
177
  pass: string;
161
178
  };
162
179
  user: string;
163
180
  pass: string;
164
- test_address?: string;
181
+ })) | {
182
+ url: string;
183
+ };
184
+ ses?: {
185
+ region: string;
186
+ [key: string]: any;
187
+ };
188
+ sendmail?: {
189
+ path?: string;
190
+ args?: string[];
165
191
  };
166
192
  file: {
167
193
  directory: string;
@@ -196,7 +222,7 @@ interface NotificationConfig {
196
222
  };
197
223
  };
198
224
  }
199
- type MergedTransportConfig = MergedConfig<NotificationConfig['transports'][NonNullable<MailDriverOptions['transport']>]>;
225
+ type MergedTransportConfig = MergedConfig<Required<NotificationConfig['transports']>[NonNullable<MailDriverOptions['transport']>]>;
200
226
  //#endregion
201
227
  //#region src/Contracts/NotificationContract.d.ts
202
228
  declare abstract class NotificationContract<TResult = DriverResult> {
@@ -244,14 +270,22 @@ declare class DbNotification extends NotificationContract<UserNotification> {
244
270
  //#region src/drivers/MailNotification.d.ts
245
271
  declare class MailNotification extends NotificationContract {
246
272
  driver: Transporter;
273
+ private options;
274
+ private ViewName;
275
+ private transport;
276
+ private sesOptions?;
277
+ private recipients?;
247
278
  private fromAddress?;
248
279
  private subjectLine?;
249
- private recipients?;
250
- private ViewName;
280
+ private driverConfig;
251
281
  private htmlTemplate?;
252
282
  private textTemplate?;
253
283
  private fileDirectory?;
254
284
  constructor(options?: MailDriverOptions);
285
+ /**
286
+ * Prepare the mail driver so we can use it to relay the message
287
+ */
288
+ private prepareDriver;
255
289
  from(from: string): this;
256
290
  /**
257
291
  * The email subject
@@ -439,7 +473,7 @@ declare class Notification<D extends keyof DriverMap = keyof DriverMap> {
439
473
  static sms(options?: SmsDriverOptions): SmsNotification;
440
474
  static db(): DbNotification;
441
475
  static realtime(options?: RealtimeDriverOptions): RealtimeNotification;
442
- static channel(channel?: NotificationChannel | 'email', options?: DriverOptions): RealtimeNotification | SmsNotification | MailNotification | DbNotification;
476
+ static channel(channel?: NotificationChannel | 'email', options?: DriverOptions): MailNotification | SmsNotification | DbNotification | RealtimeNotification;
443
477
  prepare(recipient?: null | MailRecipient | NotificationRecipient | User, data?: NotificationData): DriverMap[D];
444
478
  private static createDriver;
445
479
  }
package/dist/index.js CHANGED
@@ -201,41 +201,89 @@ const configure = (key, defaultValue) => {
201
201
  //#region src/drivers/MailNotification.ts
202
202
  var MailNotification = class extends NotificationContract {
203
203
  driver;
204
+ options = {};
205
+ ViewName = "~arkstack/notifications.mail";
206
+ transport = "smtp";
207
+ sesOptions;
208
+ recipients;
204
209
  fromAddress;
205
210
  subjectLine;
206
- recipients;
207
- ViewName = "~arkstack/notifications.mail";
211
+ driverConfig;
208
212
  htmlTemplate;
209
213
  textTemplate;
210
214
  fileDirectory;
211
215
  constructor(options = {}) {
212
216
  super();
213
- const driver = configure("drivers.mail", {});
214
- const trpt = driver.transport ?? "smtp";
215
- const transport = configure(`transports.${trpt}`, {});
216
- if (trpt === "file") {
217
+ this.driverConfig = configure("drivers.mail", {});
218
+ this.transport = this.driverConfig.transport ?? "smtp";
219
+ this.options = options;
220
+ }
221
+ /**
222
+ * Prepare the mail driver so we can use it to relay the message
223
+ */
224
+ async prepareDriver() {
225
+ const options = this.options;
226
+ const transport = configure(`transports.${this.transport}`, {});
227
+ /**
228
+ * Setup nodemailer to stream messages so we can store the mail to file
229
+ */
230
+ if (this.transport === "file") {
217
231
  this.fileDirectory = options.directory ?? transport.directory ?? env("MAIL_FILE_PATH", join(Arkstack.rootDir(), "./storage/framework/mails"));
218
- this.fromAddress = options.from ?? driver.from ?? transport.from ?? env("MAIL_FROM_ADDRESS", "no-reply@example.com");
232
+ this.fromAddress = options.from ?? this.driverConfig.from ?? transport.from ?? env("MAIL_FROM_ADDRESS", "no-reply@example.com");
219
233
  this.driver = nodemailer.createTransport({
220
234
  streamTransport: true,
221
235
  buffer: true
222
236
  });
223
237
  return;
224
238
  }
225
- const host = options.host ?? transport.host ?? env("MAIL_HOST", "localhost");
226
- const port = options.port ?? transport.port ?? env("MAIL_PORT", 1025);
227
- const secure = options.secure ?? transport.secure ?? env("MAIL_SECURE", false);
239
+ /**
240
+ * Setup nodemailer to use sendmail
241
+ */
242
+ if (this.transport === "sendmail") {
243
+ const path = transport.path ?? options.sendmailPath ?? env("MAIL_SENDMAIL_PATH", "/usr/sbin/sendmail");
244
+ this.driver = nodemailer.createTransport({
245
+ path,
246
+ sendmail: true,
247
+ args: transport.args ?? options.sendmailArgs
248
+ });
249
+ return;
250
+ }
251
+ /**
252
+ * Setup nodemailer to use Amazon SES
253
+ */
254
+ if (this.transport === "ses") {
255
+ try {
256
+ const { SESv2Client, SendEmailCommand } = await import("@aws-sdk/client-sesv2");
257
+ const { region, ...sesOptions } = transport;
258
+ const sesClient = new SESv2Client({ region: options.sesRegion ?? region ?? env("MAIL_SES_REGION") ?? env("AWS_DEFAULT_REGION") });
259
+ this.sesOptions = sesOptions;
260
+ this.driver = nodemailer.createTransport({ SES: {
261
+ sesClient,
262
+ SendEmailCommand
263
+ } });
264
+ } catch (error) {
265
+ throw new Error("Please install \"@aws-sdk/client-sesv2\" to use the ses transport", { cause: error });
266
+ }
267
+ return;
268
+ }
228
269
  const user = options.user ?? transport.auth?.user ?? transport.user ?? env("MAIL_USERNAME", "");
229
270
  const pass = options.pass ?? transport.auth?.pass ?? transport.pass ?? env("MAIL_PASSWORD", "");
230
- this.fromAddress = options.from ?? driver.from ?? transport.from ?? env("MAIL_FROM_ADDRESS", "no-reply@example.com");
271
+ this.fromAddress = options.from ?? this.driverConfig.from ?? transport.from ?? env("MAIL_FROM_ADDRESS", "no-reply@example.com");
231
272
  this.driver = nodemailer.createTransport({
232
- host,
233
- port: Number(port),
234
- secure: Boolean(secure),
273
+ url: transport.url ?? options.url ?? env("MAIL_URL"),
274
+ host: options.host ?? transport.host ?? env("MAIL_HOST", "localhost"),
275
+ port: Number(options.port ?? transport.port ?? env("MAIL_PORT", 1025)),
235
276
  auth: user || pass ? {
236
277
  user,
237
278
  pass
238
- } : void 0
279
+ } : void 0,
280
+ debug: transport.debug ?? options.debug ?? env("MAIL_DEBUG", false),
281
+ secure: Boolean(options.secure ?? transport.secure ?? env("MAIL_SECURE", false)),
282
+ logger: transport.logger ?? options.logger ?? env("MAIL_LOGGER", false),
283
+ service: transport.service ?? options.service ?? env("MAIL_SERVICE"),
284
+ ignoreTLS: transport.ignore_tls ?? options.ignoreTLS ?? env("MAIL_IGNORE_TLS"),
285
+ requireTLS: transport.require_tls ?? options.requireTLS ?? env("MAIL_REQUIRE_TLS"),
286
+ authMethod: transport.auth_method ?? options.authMethod ?? env("MAIL_AUTH_METHOD")
239
287
  });
240
288
  }
241
289
  from(from) {
@@ -321,6 +369,7 @@ var MailNotification = class extends NotificationContract {
321
369
  const resolvedMessage = interpolate(message, mergedData);
322
370
  const to = this.resolveRecipients(recipient);
323
371
  if (to.length < 1) throw new Error("No recipient provided for mail notification");
372
+ await this.prepareDriver();
324
373
  const templateData = {
325
374
  ...mergedData,
326
375
  message: resolvedMessage,
@@ -337,6 +386,7 @@ var MailNotification = class extends NotificationContract {
337
386
  }),
338
387
  html: this.htmlTemplate ? interpolate(this.htmlTemplate, templateData) : await globalThis.view(this.ViewName, templateData)
339
388
  };
389
+ if (this.transport === "ses") payload.ses = this.sesOptions;
340
390
  const result = await this.driver.sendMail(payload);
341
391
  if (this.fileDirectory) await this.storeFileMail(payload, result);
342
392
  return result;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkstack/notifications",
3
- "version": "0.17.3",
3
+ "version": "0.17.5",
4
4
  "type": "module",
5
5
  "description": "Framework-agnostic notification module for Arkstack and Nodejs, providing support for multi-channel notification delivery.",
6
6
  "homepage": "https://arkstack.toneflix.net/guide/notifications",
@@ -34,14 +34,14 @@
34
34
  "africastalking": "^0.8.0",
35
35
  "nodemailer": "^8.0.7",
36
36
  "twilio": "^6.0.0",
37
- "@arkstack/common": "^0.17.3"
37
+ "@arkstack/common": "^0.17.5"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "@kanun-hq/plugin-phone": "^0.1.8",
41
41
  "firebase-admin": "^13.0.0",
42
42
  "pusher": "^5.2.0",
43
- "@arkstack/contract": "^0.17.3",
44
- "@arkstack/database": "^0.17.3"
43
+ "@arkstack/contract": "^0.17.5",
44
+ "@arkstack/database": "^0.17.5"
45
45
  },
46
46
  "peerDependenciesMeta": {
47
47
  "pusher": {