@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.
Files changed (57) hide show
  1. package/README.md +8 -1
  2. package/dist/adapters/workos-org.d.ts +4 -0
  3. package/dist/adapters/workos-org.d.ts.map +1 -1
  4. package/dist/adapters/workos-org.js +40 -0
  5. package/dist/adapters/workos-org.js.map +1 -1
  6. package/dist/allowance.d.ts.map +1 -1
  7. package/dist/allowance.js +44 -11
  8. package/dist/allowance.js.map +1 -1
  9. package/dist/billing.d.ts.map +1 -1
  10. package/dist/billing.js +6 -5
  11. package/dist/billing.js.map +1 -1
  12. package/dist/checkout.d.ts +11 -3
  13. package/dist/checkout.d.ts.map +1 -1
  14. package/dist/checkout.js +16 -2
  15. package/dist/checkout.js.map +1 -1
  16. package/dist/create-billing.d.ts +15 -14
  17. package/dist/create-billing.d.ts.map +1 -1
  18. package/dist/create-billing.js +17 -19
  19. package/dist/create-billing.js.map +1 -1
  20. package/dist/doctor.d.ts +39 -6
  21. package/dist/doctor.d.ts.map +1 -1
  22. package/dist/doctor.js +125 -42
  23. package/dist/doctor.js.map +1 -1
  24. package/dist/index.d.ts +3 -3
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +5 -3
  27. package/dist/index.js.map +1 -1
  28. package/dist/metering.d.ts +11 -7
  29. package/dist/metering.d.ts.map +1 -1
  30. package/dist/metering.js +8 -3
  31. package/dist/metering.js.map +1 -1
  32. package/dist/plan-model.d.ts +78 -3
  33. package/dist/plan-model.d.ts.map +1 -1
  34. package/dist/plan-model.js +74 -3
  35. package/dist/plan-model.js.map +1 -1
  36. package/dist/plans.d.ts +2 -2
  37. package/dist/plans.d.ts.map +1 -1
  38. package/dist/plans.js +1 -1
  39. package/dist/plans.js.map +1 -1
  40. package/dist/sync.d.ts.map +1 -1
  41. package/dist/sync.js +27 -0
  42. package/dist/sync.js.map +1 -1
  43. package/dist/tax.d.ts +33 -0
  44. package/dist/tax.d.ts.map +1 -1
  45. package/dist/tax.js +90 -0
  46. package/dist/tax.js.map +1 -1
  47. package/dist/tools/billing.d.ts.map +1 -1
  48. package/dist/tools/billing.js +20 -4
  49. package/dist/tools/billing.js.map +1 -1
  50. package/dist/types.d.ts +44 -10
  51. package/dist/types.d.ts.map +1 -1
  52. package/dist/types.js.map +1 -1
  53. package/dist/usage-ledger.d.ts +57 -5
  54. package/dist/usage-ledger.d.ts.map +1 -1
  55. package/dist/usage-ledger.js +220 -23
  56. package/dist/usage-ledger.js.map +1 -1
  57. package/package.json +1 -1
@@ -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
- * `ensureMeters` provisions the meter, in the same spirit as `ensurePlans`.
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
- * Create the usage meter if it doesn't exist. Idempotent, like `ensurePlans`.
86
+ * Ensure the usage meter exists, eagerly. Idempotent, like `ensurePlans`.
74
87
  *
75
- * Only needed by a config with an included window; a wallet-only product never
76
- * calls it. Aggregates `sum` over the reported `value`, which is the credit cost.
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":"AAmBA,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;CAC3C;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,IAAI,WAAW,CAQtD;AAED,uEAAuE;AACvE,eAAO,MAAM,iBAAiB,wBAAwB,CAAC;AAEvD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAChC,WAAW,CAoCb;AAmBD;;;;;GAKG;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,CAahD;AAED,sEAAsE;AACtE,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC;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,CAmDlE"}
1
+ {"version":3,"file":"usage-ledger.d.ts","sourceRoot":"","sources":["../src/usage-ledger.ts"],"names":[],"mappings":"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"}
@@ -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
- * `ensureMeters` provisions the meter, in the same spirit as `ensurePlans`.
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
- // Meter ids are stable per event name; resolving one is a list call, so memoise
77
- // it per process the way plan prices are.
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
- async function meterIdFor(eventName) {
80
- const hit = meterIds.get(eventName);
81
- if (hit !== undefined)
82
- return hit;
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
- * Create the usage meter if it doesn't exist. Idempotent, like `ensurePlans`.
127
+ * The meter id for `eventName`, creating the meter when it doesn't exist.
94
128
  *
95
- * Only needed by a config with an included window; a wallet-only product never
96
- * calls it. Aggregates `sum` over the reported `value`, which is the credit cost.
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
- export async function ensureMeters(opts = {}) {
99
- const eventName = opts.eventName ?? USAGE_METER_EVENT;
100
- const existing = await meterIdFor(eventName);
101
- if (existing)
102
- return { meterId: existing, created: false };
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: opts.displayName ?? "billing-tools usage",
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
- meterIds.set(eventName, meter.id);
111
- return { meterId: meter.id, created: true };
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
@@ -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;AAyDrD;;;;;;;;;GASG;AACH,MAAM,UAAU,wBAAwB;IACtC,OAAO;QACL,KAAK,CAAC,MAAM;YACV,2CAA2C;QAC7C,CAAC;QACD,2EAA2E;QAC3E,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC;KAC7E,CAAC;AACJ,CAAC;AAED,uEAAuE;AACvE,MAAM,CAAC,MAAM,iBAAiB,GAAG,qBAAqB,CAAC;AAEvD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAA+B,EAAE;IAEjC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,iBAAiB,CAAC;IACtD,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,CAAC;YACZ,MAAM,SAAS,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC;gBAC3C,UAAU,EAAE,SAAS;gBACrB,OAAO,EAAE;oBACP,wEAAwE;oBACxE,kBAAkB,EAAE,CAAC,CAAC,UAAU;oBAChC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;oBACrB,MAAM,EAAE,CAAC,CAAC,MAAM;oBAChB,MAAM,EAAE,CAAC,CAAC,MAAM;oBAChB,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACzD,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACpD;gBACD,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC7D,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACxD,CAAC,CAAC;QACL,CAAC;QACD,KAAK,CAAC,KAAK,CAAC,CAAC;YACX,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,SAAS,CAAC,CAAC;YAC1C,IAAI,CAAC,KAAK;gBAAE,OAAO,CAAC,CAAC;YACrB,uEAAuE;YACvE,MAAM,WAAW,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,MAAM,CAAC,GAAG,EAAE,CAAC;YACjE,MAAM,SAAS,GAAG,MAAM,SAAS,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAC,KAAK,EAAE;gBAC3E,QAAQ,EAAE,CAAC,CAAC,UAAU;gBACtB,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC;gBAChC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;gBAC1C,KAAK,EAAE,GAAG;aACX,CAAC,CAAC;YACH,2EAA2E;YAC3E,2EAA2E;YAC3E,qCAAqC;YACrC,OAAO,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC;QACxE,CAAC;KACF,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,0CAA0C;AAC1C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAyB,CAAC;AAElD,KAAK,UAAU,UAAU,CAAC,SAAiB;IACzC,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACpC,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,GAAG,CAAC;IAClC,IAAI,KAAK,EAAE,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;QACxF,IAAI,CAAC,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YAC/B,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;YAC9B,OAAO,CAAC,CAAC,EAAE,CAAC;QACd,CAAC;IACH,CAAC;IACD,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC9B,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAqD,EAAE;IAEvD,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,iBAAiB,CAAC;IACtD,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,SAAS,CAAC,CAAC;IAC7C,IAAI,QAAQ;QAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC3D,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;QACpD,YAAY,EAAE,IAAI,CAAC,WAAW,IAAI,qBAAqB;QACvD,UAAU,EAAE,SAAS;QACrB,mBAAmB,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;QACvC,gBAAgB,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE;QAC5E,cAAc,EAAE,EAAE,iBAAiB,EAAE,OAAO,EAAE;KAC/C,CAAC,CAAC;IACH,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;IAClC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC9C,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,gBAAgB;IAC9B,QAAQ,CAAC,KAAK,EAAE,CAAC;AACnB,CAAC;AAwBD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;;;;;;;;;;;;;;;;;;;;;;CAsB/B,CAAC;AAEF;;0DAE0D;AAC1D,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,MAAiB;IAC5D,MAAM,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;AACvC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAiB;IACnD,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,CAAC;YACZ,wEAAwE;YACxE,2EAA2E;YAC3E,0EAA0E;YAC1E,MAAM,MAAM,CAAC,KAAK,CAChB;;;oFAG4E,EAC5E;gBACE,CAAC,CAAC,KAAK;gBACP,CAAC,CAAC,UAAU,IAAI,IAAI;gBACpB,CAAC,CAAC,MAAM;gBACR,CAAC,CAAC,IAAI;gBACN,CAAC,CAAC,MAAM;gBACR,CAAC,CAAC,MAAM,EAAE,IAAI,IAAI,IAAI;gBACtB,CAAC,CAAC,MAAM,EAAE,EAAE,IAAI,IAAI;gBACpB,CAAC,CAAC,cAAc,IAAI,IAAI;gBACxB,CAAC,CAAC,EAAE,IAAI,IAAI,CAAC,GAAG,EAAE;aACnB,CACF,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,KAAK,CAAC,CAAC;YACX,4EAA4E;YAC5E,0EAA0E;YAC1E,MAAM,MAAM,GAAc,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;YAC7C,IAAI,GAAG,GAAG;;;wDAGwC,CAAC;YACnD,IAAI,CAAC,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC;gBAClB,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;gBACnB,GAAG,IAAI,2BAA2B,MAAM,CAAC,MAAM,YAAY,CAAC;YAC9D,CAAC;YACD,4EAA4E;YAC5E,sEAAsE;YACtE,IAAI,CAAC,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC;gBACzB,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;gBACjC,GAAG,IAAI,uBAAuB,MAAM,CAAC,MAAM,EAAE,CAAC;YAChD,CAAC;YACD,IAAI,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC;gBACvB,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBAC/B,GAAG,IAAI,qBAAqB,MAAM,CAAC,MAAM,EAAE,CAAC;YAC9C,CAAC;YACD,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,KAAK,CAAoB,GAAG,EAAE,MAAM,CAAC,CAAC;YAC7D,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC;QAC/B,CAAC;KACF,CAAC;AACJ,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.10.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",