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

afriref

v1.0.0

Published

Official TypeScript client for the afriref fleet: cited government reference data (rates, tax, wages, holidays, FX) for 137 countries, payable per call with x402

Downloads

164

Readme

afriref — TypeScript client

Cited government reference data, typed: central-bank policy rates, VAT, corporate and personal income tax, minimum wages, CPI, statutory interest, official central-bank FX fixes and public holidays across 137 countries.

Every value carries the official source URL it was verified against, the date it took effect, and the date we last re-checked it. Zero runtime dependencies.

npm install afriref

Start free — no key, no wallet, no signup

import { Afriref } from "afriref";

const c = new Afriref();                       // afriref.dev (Africa)
const hol = await c.holidays("za");            // free for every country, always
console.log(hol.value.length, hol.source.url);

One country per service is completely free — every series, including history and point-in-time. It is the real paid surface, so you can check our citations against the official sources before paying anything:

const c = new Afriref();
c.evaluationCountry;                           // "gh"
const vat = await c.series("gh", "vat");       // free
console.log(vat.value, vat.unit, vat.confidence, vat.source.url);
// 15 percent primary https://gra.gov.gh/...

| Service | Free country | | Service | Free country | |---|---|---|---|---| | afriref | 🇬🇭 GH | | usaref | 🇺🇸 US | | euroref | 🇩🇪 DE | | mearef | 🇦🇪 AE | | asiaref | 🇯🇵 JP | | ausref | 🇦🇺 AU | | latamref | 🇧🇷 BR | | | |

Pay per call with x402 — no account

This is the part a REST wrapper can't do. Wrap fetch once and paid calls settle themselves:

import { Afriref } from "afriref";
import { wrapFetchWithPayment } from "@x402/fetch";
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { base } from "viem/chains";

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const wallet  = createWalletClient({ account, chain: base, transport: http() });

const c = new Afriref({ fetch: wrapFetchWithPayment(fetch, wallet) });

const vat = await c.series("ng", "vat");   // 402 → sign → retry, transparently
console.log(vat.value, vat.source.url);

Prefer a card? Buy prepaid credit at https://afriref.dev/pricing and pass apiKeyone key works on all seven services, same balance:

const c = new Afriref({ brand: "euroref", apiKey: process.env.AFRIREF_KEY });

Three things this client models that a fetch wrapper gets wrong

1. A refusal is data, not a failure. When the service holds no honest answer it says so, with a reason, and does not charge you:

import { Refused } from "afriref";

try {
  await c.workingDays("ng", "2027-01-01", "2027-01-31");
} catch (e) {
  if (e instanceof Refused) {
    e.reason;      // "calendar_not_publishable_in_advance"
    e.permanent;   // true — do NOT queue a retry
  }
}

permanent: true means waiting can never help: some public holidays are confirmed by moon sighting days ahead, or gazetted annually, so the 2027 calendar will not appear later. A client that retries those forever is the failure mode this flag exists to prevent.

2. HTTP 402 is a price quote. Without payment, you get the exact terms:

import { PaymentRequired } from "afriref";

try {
  await c.series("ng", "vat");
} catch (e) {
  if (e instanceof PaymentRequired) {
    e.priceUsd;          // 0.001
    e.network;           // "eip155:8453"  (Base)
    e.payTo;             // "0x1F04..."
    e.amountBaseUnits;   // "1000" — settle with this, never the float
  }
}

3. The citation is the product. Value keeps the evidence typed:

const v = await c.series("gh", "corporate-tax");
v.value;            // the number
v.effective_from;   // when it took LEGAL effect — not when we published it
v.last_confirmed;   // when we last re-read the official source
v.source.url;       // the government document. Follow it and check us.
v.confidence;       // "primary" = read from the authority's own publication
v.stale;            // past its expected update cycle?

Point-in-time

const gb = new Afriref({ brand: "euroref" });
(await gb.series("gb", "corporate-tax", { asAt: "2020-06-30" })).value;  // 19
(await gb.series("gb", "corporate-tax")).value;                          // 25

Alerts — free to register

Reference values fail silently: a threshold that stood 17 years moves in one budget speech and every hard-coded copy is quietly wrong. We hash every cited source daily, so we know when a value changes.

const sub = await c.createAlert("https://your-app.example/hooks/refdata", [
  "za/vat-registration-threshold",
  "ke/*",
]);
sub.secret;   // store it — payloads are HMAC-SHA256 signed, shown once

Registering is free and your first deliveries are free; after that each delivery costs one API-key call.

Everything else

await c.catalog({ confidence: "primary" });  // only values with no recorded limitation
await c.history("gh", "vat");                // earlier values with effective ranges
await c.snapshot();                          // every series, one call
await c.vat("gh", 1000);                     // net / tax / gross incl. levies
await c.incomeTax("gh", 650_000);            // tax due + per-bracket workings
await c.wageCheck("gh", 5000, "monthly");    // at or above the statutory floor?
await c.settlementDate("za", "2026-03-02");  // T+n across statutory calendars
await c.provenance("gh", "vat");             // sha256 of the exact bytes we read
await c.status();                            // live state and rate limits

Notes

  • history() returning [] means "not established", not "never changed". Where we hold no verified start date for a prior period we publish nothing rather than inventing one.
  • Each service answers only for its own countries. A NotFound on a valid country code usually means right country, wrong brand.
  • Free discovery routes are rate limited; paid data routes are not.

Independent service, not affiliated with any government. Verify against the cited official source before legal or financial use.

Docs: https://afriref.dev/docs · Accuracy record: https://afriref.dev/accuracy