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

universal-push-notifications

v1.1.0

Published

A secure, universal push notification package for React.js and Vue.js with server-side environment variable protection

Readme

Universal Push Notifications

A secure, universal push notification package for React.js and Vue.js applications with server-side environment variable protection.

Features

  • 🔒 Secure: Environment variables kept server-side
  • ⚛️ React Support: Custom hook with TypeScript support
  • 🟢 Vue Support: Composable API for Vue 2 & 3
  • 🚀 Easy Setup: Simple configuration and setup
  • 📱 PWA Ready: Service worker included
  • 🔧 Customizable: Flexible configuration options
  • 📦 Lightweight: Minimal dependencies

Package Structure

This package is organized into client and server parts for better separation of concerns:

  • Client-side imports (React/Vue components):

    // ESM
    import { usePushNotifications } from 'universal-push-notifications';
    // or CommonJS
    const { usePushNotifications } = require('universal-push-notifications');
  • Server-side imports (nodejs/express applications):

    // ESM
    import { NotificationServer } from 'universal-push-notifications/server';
    // or CommonJS
    const { NotificationServer } = require('universal-push-notifications/server');

Installation

npm install universal-push-notifications
# or
yarn add universal-push-notifications

Quick Start

1. Generate VAPID Keys

const { NotificationServer } = require('universal-push-notifications/server');

// Generate keys (run once, store securely)
const vapidKeys = NotificationServer.generateVapidKeys();
console.log(vapidKeys);
// Save these to your environment variables

2. Server Setup (Express.js)

const express = require('express');
// Import server module specifically
const { NotificationServer } = require('universal-push-notifications/server');

const app = express();
app.use(express.json());

const notificationServer = new NotificationServer({
  vapidKeys: {
    publicKey: process.env.VAPID_PUBLIC_KEY,
    privateKey: process.env.VAPID_PRIVATE_KEY
  },
  vapidDetails: {
    subject: 'mailto:[email protected]'
  }
});

const middleware = notificationServer.createMiddleware();

app.get('/api/notifications/vapid-public-key', middleware.getVapidPublicKey);
app.post('/api/notifications/subscribe', middleware.subscribe);
app.post('/api/notifications/unsubscribe', middleware.unsubscribe);
app.post('/api/notifications/send', middleware.sendNotification);

app.listen(3000);

3. Copy Service Worker

Copy the service worker to your public folder:

cp node_modules/universal-push-notifications/public/sw.js public/

4. React Usage

import React from 'react';
import { usePushNotifications } from 'universal-push-notifications';

function NotificationComponent() {
  const {
    isSupported,
    subscription,
    isSubscribed,
    permission,
    loading,
    error,
    subscribe
  } = usePushNotifications({
    apiEndpoint: '/api/notifications',
    debug: true
  });

  if (!isSupported) {
    return <div>Push notifications not supported</div>;
  }

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

  if (error) {
    return <div>Error: {error}</div>;
  }

  return (
    <div>
      <h3>Push Notifications</h3>
      <p>Current permission: {permission}</p>
      
      {!isSubscribed ? (
        <button onClick={subscribe} disabled={loading}>
          Enable Push Notifications
        </button>
      ) : (
        <div>
          <p>Notifications enabled!</p>
          <pre>{JSON.stringify(subscription, null, 2)}</pre>
        </div>
      )}
    </div>
  );
}

5. Vue Usage

// Component.js
import { createPushNotifications } from 'universal-push-notifications';

export default {
  setup() {
    const {
      isSupported,
      subscription,
      isSubscribed,
      permission,
      loading,
      error,
      subscribe
    } = createPushNotifications({
      apiEndpoint: '/api/notifications',
      debug: true
    });

    return {
      isSupported,
      isSubscribed,
      permission,
      loading,
      error,
      subscribe,
      subscription
    };
  }
};
<!-- Component.vue -->
<template>
  <div>
    <h3>Push Notifications</h3>
    
    <div v-if="!isSupported">
      Push notifications not supported
    </div>
    
    <div v-else-if="loading">
      Loading...
    </div>
    
    <div v-else-if="error">
      Error: {{ error }}
    </div>
    
    <div v-else>
      <p>Current permission: {{ permission }}</p>
      
      <button 
        v-if="!isSubscribed" 
        @click="subscribe" 
        :disabled="loading"
      >
        Enable Push Notifications
      </button>
      
      <div v-else>
        <p>Notifications enabled!</p>
        <pre>{{ JSON.stringify(subscription, null, 2) }}</pre>
      </div>
    </div>
  </div>
</template>

6. Send Notifications from Server

<template>
  <div v-if="!isSupported">
    Push notifications not supported
  </div>
  
  <div v-else>
    <h3>Push Notifications</h3>
    <p>Permission: {{ permission }}</p>
    <p>Subscribed: {{ isSubscribed ? 'Yes' : 'No' }}</p>
    
    <p v-if="error" style="color: red">Error: {{ error }}</p>
    
    <button 
      @click="subscribe" 
      :disabled="loading || isSubscribed"
    >
      {{ loading ? 'Loading...' : 'Subscribe' }}
    </button>
    
    <button 
      @click="unsubscribe" 
      :disabled="loading || !isSubscribed"
    >
      {{ loading ? 'Loading...' : 'Unsubscribe' }}
    </button>
    
    <button 
      @click="() => showTestNotification('Test', { body: 'This is a test!' })"
      :disabled="!isSubscribed"
    >
      Test Notification
    </button>
  </div>
</template>

<script>
import { createPushNotificationsVue2 } from 'universal-push-notifications';

export default createPushNotificationsVue2({
  apiEndpoint: '/api/notifications',
  debug: true
});
</script>

Configuration Options

Client Configuration

const config = {
  apiEndpoint: '/api/notifications',    // API endpoint base path
  swPath: '/sw.js',                    // Service worker path
  debug: false                         // Enable debug logging
};

Server Configuration

const notificationServer = new NotificationServer({
  vapidKeys: {
    publicKey: 'YOUR_PUBLIC_KEY',
    privateKey: 'YOUR_PRIVATE_KEY'
  },
  vapidDetails: {
    subject: 'mailto:[email protected]'  // or 'https://yoursite.com'
  }
});

API Reference

React Hook: usePushNotifications(config)

Returns an object with:

  • isSupported: boolean - Browser support
  • subscription: PushSubscription | null - Current subscription
  • isSubscribed: boolean - Subscription status
  • permission: NotificationPermission - Current permission
  • loading: boolean - Loading state
  • error: string | null - Error message
  • subscribe(): Function to subscribe
  • unsubscribe(): Function to unsubscribe
  • showTestNotification(title, options): Show test notification
  • clearError(): Clear error state

Vue Composable: createPushNotifications(config)

Returns an object with:

  • state: Reactive state object
  • isSubscribed: Computed subscription status
  • subscribe(): Function to subscribe
  • unsubscribe(): Function to unsubscribe
  • showTestNotification(title, options): Show test notification
  • clearError(): Clear error state
  • initialize(): Manual initialization

Server Class: NotificationServer

Methods:

  • static generateVapidKeys(): Generate VAPID key pair
  • createMiddleware(): Create Express middleware
  • getAllSubscriptions(): Get all subscriptions
  • getSubscriptionCount(): Get subscriber count

Environment Variables

# Required VAPID keys (keep these secret!)
VAPID_PUBLIC_KEY=your_public_key_here
VAPID_PRIVATE_KEY=your_private_key_here

# Optional
NODE_ENV=production

Security Features

Environment Variables Protected: VAPID private keys never exposed to client ✅ Secure API Endpoints: Proper validation and error handling ✅ HTTPS Required: Push notifications require HTTPS in production ✅ Origin Validation: Service worker validates notification origin ✅ Subscription Management: Automatic cleanup of invalid subscriptions

Browser Support

  • Chrome/Edge: ✅ Full support
  • Firefox: ✅ Full support
  • Safari: ✅ iOS 16.4+ / macOS 13+
  • Opera: ✅ Full support

Troubleshooting

Common Issues

  1. Notifications not showing: Check browser permissions and HTTPS
  2. Service worker not registering: Verify file path and HTTPS
  3. VAPID errors: Ensure keys are correctly set in environment
  4. Cross-origin issues: Check CORS settings on your server

Debug Mode

Enable debug logging:

const notifications = usePushNotifications({ debug: true });

Examples

Check the examples/ directory for complete working examples:

  • examples/react-example/ - Complete React app
  • examples/vue-example/ - Complete Vue app
  • examples/server-example/ - Express.js server setup

Contributing

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

License

MIT License