@absolutejs/billing

中文文档
0.19.0发布于 2026/11/05BSL-1.1TypeScriptES Module近 30 天下载 2904

Provider-neutral pricing and invoice computation used by the hosted AbsoluteJS.ai platform. Converts metered usage into exact integer-micro line items with tiers and allowances.

原始使用文档
文档目录10 节
  1. Pricing shapes
  2. Why pure?
  3. License
  4. Prepaid service credits
  5. Secure credit checkout
  6. Deferred progress
  7. Uncapped embedding plans and application budgets
  8. Provider admission
  9. Usage attribution
  10. Paid execution policy

@absolutejs/billing

Provider-neutral pricing and invoice computation used by the hosted AbsoluteJS.ai platform.

@absolutejs/billing is the pure-function layer between @absolutejs/metering (which collects usage events) and an invoicing backend (Stripe, QuickBooks, an internal billing engine).

It does two things:

  1. createPlan(...) — declares a priced product: optional flat base fee, per-dimension unit prices, optional graduated tiers, optional per-dimension free allowances.
  2. computeInvoice({ plan, period, tenant, usage }) — pure function that turns a Usage snapshot into an Invoice with line items and a total.

All money math is done in integer micros (1 micro = 1/1,000,000 of a currency unit — the same denomination Stripe stores prices in internally). Float drift is structurally impossible: a $0.0002 per-request price is 200 and rounding policy is explicit.

import { createPlan, computeInvoice, formatMicros } from "@absolutejs/billing";

const plan = createPlan({
  name: "pro",
  currency: "usd",
  basePriceMicros: 20_000_000, // $20/mo
  pricedDimensions: {
    requests: { perUnitMicros: 200, freeTier: 1_000_000 },
    cpuMs: { perUnitMicros: 50, unit: 1000, freeTier: 60_000 * 60 * 10 },
    bytesEgress: {
      perUnitMicros: 100,
      unit: 1024 * 1024,
      freeTier: 100 * 1024 * 1024,
    },
    hibernationGbSeconds: { perUnitMicros: 5 },
  },
});

const invoice = computeInvoice({
  plan,
  tenant: "acme",
  period: { start, end },
  usage, // a Usage from @absolutejs/metering
});

console.log(formatMicros(invoice.totalMicros, invoice.currency));
// "27.50 USD"

Pricing shapes

A PricedDimension is one of three:

  • Flat per-unit — { perUnitMicros: 200, unit: 1 }
  • Tiered (graduated) — { tiers: [{ upTo: 1_000_000, perUnitMicros: 200 }, { upTo: Infinity, perUnitMicros: 100 }] }
  • Custom — { price: (chargedQuantity) => micros } (escape hatch for surge / caps / non-monotonic pricing)

Optional knobs:

  • freeTier — units subtracted before pricing
  • unit — divisor so bytesEgress priced as MB ↔ unit: 1024*1024
  • label — invoice line-item display name

Plan-level knobs:

  • basePriceMicros — flat fee per period
  • minimumChargeMicros — floor; an adjustment line item fills any gap
  • rounding — 'truncate' (default; sub-cent → $0.00) or 'round-half-up'
  • currency — display label; not converted
  • metadata — arbitrary keys that flow through to the invoice

Why pure?

The control plane needs to:

  • Preview an upcoming invoice before the period closes
  • Re-price a past period under a new plan ("what would this customer have paid on the proposed enterprise tier?")
  • Dry-run plan changes before publishing them

A pure cost-model function makes all three trivial — no Stripe SDK, no side effects, no IO. The Stripe push (or QuickBooks export, or mailed-PDF generator) lives outside this package, in @absolutejs/billing-adapters/*.

License

BSL-1.1 with named carveout against hosted SaaS billing platforms (Metronome, Orb, Lago, Stripe Billing, m3ter, Chargebee). See LICENSE. Change date: 2030-05-31 → Apache 2.0.

Prepaid service credits

Durable balances, reservations, capped work, and migration rules are available through the prepaid, prepaid-postgres, and credit-work subpaths.

Secure credit checkout

Purchase-only handoffs provide expiring, single-use browser capabilities without a full login session.

@absolutejs/billing/reports provides customer-facing status, receipt pagination, and usage contracts. parseUsageRange uses a half-open UTC date interval of at most 90 days (default: the last 30 days including today). Receipt cursors are positions, never authorization: bind every query, reversal join, and cursor to the caller's account. Readers must project through the public helpers, which omit provider costs, payment tokens and vault references. Usage day and feature totals must reconcile exactly; purchased dollars and consumed service credits are different measures. Automatic refill is currently unsupported.

Deferred progress

checkpointDeferred(accountId, workId, binding, expectedRevision, value) saves progress without settling or reserving more credits. The initial revision is 0; success returns the incremented revision and saved string. It verifies the bound effect and authorization, rejects stale revisions and terminal work, and limits the value to one million characters. Existing work uses the same JSON state column; no schema migration is required.

A checkpoint is not an execution lease. Claim execution separately, persist an in-flight marker before any provider call, drain metering before saving its result, and retain the reservation if the outcome is uncertain.

Uncapped embedding plans and application budgets

Pass monthlyTokenLimit: null in EmbeddingUsageSnapshot when the configured provider plan has no monthly embedding-token cap. monthlyBudgetTokens can separately describe a host-owned spending guardrail; it is never reported as provider quota. Both values are host configuration, not a live provider balance. exhausted: true reports currently refused embeddings without assuming a monthly cap caused the refusal. Member allowances remain the host application's policy.

Provider admission

@absolutejs/billing/provider-budget exports createProviderBudget(client, table?) using the existing CreditSqlClient transaction interface. The host owns a journaled PostgreSQL table with id text primary key, scope text, period text, reserved_micros bigint, actual_micros bigint nullable, and status text (plus a scope/period index). Reserve a defensible maximum before an external request; do not treat an estimate as a hard maximum. A repeated reservation ID never authorizes another request. Monthly request and daily cost scopes can be reserved independently; release any earlier scope if later admission fails.

Settle known fulfilled or rejected calls exactly once. An interrupted/unknown provider outcome retains its full reservation until explicitly reconciled. This ledger bounds admitted research operations, independently of member-credit pricing; it does not discover or account for provider calls made outside it. The host must account for all retries/repairs in the reservation or disable them.

Usage attribution

LedgerEntry.attribution accepts a portable UsageAttribution record (call trace, run, subject, session, funded work, release, server and tool). It passes unchanged to the commit and rollup stores and does not affect pricing. The host must retain it with the event and bind subjects after authorization. Observability identity must not change a provider event's charging/idempotency identity. Unknown external-host spend is not zero.

Paid execution policy

@absolutejs/billing/paid-work-policy exports createPaidWorkPolicy, PaidAuthorization, and PaidWorkApprovalError for Node/Bun servers. Create one policy per application with currentWork and withWork adapters to its funded execution context. The context carries userSub, optional actorId and approvalId, and a mutable closed flag. Only trusted admission code may create or attach this context.

Wrap authenticated handlers in withPaidRequester(userSub, request.method, handler, impersonatorId?). Reads (including HEAD and OPTIONS) cannot authorize spending, even through a nested write scope. Start paid work with POST; its response may stream. A GET endpoint should only read previously generated data. The transport contract and the spending contract must agree: Eden's route types alone cannot verify handler side effects.

Require a PaidAuthorization parameter at each paid transport boundary. Obtain it using authorizePaidWork() in the admitted execution scope, and call requirePaidAuthorization(authorization) immediately before starting a provider attempt. Tokens are opaque, checked at runtime, specific to the policy instance and execution scope, and rejected after their funded/deferred scope closes. bindPaidExecution preserves a scope for response iterators that outlive their handler. Do not serialize tokens, accept them from clients, or cache them across requests. A payer ID alone cannot mint a capability: authorizePaidWork requires an authenticated or funded scope. The lower-level requirePaidWorkOwner retains a trusted-server payer fallback for attribution; that fallback does not authorize a provider capability.

An impersonated request requires a funded work context whose actor matches the impersonator and which has an approval ID. withoutAutomaticSpend blocks unapproved background calls. withDeferredPaidRequester is exclusively for a worker that has already atomically claimed a durable approval; it closes that permission when its callback finishes.

This policy checks execution identity and intent. The host still authenticates sessions, validates approval ownership/expiry, reserves and bounds provider costs before calling them, meters actual usage, and settles or retains uncertain reservations. An authorization token is not a credit balance or a durable execution lease. TypeScript prevents accidental missing capabilities; runtime checks remain necessary for untrusted input and changing state.

版本与发布记录

@absolutejs/billing 共发布 29 个版本,首次发布于 2026/06/01;过去 12 个月发布了 29 个版本。

版本发布日期距今
0.19.0latest2026/11/052 天前
0.18.22026/11/025 天前
0.18.12026/11/025 天前
0.18.02026/10/2117 天前
0.17.22026/10/011 个月前
0.17.12026/10/011 个月前

关于 @absolutejs/billing 的常见问题

@absolutejs/billing 是什么?

Provider-neutral pricing and invoice computation used by the hosted AbsoluteJS.ai platform. Converts metered usage into exact integer-micro line items with tiers and allowances.

如何安装 @absolutejs/billing?

在项目目录运行 npm install @absolutejs/billing,或使用 pnpm add / yarn add / bun add。

@absolutejs/billing 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@absolutejs/billing 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@absolutejs/billing 可以商用吗?

@absolutejs/billing 使用 BSL-1.1 许可。声明的许可为 BSL-1.1,请阅读许可原文确认使用条件。以上为概括,不构成法律意见,请以许可原文为准。

@absolutejs/billing 的下载量有多少?

根据 npm 官方下载统计,@absolutejs/billing 在 2026/10/05 – 2026/11/03 这 30 天内被下载 2,904 次,日均约 97 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@absolutejs/billing 还在维护吗?

最新版本 0.19.0 发布于 2026/11/05(2 天前);至今共发布 29 个版本,其中过去 12 个月发布了 29 个;首次发布于 2026/06/01。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。