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

@posterna/core

v0.1.3

Published

Verify AI agents and crawlers inside your own process: verifier, policy engine and counters client.

Readme

@posterna/core

An early release (0.1). The API may change before 1.0, and every change is in the changelog.

The core of Posterna: the verifier behind verify() and the policy engine behind decide(). It checks which AI agents and crawlers are calling your site, using HTTP message signatures (RFC 9421, Web Bot Auth), published IP ranges and forward-confirmed reverse DNS, and gives every request one of six verdicts. It runs in your own process, never sends request data anywhere, and fails open on every error.

Most apps use an adapter instead: @posterna/express or @posterna/next.

import { createVerifier, stripInboundHeaders, verdictHeaders } from "@posterna/core";

const verifier = createVerifier({ trustedProxies: ["10.0.0.0/8"], publicHost: "www.example.com" });

// Fetch API: pass the TCP peer, which a Request does not carry.
const result = await verifier.verify(request, { remoteAddress });
// { verdict: "verified_by_ip", operator: "google", agent: "Googlebot", purpose: "search", method: "ip" }
  • createVerifier(options) returns a verifier with its own directory copy, refresh timers, nonce cache and reverse DNS cache. verify(request, options) uses a shared default one.
  • verify() accepts a Fetch API Request or a Node IncomingMessage, never throws, and never waits on the network.
  • stripInboundHeaders(headers) removes client-sent X-Agent-* and X-Posterna-* headers; adapters call it first. verdictHeaders(result) gives the headers to pass to the application.
  • verifier.state() reports readiness, the proxy guard, error counts and directory versions, for counters and the debug route.

Policy

The policy engine turns a verdict into a decision from the site's agents.yaml (allow, block or throttle for pages and APIs; lift, cap or challenge recommendations for sign-up pages), with safety rails that keep verified search engines reachable and stop enforcement when something looks misconfigured. Templates start in monitor mode, so nothing is blocked until the file says mode: enforce.

import { createPolicyEngine, enforcementResponse } from "@posterna/core";

const engine = createPolicyEngine(readFileSync("agents.yaml", "utf8"), { verifier });
const decision = engine.decide(result, { path: url.pathname });
// { action: "block", enforced: true, rule: "purposes.training", reason: "purposes.training: block." }
const response = enforcementResponse(decision, result); // null means let the request through
  • createPolicyEngine(policy, options) takes agents.yaml text or a parsed policy and throws PolicyError (every error, with line numbers) when it is invalid. checkPolicy(text) validates without throwing.
  • engine.decide(result, { path, kind }) never throws. engine.setRemoteOverride("monitor" | null) applies the cloud's kill switch, which can never turn enforcement on. engine.state() reports mode, suspensions, tripped breakers, guarded and error counts and the policy hash.
  • emitRobots(policy, operators) writes robots.txt and Content Signals from the policy.
  • Templates: @posterna/core/templates/monitor.yaml, allow-list.yaml, saas-signup.yaml.

The full reference is docs/policy.md.

Counters

createCounters({ sdk, source: engine }) aggregates requests by hour, verdict, reason code, operator, agent, purpose, path group, action and enforced. With a site key (POSTERNA_SITE_KEY) it sends them to the Posterna cloud every 60 seconds and on exit, and applies the cloud's monitor override to the engine. Without one it sends nothing. Recording never blocks or slows a request, and no address, URL or header value is ever kept or sent. The adapters set this up for you.

Signatures are verified with Cloudflare's web-bot-auth packages. The operator directory snapshot comes from @posterna/directory and is refreshed in the background from posterna.com when signed directory files are available.

The JSON Schemas for directory.json, keys.json and agents.yaml ship with the package: @posterna/core/schema/directory.schema.json, keys.schema.json and agents.schema.json.

See the specification, sections 4 and 5. MIT licensed.