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

@lucerna-dev/gates-core

v0.0.1-alpha.1

Published

The Gates evaluation engine — pure functions over a compiled runtime document, no I/O, no platform APIs, no dependencies. It typechecks against a bare ES2022 lib, so it runs anywhere JavaScript does: Node, Bun, Deno, edge workers, browsers.

Downloads

72

Readme

@lucerna-dev/gates-core

The Gates evaluation engine — pure functions over a compiled runtime document, no I/O, no platform APIs, no dependencies. It typechecks against a bare ES2022 lib, so it runs anywhere JavaScript does: Node, Bun, Deno, edge workers, browsers.

Most apps never install this package directly. @lucerna-dev/gates-node downloads the runtime and evaluates with this engine in-process; @lucerna-dev/gates-browser receives decisions computed server-side by the same semantics. Reach for core when you are building your own provider (a custom transport, an offline harness, another platform SDK) and need the evaluation semantics without the plumbing.

Install

pnpm add @lucerna-dev/gates-core

Quickstart

import { evaluate, flagDecision, type GatesRuntime } from "@lucerna-dev/gates-core";

// A compiled runtime document. In production this comes from
// `GET /sdk/v1/gates/runtime` — @lucerna-dev/gates-node downloads and
// polls it for you.
const runtime: GatesRuntime = {
  schemaVersion: 1,
  environment: "production",
  generatedAt: "2026-07-15T00:00:00.000Z",
  kills: { payments: true },
  flags: {
    new_billing: {
      enabled: true,
      conditions: [],
      overrides: [],
      rollout: { percentage: 50, salt: "s_billing" },
    },
  },
  experiments: {},
  audiences: {},
};

const identity = { userId: "u_42", traits: { plan: "pro" } };

const decision = flagDecision(runtime, "new_billing", identity);
// { on: …, reason: "rollout" } — deterministic for this user and salt

const decisions = evaluate(runtime, identity);
// every kill, flag and experiment decision for one identity

This block runs verbatim in test/readme.test.ts — if it drifts from the package, the test suite fails.

API

| Export | What it does | | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | | evaluate(runtime, identity?) | Every decision for one identity — the SSR/bootstrap projection (GatesDecisions) | | flagDecision(runtime, key, identity?) | One flag's FlagDecision; undefined when the key is not in the runtime | | experimentAssignment(runtime, key, identity?) | One experiment's VariantAssignment; undefined for unknown keys | | killState(runtime, key) | Kill switch state — false means the guarded path is killed; undefined for unknown keys | | explainFlag(runtime, key, identity?) | The decision plus the rule-by-rule TraceStep trail that produced it | | explainExperiment(runtime, key, identity?) | The assignment plus the gate-by-gate trail | | evaluateFlag(flag, identity, trace?) | The flag evaluator itself, for callers that already hold a RuntimeFlag | | evaluateExperiment(experiment, audiences, identity, trace?) | The experiment evaluator itself | | bucket(salt, unitId) | The unit's bucket for a salt, in basis points [0, 10000) | | murmur3(input, seed?) | MurmurHash3 x86 32-bit over the UTF-8 bytes, as uint32 | | GATES_RUNTIME_SCHEMA_VERSION | The runtime schema this engine version understands (1) |

Runtime and decision types (GatesRuntime, GatesIdentity, FlagReason, AssignmentReason, …) are exported from src/runtime.ts and src/decisions.ts.

Guarantees & semantics

  • Pure and deterministic. Same runtime + same identity → same decisions, on every platform, forever. No I/O, no clocks, no randomness.
  • Bucketing is frozen: murmur3 (x86 32-bit) over ${salt}:${unitId}, basis points (hash % 10000), stored salts. Salts are authored server-side and carried in the runtime — renaming a key never reshuffles users.
  • Unknown rule elements fail safe. A gate carrying any rule this engine version doesn't recognize (condition operator, override kind) is answered whole with unsupported_rule — flag off, experiment unassigned. An engine never half-evaluates a document it doesn't fully understand. Unknown fields are ignored; a changed meaning requires a new schemaVersion, additions do not.
  • Flag precedence, first hit wins: environment master switch → overrides in stored order (by user id or email domain) → conditions (a conjunction — all must match) → percentage rollout, sticky by user id via the stored salt.
  • Experiment gates, in order: running → environment → audience → holdout → traffic → allocation-weighted variant walk. The salt is per iteration — restarting an iteration reshuffles every bucket by design.
  • Partial allocation needs a userId. A rollout strictly between 0 and 100 — or any experiment — with no user id answers missing_user_id (off / unassigned): there is nothing to be sticky by.
  • The golden vectors are the compatibility contract. src/vectors.json freezes (runtime, identity) → decisions and is append-only; every Lucerna SDK in every language and the API's CI replay it bit-for-bit. A vector failure is a breaking change by definition.

Errors & failure modes

Nothing here throws in normal operation. Read helpers return undefined for keys not in the runtime — the platform SDK on top owns what to serve then (fail-open defaults live in the shells, not the engine). evaluate answers every key in the document; it never performs I/O and never rejects.