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 🙏

© 2026 – Pkg Stats / Ryan Hefner

fonotify

v2.1.2

Published

Fire Once Notify Once - ultra lightweight SSE notifier

Readme


🚀 FoNotify

FoNotify = Fire Once, Notify Once

A minimal, ultra-lightweight real-time notification system.

No queues. No storage. No retries. Just one simple rule:

If client is connected → notify If not → forget


📦 NPM

https://www.npmjs.com/package/fonotify


❓ Why FoNotify Exists

Most real-time systems today are over-engineered.

To send a simple update, developers often introduce:

  • WebSockets
  • Message queues (Kafka, RabbitMQ)
  • Retry systems
  • Persistent storage layers

But many applications don’t need all that.


🔴 The Real Problem

In most apps, the requirement is simple:

“Something changed → notify client → client refreshes data”

Yet solving this often leads to complex infrastructure, higher cost, and maintenance overhead.


✅ The FoNotify Approach

FoNotify does one thing only:

Send a signal, not data

Server → notify(userId) → Client → fetch latest data

FoNotify does not transfer data, it only tells the client:

“Hey, something changed. You decide what to do.”


🧠 Core Philosophy

FoNotify is designed for systems where:

  • You don’t need guaranteed delivery
  • You only care about active/connected users
  • You want zero infrastructure overhead
  • You prefer stateless architecture

✨ Features

  • Real-time notifications (instant)

  • Zero memory (no storage, no queue)

  • Fire-and-forget architecture

  • Works with:

    • Express
    • Fastify
    • Hono
  • Built-in lightweight client SDK

  • Plug & play integration

  • Optional Redis support for scaling

  • Extremely low memory footprint


🔄 How It Works

Client connects
        ↓
Server triggers event
        ↓
notify(userId)
        ↓
If connected → notify
If not → ignore

⚡ Real Flow (Production Pattern)

Webhook / DB Change
        ↓
Server logic
        ↓
notify(userId)
        ↓
Client receives signal
        ↓
Client calls API (GET /data)
        ↓
UI updates

📦 Installation

npm install fonotify

Install only what your target needs:

# Server with Redis scaling (optional)
npm install ioredis

# React Native client
npm install react-native-sse

🚀 Backend Usage


Express

import express from "express";
import { initFoNotify, notify } from "fonotify";

const app = express();

initFoNotify(app);

app.post("/update/:userId", (req, res) => {
  notify(req.params.userId);
  res.json({ success: true });
});

app.listen(4000);

Fastify

import Fastify from "fastify";
import { initFoNotify, notify } from "fonotify";

const app = Fastify();

initFoNotify(app);

app.post("/update/:userId", async (req) => {
  notify(req.params.userId);
  return { success: true };
});

app.listen({ port: 4000 });

Hono

import { Hono } from "hono";
import { initFoNotify, notify } from "fonotify";

const app = new Hono();

initFoNotify(app);

app.post("/update/:userId", (c) => {
  notify(c.req.param("userId"));
  return c.json({ success: true });
});

export default app;

🌐 Frontend Usage

Web (Browser)

import { useEffect } from "react";
import { subscribe } from "fonotify/web";

useEffect(() => {
  const sub = subscribe("http://localhost:4000", "user-123", async () => {
    const res = await fetch("/api/data");
    const data = await res.json();
    console.log(data);
  });

  return () => {
    sub.close();
  };
}, []);

React Native

import { subscribe } from "fonotify/app";

const sub = subscribe("http://localhost:4000", "user-123", () => {
  console.log("update received");
});

// cleanup
sub.close();

Install RN SSE package in your React Native app:

npm install react-native-sse

🎯 API Reference


initFoNotify(app, redisUrl?)

initFoNotify(app);
initFoNotify(app, "redis://localhost:6379");
  • Initializes FoNotify on your server
  • Must be called once
  • Supports Express, Fastify, Hono
  • Optional Redis URL enables multi-instance scaling
  • If you pass a Redis URL, install ioredis in your server project

notify(topic)

notify("user-123");
  • Sends { update: true } signal
  • If no client is connected → does nothing
  • No retries, no storage

subscribe(url, topic, handler)

subscribe("http://localhost:4000", "user-123", () => {
  console.log("update received");
});
  • Opens a live connection
  • Triggers handler when notified
  • Returns a subscription object with .close()

⚡ Redis Support (Horizontal Scaling)

FoNotify works out of the box in single-instance mode.

To scale across multiple servers:

initFoNotify(app, "redis://localhost:6379");

How it works:

Server 1 ─┐
          ├── Redis Pub/Sub ──► All servers ──► Clients
Server 2 ─┘
  • Notifications are broadcast across instances
  • Clients connected to any server receive updates
  • Still stateless (no persistence)

📊 Behavior

| Scenario | Result | | ---------------- | -------------------- | | Client connected | Instant notification | | Client offline | Ignored | | Multiple notify | Only live delivery | | Message storage | None | | Retry mechanism | None |


🆚 Comparison

| Feature | FoNotify | WebSockets | Polling | | -------------- | -------- | ---------- | ------- | | Complexity | Low | High | Low | | Memory usage | Low | High | High | | Infrastructure | Minimal | Heavy | Minimal | | Use case | Signals | Streams | Basic |


🎯 When to Use FoNotify

Ideal for:

  • Dashboards
  • Admin panels
  • Notification systems
  • Webhook-driven updates
  • Stateless APIs
  • “Data changed → refresh UI” flows

⚠️ Limitations

  • No persistence

  • No delivery guarantees

  • Not suitable for:

    • Chat apps
    • Streaming systems
    • Financial/critical systems

📄 License

MIT License © Manoj Gowda


🙌 Author

Manoj Gowda B R

  • Full Stack Developer & DevOps
  • Focused on lightweight, scalable systems

🌐 https://manojgowda.in 💻 https://manojgowda.in/github


💡 Final Thought

Don’t send data. Send signals. Let your APIs handle the rest.