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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@webdevarif/notifications

v1.0.0

Published

A customizable, framework-agnostic notifications system with pluggable storage and WebSocket adapters

Readme

@webdevarif/notifications

A customizable, framework-agnostic notifications system with pluggable storage and WebSocket adapters.

🚀 Features

  • Framework Agnostic: Works with any JavaScript/TypeScript framework
  • Pluggable Storage: Use any database with custom storage adapters
  • Real-time Updates: WebSocket support with multiple adapter options
  • React Integration: Built-in React hooks for easy frontend integration
  • TypeScript: Full TypeScript support with comprehensive type definitions
  • Customizable: Extend notification types and behaviors
  • Event-driven: Lifecycle hooks and event system
  • Production Ready: Battle-tested patterns and error handling

📦 Installation

npm install @webdevarif/notifications

🏗️ Architecture

The package is designed with a modular architecture:

  • Core Service: Notifications class handles business logic
  • Storage Adapters: Pluggable storage implementations
  • WebSocket Adapters: Real-time communication adapters
  • Client SDK: Browser/Node.js client for API communication
  • React Hooks: React integration for frontend applications

🚀 Quick Start

Server-side Setup

import { Notifications, InMemoryStorageAdapter } from '@webdevarif/notifications';

// Create storage adapter (in-memory for this example)
const storageAdapter = new InMemoryStorageAdapter();

// Create notifications service
const notifications = new Notifications({
  storageAdapter,
  defaultType: 'info',
});

// Create a notification
const notification = await notifications.create({
  recipientId: 'user-123',
  type: 'order',
  title: 'Order Shipped',
  body: 'Your order #12345 has been shipped',
  data: { orderId: '12345', trackingNumber: 'TRK123' },
});

console.log('Created notification:', notification);

Client-side Usage

import { NotificationClientSDK } from '@webdevarif/notifications/client';

// Create client
const client = new NotificationClientSDK({
  baseUrl: 'http://localhost:3000/api',
  websocketUrl: 'ws://localhost:3000',
  autoConnect: true,
});

// Get notifications
const notifications = await client.get({
  recipientId: 'user-123',
  limit: 10,
});

// Mark as read
await client.markAsRead('notification-id');

// Listen for real-time updates
client.on('notification:created', (notification) => {
  console.log('New notification:', notification);
});

React Integration

import React from 'react';
import { useNotifications, NotificationClientSDK } from '@webdevarif/notifications/client';

const client = new NotificationClientSDK({
  baseUrl: 'http://localhost:3000/api',
  websocketUrl: 'ws://localhost:3000',
});

function NotificationList() {
  const {
    notifications,
    count,
    loading,
    markAsRead,
    markAll,
    delete: deleteNotification,
  } = useNotifications({
    client,
    filters: { recipientId: 'user-123' },
    autoFetch: true,
  });

  if (loading) return <div>Loading...</div>;

  return (
    <div>
      <h2>Notifications ({count?.unread || 0} unread)</h2>
      <button onClick={() => markAll(true)}>
        Mark All as Read
      </button>
      
      {notifications.map((notification) => (
        <div key={notification.id} className={notification.read ? 'read' : 'unread'}>
          <h3>{notification.title}</h3>
          <p>{notification.body}</p>
          <button onClick={() => markAsRead(notification.id)}>
            Mark as Read
          </button>
          <button onClick={() => deleteNotification(notification.id)}>
            Delete
          </button>
        </div>
      ))}
    </div>
  );
}

🗄️ Storage Adapters

In-Memory Adapter (Default)

import { InMemoryStorageAdapter } from '@webdevarif/notifications';

const storageAdapter = new InMemoryStorageAdapter();

Custom Database Adapter

import { BaseStorageAdapter } from '@webdevarif/notifications';

class MyDatabaseAdapter extends BaseStorageAdapter {
  constructor(private db: any) {
    super();
  }

  async save(notification) {
    // Your database save logic
    return this.db.notifications.create(notification);
  }

  async find(filters) {
    // Your database query logic
    return this.db.notifications.findMany(filters);
  }

  // ... implement other methods
}

Prisma Adapter

import { PrismaStorageAdapter } from '@webdevarif/notifications';
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();
const storageAdapter = new PrismaStorageAdapter(prisma);

🔌 WebSocket Adapters

Default WebSocket Adapter

import { DefaultWebSocketAdapter } from '@webdevarif/notifications';

const wsAdapter = new DefaultWebSocketAdapter('ws://localhost:3000', {
  reconnectInterval: 5000,
  maxReconnectAttempts: 10,
});

Socket.IO Adapter

import { SocketIOAdapter } from '@webdevarif/notifications';
import io from 'socket.io-client';

const socket = io('http://localhost:3000');
const wsAdapter = new SocketIOAdapter(socket);

Pusher Adapter

import { PusherAdapter } from '@webdevarif/notifications';
import Pusher from 'pusher-js';

const pusher = new Pusher('your-app-key', {
  cluster: 'your-cluster',
});
const wsAdapter = new PusherAdapter(pusher, 'notifications');

🎨 Customization

Custom Notification Types

// Register custom notification types
notifications.registerType('order', {
  icon: '📦',
  color: '#f97316',
  priority: 'normal',
  actions: [
    { id: 'view', label: 'View Order', action: 'view_order' },
    { id: 'track', label: 'Track Package', action: 'track_package' },
  ],
});

notifications.registerType('payment', {
  icon: '💳',
  color: '#059669',
  priority: 'high',
  autoExpire: 24 * 60 * 60 * 1000, // 24 hours
});

Lifecycle Hooks

const notifications = new Notifications({
  storageAdapter,
  hooks: {
    onBeforeCreate: async (input) => {
      // Modify notification before creation
      return { ...input, meta: { ...input.meta, source: 'api' } };
    },
    onAfterCreate: async (notification) => {
      // Send email, push notification, etc.
      await sendEmail(notification.recipientId, notification);
    },
    onBeforeDelete: async (id) => {
      // Check if deletion is allowed
      return true;
    },
  },
});

Event Listeners

// Listen to events
notifications.on('notification:created', (notification) => {
  console.log('New notification created:', notification);
});

notifications.on('notification:updated', (notification) => {
  console.log('Notification updated:', notification);
});

notifications.on('notification:deleted', (data) => {
  console.log('Notification deleted:', data.id);
});

🛠️ API Reference

Notifications Service

class Notifications {
  // Create a notification
  create(input: CreateNotificationInput): Promise<NotificationPayload>;
  
  // Get notifications with filters
  get(filters?: NotificationFilters): Promise<NotificationPayload[]>;
  
  // Get single notification
  getOne(id: string): Promise<NotificationPayload | null>;
  
  // Mark as read/unread
  markAsRead(id: string): Promise<boolean>;
  markAsUnread(id: string): Promise<boolean>;
  
  // Mark all notifications
  markAll(recipientId: string, read: boolean): Promise<number>;
  
  // Delete notification
  delete(id: string): Promise<boolean>;
  
  // Get count
  count(filters?: NotificationFilters): Promise<NotificationCount>;
  
  // Register custom type
  registerType(type: string, config: NotificationTypeConfig): void;
}

Client SDK

class NotificationClientSDK {
  // Connect to WebSocket
  connect(): Promise<void>;
  disconnect(): void;
  
  // API methods
  get(filters?: NotificationFilters): Promise<NotificationPayload[]>;
  getOne(id: string): Promise<NotificationPayload | null>;
  markAsRead(id: string): Promise<boolean>;
  markAsUnread(id: string): Promise<boolean>;
  markAll(read: boolean): Promise<number>;
  delete(id: string): Promise<boolean>;
  count(filters?: NotificationFilters): Promise<NotificationCount>;
  
  // Event listeners
  on(event: string, callback: Function): void;
  off(event: string, callback: Function): void;
}

React Hooks

// Main hook
function useNotifications(options: UseNotificationsOptions): UseNotificationsReturn;

// Count only hook
function useNotificationCount(client: NotificationClientSDK, filters?: NotificationFilters);

// Real-time hook
function useRealtimeNotifications(client: NotificationClientSDK, onNotification?: Function);

🚀 Express Server Example

See src/server/expressExample.ts for a complete Express.js server implementation with:

  • REST API endpoints
  • WebSocket support
  • Custom notification types
  • Lifecycle hooks
  • Error handling

📝 TypeScript Support

The package is written in TypeScript and provides comprehensive type definitions:

interface NotificationPayload<T = any> {
  id: string;
  recipientId: string;
  type: string;
  title: string;
  body: string;
  data?: T;
  meta?: Record<string, any>;
  read: boolean;
  createdAt: Date;
  updatedAt: Date;
}

interface NotificationFilters {
  recipientId?: string;
  type?: string;
  read?: boolean;
  limit?: number;
  offset?: number;
  sortBy?: 'createdAt' | 'updatedAt';
  sortOrder?: 'asc' | 'desc';
}

🔧 Configuration

Server Configuration

interface NotificationConfig {
  storageAdapter: StorageAdapter;
  websocketAdapter?: WebSocketAdapter;
  hooks?: NotificationHooks;
  defaultType?: string;
  maxRetries?: number;
  retryDelay?: number;
}

Client Configuration

interface ClientConfig {
  baseUrl: string;
  websocketUrl?: string;
  apiKey?: string;
  token?: string;
  autoConnect?: boolean;
  reconnectInterval?: number;
  maxReconnectAttempts?: number;
}

🧪 Testing

import { MockWebSocketAdapter } from '@webdevarif/notifications';

// Use mock adapters for testing
const mockWsAdapter = new MockWebSocketAdapter();
const notifications = new Notifications({
  storageAdapter: new InMemoryStorageAdapter(),
  websocketAdapter: mockWsAdapter,
});

🤝 Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🆘 Support

🙏 Acknowledgments

  • Built with ❤️ by the WebDevArif team
  • Inspired by modern notification systems
  • Thanks to all contributors and users