Files
zooqueenandHanzo Dev 15d5989fa3 The plan is named only by its catalog row, or its slug
GET /v1/billing/tier's displayName names the tier class ("Pro" for every Max
rung), so it never names the plan. The removal guard also reads the emitted
declarations, where an aliased type re-export would hide.

Co-authored-by: Hanzo Dev <[email protected]>
2026-10-15 23:18:13 -07:00

269 lines
11 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* A meter that reads zero is a claim, and the wrong one.
*
* "You have used none of your plan" and "we could not measure your plan" look
* identical on a bar and mean opposite things. The first is reassuring; the
* second is a fault. Rendering the second as the first tells someone who has
* been working all month that they have not started — on the one screen they
* opened to check whether their payment worked.
*
* So `usageOf` returns UNDEFINED unless a real bound and a real count both
* arrived, and <Meter> draws no bar for undefined. Every case below is a way
* the rollup can arrive without both, and each is reachable today: a server
* that predates windows, a plan declaring no bound at a span, an unreadable
* ledger.
*
* node --test
*/
import { test } from 'node:test'
import assert from 'node:assert/strict'
import { usageOf, resetsAt } from './dist/esm/usage.js'
import { held, resolvePlan } from './dist/esm/usePlan.js'
const W = (span, limit, used, extra = {}) => ({ span, limit, used, ...extra })
test('no windows is not zero usage', () => {
// A server that predates windows. It answers, and it says nothing about them.
assert.equal(usageOf({ period: '2026-08' }), undefined)
assert.equal(usageOf({ windows: [] }), undefined)
// The ledger did not answer at all.
assert.equal(usageOf(null), undefined)
})
test('a span with no bound is skipped, not read as fully spent', () => {
// limit 0 means "no bound at this period" — the opposite of "you may make
// zero requests". Reading it as spent would pin the meter at 100%.
assert.equal(usageOf({ windows: [W('hour', 0, 0), W('day', 0, 12)] }), undefined)
const u = usageOf({ windows: [W('hour', 0, 5), W('day', 100, 25)] })
assert.equal(u.span, 'day', 'the only real bound must be the one reported')
assert.equal(u.usedPct, 25)
})
test('a fresh period with no spend is a real zero', () => {
// This one IS 0%, and it must render — the difference from the cases above is
// the whole point of the file.
const u = usageOf({ windows: [W('day', 1000, 0, { remaining: 1000 })] })
assert.ok(u, 'a declared bound with no spend must report, not vanish')
assert.equal(u.usedPct, 0)
assert.equal(u.leftPct, 100)
assert.equal(u.remaining, 1000)
assert.equal(u.over, false)
})
test('the nearest bound wins, not the longest period', () => {
// Throttled on the hour while barely into the month. Telling this person they
// are 2% through the month is true and useless: the hour is what stops them.
// The binding window is deliberately NOT first in the array. Ordered first,
// "nearest wins" and "whichever came first wins" are indistinguishable, and
// the test passes against an implementation that never compares anything.
const u = usageOf({
windows: [
W('day', 1000, 300),
W('week', 5000, 900),
W('hour', 150, 148, { remaining: 2, resets: '2026-08-19T23:00:00Z' }),
W('month', 15000, 300),
],
})
assert.equal(u.span, 'hour', 'the nearest bound must win regardless of its position')
assert.equal(u.usedPct, 99)
assert.equal(u.remaining, 2)
// And the reverse ordering, so neither "first" nor "last" can masquerade.
const v = usageOf({
windows: [
W('month', 15000, 300),
W('hour', 150, 148),
W('week', 5000, 900),
W('day', 1000, 300),
],
})
assert.equal(v.span, 'hour')
})
test('used and left always sum to a whole', () => {
// Two numbers for one fact drift. left is derived from used, so a reader can
// never be shown 62% used beside 39% left.
for (const used of [0, 1, 37, 500, 999, 1000]) {
const u = usageOf({ windows: [W('day', 1000, used)] })
assert.equal(u.usedPct + u.leftPct, 100, `${used}/1000 does not sum to 100`)
}
})
test('a spent bound clamps the bar and says so', () => {
// A bar cannot draw 240%, and usage CAN pass the bound — the ledger keeps
// recording. The bar pins at full and the flag carries what it cannot.
const u = usageOf({ windows: [W('day', 1000, 2400)] })
assert.equal(u.usedPct, 100, 'the fill must not exceed the track')
assert.equal(u.leftPct, 0)
assert.equal(u.remaining, 0)
assert.equal(u.over, true)
})
test('the server’s own remaining is trusted over the subtraction', () => {
// remaining is what the GATE will enforce. If it disagrees with limit−used,
// the gate is right and the arithmetic here is the guess.
const u = usageOf({ windows: [W('day', 1000, 400, { remaining: 550 })] })
assert.equal(u.remaining, 550)
// …and the subtraction still covers a server that sent none.
assert.equal(usageOf({ windows: [W('day', 1000, 400)] }).remaining, 600)
})
test('a nonsense reading is refused rather than rendered', () => {
// Negative usage is a broken row, not a credit. Showing it as over-100% left
// would be inventing good news.
assert.equal(usageOf({ windows: [W('day', 1000, -5)] }), undefined)
assert.equal(usageOf({ windows: [W('day', -1, 10)] }), undefined)
})
test('a reset instant is shown only when it can be trusted', () => {
assert.equal(resetsAt(undefined), '')
assert.equal(resetsAt({ span: 'day', resets: '' }), '')
// A time this runtime cannot parse is worse than none: a holder waits on it.
assert.equal(resetsAt({ span: 'day', resets: 'tomorrow-ish' }), '')
// An hour rolls over at a TIME; a month at a DATE. "resets 00:00" for a month
// is technically true and reads as tonight.
assert.match(resetsAt({ span: 'hour', resets: '2026-08-19T23:00:00Z' }), /\d/)
assert.match(resetsAt({ span: 'month', resets: '2026-09-01T00:00:00Z' }), /\w/)
})
test('a bound is worth showing whether or not it was paid for', () => {
// The free rung declares 20 a day. It is a real bound, met by real people, and
// it used to be invisible because the meter keyed on "has a subscription" —
// so the viewers most likely to hit a limit were the only ones never warned
// about it. They met it as a refusal instead.
//
// usageOf does not know or care who paid; it reports a reading when one
// exists. This asserts the free shape produces one.
const u = usageOf({
windows: [
W('hour', 10, 9, { remaining: 1, resets: '2026-08-20T15:00:00Z' }),
W('day', 20, 18, { remaining: 2 }),
],
})
assert.ok(u, 'the free rung is bounded and the bound must be readable')
assert.equal(u.span, 'hour', '9/10 binds before 18/20')
assert.equal(u.remaining, 1)
})
// The catalog as GET /v1/billing/plans serves it, trimmed to what is read.
const CATALOG = [
{ slug: 'free', name: 'Free', price: 0 },
{ slug: 'dev', name: 'Pro', price: 2000 },
{ slug: 'max-5x', name: 'Max 5x', price: 10000 },
{ slug: 'max-20x', name: 'Max 20x', price: 20000 },
{ slug: 'team', name: 'Team', price: 2500 },
{ slug: 'enterprise', name: 'Enterprise', price: 0, contactSales: true },
{ slug: 'dns-free', name: 'DNS Free', price: 0 },
{ slug: 'dns-pro', name: 'DNS Pro', price: 500 },
]
// One org's subscriptions, as the server lists them: every row the org holds —
// another member's, DNS, a test bundle, a free one beside paid ones, one opened
// under a retired name. The menu must never pick from it.
const ROWS = {
subscriptions: [
{ status: 'active', userId: 'acme/bob', plan: { id: 'sub_bob', name: 'Max 20x' } },
{ status: 'active', plan: { id: 'sub_dns', name: 'DNS Pro' } },
{ status: 'trialing', plan: { id: 'sub_test', name: 'Bundle (test)' } },
{ status: 'active', plan: { id: 'sub_free', name: 'Free' } },
{ status: 'active', plan: { id: 'sub_old', name: 'Dev' } },
],
}
function server(routes) {
const asked = []
const fetchImpl = async (url, init) => {
asked.push({ url, headers: init?.headers ?? {} })
const body = routes[new URL(url, 'https://site.test').pathname]
if (body === undefined) return { ok: false, status: 404, json: async () => ({}) }
return { ok: true, status: 200, json: async () => body }
}
return { fetchImpl, asked }
}
test('the plan is the one billing serves the payer, named by the catalog', async () => {
const s = server({
'/v1/billing/tier': { plan: 'max-5x', tier: { displayName: 'Pro' } },
'/v1/billing/plans': CATALOG,
'/v1/billing/subscriptions': ROWS,
})
const { held: h } = await resolvePlan(s.fetchImpl)
assert.deepEqual(h, { tier: 'max-5x', name: 'Max 5x', paid: true, found: true })
// Five org rows, another member's paid one first: none of them is read.
assert.ok(
s.asked.every((a) => !a.url.includes('/subscriptions')),
"the org-wide subscription list must not name the viewer's plan"
)
})
test('tier is the catalog slug, never a row id', () => {
const h = held({ plan: 'dev', subscription: 'QrSJ2E1VKc8' }, CATALOG)
assert.equal(h.tier, 'dev')
})
test('a retired name is shown as the catalog names the rung now', () => {
// Billing maps the retired slug; the catalog row for it says "Pro". The tier
// CLASS beside it ("Starter" here) does not win over the catalog.
assert.equal(
held({ plan: 'dev', tier: { displayName: 'Starter' } }, CATALOG).name,
'Pro'
)
})
test("paid is the catalog's answer: a price, or a contract", () => {
assert.equal(held({ plan: 'free' }, CATALOG).paid, false)
assert.equal(held({ plan: 'dns-free' }, CATALOG).paid, false)
assert.equal(held({ plan: 'max-20x' }, CATALOG).paid, true)
// Contact-sales stores price 0 and is not free.
assert.equal(held({ plan: 'enterprise' }, CATALOG).paid, true)
// Without the catalog, nothing is claimed paid.
assert.equal(held({ plan: 'max-20x' }, null).paid, false)
})
test('free is free even when the org also holds paid rows', async () => {
const s = server({
'/v1/billing/tier': { plan: 'free' },
'/v1/billing/plans': CATALOG,
'/v1/billing/subscriptions': ROWS,
})
const { held: h } = await resolvePlan(s.fetchImpl)
assert.deepEqual(h, { tier: 'free', name: 'Free', paid: false, found: true })
})
test('a slug the catalog does not list is shown as the slug, never as its class', () => {
// The tier's displayName names a CLASS: a Max 20x holder is served in class
// "Pro". With max-20x missing from the catalog, "Pro" would be a false name.
const max = held({ plan: 'max-20x', tier: { displayName: 'Pro' } }, [])
assert.deepEqual(max, { tier: 'max-20x', name: 'max-20x', paid: false, found: true })
const pod = held({ plan: 'pod', tier: { displayName: 'Enterprise' } }, CATALOG)
assert.equal(pod.name, 'pod')
})
test('an unread or empty tier names nothing', async () => {
assert.equal(held(null, CATALOG).found, false)
assert.equal(held({ plan: '' }, CATALOG).found, false)
const s = server({ '/v1/billing/plans': CATALOG, '/v1/billing/subscriptions': ROWS })
const r = await resolvePlan(s.fetchImpl)
assert.equal(
r.held.found,
false,
'a refused tier must not fall through to a subscription row'
)
assert.equal(r.rollup, null)
})
test('a host on another origin reads the billing origin as its org', async () => {
const s = server({ '/v1/billing/tier': { plan: 'team' }, '/v1/billing/plans': CATALOG })
const { held: h } = await resolvePlan(s.fetchImpl, 'https://api.hanzo.ai/', {
'X-Org-Id': 'acme',
})
assert.equal(h.name, 'Team')
assert.deepEqual(s.asked.map((a) => a.url).sort(), [
'https://api.hanzo.ai/v1/billing/plans',
'https://api.hanzo.ai/v1/billing/tier',
'https://api.hanzo.ai/v1/billing/usage/rollup',
])
for (const a of s.asked) assert.equal(a.headers['X-Org-Id'], 'acme')
})