meterflow 0.5.1 → 0.7.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 +121 -8
- package/dist/client.d.ts +7 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/index.cjs +68 -1
- package/dist/index.js +68 -1
- package/dist/index.mjs +68 -1
- package/dist/resources/credits.d.ts +12 -3
- package/dist/resources/credits.d.ts.map +1 -1
- package/dist/resources/portal.d.ts +24 -0
- package/dist/resources/portal.d.ts.map +1 -0
- package/dist/resources/subscriptions.d.ts +12 -1
- package/dist/resources/subscriptions.d.ts.map +1 -1
- package/dist/resources/webhooks.d.ts +31 -0
- package/dist/resources/webhooks.d.ts.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ Track what your customers use, enforce credit balances, and manage subscriptions
|
|
|
23
23
|
- [Usage events](#usage-events)
|
|
24
24
|
- [Subscriptions](#subscriptions)
|
|
25
25
|
- [Plans](#plans)
|
|
26
|
+
- [Webhook receipts](#webhook-receipts)
|
|
26
27
|
- [Entitlements — ask before you act](#entitlements--ask-before-you-act)
|
|
27
28
|
- [Idempotency — safe retries for writes](#idempotency--safe-retries-for-writes)
|
|
28
29
|
- [Automatic retries](#automatic-retries)
|
|
@@ -177,15 +178,26 @@ bal.total_granted; // "5250.000000"
|
|
|
177
178
|
bal.total_consumed; // "1705.000000"
|
|
178
179
|
```
|
|
179
180
|
|
|
180
|
-
**Transactions** — the
|
|
181
|
+
**Transactions** — the customer's history, newest first, **a page at a time**:
|
|
181
182
|
|
|
182
183
|
```typescript
|
|
183
|
-
const
|
|
184
|
-
for (const t of
|
|
184
|
+
const page = await client.credits.transactions("customer_123"); // 50 rows by default
|
|
185
|
+
for (const t of page.data) {
|
|
185
186
|
console.log(t.transaction_type, t.amount, t.balance_after, t.description, t.created_at);
|
|
186
187
|
}
|
|
188
|
+
|
|
189
|
+
// The whole history, page by page. `next_cursor` is null once there is nothing after it.
|
|
190
|
+
let cursor: string | undefined;
|
|
191
|
+
do {
|
|
192
|
+
const page = await client.credits.transactions("customer_123", { limit: 200, cursor });
|
|
193
|
+
handle(page.data);
|
|
194
|
+
cursor = page.next_cursor ?? undefined;
|
|
195
|
+
} while (cursor);
|
|
187
196
|
```
|
|
188
197
|
|
|
198
|
+
> **The cursor is opaque.** Pass back exactly what `next_cursor` gave you; do not build one, and do
|
|
199
|
+
> not read anything out of it. `limit` is 1–200 and defaults to 50.
|
|
200
|
+
|
|
189
201
|
> **Amounts are decimal strings.** Balances and amounts come back as strings (`"3545.000000"`) to avoid floating-point drift on money-like values. Parse deliberately (`Number(...)` or a decimal library) when you need arithmetic.
|
|
190
202
|
|
|
191
203
|
### Usage events
|
|
@@ -198,7 +210,7 @@ Record an event every time a customer does the thing you charge for. Events are
|
|
|
198
210
|
await client.usage.record({
|
|
199
211
|
event_name: "images.generated",
|
|
200
212
|
customer_external_id: "customer_123",
|
|
201
|
-
value: 1, // what the meter aggregates: 1 for counts, seconds/MB/etc. for sums
|
|
213
|
+
value: 1, // optional — what the meter aggregates: 1 for counts, seconds/MB/etc. for sums
|
|
202
214
|
properties: {}, // free-form context; {} when unused
|
|
203
215
|
timestamp: new Date().toISOString(), // optional — defaults to arrival time on the server
|
|
204
216
|
});
|
|
@@ -224,6 +236,40 @@ for (let i = 0; i < events.length; i += MAX_BATCH_EVENTS) {
|
|
|
224
236
|
}
|
|
225
237
|
```
|
|
226
238
|
|
|
239
|
+
### Record quantities, not calls
|
|
240
|
+
|
|
241
|
+
**A batch of 100 events is still 100 events.** Batching saves HTTP requests, not quota: each item in a `recordBatch` is its own record, and your plan's monthly allowance counts records. The thing that actually moves the number is sending **one event that carries the quantity**.
|
|
242
|
+
|
|
243
|
+
If your meter's aggregation is `sum`, MeterFlow adds up the `value` of its events — so one event with `value: 100` is **one** event against your monthly allowance and **100 units** against the meter. Record per unit of work instead of per API call:
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
// ❌ One event per call — 100 calls is 100 events against your plan.
|
|
247
|
+
for (const chunk of completion.chunks) {
|
|
248
|
+
await client.usage.record({
|
|
249
|
+
event_name: "tokens.used",
|
|
250
|
+
customer_external_id: "customer_123",
|
|
251
|
+
value: 1,
|
|
252
|
+
properties: {},
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// ✅ One event carrying the quantity — 1 event against your plan, 1,300 units on the meter.
|
|
257
|
+
await client.usage.record({
|
|
258
|
+
event_name: "tokens.used",
|
|
259
|
+
customer_external_id: "customer_123",
|
|
260
|
+
value: 1300, // a `sum` meter adds these up
|
|
261
|
+
properties: { model: "gpt-4o-mini" },
|
|
262
|
+
});
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
This is usually the difference between fitting a plan and outgrowing it: 1,000 users × 100 calls a day is ~3M events a month recorded per call, and ~30k recorded per session. Aggregate in your app over whatever window you can afford to lose on a crash — a request, a job, a minute — then send one event.
|
|
266
|
+
|
|
267
|
+
Two things to keep in mind:
|
|
268
|
+
|
|
269
|
+
- **It only helps a `sum` meter.** A `count` meter ignores `value` and counts occurrences, so there each occurrence has to be its own event. `max` and `min` read `value` as a measurement, not a quantity to add, and `unique_count` does not read it at all — it counts distinct values of the property its meter names.
|
|
270
|
+
- **`value` is optional.** Leave it out and MeterFlow fills it in: for a `sum`, `max` or `min` meter that names an `aggregation_field`, the numeric value of that property on the event; otherwise `1`. So the event above can be written `properties: { tokens: 1300 }` with no `value`, as long as the meter's `aggregation_field` is `tokens`. An explicit `value` always wins, a property that is absent or is not a number falls through to `1`, and a negative one is refused with a `422`.
|
|
271
|
+
- **Billing is unchanged.** A metered plan limit charges per unit — the event's `value` — so 100 units cost the same whether they arrived as 100 events or one. You are not rounding anyone's bill by batching.
|
|
272
|
+
|
|
227
273
|
**Summary** — a customer's usage, broken down by meter:
|
|
228
274
|
|
|
229
275
|
```typescript
|
|
@@ -262,11 +308,16 @@ console.log(sub.status); // "trialing" if the plan has trial days, else "active"
|
|
|
262
308
|
**List / get:**
|
|
263
309
|
|
|
264
310
|
```typescript
|
|
265
|
-
const
|
|
311
|
+
const page = await client.subscriptions.list(); // whole project (in your key's environment)
|
|
266
312
|
const theirs = await client.subscriptions.list({ customer_id: "customer_123" }); // one customer
|
|
313
|
+
const more = await client.subscriptions.list({ limit: 200, cursor: page.next_cursor ?? undefined });
|
|
267
314
|
const one = await client.subscriptions.get(sub.id);
|
|
315
|
+
|
|
316
|
+
page.data.forEach((subscription) => console.log(subscription.customer_external_id, subscription.status));
|
|
268
317
|
```
|
|
269
318
|
|
|
319
|
+
> **`list()` answers a page**, `{ data, next_cursor }` — `get()` still answers one subscription.
|
|
320
|
+
|
|
270
321
|
> Like all reads, these are scoped to the key's environment: a live key lists live subscriptions only, a test key test ones only.
|
|
271
322
|
|
|
272
323
|
**Update** — change status or metadata. Statuses: `active`, `trialing`, `past_due`, `paused`, `canceled`, `expired`:
|
|
@@ -299,6 +350,27 @@ plan.meter_limits; // included units + overage rate per meter
|
|
|
299
350
|
|
|
300
351
|
Typical use: render your pricing page or signup flow from `plans.list()` so it can never drift from what billing actually enforces.
|
|
301
352
|
|
|
353
|
+
### Webhook receipts
|
|
354
|
+
|
|
355
|
+
Webhooks are **read-only** through the SDK too: endpoints are registered in the dashboard, where the signing secret is shown once and never again. What the SDK gives you is the other half — which endpoints exist, and what MeterFlow actually sent them.
|
|
356
|
+
|
|
357
|
+
```typescript
|
|
358
|
+
const endpoints = await client.webhooks.list(); // this project's endpoints
|
|
359
|
+
const receipts = await client.webhooks.deliveries(endpoint_id); // newest first
|
|
360
|
+
receipts[0].event_type; // "usage.recorded"
|
|
361
|
+
receipts[0].status; // "pending" | "retrying" | "success" | "failed"
|
|
362
|
+
receipts[0].response_code; // what your server answered — 200, 500, or null if it never answered
|
|
363
|
+
receipts[0].attempts; // how many times we have tried
|
|
364
|
+
receipts[0].next_retry_at; // when we will try again, or null
|
|
365
|
+
receipts[0].payload; // exactly what we sent
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
Typical use: answering "did that event reach my endpoint?" from your own tooling instead of opening the dashboard — and reading `response_body` when the answer is no.
|
|
369
|
+
|
|
370
|
+
Two things to know. The list is capped at the **most recent 100** attempts per endpoint; it is a debugging surface, not an export. And it follows your key: a `mf_test_*` key reads test receipts, a `mf_live_*` key live ones, while the endpoint list itself is shared by both worlds, because an endpoint is configuration and receives events from each.
|
|
371
|
+
|
|
372
|
+
> This is not the same as [verifying webhooks](#verifying-webhooks) below. That proves a request your server just received really came from us; this reads what we sent.
|
|
373
|
+
|
|
302
374
|
### Entitlements — ask before you act
|
|
303
375
|
|
|
304
376
|
The one call to make **before** doing work for a customer: "may they use this feature — and how much is left?" A **hard** limit says no here; recording usage afterwards never blocks, so an app that skips this call gets an honest ledger but no enforcement.
|
|
@@ -307,7 +379,7 @@ The one call to make **before** doing work for a customer: "may they use this fe
|
|
|
307
379
|
const gate = await client.entitlements.check("customer_123", "images.generated");
|
|
308
380
|
|
|
309
381
|
if (!gate.allowed) {
|
|
310
|
-
// gate.reason: "hard_limit_reached" | "no_subscription" | "not_in_plan" | "insufficient_credits"
|
|
382
|
+
// gate.reason: "hard_limit_reached" | "no_subscription" | "not_in_plan" | "insufficient_credits" | "spend_cap_reached"
|
|
311
383
|
return showUpgradePrompt(gate); // gate.used / gate.included / gate.period_end are there for the copy
|
|
312
384
|
}
|
|
313
385
|
|
|
@@ -331,6 +403,30 @@ const { entitlements, period_end } = await client.entitlements.get("customer_123
|
|
|
331
403
|
|
|
332
404
|
Prefer to be told rather than to ask? Subscribe a webhook to `limit.reached` (see below).
|
|
333
405
|
|
|
406
|
+
### The balance portal — a page you don't have to build
|
|
407
|
+
|
|
408
|
+
Mint a short-lived link to a MeterFlow-hosted page showing **one** customer's balance and ledger.
|
|
409
|
+
Call it from your server; send the `url` to that customer.
|
|
410
|
+
|
|
411
|
+
```typescript
|
|
412
|
+
const link = await client.portal.createSession({
|
|
413
|
+
customer_external_id: "customer_123",
|
|
414
|
+
topup_url: "https://acme.test/billing", // your checkout — "buy more" goes here
|
|
415
|
+
return_url: "https://acme.test/app", // where "done" goes
|
|
416
|
+
expires_in_minutes: 60, // default 60, maximum 1440
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
sendEmail(customer.email, `Your balance: ${link.url}`);
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
The token in that link reads **that one customer's** balance and ledger, in the environment of the
|
|
423
|
+
key you minted it with, and nothing else: it cannot write, cannot name another customer, and is
|
|
424
|
+
refused everywhere else in the API. It is never your API key — never send that to anyone.
|
|
425
|
+
|
|
426
|
+
> **MeterFlow never takes the payment.** `topup_url` is a link we carry and hand back to the page;
|
|
427
|
+
> what happens there is between you and your own payment provider. Grant the credits with
|
|
428
|
+
> `credits.grant()` when your checkout tells you it was paid.
|
|
429
|
+
|
|
334
430
|
## Idempotency — safe retries for writes
|
|
335
431
|
|
|
336
432
|
Connections drop. When your app can't tell whether a write arrived, the correct move is to send it again **with the same idempotency key** — MeterFlow recognises the key and acts only once:
|
|
@@ -345,6 +441,17 @@ await client.credits.deduct(
|
|
|
345
441
|
|
|
346
442
|
Every write method accepts the option: `credits.grant/deduct`, `usage.record/recordBatch`, `subscriptions.create/update`. Use a key that identifies the *business operation* (order ID, job ID) — not a random value per attempt, which would defeat the purpose.
|
|
347
443
|
|
|
444
|
+
**A key is bound to the body you first used it with.** MeterFlow stores a fingerprint of the request alongside the key, so a retry only replays when it is genuinely the same request. Reuse the key with a *different* body and the call is refused with `ConflictError` (409) instead of quietly handing back the original record:
|
|
445
|
+
|
|
446
|
+
```typescript
|
|
447
|
+
await client.credits.grant({ customer_external_id: "customer_123", amount: 100, metadata: {} }, { idempotencyKey: "welcome-123" });
|
|
448
|
+
|
|
449
|
+
// Same key, different amount → ConflictError. Nothing is written, and the first grant stands.
|
|
450
|
+
await client.credits.grant({ customer_external_id: "customer_123", amount: 250, metadata: {} }, { idempotencyKey: "welcome-123" });
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
That is deliberate: silently returning the first record would turn two different operations into one and report success. One key per operation, reused only to retry that same operation. Keys stay namespaced per environment, so a `mf_test_` and a `mf_live_` key never collide.
|
|
454
|
+
|
|
348
455
|
## Automatic retries
|
|
349
456
|
|
|
350
457
|
The SDK retries transient failures for you — exponential backoff with jitter, 3 attempts by default:
|
|
@@ -377,7 +484,7 @@ Every error carries:
|
|
|
377
484
|
|
|
378
485
|
- **`requestId`** — the API's `X-Request-ID` for that call. Include it when contacting support; it pinpoints the exact request in our logs.
|
|
379
486
|
- **`statusCode`**, **`errorType`**, and **`retryable`** — for programmatic handling and structured logging.
|
|
380
|
-
- **`message`** — the API's own sentence (e.g. `Plan limit reached: the Drip plan includes
|
|
487
|
+
- **`message`** — the API's own sentence (e.g. `Plan limit reached: the Drip plan includes 50,000 usage events per month…`). A `ValidationError` appends its field detail (`Validation failed: amount: must be greater than 0`) and also exposes it structured as **`.fields`** (`{ field, message }[]`).
|
|
381
488
|
|
|
382
489
|
```typescript
|
|
383
490
|
import { MeterFlowError, InsufficientCreditsError, RateLimitError } from "meterflow";
|
|
@@ -440,6 +547,12 @@ Every delivery is a flat JSON object (`Content-Type: application/json`) with two
|
|
|
440
547
|
| `subscription.created` | a subscription is created | `customer_id`, `plan_id`, `subscription_id`, `status` |
|
|
441
548
|
| `subscription.updated` | a subscription is updated | `customer_id`, `subscription_id`, `status` |
|
|
442
549
|
| `limit.reached` | a customer first reaches a **hard** or **soft** limit's included units this billing period (once per meter per period; metered limits report through `credit.deducted` instead) | `customer_id`, `subscription_id`, `feature` (the meter's `event_name`), `meter_id`, `limit_type`, `included`, `used`, `period_start`, `period_end` |
|
|
550
|
+
| `balance.low` | a spend takes a customer's balance **down through** this endpoint's `low_balance_threshold` — a crossing, so it fires once and not again while they stay below. Raised by both doors that spend: `credits.deduct` and a metered usage charge. **Both crossing events follow from the endpoint's `low_balance_threshold`: set one and the API adds them, clear it and the API removes them — so a line is the only thing to configure.** | `customer_id`, `balance`, `threshold`, `suggested_topup` (the subscription's `topup_amount`, `null` when unset), `transaction_id` |
|
|
551
|
+
| `balance.exhausted` | a balance reaches zero, **or** a request is refused for want of credits (a deduction returning 402, or `entitlements.check` answering `insufficient_credits`). Unlike `balance.low` this repeats: every refused request is its own blocked request | `customer_id`, `balance`, `reason` (`balance_zero` / `insufficient_credits`), `requested_amount` and `feature` where they apply, `transaction_id` on the zero case |
|
|
552
|
+
| `subscription.renewed` | a billing period opens — either a paid period rolling forward or a **trial converting** to its first paid period, told apart by `reason` (the renewer emits no `subscription.updated` for either) | `customer_id`, `subscription_id`, `plan_id`, `status`, `reason` (`period_renewed` / `trial_converted`), `current_period_start`, `current_period_end`, `credits_granted` |
|
|
553
|
+
| `subscription.canceled` | a subscription's status becomes canceled — fired **alongside** `subscription.updated`, once, on the call that actually cancels | `customer_id`, `subscription_id`, `plan_id`, `canceled_at` |
|
|
554
|
+
| `balance.topped_up` | a grant takes a customer's balance **up through** this endpoint's `low_balance_threshold` — the upward mirror of `balance.low`, on the same per-endpoint line, so the endpoint told "low" is the one told "recovered". Subscribed together with `balance.low` by setting the threshold, never on its own | `customer_id`, `balance`, `threshold`, `amount`, `transaction_id` |
|
|
555
|
+
| `cap.reached` | a customer's credit spending reaches their subscription's `spend_cap` for the period — once per subscription per period, whether they landed on the cap or were refused by it. A refusal that still leaves headroom is not a reach and does not fire | `customer_id`, `subscription_id`, `cap`, `spent`, `period_start`, `period_end` |
|
|
443
556
|
|
|
444
557
|
For example, a `credit.granted` delivery:
|
|
445
558
|
|
|
@@ -509,6 +622,6 @@ await client.usage.record({
|
|
|
509
622
|
|
|
510
623
|
// Support asks: "what's Ana's situation?"
|
|
511
624
|
const balance = await client.credits.balance("ana");
|
|
512
|
-
const history = await client.credits.transactions("ana"
|
|
625
|
+
const { data: history } = await client.credits.transactions("ana");
|
|
513
626
|
const usage = await client.usage.summary("ana");
|
|
514
627
|
```
|
package/dist/client.d.ts
CHANGED
|
@@ -2,7 +2,9 @@ import { CreditsResource } from "./resources/credits";
|
|
|
2
2
|
import { UsageResource } from "./resources/usage";
|
|
3
3
|
import { SubscriptionsResource } from "./resources/subscriptions";
|
|
4
4
|
import { PlansResource } from "./resources/plans";
|
|
5
|
+
import { PortalResource } from "./resources/portal";
|
|
5
6
|
import { EntitlementsResource } from "./resources/entitlements";
|
|
7
|
+
import { WebhooksResource } from "./resources/webhooks";
|
|
6
8
|
export interface MeterFlowOptions {
|
|
7
9
|
apiKey: string;
|
|
8
10
|
baseUrl?: string;
|
|
@@ -22,13 +24,18 @@ export declare class MeterFlow {
|
|
|
22
24
|
private _usage?;
|
|
23
25
|
private _subscriptions?;
|
|
24
26
|
private _plans?;
|
|
27
|
+
private _portal?;
|
|
25
28
|
private _entitlements?;
|
|
29
|
+
private _webhooks?;
|
|
26
30
|
constructor(options: MeterFlowOptions);
|
|
31
|
+
get portal(): PortalResource;
|
|
27
32
|
get credits(): CreditsResource;
|
|
28
33
|
get usage(): UsageResource;
|
|
29
34
|
get subscriptions(): SubscriptionsResource;
|
|
30
35
|
get plans(): PlansResource;
|
|
31
36
|
get entitlements(): EntitlementsResource;
|
|
37
|
+
/** Read-only: the endpoints registered for this project, and what we sent them. */
|
|
38
|
+
get webhooks(): WebhooksResource;
|
|
32
39
|
/** @internal — used by resource classes only; not part of the public API */
|
|
33
40
|
request<T>(method: string, path: string, opts?: RequestOptions): Promise<T>;
|
|
34
41
|
}
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IAClD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,SAAS;IACpB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IAE7C,OAAO,CAAC,QAAQ,CAAC,CAAkB;IACnC,OAAO,CAAC,MAAM,CAAC,CAAgB;IAC/B,OAAO,CAAC,cAAc,CAAC,CAAwB;IAC/C,OAAO,CAAC,MAAM,CAAC,CAAgB;IAC/B,OAAO,CAAC,OAAO,CAAC,CAAiB;IACjC,OAAO,CAAC,aAAa,CAAC,CAAuB;IAC7C,OAAO,CAAC,SAAS,CAAC,CAAmB;gBAEzB,OAAO,EAAE,gBAAgB;IAerC,IAAI,MAAM,IAAI,cAAc,CAE3B;IAED,IAAI,OAAO,IAAI,eAAe,CAE7B;IAED,IAAI,KAAK,IAAI,aAAa,CAEzB;IAED,IAAI,aAAa,IAAI,qBAAqB,CAEzC;IAED,IAAI,KAAK,IAAI,aAAa,CAEzB;IAED,IAAI,YAAY,IAAI,oBAAoB,CAEvC;IAED,mFAAmF;IACnF,IAAI,QAAQ,IAAI,gBAAgB,CAE/B;IAED,4EAA4E;IAC5E,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC;CAG5E"}
|
package/dist/index.cjs
CHANGED
|
@@ -35,7 +35,7 @@ __export(index_exports, {
|
|
|
35
35
|
module.exports = __toCommonJS(index_exports);
|
|
36
36
|
|
|
37
37
|
// package.json
|
|
38
|
-
var version = "0.
|
|
38
|
+
var version = "0.7.0";
|
|
39
39
|
|
|
40
40
|
// src/errors.ts
|
|
41
41
|
var MeterFlowError = class extends Error {
|
|
@@ -245,6 +245,13 @@ var CreditsResource = class {
|
|
|
245
245
|
balance(customerId) {
|
|
246
246
|
return this.client.request("GET", `credits/${encodeURIComponent(customerId)}/balance`);
|
|
247
247
|
}
|
|
248
|
+
/**
|
|
249
|
+
* One page of the customer's ledger, newest first.
|
|
250
|
+
*
|
|
251
|
+
* The ledger grows with every charge, so it is read a page at a time: `data` holds the rows and
|
|
252
|
+
* `next_cursor` the mark for the page after this one (`null` on the last). Pass it back as
|
|
253
|
+
* `cursor` unchanged — it is opaque, and nothing but this API reads it.
|
|
254
|
+
*/
|
|
248
255
|
transactions(customerId, query) {
|
|
249
256
|
return this.client.request("GET", `credits/${encodeURIComponent(customerId)}/transactions`, {
|
|
250
257
|
...query !== void 0 && { query }
|
|
@@ -303,6 +310,12 @@ var SubscriptionsResource = class {
|
|
|
303
310
|
...opts?.idempotencyKey !== void 0 && { idempotencyKey: opts.idempotencyKey }
|
|
304
311
|
});
|
|
305
312
|
}
|
|
313
|
+
/**
|
|
314
|
+
* One page of the project's subscriptions in this key's environment, newest first.
|
|
315
|
+
*
|
|
316
|
+
* `data` holds the rows and `next_cursor` the mark for the page after this one (`null` on the
|
|
317
|
+
* last). Pass it back as `cursor` unchanged — it is opaque, and nothing but this API reads it.
|
|
318
|
+
*/
|
|
306
319
|
list(query) {
|
|
307
320
|
return this.client.request("GET", "subscriptions", {
|
|
308
321
|
...query !== void 0 && { query }
|
|
@@ -339,6 +352,29 @@ var PlansResource = class {
|
|
|
339
352
|
}
|
|
340
353
|
};
|
|
341
354
|
|
|
355
|
+
// src/resources/portal.ts
|
|
356
|
+
var PortalResource = class {
|
|
357
|
+
constructor(client) {
|
|
358
|
+
this.client = client;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Mint a link to the hosted balance page for one of your customers.
|
|
362
|
+
*
|
|
363
|
+
* Call this from **your** server and send the `url` to that customer — it carries a short-lived
|
|
364
|
+
* token that can read their balance and their ledger and nothing else, in the environment of the
|
|
365
|
+
* key you called with. It is never your API key, and it can write nothing.
|
|
366
|
+
*
|
|
367
|
+
* The page shows the balance and sends "buy more" to your own checkout (`topup_url`): MeterFlow
|
|
368
|
+
* never takes the payment. `expires_in_minutes` defaults to 60 and may not exceed 1440.
|
|
369
|
+
*
|
|
370
|
+
* The two reads behind the page are **not** on this client by design: they belong to the person
|
|
371
|
+
* holding the link, and this client holds a secret key.
|
|
372
|
+
*/
|
|
373
|
+
createSession(body) {
|
|
374
|
+
return this.client.request("POST", "portal/sessions", { body });
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
|
|
342
378
|
// src/resources/entitlements.ts
|
|
343
379
|
var EntitlementsResource = class {
|
|
344
380
|
constructor(client) {
|
|
@@ -356,6 +392,28 @@ var EntitlementsResource = class {
|
|
|
356
392
|
}
|
|
357
393
|
};
|
|
358
394
|
|
|
395
|
+
// src/resources/webhooks.ts
|
|
396
|
+
var WebhooksResource = class {
|
|
397
|
+
constructor(client) {
|
|
398
|
+
this.client = client;
|
|
399
|
+
}
|
|
400
|
+
/** Every endpoint registered for the key's project. Never includes a secret. */
|
|
401
|
+
list() {
|
|
402
|
+
return this.client.request("GET", "webhooks");
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* One endpoint's delivery attempts, newest first: the payload sent, the HTTP status that came
|
|
406
|
+
* back, how many attempts and when the next retry is due.
|
|
407
|
+
*
|
|
408
|
+
* Capped at the most recent 100, and scoped to the key's own environment — a `mf_test_*` key
|
|
409
|
+
* reads test receipts, a `mf_live_*` key live ones. A webhook belonging to another project
|
|
410
|
+
* answers 404.
|
|
411
|
+
*/
|
|
412
|
+
deliveries(webhookId) {
|
|
413
|
+
return this.client.request("GET", `webhooks/${encodeURIComponent(webhookId)}/deliveries`);
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
|
|
359
417
|
// src/client.ts
|
|
360
418
|
var MeterFlow = class {
|
|
361
419
|
options;
|
|
@@ -363,7 +421,9 @@ var MeterFlow = class {
|
|
|
363
421
|
_usage;
|
|
364
422
|
_subscriptions;
|
|
365
423
|
_plans;
|
|
424
|
+
_portal;
|
|
366
425
|
_entitlements;
|
|
426
|
+
_webhooks;
|
|
367
427
|
constructor(options) {
|
|
368
428
|
if (!options.apiKey.startsWith("mf_live_") && !options.apiKey.startsWith("mf_test_")) {
|
|
369
429
|
throw new Error("apiKey must start with mf_live_ or mf_test_");
|
|
@@ -378,6 +438,9 @@ var MeterFlow = class {
|
|
|
378
438
|
fetch: options.fetch ?? globalThis.fetch.bind(globalThis)
|
|
379
439
|
};
|
|
380
440
|
}
|
|
441
|
+
get portal() {
|
|
442
|
+
return this._portal ??= new PortalResource(this);
|
|
443
|
+
}
|
|
381
444
|
get credits() {
|
|
382
445
|
return this._credits ??= new CreditsResource(this);
|
|
383
446
|
}
|
|
@@ -393,6 +456,10 @@ var MeterFlow = class {
|
|
|
393
456
|
get entitlements() {
|
|
394
457
|
return this._entitlements ??= new EntitlementsResource(this);
|
|
395
458
|
}
|
|
459
|
+
/** Read-only: the endpoints registered for this project, and what we sent them. */
|
|
460
|
+
get webhooks() {
|
|
461
|
+
return this._webhooks ??= new WebhooksResource(this);
|
|
462
|
+
}
|
|
396
463
|
/** @internal — used by resource classes only; not part of the public API */
|
|
397
464
|
request(method, path, opts) {
|
|
398
465
|
return httpRequest(this.options, method, path, opts);
|
package/dist/index.js
CHANGED
|
@@ -35,7 +35,7 @@ __export(index_exports, {
|
|
|
35
35
|
module.exports = __toCommonJS(index_exports);
|
|
36
36
|
|
|
37
37
|
// package.json
|
|
38
|
-
var version = "0.
|
|
38
|
+
var version = "0.7.0";
|
|
39
39
|
|
|
40
40
|
// src/errors.ts
|
|
41
41
|
var MeterFlowError = class extends Error {
|
|
@@ -245,6 +245,13 @@ var CreditsResource = class {
|
|
|
245
245
|
balance(customerId) {
|
|
246
246
|
return this.client.request("GET", `credits/${encodeURIComponent(customerId)}/balance`);
|
|
247
247
|
}
|
|
248
|
+
/**
|
|
249
|
+
* One page of the customer's ledger, newest first.
|
|
250
|
+
*
|
|
251
|
+
* The ledger grows with every charge, so it is read a page at a time: `data` holds the rows and
|
|
252
|
+
* `next_cursor` the mark for the page after this one (`null` on the last). Pass it back as
|
|
253
|
+
* `cursor` unchanged — it is opaque, and nothing but this API reads it.
|
|
254
|
+
*/
|
|
248
255
|
transactions(customerId, query) {
|
|
249
256
|
return this.client.request("GET", `credits/${encodeURIComponent(customerId)}/transactions`, {
|
|
250
257
|
...query !== void 0 && { query }
|
|
@@ -303,6 +310,12 @@ var SubscriptionsResource = class {
|
|
|
303
310
|
...opts?.idempotencyKey !== void 0 && { idempotencyKey: opts.idempotencyKey }
|
|
304
311
|
});
|
|
305
312
|
}
|
|
313
|
+
/**
|
|
314
|
+
* One page of the project's subscriptions in this key's environment, newest first.
|
|
315
|
+
*
|
|
316
|
+
* `data` holds the rows and `next_cursor` the mark for the page after this one (`null` on the
|
|
317
|
+
* last). Pass it back as `cursor` unchanged — it is opaque, and nothing but this API reads it.
|
|
318
|
+
*/
|
|
306
319
|
list(query) {
|
|
307
320
|
return this.client.request("GET", "subscriptions", {
|
|
308
321
|
...query !== void 0 && { query }
|
|
@@ -339,6 +352,29 @@ var PlansResource = class {
|
|
|
339
352
|
}
|
|
340
353
|
};
|
|
341
354
|
|
|
355
|
+
// src/resources/portal.ts
|
|
356
|
+
var PortalResource = class {
|
|
357
|
+
constructor(client) {
|
|
358
|
+
this.client = client;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Mint a link to the hosted balance page for one of your customers.
|
|
362
|
+
*
|
|
363
|
+
* Call this from **your** server and send the `url` to that customer — it carries a short-lived
|
|
364
|
+
* token that can read their balance and their ledger and nothing else, in the environment of the
|
|
365
|
+
* key you called with. It is never your API key, and it can write nothing.
|
|
366
|
+
*
|
|
367
|
+
* The page shows the balance and sends "buy more" to your own checkout (`topup_url`): MeterFlow
|
|
368
|
+
* never takes the payment. `expires_in_minutes` defaults to 60 and may not exceed 1440.
|
|
369
|
+
*
|
|
370
|
+
* The two reads behind the page are **not** on this client by design: they belong to the person
|
|
371
|
+
* holding the link, and this client holds a secret key.
|
|
372
|
+
*/
|
|
373
|
+
createSession(body) {
|
|
374
|
+
return this.client.request("POST", "portal/sessions", { body });
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
|
|
342
378
|
// src/resources/entitlements.ts
|
|
343
379
|
var EntitlementsResource = class {
|
|
344
380
|
constructor(client) {
|
|
@@ -356,6 +392,28 @@ var EntitlementsResource = class {
|
|
|
356
392
|
}
|
|
357
393
|
};
|
|
358
394
|
|
|
395
|
+
// src/resources/webhooks.ts
|
|
396
|
+
var WebhooksResource = class {
|
|
397
|
+
constructor(client) {
|
|
398
|
+
this.client = client;
|
|
399
|
+
}
|
|
400
|
+
/** Every endpoint registered for the key's project. Never includes a secret. */
|
|
401
|
+
list() {
|
|
402
|
+
return this.client.request("GET", "webhooks");
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* One endpoint's delivery attempts, newest first: the payload sent, the HTTP status that came
|
|
406
|
+
* back, how many attempts and when the next retry is due.
|
|
407
|
+
*
|
|
408
|
+
* Capped at the most recent 100, and scoped to the key's own environment — a `mf_test_*` key
|
|
409
|
+
* reads test receipts, a `mf_live_*` key live ones. A webhook belonging to another project
|
|
410
|
+
* answers 404.
|
|
411
|
+
*/
|
|
412
|
+
deliveries(webhookId) {
|
|
413
|
+
return this.client.request("GET", `webhooks/${encodeURIComponent(webhookId)}/deliveries`);
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
|
|
359
417
|
// src/client.ts
|
|
360
418
|
var MeterFlow = class {
|
|
361
419
|
options;
|
|
@@ -363,7 +421,9 @@ var MeterFlow = class {
|
|
|
363
421
|
_usage;
|
|
364
422
|
_subscriptions;
|
|
365
423
|
_plans;
|
|
424
|
+
_portal;
|
|
366
425
|
_entitlements;
|
|
426
|
+
_webhooks;
|
|
367
427
|
constructor(options) {
|
|
368
428
|
if (!options.apiKey.startsWith("mf_live_") && !options.apiKey.startsWith("mf_test_")) {
|
|
369
429
|
throw new Error("apiKey must start with mf_live_ or mf_test_");
|
|
@@ -378,6 +438,9 @@ var MeterFlow = class {
|
|
|
378
438
|
fetch: options.fetch ?? globalThis.fetch.bind(globalThis)
|
|
379
439
|
};
|
|
380
440
|
}
|
|
441
|
+
get portal() {
|
|
442
|
+
return this._portal ??= new PortalResource(this);
|
|
443
|
+
}
|
|
381
444
|
get credits() {
|
|
382
445
|
return this._credits ??= new CreditsResource(this);
|
|
383
446
|
}
|
|
@@ -393,6 +456,10 @@ var MeterFlow = class {
|
|
|
393
456
|
get entitlements() {
|
|
394
457
|
return this._entitlements ??= new EntitlementsResource(this);
|
|
395
458
|
}
|
|
459
|
+
/** Read-only: the endpoints registered for this project, and what we sent them. */
|
|
460
|
+
get webhooks() {
|
|
461
|
+
return this._webhooks ??= new WebhooksResource(this);
|
|
462
|
+
}
|
|
396
463
|
/** @internal — used by resource classes only; not part of the public API */
|
|
397
464
|
request(method, path, opts) {
|
|
398
465
|
return httpRequest(this.options, method, path, opts);
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// package.json
|
|
2
|
-
var version = "0.
|
|
2
|
+
var version = "0.7.0";
|
|
3
3
|
|
|
4
4
|
// src/errors.ts
|
|
5
5
|
var MeterFlowError = class extends Error {
|
|
@@ -209,6 +209,13 @@ var CreditsResource = class {
|
|
|
209
209
|
balance(customerId) {
|
|
210
210
|
return this.client.request("GET", `credits/${encodeURIComponent(customerId)}/balance`);
|
|
211
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
* One page of the customer's ledger, newest first.
|
|
214
|
+
*
|
|
215
|
+
* The ledger grows with every charge, so it is read a page at a time: `data` holds the rows and
|
|
216
|
+
* `next_cursor` the mark for the page after this one (`null` on the last). Pass it back as
|
|
217
|
+
* `cursor` unchanged — it is opaque, and nothing but this API reads it.
|
|
218
|
+
*/
|
|
212
219
|
transactions(customerId, query) {
|
|
213
220
|
return this.client.request("GET", `credits/${encodeURIComponent(customerId)}/transactions`, {
|
|
214
221
|
...query !== void 0 && { query }
|
|
@@ -267,6 +274,12 @@ var SubscriptionsResource = class {
|
|
|
267
274
|
...opts?.idempotencyKey !== void 0 && { idempotencyKey: opts.idempotencyKey }
|
|
268
275
|
});
|
|
269
276
|
}
|
|
277
|
+
/**
|
|
278
|
+
* One page of the project's subscriptions in this key's environment, newest first.
|
|
279
|
+
*
|
|
280
|
+
* `data` holds the rows and `next_cursor` the mark for the page after this one (`null` on the
|
|
281
|
+
* last). Pass it back as `cursor` unchanged — it is opaque, and nothing but this API reads it.
|
|
282
|
+
*/
|
|
270
283
|
list(query) {
|
|
271
284
|
return this.client.request("GET", "subscriptions", {
|
|
272
285
|
...query !== void 0 && { query }
|
|
@@ -303,6 +316,29 @@ var PlansResource = class {
|
|
|
303
316
|
}
|
|
304
317
|
};
|
|
305
318
|
|
|
319
|
+
// src/resources/portal.ts
|
|
320
|
+
var PortalResource = class {
|
|
321
|
+
constructor(client) {
|
|
322
|
+
this.client = client;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Mint a link to the hosted balance page for one of your customers.
|
|
326
|
+
*
|
|
327
|
+
* Call this from **your** server and send the `url` to that customer — it carries a short-lived
|
|
328
|
+
* token that can read their balance and their ledger and nothing else, in the environment of the
|
|
329
|
+
* key you called with. It is never your API key, and it can write nothing.
|
|
330
|
+
*
|
|
331
|
+
* The page shows the balance and sends "buy more" to your own checkout (`topup_url`): MeterFlow
|
|
332
|
+
* never takes the payment. `expires_in_minutes` defaults to 60 and may not exceed 1440.
|
|
333
|
+
*
|
|
334
|
+
* The two reads behind the page are **not** on this client by design: they belong to the person
|
|
335
|
+
* holding the link, and this client holds a secret key.
|
|
336
|
+
*/
|
|
337
|
+
createSession(body) {
|
|
338
|
+
return this.client.request("POST", "portal/sessions", { body });
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
|
|
306
342
|
// src/resources/entitlements.ts
|
|
307
343
|
var EntitlementsResource = class {
|
|
308
344
|
constructor(client) {
|
|
@@ -320,6 +356,28 @@ var EntitlementsResource = class {
|
|
|
320
356
|
}
|
|
321
357
|
};
|
|
322
358
|
|
|
359
|
+
// src/resources/webhooks.ts
|
|
360
|
+
var WebhooksResource = class {
|
|
361
|
+
constructor(client) {
|
|
362
|
+
this.client = client;
|
|
363
|
+
}
|
|
364
|
+
/** Every endpoint registered for the key's project. Never includes a secret. */
|
|
365
|
+
list() {
|
|
366
|
+
return this.client.request("GET", "webhooks");
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* One endpoint's delivery attempts, newest first: the payload sent, the HTTP status that came
|
|
370
|
+
* back, how many attempts and when the next retry is due.
|
|
371
|
+
*
|
|
372
|
+
* Capped at the most recent 100, and scoped to the key's own environment — a `mf_test_*` key
|
|
373
|
+
* reads test receipts, a `mf_live_*` key live ones. A webhook belonging to another project
|
|
374
|
+
* answers 404.
|
|
375
|
+
*/
|
|
376
|
+
deliveries(webhookId) {
|
|
377
|
+
return this.client.request("GET", `webhooks/${encodeURIComponent(webhookId)}/deliveries`);
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
|
|
323
381
|
// src/client.ts
|
|
324
382
|
var MeterFlow = class {
|
|
325
383
|
options;
|
|
@@ -327,7 +385,9 @@ var MeterFlow = class {
|
|
|
327
385
|
_usage;
|
|
328
386
|
_subscriptions;
|
|
329
387
|
_plans;
|
|
388
|
+
_portal;
|
|
330
389
|
_entitlements;
|
|
390
|
+
_webhooks;
|
|
331
391
|
constructor(options) {
|
|
332
392
|
if (!options.apiKey.startsWith("mf_live_") && !options.apiKey.startsWith("mf_test_")) {
|
|
333
393
|
throw new Error("apiKey must start with mf_live_ or mf_test_");
|
|
@@ -342,6 +402,9 @@ var MeterFlow = class {
|
|
|
342
402
|
fetch: options.fetch ?? globalThis.fetch.bind(globalThis)
|
|
343
403
|
};
|
|
344
404
|
}
|
|
405
|
+
get portal() {
|
|
406
|
+
return this._portal ??= new PortalResource(this);
|
|
407
|
+
}
|
|
345
408
|
get credits() {
|
|
346
409
|
return this._credits ??= new CreditsResource(this);
|
|
347
410
|
}
|
|
@@ -357,6 +420,10 @@ var MeterFlow = class {
|
|
|
357
420
|
get entitlements() {
|
|
358
421
|
return this._entitlements ??= new EntitlementsResource(this);
|
|
359
422
|
}
|
|
423
|
+
/** Read-only: the endpoints registered for this project, and what we sent them. */
|
|
424
|
+
get webhooks() {
|
|
425
|
+
return this._webhooks ??= new WebhooksResource(this);
|
|
426
|
+
}
|
|
360
427
|
/** @internal — used by resource classes only; not part of the public API */
|
|
361
428
|
request(method, path, opts) {
|
|
362
429
|
return httpRequest(this.options, method, path, opts);
|
|
@@ -3,6 +3,7 @@ import type { components } from "../types/openapi";
|
|
|
3
3
|
type CreditGrantRequest = components["schemas"]["CreditGrantRequest"];
|
|
4
4
|
type CreditDeductRequest = components["schemas"]["CreditDeductRequest"];
|
|
5
5
|
type CreditTransactionResponse = components["schemas"]["CreditTransactionResponse"];
|
|
6
|
+
type CreditTransactionPage = components["schemas"]["CreditTransactionPage"];
|
|
6
7
|
type CreditBalanceResponse = components["schemas"]["CreditBalanceResponse"];
|
|
7
8
|
export interface GrantOptions {
|
|
8
9
|
idempotencyKey?: string;
|
|
@@ -10,9 +11,10 @@ export interface GrantOptions {
|
|
|
10
11
|
export interface DeductOptions {
|
|
11
12
|
idempotencyKey?: string;
|
|
12
13
|
}
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
/** One page of a list: how many rows, and where to carry on from. */
|
|
15
|
+
export interface PageQuery {
|
|
15
16
|
limit?: number;
|
|
17
|
+
cursor?: string;
|
|
16
18
|
}
|
|
17
19
|
export declare class CreditsResource {
|
|
18
20
|
private readonly client;
|
|
@@ -20,7 +22,14 @@ export declare class CreditsResource {
|
|
|
20
22
|
grant(body: CreditGrantRequest, opts?: GrantOptions): Promise<CreditTransactionResponse>;
|
|
21
23
|
deduct(body: CreditDeductRequest, opts?: DeductOptions): Promise<CreditTransactionResponse>;
|
|
22
24
|
balance(customerId: string): Promise<CreditBalanceResponse>;
|
|
23
|
-
|
|
25
|
+
/**
|
|
26
|
+
* One page of the customer's ledger, newest first.
|
|
27
|
+
*
|
|
28
|
+
* The ledger grows with every charge, so it is read a page at a time: `data` holds the rows and
|
|
29
|
+
* `next_cursor` the mark for the page after this one (`null` on the last). Pass it back as
|
|
30
|
+
* `cursor` unchanged — it is opaque, and nothing but this API reads it.
|
|
31
|
+
*/
|
|
32
|
+
transactions(customerId: string, query?: PageQuery): Promise<CreditTransactionPage>;
|
|
24
33
|
}
|
|
25
34
|
export {};
|
|
26
35
|
//# sourceMappingURL=credits.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credits.d.ts","sourceRoot":"","sources":["../../../src/resources/credits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,KAAK,kBAAkB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,oBAAoB,CAAC,CAAC;AACtE,KAAK,mBAAmB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,qBAAqB,CAAC,CAAC;AACxE,KAAK,yBAAyB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,2BAA2B,CAAC,CAAC;AACpF,KAAK,qBAAqB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,uBAAuB,CAAC,CAAC;AAE5E,MAAM,WAAW,YAAY;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"credits.d.ts","sourceRoot":"","sources":["../../../src/resources/credits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,KAAK,kBAAkB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,oBAAoB,CAAC,CAAC;AACtE,KAAK,mBAAmB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,qBAAqB,CAAC,CAAC;AACxE,KAAK,yBAAyB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,2BAA2B,CAAC,CAAC;AACpF,KAAK,qBAAqB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,uBAAuB,CAAC,CAAC;AAC5E,KAAK,qBAAqB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,uBAAuB,CAAC,CAAC;AAE5E,MAAM,WAAW,YAAY;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,qEAAqE;AACrE,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,SAAS;IAE9C,KAAK,CAAC,IAAI,EAAE,kBAAkB,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAOxF,MAAM,CAAC,IAAI,EAAE,mBAAmB,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAO3F,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAI3D;;;;;;OAMG;IACH,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,qBAAqB,CAAC;CAKpF"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { MeterFlow } from "../client";
|
|
2
|
+
import type { components } from "../types/openapi";
|
|
3
|
+
type PortalLinkRequest = components["schemas"]["PortalLinkRequest"];
|
|
4
|
+
type PortalLinkResponse = components["schemas"]["PortalLinkResponse"];
|
|
5
|
+
export declare class PortalResource {
|
|
6
|
+
private readonly client;
|
|
7
|
+
constructor(client: MeterFlow);
|
|
8
|
+
/**
|
|
9
|
+
* Mint a link to the hosted balance page for one of your customers.
|
|
10
|
+
*
|
|
11
|
+
* Call this from **your** server and send the `url` to that customer — it carries a short-lived
|
|
12
|
+
* token that can read their balance and their ledger and nothing else, in the environment of the
|
|
13
|
+
* key you called with. It is never your API key, and it can write nothing.
|
|
14
|
+
*
|
|
15
|
+
* The page shows the balance and sends "buy more" to your own checkout (`topup_url`): MeterFlow
|
|
16
|
+
* never takes the payment. `expires_in_minutes` defaults to 60 and may not exceed 1440.
|
|
17
|
+
*
|
|
18
|
+
* The two reads behind the page are **not** on this client by design: they belong to the person
|
|
19
|
+
* holding the link, and this client holds a secret key.
|
|
20
|
+
*/
|
|
21
|
+
createSession(body: PortalLinkRequest): Promise<PortalLinkResponse>;
|
|
22
|
+
}
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=portal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portal.d.ts","sourceRoot":"","sources":["../../../src/resources/portal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,KAAK,iBAAiB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,mBAAmB,CAAC,CAAC;AACpE,KAAK,kBAAkB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,oBAAoB,CAAC,CAAC;AAEtE,qBAAa,cAAc;IACb,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,SAAS;IAE9C;;;;;;;;;;;;OAYG;IACH,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAGpE"}
|
|
@@ -3,17 +3,28 @@ import type { components } from "../types/openapi";
|
|
|
3
3
|
type SubscriptionCreateRequest = components["schemas"]["SubscriptionCreateRequest"];
|
|
4
4
|
type SubscriptionUpdateRequest = components["schemas"]["SubscriptionUpdateRequest"];
|
|
5
5
|
type SubscriptionResponse = components["schemas"]["SubscriptionResponse"];
|
|
6
|
+
type SubscriptionPage = components["schemas"]["SubscriptionPage"];
|
|
6
7
|
export interface CreateOptions {
|
|
7
8
|
idempotencyKey?: string;
|
|
8
9
|
}
|
|
9
10
|
export interface ListQuery {
|
|
10
11
|
customer_id?: string;
|
|
12
|
+
/** Rows per page, 1–200 (50 by default). */
|
|
13
|
+
limit?: number;
|
|
14
|
+
/** `next_cursor` from the previous page; omit for the first. */
|
|
15
|
+
cursor?: string;
|
|
11
16
|
}
|
|
12
17
|
export declare class SubscriptionsResource {
|
|
13
18
|
private readonly client;
|
|
14
19
|
constructor(client: MeterFlow);
|
|
15
20
|
create(body: SubscriptionCreateRequest, opts?: CreateOptions): Promise<SubscriptionResponse>;
|
|
16
|
-
|
|
21
|
+
/**
|
|
22
|
+
* One page of the project's subscriptions in this key's environment, newest first.
|
|
23
|
+
*
|
|
24
|
+
* `data` holds the rows and `next_cursor` the mark for the page after this one (`null` on the
|
|
25
|
+
* last). Pass it back as `cursor` unchanged — it is opaque, and nothing but this API reads it.
|
|
26
|
+
*/
|
|
27
|
+
list(query?: ListQuery): Promise<SubscriptionPage>;
|
|
17
28
|
get(subscriptionId: string): Promise<SubscriptionResponse>;
|
|
18
29
|
update(subscriptionId: string, body: SubscriptionUpdateRequest, opts?: {
|
|
19
30
|
idempotencyKey?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subscriptions.d.ts","sourceRoot":"","sources":["../../../src/resources/subscriptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,KAAK,yBAAyB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,2BAA2B,CAAC,CAAC;AACpF,KAAK,yBAAyB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,2BAA2B,CAAC,CAAC;AACpF,KAAK,oBAAoB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,sBAAsB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"subscriptions.d.ts","sourceRoot":"","sources":["../../../src/resources/subscriptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,KAAK,yBAAyB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,2BAA2B,CAAC,CAAC;AACpF,KAAK,yBAAyB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,2BAA2B,CAAC,CAAC;AACpF,KAAK,oBAAoB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,sBAAsB,CAAC,CAAC;AAC1E,KAAK,gBAAgB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,kBAAkB,CAAC,CAAC;AAElE,MAAM,WAAW,aAAa;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,SAAS;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,qBAAqB;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,SAAS;IAE9C,MAAM,CAAC,IAAI,EAAE,yBAAyB,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAO5F;;;;;OAKG;IACH,IAAI,CAAC,KAAK,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAMlD,GAAG,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAI1D,MAAM,CAAC,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,yBAAyB,EAAE,IAAI,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAOlI,MAAM,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG9C"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { MeterFlow } from "../client";
|
|
2
|
+
import type { components } from "../types/openapi";
|
|
3
|
+
type WebhookResponse = components["schemas"]["WebhookResponse"];
|
|
4
|
+
type WebhookDeliveryResponse = components["schemas"]["WebhookDeliveryResponse"];
|
|
5
|
+
/**
|
|
6
|
+
* Webhook **receipts** — read-only on purpose.
|
|
7
|
+
*
|
|
8
|
+
* An endpoint is registered, edited and deleted in the dashboard, where the signing secret is
|
|
9
|
+
* shown once and never again. What an SDK consumer needs at 3am is the other half: which
|
|
10
|
+
* endpoints exist, and what MeterFlow actually sent them. That is this.
|
|
11
|
+
*
|
|
12
|
+
* Not to be confused with `meterflow/webhook`, which verifies the signature on a webhook your
|
|
13
|
+
* server has just received. This reads what we sent; that proves we sent it.
|
|
14
|
+
*/
|
|
15
|
+
export declare class WebhooksResource {
|
|
16
|
+
private readonly client;
|
|
17
|
+
constructor(client: MeterFlow);
|
|
18
|
+
/** Every endpoint registered for the key's project. Never includes a secret. */
|
|
19
|
+
list(): Promise<WebhookResponse[]>;
|
|
20
|
+
/**
|
|
21
|
+
* One endpoint's delivery attempts, newest first: the payload sent, the HTTP status that came
|
|
22
|
+
* back, how many attempts and when the next retry is due.
|
|
23
|
+
*
|
|
24
|
+
* Capped at the most recent 100, and scoped to the key's own environment — a `mf_test_*` key
|
|
25
|
+
* reads test receipts, a `mf_live_*` key live ones. A webhook belonging to another project
|
|
26
|
+
* answers 404.
|
|
27
|
+
*/
|
|
28
|
+
deliveries(webhookId: string): Promise<WebhookDeliveryResponse[]>;
|
|
29
|
+
}
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=webhooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../../src/resources/webhooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,KAAK,eAAe,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,iBAAiB,CAAC,CAAC;AAChE,KAAK,uBAAuB,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,yBAAyB,CAAC,CAAC;AAEhF;;;;;;;;;GASG;AACH,qBAAa,gBAAgB;IACf,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,SAAS;IAE9C,gFAAgF;IAChF,IAAI,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IAIlC;;;;;;;OAOG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,EAAE,CAAC;CAGlE"}
|