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

cookie-nom

v0.1.0

Published

A calm, neuro-inclusive cookie-consent framework with LCARS-inspired UI, automatic cookie detection, and script blocking

Readme

CookieNom

A calm, neuro-inclusive cookie-consent framework

CookieNom replaces intrusive cookie banners with a friendly, LCARS-style "CookieCar" that sits quietly at the bottom of the page. It handles consent, auto-detects and categorises cookies, blocks third-party scripts until consent is given, and lets users manage preferences at any time -- no pop-ups, no dark patterns.

Features

  • Neuro-inclusive & Accessible -- ARIA labels, keyboard navigation, focus trapping, prefers-reduced-motion support
  • LCARS-Inspired Design -- retro-futuristic styling, soft animations, rounded shapes
  • Privacy-First -- defaults to essential-only; "no action" = no consent
  • Automatic Cookie Detection -- built-in database of 40+ known cookie patterns (GA, Facebook, Hotjar, TikTok, etc.)
  • Script Blocking -- block third-party <script> tags until the matching category is consented to
  • Cookie Cleanup -- removes non-consented cookies when consent is revoked
  • Granular Preferences -- per-category toggle dialog with detected cookie details
  • Emoji Status Indicator -- persistent button showing current state
  • Zero Dependencies -- lightweight, no runtime deps
  • TypeScript -- full type definitions included

Installation

npm install cookie-nom

Quick Start

import CookieNom from 'cookie-nom';

const cookieNom = new CookieNom({
  onConsentChange: (state, categories) => {
    console.log('Consent changed:', state, categories);
  }
});

cookieNom.init();

That's it. CookieNom will show a consent banner for first-time visitors and a small indicator for returning visitors.

Script Blocking

Tag third-party scripts with type="text/plain" and data-cookienom="<category>". CookieNom will only execute them once the matching category is consented to.

<!-- Blocked until analytics consent -->
<script type="text/plain" data-cookienom="analytics"
        src="https://www.googletagmanager.com/gtag/js?id=G-XXXXX"></script>

<!-- Blocked until marketing consent -->
<script type="text/plain" data-cookienom="marketing">
  fbq('init', '1234567890');
  fbq('track', 'PageView');
</script>

When consent is granted, CookieNom replaces the blocked script with an executable copy, preserving all attributes. It also watches for dynamically added scripts via MutationObserver.

Cookie Detection

CookieNom includes a built-in database of common cookie patterns:

| Category | Examples | |----------|----------| | Analytics | _ga, _gid, _hj*, mp_*, _pk_*, _clck | | Marketing | _fbp, _gcl_*, _ttp, _uet*, IDE, li_sugr | | Preferences | i18next, lang, locale, wp-settings-* |

You can add custom patterns:

import { CookieCategory } from 'cookie-nom';

cookieNom.addCookiePattern(/^myapp_track/, CookieCategory.ANALYTICS, 'MyApp Tracking');

Scan all cookies on the current page:

const cookies = cookieNom.scanCookies();
// [{ name: '_ga', category: 'analytics', service: 'Google Analytics', value: '...' }, ...]

Configuration

const cookieNom = new CookieNom({
  // Banner message
  message: 'We use cookies to improve your experience. Essential cookies are always active.',

  // Button labels (equal visual weight -- no dark patterns)
  acceptText: 'Accept All',    // default
  declineText: 'No Thanks',   // default

  // Position of the CookieCar
  position: 'bottom-left',    // 'bottom-left' | 'bottom-right' | 'bottom-center'

  // Auto-hide delay in ms (auto-hide = implicit decline)
  autoHideDelay: 30000,        // default: 30s

  // Cookie categories to manage
  categories: [
    CookieCategory.ESSENTIAL,
    CookieCategory.ANALYTICS,
    CookieCategory.MARKETING,
    CookieCategory.PREFERENCES
  ],

  // Name and expiry of the consent cookie itself
  cookieName: 'cookienom_consent',  // default
  cookieExpiry: 365,                 // days, default

  // Consent change callback
  onConsentChange: (state, categories) => {
    if (categories.includes(CookieCategory.ANALYTICS)) {
      // enable analytics
    }
  },

  // Additional CSS to inject
  customStyles: ''
});

API

Methods

| Method | Description | |--------|-------------| | init() | Initialize -- call when DOM is ready | | isCategoryAllowed(category) | Check if a category is currently allowed | | getState() | Get current state: 'pending', 'essentials_only', or 'accepted' | | getAllowedCategories() | Get array of currently allowed categories | | showPreferences() | Open the preferences dialog programmatically | | scanCookies() | Scan and categorize all cookies on the page | | addCookiePattern(pattern, category, service) | Register a custom cookie pattern | | reset() | Clear consent and re-show the banner | | destroy() | Remove all UI elements and stop script observation |

Enums

enum ConsentState {
  PENDING = 'pending',
  ESSENTIALS_ONLY = 'essentials_only',
  ACCEPTED = 'accepted'
}

enum CookieCategory {
  ESSENTIAL = 'essential',
  ANALYTICS = 'analytics',
  MARKETING = 'marketing',
  PREFERENCES = 'preferences'
}

Consent States

| Emoji | State | Meaning | |-------|-------|---------| | neutral | PENDING | No decision yet | | sleeping | ESSENTIALS_ONLY | Declined or auto-dismissed | | happy | ACCEPTED | Opted in to extras |

Accessibility

  • role="dialog" with aria-labelledby and aria-describedby
  • Keyboard navigation: Tab to cycle, Enter/Space to activate, Escape to decline
  • Focus trap in preferences dialog with focus restoration on close
  • aria-live="polite" for auto-dismiss countdown
  • Toggle switches use role="switch" with aria-checked
  • All animations respect prefers-reduced-motion: reduce
  • High-contrast LCARS colour palette

Design Principles

  1. No dark patterns -- accept and decline have equal visual weight
  2. Calm & kind -- non-intrusive, auto-hides gently if ignored
  3. Clear consent -- auto-hide = essentials only (no implicit acceptance)
  4. Always reversible -- persistent indicator lets users change their mind
  5. Neuro-inclusive -- low stimulation, soft motion, clear labels

Browser Support

Chrome/Edge 90+, Firefox 88+, Safari 14+, Opera 76+.

Development

npm install
npm run build    # compile to dist/
npm run dev      # watch mode
npm test         # run tests

License

MIT


Made with care, for humans.