UNPKG

rokot-notification

Version:

Rokot - [Rocketmakers](http://www.rocketmakers.com/) TypeScript NodeJs Platform

285 lines (219 loc) 11 kB
# rokot-notification Rokot - [Rocketmakers](http://www.rocketmakers.com/) 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: 1. a unique `type` (this is the key to indicate which handler will process the notification) 1. 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:"developer@code.com", apns:["ABC", "XYYZ"], gcm:"xds")` to support multiple transports and multiple tokens ```typescript import {INotification} from "rokot-notification"; export interface ISampleTemplateNotification extends INotification { fail?: boolean; } ``` ```typescript const notification: ISampleTemplateNotification = { type: "sample-underscore-template-message", recipient: { email:"developers@rocketmakers.com" }, fail: false } ``` #### INotificationHandler Each notification `type` requires a notification handler The framework provides this handler with decorators to add functions to support: 1. validating notifications before the transport method is called 1. creating template content (html/text content via underscore templates) 1. to pre cache the templates at startup (loading template content from disk/db early) 1. to validate the template execution at startup with test case notifications you provide A simple notification handler that just utilise the transport ```typescript 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 ```typescript 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 ```typescript 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 ```typescript 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 ```typescript 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 ```html <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](https://github.com/ToothlessGear/node-gcm) Android Push Notifications ### [apn](https://github.com/node-apn/node-apn/) Apple Push Notifications ### [nodemailer](https://github.com/nodemailer/nodemailer) Email Notifications ### [nodemailer-sendgrid-transport](https://github.com/sendgrid/nodemailer-sendgrid-transport) Email via sendgrid transport ### [rokot-test](https://github.com/Rocketmakers/rokot-test) The testing framework used within the Rokot Platform!