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

@agentoria/paykit

v0.4.0

Published

A framework-agnostic, storage-agnostic payment toolkit — one PaymentProvider port with Stripe, 虎皮椒 (xunhupay), and manual adapters, currency/region routing, an idempotent order state machine, and receipts. Runs on Node, Cloudflare Workers, Deno, and Bun.

Readme

paykit

A framework-agnostic, storage-agnostic payment toolkit — one PaymentProvider port with Stripe, 虎皮椒 (xunhupay), and manual adapters, currency/region routing, an idempotent order state machine, and receipts. It runs unchanged on Node 18+, Cloudflare Workers, Deno, and Bun because it uses only Web-standard APIs (fetch, Web Crypto, Request/Response).

Take a payment (China + overseas), record an order, settle a webhook idempotently, issue a receipt — without wiring it up from scratch in every project.

Install

npm install @agentoria/paykit

Quick start

Wire a store, the providers you've configured, and a onPaid hook — that's it. paykit records the money; your onPaid applies its meaning (grant a plan, add credits, ship the thing).

import { PaymentGateway } from "@agentoria/paykit";
import { manualProvider } from "@agentoria/paykit/providers/manual";
import { MemoryOrderStore } from "@agentoria/paykit/stores/memory";

const gateway = new PaymentGateway({
  store: new MemoryOrderStore(),          // or @agentoria/paykit/stores/d1 | /sqlite | /postgres
  providers: [manualProvider],            // add stripe / xunhupay / router
  env: process.env,                       // providers read STRIPE_* / XUNHUPAY_* here
  hooks: {
    async onPaid(order) {
      // fires exactly once per order, even under duplicate webhooks
      await grantPlan(order.buyerId, order.item.sku);
    },
  },
});

// 1) open an order + start payment
const checkout = await gateway.checkout(
  { buyer: { id: "u1", email: "[email protected]" }, item: { sku: "pro", label: "Pro — Yearly" }, amount: { amount: 1999, currency: "USD" } },
  { baseUrl: "https://app.example.com" },
);
// → { orderId, orderNo, provider, redirectUrl? | qrCode? | manual? }

// 2) settle the gateway's webhook (idempotent; verifies signature + amount)
const res = await gateway.handleWebhook("stripe", request);
return new Response(res.ack, { status: res.ok ? 200 : 400 });

Design

  • One port, many gateways. A PaymentProvider implements configured / createCheckout / parseWebhook / refund?. Adding a channel is a new file + one registry entry.
  • Storage-agnostic. Every persistence port (OrderStore, CouponStore, InvoiceStore, AnomalyStore, OrderEventLog) ships an in-memory adapter plus SQL-backed adapters over a tiny SqlDriver — @agentoria/paykit/stores/d1 and @agentoria/paykit/stores/sqlite (d1CouponStore(env.DB), sqliteInvoiceStore(db), …). Bring any DB by implementing three methods; create every table in one idempotent call — d1MigrateAll(env.DB) / sqliteMigrateAll(db) (or migrateAll(driver)) — or ship the exported *_SCHEMA.
  • Idempotent settlement. The order state machine (pending → paid | canceled | expired, paid → refunded) is guarded at the store, so a webhook delivered twice settles once and onPaid fires once.
  • Region routing. A router meta-provider sends CNY → 虎皮椒 (WeChat/Alipay) and everything else → Stripe, so one deployment serves mainland China and overseas at once.
  • Hooks, not coupling. paykit never touches your users/plans tables — it calls onPaid / onRefunded and hands you the order.

Money

Amounts are always integers in a currency's minor units (1999 = $19.99) + an ISO-4217 code. Never floats — what you charge always equals what you record. money(19.99, "USD") and formatMoney({ amount: 1999, currency: "USD" }) help at the edges.

Roadmap

paykit is built in tiers; subpaths land as each ships.

  • Tier 0 — core ✅  PaymentGateway, order state machine, PaymentProvider + OrderStore ports, manual provider, in-memory store, hooks, Web-Crypto helpers.
  • Tier 1 — providers + routing ✅  stripe + xunhupay (虎皮椒) providers (real HMAC/MD5 webhook verification + refunds), currency/region router (CNY → 虎皮椒 / else → Stripe), a portable MD5, and SQL stores (sql + d1 + sqlite).
  • Tier 2 — framework glue + receipts ✅  a one-line hono mount — billingRoutes (config / checkout / orders / webhooks) or the fuller createBillingRouter, which adds an opt-in block per store you pass (receipts + scan-verify, coupon preview + admin CRUD, invoice request + admin resolve/issue, anomaly reconcile), each /admin/* route gated by your isAdmin — plus a framework-neutral webhook handler and a framework-neutral core router (@agentoria/paykit/web — createBillingHandler, a (Request) => Response | null covering config / checkout / orders / cancel / mock-pay / webhook, for a catch-all route in Astro / Next / Deno / Bun without pulling in hono); receipts (@agentoria/paykit/receipts) — issue from a paid order, merchant config, self-contained HTML, HMAC verify token; and a one-page A4 PDF renderer (@agentoria/paykit/receipt-pdf) with a verify QR + SHA-256 fingerprint — pdf-lib/qrcode are optional peer deps and the CJK font is caller-supplied, so the core stays dependency-free.
  • Tier 3 — billing  🚧  Coinbase (crypto) provider (@agentoria/paykit/providers/coinbase) ✅, discount coupons (@agentoria/paykit/coupons — pure pricing + a CouponStore port) ✅, upgrade proration (@agentoria/paykit/prorate) ✅, tax-invoice requests + issue seam (@agentoria/paykit/invoices) ✅, and SQL adapters for the coupon + invoice stores (SqlCouponStore / SqlInvoiceStore over d1 + sqlite) ✅. Still to come: subscriptions + renewal, a postgres store.
  • Tier 4 — ops  🚧  order-lifecycle audit log (@agentoria/paykit/order-events) ✅, payment-anomaly queue (@agentoria/paykit/anomalies) ✅, revenue rollup (@agentoria/paykit/metrics — summarizeOrders) ✅, and SQL adapters for the anomaly log + order-event log (SqlAnomalyStore / SqlOrderEventLog) ✅. Still to come: admin/finance helpers, docs + examples.
  • Tier 5 — client + UI  🚧  a framework-agnostic @agentoria/paykit/client (a typed fetch wrapper over the mounted router — checkout, orders, coupon preview, receipt verify, invoices, admin) ✅, and headless @agentoria/paykit/react hooks (useCheckout / useOrders / useCouponPreview / useCoupons) with react as an optional peer dep ✅. Still to come: styled default components, more framework bindings.

License

MIT © WangYihang