npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@osenco/adonisjs-notifications

v0.0.3

Published

The easiest way to send notifications in AdonisJS

Downloads

71

Readme

Based on the good work of verful/adonis-notifications

Pre-requisites

The @osenco/adonisjs-notifications package requires @adonisjs/core >= 6.2.0

Also, it relies on @adonisjs/lucid >= 20.5.1 for database notifications and on @adonisjs/mail >= 9.2.1 for mail notifications.

Setup

Install the package from the npm registry as follows.

npm i @osenco/adonisjs-notifications
# or
yarn add @osenco/adonisjs-notifications
# or
bun add @osenco/adonisjs-notifications

Next, configure the package by running the following ace command.

node ace configure @osenco/adonisjs-notifications

And then add the path to the tsconfig.json

{
  "extends": "@adonisjs/tsconfig/tsconfig.app.json",
  "compilerOptions": {
    //...other options,
    "paths": {
     //...other paths,
      "#notifications/*": ["./app/notifications/*.js"]
    }
  }
}

and package.json

{
  "name": "adonis-app",
  "version": "0.0.0",
  "imports": {
    //...other imports,
    "#notifications/*": "./app/notifications/*.js"
  },
  ...
}

Generating Notifications

Notifications are represented by a simple class, generally stored in the app/Notifications directory. If you dont see the directory, dont worry, it will be created when you run the make:notification ace command.

node ace make:notification TestNotification

The command will create a notification class in the app/notifications directory. Each notification class contains a via method and any number of message builder methods, like toMail or toDatabase, that convert the notification to a message made for that channel.

Sending Notifications

Notifications may be sent using the notify or the notifyLater methods of the Notifiable mixin, or using the Notification module.

Using the Notifiable Mixin

First, apply the mixin on the model you are wanting to notify.

import { BaseModel } from '@adonisjs/lucid/orm'
import { compose } from '@adonisjs/core/helpers'
import Notifiable from '@osenco/adonisjs-notifications/mixins/notifiable'

// Notifiable takes the notification table name as it's only param 
export default class User extends compose(BaseModel, Notifiable('notifications')){
}

Then use the notify or the notifyLater methods to notify the model.

import { TestNotification } from '#/notifiacations/test_notification.js'


user.notify(new TestNotification())
// Uses a in-memory queue to send the notification
user.notifyLater(new TestNotification())

Using the Notification module

You can also use the Notification module to send notifications. Sending notifications this way is useful when you need to send a notification to multiple notifiables, like a array of users.

import notification from '@osenco/adonisjs-notifications/services/main'
import { TestNotification } from '#/notifiacations/test_notification.js'


notification.send(users, new TestNotification())

You can also delay notifications using the sendLater method. This method uses a in-memory queue to send the notifications.

import notification from '@osenco/adonisjs-notifications/services/main'
import { TestNotification } from '#/notifiacations/test_notification.js'

Notification.sendLater(users, new TestNotification())

Specifying Delivery Channels

Every notification class has a via method that determines which channels will be used to deliver the notification.

If you want to use other delivery channels, you can build your own.

The via method receives a notifiable instance, that is a instance of the class which the notification is being sent. You may use the notifiable to determine which channels to sent the notification to.

class TestNotification implements NotificationContract<User> {
  public via(notifiable: User): NotificationChannelName | NotificationChannelName[] {
    return notifiable.prefersEmail ? 'mail' : 'database'
  }
}

Delaying notifications

Sending notifications can take some time, to ensure the notification doesn't block HTTP requests, you can use the notifyLater method of the Notifiable Mixin and the sendLater method of the Notification module to sms notifications to a in-memory queue, ensuring that notifications will be sent after the http request ends.

Mail Notifications

If you want to send a notification via e-mail, you should define a toMail method on the notification class. This method receives the notifiable entity and should return a BaseMailer instance

If you want to use a mail driver other than default driver to send the notification, you can define it in the mailer class

// app/mails/test_mail.ts
export default class TestMail extends BaseMail {
  from = '[email protected]'
  subject = 'Test email'

  constructor(private user: User) {
    super()
  }
  
  prepare() {
    this.message.to(this.user.email)
  }
}

// app/notifications/test_notification.ts
class TestNotification implements NotificationContract<User> {
  public toMail(notifiable: User){
    return new TestMail(notifiable)
  }
}

Mail notifications requires @adonisjs/mail >= 9.2.1

Database Notifications

The database channel stores the notification in a database table. This table contain the notification, and a JSON object that describes the notification

Database notifications requires @adonisjs/lucid >= 20.5.1

You can query the table to display the notifications in your UI. But, before you can do that, you need to create a table to store the notifications. You may use the notifications:table ace command to generate a migration with the correct table schema.

node ace notifications:table

node ace migration:run

Sending Database Notifications

If you want to store a notification in a database, you should define a toDatabase method on the notification class. This method receives the notifiable entity and should return a javascript object that can be transformed in JSON

class TestNotification implements NotificationContract<User> {
  public toDatabase(notifiable: User){
    return {
      title: `Hello, ${notifiable.email}, this is a test notification`
    }
  }
}

Typing the Database Notifications data

In the notification config file the DatabaseChannelData Interface can be defined

// config/notification.ts
declare module '@osenco/adonisjs-notifications/types' {
  interface DatabaseChannelData {
    title: string
  }
}

Accessing the notifications

After notifications are stored, you can access them from your notifiable model entities. The Notifiable mixin includes a notifications Lucid relationship that returns the notifications for that entity. You can use the notifications like any other Lucid relationship. By default, the readNotifications and unreadNotifications methods will sort the notifications using the created_at timestamp, with the most recent at the beginning.

const user = User.findOrFail(1)

for(const notification of await user.readNotifications()){
  console.log(notification.data)
}

If you want to retrieve only the unread notifications, you may use the unreadNotifications method.

const user = User.findOrFail(1)

for(const notification of await user.unreadNotifications()){
  console.log(notification.data)
}

The notifications are normal Lucid Models, you can use anything that applies to a Lucid Model on them

Marking notifications as read

Typically, you will want to mark a notification as read when a user views it. The notification model provides a markAsRead method, which updates the read_at column on the notification's database record:

const user = User.findOrFail(1)

for(const notification of await user.unreadNotifications()){
  await notification.markAsRead();
}

If you want to mark all notifications of a user as read, you can use the markNotificationsAsRead method of the Notifiable mixin

const user = User.findOrFail(1)

await user.markNotificationsAsRead()

There is also markAsRead and markNotificationsAsUnread methods to mark notifications as unread.

Custom Channels

You may want to deliver notifications using other channels, for that, you can use any class that implements the NotificationChannelContract

// channels/sms.ts
import { NotifiableModel, NotificationChannelContract } from '@osenco/adonisjs-notifications/types'

interface SmsPayload {
  text: string
}

export class SmsChannel implements NotificationChannelContract {
  async send(data: SmsPayload, to: NotifiableModel) {
    // Implement API call to send
  }
}

After the channel is created, you must register the channel in the notification config at config/notification.ts

// config/notification.ts

import { SmsChannelContract } from '../app/channels/sms.js' // or "#channels/sms"

const notificationConfig = defineConfig({
  channels: {
    ...
    sms: () => new SmsChannel(),
  },
})