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

@naulon/enforce

v0.2.0

Published

Runtime-agnostic naulon toll-decision kernel + in-app enforcement middleware. The neutral low-level core shared by @naulon/tollgate (the gate) and @naulon/sdk (the publisher SDK) — no dependency cycle.

Readme

@naulon/enforce

The runtime-agnostic toll-decision kernel plus the in-app enforcement middleware.

This is the neutral low-level core that both @naulon/tollgate (the gate shell — the reverse-proxy that boots createApp) and @naulon/sdk (the publisher SDK) sit above, with no dependency cycle. It depends only on @naulon/shared (and viem, for the holder-of-key proof). The heavy settlement path — the Circle facilitator, the pending-leg drain — stays in @naulon/tollgate; nothing here imports @circle-fin/x402-batching.

Why it exists

decide() is one pure function: given a web Request and a known publisher, it returns a verdict — serve free, refuse, or 402 with the payment legs — and performs no side effects (no proxy, no settle, no observe). Extracting it lets two very different runtimes reach the same verdict:

  • The gate (@naulon/tollgate) runs decide() inside its Hono reverse proxy.
  • In-app middleware runs the identical decide() in the publisher's own app, so an agent's request reaches the origin directly instead of routing through the fleet's single egress IP (which an origin edge can rate-limit).

Both build a byte-identical 402, because they share this code.

Exports

@naulon/enforce

The decision kernel and the framework-agnostic middleware core:

  • decide(input) — the pure verdict function.
  • naulonMiddleware(opts) — takes a Request, returns { response, setHeaders }: a Response to short-circuit (402/403), or null to let the app render (with setHeaders to attach to the app's response on a paid pass).
  • withNaulon(handler, opts) — wrap a generic fetch handler.
  • localQuoteSource(fn) / httpQuoteSource(url, key) — pluggable price + payees.
  • The classification, Web Bot Auth, nonce, and proof primitives (classify, verifyBotAuth, …) and the x402 build side (build402, buildRequirements).
  • Cloudflare pay-per-crawl interop — formatCrawlerPrice, parseCrawlerPrice, declaredCrawlerBudget, crawlerBudgetVerdict, totalChargedMicro, and the four header constants (crawler-max-price / crawler-exact-price on the request, crawler-price on a 402, crawler-charged on a paid 200). A crawler already fluent in that vocabulary can price your origin with no change on its side. You advertise in their vocabulary and settle in ours — x402/USDC, buyer→author — so nothing here moves money or changes who is charged. Prices render at full precision rather than Cloudflare's USD XX.XX: a citation toll is often sub-cent, and (0.001).toFixed(2) would advertise a free read. It lives here rather than in tollgate so a self-hosting publisher on the SDK gets it too.

@naulon/enforce/next

  • createNaulonMiddleware(opts, NextResponse) — the Next.js App Router adapter. It has no hard next dependency; you inject NextResponse (your app already has it), keeping the core framework-agnostic.

Usage

// middleware.ts (Next.js App Router)
import { NextResponse } from "next/server";
import { createNaulonMiddleware } from "@naulon/enforce/next";
import { httpQuoteSource } from "@naulon/enforce";

export const middleware = createNaulonMiddleware(
  {
    publisher: { id: "your-site", articlePrefixes: ["articles"] },
    quote: httpQuoteSource("https://<your-control-plane>/_naulon/quote", process.env.NAULON_API_KEY!),
    verifyUrl: "https://<your-control-plane>/_naulon/verify",
    apiKey: process.env.NAULON_API_KEY!,
  },
  NextResponse,
);

export const config = { matcher: ["/articles/:path*"] };

quote and verifyUrl point at whatever runs the money + catalog legs — the managed control plane, or your own self-hosted POST /_naulon/verify + GET /_naulon/quote. The middleware never holds funds: it forwards the buyer's signed payment to verifyUrl, which settles buyer → author directly.

Layering

Arrows point to what a package depends on:

flowchart TD
    tollgate["@naulon/tollgate<br/><i>gate shell — runs decide() in its reverse proxy</i>"] --> enforce
    enforce["@naulon/enforce<br/><i>this package — decision kernel + middleware</i>"] --> shared["@naulon/shared"]

A publisher vendors @naulon/enforce directly (it builds to its own dist/ tarball) and wires the middleware; the gate consumes the very same package, which is what guarantees both reach an identical verdict. @naulon/enforce is deliberately NOT re-exported through @naulon/sdk@naulon/shared imports the SDK and re-exports it, so an sdk → enforce edge would close the loop sdk → enforce → shared → sdk, a declaration-build cycle. Keeping enforce standalone (a second, small dependency alongside the SDK) avoids that and keeps the package graph a clean chain.