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

@beinfi/nextjs

v0.9.2

Published

Infi building blocks for Next.js — drop-in App Router handlers for hosted auth and usage metering.

Readme

@beinfi/nextjs

Drop-in Next.js App Router handlers for Infi. Each block is one line — export it from a route and the capability is wired.

npm install @beinfi/nextjs @beinfi/sdk

Env:

INFI_SECRET_KEY=sk_test_...      # server-side secret key
INFI_APP_SLUG=your-app           # app slug the hosted login is scoped to
# optional
INFI_API_URL=https://api.beinfi.com
INFI_AUTH_BASE_URL=https://auth.beinfi.com

Identity

Beinfi does not handle login — bring your own auth. Every handler here takes a resolveCustomerId so you stamp your authed user onto the call:

resolveCustomerId: async (req) => (await mySession(req)).enrollmentId,

Usage metering

Ingest events server-side (single event or { events: [...] }). Never ingest from the browser.

// app/api/usage/route.ts
import { Usage } from "@beinfi/nextjs";

export const POST = Usage({
  secretKey: process.env.INFI_SECRET_KEY!,
  // stamp the authed customer onto every event
  resolveCustomerId: async (req) => (await mySession(req)).enrollmentId,
});

Metered LLM routes

Gate a credit-consuming route: withMeter checks the customer's credit, runs your handler, records its usage, and returns the handler's data as JSON. Out of credit → 402 before the handler runs (never do the work for free); unresolved customer → 400. Server-side only.

Your handler returns the JSON-serializable result (e.g. the model response); withMeter auto-detects the token usage from it (OpenAI/Anthropic/AI-SDK shapes, or set value/extract). The resolved id is passed to your handler as the second arg ({ customerId }) so you don't re-resolve the session.

// app/api/chat/route.ts
import { withMeter } from "@beinfi/nextjs";

export const POST = withMeter(
  {
    secretKey: process.env.INFI_SECRET_KEY!,
    meter: "tokens",
    resolveCustomerId: async (req) => (await mySession(req)).enrollmentId,
  },
  async (req, { customerId }) => {
    const { messages } = await req.json();
    return openai.chat.completions.create({ model: "gpt-4o", messages });
  },
);

mode selects the billing behavior (default "prepaid" = gate + record): "postpaid" records without gating (metered API / rate-card — replaces skipGuard), "streaming" gates but doesn't record (record later yourself). Flat/per-unit metering: set value: 1.

Return a Response or throw MeterAbort. If your handler returns a Response/NextResponse it is passed through untouched (usage recorded only on 2xx, and only when value/extract is set — an opaque/streamed body can't be auto-detected). For a business error (bad input), throw new MeterAbort(status, body)withMeter returns NextResponse.json(body, { status }) and records nothing, so validation failures stop surfacing as generic 500s.

Metering outside a route (Server Actions)

withMeter wraps a route handler. For a Next.js Server Action (or any non-route code), use meterAction (wraps the action — gates, runs, records, returns the action's plain value) or the bare guardCredit gate:

"use server";
import { meterAction, guardCredit } from "@beinfi/nextjs";

// wrap the whole action
export const createLead = meterAction(
  { secretKey: process.env.INFI_SECRET_KEY!, meter: "leads", value: 1, mode: "postpaid",
    customerId: /* resolved from the session */ enrollmentId },
  async (input: LeadInput) => db.lead.create({ data: input }),
);

// or just gate at the top of an existing action
export async function generate(input: Input) {
  await guardCredit({ secretKey: process.env.INFI_SECRET_KEY!, customerId: enrollmentId });
  // ...do the work
}

Customer state route

State mirrors Usage — a drop-in GET that returns infi.customers.state(id) as JSON, so a client (or a non-Next app) can read a customer's balance/usage without hand-rolling a proxy:

// app/api/state/route.ts
import { State } from "@beinfi/nextjs";

export const GET = State({
  secretKey: process.env.INFI_SECRET_KEY!,
  resolveCustomerId: async (req) => (await mySession(req)).enrollmentId,
});

Options

UsagesecretKey, baseUrl?, resolveCustomerId?.

StatesecretKey, baseUrl?, resolveCustomerId.

withMetersecretKey, meter, resolveCustomerId, mode? ("prepaid" | "postpaid" | "streaming"), value?, extract?, skipGuard? (deprecated → mode), metadata?, baseUrl?, onMissingCustomer? (default 400), onInsufficientCredit? (default 402). Handler receives (req, { customerId }); return a Response to pass through, throw MeterAbort(status, body) for business errors.

meterActionsecretKey, customerId, meter, mode?, value?, extract?, metadata?, baseUrl?. guardCredit{ secretKey, customerId, baseUrl? }.