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

@deldev/license_guard

v1.0.10

Published

A React component library for managing application validation and maintenance modes with built-in caching and graceful fallback handling.

Readme

App Validator

A React component library for managing application validation and maintenance modes with built-in caching and graceful fallback handling.

Features

  • Automatic application validation via API endpoint
  • Cookie-based caching to reduce API calls
  • Customizable maintenance page
  • Loading states with elegant spinner
  • Graceful error handling
  • TypeScript support
  • Framework-agnostic (works with any React-based framework)

Installation

npm install @deldev/license_guard
# or
yarn add @deldev/license_guard
# or
pnpm add @deldev/license_guard

Quick Start

import { AppValidator } from "@deldev/license_guard";

function App() {
  return (
    <AppValidator appId="your-app-id">
      <YourApplication />
    </AppValidator>
  );
}

API Reference

AppValidator Component

Main component that wraps your application and handles validation.

Props

| Prop | Type | Required | Default | Description | | ------------- | ----------- | -------- | ---------------- | -------------------------------------- | | appId | string | Yes | - | Unique identifier for your application | | appName | string | No | - | Display name shown on maintenance page | | apiEndpoint | string | No | Default endpoint | Custom validation API endpoint | | children | ReactNode | Yes | - | Your application content |

Example

<AppValidator
  appId="my-app-123"
  appName="My Awesome App"
  apiEndpoint="https://api.example.com/validate"
>
  <App />
</AppValidator>

Validation Response

The API endpoint should return JSON in this format:

interface ValidationResponse {
  status: "OK" | "MAINTENANCE";
  message?: string; // Optional message for maintenance mode
}

Framework Integration

Next.js (App Router)

// app/layout.tsx
import { AppValidator } from "@deldev/license_guard";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <AppValidator appId="nextjs-app-123" appName="Next.js App">
          {children}
        </AppValidator>
      </body>
    </html>
  );
}

Next.js (Pages Router)

// pages/_app.tsx
import { AppValidator } from "@deldev/license_guard";
import type { AppProps } from "next/app";

export default function App({ Component, pageProps }: AppProps) {
  return (
    <AppValidator appId="nextjs-pages-123" appName="My Next.js App">
      <Component {...pageProps} />
    </AppValidator>
  );
}

Create React App (CRA)

// src/index.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { AppValidator } from "@deldev/license_guard";
import App from "./App";

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement,
);

root.render(
  <React.StrictMode>
    <AppValidator appId="cra-app-123" appName="CRA Application">
      <App />
    </AppValidator>
  </React.StrictMode>,
);

Vite + React

// src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { AppValidator } from "@deldev/license_guard";
import App from "./App";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <AppValidator appId="vite-app-123" appName="Vite App">
      <App />
    </AppValidator>
  </React.StrictMode>,
);

Remix

// app/root.tsx
import { AppValidator } from "@deldev/license_guard";
import {
  Links,
  LiveReload,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration,
} from "@remix-run/react";

export default function App() {
  return (
    <html lang="en">
      <head>
        <Meta />
        <Links />
      </head>
      <body>
        <AppValidator appId="remix-app-123" appName="Remix App">
          <Outlet />
        </AppValidator>
        <ScrollRestoration />
        <Scripts />
        <LiveReload />
      </body>
    </html>
  );
}

Gatsby

// gatsby-browser.js or gatsby-ssr.js
import React from "react";
import { AppValidator } from "@deldev/license_guard";

export const wrapRootElement = ({ element }) => (
  <AppValidator appId="gatsby-app-123" appName="Gatsby Site">
    {element}
  </AppValidator>
);

Astro (with React integration)

---
// src/layouts/Layout.astro
import { AppValidator } from '@deldev/license_guard';
---

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Astro App</title>
  </head>
  <body>
    <AppValidator client:only="react" appId="astro-app-123" appName="Astro App">
      <slot />
    </AppValidator>
  </body>
</html>

Expo / React Native Web

// App.tsx
import { AppValidator } from "@deldev/license_guard";
import { registerRootComponent } from "expo";

function App() {
  return (
    <AppValidator appId="expo-app-123" appName="Expo App">
      <YourApp />
    </AppValidator>
  );
}

registerRootComponent(App);

Backend API Implementation

Node.js + Express

const express = require("express");
const app = express();

app.post("/validate", (req, res) => {
  const appId = req.headers["x-app-id"];

  // Your validation logic here
  const isInMaintenance = checkMaintenanceStatus(appId);

  if (isInMaintenance) {
    res.json({
      status: "MAINTENANCE",
      message: "We are currently performing scheduled maintenance.",
    });
  } else {
    res.json({ status: "OK" });
  }
});

Next.js API Route

// app/api/validate/route.ts (App Router)
import { NextRequest, NextResponse } from "next/server";

export async function POST(request: NextRequest) {
  const appId = request.headers.get("x-app-id");

  // Your validation logic
  const isInMaintenance = await checkMaintenanceStatus(appId);

  if (isInMaintenance) {
    return NextResponse.json({
      status: "MAINTENANCE",
      message: "Scheduled maintenance in progress",
    });
  }

  return NextResponse.json({ status: "OK" });
}

Serverless Function (Vercel/Netlify)

// api/validate.ts
import { VercelRequest, VercelResponse } from "@vercel/node";

export default async function handler(req: VercelRequest, res: VercelResponse) {
  const appId = req.headers["x-app-id"];

  // Validation logic
  const isInMaintenance = process.env.MAINTENANCE_MODE === "true";

  if (isInMaintenance) {
    return res.json({
      status: "MAINTENANCE",
      message: "Under maintenance",
    });
  }

  return res.json({ status: "OK" });
}

Caching Behavior

  • Validation results are cached in cookies for 24 hours by default
  • Reduces unnecessary API calls
  • OK status cached for 24 hours
  • MAINTENANCE status cached for 24 hours
  • Cache is automatically cleared after expiration

Error Handling

The component handles errors gracefully:

  • Network errors: Shows maintenance mode with "Network error" message
  • Server errors: Shows maintenance mode with "Server error" message
  • Invalid responses: Treats as maintenance mode
  • Grace period: If cookie shows OK but validation fails, maintains OK status temporarily

TypeScript Support

Full TypeScript support with exported types:

import type { ValidationResponse } from "@deldev/license_guard";

const response: ValidationResponse = {
  status: "OK",
  message: "Optional message",
};

Browser Support

  • Modern browsers (Chrome, Firefox, Safari, Edge)
  • Requires support for:
    • fetch API
    • ES6 features
    • Cookie support

License

MIT

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

Support

For issues and questions, please open an issue on GitHub.