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

network-guard-engine

v1.0.3

Published

Zero-dependency network status monitor with pluggable handlers.

Readme

network-guard-engine

Zero-dependency network status monitor with pluggable notification handlers.
Works in React, Next.js, and vanilla JavaScript — bring your own notification system or use none at all.


Table of Contents


Features

  • Zero runtime dependencies — core has no dependencies
  • SSR-safe — all browser APIs are properly guarded
  • Pluggable architecture — use any notification system
  • Debounced events — prevents flicker on unstable connections
  • Fully typed — built with TypeScript
  • Tree-shakeable — framework integrations are isolated entry points
  • React 19 compatible — uses ref-stabilized callbacks, no stale closures
  • Framework-specific entry pointsreact, next, handlers

Installation

npm install network-guard-engine
# or
pnpm add network-guard-engine
# or
yarn add network-guard-engine

Quick Start

import { createNetworkMonitor } from "network-guard-engine";

const monitor = createNetworkMonitor({
  onOnline:  ({ message }) => console.log(message),
  onOffline: ({ message }) => console.warn(message),
});

// Stop when done
monitor.stop();

Vanilla JavaScript

createNetworkMonitor(options?)

The simplest way to get started. Creates a monitor and starts it immediately.

import { createNetworkMonitor } from "network-guard-engine";

const monitor = createNetworkMonitor({
  messages: {
    online:         "Connection restored ✓",
    offline:        "Connection lost ✗",
    offlineOnMount: "No network connection detected",
  },
  debounce:     800,    // wait 800ms before firing (default: 500)
  checkOnMount: true,   // fire offline handler immediately if offline (default: true)

  onOnline:  ({ message, timestamp, isInitial }) => {
    console.log(`[${timestamp.toLocaleTimeString()}] ${message}`);
  },
  onOffline: ({ message, isInitial }) => {
    if (!isInitial) console.warn("Lost connection:", message);
  },
});

// Clean up when done (e.g. on page unload or SPA route change)
monitor.stop();

new NetworkMonitor(options?)

Use the class directly when you need more control, such as starting and stopping imperatively.

import { NetworkMonitor } from "network-guard-engine";

const monitor = new NetworkMonitor({
  onOnline:  ({ message }) => showToast(message, "success"),
  onOffline: ({ message }) => showToast(message, "error"),
});

// Start manually (e.g. after user logs in)
monitor.start();

// Check status at any time
console.log(monitor.running); // true
console.log(monitor.status);  // "online" | "offline" | null

// Stop and restart
monitor.stop();
monitor.start();

React Integration

# React is a peer dependency — install if you haven't already
npm install react

useNetworkStatus

The simplest React hook. Returns the current network status as reactive values.

import { useNetworkStatus } from "network-guard-engine/react";

function App() {
  const { isOnline, isOffline, status, lastChanged } = useNetworkStatus();

  return (
    <>
      {isOffline && (
        <div className="banner">
          You are offline
          {lastChanged && ` since ${lastChanged.toLocaleTimeString()}`}
        </div>
      )}
      <main>{/* your app */}</main>
    </>
  );
}

Return values:

| Field | Type | Description | |---------------|-------------------------|------------------------------------------------------| | status | "online" \| "offline" | Current network status | | isOnline | boolean | Shorthand for status === "online" | | isOffline | boolean | Shorthand for status === "offline" | | lastChanged | Date \| null | Timestamp of the last status change, or null |


useNetworkMonitor

A lower-level hook that provides imperative start / stop control alongside the reactive status values. Useful when you need to conditionally enable monitoring or expose controls in your UI.

import { useNetworkMonitor } from "network-guard-engine/react";

function MonitorPanel() {
  const { isOnline, isOffline, isMonitoring, start, stop, lastChanged } =
    useNetworkMonitor({
      debounce: 800,
      messages: { offline: "Connection interrupted." },
    });

  return (
    <div>
      <p>Status: {isOnline ? "🟢 Online" : "🔴 Offline"}</p>
      {lastChanged && <p>Since: {lastChanged.toLocaleTimeString()}</p>}
      <button onClick={isMonitoring ? stop : start}>
        {isMonitoring ? "Stop monitoring" : "Start monitoring"}
      </button>
    </div>
  );
}

Options:

| Option | Type | Default | Description | |----------------|-------------------|----------|-------------------------------------------------| | debounce | number | 500 | Milliseconds to wait before firing a handler | | checkOnMount | boolean | true | Fire offline handler on mount if already offline| | messages | NetworkMessages | built-in | Custom message strings |

Return values (extends UseNetworkStatusReturn):

| Field | Type | Description | |----------------|------------|--------------------------------------------------| | isMonitoring | boolean | true while the monitor is actively listening | | start | () => void | Start monitoring (no-op if already running) | | stop | () => void | Stop monitoring and cancel pending debounce |


NetworkProvider

A provider component that fires your own notification callbacks on network changes. It has no built-in UI — bring your own toast library, Redux action, or Zustand setter.

import { NetworkProvider } from "network-guard-engine/react";
import { toast } from "sonner";

let offlineToastId: string | number | null = null;

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <NetworkProvider
      messages={{
        online:  "Back online!",
        offline: "Connection lost. Please check your network.",
      }}
      onOnline={({ message }) => {
        if (offlineToastId !== null) toast.dismiss(offlineToastId);
        toast.success(message, { duration: 3000 });
        offlineToastId = null;
      }}
      onOffline={({ message }) => {
        if (offlineToastId !== null) toast.dismiss(offlineToastId);
        offlineToastId = toast.error(message, { duration: Infinity });
      }}
    >
      {children}
    </NetworkProvider>
  );
}

Props:

| Prop | Type | Default | Description | |----------------|-------------------|----------|----------------------------------------------------------| | children | React.ReactNode | — | Required. Rendered as-is. | | onOnline | NetworkHandler | — | Called when connection is restored | | onOffline | NetworkHandler | — | Called when connection is lost | | onChange | NetworkHandler | — | Called on both online and offline events | | debounce | number | 500 | Milliseconds to debounce before firing handlers | | checkOnMount | boolean | true | Fire onOffline on mount if already offline | | messages | NetworkMessages | built-in | Custom message strings |

Spread with built-in handlers:

import { consoleHandler } from "network-guard-engine/handlers";

<NetworkProvider {...consoleHandler({ offlineLevel: "error" })}>
  {children}
</NetworkProvider>

With Zustand:

import { useNetworkStore } from "@/stores/network";

function AppShell({ children }: { children: React.ReactNode }) {
  const setOnline  = useNetworkStore((s) => s.setOnline);
  const setOffline = useNetworkStore((s) => s.setOffline);

  return (
    <NetworkProvider onOnline={setOnline} onOffline={setOffline}>
      {children}
    </NetworkProvider>
  );
}

With onChange (single handler for both events):

<NetworkProvider
  onChange={({ status, isInitial, timestamp }) => {
    analytics.track("network_status_changed", { status, isInitial, timestamp });
  }}
>
  {children}
</NetworkProvider>

Next.js Integration

The /next entry re-exports everything from /react with a "use client" directive already prepended, so you don't need to add it yourself.

// app/providers.tsx
import { NetworkProvider } from "network-guard-engine/next";
import { toast } from "sonner";

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <NetworkProvider
      onOnline={({ message }) => toast.success(message)}
      onOffline={({ message }) => toast.error(message, { duration: Infinity })}
    >
      {children}
    </NetworkProvider>
  );
}
// app/layout.tsx
import { Providers } from "./providers";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}

Hooks are available from the /next entry too:

"use client";
import { useNetworkStatus } from "network-guard-engine/next";

Built-in Handlers

Import from network-guard-engine/handlers (or from the main entry for vanilla usage).

consoleHandler

Logs network status changes to the browser or Node.js console.

import { createNetworkMonitor } from "network-guard-engine";
import { consoleHandler }       from "network-guard-engine/handlers";

createNetworkMonitor({
  ...consoleHandler({
    offlineLevel:  "error",   // "log" | "warn" | "error" (default: "warn")
    onlineLevel:   "info",    // "log" | "info"            (default: "log")
    showTimestamp: true,      //                           (default: true)
    messages: {
      online:  "Connected",
      offline: "Disconnected",
    },
  }),
});

Output example:

[14:32:07] Disconnected          ← offline (logged via console.error)
[14:32:45] Connected             ← online  (logged via console.info)

alertHandler

Shows a native window.alert() dialog on each status change.

Best for quick debugging or environments without a notification system. Not recommended for production.

import { createNetworkMonitor } from "network-guard-engine";
import { alertHandler }         from "network-guard-engine/handlers";

createNetworkMonitor({
  ...alertHandler({
    messages: {
      online:  "You're back online.",
      offline: "You lost your connection.",
    },
  }),
});

customHandler

The recommended adapter for integrating any external toast or notification library. Receives a clean message string plus the full NetworkEventPayload.

import { createNetworkMonitor } from "network-guard-engine";
import { customHandler }        from "network-guard-engine/handlers";
import { toast }                from "sonner";

let offlineToastId: string | number | null = null;

createNetworkMonitor({
  ...customHandler({
    messages: {
      online:         "Back online!",
      offline:        "Connection lost. Please check your network.",
      offlineOnMount: "No internet connection detected.",
    },
    onOnline: (message) => {
      if (offlineToastId !== null) toast.dismiss(offlineToastId);
      toast.success(message, { duration: 3000 });
      offlineToastId = null;
    },
    onOffline: (message) => {
      if (offlineToastId !== null) toast.dismiss(offlineToastId);
      offlineToastId = toast.error(message, { duration: Infinity });
    },
  }),
});

Full payload access (second argument):

customHandler({
  onOffline: (message, payload) => {
    // payload.isInitial — true only on the first mount check
    if (!payload.isInitial) Sentry.captureMessage("User went offline");
    showBanner(message);
  },
});

With React Hot Toast:

import toast from "react-hot-toast";

createNetworkMonitor({
  ...customHandler({
    onOnline:  (message) => toast.success(message),
    onOffline: (message) => toast.error(message, { duration: Infinity }),
  }),
});

domBannerHandler

Injects a fixed, animated banner at the top of the page — no React, no external libraries required.

  • Created lazily on the first event and reused for subsequent events.
  • Slides in/out using CSS transitions.
  • Fully accessible: sets role="alert" and aria-live="assertive".
import { createNetworkMonitor } from "network-guard-engine";
import { domBannerHandler }     from "network-guard-engine/handlers";

createNetworkMonitor({
  ...domBannerHandler(),
});

With custom options:

createNetworkMonitor({
  ...domBannerHandler({
    container:      "#app-root",  // CSS selector or HTMLElement (default: document.body)
    onlineDuration: 2500,         // ms before hiding the "back online" banner (default: 3000)
    messages: {
      online:         "Reconnected!",
      offline:        "No connection",
      offlineOnMount: "You appear to be offline.",
    },
    offlineStyle: {
      background:    "#7f1d1d",
      letterSpacing: "0.05em",
    },
    onlineStyle: {
      background: "#14532d",
    },
  }),
});

Options:

| Option | Type | Default | Description | |------------------|----------------------------------|-----------------|-------------------------------------------------------| | messages | NetworkMessages | built-in | Custom text for each status | | container | string \| HTMLElement | document.body | Where to mount the banner element | | offlineStyle | Partial<CSSStyleDeclaration> | — | Additional styles applied while offline | | onlineStyle | Partial<CSSStyleDeclaration> | — | Additional styles applied while online | | onlineDuration | number | 3000 | How long (ms) the "back online" banner stays visible. Set 0 to keep it until next change. |


API Reference

NetworkEventPayload

Delivered to every handler. All fields are readonly — the object is frozen.

type NetworkEventPayload = {
  readonly status:    "online" | "offline";
  readonly message:   string;   // resolved human-readable message
  readonly isInitial: boolean;  // true only on the first mount check
  readonly timestamp: Date;     // when this event was fired
};

NetworkMessages

All fields are optional and fall back to built-in defaults.

type NetworkMessages = {
  online?:         string;  // default: "Back online"
  offline?:        string;  // default: "You are offline. Please check your connection."
  offlineOnMount?: string;  // default: "No internet connection. Please check your network."
};

NetworkMonitor class

new NetworkMonitor(options?: NetworkMonitorOptions): NetworkMonitor

monitor.start():   this           // start listening, returns this (chainable)
monitor.stop():    this           // stop and cancel pending debounce, returns this
monitor.running:   boolean        // true while actively listening
monitor.status:    "online" | "offline" | null  // last known status (null before first start)

createNetworkMonitor(options?)

createNetworkMonitor(options?: NetworkMonitorOptions): NetworkMonitor
// Equivalent to: new NetworkMonitor(options).start()

NetworkMonitorOptions

| Option | Type | Default | Description | |----------------|-------------------|----------|---------------------------------------------------------| | debounce | number | 500 | Milliseconds to wait before firing after a status change| | checkOnMount | boolean | true | Fire onOffline immediately on start if already offline| | onOnline | NetworkHandler | — | Called when connection is restored | | onOffline | NetworkHandler | — | Called when connection is lost | | messages | NetworkMessages | built-in | Custom message strings |


Browser Support

| Browser | Support | |---------------|---------| | Chrome 66+ | ✅ | | Firefox 60+ | ✅ | | Safari 12.1+ | ✅ | | Edge 79+ | ✅ | | Node.js / SSR | ✅ (safe — all browser APIs are guarded) |

The library uses window.addEventListener("online" / "offline") and navigator.onLine, which have broad browser support. The core module is SSR-safe: every window and navigator access is guarded, so you can safely import and instantiate the monitor in a server environment — it simply becomes a no-op until .start() is called in the browser.


TypeScript

All types are exported from the main entry point:

import type {
  NetworkStatus,
  NetworkMessages,
  NetworkEventPayload,
  NetworkHandler,
  NetworkMonitorOptions,
  NetworkProviderProps,
  UseNetworkStatusReturn,
  UseNetworkMonitorReturn,
  AlertHandlerOptions,
  ConsoleHandlerOptions,
  CustomHandlerOptions,
  DomBannerHandlerOptions,
} from "network-guard-engine";