@arnaudjnn/billing-tools 2.19.0 → 3.0.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 +1 -1
- package/dist/adapters/workos-org.d.ts +23 -0
- package/dist/adapters/workos-org.d.ts.map +1 -1
- package/dist/adapters/workos-org.js +4 -2
- package/dist/adapters/workos-org.js.map +1 -1
- package/dist/bound-api.d.ts +173 -0
- package/dist/bound-api.d.ts.map +1 -0
- package/dist/bound-api.js +152 -0
- package/dist/bound-api.js.map +1 -0
- package/dist/cli/commands.js +25 -0
- package/dist/cli/commands.js.map +1 -1
- package/dist/create-billing.d.ts +128 -41
- package/dist/create-billing.d.ts.map +1 -1
- package/dist/create-billing.js +24 -14
- package/dist/create-billing.js.map +1 -1
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +7 -0
- package/dist/doctor.js.map +1 -1
- package/dist/entries/agent-auth.d.ts +5 -0
- package/dist/entries/agent-auth.d.ts.map +1 -0
- package/dist/entries/agent-auth.js +17 -0
- package/dist/entries/agent-auth.js.map +1 -0
- package/dist/entries/plans.d.ts +4 -0
- package/dist/entries/plans.d.ts.map +1 -0
- package/dist/entries/plans.js +36 -0
- package/dist/entries/plans.js.map +1 -0
- package/dist/entries/routes.d.ts +5 -0
- package/dist/entries/routes.d.ts.map +1 -0
- package/dist/entries/routes.js +17 -0
- package/dist/entries/routes.js.map +1 -0
- package/dist/entries/tools.d.ts +6 -0
- package/dist/entries/tools.d.ts.map +1 -0
- package/dist/entries/tools.js +20 -0
- package/dist/entries/tools.js.map +1 -0
- package/dist/index.d.ts +6 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +38 -15
- package/dist/index.js.map +1 -1
- package/dist/metering.d.ts +4 -3
- package/dist/metering.d.ts.map +1 -1
- package/dist/metering.js.map +1 -1
- package/dist/plan-model.d.ts +58 -3
- package/dist/plan-model.d.ts.map +1 -1
- package/dist/plan-model.js +61 -4
- 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/billing.d.ts +2 -1
- package/dist/tools/billing.d.ts.map +1 -1
- package/dist/tools/billing.js +185 -64
- package/dist/tools/billing.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 +210 -187
- package/dist/tools/management.js.map +1 -1
- package/dist/tools/register.d.ts +13 -1
- package/dist/tools/register.d.ts.map +1 -1
- package/dist/tools/register.js +28 -6
- package/dist/tools/register.js.map +1 -1
- package/dist/tools/subscription.d.ts +2 -1
- package/dist/tools/subscription.d.ts.map +1 -1
- package/dist/tools/subscription.js +115 -108
- package/dist/tools/subscription.js.map +1 -1
- package/dist/usage-ledger.d.ts +15 -37
- package/dist/usage-ledger.d.ts.map +1 -1
- package/dist/usage-ledger.js +24 -119
- package/dist/usage-ledger.js.map +1 -1
- package/dist/usage-scopes.d.ts +55 -0
- package/dist/usage-scopes.d.ts.map +1 -0
- package/dist/usage-scopes.js +284 -0
- package/dist/usage-scopes.js.map +1 -0
- package/dist/util/clearout.d.ts.map +1 -1
- package/dist/util/clearout.js +15 -3
- package/dist/util/clearout.js.map +1 -1
- package/package.json +21 -1
- package/dist/usage-counters.d.ts +0 -104
- package/dist/usage-counters.d.ts.map +0 -1
- package/dist/usage-counters.js +0 -214
- package/dist/usage-counters.js.map +0 -1
package/dist/usage-counters.js
DELETED
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
// Counting usage as COUNTERS rather than as events — the scale-correct store, and
|
|
2
|
-
// the one that works without SQL.
|
|
3
|
-
//
|
|
4
|
-
// ── Why counters, when `postgresUsageLedger` already works ──────────────────
|
|
5
|
-
//
|
|
6
|
-
// Because of what the seam is actually asked. Every read in this library is the
|
|
7
|
-
// same shape — `sum(cost) where org, [start, end), callerKind?, callerId?` — and
|
|
8
|
-
// every window is FIXED and UTC-aligned (`rateWindowFor`, `cycleWindowFor`). An
|
|
9
|
-
// append-only event log answers that by aggregating a range on the hot path of
|
|
10
|
-
// every metered call, over a table that grows by one row per call forever. At the
|
|
11
|
-
// volumes a plan actually declares (an Enterprise window of 200 000 credits a
|
|
12
|
-
// week) that is millions of rows a month whose only purpose is to be summed back
|
|
13
|
-
// into a handful of integers, plus the retention and partitioning work that
|
|
14
|
-
// follows.
|
|
15
|
-
//
|
|
16
|
-
// Counters answer it with a point read. One row per (org, scope, hour), so a
|
|
17
|
-
// caller making a thousand calls in an hour writes ONE row instead of a thousand,
|
|
18
|
-
// and the row count is bounded by time rather than by traffic.
|
|
19
|
-
//
|
|
20
|
-
// ── Why HOURLY buckets rather than one counter per declared window ──────────
|
|
21
|
-
//
|
|
22
|
-
// A counter keyed by the plan's own windows would be smaller still, but `record`
|
|
23
|
-
// would have to know which windows exist — and a window it failed to bump is
|
|
24
|
-
// usage counted by nothing, which reads as 0% and refuses no one. That failure
|
|
25
|
-
// looks like generosity, which is the exact class of defect this file is written
|
|
26
|
-
// to avoid. Bucketing by a fixed grain instead means `record` needs no plan
|
|
27
|
-
// knowledge at all: it bumps the bucket the event falls in, and `total` sums the
|
|
28
|
-
// buckets its window covers. Any window is answerable, including one added to the
|
|
29
|
-
// config later.
|
|
30
|
-
//
|
|
31
|
-
// An hour is the grain because `every: "hour"` is the tightest window the plan
|
|
32
|
-
// model can express, so it is the finest anything can ask for. A month is then at
|
|
33
|
-
// most 744 keys in ONE batched read.
|
|
34
|
-
//
|
|
35
|
-
// ── What this gives up ──────────────────────────────────────────────────────
|
|
36
|
-
//
|
|
37
|
-
// The audit trail. A counter cannot say WHICH actions made up a total, or when
|
|
38
|
-
// inside the hour. `postgresUsageLedger` keeps that and stays the right choice for
|
|
39
|
-
// a consumer who wants per-action history; the two satisfy the same seam, so a
|
|
40
|
-
// deployment can even write to both.
|
|
41
|
-
/** Milliseconds in the bucket grain. The tightest window a plan can declare. */
|
|
42
|
-
export const BUCKET_MS = 3_600_000;
|
|
43
|
-
/** The bucket an instant falls in: hours since the epoch, UTC-aligned. */
|
|
44
|
-
export const bucketOf = (atMs) => Math.floor(atMs / BUCKET_MS);
|
|
45
|
-
/**
|
|
46
|
-
* WHOSE counter. Derived identically on the write and read paths, which is the
|
|
47
|
-
* whole contract — a `total` that computed a different scope string from the same
|
|
48
|
-
* caller would read a counter nobody writes, and report 0 forever.
|
|
49
|
-
*
|
|
50
|
-
* `org` is every call in the workspace. A caller kind with no id is every caller
|
|
51
|
-
* of that kind (how a shared API seat is measured); with an id it is one member.
|
|
52
|
-
*/
|
|
53
|
-
export function scopeOf(filter) {
|
|
54
|
-
if (filter?.callerId)
|
|
55
|
-
return `u:${filter.callerId}`;
|
|
56
|
-
if (filter?.callerKind)
|
|
57
|
-
return `k:${filter.callerKind}`;
|
|
58
|
-
return "org";
|
|
59
|
-
}
|
|
60
|
-
/** Every scope a single event counts toward. An event is counted once per scope,
|
|
61
|
-
* so an org-wide read and a per-member read both see it. */
|
|
62
|
-
export function scopesFor(event) {
|
|
63
|
-
const scopes = ["org"];
|
|
64
|
-
if (event.caller?.kind)
|
|
65
|
-
scopes.push(`k:${event.caller.kind}`);
|
|
66
|
-
if (event.caller?.id)
|
|
67
|
-
scopes.push(`u:${event.caller.id}`);
|
|
68
|
-
return scopes;
|
|
69
|
-
}
|
|
70
|
-
/** `org|scope|bucket` — derivable from either side, so no index is needed to find
|
|
71
|
-
* a counter and a KV store works as well as a table. */
|
|
72
|
-
export const counterKey = (orgId, scope, bucket) => `${orgId}|${scope}|${bucket}`;
|
|
73
|
-
/**
|
|
74
|
-
* A `UsageLedger` backed by counters. Counts EVERYTHING — included and
|
|
75
|
-
* wallet-funded, org-wide and per member — which is what `covers` declares.
|
|
76
|
-
*/
|
|
77
|
-
export function counterUsageLedger(store, opts = {}) {
|
|
78
|
-
const retentionMs = opts.retentionMs ?? 400 * 86_400_000;
|
|
79
|
-
const maxKeys = Math.max(1, opts.maxKeysPerRead ?? 8_784);
|
|
80
|
-
return {
|
|
81
|
-
covers: { orgIncluded: true, callerIncluded: true },
|
|
82
|
-
async record(event) {
|
|
83
|
-
if (!event.cost)
|
|
84
|
-
return; // a free call moves no counter
|
|
85
|
-
const at = event.at ?? Date.now();
|
|
86
|
-
const bucket = bucketOf(at);
|
|
87
|
-
const keys = scopesFor(event).map((s) => counterKey(event.orgId, s, bucket));
|
|
88
|
-
// One call for every scope: a store can pipeline them, and a table can do it
|
|
89
|
-
// in a single multi-row upsert.
|
|
90
|
-
await store.add(keys, event.cost, at + retentionMs);
|
|
91
|
-
},
|
|
92
|
-
async total(query) {
|
|
93
|
-
// [start, end): the half-open window this library defines everywhere. The
|
|
94
|
-
// END bucket is inclusive when the window ends mid-bucket, because an event
|
|
95
|
-
// in that hour may fall inside the window — a counter cannot say where in
|
|
96
|
-
// the hour it happened, so it is counted. The overshoot is bounded by one
|
|
97
|
-
// bucket and only ever at the CURRENT edge, where the alternative is to
|
|
98
|
-
// ignore the usage that just happened.
|
|
99
|
-
const from = bucketOf(query.start);
|
|
100
|
-
const to = bucketOf((query.end ?? Date.now()) - 1);
|
|
101
|
-
if (to < from)
|
|
102
|
-
return 0;
|
|
103
|
-
const scope = scopeOf(query.filter);
|
|
104
|
-
const keys = [];
|
|
105
|
-
// Newest-first when clamped, so a window wider than the cap keeps the slice
|
|
106
|
-
// that decides whether the NEXT call is allowed.
|
|
107
|
-
const first = Math.max(from, to - maxKeys + 1);
|
|
108
|
-
for (let b = first; b <= to; b++)
|
|
109
|
-
keys.push(counterKey(query.orgId, scope, b));
|
|
110
|
-
return store.sum(keys);
|
|
111
|
-
},
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
// ── Backends ────────────────────────────────────────────────────────────────
|
|
115
|
-
/** The table + the one index its read uses. Idempotent, so it is safe to run from
|
|
116
|
-
* a migration on every deploy. Bounded by (orgs × scopes × hours kept), not by
|
|
117
|
-
* traffic — the reason to prefer it over `usage_events` at volume. */
|
|
118
|
-
export const USAGE_COUNTERS = `
|
|
119
|
-
CREATE TABLE IF NOT EXISTS usage_counters (
|
|
120
|
-
key text PRIMARY KEY,
|
|
121
|
-
used bigint NOT NULL,
|
|
122
|
-
-- Kept for bulk expiry; the read never filters on it.
|
|
123
|
-
stale timestamptz
|
|
124
|
-
);
|
|
125
|
-
CREATE INDEX IF NOT EXISTS usage_counters_stale_idx ON usage_counters (stale);
|
|
126
|
-
`;
|
|
127
|
-
/** @deprecated Renamed to `USAGE_COUNTERS`, alongside `USAGE_EVENTS`. */
|
|
128
|
-
export const USAGE_COUNTERS_DDL = USAGE_COUNTERS;
|
|
129
|
-
export async function ensureUsageCountersTable(client) {
|
|
130
|
-
await client.query(USAGE_COUNTERS);
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Counters in Postgres: one upsert per scope on write, one `SUM` over a primary-key
|
|
134
|
-
* lookup on read.
|
|
135
|
-
*
|
|
136
|
-
* `used = usage_counters.used + excluded.used` is the atomic increment — the row
|
|
137
|
-
* lock is held for the statement, so concurrent calls serialise instead of losing
|
|
138
|
-
* one another's writes.
|
|
139
|
-
*/
|
|
140
|
-
export function sqlUsageCounters(client) {
|
|
141
|
-
return {
|
|
142
|
-
async add(keys, amount, expiresAtMs) {
|
|
143
|
-
if (!keys.length)
|
|
144
|
-
return;
|
|
145
|
-
// One statement for every scope: unnest the keys rather than issuing N
|
|
146
|
-
// round trips on the hot path.
|
|
147
|
-
await client.query(`INSERT INTO usage_counters (key, used, stale)
|
|
148
|
-
SELECT k, $2::bigint, $3::timestamptz FROM unnest($1::text[]) AS k
|
|
149
|
-
ON CONFLICT (key) DO UPDATE
|
|
150
|
-
SET used = usage_counters.used + excluded.used,
|
|
151
|
-
stale = GREATEST(usage_counters.stale, excluded.stale)`, [keys, amount, expiresAtMs == null ? null : new Date(expiresAtMs).toISOString()]);
|
|
152
|
-
},
|
|
153
|
-
async sum(keys) {
|
|
154
|
-
if (!keys.length)
|
|
155
|
-
return 0;
|
|
156
|
-
const r = await client.query(`SELECT COALESCE(SUM(used), 0) AS total
|
|
157
|
-
FROM usage_counters WHERE key = ANY($1::text[])`, [keys]);
|
|
158
|
-
// bigint comes back as a string from `pg`; Number is exact to 2^53, far
|
|
159
|
-
// beyond any credit total.
|
|
160
|
-
return Number(r.rows[0]?.total ?? 0) || 0;
|
|
161
|
-
},
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
/** Delete expired buckets. Call it from a cron; nothing depends on it running —
|
|
165
|
-
* a stale bucket is simply never read once its window has passed. */
|
|
166
|
-
export async function pruneUsageCounters(client, now = Date.now()) {
|
|
167
|
-
await client.query(`DELETE FROM usage_counters WHERE stale IS NOT NULL AND stale < $1`, [
|
|
168
|
-
new Date(now).toISOString(),
|
|
169
|
-
]);
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* Counters in Redis: `INCRBY` per scope, one `MGET` per read.
|
|
173
|
-
*
|
|
174
|
-
* The expiry is set on every write rather than only on create. `PEXPIREAT` is
|
|
175
|
-
* idempotent and one round trip, whereas checking first is two and races — and a
|
|
176
|
-
* bucket that lost its expiry is a leak that only shows up as memory months later.
|
|
177
|
-
*/
|
|
178
|
-
export function redisUsageCounters(client) {
|
|
179
|
-
return {
|
|
180
|
-
async add(keys, amount, expiresAtMs) {
|
|
181
|
-
await Promise.all(keys.map(async (key) => {
|
|
182
|
-
await client.incrby(key, amount);
|
|
183
|
-
if (expiresAtMs != null && client.pexpireat)
|
|
184
|
-
await client.pexpireat(key, expiresAtMs);
|
|
185
|
-
}));
|
|
186
|
-
},
|
|
187
|
-
async sum(keys) {
|
|
188
|
-
if (!keys.length)
|
|
189
|
-
return 0;
|
|
190
|
-
const values = await client.mget(keys);
|
|
191
|
-
return values.reduce((acc, v) => acc + (v == null ? 0 : Number(v) || 0), 0);
|
|
192
|
-
},
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
/** In-memory counters, for tests and single-process development. Not for a
|
|
196
|
-
* deployment with more than one instance: each would count its own share, and the
|
|
197
|
-
* gate would allow the sum of every instance's window. */
|
|
198
|
-
export function memoryUsageCounters() {
|
|
199
|
-
const map = new Map();
|
|
200
|
-
return {
|
|
201
|
-
map,
|
|
202
|
-
async add(keys, amount) {
|
|
203
|
-
for (const key of keys)
|
|
204
|
-
map.set(key, (map.get(key) ?? 0) + amount);
|
|
205
|
-
},
|
|
206
|
-
async sum(keys) {
|
|
207
|
-
let total = 0;
|
|
208
|
-
for (const key of keys)
|
|
209
|
-
total += map.get(key) ?? 0;
|
|
210
|
-
return total;
|
|
211
|
-
},
|
|
212
|
-
};
|
|
213
|
-
}
|
|
214
|
-
//# sourceMappingURL=usage-counters.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"usage-counters.js","sourceRoot":"","sources":["../src/usage-counters.ts"],"names":[],"mappings":"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"}
|