NestboltNestbolt

@nestbolt/notifications

Quick Start

Get up and running with @nestbolt/notifications in three steps -- register the module, create a notification, and send it.

This guide walks through a complete working example: registering the notification module, creating a notification class, setting up a notifiable entity, and sending your first notification.

Step 1: Register the Module

Import NotificationModule in your root AppModule and call forRoot() with your desired configuration. The module is registered globally, so you only need to import it once.

import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { NotificationModule } from "@nestbolt/notifications";
import { User } from "./users/user.entity";

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: "postgres",
      host: "localhost",
      port: 5432,
      username: "postgres",
      password: "postgres",
      database: "myapp",
      entities: [User],
      synchronize: true,
    }),
    NotificationModule.forRoot({
      channels: {
        database: true,
      },
    }),
  ],
})
export class AppModule {}

This enables the database channel, which stores notifications in the notifications table. The mail channel and custom channels can be added later -- see Configuration.

Step 2: Create a Notifiable Entity

A "notifiable" is any TypeORM entity that can receive notifications. Apply the @Notifiable() decorator and extend NotifiableMixin(BaseEntity):

import { Entity, PrimaryGeneratedColumn, Column, BaseEntity } from "typeorm";
import { Notifiable, NotifiableMixin } from "@nestbolt/notifications";

@Entity("users")
@Notifiable()
export class User extends NotifiableMixin(BaseEntity) {
  @PrimaryGeneratedColumn("uuid")
  id!: string;

  @Column()
  name!: string;

  @Column()
  email!: string;

  routeNotificationFor(channel: string): string | undefined {
    if (channel === "mail") return this.email;
    return undefined;
  }
}

The mixin adds methods like notify(), getNotifications(), unreadNotifications(), and more directly to your entity. See Notifiable Entities for the full API.

Step 3: Create a Notification Class

Define a notification by extending the Notification base class. Override via() to declare delivery channels, and implement a method for each channel:

import { Notification } from "@nestbolt/notifications";

export class WelcomeNotification extends Notification {
  constructor(private user: { name: string }) {
    super();
  }

  via(): string[] {
    return ["database"];
  }

  toDatabase() {
    return {
      message: `Welcome to the platform, ${this.user.name}!`,
      type: "welcome",
    };
  }

  notificationType(): string {
    return "WelcomeNotification";
  }
}

Step 4: Send the Notification

There are two ways to send notifications.

Option A: Via NotificationService

Inject NotificationService into any service or controller:

import { Injectable } from "@nestjs/common";
import { NotificationService } from "@nestbolt/notifications";
import { WelcomeNotification } from "./notifications/welcome.notification";
import { User } from "./users/user.entity";

@Injectable()
export class UserService {
  constructor(private readonly notificationService: NotificationService) {}

  async register(name: string, email: string): Promise<User> {
    const user = new User();
    user.name = name;
    user.email = email;
    await user.save();

    await this.notificationService.send(
      user,
      new WelcomeNotification(user),
    );

    return user;
  }
}

Option B: Via the Entity Mixin

If your entity uses NotifiableMixin, you can call notify() directly on the entity instance:

await user.notify(new WelcomeNotification(user));

This is functionally identical to calling notificationService.send().

Step 5: Query Notifications

After sending, you can query the user's notifications:

// Get all notifications
const notifications = await user.getNotifications();

// Get only unread notifications
const unread = await user.unreadNotifications();

// Get the unread count
const count = await user.getUnreadNotificationCount();

// Mark a notification as read
await user.markNotificationAsRead(notifications[0].id);

// Mark all as read
await user.markAllNotificationsAsRead();

Or use NotificationService directly:

const notifications = await notificationService.getNotifications("User", user.id);
const unread = await notificationService.getUnreadNotifications("User", user.id);
const count = await notificationService.getUnreadCount("User", user.id);

Complete Example

Here is a full working example combining all the pieces:

// notifications/order-shipped.notification.ts
import { Notification, MailMessage } from "@nestbolt/notifications";

interface Order {
  id: string;
  trackingUrl: string;
  customerName: string;
}

export class OrderShippedNotification extends Notification {
  constructor(private order: Order) {
    super();
  }

  via(): string[] {
    return ["database", "mail"];
  }

  toDatabase() {
    return {
      message: `Your order #${this.order.id} has been shipped.`,
      orderId: this.order.id,
      trackingUrl: this.order.trackingUrl,
    };
  }

  toMail() {
    return new MailMessage()
      .subject("Your order has shipped!")
      .greeting(`Hello ${this.order.customerName}`)
      .line(`Great news -- your order #${this.order.id} is on its way.`)
      .line("You can track your package using the link below.")
      .action("Track Your Order", this.order.trackingUrl)
      .salutation("Thank you for shopping with us");
  }
}
// orders/order.service.ts
import { Injectable } from "@nestjs/common";
import { NotificationService } from "@nestbolt/notifications";
import { OrderShippedNotification } from "../notifications/order-shipped.notification";

@Injectable()
export class OrderService {
  constructor(private readonly notificationService: NotificationService) {}

  async shipOrder(order: Order, customer: User): Promise<void> {
    // ... shipping logic ...

    await this.notificationService.send(
      customer,
      new OrderShippedNotification(order),
    );
  }
}

Next Steps

  • Configuration -- Explore forRoot() and forRootAsync() options, including mail transport and custom channels.
  • Creating Notifications -- Learn about the full Notification base class API.
  • Mail Channel -- Deep dive into the MailMessage builder for rich emails.