rokot-notification
v3.0.2
Published
Rokot - [Rocketmakers](http://www.rocketmakers.com/) TypeScript NodeJs Platform
Downloads
10
Readme
rokot-notification
Rokot - Rocketmakers TypeScript NodeJs Platform
Introduction
The Rokot Notification library provides a framework to create (JSON) Notification Messages and send them to users via a notification channel (email
, apns
and gcm
'out-the-box')
These notification messages are generally transcoded into some form of textual content (HTML/text), but could also directly contain the content to be sent
Core Components
INotification
The library is based around the core concept of a notification message (INotification
)
This should represent the real life data behind the user notification
Each notification should have:
- a unique
type
(this is the key to indicate which handler will process the notification) - a
recipient
to indicate the audience of the notification - which can be string values (for use in a single transport scenario), or transport keys{email:"[email protected]", apns:["ABC", "XYYZ"], gcm:"xds")
to support multiple transports and multiple tokens
import {INotification} from "rokot-notification";
export interface ISampleTemplateNotification extends INotification {
fail?: boolean;
}
const notification: ISampleTemplateNotification = {
type: "sample-underscore-template-message",
recipient: {
email:"[email protected]"
},
fail: false
}
INotificationHandler
Each notification type
requires a notification handler
The framework provides this handler with decorators to add functions to support:
- validating notifications before the transport method is called
- creating template content (html/text content via underscore templates)
- to pre cache the templates at startup (loading template content from disk/db early)
- to validate the template execution at startup with test case notifications you provide
A simple notification handler that just utilise the transport
import {notifications, INotification} from "rokot-notification";
import {INodemailerNotificationHandler, INodemailerNotificationTransport} from "rokot-notification/lib/nodemailer";
/** Define the shape of the Notification */
export interface ISimpleNotification extends INotification {
html: string;
text: string;
}
/**
Register this handler for the notification type via @notification.handler("simple")
NOTE: You dont need to export the notification handler
*/
@notifications.handler("simple")
class SimpleHandler implements INodemailerNotificationHandler<ISimpleNotification>{
/**
register the nodemailer transport function via @notifications.transport()
*/
@notifications.transport()
async nodemailer(notification: ISimpleNotification, transport: INodemailerNotificationTransport) {
return await transport.send(notification.recipient, m => {
m.from = transport.getFromAddress(notification)
m.subject = `Simple Email`
m.text = notification.text
m.html = notification.html
})
}
}
Or a complete example showing usage of all the functions
import {notifications, UnderscoreFileSystemTemplateProcessorFactory, INotification} from "rokot-notification";
import {INodemailerNotificationHandler, INodemailerNotificationTransport} from "rokot-notification/lib/nodemailer";
import {ISampleTemplateNotification} from "./sampleTemplateNotification";
import {emailTo} from "../../settings";
/** The example templates processor factory */
const exampleTemplatesFactory = new UnderscoreFileSystemTemplateProcessorFactory("./source/test/examples/templates")
export const notificationType = "sample-underscore-template-message"
/** You dont need to export the notification handler*/
@notifications.handler(notificationType)
class TemplateHandler implements INodemailerNotificationHandler<ISampleTemplateNotification>{
/** Validate the notification before its passed to the transport method */
@notifications.validator()
validate(notification: ISampleTemplateNotification){
return Promise.resolve(notification);
}
/** Provides a sample notification that will be validated against any @notification.template() functions */
@notifications.testCase()
testMessage() : ISampleTemplateNotification{
return {type: notificationType, recipient: {nodemailer: emailTo}, fail: true}
}
/** You can provide as many test cases as you like (to exercise the template generation) */
@notifications.testCase()
testMessage1() : ISampleTemplateNotification{
return {type: notificationType, recipient: {nodemailer: emailTo}, fail: false}
}
/** You can also inspect which @notification.template() function is requesting the data */
@notifications.testCase()
testMessage2(template: string) : ISampleTemplateNotification{
if (template === "text") {
// dont use this for the 'text' template
return
}
return {type: notificationType, recipient: {nodemailer: emailTo}}
}
/**
Using Underscore templates loaded from a root folder
These template providing function are pre-cached at startup to reduce runtime IO
*/
@notifications.template()
html(){
return exampleTemplatesFactory.create<ISampleTemplateNotification>(`${notificationType}.html`)
}
/** Using Underscore templates loaded from a root folder */
@notifications.template()
text() {
return exampleTemplatesFactory.create<ISampleTemplateNotification>(`${notificationType}.txt`)
}
/** the nodemailer transport function */
@notifications.transport()
async nodemailer(notification: ISampleTemplateNotification, transport: INodemailerNotificationTransport) {
return await transport.send(notification.recipient, m => {
m.from = transport.getFromAddress(notification)
m.subject = `Template Email`
// using templates.transform provides access to the pre-cached @notification.template() decorated function results
m.text = notifications.transformTemplate(notification, this.text)
m.html = notifications.transformTemplate(notification, this.html)
})
}
}
Or a notification handler using multiple transports
import {notifications, INotification} from "rokot-notification";
import {INodemailerNotificationHandler, INodemailerNotificationTransport} from "rokot-notification/lib/nodemailer";
import {IApnsNotificationHandler, IApnsNotificationTransport} from "rokot-notification/lib/apns";
export interface IMultipleNotification extends INotification {
type: "sample-multi-channel-message"
count: number;
}
@notifications.handler("sample-multi-channel-message")
class MultipleHandler implements IApnsNotificationHandler<IMultipleNotification>, INodemailerNotificationHandler<IMultipleNotification>{
/** the apns transport function */
@notifications.transport()
async apns(notification: IMultipleNotification, transport: IApnsNotificationTransport) : Promise<any>{
return await transport.send(notification.recipient, n => {
n.body = `Count of ${notification.count}`
n.topic = "<app package id>"
})
}
/** the nodemailer transport function */
@notifications.transport()
async nodemailer(notification: IMultipleNotification, transport: INodemailerNotificationTransport) {
return await transport.send(notification.recipient, m => {
m.from = transport.getFromAddress(notification)
m.subject = `Test Email`
m.text = `Count of ${notification.count}`
m.html = `Test HTML email`
})
}
}
NOTE: There are 3 core notification handlers avaiable 'out-the-box' IApnsNotificationHandler<TNotification>
, IGcmNotificationHandler<TNotification>
and INodemailerNotificationHandler<TNotification>
NotificationDispatcher
The framework provides a NotificationDispatcher
to route notifications to their dispatch handler
You need to create your Application NotificationDispatcher
and configuring which transports are used
import {NotificationDispatcherFactory} from "rokot-notification";
import {apnsInitializer, IApnsProviderOptions} from "rokot-notification/lib/apns";
import {sendgridInitializer,INodemailerSendgridOptions} from "rokot-notification/lib/nodemailer";
import {gcmInitializer,IGcmProviderOptions} from "rokot-notification/lib/gcm";
import {ConsoleLogger, Logger} from "rokot-log";
async function createDispatcher(nodemailerOptions: INodemailerSendgridOptions, apnsOptions: IApnsProviderOptions, gcmOptions: IGcmProviderOptions) {
const logger = ConsoleLogger.create("test-multiple-message-dispatcher")
const dispatcherFactory = new NotificationDispatcherFactory(logger)
return await dispatcherFactory.createDispatcher(
sendgridInitializer(logger, nodemailerOptions),
gcmInitializer(logger, gcmOptions),
apnsInitializer(logger, apnsOptions));
}
// createDispatcher({username:"sendgrid username", password:"send grid password"}, {token:{key:"/path/to.p8",keyId:"KEY_ID",teamId:"TEAM_ID"},production:false}, {apiKey:"<gcm api key>"})
NOTE: You can create your own MessageHandler for any kind of notification channel you like, or change the Nodemailer transport (from the 'out-the-box' sendgrid)
Notification Client Generation
You can create a typescript file in the root of your source and include the source below (modifying the paths to match your handler locations)
This code will inspect the source code and generate a Notifications client - exposing methods for each of the notification types
import {ConsoleLogger} from "rokot-log";
import {generateClient, getInterfaceFunctionName, getFolderFiles} from "rokot-notification/lib/client/generator";
const logger = ConsoleLogger.create("create notification client",{level:"info"})
/** Get all notification handler source files (all in a single folder) */
const files = getFolderFiles("./source/test/examples/handlers");
/** Generate a notification client */
generateClient(logger, files, "./source/test/examples/notifications.ts", {
/** override the method naming function */
functionName: getInterfaceFunctionName
})
Templates
HTML Template
<div>
Hello There <%= model.recipient.nodemailer || model.recipient.email || model.recipient %> (<%= model.type %>)
Process <%= model.fail ? "Failed" : "Ok" %>
</div>
Getting Started
Installation
Install via yarn
yarn add rokot-notification
Further Examples
Check out the examples in /package/source/test/examples
to see various dispatcher configs and message handlers
Consumed Libraries
node-gcm
Android Push Notifications
apn
Apple Push Notifications
nodemailer
Email Notifications
nodemailer-sendgrid-transport
Email via sendgrid transport
rokot-test
The testing framework used within the Rokot Platform!