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

featurely-site-manager

v1.1.1

Published

Complete site management SDK for maintenance mode, status messages, feature flags, version checking, and analytics

Readme

featurely-site-manager

Powerful site management SDK for controlling maintenance mode, displaying status messages, and managing site-wide features from your Featurely dashboard.

📦 Installation

npm install featurely-site-manager

🚀 Quick Start

import { SiteManager } from "featurely-site-manager";

const siteManager = new SiteManager({
  apiKey: "your-featurely-api-key",
  projectId: "your-project-id",
});

siteManager.init();

✨ Features

🔧 Maintenance Mode

  • Default or custom maintenance pages
  • Expected restoration time countdown
  • Status page links
  • Smart whitelist system:
    • localStorage keys
    • Email addresses
    • Custom bypass functions

📢 Status Messages

  • Multiple message types: info, warning, error, success
  • Flexible positioning: top, bottom banners or toast notifications
  • Dismissible messages with persistence
  • Scheduled messages (start/end times)
  • Page targeting (show on specific URLs)
  • Call-to-action buttons
  • Auto-expire functionality

🚀 Version Management

  • Automatic version checking
  • Force updates for critical releases (minimum version)
  • Recommended version notifications
  • Configurable check intervals (default: 1 hour)
  • Release notes and download URLs
  • Beta version support
  • Update callbacks for custom UI

🔐 Feature Flags

  • Enable/disable features remotely
  • Percentage-based rollouts
  • User targeting by email
  • A/B testing with variants
  • Consistent user bucketing

📊 Analytics

  • Track custom events
  • Automatic feature flag usage tracking
  • Session management
  • User identification

📖 Usage

Basic Setup

const manager = new SiteManager({
  apiKey: "ft_live_your_api_key",
  projectId: "proj_your_project_id",
});

manager.init();

With User Context

const manager = new SiteManager({
  apiKey: "ft_live_your_api_key",
  projectId: "proj_your_project_id",
  userEmail: "[email protected]", // For whitelist checks
});

manager.init();

// Update user later
manager.setUser("[email protected]");

With Callbacks

const manager = new SiteManager({
  apiKey: "ft_live_your_api_key",
  projectId: "proj_your_project_id",

  onMaintenanceEnabled: (config) => {
    console.log("Maintenance mode enabled:", config);
    // Track in analytics
  },

  onMaintenanceDisabled: () => {
    console.log("Site is back online!");
  },

  onMessageReceived: (message) => {
    console.log("New message:", message);
  },

  onError: (error) => {
    console.error("Site Manager error:", error);
  },
});

manager.init();

Custom Maintenance Bypass

const manager = new SiteManager({
  apiKey: "ft_live_your_api_key",
  projectId: "proj_your_project_id",

  bypassCheck: () => {
    // Custom logic - e.g., check if user is admin
    return window.location.search.includes("admin=true");
  },
});

manager.init();

Version Checking

const manager = new SiteManager({
  apiKey: "ft_live_your_api_key",
  projectId: "proj_your_project_id",
  appVersion: "1.2.3", // Your current app version
  enableVersionCheck: true,
  versionCheckInterval: 3600000, // Check every hour (default)

  onUpdateAvailable: (versionInfo) => {
    console.log("Update available:", versionInfo.latestVersion);
    // Show optional update notification to user
  },

  onUpdateRequired: (versionInfo) => {
    console.log("Update required:", versionInfo.latestVersion);
    // Force user to update (breaking changes)
    if (confirm(`Update required: ${versionInfo.latestVersion.title}\n\n${versionInfo.latestVersion.releaseNotes}`)) {
      window.location.href = versionInfo.latestVersion.downloadUrl || '/update';
    }
  },
});

manager.init();

// Manual version check
const versionStatus = await manager.checkVersion();
if (versionStatus?.updateAvailable) {
  console.log("New version:", versionStatus.latestVersion);
}

Feature Flags

const manager = new SiteManager({
  apiKey: "ft_live_your_api_key",
  projectId: "proj_your_project_id",
  userEmail: "[email protected]",

  onFeatureFlagsUpdated: (flags) => {
    console.log("Feature flags updated:", flags);
  },
});

manager.init();

// Check if a feature is enabled
if (manager.isFeatureEnabled("new-checkout")) {
  // Show new checkout UI
}

// Get A/B test variant
const variant = manager.getFeatureVariant("homepage-design");
if (variant === "variant-a") {
  // Show design A
}

// Get all enabled features
const enabledFeatures = manager.getEnabledFeatures();
console.log("Enabled features:", enabledFeatures);

Analytics

const manager = new SiteManager({
  apiKey: "ft_live_your_api_key",
  projectId: "proj_your_project_id",
  userId: "user_123",
  enableAnalytics: true,
  analyticsFlushInterval: 60000, // Flush every minute
});

manager.init();

// Track custom events
manager.trackEvent("button_clicked", {
  button: "signup",
  page: "/home",
});

manager.trackEvent("feature_used", {
  feature: "dark_mode",
  enabled: true,
});

Custom Poll Interval

const manager = new SiteManager({
  apiKey: "ft_live_your_api_key",
  projectId: "proj_your_project_id",
  pollInterval: 30000, // Check every 30 seconds instead of default 60s
});

manager.init();

🔧 Configuration

SiteManagerConfig

| Option | Type | Required | Default | Description | | ------------------------ | --------------- | -------- | ------------------------- | ----------------------------------------- | | apiKey | string | ✅ | - | Your Featurely API key | | projectId | string | ✅ | - | Your Featurely project ID | | apiUrl | string | ❌ | 'https://featurely.no' | Custom API endpoint | | pollInterval | number | ❌ | 60000 | Config polling interval in ms | | userEmail | string | ❌ | - | User email for whitelist & targeting | | userId | string | ❌ | - | User ID for analytics & feature flags | | bypassCheck | () => boolean | ❌ | - | Custom maintenance bypass function | | onMaintenanceEnabled | function | ❌ | - | Maintenance enabled callback | | onMaintenanceDisabled | function | ❌ | - | Maintenance disabled callback | | onMessageReceived | function | ❌ | - | Message received callback | | onMessageDismissed | function | ❌ | - | Message dismissed callback | | onFeatureFlagsUpdated | function | ❌ | - | Feature flags updated callback | | enableAnalytics | boolean | ❌ | true | Enable analytics tracking | | analyticsFlushInterval | number | ❌ | 60000 | Analytics flush interval in ms | | appVersion | string | ❌ | - | Current app version for version checking | | enableVersionCheck | boolean | ❌ | false | Enable automatic version checking | | versionCheckInterval | number | ❌ | 3600000 | Version check interval in ms (1 hour) | | onUpdateAvailable | function | ❌ | - | Callback when update is available | | onUpdateRequired | function | ❌ | - | Callback when update is required (forced) | | onError | function | ❌ | - | Error callback |

🎯 API Methods

Core Methods

init()

Initialize and start the site manager.

await manager.init();

setUser(email: string, userId?: string)

Update user email and ID for whitelist and targeting.

manager.setUser("[email protected]", "user_123");

refresh()

Manually refresh configuration from server.

await manager.refresh();

destroy()

Stop the manager and clean up.

manager.destroy();

Version Management Methods

checkVersion(currentVersion?: string)

Manually check if an update is available.

const versionInfo = await manager.checkVersion();
if (versionInfo?.updateAvailable) {
  console.log("Update available:", versionInfo.latestVersion);
  console.log("Is required?", versionInfo.updateRequired);
  console.log("Is recommended?", versionInfo.updateRecommended);
}

// Check a specific version
const customCheck = await manager.checkVersion("1.0.0");

getLastVersionCheck()

Get the last cached version check result.

const lastCheck = manager.getLastVersionCheck();
if (lastCheck?.updateAvailable) {
  // Show update notification
}

Feature Flag Methods

isFeatureEnabled(flagKey: string)

Check if a feature flag is enabled for the current user.

if (manager.isFeatureEnabled("new-dashboard")) {
  // Show new dashboard
}

getFeatureVariant(flagKey: string)

Get the assigned variant for A/B testing.

const variant = manager.getFeatureVariant("homepage-redesign");
// Returns: 'control', 'variant-a', 'variant-b', etc.

getAllFeatureFlags()

Get all feature flags.

const flags = manager.getAllFeatureFlags();
console.log("All flags:", flags);

getEnabledFeatures()

Get all enabled feature flag keys for the current user.

const enabledFeatures = manager.getEnabledFeatures();
// Returns: ['feature-1', 'feature-2', ...]

Analytics Methods

trackEvent(eventName: string, properties?: object)

Track a custom analytics event.

manager.trackEvent("button_clicked", {
  button: "signup",
  page: "/pricing",
});

manager.trackEvent("purchase_completed", {
  amount: 99.99,
  currency: "USD",
  plan: "pro",
});

💼 Use Cases

Update Notifications

const manager = new SiteManager({
  apiKey: "ft_live_...",
  projectId: "proj_...",
  appVersion: "1.2.3",
  enableVersionCheck: true,

  onUpdateRequired: (versionInfo) => {
    // Block app usage until updated
    document.body.innerHTML = `
      <div style="text-align: center; padding: 60px;">
        <h1>Critical Update Required</h1>
        <p>${versionInfo.latestVersion.title}</p>
        <p>${versionInfo.latestVersion.releaseNotes}</p>
        <a href="${versionInfo.latestVersion.downloadUrl}">
          <button>Download Update</button>
        </a>
      </div>
    `;
  },

  onUpdateAvailable: (versionInfo) => {
    // Show non-blocking notification
    if (!versionInfo.latestVersion.isBeta) {
      showToast(`Update available: ${versionInfo.latestVersion.version}`);
    }
  },
});

Feature Rollouts

// Dashboard configuration
manager.init();

// Gradually enable new checkout for 20% of users
if (manager.isFeatureEnabled("new-checkout-v2")) {
  loadNewCheckout();
} else {
  loadLegacyCheckout();
}

// A/B test with variants
const buttonColor = manager.getFeatureVariant("cta-button-color");
switch (buttonColor) {
  case "green":
    setButtonColor("#00CC66");
    break;
  case "blue":
    setButtonColor("#0066CC");
    break;
  default:
    setButtonColor("#FF6600"); // control
}

Custom Poll Interval

const manager = new SiteManager({
  apiKey: "ft_live_your_api_key",
  projectId: "proj_your_project_id",
  pollInterval: 30000, // Check every 30 seconds instead of default 60s
});

manager.init();

🔧 Configuration

SiteManagerConfig

| Option | Type | Required | Default | Description | | ----------------------- | --------------- | -------- | ------------------------- | ----------------------------- | | apiKey | string | ✅ | - | Your Featurely API key | | projectId | string | ✅ | - | Your Featurely project ID | | apiUrl | string | ❌ | 'https://featurely.no' | Custom API endpoint | | pollInterval | number | ❌ | 60000 | Polling interval in ms | | userEmail | string | ❌ | - | User email for whitelist | | bypassCheck | () => boolean | ❌ | - | Custom bypass function | | onMaintenanceEnabled | function | ❌ | - | Maintenance enabled callback | | onMaintenanceDisabled | function | ❌ | - | Maintenance disabled callback | | onMessageReceived | function | ❌ | - | Message received callback | | onMessageDismissed | function | ❌ | - | Message dismissed callback | | onError | function | ❌ | - | Error callback |

🎯 API Methods

init()

Initialize and start the site manager.

await manager.init();

setUser(email: string)

Update user email for whitelist checks.

manager.setUser("[email protected]");

refresh()

Manually refresh configuration from server.

await manager.refresh();

destroy()

Stop the manager and clean up.

manager.destroy();

🎨 Maintenance Mode

Default Page

The SDK includes a beautiful default maintenance page with:

  • Professional gradient background
  • Maintenance icon
  • Customizable messages
  • Expected restoration time
  • Optional status page link

Custom Page

Provide your own HTML:

// Set in Featurely dashboard:
{
  "type": "custom",
  "customHtml": "<div>Your custom HTML here</div>"
}

Whitelist System

localStorage Keys: Users with specific localStorage keys bypass maintenance.

// In Featurely dashboard, set whitelist keys: ['featurely_admin', 'bypass_key']
// Users can set: localStorage.setItem('featurely_admin', 'true');

Email Addresses: Specific users bypass maintenance.

// In Featurely dashboard: ['[email protected]', '[email protected]']
const manager = new SiteManager({
  apiKey: "ft_live_...",
  projectId: "proj_...",
  userEmail: "[email protected]", // This user bypasses
});

Custom Function: Complex bypass logic.

const manager = new SiteManager({
  apiKey: "ft_live_...",
  projectId: "proj_...",
  bypassCheck: () => {
    // E.g., check if admin query param is present
    return new URLSearchParams(window.location.search).get("admin") === "true";
  },
});

📢 Status Messages

Messages are managed from your Featurely dashboard and automatically displayed based on:

  • Start/end times
  • Target pages (URL patterns)
  • Message type and priority

Message Types

  • info (blue) - Informational messages
  • warning (orange) - Warnings and alerts
  • error (red) - Critical errors
  • success (green) - Success notifications

Message Styles

  • banner - Full-width top or bottom banner
  • toast - Small notification in corner

Example Message Configuration

{
  "id": "msg_123",
  "type": "warning",
  "title": "Scheduled Maintenance",
  "message": "We'll be performing maintenance tonight at 3 AM EST.",
  "position": "top",
  "style": "banner",
  "dismissible": true,
  "startsAt": "2026-03-14T10:00:00Z",
  "expiresAt": "2026-03-15T03:00:00Z",
  "cta": {
    "text": "Learn More",
    "url": "/maintenance-info"
  }
}

🌐 Framework Integration

React

import { useEffect } from "react";
import { SiteManager } from "featurely-site-manager";

function App() {
  useEffect(() => {
    const manager = new SiteManager({
      apiKey: process.env.REACT_APP_FEATURELY_API_KEY!,
      projectId: process.env.REACT_APP_FEATURELY_PROJECT_ID!,
    });

    manager.init();

    return () => manager.destroy();
  }, []);

  return <div>Your app</div>;
}

Next.js

// app/layout.tsx
"use client";

import { useEffect } from "react";
import { SiteManager } from "featurely-site-manager";

export default function RootLayout({ children }) {
  useEffect(() => {
    if (typeof window === "undefined") return;

    const manager = new SiteManager({
      apiKey: process.env.NEXT_PUBLIC_FEATURELY_API_KEY!,
      projectId: process.env.NEXT_PUBLIC_FEATURELY_PROJECT_ID!,
    });

    manager.init();

    return () => manager.destroy();
  }, []);

  return (
    <html>
      <body>{children}</body>
    </html>
  );
}

Vue

<script setup>
import { onMounted, onUnmounted } from "vue";
import { SiteManager } from "featurely-site-manager";

let manager = null;

onMounted(() => {
  manager = new SiteManager({
    apiKey: import.meta.env.VITE_FEATURELY_API_KEY,
    projectId: import.meta.env.VITE_FEATURELY_PROJECT_ID,
  });

  manager.init();
});

onUnmounted(() => {
  manager?.destroy();
});
</script>

🌐 Environment Variables

React/Vite:

VITE_FEATURELY_API_KEY=ft_live_your_key
VITE_FEATURELY_PROJECT_ID=proj_your_id

Next.js:

NEXT_PUBLIC_FEATURELY_API_KEY=ft_live_your_key
NEXT_PUBLIC_FEATURELY_PROJECT_ID=proj_your_id

🎨 Styling

The SDK injects minimal, scoped styles. All classes are prefixed with featurely- to avoid conflicts.

Custom Styling

Override default styles:

/* Customize maintenance page */
.featurely-maintenance-overlay {
  background: linear-gradient(to right, #your #colors) !important;
}

/* Customize messages */
.featurely-message-info {
  background: #your-color !important;
}

📊 Dashboard Management

Manage all settings from your Featurely dashboard at: https://featurely.no/dashboard/settings → Site Management tab

Maintenance Mode Panel

  • Toggle on/off
  • Set expected restoration time
  • Configure whitelist (emails, localStorage keys)
  • Choose default or custom page
  • Add status page link

Status Messages Panel

  • Create new messages
  • Set type, title, and content
  • Schedule start/end times
  • Target specific pages
  • Add CTA buttons
  • Set priority

🔒 Security

  • API keys should be environment variables
  • All requests use HTTPS
  • Whitelist checks happen client-side (easily bypassable - use for convenience, not security)
  • For true access control, implement server-side authentication

📱 Browser Support

  • Chrome/Edge (latest)
  • Firefox (latest)
  • Safari (latest)
  • Mobile browsers

📄 License

MIT License - see LICENSE file for details.

🔗 Links

💬 Support