FacteurJS
Facteur is a framework-agnostic notification library for Node.js. Define one notification class, format messages for each channel, and send to a recipient or a list of recipients.
Current channels include database storage (Knex/Kysely), AdonisJS Mail, Twilio SMS, AWS SNS SMS, Web Push, Firebase Cloud Messaging, Expo, Slack/Discord webhooks, Socket.IO and Transmit (SSE). WhatsApp is planned, not implemented.
In-App
Kysely
Store notifications using Kysely query builder
Knex
Store notifications using Knex.js query builder
@adonisjs/mail
Send email notifications using AdonisJS Mail system
Realtime
Socket.IO
Real-time notifications using Socket.IO
Transmit
Real-time notifications using Server-Sent Events
Chats
Slack
Send notifications to Slack channels or users
Discord
Send notifications to Discord servers and channels
SMS
Twilio
Send SMS notifications using Twilio messaging service
AWS SNS
Send SMS notifications using AWS SNS messaging service
Web Push
Expo Notifications
Push notifications for Expo and React Native apps
Web Push
Browser push notifications using VAPID protocol
Firebase Cloud Messaging
Firebase Cloud Messaging for mobile push notifications
Misc
Webhook
Send HTTP requests to custom webhook endpoints
Sending notifications
After configuring Facteur, define a notification:
import { Notification } from '@facteurjs/core/types'
import { SlackMessage } from '@facteurjs/core/channels/slack'
export default class UserRegisteredNotification extends Notification<User> {
static options = {
name: 'User Registered',
category: 'business',
deliverBy: { slack: true },
}
asSlackMessage() {
return SlackMessage.create().setText(`A new user registered: ${this.notifiable.name}`)
}
}
User is your application's recipient model. It provides notificationTargets() with a Slack webhook destination (see Slack).
await facteur.notification(UserRegisteredNotification).to(user).send()
Use the fluent builder for explicit targets, parameters, tenants, retries and bulk sending. FCM and Expo support native batches when you opt in with .useDriverBatching().
In-app notifications
Combine database storage with a realtime channel to build a notification center. Store arbitrary JSON with DatabaseMessage.create().setContent(...); send realtime data with SocketIoMessage.create().setData(...) or TransmitMessage.create().setContent(...).
Facteur provides a Server API to list notifications, mark them read/seen and manage preferences. Register it through Hono, AdonisJS, or a custom HTTP adapter. Authorization is required, and the current mark-as route additionally needs an application-level ownership check.
Follow In-App Notifications for a complete setup.
Preferences and tenants
Database-backed User Preferences expose global, per-notification and tenant-specific channel settings. Category updates apply to the currently discovered classes in that category. Critical notifications bypass preferences; explicit via() also bypasses them. See that guide for current resolution limitations.
Use .tenant(id) to attach tenant context to a send. Multi-tenancy explains storage, API filtering and tenant-access requirements.
Frontend SDK and React hooks
The framework-independent client lives in @facteurjs/client:
import { createFacteurClient } from '@facteurjs/client'
const client = createFacteurClient({
apiUrl: 'https://api.example.com',
notifiableId: '123',
credentials: 'include',
})
const notifications = await client.notifications.list({ tenantId: '456' })
await client.notifications.markAsRead({ notificationId: '789' })
await client.preferences.update({ preferences: { slack: false } })
@facteurjs/react provides TanStack Query hooks inside FacteurProvider and QueryClientProvider:
import { useNotifications, useMarkAsRead } from '@facteurjs/react'
const { data, isLoading } = useNotifications({ tenantId: '456' })
const { mutate: markAsRead } = useMarkAsRead()
See Frontend SDK and React hooks. The hooks use HTTP; realtime subscriptions remain application code.
Extending Facteur
Create custom channels and HTTP adapters for services or frameworks not built in. Database adapters currently support Knex and Kysely; Prisma is not bundled.
Queues, delayed delivery, debouncing, topics and headless UI components are not implemented in the current sending API. Native FCM/Expo batching and retries are already available.
Sponsor
If you find Facteur useful, consider sponsoring the project.