@usebillow/sdk 0.8.0 → 0.10.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 (49) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/{billing-B-VyZCXV.d.cts → billing-8ug1Gw05.d.cts} +14 -10
  3. package/dist/{billing-CgjcWmvb.d.ts → billing-Bs10EcjR.d.ts} +14 -10
  4. package/dist/{billing-status-BZQN_gm7.d.cts → billing-status-DZkB0VPK.d.cts} +5 -5
  5. package/dist/{billing-status-BZQN_gm7.d.ts → billing-status-DZkB0VPK.d.ts} +5 -5
  6. package/dist/{chunk-CCG4F5FK.js → chunk-47J7FYM5.js} +2 -2
  7. package/dist/chunk-47J7FYM5.js.map +1 -0
  8. package/dist/{chunk-J6JIZGWB.js → chunk-XKN7ZRAR.js} +81 -22
  9. package/dist/chunk-XKN7ZRAR.js.map +1 -0
  10. package/dist/config.cjs +3 -3
  11. package/dist/config.cjs.map +1 -1
  12. package/dist/config.d.cts +10 -10
  13. package/dist/config.d.ts +10 -10
  14. package/dist/config.js +3 -3
  15. package/dist/config.js.map +1 -1
  16. package/dist/{hosted-domains-BbuyxnuH.d.cts → hosted-domains-Ci6jeNAe.d.cts} +124 -17
  17. package/dist/{hosted-domains-BP91tg9P.d.ts → hosted-domains-DSs5Iw9U.d.ts} +124 -17
  18. package/dist/index.cjs +79 -20
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.cts +89 -55
  21. package/dist/index.d.ts +89 -55
  22. package/dist/index.js +2 -2
  23. package/dist/ingestion.cjs.map +1 -1
  24. package/dist/ingestion.d.cts +19 -19
  25. package/dist/ingestion.d.ts +19 -19
  26. package/dist/ingestion.js.map +1 -1
  27. package/dist/react.cjs +28 -5
  28. package/dist/react.cjs.map +1 -1
  29. package/dist/react.d.cts +7 -7
  30. package/dist/react.d.ts +7 -7
  31. package/dist/react.js +2 -2
  32. package/dist/react.js.map +1 -1
  33. package/dist/server.cjs.map +1 -1
  34. package/dist/server.d.cts +12 -12
  35. package/dist/server.d.ts +12 -12
  36. package/dist/server.js.map +1 -1
  37. package/dist/status.cjs.map +1 -1
  38. package/dist/status.d.cts +1 -1
  39. package/dist/status.d.ts +1 -1
  40. package/dist/status.js +1 -1
  41. package/dist/webhooks.cjs.map +1 -1
  42. package/dist/webhooks.d.cts +27 -14
  43. package/dist/webhooks.d.ts +27 -14
  44. package/dist/webhooks.js.map +1 -1
  45. package/package.json +1 -1
  46. package/dist/chunk-CCG4F5FK.js.map +0 -1
  47. package/dist/chunk-J6JIZGWB.js.map +0 -1
  48. package/dist/{index.d-CKQAhQfJ.d.ts → index.d-DSEYhV2c.d.cts} +2 -2
  49. package/dist/{index.d-CKQAhQfJ.d.cts → index.d-DSEYhV2c.d.ts} +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @usebillow/sdk
2
2
 
3
+ ## 0.10.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 935c12d: Included credits now follow plan changes and early endings. A plan upgrade inside the period raises its current and later Included Credit Windows to the new plan's rule (a high-water mark, never lowered), and the difference is issued at once as an `included` grant with ledger reason `subscription_upgrade`; `CreditIncludedWindow` gains `raisedAt`, when an upgrade last raised the window. An immediate cancellation, or a lost chargeback of the payment for the period, ends the period's unspent included credits and its later refills: the window reads `ended` with its `endedAt` and `endCause` (`canceled` or `charged_back`), and the grant's unheld credits expire with ledger reason `subscription_canceled` or `subscription_charged_back`. The `credit_grant.expired` webhook data's `reason` is now `grant_expired`, `subscription_canceled` or `subscription_charged_back`.
8
+ - a41c39f: `BillowApiError.retryAfterSeconds` says how many seconds to wait before trying again, read from the response's `Retry-After` header: whole seconds, or an HTTP date (`Sun, 06 Nov 1994 08:49:37 GMT`) counted from now, at most an hour. billow sends it with a `429 rate_limited`; it is undefined when the response did not say, or said something that is neither. With `maxRetries` set, the SDK already waited between attempts (now at most an hour, however long the header asks); a caller that does not retry can now tell its user when to try again.
9
+
10
+ ### Patch Changes
11
+
12
+ - a41c39f: Usage line descriptions count their units in words: `Usage - 1 unit over allowance` or `Usage - 7 units over allowance` (and `Usage - api: 7 units over allowance (2026-03-01 - 2026-04-01)` for a reset window) instead of `unit(s)`. This is the text of an invoice's usage `lineItems` from `invoices.get`, and of an invoice's `reason` (its first line) from `invoices.list` and the portal's `invoices.list` and `invoices.get` when that line is a usage line. Invoices issued before keep the descriptions they were issued with. No SDK code changed.
13
+
14
+ ## 0.9.0
15
+
16
+ ### Minor Changes
17
+
18
+ - 598ec24: Included credits are now issued: each period Billow grants a subscription on a Price with an Included Credit Rule records its Included Credit Windows and issues them as `included` grants. New `credits.includedWindows.list` reads them - for one or more subscriptions (`subscription`, an id or a list) or a customer (`customer`), newest first, auto-paginating by cursor, with `current: true` for each subscription's latest started window - each with its bounds and its billing period's, `nextRefillAt`, `entitled`, `issued` and a `state` (`scheduled`, `pending`, `blocked` with its `blockedCause`, `issued`, `suspended`, `lapsed`, `ended` or `account_closed`). `CreditBalance` gains `includedPeriods` (each subscription's current window, with `periodStart`, `periodEnd` and `nextRefillAt`), and its `currentPeriod` now describes the current windows (its `end` is always set). `CreditLedgerEntry` gains `subscriptionId`. The `credit_grant.created` webhook data gains `subscriptionId`, `periodStart` and `periodEnd`, and `credit_grant.expired` gains `reason`. The data export's credits gain `includedWindows`. New types: `CreditIncludedWindow`, `CreditIncludedWindowListParams`, `CreditWindowState`, `IncludedCredits` and `IncludedPeriod`.
19
+
20
+ ### Patch Changes
21
+
22
+ - 8d2c420: Invoice lines and a product's prices and entitlements always come back in a stable order. `invoices.get` lists an invoice's `lineItems` in the order the invoice lists them (as its PDF and receipt email do), and a product's `prices` and `entitlements` come back in the order they were given to `products.create` or last to `products.update`; an invoice's usage lines follow the price order too. The customer data export lists each invoice's lines in order and carries each line's `position`.
23
+ - 2b175c1: Document `subscriptions.pause` and `subscriptions.resume`. Paused time is never billed: usage recorded while a subscription is paused is never invoiced. A subscription resumed before its paid period ends carries on and renews at `currentPeriodEnd`; one resumed after it ended starts a fresh full period at the moment of resume and is charged for it at once, like a renewal, together with the ended period's usage (a declined charge returns it `past_due`). A paused trial resumes `trialing`. Resuming an already active or trialing subscription changes nothing; resuming one that is `past_due` or `unpaid` is refused. Pause, resume, plan, item and coupon changes are refused while one of the subscription's invoices is still being collected.
24
+
3
25
  ## 0.8.0
4
26
 
5
27
  ### Minor Changes
@@ -1,5 +1,5 @@
1
- import { A as ActivatedSubscriptionResponse, C as CreateSubscriptionResponse, P as PendingSubscriptionCheckoutResponse, a as ProductResponse, b as ProductEntitlementResponse, c as ProductPriceResponse, S as SubscriptionResponse, d as SubscriptionDetailResponse, e as SubscriptionItemResponse } from './index.d-CKQAhQfJ.cjs';
2
- import { C as ChargeStatus } from './billing-status-BZQN_gm7.cjs';
1
+ import { A as ActivatedSubscriptionResponse, C as CreateSubscriptionResponse, P as PendingSubscriptionCheckoutResponse, a as ProductResponse, b as ProductEntitlementResponse, c as ProductPriceResponse, S as SubscriptionResponse, d as SubscriptionDetailResponse, e as SubscriptionItemResponse } from './index.d-DSEYhV2c.cjs';
2
+ import { C as ChargeStatus } from './billing-status-DZkB0VPK.cjs';
3
3
 
4
4
  /** Public SDK types for this domain. Re-exported by ../types.ts. */
5
5
  interface BillowOptions {
@@ -16,14 +16,14 @@ interface BillowOptions {
16
16
  */
17
17
  timeoutMs?: number;
18
18
  /**
19
- * How many times to retry a transient failure. Retries are **opt-in** — the default is
19
+ * How many times to retry a transient failure. Retries are **opt-in** - the default is
20
20
  * `0`. Only requests that are safe to repeat are retried: every `GET`, plus **any** method
21
21
  * on a `429` (a rate-limited request never executed). A write (`POST`/`PATCH`/`DELETE`) is
22
22
  * never retried on a `5xx`/network error, since it may have already applied.
23
23
  */
24
24
  maxRetries?: number;
25
25
  /**
26
- * Base backoff in milliseconds between retries — exponential (`base × 2^attempt`), and a
26
+ * Base backoff in milliseconds between retries - exponential (`base × 2^attempt`), and a
27
27
  * `Retry-After` response header takes precedence when present. Defaults to 500.
28
28
  */
29
29
  retryBackoffMs?: number;
@@ -32,7 +32,7 @@ interface BillowOptions {
32
32
  * Per-call overrides passed as the last argument to a resource method.
33
33
  * - `signal` cancels the request (a caller abort is surfaced immediately and never retried).
34
34
  * - `timeoutMs` overrides the client's default timeout for this call (applied per attempt).
35
- * - `idempotencyKey` sends an `Idempotency-Key` and makes the write **safe to retry** — reused
35
+ * - `idempotencyKey` sends an `Idempotency-Key` and makes the write **safe to retry** - reused
36
36
  * verbatim on every attempt. Only exposed on writes the server replays (create/attach/track/refund).
37
37
  */
38
38
  interface RequestOptions {
@@ -44,7 +44,7 @@ interface RequestOptions {
44
44
  type IdempotentRequestOptions = RequestOptions & {
45
45
  idempotencyKey: string;
46
46
  };
47
- /** Per-call overrides for reads and non-replayable writes — cancellation + timeout, no idempotency key. */
47
+ /** Per-call overrides for reads and non-replayable writes - cancellation + timeout, no idempotency key. */
48
48
  type CallOptions = Omit<RequestOptions, "idempotencyKey">;
49
49
  interface Customer {
50
50
  id: string;
@@ -77,7 +77,7 @@ interface MeterFilter {
77
77
  key: string;
78
78
  values: string[];
79
79
  }
80
- /** A meter's measurement config (ADR-0011) — how a metered feature's usage aggregates. */
80
+ /** A meter's measurement config (ADR-0011) - how a metered feature's usage aggregates. */
81
81
  interface MeterConfig {
82
82
  aggregation: MeterAggregation;
83
83
  eventProperty?: string | null;
@@ -142,7 +142,9 @@ interface CreateProductInput {
142
142
  isAddOn?: boolean;
143
143
  /** Free-form string map that round-trips on the product + on subscription.* webhooks. */
144
144
  metadata?: Record<string, string>;
145
+ /** In the order the product lists them: every read of it, and an invoice's usage lines, keep it. */
145
146
  prices: PriceInput[];
147
+ /** In the order the product lists them: every read of it keeps it. */
146
148
  entitlements?: EntitlementInput[];
147
149
  }
148
150
  /** A price in a product edit: carry `id` to update that row in place, omit it to add. */
@@ -169,7 +171,9 @@ interface UpdateProductInput {
169
171
  archived?: boolean;
170
172
  /** Replace the product's metadata map. */
171
173
  metadata?: Record<string, string>;
174
+ /** The product's whole price list, in the order it lists them from now on. */
172
175
  prices?: UpdatePriceInput[];
176
+ /** The product's whole entitlement list, in the order it lists them from now on. */
173
177
  entitlements?: EntitlementInput[];
174
178
  }
175
179
  interface Feature {
@@ -182,7 +186,7 @@ interface Feature {
182
186
  }
183
187
  /**
184
188
  * An in-place edit to a feature. `name` is always allowed; `meter` re-configures a
185
- * metered feature's aggregation — but the server refuses a meter change once usage has
189
+ * metered feature's aggregation - but the server refuses a meter change once usage has
186
190
  * been recorded (it would rewrite billed history). At least one field must be present.
187
191
  */
188
192
  interface UpdateFeatureInput {
@@ -217,7 +221,7 @@ interface CreateUsageAlertInput {
217
221
  }
218
222
  interface TrackResult {
219
223
  ok: true;
220
- /** True when the idempotency key was already seen — the call was a no-op. */
224
+ /** True when the idempotency key was already seen - the call was a no-op. */
221
225
  deduplicated: boolean;
222
226
  /** Remaining balance for the feature; `null` if unlimited. */
223
227
  balance: number | null;
@@ -234,7 +238,7 @@ type Product = ProductResponse;
234
238
  type Subscription = SubscriptionResponse;
235
239
  /** A single fetched subscription (`subscriptions.get`) - {@link Subscription} plus the stable `customerExternalId` + `productSlug`. */
236
240
  type SubscriptionDetail = SubscriptionDetailResponse;
237
- /** A subscription line item — the base plan or an attached add-on (Phase D2). */
241
+ /** A subscription line item - the base plan or an attached add-on (Phase D2). */
238
242
  type SubscriptionItem = SubscriptionItemResponse;
239
243
  interface CreateSubscriptionInput {
240
244
  customerId: string;
@@ -1,5 +1,5 @@
1
- import { A as ActivatedSubscriptionResponse, C as CreateSubscriptionResponse, P as PendingSubscriptionCheckoutResponse, a as ProductResponse, b as ProductEntitlementResponse, c as ProductPriceResponse, S as SubscriptionResponse, d as SubscriptionDetailResponse, e as SubscriptionItemResponse } from './index.d-CKQAhQfJ.js';
2
- import { C as ChargeStatus } from './billing-status-BZQN_gm7.js';
1
+ import { A as ActivatedSubscriptionResponse, C as CreateSubscriptionResponse, P as PendingSubscriptionCheckoutResponse, a as ProductResponse, b as ProductEntitlementResponse, c as ProductPriceResponse, S as SubscriptionResponse, d as SubscriptionDetailResponse, e as SubscriptionItemResponse } from './index.d-DSEYhV2c.js';
2
+ import { C as ChargeStatus } from './billing-status-DZkB0VPK.js';
3
3
 
4
4
  /** Public SDK types for this domain. Re-exported by ../types.ts. */
5
5
  interface BillowOptions {
@@ -16,14 +16,14 @@ interface BillowOptions {
16
16
  */
17
17
  timeoutMs?: number;
18
18
  /**
19
- * How many times to retry a transient failure. Retries are **opt-in** — the default is
19
+ * How many times to retry a transient failure. Retries are **opt-in** - the default is
20
20
  * `0`. Only requests that are safe to repeat are retried: every `GET`, plus **any** method
21
21
  * on a `429` (a rate-limited request never executed). A write (`POST`/`PATCH`/`DELETE`) is
22
22
  * never retried on a `5xx`/network error, since it may have already applied.
23
23
  */
24
24
  maxRetries?: number;
25
25
  /**
26
- * Base backoff in milliseconds between retries — exponential (`base × 2^attempt`), and a
26
+ * Base backoff in milliseconds between retries - exponential (`base × 2^attempt`), and a
27
27
  * `Retry-After` response header takes precedence when present. Defaults to 500.
28
28
  */
29
29
  retryBackoffMs?: number;
@@ -32,7 +32,7 @@ interface BillowOptions {
32
32
  * Per-call overrides passed as the last argument to a resource method.
33
33
  * - `signal` cancels the request (a caller abort is surfaced immediately and never retried).
34
34
  * - `timeoutMs` overrides the client's default timeout for this call (applied per attempt).
35
- * - `idempotencyKey` sends an `Idempotency-Key` and makes the write **safe to retry** — reused
35
+ * - `idempotencyKey` sends an `Idempotency-Key` and makes the write **safe to retry** - reused
36
36
  * verbatim on every attempt. Only exposed on writes the server replays (create/attach/track/refund).
37
37
  */
38
38
  interface RequestOptions {
@@ -44,7 +44,7 @@ interface RequestOptions {
44
44
  type IdempotentRequestOptions = RequestOptions & {
45
45
  idempotencyKey: string;
46
46
  };
47
- /** Per-call overrides for reads and non-replayable writes — cancellation + timeout, no idempotency key. */
47
+ /** Per-call overrides for reads and non-replayable writes - cancellation + timeout, no idempotency key. */
48
48
  type CallOptions = Omit<RequestOptions, "idempotencyKey">;
49
49
  interface Customer {
50
50
  id: string;
@@ -77,7 +77,7 @@ interface MeterFilter {
77
77
  key: string;
78
78
  values: string[];
79
79
  }
80
- /** A meter's measurement config (ADR-0011) — how a metered feature's usage aggregates. */
80
+ /** A meter's measurement config (ADR-0011) - how a metered feature's usage aggregates. */
81
81
  interface MeterConfig {
82
82
  aggregation: MeterAggregation;
83
83
  eventProperty?: string | null;
@@ -142,7 +142,9 @@ interface CreateProductInput {
142
142
  isAddOn?: boolean;
143
143
  /** Free-form string map that round-trips on the product + on subscription.* webhooks. */
144
144
  metadata?: Record<string, string>;
145
+ /** In the order the product lists them: every read of it, and an invoice's usage lines, keep it. */
145
146
  prices: PriceInput[];
147
+ /** In the order the product lists them: every read of it keeps it. */
146
148
  entitlements?: EntitlementInput[];
147
149
  }
148
150
  /** A price in a product edit: carry `id` to update that row in place, omit it to add. */
@@ -169,7 +171,9 @@ interface UpdateProductInput {
169
171
  archived?: boolean;
170
172
  /** Replace the product's metadata map. */
171
173
  metadata?: Record<string, string>;
174
+ /** The product's whole price list, in the order it lists them from now on. */
172
175
  prices?: UpdatePriceInput[];
176
+ /** The product's whole entitlement list, in the order it lists them from now on. */
173
177
  entitlements?: EntitlementInput[];
174
178
  }
175
179
  interface Feature {
@@ -182,7 +186,7 @@ interface Feature {
182
186
  }
183
187
  /**
184
188
  * An in-place edit to a feature. `name` is always allowed; `meter` re-configures a
185
- * metered feature's aggregation — but the server refuses a meter change once usage has
189
+ * metered feature's aggregation - but the server refuses a meter change once usage has
186
190
  * been recorded (it would rewrite billed history). At least one field must be present.
187
191
  */
188
192
  interface UpdateFeatureInput {
@@ -217,7 +221,7 @@ interface CreateUsageAlertInput {
217
221
  }
218
222
  interface TrackResult {
219
223
  ok: true;
220
- /** True when the idempotency key was already seen — the call was a no-op. */
224
+ /** True when the idempotency key was already seen - the call was a no-op. */
221
225
  deduplicated: boolean;
222
226
  /** Remaining balance for the feature; `null` if unlimited. */
223
227
  balance: number | null;
@@ -234,7 +238,7 @@ type Product = ProductResponse;
234
238
  type Subscription = SubscriptionResponse;
235
239
  /** A single fetched subscription (`subscriptions.get`) - {@link Subscription} plus the stable `customerExternalId` + `productSlug`. */
236
240
  type SubscriptionDetail = SubscriptionDetailResponse;
237
- /** A subscription line item — the base plan or an attached add-on (Phase D2). */
241
+ /** A subscription line item - the base plan or an attached add-on (Phase D2). */
238
242
  type SubscriptionItem = SubscriptionItemResponse;
239
243
  interface CreateSubscriptionInput {
240
244
  customerId: string;
@@ -5,21 +5,21 @@
5
5
  * against it (see billing-status.test.ts); webhook-delivery status is a free-text column
6
6
  * server-side with a fixed vocabulary, documented here.
7
7
  */
8
- /** A charge's lifecycle status — mirrors `@billow/core` `CHARGE_STATUSES`. */
8
+ /** A charge's lifecycle status - mirrors `@billow/core` `CHARGE_STATUSES`. */
9
9
  declare const CHARGE_STATUSES: readonly ["pending", "processing", "succeeded", "failed", "requires_reconciliation", "disputed"];
10
10
  type ChargeStatus = (typeof CHARGE_STATUSES)[number];
11
- /** An invoice's lifecycle status — mirrors `@billow/core` `INVOICE_STATUSES`. */
11
+ /** An invoice's lifecycle status - mirrors `@billow/core` `INVOICE_STATUSES`. */
12
12
  declare const INVOICE_STATUSES: readonly ["draft", "open", "paid", "uncollectible", "void"];
13
13
  type InvoiceStatus = (typeof INVOICE_STATUSES)[number];
14
- /** A refund's lifecycle status — mirrors `@billow/core` `REFUND_STATUSES`. */
14
+ /** A refund's lifecycle status - mirrors `@billow/core` `REFUND_STATUSES`. */
15
15
  declare const REFUND_STATUSES: readonly ["pending", "succeeded", "failed"];
16
16
  type RefundStatus = (typeof REFUND_STATUSES)[number];
17
- /** A saved payment method's status — mirrors `@billow/core` `PAYMENT_METHOD_STATUSES`. */
17
+ /** A saved payment method's status - mirrors `@billow/core` `PAYMENT_METHOD_STATUSES`. */
18
18
  declare const PAYMENT_METHOD_STATUSES: readonly ["active", "expired", "removed"];
19
19
  type PaymentMethodStatus = (typeof PAYMENT_METHOD_STATUSES)[number];
20
20
  /**
21
21
  * A webhook delivery attempt's status. Not a DB enum (a free-text column); the dispatcher
22
- * inserts one row per attempt with exactly `delivered` (a 2xx) or `failed` (anything else) —
22
+ * inserts one row per attempt with exactly `delivered` (a 2xx) or `failed` (anything else) -
23
23
  * see `packages/server/src/jobs/outbox.ts`. (Retry/backoff state lives on the outbox event,
24
24
  * a separate table, not on the delivery record.)
25
25
  */
@@ -5,21 +5,21 @@
5
5
  * against it (see billing-status.test.ts); webhook-delivery status is a free-text column
6
6
  * server-side with a fixed vocabulary, documented here.
7
7
  */
8
- /** A charge's lifecycle status — mirrors `@billow/core` `CHARGE_STATUSES`. */
8
+ /** A charge's lifecycle status - mirrors `@billow/core` `CHARGE_STATUSES`. */
9
9
  declare const CHARGE_STATUSES: readonly ["pending", "processing", "succeeded", "failed", "requires_reconciliation", "disputed"];
10
10
  type ChargeStatus = (typeof CHARGE_STATUSES)[number];
11
- /** An invoice's lifecycle status — mirrors `@billow/core` `INVOICE_STATUSES`. */
11
+ /** An invoice's lifecycle status - mirrors `@billow/core` `INVOICE_STATUSES`. */
12
12
  declare const INVOICE_STATUSES: readonly ["draft", "open", "paid", "uncollectible", "void"];
13
13
  type InvoiceStatus = (typeof INVOICE_STATUSES)[number];
14
- /** A refund's lifecycle status — mirrors `@billow/core` `REFUND_STATUSES`. */
14
+ /** A refund's lifecycle status - mirrors `@billow/core` `REFUND_STATUSES`. */
15
15
  declare const REFUND_STATUSES: readonly ["pending", "succeeded", "failed"];
16
16
  type RefundStatus = (typeof REFUND_STATUSES)[number];
17
- /** A saved payment method's status — mirrors `@billow/core` `PAYMENT_METHOD_STATUSES`. */
17
+ /** A saved payment method's status - mirrors `@billow/core` `PAYMENT_METHOD_STATUSES`. */
18
18
  declare const PAYMENT_METHOD_STATUSES: readonly ["active", "expired", "removed"];
19
19
  type PaymentMethodStatus = (typeof PAYMENT_METHOD_STATUSES)[number];
20
20
  /**
21
21
  * A webhook delivery attempt's status. Not a DB enum (a free-text column); the dispatcher
22
- * inserts one row per attempt with exactly `delivered` (a 2xx) or `failed` (anything else) —
22
+ * inserts one row per attempt with exactly `delivered` (a 2xx) or `failed` (anything else) -
23
23
  * see `packages/server/src/jobs/outbox.ts`. (Retry/backoff state lives on the outbox event,
24
24
  * a separate table, not on the delivery record.)
25
25
  */
@@ -44,5 +44,5 @@ function isTerminal(status) {
44
44
  }
45
45
 
46
46
  export { ACTIVE_SUBSCRIPTION_STATUSES, CHARGE_STATUSES, INVOICE_STATUSES, NEVER_ACTIVATED_SUBSCRIPTION_STATUSES, PAYMENT_METHOD_STATUSES, REFUND_STATUSES, SUBSCRIPTION_STATUSES, TERMINAL_SUBSCRIPTION_STATUSES, WEBHOOK_DELIVERY_STATUSES, grantsAccess, isTerminal };
47
- //# sourceMappingURL=chunk-CCG4F5FK.js.map
48
- //# sourceMappingURL=chunk-CCG4F5FK.js.map
47
+ //# sourceMappingURL=chunk-47J7FYM5.js.map
48
+ //# sourceMappingURL=chunk-47J7FYM5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/billing-status.ts","../src/subscription-status.ts"],"names":[],"mappings":";AASO,IAAM,eAAA,GAAkB;AAAA,EAC7B,SAAA;AAAA,EACA,YAAA;AAAA,EACA,WAAA;AAAA,EACA,QAAA;AAAA,EACA,yBAAA;AAAA,EACA;AACF;AAIO,IAAM,mBAAmB,CAAC,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,iBAAiB,MAAM;AAI1E,IAAM,eAAA,GAAkB,CAAC,SAAA,EAAW,WAAA,EAAa,QAAQ;AAIzD,IAAM,uBAAA,GAA0B,CAAC,QAAA,EAAU,SAAA,EAAW,SAAS;AAS/D,IAAM,yBAAA,GAA4B,CAAC,WAAA,EAAa,QAAQ;;;ACxBxD,IAAM,qBAAA,GAAwB;AAAA,EACnC,YAAA;AAAA,EACA,oBAAA;AAAA,EACA,UAAA;AAAA,EACA,QAAA;AAAA,EACA,UAAA;AAAA,EACA,QAAA;AAAA,EACA,UAAA;AAAA,EACA;AACF;AAQO,IAAM,4BAAA,GAA8D;AAAA,EACzE,UAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF;AAGO,IAAM,8BAAA,GAAgE;AAAA,EAC3E,oBAAA;AAAA,EACA;AACF;AAGO,IAAM,qCAAA,GAAuE;AAAA,EAClF,YAAA;AAAA,EACA;AACF;AAGO,SAAS,aAAa,MAAA,EAAqC;AAChE,EAAA,OAAO,4BAAA,CAA6B,SAAS,MAAM,CAAA;AACrD;AAGO,SAAS,WAAW,MAAA,EAAqC;AAC9D,EAAA,OAAO,8BAAA,CAA+B,SAAS,MAAM,CAAA;AACvD","file":"chunk-47J7FYM5.js","sourcesContent":["/**\n * Charge / invoice / refund / payment-method / webhook-delivery status vocabularies,\n * mirrored for the SDK (which cannot import the server-side `@billow/core`). The DB-enum\n * ones (charge, invoice, refund, payment method) mirror core enums and are parity-tested\n * against it (see billing-status.test.ts); webhook-delivery status is a free-text column\n * server-side with a fixed vocabulary, documented here.\n */\n\n/** A charge's lifecycle status - mirrors `@billow/core` `CHARGE_STATUSES`. */\nexport const CHARGE_STATUSES = [\n \"pending\",\n \"processing\",\n \"succeeded\",\n \"failed\",\n \"requires_reconciliation\",\n \"disputed\",\n] as const;\nexport type ChargeStatus = (typeof CHARGE_STATUSES)[number];\n\n/** An invoice's lifecycle status - mirrors `@billow/core` `INVOICE_STATUSES`. */\nexport const INVOICE_STATUSES = [\"draft\", \"open\", \"paid\", \"uncollectible\", \"void\"] as const;\nexport type InvoiceStatus = (typeof INVOICE_STATUSES)[number];\n\n/** A refund's lifecycle status - mirrors `@billow/core` `REFUND_STATUSES`. */\nexport const REFUND_STATUSES = [\"pending\", \"succeeded\", \"failed\"] as const;\nexport type RefundStatus = (typeof REFUND_STATUSES)[number];\n\n/** A saved payment method's status - mirrors `@billow/core` `PAYMENT_METHOD_STATUSES`. */\nexport const PAYMENT_METHOD_STATUSES = [\"active\", \"expired\", \"removed\"] as const;\nexport type PaymentMethodStatus = (typeof PAYMENT_METHOD_STATUSES)[number];\n\n/**\n * A webhook delivery attempt's status. Not a DB enum (a free-text column); the dispatcher\n * inserts one row per attempt with exactly `delivered` (a 2xx) or `failed` (anything else) -\n * see `packages/server/src/jobs/outbox.ts`. (Retry/backoff state lives on the outbox event,\n * a separate table, not on the delivery record.)\n */\nexport const WEBHOOK_DELIVERY_STATUSES = [\"delivered\", \"failed\"] as const;\nexport type WebhookDeliveryStatus = (typeof WEBHOOK_DELIVERY_STATUSES)[number];\n","/**\n * The subscription status vocabulary + access predicate, mirrored from @billow/core\n * (`enums.ts` + `billing/subscription-state.ts`) so SDK consumers can type and branch on\n * billow's own model instead of hand-maintaining a union that drifts (a real bug: an app\n * copy once carried a non-existent `ended` status - that string is a webhook event type,\n * not a subscription status).\n *\n * Mirrored, not imported: @billow/core is a server package the published SDK cannot depend\n * on (the same reason @billow/contracts mirrors core's pure logic). The parity test\n * `subscription-status.test.ts` imports @billow/core and fails CI on any drift.\n */\n\n/** The 8 canonical subscription statuses, in lifecycle order. */\nexport const SUBSCRIPTION_STATUSES = [\n \"incomplete\",\n \"incomplete_expired\",\n \"trialing\",\n \"active\",\n \"past_due\",\n \"paused\",\n \"canceled\",\n \"unpaid\",\n] as const;\n\nexport type SubscriptionStatus = (typeof SUBSCRIPTION_STATUSES)[number];\n\n/**\n * Statuses that currently grant access (a live commitment): `trialing`, `active`, and\n * `past_due` (access is retained through dunning). Note `paused` does NOT grant access.\n */\nexport const ACTIVE_SUBSCRIPTION_STATUSES: readonly SubscriptionStatus[] = [\n \"trialing\",\n \"active\",\n \"past_due\",\n];\n\n/** Statuses a subscription can never leave: `incomplete_expired` and `canceled`. */\nexport const TERMINAL_SUBSCRIPTION_STATUSES: readonly SubscriptionStatus[] = [\n \"incomplete_expired\",\n \"canceled\",\n];\n\n/** Statuses in which a subscription never activated (no access was ever granted). */\nexport const NEVER_ACTIVATED_SUBSCRIPTION_STATUSES: readonly SubscriptionStatus[] = [\n \"incomplete\",\n \"incomplete_expired\",\n];\n\n/** Whether access should currently be granted for a subscription in this state. */\nexport function grantsAccess(status: SubscriptionStatus): boolean {\n return ACTIVE_SUBSCRIPTION_STATUSES.includes(status);\n}\n\n/** Whether this is a terminal status the subscription can never leave. */\nexport function isTerminal(status: SubscriptionStatus): boolean {\n return TERMINAL_SUBSCRIPTION_STATUSES.includes(status);\n}\n"]}
@@ -20,19 +20,26 @@ var BillowApiError = class extends Error {
20
20
  code;
21
21
  /** Structured error context from the server (e.g. per-field validation issues), when present. */
22
22
  details;
23
- /** billow's per-request id (`x-request-id`) — quote it in a bug report to trace the server log. */
23
+ /** billow's per-request id (`x-request-id`) - quote it in a bug report to trace the server log. */
24
24
  requestId;
25
- constructor(status, code, message, details, requestId) {
25
+ /**
26
+ * How many seconds to wait before trying again, from the response's `Retry-After` header (sent
27
+ * with a `429 rate_limited`); undefined when the response did not say.
28
+ */
29
+ retryAfterSeconds;
30
+ constructor(status, code, message, details, requestId, retryAfterSeconds) {
26
31
  super(message);
27
32
  this.name = "BillowApiError";
28
33
  this.status = status;
29
34
  this.code = code;
30
35
  this.details = details;
31
36
  this.requestId = requestId;
37
+ this.retryAfterSeconds = retryAfterSeconds;
32
38
  }
33
39
  };
34
40
  var DEFAULT_TIMEOUT_MS = 6e4;
35
41
  var DEFAULT_RETRY_BACKOFF_MS = 500;
42
+ var MAX_RETRY_AFTER_SECONDS = 3600;
36
43
  function makeContext(bearer, opts) {
37
44
  return {
38
45
  fetch: opts.fetch ?? fetch,
@@ -51,7 +58,7 @@ function isRetryable(status, safeToRepeat2) {
51
58
  function backoffMs(base, attempt, retryAfter) {
52
59
  if (retryAfter) {
53
60
  const secs = Number(retryAfter);
54
- if (Number.isFinite(secs) && secs >= 0) return secs * 1e3;
61
+ if (Number.isFinite(secs) && secs >= 0) return Math.min(secs, MAX_RETRY_AFTER_SECONDS) * 1e3;
55
62
  }
56
63
  return base * 2 ** attempt;
57
64
  }
@@ -173,9 +180,25 @@ function errorFrom(res, data) {
173
180
  err.code ?? "error",
174
181
  err.message ?? String(res.status),
175
182
  err.details,
176
- requestIdOf(res)
183
+ requestIdOf(res),
184
+ retryAfterOf(res)
177
185
  );
178
186
  }
187
+ var IMF_FIXDATE = /^[A-Z][a-z]{2}, \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2} GMT$/;
188
+ function retryAfterOf(res) {
189
+ const value = res.headers.get("retry-after")?.trim();
190
+ if (!value) return void 0;
191
+ let seconds;
192
+ if (/^\d+$/.test(value)) {
193
+ seconds = Number(value);
194
+ } else if (IMF_FIXDATE.test(value)) {
195
+ seconds = Math.ceil((Date.parse(value) - Date.now()) / 1e3);
196
+ } else {
197
+ return void 0;
198
+ }
199
+ if (!Number.isFinite(seconds)) return void 0;
200
+ return Math.min(Math.max(0, seconds), MAX_RETRY_AFTER_SECONDS);
201
+ }
179
202
  async function apiRequestBinary(ctx, method, path2, options) {
180
203
  const res = await sendWithResilience(
181
204
  ctx,
@@ -529,6 +552,31 @@ function createCreditsResource(ctx) {
529
552
  options
530
553
  )
531
554
  },
555
+ includedWindows: {
556
+ /**
557
+ * The Included Credit Windows of one or more subscriptions (`subscription`, an id or a list
558
+ * of up to 100), or of a customer (`customer`, by external id) - newest first: what each
559
+ * period Billow granted includes (the whole period, each month of it under a monthly rule,
560
+ * or a trial), how far it was issued, and its `state`. With `current: true`, only each
561
+ * subscription's latest window that has started - what it stands at now. Auto-paginating by
562
+ * cursor: `await` the first page, `for await (…)` every window, or `.listAll()` to collect
563
+ * them.
564
+ */
565
+ list: (params, options) => {
566
+ const { subscription, ...rest } = params;
567
+ const subscriptions = Array.isArray(subscription) ? subscription.join(",") : subscription;
568
+ return makeCursorListPromise(
569
+ (p) => apiRequest(
570
+ ctx,
571
+ "GET",
572
+ `/v1/credits/included-windows${toQuery({ ...p, subscription: subscriptions })}`,
573
+ void 0,
574
+ options
575
+ ),
576
+ rest
577
+ );
578
+ }
579
+ },
532
580
  topUps: {
533
581
  /**
534
582
  * Buy a Credit Pack for a customer: answers the top-up with `checkoutUrl`, the hosted
@@ -1136,7 +1184,7 @@ function createSettingsResource(ctx) {
1136
1184
  },
1137
1185
  /**
1138
1186
  * Usage settlement grace (hours): defers *collection* of a boundary-adjacent priced
1139
- * calendar-meter renewal past the tz month boundary until late usage settles — the billed
1187
+ * calendar-meter renewal past the tz month boundary until late usage settles - the billed
1140
1188
  * windows/amount are unchanged, only the invoice timing shifts. `0` disables it (the default);
1141
1189
  * a no-op for any subscription without a priced calendar meter. Cap 72h.
1142
1190
  */
@@ -1263,7 +1311,7 @@ function createSubscriptionsResource(ctx) {
1263
1311
  void 0,
1264
1312
  options
1265
1313
  ),
1266
- /** Cancel — immediately, or at period end with `{ atPeriodEnd: true }`. */
1314
+ /** Cancel - immediately, or at period end with `{ atPeriodEnd: true }`. */
1267
1315
  cancel: (id, opts) => apiRequest(
1268
1316
  ctx,
1269
1317
  "POST",
@@ -1276,7 +1324,18 @@ function createSubscriptionsResource(ctx) {
1276
1324
  "POST",
1277
1325
  `/v1/subscriptions/${encodeURIComponent(id)}/resume-cancellation`
1278
1326
  ),
1327
+ /**
1328
+ * Pause an active or trialing subscription: no renewals and no access until it is resumed.
1329
+ * Refused while one of its invoices is still being collected.
1330
+ */
1279
1331
  pause: (id) => apiRequest(ctx, "POST", `/v1/subscriptions/${encodeURIComponent(id)}/pause`),
1332
+ /**
1333
+ * Resume a paused subscription. Paused time is never billed: resumed before its paid period
1334
+ * ends, it carries on and renews at `currentPeriodEnd`; resumed after, a fresh full period
1335
+ * starts now and is charged at once like a renewal, with the ended period's usage (a decline
1336
+ * returns it `past_due`). Usage recorded while paused is never billed. A paused trial resumes
1337
+ * `trialing`. Duplicate calls are safe.
1338
+ */
1280
1339
  resume: (id) => apiRequest(ctx, "POST", `/v1/subscriptions/${encodeURIComponent(id)}/resume`),
1281
1340
  /** Apply a coupon to an existing subscription. */
1282
1341
  applyCoupon: (id, code) => apiRequest(
@@ -1285,7 +1344,7 @@ function createSubscriptionsResource(ctx) {
1285
1344
  `/v1/subscriptions/${encodeURIComponent(id)}/coupon`,
1286
1345
  { code }
1287
1346
  ),
1288
- /** Change plan — immediate prorated upgrade, or downgrade scheduled for period end. `productId` accepts the product's id or slug. */
1347
+ /** Change plan - immediate prorated upgrade, or downgrade scheduled for period end. `productId` accepts the product's id or slug. */
1289
1348
  changePlan: (id, productId) => apiRequest(ctx, "POST", `/v1/subscriptions/${encodeURIComponent(id)}/change-plan`, { productId }),
1290
1349
  /** Clear a pending downgrade. Duplicate calls are safe. */
1291
1350
  clearScheduledPlanChange: (id) => apiRequest(
@@ -1359,7 +1418,7 @@ function createWebhookEndpointsResource(ctx) {
1359
1418
  ),
1360
1419
  /** Delete an endpoint and its delivery history. */
1361
1420
  delete: (id) => apiRequest(ctx, "DELETE", `/v1/webhook-endpoints/${encodeURIComponent(id)}`),
1362
- /** Rotate the signing secret — the new plaintext is returned once. */
1421
+ /** Rotate the signing secret - the new plaintext is returned once. */
1363
1422
  rotateSecret: (id) => apiRequest(
1364
1423
  ctx,
1365
1424
  "POST",
@@ -1398,7 +1457,7 @@ var Billow = class {
1398
1457
  /** Custom domains for the hosted customer portal (live keys, behind a rollout flag). */
1399
1458
  hostedDomains;
1400
1459
  /**
1401
- * Organization settings (Phase D3, F) — the configurable dunning schedule, usage settlement grace,
1460
+ * Organization settings (Phase D3, F) - the configurable dunning schedule, usage settlement grace,
1402
1461
  * and the cross-currency reporting currency + FX-rate registry (ADR-0013).
1403
1462
  */
1404
1463
  settings;
@@ -1426,7 +1485,7 @@ var Billow = class {
1426
1485
  coupons = {
1427
1486
  /** Define a coupon (a reusable discount template). */
1428
1487
  create: (input) => this.#request("POST", "/v1/coupons", input),
1429
- /** List coupons (secret key only — enumerates live promo codes). Auto-paginating. */
1488
+ /** List coupons (secret key only - enumerates live promo codes). Auto-paginating. */
1430
1489
  list: (params = {}, options) => makeListPromise(
1431
1490
  (p) => this.#request("GET", `/v1/coupons${toQuery(p)}`, void 0, options),
1432
1491
  params
@@ -1434,13 +1493,13 @@ var Billow = class {
1434
1493
  /** Deactivate a coupon (existing discounts keep running). */
1435
1494
  deactivate: (id) => this.#request("POST", `/v1/coupons/${encodeURIComponent(id)}/deactivate`)
1436
1495
  };
1437
- /** Manage developer webhook endpoints — register, rotate secrets, inspect deliveries.
1496
+ /** Manage developer webhook endpoints - register, rotate secrets, inspect deliveries.
1438
1497
  * (To VERIFY incoming deliveries, import `constructEvent` from `@usebillow/sdk/webhooks`.) */
1439
1498
  features = {
1440
1499
  /** Define a feature (a boolean access gate, or a metered feature with a meter). */
1441
1500
  create: (input) => this.#request("POST", "/v1/features", input),
1442
1501
  /**
1443
- * Edit a feature in place: its `name`, and — for a metered feature — its `meter`
1502
+ * Edit a feature in place: its `name`, and - for a metered feature - its `meter`
1444
1503
  * aggregation. The server refuses a meter change once usage has been recorded (it
1445
1504
  * would rewrite billed history), so set the meter right at create time or before you
1446
1505
  * start tracking. Returns the updated feature.
@@ -1497,7 +1556,7 @@ var Billow = class {
1497
1556
  * choose a credential set and `target` to probe one verify target (Paymob: a
1498
1557
  * method); pass `sampleToken` (SANDBOX ONLY) to run a functional sub-test.
1499
1558
  * This probe hits the provider's live API (mutates nothing here), so it takes a
1500
- * per-call {@link CallOptions} for a timeout / cancellation — `opts` is spread into
1559
+ * per-call {@link CallOptions} for a timeout / cancellation - `opts` is spread into
1501
1560
  * the body, so `options` stays a separate trailing arg (never merged in).
1502
1561
  */
1503
1562
  verify: (provider, opts, options) => this.#request(
@@ -1524,7 +1583,7 @@ var Billow = class {
1524
1583
  )
1525
1584
  }
1526
1585
  };
1527
- /** The merchant's business identity — the seller block on documents and email from-name. */
1586
+ /** The merchant's business identity - the seller block on documents and email from-name. */
1528
1587
  businessProfile = {
1529
1588
  /** The stored profile, or null if one was never saved. */
1530
1589
  get: (options) => this.#request(
@@ -1540,11 +1599,11 @@ var Billow = class {
1540
1599
  };
1541
1600
  /**
1542
1601
  * Hosted customer surfaces (Phase G, ADR-0014). Mint a portal session for one of
1543
- * your signed-in users and redirect them to the returned `url` — the self-serve
1602
+ * your signed-in users and redirect them to the returned `url` - the self-serve
1544
1603
  * portal, or a `checkout` hand-off for `productId`. The Customer's own calls go
1545
1604
  * through {@link BillowPortal}, constructed with the session token.
1546
1605
  */
1547
- /** Identity of this key's tenant — org, environment, configured currencies. */
1606
+ /** Identity of this key's tenant - org, environment, configured currencies. */
1548
1607
  me(options) {
1549
1608
  return this.#request("GET", "/v1/me", void 0, options);
1550
1609
  }
@@ -1564,14 +1623,14 @@ var Billow = class {
1564
1623
  // ── The headline verbs ──────────────────────────────────────────────
1565
1624
  /**
1566
1625
  * Gate access to a feature. `featureId` is the feature slug. Returns
1567
- * `{ allowed, balance }` — `balance` is `null` for unlimited/boolean features.
1626
+ * `{ allowed, balance }` - `balance` is `null` for unlimited/boolean features.
1568
1627
  */
1569
1628
  check(input, options) {
1570
1629
  return this.#request("POST", "/v1/check", input, options);
1571
1630
  }
1572
1631
  /**
1573
1632
  * Record usage of a metered feature (`value` defaults to 1; negative credits
1574
- * back). Pass `idempotencyKey` to make a retried call a no-op — which also makes the call
1633
+ * back). Pass `idempotencyKey` to make a retried call a no-op - which also makes the call
1575
1634
  * safe to retry automatically when `maxRetries` is set.
1576
1635
  */
1577
1636
  track(input, options) {
@@ -1608,7 +1667,7 @@ var BillowPublishable = class {
1608
1667
  this.#ctx = makeContext(publishableKey, opts);
1609
1668
  }
1610
1669
  products = {
1611
- /** The active catalog — products and their prices, for a pricing table. */
1670
+ /** The active catalog - products and their prices, for a pricing table. */
1612
1671
  list: (options) => apiRequest(
1613
1672
  this.#ctx,
1614
1673
  "GET",
@@ -1632,7 +1691,7 @@ var BillowPortal = class {
1632
1691
  if (!sessionToken) throw new Error("billow: a portal session token is required");
1633
1692
  this.#ctx = makeContext(sessionToken, opts);
1634
1693
  }
1635
- /** The portal shell: flow, return URL, merchant brand, and customer identity —
1694
+ /** The portal shell: flow, return URL, merchant brand, and customer identity -
1636
1695
  * the lightweight payload the hosting app frames every page with, and the
1637
1696
  * validate-and-route check at login. */
1638
1697
  session(options) {
@@ -1760,5 +1819,5 @@ var BillowPortal = class {
1760
1819
  };
1761
1820
 
1762
1821
  export { BILLOW_ERROR_CODES, Billow, BillowApiError, BillowPortal, BillowPublishable, currencyExponent, formatMoney, isSecretField, toMajorUnits, toMinorUnits };
1763
- //# sourceMappingURL=chunk-J6JIZGWB.js.map
1764
- //# sourceMappingURL=chunk-J6JIZGWB.js.map
1822
+ //# sourceMappingURL=chunk-XKN7ZRAR.js.map
1823
+ //# sourceMappingURL=chunk-XKN7ZRAR.js.map