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

invoicing-kit

v0.16.0

Published

Drop-in invoicing API for Hono + better-auth apps: clients, products, taxes, quotes, invoices, and payments.

Readme

invoicing-kit

npm version license

Drop-in invoicing API for Hono apps using better-auth. Mount one router and get organization-scoped clients, products, taxes, payment methods, quotes, invoices, and payments — backed by Prisma (or your own repository implementation).

Features

  • One-line mountapp.route("/", kit.router) adds the full REST surface.
  • Organization-scoped — every resource is isolated per better-auth organization.
  • Quotes → invoices — convert an accepted quote into an invoice in one call.
  • Payments — record manual payments and track invoice paid / partially-paid state.
  • Catalog by reference — link line items to your own domain objects (an experience, course, plan…) and the kit find-or-creates the backing product.
  • Money-safe — amounts are integer minor units, rates/quantities are decimal strings; no floats cross the boundary.
  • Pluggable storage — ships a Prisma adapter and an in-memory test adapter; bring your own by implementing the repository interfaces.
  • Typed & validated — Zod schemas on every route, OpenAPI metadata included.

Install

bun add invoicing-kit
# peer deps:
bun add @prisma/client better-auth hono @hono/zod-openapi zod

Quick start

import { createInvoicingKit, prismaAdapter } from "invoicing-kit";
import { Hono } from "hono";
import { PrismaClient } from "@prisma/client";
import { auth } from "./auth"; // your better-auth instance with the organization plugin

const prisma = new PrismaClient();

const kit = createInvoicingKit({
  adapter: prismaAdapter(prisma),
  auth,
  basePath: "/api/bills", // default: "/api/bills"
});

const app = new Hono();
app.route("/", kit.router);
app.route("/api/auth", auth.handler); // your own better-auth mount

export default app;

Configuration

createInvoicingKit(config) accepts:

| Option | Type | Description | | ---------- | -------------- | --------------------------------------------------------- | | adapter | Repositories | Storage backend. Use prismaAdapter(prisma) or your own. | | auth | better-auth | Instance with the organization plugin enabled. | | basePath | string | Mount path for the router. Default "/api/bills". |

It returns { router, services, repos } — mount router, or call services / repos directly for server-side work.

Routes

Mounted under basePath:

| Resource | Routes | | --------------- | ------------------------------------------------------------------- | | Clients | POST/GET/GET/PATCH/DELETE /clients[/:id] | | Products | POST/GET/GET/PATCH/DELETE /products[/:id] | | Taxes | POST/GET/GET/PATCH/DELETE /taxes[/:id] | | Payment methods | POST/GET/GET/PATCH/DELETE /payment-methods[/:id] | | Quotes | POST/GET/GET/PATCH/DELETE /quotes[/:id] | | Invoices | POST/GET/GET/PATCH/DELETE /invoices[/:id] | | Convert | POST /invoices/from-quote/:quoteId | | Payments | POST/GET /invoices/:invoiceId/payments, GET/DELETE /payments/:id |

Money units

Values cross the API boundary as strings to avoid floating-point drift:

  • Amounts (price, amount, invoice totals) — integer minor units (cents), e.g. "5000" for $50.00.
  • Rates / quantities — canonical decimal strings, e.g. "1.5", "18".

Your application converts to/from display units at its own edge.

Payment methods & providers

A payment method's type and a payment's provider are free-form strings — "STRIPE", "MANUAL", and "AZUL" are the conventional values, but any gateway string is accepted, so you can support regional providers without a library change. Constrain the set in your own app if you need to.

Linking products to your domain objects

A line item normally references an existing product by productId. It can instead reference one of your own domain objects (an experience, course, plan, …) via source, and the kit find-or-creates the backing product for you — keyed on (organization, sourceType, sourceId):

// reference a product directly
{ "productId": "…", "quantity": "1", "price": "5000", "taxIds": [] }

// reference your own object; product is created on first use
{ "source": { "type": "experience", "id": "42", "name": "Sunset Tour" },
  "quantity": "2", "price": "5000", "taxIds": [] }

Provide exactly one of productId / source. The product is created once (price defaults from the line item's minor units) and reused on later sales; the line item still carries its own price / description, so it remains the immutable snapshot of the sale. Product exposes the same sourceType / sourceId on create and read for catalog lookups.

Documents are single-currency: every line item's product must be denominated in the document's currency (compared case-insensitively; stored lowercase). Auto-created source products inherit the document currency; referencing a product priced in another currency fails with 422 LINE_ITEM_CURRENCY_MISMATCH. Each line item also records a currency snapshot, and products accept an optional currency (ISO 4217, default usd) on create/update.

Sale vs. purchase products

Each product carries a usage of SALE, PURCHASE, or BOTH (default BOTH) — which side of the ledger it may appear on. Sales documents (invoices, quotes, credit notes) accept SALE/BOTH products; purchase documents (vendor bills, debit notes) accept PURCHASE/BOTH. Referencing a product whose usage excludes the document's side fails with 422 PRODUCT_NOT_SELLABLE or 422 PRODUCT_NOT_PURCHASABLE. A product created from a source line inherits the side it was first used on. List with ?usage=SALE / ?usage=PURCHASE to fetch only the products valid for a side (the filter returns that side plus BOTH). Products also accept an optional cost (purchase unit price, decimal) independent of the sale price.

Testing

The invoicing-kit/testing entry point exports an in-memory adapter so you can exercise the full router without a database:

import { createInvoicingKit } from "invoicing-kit";
import { inMemoryAdapter } from "invoicing-kit/testing";

const kit = createInvoicingKit({ adapter: inMemoryAdapter(), auth, basePath: "/api/bills" });

License

MIT © Bitzer AI