Notifications System Core Package
Description
Core package for Notifications System
Install
npm i @notifications-system/core
Exports
- Services;
- Interfaces;
- Types;
- InMemory Storage;
- Console Transport;
- Helpers;
Description
The Core module provide basic notifications/queue logic and interfaces such as:
- Notification service with queue;
- Notification history;
- Configurable error processing: Default ResendErrorHandler with "Resend Strategy";
- Configurable "Leaky Bucket" provides transport limitation of send count per (time or by try);
Services
- NotificationService: Base service for sending/processing notifications;
- NotificationQueueManager: Queue processing. If it isn't used, you must to manually call
NotificationService::processQueue(transports?: ITransport | ITransport[]) periodically;
Default internal configuration of NotificationService
No Error processing, No LeakyBucket
<IConfig> {
eventEmitter: new EventEmitter(),
errorHandler: new DummyErrorHandler(),
leakyBucket: new DummyBucketService(),
processingInterval: 3,
}
Demo Sample with In-Memory storage and ConsoleTransport
ConsoleTransport - demo transport that nothing really send, but only logs all message to console
import {
ConsoleTransport,
GeometryProgressionStrategy,
IOriginalData,
IQueueProcessingEvent,
MemoryStorage,
NotificationQueueManager,
NotificationService,
QUEUE_BEFORE_PROCESSING,
ResendErrorHandler,
TRANSPORT_CONSOLE,
} from '@notifications-system/core';
let service: NotificationService;
async function main() {
service = new NotificationService(
await new MemoryStorage().initialize(),
[
new ConsoleTransport(),
],
{
errorHandler: new ResendErrorHandler(new GeometryProgressionStrategy(20, 10, 3600)),
leakyBucket: new LeakyBucketService(10),
processingInterval: 5,
},
);
service.eventEmitter.on(QUEUE_BEFORE_PROCESSING, (event: IQueueProcessingEvent) => {
console.info(`process ${event.items.length} at ${(new Date()).toLocaleTimeString()}:`);
});
const queueManager = new NotificationQueueManager(service).queueStart();
const recipient: string = 'user-01@mail.test User-01'
const data: IOriginalData = {
recipient,
payload: {
title: 'Notification',
body: 'Hello from Notification System!!',
},
};
const transport = TRANSPORT_CONSOLE;
await service.send(transport, data);
}
main();
NestJS Integration (with Mail transport and TypeORM-0.2.45 storage)
Used Packages:
Install Notification System with necessary packages
npm i typeorm@0.2.45
npm i --save-dev typeorm-extension@1.2.2
npm i @notifications-system/core
npm i @notifications-system/transport-mailer
npm i @notifications-system/storage-typeorm-0.2
Prepare
- Copy content of mailer .env.dist
to your .env and change parameters for you SMTP Service
- Copy content
of typeorm-0.2 .env.dist
to your .env and change parameters for you database connection
Migrations
Copy ormconfig
(documentation)
to project root directory:
cp ./node_modules/@notifications-system/storage-typeorm-0.2/ormconfig.js ./
Copy migrations from library to project migrations directory:
cp ./node_modules/@notifications-system/storage-typeorm-0.2/migrations/*.js ./migrations/
Run migrations:
./node_modules/.bin/typeorm migration:run
Create notification.service.ts
file in src
directory
[src/notification.service.ts]:
import { Injectable } from '@nestjs/common';
import {
INotificationEntity,
IOptions,
IQueueEntity,
ITransport,
NotificationService as BaseService,
UNREAD_STATUSES,
} from '@notifications-system/core';
import { FindWhere, TypeormStorage } from '@notifications-system/storage-typeorm-0.2';
import { In } from 'typeorm';
@Injectable()
export class NotificationService extends BaseService<TypeormStorage> {
async findByRecipient(userId: string, transports?: ITransport[], withRead = false, options?: IOptions)
: Promise<INotificationEntity<string, string>[]> {
const where: FindWhere<INotificationEntity<string, string>> = {};
if (transports && transports.length > 0) {
where.transport = In(transports);
}
if (!withRead) {
where.status = In(UNREAD_STATUSES);
}
return this.storage.notificationRepo?.findByRecipient(userId, where, options) ?? [];
}
}
Modify app.module.ts
[src/app.module.ts]:
require('dotenv').config();
import { Module } from '@nestjs/common';
import { NotificationQueueManager } from '@notifications-system/core';
import { StorageOptions, TypeormStorage } from '@notifications-system/storage-typeorm-0.2';
import { ISmtpTransportConfig, MailDataProvider, SmtpTransport } from '@notifications-system/transport-mailer';
import { configDatabase, configTransportSmtp } from './config';
import { NotificationService } from './notification.service';
@Module({
providers: [
{
provide: NotificationService,
useFactory: async () => {
return new NotificationService(
await new TypeormStorage().initialize(require('../../ormconfig.js')),
[
new SmtpTransport({
options: {
host: process.env.MAIL_HOST,
port: Number(process.env.MAIL_PORT) || undefined,
auth: {
user: process.env.MAIL_USER,
pass: process.env.MAIL_PASS,
},
},
defaults: {
from: process.env.MAIL_FROM,
},
}, new MailDataProvider()),
],
{
errorHandler: new ResendErrorHandler(new GeometryProgressionStrategy(20, 10, 3600)),
leakyBucket: new LeakyBucketService(10),
processingInterval: 5,
},
);
},
},
],
})
export class AppModule {
private notificationQueueManager: NotificationQueueManager;
constructor(service: NotificationService) {
this.notificationQueueManager = new NotificationQueueManager(service).queueStart();
}
}
Usage
import { IQueueEntity, IUserEntity } from '@notifications-system/core';
import { TRANSPORT_SMTP } from '@notifications-system/transport-mailer';
import { NotificationService } from './notification.service';
@Injectable()
export class SampleService {
constructor(
private readonly notificationService: NotificationService,
) {}
sendEmail(recipient: IUserEntity | string, body: string, title?: string): Promise<IQueueEntity[]> {
return this.notificationService.send(TRANSPORT_SMTP, { recipient, payload: title ? { title, body } : body });
}
}