@arnaudjnn/billing-tools 0.61.0 → 0.62.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/dist/allowance.d.ts +26 -3
- package/dist/allowance.d.ts.map +1 -1
- package/dist/allowance.js +69 -6
- package/dist/allowance.js.map +1 -1
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +40 -0
- package/dist/doctor.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/metering.d.ts +6 -1
- package/dist/metering.d.ts.map +1 -1
- package/dist/metering.js +5 -2
- package/dist/metering.js.map +1 -1
- package/dist/plan-model.d.ts +51 -0
- package/dist/plan-model.d.ts.map +1 -1
- package/dist/plan-model.js +63 -2
- 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/tools/management.d.ts +2 -1
- package/dist/tools/management.d.ts.map +1 -1
- package/dist/tools/management.js +56 -1
- package/dist/tools/management.js.map +1 -1
- package/dist/tools/register.d.ts +1 -1
- package/dist/tools/register.d.ts.map +1 -1
- package/dist/tools/register.js +1 -0
- package/dist/tools/register.js.map +1 -1
- package/dist/usage.d.ts +93 -0
- package/dist/usage.d.ts.map +1 -0
- package/dist/usage.js +110 -0
- package/dist/usage.js.map +1 -0
- package/package.json +1 -1
package/dist/usage.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { getBillingCustomerId } from "./billing.js";
|
|
2
|
+
import { resolveAllowance } from "./allowance.js";
|
|
3
|
+
import { getSeatType } from "./seats.js";
|
|
4
|
+
import { planModel } from "./plan-model.js";
|
|
5
|
+
import { stripeBalanceUsageLedger } from "./usage-ledger.js";
|
|
6
|
+
const pct = (used, size) => size <= 0 ? 100 : Math.min(100, Math.max(0, Math.round((used / size) * 100)));
|
|
7
|
+
function toWindow(l) {
|
|
8
|
+
return { ...l, percent: pct(l.used, l.size), resetsAt: l.window.end };
|
|
9
|
+
}
|
|
10
|
+
/** The cap's own window, so a screen can render pool/pack with the same row as a
|
|
11
|
+
* rate limit rather than special-casing three shapes. */
|
|
12
|
+
function capWindow(every, label, size, used, cycle) {
|
|
13
|
+
return {
|
|
14
|
+
every,
|
|
15
|
+
scope: "org",
|
|
16
|
+
label,
|
|
17
|
+
size,
|
|
18
|
+
used,
|
|
19
|
+
remaining: Math.max(0, size - used),
|
|
20
|
+
window: cycle,
|
|
21
|
+
percent: pct(used, size),
|
|
22
|
+
resetsAt: cycle.end,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Everything a usage screen shows for one subject (a workspace, or one member).
|
|
27
|
+
*
|
|
28
|
+
* One `resolveAllowance` underneath, so the numbers a screen shows and the numbers
|
|
29
|
+
* the meter enforces are the same numbers, read the same way. A screen that
|
|
30
|
+
* computed its own would eventually disagree with the gate — and the disagreement
|
|
31
|
+
* would be invisible until a customer was refused at 60%.
|
|
32
|
+
*/
|
|
33
|
+
export async function usageSummary(adapter, config, input) {
|
|
34
|
+
const model = planModel(input.plans, input.plan ?? null);
|
|
35
|
+
const at = input.now ?? Date.now();
|
|
36
|
+
// A member's seat decides which pack and which seat-scoped limits apply, so
|
|
37
|
+
// resolve it here rather than making every page do it.
|
|
38
|
+
let caller = input.caller;
|
|
39
|
+
if (caller && !caller.seatType) {
|
|
40
|
+
const seatType = caller.kind === "api"
|
|
41
|
+
? "api"
|
|
42
|
+
: ((caller.id && (await getSeatType(adapter, input.orgId, caller.id))) || "standard");
|
|
43
|
+
caller = { ...caller, seatType };
|
|
44
|
+
}
|
|
45
|
+
const state = await resolveAllowance(adapter, config, {
|
|
46
|
+
orgId: input.orgId,
|
|
47
|
+
plans: input.plans,
|
|
48
|
+
plan: input.plan,
|
|
49
|
+
caller,
|
|
50
|
+
ledger: input.ledger ?? stripeBalanceUsageLedger(),
|
|
51
|
+
now: at,
|
|
52
|
+
});
|
|
53
|
+
return {
|
|
54
|
+
plan: state.plan,
|
|
55
|
+
cycle: state.cycle,
|
|
56
|
+
windows: state.limits.map(toWindow),
|
|
57
|
+
pool: state.pool
|
|
58
|
+
? capWindow("cycle", model?.display?.pooled?.title ?? null, state.pool.size, state.pool.used, state.cycle)
|
|
59
|
+
: null,
|
|
60
|
+
pack: state.pack
|
|
61
|
+
? {
|
|
62
|
+
...capWindow("cycle", null, state.pack.size + state.pack.extra, state.pack.used, state.cycle),
|
|
63
|
+
seatType: state.pack.seatType,
|
|
64
|
+
extra: state.pack.extra,
|
|
65
|
+
}
|
|
66
|
+
: null,
|
|
67
|
+
wallet: state.wallet,
|
|
68
|
+
at,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Per-member usage for an admin view.
|
|
73
|
+
*
|
|
74
|
+
* One summary per member, run in parallel: the ledger has no group-by, and adding
|
|
75
|
+
* one to the seam would mean either a Stripe meter dimension per member (there is
|
|
76
|
+
* no such thing) or paging every transaction in the window and bucketing it here.
|
|
77
|
+
* A workspace is tens of members, not thousands, and this is a page, not the hot
|
|
78
|
+
* path — but it IS N round trips, so a caller that renders it on every request
|
|
79
|
+
* should cache it.
|
|
80
|
+
*/
|
|
81
|
+
export async function memberUsage(adapter, config, input) {
|
|
82
|
+
const at = input.now ?? Date.now();
|
|
83
|
+
const customerId = await getBillingCustomerId(adapter, input.orgId);
|
|
84
|
+
if (!customerId)
|
|
85
|
+
return [];
|
|
86
|
+
return Promise.all(input.members.map(async (m) => {
|
|
87
|
+
const kind = m.kind ?? "user";
|
|
88
|
+
const summary = await usageSummary(adapter, config, {
|
|
89
|
+
orgId: input.orgId,
|
|
90
|
+
plans: input.plans,
|
|
91
|
+
plan: input.plan,
|
|
92
|
+
caller: { kind, id: m.id },
|
|
93
|
+
ledger: input.ledger,
|
|
94
|
+
now: at,
|
|
95
|
+
});
|
|
96
|
+
// The pack is the per-member figure when the plan has one; without a pack
|
|
97
|
+
// (a pool or a pure wallet) fall back to the caller-scoped window, and
|
|
98
|
+
// failing that to zero, which is honest: a pooled plan does not attribute.
|
|
99
|
+
const usedInCycle = summary.pack?.used ?? summary.windows.find((w) => w.scope === "caller")?.used ?? 0;
|
|
100
|
+
return {
|
|
101
|
+
id: m.id,
|
|
102
|
+
kind,
|
|
103
|
+
seatType: summary.pack?.seatType ?? (kind === "api" ? "api" : "standard"),
|
|
104
|
+
pack: summary.pack ? { ...summary.pack, extra: summary.pack.extra } : null,
|
|
105
|
+
windows: summary.windows.filter((w) => w.scope === "caller"),
|
|
106
|
+
usedInCycle,
|
|
107
|
+
};
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=usage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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": "0.
|
|
3
|
+
"version": "0.62.0",
|
|
4
4
|
"description": "The get-paid engine for Stripe + WorkOS apps, for humans and AI agents. Drop-in API-key auth, token/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",
|