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

@particle-academy/fancy-features

v0.1.1

Published

Headless, zero-dependency feature-management engine (boolean + metered-resource gating, feature groups, quota usage). The Node/TypeScript mirror of the PHP particle-academy/laravel-fms — and the owner of the shared feature contract consumed by @particle-a

Downloads

649

Readme

@particle-academy/fancy-features

Fancy UI suite

Headless, zero-dependency feature-management engine — boolean flags + metered-resource gating, feature groups (with extends, overrides, and callable gates), and quota usage tracking. The Node/TypeScript mirror of the PHP particle-academy/laravel-fms — same resolution semantics, no Laravel/Eloquent. It also owns the shared feature contract consumed by @particle-academy/fancy-catalog.

import { createFeatures } from "@particle-academy/fancy-features";

const features = createFeatures({
  features: {
    "use-mcp": { type: "boolean", enabled: true },
    "ai-tokens": { type: "resource", limit: 10_000 },
  },
  groups: [
    { key: "pro-plan", features: ["use-mcp", "ai-tokens"], overrides: { "ai-tokens": { limit: 50_000 } } },
  ],
});

await features.canAccess("use-mcp", user); // true
await features.remaining("ai-tokens", user); // 10000 − usage

// Group assignment lifts the cap (MAX wins):
features.groupStore.assign(user, "pro-plan");
await features.remaining("ai-tokens", user); // 50000 − usage

Resolution order

pre-strategies → gate → registry → groups (OR) → config → sources → default deny

  • pre-strategiesregisterPreStrategy(name, (feature, subject, context) => boolean | null); first non-null wins (authoritative). registerPreRemainingStrategy is the number | null analog for remaining().
  • gate — an injected gate(feature, subject, context) => boolean | null; a boolean is authoritative (can deny even when later sources would allow).
  • registry / config — programmatic + config-map feature definitions; enabled/check evaluated.
  • groups — the subject's assigned groups (GroupStore) plus callable-gated groups, OR'd; group overrides raise resource limits (MAX wins).
  • sourcesFeatureSource[] resolve FeatureGrant[]; a grant with enabled:true turns the feature on. This is where fancy-catalog plugs in.
  • resource remainingMAX(group/source limit, feature.limit) − UsageStore.getUsage, clamped ≥0; null ⇒ unlimited.

API

createFeatures(opts) / new FeatureManager(opts):

  • canAccess(key, subject?, context?)Promise<boolean> (isEnabled / hasFeature are aliases)
  • remaining(key, subject?, context?)Promise<number | null> (null = unlimited)
  • enabled(subject?, context?)Promise<string[]> (all enabled keys)
  • explain(key, subject?, context?)Promise<AccessResult> ({ allowed, source, remaining?, limit?, used? })
  • registerPreStrategy / registerPreRemainingStrategy
  • registerSource(FeatureSource) · registerFeature(key, def) · registerGroup(group)
  • Quota helpers: increment · decrement · tryConsume (atomic) · usageFor · resetPeriod

RegistryFeatureRegistry: array | factory fn | class-with-definition().

GroupsFeatureGroupRegistry (resolvedFeatures, resolvedOverrides, groupsContaining, 1-level extends with cycle detection) + GroupStore (in-memory InMemoryGroupStore default).

UsageUsageStore (in-memory InMemoryUsageStore default).

GuardrequireFeature(manager, keys, subject?) (OR logic, throws FeatureAccessDeniedError) + canAccessAny predicate + requireFeatureMiddleware (generic (req,res,next), no express dependency).

Helpersfeature(), canAccessFeature(), hasFeature(), featureRemaining(), enabledFeatures() bound to a default instance via setDefaultFeatures / configureFeatures.

The shared contract

Exported verbatim from the barrel and mirrored structurally by fancy-catalog's ./features subpath: FeatureType, Subject, BillingPeriod, FeatureGrant, FeatureSource, UsageStore, AccessResult, Feature, FeatureGroup. A FeatureSource built in catalog is assignable here with no build-time dependency between the two packages.

import { createCatalogFeatureSource } from "@particle-academy/fancy-catalog/features";

const features = createFeatures({
  sources: [createCatalogFeatureSource(catalog, { resolveSubscription })],
});
await features.canAccess("use-mcp", user); // resolves via the user's subscription's product features

⭐ Star Fancy UI

If this package is useful to you, a quick ⭐ on the repo really helps us build a better kit. Thank you!