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

@zenuinebit/subscription-billing

v0.1.0

Published

Subscription billing periods, trials, proration for upgrades and cancellations, usage tiers, dunning dates and MRR.

Readme

@zenuinebit/subscription-billing

Subscription billing arithmetic: billing periods with trials, anniversary or calendar billing, proration for upgrades and cancellations, metered-usage tiers, retry dates after a failed payment, and MRR. Amounts are integers in minor units (see @zenuinebit/money); dates are "YYYY-MM-DD".

No plans or prices are built in, and no tax is added: apply tax to the invoice with @zenuinebit/tax. You store plans and subscriptions; this works out the figures.

import { billingPeriods, prorateChange, refundUnused, usageCharge, dunningSchedule, mrr } from "@zenuinebit/subscription-billing";

const plan = { id: "pro", amount: 100_000, interval: "month", trialDays: 14, setupFee: 50_000 };   // per seat, per month
const sub = { id: "s1", planId: "pro", startDate: "2025-03-01", quantity: 5 };

billingPeriods(sub, plan, { through: "2025-06-01" });
// [{ type: "trial", start: "2025-03-01", end: "2025-03-14", amount: 0 },
//  { type: "paid",  start: "2025-03-15", end: "2025-04-14", amount: 500_000, setupFee: 50_000 }, ...]

// Mid-period upgrade or seat change: credit the unused old price, charge the rest at the new one
prorateChange({ periodStart: "2025-04-01", periodEnd: "2025-04-30", changeDate: "2025-04-16", oldAmount: 100_000, newAmount: 250_000 });
// { remainingDays: 15, credit: 50_000, charge: 125_000, net: 75_000 }

refundUnused({ periodStart: "2025-04-01", periodEnd: "2025-04-30", amount: 90_000, lastServiceDate: "2025-04-20" });   // { unusedDays: 10, refund: 30_000 }

// Metered usage: graduated (each slice at its tier) or volume (all units at the tier reached)
usageCharge(6_000, [{ upTo: 1_000, unitPrice: 2 }, { upTo: 5_000, unitPrice: 1.5 }, { unitPrice: 1 }]);   // { amount: 9_000, slices: [...] }

dunningSchedule("2025-04-10", [1, 3, 7]);      // retry dates: 11, 13 and 17 April
mrr(subscriptions, plans, "2025-06-15");       // { mrr, arr, count } - yearly, quarterly and weekly plans normalised to a month

How it works

  • Anniversary billing (default): periods are billed in advance and count from the first paid day, so a 31 January start renews on 28 February and then 31 March again, with no drift. Weeks, months, quarters and years work, with intervalCount for "every 2 months".
  • Calendar billing (anchor: "calendar"): periods line up with calendar months, quarters or years, and the first is prorated by days (21 of 30 days, 46 of 91...). It is for one month, quarter or year at a time, not weeks.
  • Trials come first and cost nothing; the first paid period starts the day after. The setup fee goes on the first paid period.
  • Cancellation: endDate is the last day of service. By default the last period stays billed in full (it was billed in advance); pass prorateFinal: true to charge only the days used, or use refundUnused to refund them.
  • mrr leaves out subscriptions that have not started, have ended, or are still in a free trial (includeTrials: true counts them).

Not included: invoices and payment collection, coupons and discounts, mid-period quantity schedules, pausing, tax, and revenue recognition.