@arnaudjnn/billing-tools 2.11.0 → 2.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -1
- package/dist/adapters/workos-org.d.ts +2 -0
- package/dist/adapters/workos-org.d.ts.map +1 -1
- package/dist/adapters/workos-org.js +40 -5
- package/dist/adapters/workos-org.js.map +1 -1
- package/dist/allowance.d.ts.map +1 -1
- package/dist/allowance.js +6 -2
- package/dist/allowance.js.map +1 -1
- package/dist/billing.d.ts.map +1 -1
- package/dist/billing.js +6 -5
- package/dist/billing.js.map +1 -1
- package/dist/checkout.d.ts +11 -3
- package/dist/checkout.d.ts.map +1 -1
- package/dist/checkout.js +16 -2
- package/dist/checkout.js.map +1 -1
- package/dist/create-billing.d.ts.map +1 -1
- package/dist/create-billing.js +8 -26
- package/dist/create-billing.js.map +1 -1
- package/dist/doctor.d.ts +39 -6
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +100 -51
- package/dist/doctor.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/metering.d.ts +11 -7
- package/dist/metering.d.ts.map +1 -1
- package/dist/metering.js +8 -3
- package/dist/metering.js.map +1 -1
- package/dist/plan-model.d.ts +84 -9
- package/dist/plan-model.d.ts.map +1 -1
- package/dist/plan-model.js +71 -6
- package/dist/plan-model.js.map +1 -1
- package/dist/plans.d.ts +2 -2
- package/dist/plans.d.ts.map +1 -1
- package/dist/plans.js +1 -1
- package/dist/plans.js.map +1 -1
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +23 -7
- package/dist/sync.js.map +1 -1
- package/dist/tax.d.ts +33 -0
- package/dist/tax.d.ts.map +1 -1
- package/dist/tax.js +90 -0
- package/dist/tax.js.map +1 -1
- package/dist/tools/billing.d.ts.map +1 -1
- package/dist/tools/billing.js +20 -4
- package/dist/tools/billing.js.map +1 -1
- package/dist/types.d.ts +39 -10
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/usage-ledger.d.ts +38 -5
- package/dist/usage-ledger.d.ts.map +1 -1
- package/dist/usage-ledger.js +178 -23
- package/dist/usage-ledger.js.map +1 -1
- package/dist/usage.d.ts +27 -1
- package/dist/usage.d.ts.map +1 -1
- package/dist/usage.js +27 -4
- package/dist/usage.js.map +1 -1
- package/package.json +1 -1
package/dist/usage-ledger.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getStripe, usageSince } from "./billing.js";
|
|
2
|
+
import { ledgerGaps, normalizePlans } from "./plan-model.js";
|
|
2
3
|
/**
|
|
3
4
|
* The ledger this library has always had: the debits themselves.
|
|
4
5
|
*
|
|
@@ -11,6 +12,9 @@ import { getStripe, usageSince } from "./billing.js";
|
|
|
11
12
|
*/
|
|
12
13
|
export function stripeBalanceUsageLedger() {
|
|
13
14
|
return {
|
|
15
|
+
// Per-caller, because a debit carries the caller on its metadata — but only
|
|
16
|
+
// where money moved, so nothing INCLUDED is visible on either axis.
|
|
17
|
+
covers: { orgIncluded: false, callerIncluded: false },
|
|
14
18
|
async record() {
|
|
15
19
|
/* the balance transaction IS the record */
|
|
16
20
|
},
|
|
@@ -33,12 +37,24 @@ export const USAGE_METER_EVENT = "billing_tools_usage";
|
|
|
33
37
|
* overshoot slightly. Irrelevant against a pool of a million credits; it is why
|
|
34
38
|
* seat packs, which are small, can keep using the exact balance path.
|
|
35
39
|
*
|
|
36
|
-
*
|
|
40
|
+
* The meter provisions itself on first use, like plan prices. `ensureMeters` is
|
|
41
|
+
* the same call made eagerly, for a deploy step that wants it to exist before a
|
|
42
|
+
* request does.
|
|
37
43
|
*/
|
|
38
44
|
export function stripeMeterUsageLedger(opts = {}) {
|
|
39
45
|
const eventName = opts.eventName ?? USAGE_METER_EVENT;
|
|
40
46
|
return {
|
|
47
|
+
// One dimension, aggregated server-side: it sees every call whatever funded
|
|
48
|
+
// it, and cannot be filtered by caller.
|
|
49
|
+
covers: { orgIncluded: true, callerIncluded: false },
|
|
41
50
|
async record(e) {
|
|
51
|
+
// Resolve (and create) the meter BEFORE reporting to it. A meter event names
|
|
52
|
+
// its meter by `event_name`, so without this the very first call on a fresh
|
|
53
|
+
// account reports into nothing — and this is the write side, the one whose
|
|
54
|
+
// loss can't be recovered later by a read. Memoised, so it costs one list on
|
|
55
|
+
// the first metered call of the process and nothing after.
|
|
56
|
+
if (!(await meterIdFor(eventName)))
|
|
57
|
+
return;
|
|
42
58
|
await getStripe().billing.meterEvents.create({
|
|
43
59
|
event_name: eventName,
|
|
44
60
|
payload: {
|
|
@@ -73,46 +89,122 @@ export function stripeMeterUsageLedger(opts = {}) {
|
|
|
73
89
|
},
|
|
74
90
|
};
|
|
75
91
|
}
|
|
76
|
-
//
|
|
77
|
-
//
|
|
92
|
+
// ── Resolving the meter, and creating it if it isn't there ───────────────────
|
|
93
|
+
//
|
|
94
|
+
// Provisioned on first use rather than asked of the deployment, which is the rule
|
|
95
|
+
// the rest of this library already follows (`ensurePlans` for prices,
|
|
96
|
+
// `ensurePaymentMethodConfig` for payment forms): the ONE thing a developer sets
|
|
97
|
+
// is the Stripe key.
|
|
98
|
+
//
|
|
99
|
+
// It used to be the exception, and the cost of that was invisible. A config with
|
|
100
|
+
// an included window whose deployment never called `ensureMeters` had no meter, so
|
|
101
|
+
// every window read 0 — nothing was ever refused, which looks like generosity
|
|
102
|
+
// rather than a fault, and the pool it was supposed to enforce might as well not
|
|
103
|
+
// have been declared.
|
|
104
|
+
//
|
|
105
|
+
// Memoised per process and per event name, with in-flight calls shared, so a burst
|
|
106
|
+
// of cold metered calls resolves once. Meter ids are stable, so once found the
|
|
107
|
+
// answer is the answer.
|
|
78
108
|
const meterIds = new Map();
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
109
|
+
const meterInflight = new Map();
|
|
110
|
+
// One line per process, not per call: a metered endpoint under load would
|
|
111
|
+
// otherwise turn a config problem into thousands of identical lines.
|
|
112
|
+
const warned = new Set();
|
|
113
|
+
// A FAILED resolve is remembered only briefly. Not remembering it at all would put
|
|
114
|
+
// a list plus a create attempt on the hot path of every metered call for as long as
|
|
115
|
+
// the failure lasts; remembering it forever would mean a permission granted at
|
|
116
|
+
// 09:05 doesn't take effect until the process restarts. So: back off, then retry.
|
|
117
|
+
const RESOLVE_RETRY_MS = 5 * 60 * 1000;
|
|
118
|
+
const failedAt = new Map();
|
|
119
|
+
async function findMeter(eventName) {
|
|
83
120
|
for await (const m of getStripe().billing.meters.list({ status: "active", limit: 100 })) {
|
|
84
|
-
if (m.event_name === eventName)
|
|
85
|
-
meterIds.set(eventName, m.id);
|
|
121
|
+
if (m.event_name === eventName)
|
|
86
122
|
return m.id;
|
|
87
|
-
}
|
|
88
123
|
}
|
|
89
|
-
meterIds.set(eventName, null);
|
|
90
124
|
return null;
|
|
91
125
|
}
|
|
92
126
|
/**
|
|
93
|
-
*
|
|
127
|
+
* The meter id for `eventName`, creating the meter when it doesn't exist.
|
|
94
128
|
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
129
|
+
* NEVER THROWS — the same rule `defaultPaymentMethodConfig` follows, and for the
|
|
130
|
+
* same reason: this is reached from `ledger.record` on the hot path of every
|
|
131
|
+
* metered call, so a key without permission to create a meter must not take the
|
|
132
|
+
* product down. It degrades to `null` (windows read 0) and says so once, loudly,
|
|
133
|
+
* because that state is otherwise indistinguishable from no usage.
|
|
97
134
|
*/
|
|
98
|
-
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
135
|
+
function meterIdFor(eventName, opts = {}) {
|
|
136
|
+
const hit = meterIds.get(eventName);
|
|
137
|
+
if (hit)
|
|
138
|
+
return Promise.resolve(hit);
|
|
139
|
+
const failed = failedAt.get(eventName);
|
|
140
|
+
if (failed !== undefined && Date.now() - failed < RESOLVE_RETRY_MS)
|
|
141
|
+
return Promise.resolve(null);
|
|
142
|
+
const pending = meterInflight.get(eventName);
|
|
143
|
+
if (pending)
|
|
144
|
+
return pending;
|
|
145
|
+
const resolve = (async () => {
|
|
146
|
+
try {
|
|
147
|
+
const found = (await findMeter(eventName)) ??
|
|
148
|
+
(opts.create === false ? null : await createMeter(eventName));
|
|
149
|
+
// Only a real id is remembered. Caching the miss would poison the memo for
|
|
150
|
+
// the life of the process — including for `ensureMeters`, which probes with
|
|
151
|
+
// `create: false` and creates the meter itself immediately afterwards.
|
|
152
|
+
if (found)
|
|
153
|
+
meterIds.set(eventName, found);
|
|
154
|
+
return found;
|
|
155
|
+
}
|
|
156
|
+
catch (e) {
|
|
157
|
+
failedAt.set(eventName, Date.now());
|
|
158
|
+
if (!warned.has(eventName)) {
|
|
159
|
+
warned.add(eventName);
|
|
160
|
+
console.error(`[billing] could not resolve or create the Stripe billing meter "${eventName}": ` +
|
|
161
|
+
`${e.message}. Included usage cannot be counted until it exists, so every ` +
|
|
162
|
+
"org-wide window reads 0 and no cap or org-scoped rate limit will ever apply. " +
|
|
163
|
+
"Create it once with ensureMeters(), or grant the key write access to billing meters.");
|
|
164
|
+
}
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
})().finally(() => meterInflight.delete(eventName));
|
|
168
|
+
meterInflight.set(eventName, resolve);
|
|
169
|
+
return resolve;
|
|
170
|
+
}
|
|
171
|
+
async function createMeter(eventName, displayName) {
|
|
103
172
|
const meter = await getStripe().billing.meters.create({
|
|
104
|
-
display_name:
|
|
173
|
+
display_name: displayName ?? "billing-tools usage",
|
|
105
174
|
event_name: eventName,
|
|
106
175
|
default_aggregation: { formula: "sum" },
|
|
107
176
|
customer_mapping: { type: "by_id", event_payload_key: "stripe_customer_id" },
|
|
108
177
|
value_settings: { event_payload_key: "value" },
|
|
109
178
|
});
|
|
110
|
-
|
|
111
|
-
|
|
179
|
+
return meter.id;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Ensure the usage meter exists, eagerly. Idempotent, like `ensurePlans`.
|
|
183
|
+
*
|
|
184
|
+
* No longer a prerequisite — the ledger provisions the meter on first use — but
|
|
185
|
+
* still worth calling from a deploy step or a setup script when you'd rather the
|
|
186
|
+
* meter existed before a customer's request pays for creating it, or want the
|
|
187
|
+
* failure to surface in a deploy log instead of a warning. Unlike the lazy path
|
|
188
|
+
* this one THROWS, because a setup script wants to know.
|
|
189
|
+
*
|
|
190
|
+
* Aggregates `sum` over the reported `value`, which is the credit cost.
|
|
191
|
+
*/
|
|
192
|
+
export async function ensureMeters(opts = {}) {
|
|
193
|
+
const eventName = opts.eventName ?? USAGE_METER_EVENT;
|
|
194
|
+
const existing = await meterIdFor(eventName, { create: false });
|
|
195
|
+
if (existing)
|
|
196
|
+
return { meterId: existing, created: false };
|
|
197
|
+
const meterId = await createMeter(eventName, opts.displayName);
|
|
198
|
+
meterIds.set(eventName, meterId);
|
|
199
|
+
return { meterId, created: true };
|
|
112
200
|
}
|
|
113
|
-
/** Forget resolved meter ids — for a test, or after archiving one.
|
|
201
|
+
/** Forget resolved meter ids — for a test, or after archiving one. Also clears the
|
|
202
|
+
* once-per-process complaint above, so a key that gains permission (or a test that
|
|
203
|
+
* wants to see it again) gets a fresh line rather than silence. */
|
|
114
204
|
export function invalidateMeters() {
|
|
115
205
|
meterIds.clear();
|
|
206
|
+
warned.clear();
|
|
207
|
+
failedAt.clear();
|
|
116
208
|
}
|
|
117
209
|
// ── The composite: route each read to the store that can answer it ───────────
|
|
118
210
|
//
|
|
@@ -141,7 +233,19 @@ export function invalidateMeters() {
|
|
|
141
233
|
export function stripeUsageLedger(opts = {}) {
|
|
142
234
|
const meter = opts.orgWide ?? stripeMeterUsageLedger({ eventName: opts.eventName });
|
|
143
235
|
const perCaller = opts.perCaller ?? stripeBalanceUsageLedger();
|
|
236
|
+
// Each axis inherits the leg that answers it, so `stripeUsageLedger({ perCaller:
|
|
237
|
+
// postgresUsageLedger(db) })` reports full coverage and the bare composite reports
|
|
238
|
+
// the org axis only — which is exactly what each can do. A leg that declares
|
|
239
|
+
// nothing (a consumer's own) makes the composite silent too rather than making it
|
|
240
|
+
// guess: an invented `false` would fail a config that is perfectly wired.
|
|
241
|
+
const covers = meter.covers && perCaller.covers
|
|
242
|
+
? {
|
|
243
|
+
orgIncluded: meter.covers.orgIncluded,
|
|
244
|
+
callerIncluded: perCaller.covers.callerIncluded,
|
|
245
|
+
}
|
|
246
|
+
: undefined;
|
|
144
247
|
return {
|
|
248
|
+
...(covers ? { covers } : {}),
|
|
145
249
|
async record(e) {
|
|
146
250
|
// The meter always, so org-wide windows see every call whatever funded it.
|
|
147
251
|
// The per-caller leg too, in the same round — for the balance ledger that is
|
|
@@ -156,6 +260,54 @@ export function stripeUsageLedger(opts = {}) {
|
|
|
156
260
|
},
|
|
157
261
|
};
|
|
158
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* The default ledger, defined ONCE.
|
|
265
|
+
*
|
|
266
|
+
* `createMeter` and `createBilling` used to answer this differently — the balance
|
|
267
|
+
* ledger and the composite — and the difference was invisible to the consumer who
|
|
268
|
+
* picked the wrong entry point: wiring `createMeter` directly got a ledger that
|
|
269
|
+
* cannot see included usage, so a pooled cap read 0% forever and no call was ever
|
|
270
|
+
* refused. Two defaults for one decision is how that happens, so there is one.
|
|
271
|
+
*
|
|
272
|
+
* Built once per process: it holds only memoised lookups, and rebuilding it per
|
|
273
|
+
* metered call would throw those away.
|
|
274
|
+
*/
|
|
275
|
+
let defaultLedger = null;
|
|
276
|
+
export function defaultUsageLedger() {
|
|
277
|
+
return (defaultLedger ??= stripeUsageLedger());
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Warn at boot about the plans whose included windows this ledger cannot count.
|
|
281
|
+
*
|
|
282
|
+
* Worth a line in a deploy log because the failure is silent and looks like
|
|
283
|
+
* generosity: the window reads 0, so nothing is ever refused. A ledger that
|
|
284
|
+
* declares no `covers` (a consumer's own) says nothing here — see `UsageLedger`.
|
|
285
|
+
*
|
|
286
|
+
* Called from `createMeter`, i.e. once per composition rather than per metered
|
|
287
|
+
* call, so it needs no de-duplication: a second line means a second meter was
|
|
288
|
+
* built, which is itself worth seeing.
|
|
289
|
+
*/
|
|
290
|
+
export function warnLedgerGaps(plans, ledger) {
|
|
291
|
+
if (!ledger.covers)
|
|
292
|
+
return;
|
|
293
|
+
const { org, caller } = ledgerGaps(normalizePlans(plans), ledger.covers);
|
|
294
|
+
const say = (msg) => console.warn(`[billing] ${msg}`);
|
|
295
|
+
if (org.length) {
|
|
296
|
+
say(`plans ${org.map((m) => m.key).join(", ")} include usage org-wide (a pool, or a ` +
|
|
297
|
+
"`scope: \"org\"` rate limit) and the wired ledger can only see calls the wallet paid " +
|
|
298
|
+
"for. Included usage counts as 0, so the window never applies and nothing is refused. " +
|
|
299
|
+
"Use the default `stripeUsageLedger()` — it counts these on a Stripe meter, at any " +
|
|
300
|
+
"volume, with no store.");
|
|
301
|
+
}
|
|
302
|
+
if (caller.length) {
|
|
303
|
+
say(`plans ${caller.map((m) => m.key).join(", ")} meter an INCLUDED window per member (a seat ` +
|
|
304
|
+
"pack, or a `scope: \"caller\"` rate limit), which no Stripe primitive can count: a " +
|
|
305
|
+
"balance transaction carries the caller but only exists where money moved, and a meter " +
|
|
306
|
+
"summary cannot be filtered by caller. That usage counts as 0. Pass `meter.db` (a " +
|
|
307
|
+
"Postgres client) or a `ledger` of your own — or pool the allowance instead " +
|
|
308
|
+
'(`cap: { kind: "pool", perSeat: N }`), which needs no store.');
|
|
309
|
+
}
|
|
310
|
+
}
|
|
159
311
|
/**
|
|
160
312
|
* The table, and the three indexes the two queries below actually use.
|
|
161
313
|
*
|
|
@@ -205,6 +357,9 @@ export async function ensureUsageLedgerTable(client) {
|
|
|
205
357
|
*/
|
|
206
358
|
export function postgresUsageLedger(client) {
|
|
207
359
|
return {
|
|
360
|
+
// Every event is a row carrying both the caller and what funded it, so this is
|
|
361
|
+
// the one implementation that can answer either question.
|
|
362
|
+
covers: { orgIncluded: true, callerIncluded: true },
|
|
208
363
|
async record(e) {
|
|
209
364
|
// ON CONFLICT on the idempotency key, so a retried execution is counted
|
|
210
365
|
// once. Without a key (the common case) every row is a distinct event. The
|
package/dist/usage-ledger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage-ledger.js","sourceRoot":"","sources":["../src/usage-ledger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"usage-ledger.js","sourceRoot":"","sources":["../src/usage-ledger.ts"],"names":[],"mappings":"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"}
|
package/dist/usage.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type AllowanceState, type LimitState } from "./allowance.js";
|
|
2
|
-
import
|
|
2
|
+
import { type LocaleOptions } from "./i18n.js";
|
|
3
|
+
import { type CycleWindow, type PlanCatalog, type PlanModel } from "./plan-model.js";
|
|
3
4
|
import { type UsageLedger } from "./usage-ledger.js";
|
|
4
5
|
import type { BillingAdapter, ResolvedConfig } from "./types.js";
|
|
5
6
|
/** One window with progress. `resetsAt` is null only for an open-ended cycle. */
|
|
@@ -8,6 +9,17 @@ export interface UsageWindow extends LimitState {
|
|
|
8
9
|
percent: number;
|
|
9
10
|
resetsAt: number | null;
|
|
10
11
|
}
|
|
12
|
+
/** Which seat the caller holds, and the plan's own word for it. */
|
|
13
|
+
export interface UsageSeat {
|
|
14
|
+
/** Seat type key: a sold seat type, the plan's implicit seat, or `api`. */
|
|
15
|
+
type: string;
|
|
16
|
+
/**
|
|
17
|
+
* `display.badge`, else `display.label`, resolved for the requested locale —
|
|
18
|
+
* null when the config gave that seat no display at all. The badge form wins
|
|
19
|
+
* because this is the pill on a usage screen, not a pricing card.
|
|
20
|
+
*/
|
|
21
|
+
label: string | null;
|
|
22
|
+
}
|
|
11
23
|
export interface UsageSummary {
|
|
12
24
|
plan: string | null;
|
|
13
25
|
/** The billing cycle the cap is measured over. */
|
|
@@ -21,6 +33,12 @@ export interface UsageSummary {
|
|
|
21
33
|
seatType: string;
|
|
22
34
|
extra: number;
|
|
23
35
|
}) | null;
|
|
36
|
+
/**
|
|
37
|
+
* The caller's seat, when a caller was given. Present even on a plan that caps
|
|
38
|
+
* nothing per seat — you hold a seat on a free plan too, and `pack` is about
|
|
39
|
+
* an allowance, not about who you are.
|
|
40
|
+
*/
|
|
41
|
+
seat: UsageSeat | null;
|
|
24
42
|
/** Prepaid balance, in the configured currency. */
|
|
25
43
|
wallet: number;
|
|
26
44
|
/** Epoch ms this was read. What a "last updated" line shows. */
|
|
@@ -42,7 +60,15 @@ export interface UsageSummaryInput {
|
|
|
42
60
|
};
|
|
43
61
|
ledger?: UsageLedger;
|
|
44
62
|
now?: number;
|
|
63
|
+
/** Which language to resolve `seat.label` in. The only string this returns. */
|
|
64
|
+
locale?: LocaleOptions;
|
|
45
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* How a plan presents one seat type: a sold seat type first, then the implicit
|
|
68
|
+
* seat of a plan that sells none. Exported because a members list wants the same
|
|
69
|
+
* pill as a usage screen, and reimplementing this lookup is how the two drift.
|
|
70
|
+
*/
|
|
71
|
+
export declare function resolveSeat(model: PlanModel | null, type: string, locale?: LocaleOptions): UsageSeat;
|
|
46
72
|
/**
|
|
47
73
|
* Everything a usage screen shows for one subject (a workspace, or one member).
|
|
48
74
|
*
|
package/dist/usage.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"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"}
|
package/dist/usage.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { getBillingCustomerId } from "./billing.js";
|
|
2
2
|
import { resolveAllowance } from "./allowance.js";
|
|
3
|
+
import { resolveLocalized } from "./i18n.js";
|
|
3
4
|
import { getSeatType } from "./seats.js";
|
|
5
|
+
import { DEFAULT_SEAT_TYPE, planModel, } from "./plan-model.js";
|
|
4
6
|
import { stripeBalanceUsageLedger } from "./usage-ledger.js";
|
|
5
7
|
const pct = (used, size) => size <= 0 ? 100 : Math.min(100, Math.max(0, Math.round((used / size) * 100)));
|
|
6
8
|
function toWindow(l) {
|
|
@@ -21,6 +23,19 @@ function capWindow(every, label, size, used, cycle) {
|
|
|
21
23
|
resetsAt: cycle.end,
|
|
22
24
|
};
|
|
23
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* How a plan presents one seat type: a sold seat type first, then the implicit
|
|
28
|
+
* seat of a plan that sells none. Exported because a members list wants the same
|
|
29
|
+
* pill as a usage screen, and reimplementing this lookup is how the two drift.
|
|
30
|
+
*/
|
|
31
|
+
export function resolveSeat(model, type, locale) {
|
|
32
|
+
const display = model?.seatTypes.find((s) => s.key === type)?.display ??
|
|
33
|
+
(model?.seat?.key === type ? model.seat.display : null);
|
|
34
|
+
return {
|
|
35
|
+
type,
|
|
36
|
+
label: display ? (resolveLocalized(display.badge ?? display.label, locale) ?? null) : null,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
24
39
|
/**
|
|
25
40
|
* Everything a usage screen shows for one subject (a workspace, or one member).
|
|
26
41
|
*
|
|
@@ -33,11 +48,15 @@ export async function usageSummary(adapter, config, input) {
|
|
|
33
48
|
const at = input.now ?? Date.now();
|
|
34
49
|
// A member's seat decides which pack and which seat-scoped limits apply, so
|
|
35
50
|
// resolve it here rather than making every page do it.
|
|
51
|
+
const model = planModel(input.plans, input.plan ?? null);
|
|
36
52
|
let caller = input.caller;
|
|
37
53
|
if (caller && !caller.seatType) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
54
|
+
// Nobody assigned them one: the plan's own implicit seat if it named one,
|
|
55
|
+
// else the historical default. A plan that SELLS seats has no implicit seat
|
|
56
|
+
// (`model.seat` is null there), because an unassigned member is a data gap
|
|
57
|
+
// and guessing at a sold seat type would hand out an allowance.
|
|
58
|
+
const assigned = caller.id ? await getSeatType(adapter, input.orgId, caller.id) : null;
|
|
59
|
+
const seatType = caller.kind === "api" ? "api" : assigned || model?.seat?.key || DEFAULT_SEAT_TYPE;
|
|
41
60
|
caller = { ...caller, seatType };
|
|
42
61
|
}
|
|
43
62
|
const state = await resolveAllowance(adapter, config, {
|
|
@@ -65,6 +84,7 @@ export async function usageSummary(adapter, config, input) {
|
|
|
65
84
|
extra: state.pack.extra,
|
|
66
85
|
}
|
|
67
86
|
: null,
|
|
87
|
+
seat: caller?.seatType ? resolveSeat(model, caller.seatType, input.locale) : null,
|
|
68
88
|
wallet: state.wallet,
|
|
69
89
|
at,
|
|
70
90
|
};
|
|
@@ -123,7 +143,10 @@ export async function memberUsage(adapter, config, input) {
|
|
|
123
143
|
return {
|
|
124
144
|
id: m.id,
|
|
125
145
|
kind,
|
|
126
|
-
|
|
146
|
+
// From the resolved seat, not from the pack: a POOLED plan has no pack
|
|
147
|
+
// and reported every member as `standard`, a seat type such a plan does
|
|
148
|
+
// not even declare.
|
|
149
|
+
seatType: summary.seat?.type ?? (kind === "api" ? "api" : DEFAULT_SEAT_TYPE),
|
|
127
150
|
pack: summary.pack ? { ...summary.pack, extra: summary.pack.extra } : null,
|
|
128
151
|
windows: summary.windows.filter((w) => w.scope === "caller"),
|
|
129
152
|
usedInCycle,
|
package/dist/usage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAwC,MAAM,gBAAgB,CAAC;AACxF,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arnaudjnn/billing-tools",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.13.0",
|
|
4
4
|
"description": "The get-paid engine for Stripe + WorkOS apps, for humans and AI agents. Drop-in API-key auth, credit + subscription billing, auth.md agent registration, and MPP machine payments, as MCP tools, a REST API, and a CLI. Framework-agnostic, storage-pluggable.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Arnaud Jeannin",
|