@arnaudjnn/billing-tools 2.10.2 → 2.12.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 +4 -0
- package/dist/adapters/workos-org.d.ts.map +1 -1
- package/dist/adapters/workos-org.js +40 -0
- package/dist/adapters/workos-org.js.map +1 -1
- package/dist/allowance.d.ts.map +1 -1
- package/dist/allowance.js +44 -11
- 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 +15 -14
- package/dist/create-billing.d.ts.map +1 -1
- package/dist/create-billing.js +17 -19
- 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 +125 -42
- package/dist/doctor.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -3
- 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 +78 -3
- package/dist/plan-model.d.ts.map +1 -1
- package/dist/plan-model.js +74 -3
- 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 +27 -0
- 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 +44 -10
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/usage-ledger.d.ts +57 -5
- package/dist/usage-ledger.d.ts.map +1 -1
- package/dist/usage-ledger.js +220 -23
- package/dist/usage-ledger.js.map +1 -1
- package/package.json +1 -1
package/dist/usage-ledger.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type LedgerCoverage, type PlanCatalog } from "./plan-model.js";
|
|
1
2
|
/** Which allowance paid for a call. */
|
|
2
3
|
export type FundingSource =
|
|
3
4
|
/** The org-wide included window. */
|
|
@@ -37,6 +38,16 @@ export interface UsageLedger {
|
|
|
37
38
|
record(event: UsageEvent): Promise<void>;
|
|
38
39
|
/** Summed cost in [start, end). */
|
|
39
40
|
total(query: UsageQuery): Promise<number>;
|
|
41
|
+
/**
|
|
42
|
+
* Which windows this ledger can count (see `LedgerCoverage`).
|
|
43
|
+
*
|
|
44
|
+
* Optional, and omitting it means "not stated" rather than "counts nothing":
|
|
45
|
+
* the config checks skip a ledger that doesn't declare, exactly as they skip a
|
|
46
|
+
* caller who passes no ledger at all. Every implementation shipped here declares
|
|
47
|
+
* it, which is what lets one static check catch a plan whose included window the
|
|
48
|
+
* wired ledger cannot see — the failure that otherwise reads 0% forever.
|
|
49
|
+
*/
|
|
50
|
+
readonly covers?: LedgerCoverage;
|
|
40
51
|
}
|
|
41
52
|
/**
|
|
42
53
|
* The ledger this library has always had: the debits themselves.
|
|
@@ -64,16 +75,23 @@ export declare const USAGE_METER_EVENT = "billing_tools_usage";
|
|
|
64
75
|
* overshoot slightly. Irrelevant against a pool of a million credits; it is why
|
|
65
76
|
* seat packs, which are small, can keep using the exact balance path.
|
|
66
77
|
*
|
|
67
|
-
*
|
|
78
|
+
* The meter provisions itself on first use, like plan prices. `ensureMeters` is
|
|
79
|
+
* the same call made eagerly, for a deploy step that wants it to exist before a
|
|
80
|
+
* request does.
|
|
68
81
|
*/
|
|
69
82
|
export declare function stripeMeterUsageLedger(opts?: {
|
|
70
83
|
eventName?: string;
|
|
71
84
|
}): UsageLedger;
|
|
72
85
|
/**
|
|
73
|
-
*
|
|
86
|
+
* Ensure the usage meter exists, eagerly. Idempotent, like `ensurePlans`.
|
|
74
87
|
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
88
|
+
* No longer a prerequisite — the ledger provisions the meter on first use — but
|
|
89
|
+
* still worth calling from a deploy step or a setup script when you'd rather the
|
|
90
|
+
* meter existed before a customer's request pays for creating it, or want the
|
|
91
|
+
* failure to surface in a deploy log instead of a warning. Unlike the lazy path
|
|
92
|
+
* this one THROWS, because a setup script wants to know.
|
|
93
|
+
*
|
|
94
|
+
* Aggregates `sum` over the reported `value`, which is the credit cost.
|
|
77
95
|
*/
|
|
78
96
|
export declare function ensureMeters(opts?: {
|
|
79
97
|
eventName?: string;
|
|
@@ -82,8 +100,42 @@ export declare function ensureMeters(opts?: {
|
|
|
82
100
|
meterId: string;
|
|
83
101
|
created: boolean;
|
|
84
102
|
}>;
|
|
85
|
-
/** Forget resolved meter ids — for a test, or after archiving one.
|
|
103
|
+
/** Forget resolved meter ids — for a test, or after archiving one. Also clears the
|
|
104
|
+
* once-per-process complaint above, so a key that gains permission (or a test that
|
|
105
|
+
* wants to see it again) gets a fresh line rather than silence. */
|
|
86
106
|
export declare function invalidateMeters(): void;
|
|
107
|
+
export declare function stripeUsageLedger(opts?: {
|
|
108
|
+
eventName?: string;
|
|
109
|
+
/**
|
|
110
|
+
* Where a per-CALLER window is read from. Default: the balance ledger (exact,
|
|
111
|
+
* per-member, wallet-funded only). A store belongs here for a plan whose
|
|
112
|
+
* per-member window is INCLUDED.
|
|
113
|
+
*/
|
|
114
|
+
perCaller?: UsageLedger;
|
|
115
|
+
/**
|
|
116
|
+
* Where an ORG-wide window is read from. Default: the Stripe meter, which is
|
|
117
|
+
* the right answer today.
|
|
118
|
+
*
|
|
119
|
+
* A seam rather than a constant because this is the leg most likely to change:
|
|
120
|
+
* Stripe's Meter Usage Analytics API can answer the same question grouped by a
|
|
121
|
+
* dimension, and when it leaves preview it belongs here — at which point the
|
|
122
|
+
* per-caller leg can point at it too and the store disappears entirely.
|
|
123
|
+
*/
|
|
124
|
+
orgWide?: UsageLedger;
|
|
125
|
+
}): UsageLedger;
|
|
126
|
+
export declare function defaultUsageLedger(): UsageLedger;
|
|
127
|
+
/**
|
|
128
|
+
* Warn at boot about the plans whose included windows this ledger cannot count.
|
|
129
|
+
*
|
|
130
|
+
* Worth a line in a deploy log because the failure is silent and looks like
|
|
131
|
+
* generosity: the window reads 0, so nothing is ever refused. A ledger that
|
|
132
|
+
* declares no `covers` (a consumer's own) says nothing here — see `UsageLedger`.
|
|
133
|
+
*
|
|
134
|
+
* Called from `createMeter`, i.e. once per composition rather than per metered
|
|
135
|
+
* call, so it needs no de-duplication: a second line means a second meter was
|
|
136
|
+
* built, which is itself worth seeing.
|
|
137
|
+
*/
|
|
138
|
+
export declare function warnLedgerGaps(plans: PlanCatalog, ledger: UsageLedger): void;
|
|
87
139
|
/** The one method this needs from a driver. */
|
|
88
140
|
export interface SqlClient {
|
|
89
141
|
query<R = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage-ledger.d.ts","sourceRoot":"","sources":["../src/usage-ledger.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"usage-ledger.d.ts","sourceRoot":"","sources":["../src/usage-ledger.ts"],"names":[],"mappings":"AACA,OAAO,EAA8B,KAAK,cAAc,EAAE,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAmBpG,uCAAuC;AACvC,MAAM,MAAM,aAAa;AACvB,oCAAoC;AAClC,MAAM;AACR,8BAA8B;GAC5B,MAAM;AACR,uDAAuD;GACrD,QAAQ,CAAC;AAEb,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,iCAAiC;IACjC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,iEAAiE;IACjE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACrD;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,mCAAmC;IACnC,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C;;;;;;;;OAQG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC;CAClC;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,IAAI,WAAW,CAWtD;AAED,uEAAuE;AACvE,eAAO,MAAM,iBAAiB,wBAAwB,CAAC;AAEvD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAChC,WAAW,CA6Cb;AA8FD;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAChC,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GACtD,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAOhD;AAED;;oEAEoE;AACpE,wBAAgB,gBAAgB,IAAI,IAAI,CAIvC;AA2BD,wBAAgB,iBAAiB,CAC/B,IAAI,GAAE;IACJ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,WAAW,CAAC;CAClB,GACL,WAAW,CA8Bb;AAeD,wBAAgB,kBAAkB,IAAI,WAAW,CAEhD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAuB5E;AAgBD,+CAA+C;AAC/C,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,OAAO,EAAE,GACjB,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,EAAE,CAAA;KAAE,CAAC,CAAC;CAC3B;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,k6BAsB5B,CAAC;AAEF;;0DAE0D;AAC1D,wBAAsB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAE7E;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,GAAG,WAAW,CAsDlE"}
|
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,224 @@ 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();
|
|
208
|
+
}
|
|
209
|
+
// ── The composite: route each read to the store that can answer it ───────────
|
|
210
|
+
//
|
|
211
|
+
// Neither Stripe ledger above is the right answer on its own, and which one is
|
|
212
|
+
// wrong depends on the QUERY rather than on the config:
|
|
213
|
+
//
|
|
214
|
+
// an ORG-wide window (pool, `scope: "org"` limits, spend limit)
|
|
215
|
+
// → the meter. It sees every call, included ones too, and a summary is ONE
|
|
216
|
+
// request for any window width. This is the leg that removes a database:
|
|
217
|
+
// a 200 000-credit weekly window costs the same read as a 400-credit one.
|
|
218
|
+
//
|
|
219
|
+
// a PER-CALLER window (a seat pack, `scope: "caller"` limits)
|
|
220
|
+
// → balance transactions, which carry the caller on their metadata. Exact and
|
|
221
|
+
// per-member, but they only exist where money moved, so INCLUDED per-member
|
|
222
|
+
// usage is invisible to them.
|
|
223
|
+
//
|
|
224
|
+
// That last line is the honest limit of running with no store, and it is why this
|
|
225
|
+
// is not simply "the new default for everything": a plan that both includes usage
|
|
226
|
+
// AND meters it per member still needs `meter.db` (or the counter leg, when it
|
|
227
|
+
// lands). `createBilling` warns for exactly that combination rather than for any
|
|
228
|
+
// cap, which is the difference between "you need a database" and "you don't".
|
|
229
|
+
//
|
|
230
|
+
// Pass `perCaller` to swap the second leg for a store — `stripeUsageLedger({
|
|
231
|
+
// perCaller: postgresUsageLedger(db) })` is strictly better than the SQL ledger
|
|
232
|
+
// alone, because the org-wide reads stop scanning rows at all.
|
|
233
|
+
export function stripeUsageLedger(opts = {}) {
|
|
234
|
+
const meter = opts.orgWide ?? stripeMeterUsageLedger({ eventName: opts.eventName });
|
|
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;
|
|
247
|
+
return {
|
|
248
|
+
...(covers ? { covers } : {}),
|
|
249
|
+
async record(e) {
|
|
250
|
+
// The meter always, so org-wide windows see every call whatever funded it.
|
|
251
|
+
// The per-caller leg too, in the same round — for the balance ledger that is
|
|
252
|
+
// a no-op (the debit IS the record) and for a store it is the write. Never
|
|
253
|
+
// a second money movement: `deductCredits` owns that, and it has already
|
|
254
|
+
// run for a wallet-funded call.
|
|
255
|
+
await Promise.all([meter.record(e), perCaller.record(e)]);
|
|
256
|
+
},
|
|
257
|
+
total(q) {
|
|
258
|
+
const perCallerQuery = Boolean(q.filter?.callerKind || q.filter?.callerId);
|
|
259
|
+
return perCallerQuery ? perCaller.total(q) : meter.total(q);
|
|
260
|
+
},
|
|
261
|
+
};
|
|
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
|
+
}
|
|
116
310
|
}
|
|
117
311
|
/**
|
|
118
312
|
* The table, and the three indexes the two queries below actually use.
|
|
@@ -163,6 +357,9 @@ export async function ensureUsageLedgerTable(client) {
|
|
|
163
357
|
*/
|
|
164
358
|
export function postgresUsageLedger(client) {
|
|
165
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 },
|
|
166
363
|
async record(e) {
|
|
167
364
|
// ON CONFLICT on the idempotency key, so a retried execution is counted
|
|
168
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arnaudjnn/billing-tools",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12.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",
|