A lightweight, delivery-focused notification library for NestJS. Send notifications through multiple channels (Email, SMS, Push, WhatsApp) with pluggable providers. Your app manages content and templates, NotificationKit handles delivery.
- π― Lightweight & Focused - Does one thing well: delivers notifications. No bloat, no unnecessary dependencies.
- π Multi-Channel Support - Email, SMS, Push, and WhatsApp notifications in one unified interface
- π Pluggable Providers - Support for multiple providers (Twilio, AWS SNS, Firebase, Nodemailer, etc.)
- π± WhatsApp Support - Send WhatsApp messages with media support via Twilio API
- π― NestJS First - Built specifically for NestJS with dependency injection support
- π¦ Framework Agnostic Core - Clean architecture with framework-independent domain logic
- π Retry & Queue Management - Built-in retry logic and notification state management
- π Event System - Track notification lifecycle with event emitters
- πΎ Flexible Storage - MongoDB, PostgreSQL, or custom repository implementations
- β Fully Tested - Comprehensive test suite with 133+ tests
- π Type Safe - Written in TypeScript with full type definitions
π Design Philosophy: NotificationKit is a delivery library, not a content management system. Your application should manage templates, content, and business logic. NotificationKit focuses solely on reliable multi-channel delivery.
npm install @ciscode/notification-kitInstall peer dependencies for the providers you need:
# For NestJS
npm install @nestjs/common @nestjs/core reflect-metadata
# For email (Nodemailer)
npm install nodemailer
# For SMS (choose one)
npm install twilio # Twilio
npm install @aws-sdk/client-sns # AWS SNS
npm install @vonage/server-sdk # Vonage
# For WhatsApp
npm install twilio # Twilio WhatsApp API
# For push notifications (choose one)
npm install firebase-admin # Firebase
npm install @aws-sdk/client-sns # AWS SNS
# For database (choose one)
npm install mongoose # MongoDB
# Or use custom repositoryimport { Module } from "@nestjs/common";
import { NotificationKitModule } from "@ciscode/notification-kit";
import { NodemailerSender, MongooseNotificationRepository } from "@ciscode/notification-kit/infra";
@Module({
imports: [
NotificationKitModule.register({
senders: [
new NodemailerSender({
host: "smtp.gmail.com",
port: 587,
secure: false,
auth: {
user: process.env.EMAIL_USER,
pass: process.env.EMAIL_PASSWORD,
},
from: "noreply@example.com",
}),
],
repository: new MongooseNotificationRepository(/* mongoose connection */),
}),
],
})
export class AppModule {}import { Injectable } from "@nestjs/common";
import {
NotificationService,
NotificationChannel,
NotificationPriority,
} from "@ciscode/notification-kit";
@Injectable()
export class UserService {
constructor(private readonly notificationService: NotificationService) {}
async sendWelcomeEmail(user: User) {
const result = await this.notificationService.send({
channel: NotificationChannel.EMAIL,
priority: NotificationPriority.HIGH,
recipient: {
id: user.id,
email: user.email,
},
content: {
title: "Welcome!",
body: `Hello ${user.name}, welcome to our platform!`,
},
});
return result;
}
}Enable REST endpoints by setting enableRestApi: true:
NotificationKitModule.register({
enableRestApi: true,
// ... other options
});Then use the endpoints:
# Send notification
POST /notifications/send
{
"channel": "EMAIL",
"priority": "HIGH",
"recipient": { "id": "user-123", "email": "user@example.com" },
"content": { "title": "Hello", "body": "Welcome!" }
}
# Get notification by ID
GET /notifications/:id
# Query notifications
GET /notifications?status=SENT&limit=10
# Retry failed notification
POST /notifications/:id/retry
# Cancel notification
POST /notifications/:id/cancelNotificationKit now supports WhatsApp messaging via Twilio's WhatsApp API with full media and template support!
import { TwilioWhatsAppSender, MockWhatsAppSender } from "@ciscode/notification-kit";
// For production (real Twilio API)
NotificationKitModule.register({
senders: [
new TwilioWhatsAppSender({
accountSid: process.env.TWILIO_ACCOUNT_SID,
authToken: process.env.TWILIO_AUTH_TOKEN,
fromNumber: process.env.TWILIO_WHATSAPP_FROM, // e.g., '+14155238886'
templates: {
orderShipped: "order_shipped_v1",
welcomeMessage: "welcome_v2",
},
}),
],
// ... other config
});
// For development/testing (no credentials needed)
NotificationKitModule.register({
senders: [new MockWhatsAppSender({ logMessages: true })],
// ... other config
});await notificationService.send({
channel: NotificationChannel.WHATSAPP,
priority: NotificationPriority.HIGH,
recipient: {
id: "user-123",
phone: "+14155551234", // E.164 format required
},
content: {
title: "Order Update",
body: "Your order #12345 has been shipped!",
},
});await notificationService.send({
channel: NotificationChannel.WHATSAPP,
recipient: {
id: "user-456",
phone: "+447911123456",
},
content: {
title: "Invoice Ready",
body: "Your invoice is attached",
data: {
mediaUrl: "https://example.com/invoice.pdf",
},
},
});await notificationService.send({
channel: NotificationChannel.WHATSAPP,
recipient: {
id: "user-789",
phone: "+212612345678",
},
content: {
title: "OTP Code",
body: "Your verification code is {{code}}",
templateId: "otp_verification",
templateVars: {
code: "123456",
expiryMinutes: "5",
},
},
});- Phone Format: Must be E.164 format (
+[country code][number])- β
Valid:
+14155551234,+447911123456,+212612345678 - β Invalid:
4155551234,+1-415-555-1234,+1 (415) 555-1234
- β
Valid:
- Twilio Account: Required for production use
- WhatsApp Opt-in: Recipients must opt-in to receive messages (send "join [code]" to Twilio number)
- Media Support: Images, videos, audio, PDFs (max 16MB for videos, 5MB for images)
- Templates: Some message types require pre-approved WhatsApp templates
Use MockWhatsAppSender for development:
const mockSender = new MockWhatsAppSender({ logMessages: true });
// Simulates sending and logs to console
// No actual API calls or credentials neededConsole output example:
βββββββββββββββββββββββββββββββββββββββββββ
π± [MockWhatsApp] Simulating WhatsApp send
βββββββββββββββββββββββββββββββββββββββββββ
To: +14155551234
Recipient ID: user-123
π¬ Message: Your order has been shipped!
βββββββββββββββββββββββββββββββββββββββββββ
- EMAIL - Email notifications via SMTP providers
- SMS - Text messages via SMS gateways
- PUSH - Mobile push notifications
- WHATSAPP - WhatsApp messages via Twilio or Meta Business API
- WEBHOOK - HTTP callbacks (coming soon)
QUEUED β SENDING β SENT β DELIVERED
β β
FAILED β (can retry)
β
CANCELLED
- LOW - Non-urgent notifications (newsletters, summaries)
- NORMAL - Standard notifications (default)
- HIGH - Important notifications (account alerts)
- URGENT - Critical notifications (security alerts)
- NodemailerSender - SMTP email (Gmail, SendGrid, AWS SES, etc.)
- TwilioSmsSender - Twilio SMS service
- AwsSnsSender - AWS SNS for SMS
- VonageSmsSender - Vonage (formerly Nexmo)
- TwilioWhatsAppSender - Twilio WhatsApp API (supports media & templates)
- MockWhatsAppSender - Mock sender for testing without credentials
- FirebasePushSender - Firebase Cloud Messaging (FCM)
- OneSignalPushSender - OneSignal push notifications
- AwsSnsPushSender - AWS SNS for push notifications
- MongoDB - Via separate
@ciscode/notification-kit-mongodbpackage - PostgreSQL - Via separate
@ciscode/notification-kit-postgrespackage - Custom - Implement
INotificationRepositoryinterface
See Infrastructure Documentation for detailed provider configuration.
This package includes comprehensive testing utilities and examples.
# Run all tests
npm test
# Run tests in watch mode
npm run test:watch
# Run tests with coverage
npm run test:covThe package maintains high test coverage across all components:
- β 133+ tests across 10 test suites
- β Unit tests for all core domain logic
- β Integration tests for end-to-end workflows
- β Controller tests for REST API endpoints
- β Module tests for NestJS dependency injection
The package provides shared test utilities for your own tests:
import {
createNotificationServiceWithDeps,
MockRepository,
MockSender,
defaultNotificationDto,
} from "@ciscode/notification-kit/test-utils";
describe("My Feature", () => {
it("should send notification", async () => {
const { service, repository, sender } = createNotificationServiceWithDeps();
const result = await service.send(defaultNotificationDto);
expect(result.success).toBe(true);
});
});Available test utilities:
MockRepository- In-memory notification repositoryMockSender- Mock notification senderMockTemplateEngine- Mock template enginecreateNotificationServiceWithDeps()- Factory for service with mocksdefaultNotificationDto- Standard test notification data
See Testing Documentation for detailed testing guidelines.
NotificationKitModule.registerAsync({
imports: [ConfigModule],
useFactory: (configService: ConfigService) => ({
senders: [
new NodemailerSender({
host: configService.get("SMTP_HOST"),
port: configService.get("SMTP_PORT"),
auth: {
user: configService.get("SMTP_USER"),
pass: configService.get("SMTP_PASS"),
},
}),
],
repository: new MongooseNotificationRepository(/* connection */),
// templateEngine: optional - most apps manage templates in backend
eventEmitter: new InMemoryEventEmitter(),
}),
inject: [ConfigService],
});import { InMemoryEventEmitter } from "@ciscode/notification-kit/infra";
const eventEmitter = new InMemoryEventEmitter();
// Listen to specific events
eventEmitter.on("notification.sent", (event) => {
console.log("Notification sent:", event.notification.id);
});
eventEmitter.on("notification.failed", (event) => {
console.error("Notification failed:", event.error);
});
// Listen to all events
eventEmitter.on("*", (event) => {
logger.log(`Event: ${event.type}`, event);
});
β οΈ Best Practice: Manage templates and content in your backend application, not in NotificationKit. Your app knows your business logic, user preferences, and localization needs better than a delivery library.
Recommended Approach (Render in Your Backend):
@Injectable()
export class NotificationService {
constructor(
private templateService: TemplateService, // Your template service
private notificationKit: NotificationService, // From NotificationKit
) {}
async sendWelcomeEmail(user: User) {
// 1. Your backend renders the template
const content = await this.templateService.render("welcome", {
name: user.name,
appName: "MyApp",
});
// 2. NotificationKit delivers it
await this.notificationKit.send({
channel: NotificationChannel.EMAIL,
recipient: { id: user.id, email: user.email },
content: {
title: content.subject,
body: content.text,
html: content.html,
},
});
}
}Built-in Template Engine (Optional, for simple use cases):
NotificationKit includes optional template engines for quick prototyping:
import { SimpleTemplateEngine } from "@ciscode/notification-kit/infra";
// Only use for demos/prototyping
NotificationKitModule.register({
templateEngine: new SimpleTemplateEngine({
welcome: {
title: "Welcome {{name}}!",
body: "Hello {{name}}, welcome to {{appName}}!",
},
}),
});
// Send using template
await notificationService.send({
content: {
templateId: "welcome",
templateVars: { name: "John", appName: "MyApp" },
},
});Note: Built-in templates are optional and best suited for prototyping. Production apps should manage templates in the backend for flexibility, versioning, and localization. See Template Configuration Guide for details.
Enable webhook endpoints to receive delivery notifications from providers:
```typescript
NotificationKitModule.register({
enableWebhooks: true,
webhookSecret: process.env.WEBHOOK_SECRET,
// ... other options
});
Webhook endpoint: POST /notifications/webhook
NotificationKit follows Clean Architecture principles:
src/
βββ core/ # Domain logic (framework-agnostic)
β βββ types.ts # Domain types and interfaces
β βββ ports.ts # Port interfaces (repository, sender, etc.)
β βββ dtos.ts # Data transfer objects with validation
β βββ errors.ts # Domain errors
β βββ notification.service.ts # Core business logic
βββ infra/ # Infrastructure implementations
β βββ senders/ # Provider implementations
β βββ repositories/ # Data persistence
β βββ providers/ # Utility providers
βββ nest/ # NestJS integration layer
βββ module.ts # NestJS module
βββ controllers/ # REST API controllers
βββ decorators.ts # DI decorators
Key principles:
- π― Domain logic is isolated and testable
- π Infrastructure is pluggable
- π Framework code is minimized
- β Everything is fully typed
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
# Clone the repository
git clone https://github.com/CISCODE-MA/NotificationKit.git
cd NotificationKit
# Install dependencies
npm install
# Run tests
npm test
# Run linter
npm run lint
# Type check
npm run typecheck
# Build
npm run buildBefore submitting a PR, ensure:
npm run lint # Lint passes
npm run typecheck # No TypeScript errors
npm test # All tests pass
npm run build # Build succeedsMIT Β© CisCode
- π Report Bug
- β¨ Request Feature
- π¬ GitHub Discussions
Made with β€οΈ by CisCode