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

@ferrow/feature-flags

v2.0.0

Published

Deterministic feature flag evaluation engine: boolean flags, percentage rollout via consistent hashing, attribute targeting rules (eq/in/gt/lt), environment overrides, and a pluggable async store.

Readme

feature-flags

CI

A deterministic feature flag evaluation engine. Boolean flags, percentage rollouts via consistent hashing, attribute-based targeting rules, per-environment overrides, and a pluggable async store — with zero runtime dependencies.

Deterministic means what it sounds like: the same flag key + user id + attributes always evaluates to the same result, every time, on every process — no coin flips, no per-request randomness.

Install

npm install feature-flags

Quickstart

import { FeatureFlagEngine, InMemoryStore } from "feature-flags";

const engine = new FeatureFlagEngine(new InMemoryStore());

await engine.setFlag({
  key: "new-checkout",
  defaultValue: false,
  rolloutPercentage: 30, // ~30% of users, stably bucketed
});

const enabled = await engine.isEnabled("new-checkout", { userId: "user-42" });

API

new FeatureFlagEngine(store: FlagStore)

  • setFlag(definition: FlagDefinition): Promise<void>
  • removeFlag(flagKey: string): Promise<void>
  • listFlags(): Promise<FlagDefinition[]>
  • evaluate(flagKey: string, ctx: EvaluationContext): Promise<EvaluationResult>
  • isEnabled(flagKey: string, ctx: EvaluationContext): Promise<boolean> — convenience wrapper around evaluate.

FlagDefinition

interface FlagDefinition {
  key: string;
  defaultValue: boolean;
  rules?: TargetingRule[];                      // evaluated in order, first match wins
  rolloutPercentage?: number;                    // 0-100
  environmentOverrides?: Record<string, boolean>;
}

interface TargetingRule {
  attribute: string;             // read from ctx.attributes
  operator: "eq" | "in" | "gt" | "lt";
  value: unknown;                // array for "in", scalar otherwise
  serve: boolean;
}

Evaluation order

  1. environmentOverrides[ctx.environment], if set and present.
  2. rules, in array order — first matching rule wins.
  3. rolloutPercentage, via consistent hashing (see below).
  4. defaultValue.

EvaluationResult.reason tells you which of these decided the outcome ("environment_override" | "rule_match" | "rollout" | "default" | "flag_not_found").

FlagStore (pluggable)

interface FlagStore {
  get(flagKey: string): Promise<FlagDefinition | undefined>;
  set(flagKey: string, definition: FlagDefinition): Promise<void>;
  delete(flagKey: string): Promise<void>;
  list(): Promise<FlagDefinition[]>;
}

InMemoryStore is bundled. Implement the interface yourself for Postgres/Redis/a config file/whatever you already have.

fnv1a / bucketOf

Exported for testing or building your own rollout logic: bucketOf(flagKey, userId) returns a stable integer in [0, 10000) derived from FNV-1a of "${flagKey}:${userId}".

Design notes

Rollout uses FNV-1a hashing rather than Math.random() specifically so the same user always lands in the same bucket for a given flag — that's what makes a "30% rollout" actually mean something across page loads, servers, and days, instead of re-flipping a coin every evaluation. The store is an interface, not a bundled database client, because flag state belongs wherever the rest of your app's config already lives; shipping our own Postgres/Redis dependency would mean forcing infrastructure choices on you that have nothing to do with flag evaluation logic.


Sponsored by Ferrow


Part of the ferrow-toolkit collection · Sponsored by Ferrow