@usethrottle/subscriptions 4.0.0 → 4.1.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 CHANGED
@@ -133,6 +133,13 @@ await subscriptions.setPaymentMethod('sub_123', 'pm_456');
133
133
  subscription per checkout; omit it when the cart's lines carry `recurring`
134
134
  (`@usethrottle/cart`), and each such line becomes its own subscription.
135
135
 
136
+ ## Money
137
+
138
+ Amounts are integers in the subscription's minor unit. Show them with
139
+ `formatMoney(sub.amount, sub.currency)`: this package re-exports
140
+ `@usethrottle/money` as `money` and `formatMoney` by name, plus the
141
+ `CurrencyCode` and `MoneyValue` types.
142
+
136
143
  ## Boundaries
137
144
 
138
145
  - Customer-scoped browser tokens are not part of v1. Use the proxy helper.
@@ -29,7 +29,8 @@ function normalizeSubscription(raw) {
29
29
  nextPaymentAmount: raw?.nextPaymentAmount == null ? null : Number(raw.nextPaymentAmount),
30
30
  amount: Number(raw?.amount ?? 0),
31
31
  quantity: Number(raw?.quantity ?? 1),
32
- currency: optionalString(raw?.currency) ?? "USD",
32
+ // No USD fallback (MC2-R35): a subscription without a currency is a broken response.
33
+ currency: requiredString(raw?.currency, "subscription.currency"),
33
34
  currentPeriodStart: requiredDateString(
34
35
  raw?.currentPeriodStart,
35
36
  "subscription.currentPeriodStart"
@@ -48,7 +49,8 @@ function normalizeSubscription(raw) {
48
49
  paymentMethodId: optionalString(raw?.paymentMethodId),
49
50
  deliveryMethod: raw?.deliveryMethod === "shipment" ? "shipment" : "access_grant",
50
51
  shippingAddress: raw?.shippingAddress && typeof raw.shippingAddress === "object" ? raw.shippingAddress : null,
51
- renewalIssue: normalizeRenewalIssue(raw?.renewalIssue),
52
+ // `currency` above has already been checked.
53
+ renewalIssue: normalizeRenewalIssue(raw?.renewalIssue, raw.currency),
52
54
  proration: raw?.proration ? {
53
55
  creditCents: raw.proration.creditCents,
54
56
  chargedCents: raw.proration.chargedCents,
@@ -71,7 +73,7 @@ function normalizePaymentSchedule(raw) {
71
73
  dueAt: optionalDateString(r?.dueAt)
72
74
  }));
73
75
  }
74
- function normalizeRenewalIssue(raw) {
76
+ function normalizeRenewalIssue(raw, subscriptionCurrency) {
75
77
  if (!raw || typeof raw !== "object") return null;
76
78
  return {
77
79
  kind: raw.kind,
@@ -84,7 +86,7 @@ function normalizeRenewalIssue(raw) {
84
86
  charge: raw.charge ? {
85
87
  transactionId: optionalString(raw.charge.transactionId),
86
88
  amount: Number(raw.charge.amount ?? 0),
87
- currency: optionalString(raw.charge.currency) ?? "USD",
89
+ currency: optionalString(raw.charge.currency) || subscriptionCurrency,
88
90
  periodStart: optionalString(raw.charge.periodStart) ?? void 0
89
91
  } : null
90
92
  };
@@ -520,4 +522,4 @@ export {
520
522
  SubscriptionsClient,
521
523
  createSubscriptionsClient
522
524
  };
523
- //# sourceMappingURL=chunk-UDTLH4G3.js.map
525
+ //# sourceMappingURL=chunk-GK6QY63F.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/normalize.ts","../src/client.ts"],"sourcesContent":["import { ThrottleError, type ThrottleErrorArgs } from '@usethrottle/errors';\n\n/**\n * Thrown on a non-2xx response from the Throttle Subscriptions API.\n *\n * Extends the shared {@link ThrottleError} so a single\n * `catch (e) { if (e instanceof ThrottleError) … }` covers errors from every\n * Throttle SDK. `instanceof ThrottleSubscriptionsError` keeps working.\n */\nexport class ThrottleSubscriptionsError extends ThrottleError {\n constructor(args: {\n code: string;\n message: string;\n statusCode: number;\n details?: unknown;\n responseHeaders?: ThrottleErrorArgs['responseHeaders'];\n }) {\n super(args);\n this.name = 'ThrottleSubscriptionsError';\n }\n}\n\nexport { ThrottleError, isThrottleError } from '@usethrottle/errors';\n","import type {\n CheckoutSession,\n Customer,\n CustomerPaymentMethod,\n Pagination,\n Subscription,\n SubscriptionInterval,\n SubscriptionIntervalUnit,\n SubscriptionRenewalIssue,\n SubscriptionStatus,\n SubscriptionUsageItem,\n TrialEligibilityResult,\n} from './types';\n\nexport function normalizeSubscription(raw: any): Subscription {\n return {\n id: requiredString(raw?.id, 'subscription.id'),\n workspaceId: optionalString(raw?.workspaceId),\n applicationId: optionalString(raw?.applicationId),\n customerId: requiredString(raw?.customerId, 'subscription.customerId'),\n status: (raw?.status ?? 'active') as SubscriptionStatus,\n planReference: requiredString(raw?.planReference, 'subscription.planReference'),\n planName: optionalString(raw?.planName),\n interval: (raw?.interval ?? 'monthly') as SubscriptionInterval,\n intervalUnit: (optionalString(raw?.intervalUnit) as Subscription['intervalUnit']) ?? null,\n intervalCount: raw?.intervalCount == null ? null : Number(raw.intervalCount),\n totalPayments: raw?.totalPayments == null ? null : Number(raw.totalPayments),\n paymentsMade: Number(raw?.paymentsMade ?? 0),\n completedAt: optionalIsoDateString(raw?.completedAt),\n paymentSchedule: normalizePaymentSchedule(raw?.paymentSchedule),\n scheduleTotal: raw?.scheduleTotal == null ? null : Number(raw.scheduleTotal),\n nextPaymentAmount: raw?.nextPaymentAmount == null ? null : Number(raw.nextPaymentAmount),\n amount: Number(raw?.amount ?? 0),\n quantity: Number(raw?.quantity ?? 1),\n // No USD fallback (MC2-R35): a subscription without a currency is a broken response.\n currency: requiredString(raw?.currency, 'subscription.currency'),\n currentPeriodStart: requiredDateString(\n raw?.currentPeriodStart,\n 'subscription.currentPeriodStart',\n ),\n currentPeriodEnd: requiredDateString(\n raw?.currentPeriodEnd,\n 'subscription.currentPeriodEnd',\n ),\n trialEnd: optionalDateString(raw?.trialEnd),\n cancelAtPeriodEnd: Boolean(raw?.cancelAtPeriodEnd ?? false),\n failureCount: Number(raw?.failureCount ?? 0),\n lastPaymentAt: optionalDateString(raw?.lastPaymentAt),\n pausedAt: optionalDateString(raw?.pausedAt),\n cancelledAt: optionalDateString(raw?.cancelledAt),\n metadata: objectOrEmpty(raw?.metadata),\n paymentMethodId: optionalString(raw?.paymentMethodId),\n deliveryMethod: raw?.deliveryMethod === 'shipment' ? 'shipment' : 'access_grant',\n shippingAddress:\n raw?.shippingAddress && typeof raw.shippingAddress === 'object' ? raw.shippingAddress : null,\n // `currency` above has already been checked.\n renewalIssue: normalizeRenewalIssue(raw?.renewalIssue, raw.currency),\n proration: raw?.proration\n ? {\n creditCents: raw.proration.creditCents,\n chargedCents: raw.proration.chargedCents,\n fullAmount: raw.proration.fullAmount,\n }\n : undefined,\n createdAt: optionalDateString(raw?.createdAt) ?? undefined,\n updatedAt: optionalDateString(raw?.updatedAt) ?? undefined,\n };\n}\n\nfunction normalizePaymentSchedule(raw: any): Subscription['paymentSchedule'] {\n if (!Array.isArray(raw)) return null;\n return raw.map((r: any) => ({\n index: Number(r?.index ?? 0),\n amount: Number(r?.amount ?? 0),\n discount: Number(r?.discount ?? 0),\n net: Number(r?.net ?? 0),\n intervalUnit: (optionalString(r?.intervalUnit) as SubscriptionIntervalUnit | null) ?? null,\n intervalCount: r?.intervalCount == null ? null : Number(r.intervalCount),\n status: r?.status as 'paid' | 'due' | 'upcoming',\n dueAt: optionalDateString(r?.dueAt),\n }));\n}\n\nfunction normalizeRenewalIssue(raw: any, subscriptionCurrency: string): SubscriptionRenewalIssue | null {\n if (!raw || typeof raw !== 'object') return null;\n return {\n kind: raw.kind,\n reason: raw.reason,\n count: Number(raw.count ?? 0),\n firstAt: optionalString(raw.firstAt) ?? undefined,\n lastAt: requiredString(raw.lastAt, 'subscription.renewalIssue.lastAt'),\n message: raw.message ?? '',\n alertedAt: optionalDateString(raw.alertedAt),\n charge: raw.charge\n ? {\n transactionId: optionalString(raw.charge.transactionId),\n amount: Number(raw.charge.amount ?? 0),\n currency: optionalString(raw.charge.currency) || subscriptionCurrency,\n periodStart: optionalString(raw.charge.periodStart) ?? undefined,\n }\n : null,\n };\n}\n\nexport function normalizeUsageItem(raw: any): SubscriptionUsageItem {\n return {\n id: requiredString(raw?.id, 'usageItem.id'),\n subscriptionId: requiredString(raw?.subscriptionId, 'usageItem.subscriptionId'),\n kind: raw?.kind ?? '',\n unitCount: Number(raw?.unitCount ?? 0),\n unitPriceCents: Number(raw?.unitPriceCents ?? 0),\n totalCents: Number(raw?.totalCents ?? 0),\n periodStart: requiredDateString(raw?.periodStart, 'usageItem.periodStart'),\n periodEnd: requiredDateString(raw?.periodEnd, 'usageItem.periodEnd'),\n createdAt: requiredDateString(raw?.createdAt, 'usageItem.createdAt'),\n };\n}\n\nexport function normalizeCustomer(raw: any): Customer | null {\n if (!raw) return null;\n return {\n id: requiredString(raw?.id, 'customer.id'),\n externalId: optionalString(raw?.externalId),\n email: optionalString(raw?.email),\n firstName: optionalString(raw?.firstName),\n lastName: optionalString(raw?.lastName),\n phone: optionalString(raw?.phone),\n company: optionalString(raw?.company),\n metadata: objectOrEmpty(raw?.metadata),\n createdAt: optionalDateString(raw?.createdAt) ?? undefined,\n updatedAt: optionalDateString(raw?.updatedAt) ?? undefined,\n };\n}\n\nexport function normalizeCustomerPaymentMethod(raw: any): CustomerPaymentMethod {\n return {\n id: requiredString(raw?.id, 'paymentMethod.id'),\n processor: optionalString(raw?.processor),\n methodType: optionalString(raw?.methodType),\n cardBrand: optionalString(raw?.cardBrand),\n cardLastFour: optionalString(raw?.cardLastFour),\n isDefault: Boolean(raw?.isDefault ?? false),\n isActive: Boolean(raw?.isActive ?? true),\n createdAt: optionalDateString(raw?.createdAt) ?? undefined,\n updatedAt: optionalDateString(raw?.updatedAt) ?? undefined,\n };\n}\n\nexport function normalizeCheckoutSession(raw: any): CheckoutSession {\n const sessionId = raw?.sessionId ?? raw?.id;\n return {\n ...withoutUnderscoreKeys(raw),\n id: optionalString(raw?.id) ?? undefined,\n sessionId: requiredString(sessionId, 'checkoutSession.sessionId'),\n checkoutUrl: optionalString(raw?.checkoutUrl) ?? undefined,\n embedToken: optionalString(raw?.embedToken) ?? undefined,\n expiresAt: optionalDateString(raw?.expiresAt) ?? undefined,\n };\n}\n\nexport function normalizeTrialEligibility(raw: any): TrialEligibilityResult {\n return {\n eligible: Boolean(raw?.eligible),\n reason: raw?.reason,\n };\n}\n\nexport function normalizePagination(raw: any): Pagination | undefined {\n if (!raw) return undefined;\n return {\n cursor: raw.cursor ?? null,\n hasMore: Boolean(raw.hasMore ?? false),\n };\n}\n\nexport function toIso(value: string | Date | undefined): string | undefined {\n if (value === undefined) return undefined;\n return value instanceof Date ? value.toISOString() : value;\n}\n\nfunction requiredString(value: unknown, label: string): string {\n if (typeof value === 'string' && value.length > 0) return value;\n throw new Error(`Invalid Throttle response: missing ${label}`);\n}\n\nfunction optionalString(value: unknown): string | null {\n return typeof value === 'string' ? value : null;\n}\n\nfunction requiredDateString(value: unknown, label: string): string {\n if (value instanceof Date) return value.toISOString();\n if (typeof value === 'string' && value.length > 0) return value;\n throw new Error(`Invalid Throttle response: missing ${label}`);\n}\n\nfunction optionalDateString(value: unknown): string | null {\n if (value instanceof Date) return value.toISOString();\n if (typeof value === 'string' && value.length > 0) return value;\n return null;\n}\n\n/**\n * Like `optionalDateString`, but always reserializes to a full ISO string\n * (with milliseconds) rather than passing a raw string through unchanged.\n * `completedAt` is a fresh field with no legacy raw-string callers to stay\n * compatible with, so it normalizes cleanly instead of echoing whatever the\n * API sent.\n */\nfunction optionalIsoDateString(value: unknown): string | null {\n if (value instanceof Date) return value.toISOString();\n if (typeof value === 'string' && value.length > 0) {\n const d = new Date(value);\n return Number.isNaN(d.getTime()) ? value : d.toISOString();\n }\n return null;\n}\n\nfunction objectOrEmpty(value: unknown): Record<string, unknown> {\n return value && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n}\n\nfunction withoutUnderscoreKeys(value: unknown): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return {};\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>).filter(([key]) => !key.includes('_')),\n );\n}\n","import { ThrottleSubscriptionsError } from './errors';\nimport {\n normalizeCheckoutSession,\n normalizeCustomer,\n normalizeCustomerPaymentMethod,\n normalizePagination,\n normalizeSubscription,\n normalizeTrialEligibility,\n normalizeUsageItem,\n toIso,\n} from './normalize';\nimport type {\n ChangePlanInput,\n ChangeQuantityInput,\n CheckoutSession,\n CreateCheckoutSessionInput,\n CreateSubscriptionInput,\n Customer,\n CustomerPaymentMethod,\n ListSubscriptionsParams,\n PaginatedSubscriptions,\n RecordUsageInput,\n Subscription,\n SubscriptionInvoiceRefund,\n SubscriptionUsageItem,\n SubscriptionsClientContract,\n SubscriptionsClientOptions,\n ThrottleEnvelope,\n TrialEligibilityInput,\n TrialEligibilityResult,\n UpdateSubscriptionInput,\n WaivePeriodInput,\n} from './types';\n\nexport class SubscriptionsClient implements SubscriptionsClientContract {\n private readonly apiKey?: string;\n private readonly baseUrl: string;\n private readonly fetchImpl: typeof globalThis.fetch;\n private readonly fetcher?: SubscriptionsClientOptions['fetcher'];\n private readonly timeoutMs: number;\n\n constructor(opts: SubscriptionsClientOptions = {}) {\n const fetchImpl = opts.fetch ?? globalThis.fetch;\n if (!fetchImpl) throw new Error('SubscriptionsClient: fetch is required');\n if (!opts.apiKey && !opts.fetcher) {\n throw new Error('SubscriptionsClient: apiKey or fetcher is required');\n }\n\n this.apiKey = opts.apiKey;\n this.baseUrl = (opts.baseUrl ?? 'https://api.usethrottle.dev').replace(/\\/+$/, '');\n this.fetchImpl = fetchImpl;\n this.fetcher = opts.fetcher;\n this.timeoutMs = opts.timeoutMs ?? 30_000;\n }\n\n async request<T = unknown>(method: string, path: string, body?: unknown): Promise<T> {\n const envelope = await this.requestEnvelope<T>(method, path, body);\n if (Object.prototype.hasOwnProperty.call(envelope, 'data')) {\n return envelope.data as T;\n }\n return envelope as T;\n }\n\n async requestEnvelope<T = unknown>(\n method: string,\n path: string,\n body?: unknown,\n ): Promise<ThrottleEnvelope<T>> {\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);\n\n try {\n const init: RequestInit = {\n method,\n headers: {\n 'content-type': 'application/json',\n ...(this.apiKey ? { 'x-api-key': this.apiKey } : {}),\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n signal: ctrl.signal,\n };\n\n const res = this.fetcher\n ? await this.fetcher(path, init)\n : await this.fetchImpl(toAbsoluteUrl(this.baseUrl, path), init);\n\n if (res.status === 204) return { data: undefined as T };\n\n const json = (await res.json().catch(() => ({}))) as ThrottleEnvelope<T>;\n if (!res.ok) {\n throw new ThrottleSubscriptionsError({\n code: json.error?.code ?? 'unknown_error',\n message: json.error?.message ?? `HTTP ${res.status}`,\n statusCode: res.status,\n details: json.error?.details,\n responseHeaders: res.headers,\n });\n }\n return json;\n } finally {\n clearTimeout(timer);\n }\n }\n\n async create(input: CreateSubscriptionInput): Promise<Subscription> {\n const customerId = await this.resolveCustomerId(input.customerId, input.externalCustomerId);\n const data = await this.request<unknown>('POST', '/api/v1/subscriptions', {\n applicationId: input.applicationId,\n customerId,\n planReference: input.planReference,\n planName: input.planName,\n interval: input.interval,\n intervalUnit: input.intervalUnit,\n intervalCount: input.intervalCount,\n totalPayments: input.totalPayments,\n amount: input.amount,\n allowZeroAmount: input.allowZeroAmount,\n schedule: input.schedule,\n currency: input.currency,\n currentPeriodStart: toIso(input.currentPeriodStart),\n currentPeriodEnd: toIso(input.currentPeriodEnd),\n trialEnd: toIso(input.trialEnd),\n metadata: input.metadata ?? {},\n orderId: input.orderId,\n });\n return normalizeSubscription(data);\n }\n\n async list(params: ListSubscriptionsParams = {}): Promise<PaginatedSubscriptions> {\n const query = new URLSearchParams();\n setQuery(query, 'customerId', params.customerId);\n setQuery(query, 'externalCustomerId', params.externalCustomerId);\n setQuery(query, 'status', params.status);\n setQuery(query, 'interval', params.interval);\n setQuery(query, 'installment', params.installment);\n setQuery(query, 'q', params.q);\n setQuery(query, 'cursor', params.cursor);\n setQuery(query, 'limit', params.limit);\n setQuery(query, 'sort', params.sort);\n setQuery(query, 'createdAfter', toIso(params.createdAfter));\n setQuery(query, 'createdBefore', toIso(params.createdBefore));\n\n const suffix = query.toString() ? `?${query}` : '';\n const envelope = await this.requestEnvelope<unknown[]>('GET', `/api/v1/subscriptions${suffix}`);\n return {\n data: (envelope.data ?? []).map(normalizeSubscription),\n pagination: normalizePagination(envelope.meta?.pagination),\n };\n }\n\n async get(id: string): Promise<Subscription> {\n const data = await this.request<unknown>(\n 'GET',\n `/api/v1/subscriptions/${encodeURIComponent(id)}`,\n );\n return normalizeSubscription(data);\n }\n\n /**\n * A term-only edit: rename the plan, correct the cadence or the amount on\n * the row — no proration, no charge, no period reset. Mirrors\n * `PATCH /api/v1/subscriptions/{id}`. This is what `changePlan()` did\n * before 3.0.0; use `changePlan()` now for an actual plan change.\n */\n async update(id: string, input: UpdateSubscriptionInput): Promise<Subscription> {\n const data = await this.request<unknown>(\n 'PATCH',\n `/api/v1/subscriptions/${encodeURIComponent(id)}`,\n input,\n );\n return normalizeSubscription(data);\n }\n\n /**\n * A real plan change: prorated and charged immediately when\n * `effective: 'now'`, or scheduled for period end with no charge today.\n * Mirrors `POST /api/v1/subscriptions/{id}/change-plan`. The resolved\n * subscription carries `proration` when the server computed one.\n *\n * This is NOT the old `changePlan()` (a PATCH-style term edit with no\n * proration and no charge) — use `update()` for that.\n */\n async changePlan(input: ChangePlanInput): Promise<Subscription> {\n const { id, ...body } = input;\n const data = await this.request<unknown>(\n 'POST',\n `/api/v1/subscriptions/${encodeURIComponent(id)}/change-plan`,\n {\n planReference: body.planReference,\n planName: body.planName,\n interval: body.interval,\n intervalUnit: body.intervalUnit,\n intervalCount: body.intervalCount,\n amount: body.amount,\n allowZeroAmount: body.allowZeroAmount,\n effective: body.effective,\n },\n );\n return normalizeSubscription(data);\n }\n\n /**\n * Change the seat quantity: prorated and charged immediately when\n * `effective: 'now'`, or scheduled for period end with no charge today.\n * Mirrors `POST /api/v1/subscriptions/{id}/change-quantity`.\n */\n async changeQuantity(id: string, input: ChangeQuantityInput): Promise<Subscription> {\n const data = await this.request<unknown>(\n 'POST',\n `/api/v1/subscriptions/${encodeURIComponent(id)}/change-quantity`,\n { quantity: input.quantity, effective: input.effective },\n );\n return normalizeSubscription(data);\n }\n\n /**\n * Charge a past-due subscription's card again now, instead of waiting for\n * the next scheduled dunning retry. Mirrors\n * `POST /api/v1/subscriptions/{id}/retry-charge`.\n */\n async retryCharge(id: string): Promise<Subscription> {\n const data = await this.request<unknown>(\n 'POST',\n `/api/v1/subscriptions/${encodeURIComponent(id)}/retry-charge`,\n );\n return normalizeSubscription(data);\n }\n\n /**\n * Forgive the current past-due period — the merchant is not collecting it.\n * Mirrors `POST /api/v1/subscriptions/{id}/waive-period`.\n */\n async waivePeriod(id: string, input: WaivePeriodInput): Promise<Subscription> {\n const data = await this.request<unknown>(\n 'POST',\n `/api/v1/subscriptions/${encodeURIComponent(id)}/waive-period`,\n { reason: input.reason },\n );\n return normalizeSubscription(data);\n }\n\n /**\n * Set the saved card this one subscription renews on. Only this\n * subscription moves: the customer's default card and their other\n * subscriptions stay as they are. Nothing is charged now; the next renewal\n * (or dunning retry) charges the new card. Mirrors\n * `PATCH /api/v1/subscriptions/{id}/payment-method`.\n */\n async setPaymentMethod(id: string, paymentMethodId: string): Promise<Subscription> {\n const data = await this.request<unknown>(\n 'PATCH',\n `/api/v1/subscriptions/${encodeURIComponent(id)}/payment-method`,\n { paymentMethodId },\n );\n return normalizeSubscription(data);\n }\n\n /**\n * Record (upsert) a usage item for the subscription's current billing\n * period. Mirrors `POST /api/v1/subscriptions/{id}/usage`.\n */\n async recordUsage(id: string, input: RecordUsageInput): Promise<SubscriptionUsageItem> {\n const data = await this.request<unknown>(\n 'POST',\n `/api/v1/subscriptions/${encodeURIComponent(id)}/usage`,\n { kind: input.kind, unitCount: input.unitCount, unitPriceCents: input.unitPriceCents },\n );\n return normalizeUsageItem(data);\n }\n\n /**\n * List usage items recorded for the subscription's current billing period.\n * Mirrors `GET /api/v1/subscriptions/{id}/usage`.\n */\n async listUsage(id: string): Promise<SubscriptionUsageItem[]> {\n const envelope = await this.requestEnvelope<{ items?: unknown[] }>(\n 'GET',\n `/api/v1/subscriptions/${encodeURIComponent(id)}/usage`,\n );\n // This route answers `{ items: [...] }`, not the usual `{ data, meta }`\n // envelope, so `request()`'s data-unwrap would just hand back the whole\n // body — read `items` off the raw envelope instead.\n const items = (envelope as unknown as { items?: unknown[] }).items ?? [];\n return items.map(normalizeUsageItem);\n }\n\n async pause(id: string): Promise<Subscription> {\n const data = await this.request<unknown>(\n 'POST',\n `/api/v1/subscriptions/${encodeURIComponent(id)}/pause`,\n );\n return normalizeSubscription(data);\n }\n\n async resume(id: string): Promise<Subscription> {\n const data = await this.request<unknown>(\n 'POST',\n `/api/v1/subscriptions/${encodeURIComponent(id)}/resume`,\n );\n return normalizeSubscription(data);\n }\n\n async cancel(\n id: string,\n input: { atPeriodEnd?: boolean; refund?: 'none' | 'prorated' | 'last_cycle' } = {},\n ): Promise<Subscription> {\n const data = await this.request<unknown>(\n 'POST',\n `/api/v1/subscriptions/${encodeURIComponent(id)}/cancel`,\n { atPeriodEnd: input.atPeriodEnd ?? false, refund: input.refund ?? 'none' },\n );\n return normalizeSubscription(data);\n }\n\n /**\n * Refund one billing cycle.\n *\n * `intent` has no default: refunding money and ending the subscription are\n * separate decisions, and guessing either way is wrong often enough that the\n * API requires the caller to say which one they mean.\n */\n async refundInvoice(\n id: string,\n invoiceId: string,\n input: { intent: 'money_only' | 'refund_and_cancel'; amount?: number; reason?: string },\n ): Promise<SubscriptionInvoiceRefund> {\n return this.request<SubscriptionInvoiceRefund>(\n 'POST',\n `/api/v1/subscriptions/${encodeURIComponent(id)}/invoices/${encodeURIComponent(invoiceId)}/refund`,\n input,\n );\n }\n\n async createCheckoutSession(input: CreateCheckoutSessionInput): Promise<CheckoutSession> {\n const data = await this.request<unknown>('POST', '/api/v1/checkout/sessions', input);\n return normalizeCheckoutSession(data);\n }\n\n async checkTrialEligibility(input: TrialEligibilityInput): Promise<TrialEligibilityResult> {\n const data = await this.request<unknown>('POST', '/api/v1/subscriptions/eligibility-check', {\n paymentMethodId: input.paymentMethodId,\n });\n return normalizeTrialEligibility(data);\n }\n\n async getCustomerByExternalId(externalId: string): Promise<Customer | null> {\n try {\n const data = await this.request<unknown>(\n 'GET',\n `/api/v1/customers/by-external/${encodeURIComponent(externalId)}`,\n );\n return normalizeCustomer(data);\n } catch (err) {\n if (err instanceof ThrottleSubscriptionsError && err.statusCode === 404) return null;\n throw err;\n }\n }\n\n async listCustomerPaymentMethods(customerId: string): Promise<CustomerPaymentMethod[]> {\n const data = await this.request<unknown[]>(\n 'GET',\n `/api/v1/customers/${encodeURIComponent(customerId)}/payment-methods`,\n );\n return (data ?? []).map(normalizeCustomerPaymentMethod);\n }\n\n private async resolveCustomerId(\n customerId?: string,\n externalCustomerId?: string,\n ): Promise<string> {\n if (customerId) return customerId;\n if (!externalCustomerId) {\n throw new ThrottleSubscriptionsError({\n code: 'invalid_request',\n message: 'customerId or externalCustomerId is required',\n statusCode: 400,\n });\n }\n\n const customer = await this.getCustomerByExternalId(externalCustomerId);\n if (!customer) {\n throw new ThrottleSubscriptionsError({\n code: 'customer_not_found',\n message: 'Customer not found',\n statusCode: 404,\n });\n }\n return customer.id;\n }\n}\n\nexport function createSubscriptionsClient(opts: SubscriptionsClientOptions): SubscriptionsClient {\n return new SubscriptionsClient(opts);\n}\n\nfunction toAbsoluteUrl(baseUrl: string, path: string): string {\n if (/^https?:\\/\\//i.test(path)) return path;\n return `${baseUrl}${path.startsWith('/') ? path : `/${path}`}`;\n}\n\nfunction setQuery(query: URLSearchParams, key: string, value: unknown): void {\n if (value === undefined || value === null || value === '') return;\n query.set(key, String(value));\n}\n"],"mappings":"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","names":["ThrottleError"]}
@@ -1,4 +1,5 @@
1
1
  import { CSSProperties, ReactNode } from 'react';
2
+ import { CurrencyCode } from '@usethrottle/money';
2
3
  import { ThrottleError, ThrottleErrorArgs } from '@usethrottle/errors';
3
4
 
4
5
  type SubscriptionStatus = 'active' | 'paused' | 'cancelled' | 'past_due' | 'trialing' | 'unpaid' | 'completed';
@@ -42,7 +43,7 @@ interface Subscription {
42
43
  amount: number;
43
44
  /** #688 — number of seats. Per-seat price is `amount`; the period charge is `amount × quantity`. Defaults to 1. */
44
45
  quantity: number;
45
- currency: string;
46
+ currency: CurrencyCode;
46
47
  currentPeriodStart: string;
47
48
  currentPeriodEnd: string;
48
49
  trialEnd?: string | null;
@@ -100,7 +101,8 @@ interface SubscriptionRenewalIssue {
100
101
  charge?: {
101
102
  transactionId: string | null;
102
103
  amount: number;
103
- currency: string;
104
+ /** The subscription's currency when the API did not name one. */
105
+ currency: CurrencyCode;
104
106
  periodStart?: string;
105
107
  } | null;
106
108
  }
@@ -1,4 +1,5 @@
1
1
  import { CSSProperties, ReactNode } from 'react';
2
+ import { CurrencyCode } from '@usethrottle/money';
2
3
  import { ThrottleError, ThrottleErrorArgs } from '@usethrottle/errors';
3
4
 
4
5
  type SubscriptionStatus = 'active' | 'paused' | 'cancelled' | 'past_due' | 'trialing' | 'unpaid' | 'completed';
@@ -42,7 +43,7 @@ interface Subscription {
42
43
  amount: number;
43
44
  /** #688 — number of seats. Per-seat price is `amount`; the period charge is `amount × quantity`. Defaults to 1. */
44
45
  quantity: number;
45
- currency: string;
46
+ currency: CurrencyCode;
46
47
  currentPeriodStart: string;
47
48
  currentPeriodEnd: string;
48
49
  trialEnd?: string | null;
@@ -100,7 +101,8 @@ interface SubscriptionRenewalIssue {
100
101
  charge?: {
101
102
  transactionId: string | null;
102
103
  amount: number;
103
- currency: string;
104
+ /** The subscription's currency when the API did not name one. */
105
+ currency: CurrencyCode;
104
106
  periodStart?: string;
105
107
  } | null;
106
108
  }
package/dist/index.cjs CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,11 +17,20 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.tsx
21
31
  var index_exports = {};
22
32
  __export(index_exports, {
33
+ CURRENCIES: () => import_money.CURRENCIES,
23
34
  DunningBanner: () => DunningBanner,
24
35
  SubscriptionProvider: () => SubscriptionProvider,
25
36
  SubscriptionProviderWithClient: () => SubscriptionProviderWithClient,
@@ -28,6 +39,7 @@ __export(index_exports, {
28
39
  ThrottleError: () => import_errors2.ThrottleError,
29
40
  ThrottleSubscriptionsError: () => ThrottleSubscriptionsError,
30
41
  TrialCountdown: () => TrialCountdown,
42
+ UnknownCurrencyError: () => import_money.UnknownCurrencyError,
31
43
  cadenceLabel: () => cadenceLabel2,
32
44
  cadenceNoun: () => cadenceNoun2,
33
45
  canCancelSubscription: () => canCancelSubscription,
@@ -35,12 +47,21 @@ __export(index_exports, {
35
47
  canResumeSubscription: () => canResumeSubscription,
36
48
  createSubscriptionFetcher: () => createSubscriptionFetcher,
37
49
  createSubscriptionsClient: () => createSubscriptionsClient,
50
+ currencySymbol: () => import_money.currencySymbol,
38
51
  daysUntil: () => daysUntil,
52
+ formatMoney: () => import_money.formatMoney,
39
53
  installmentProgress: () => installmentProgress2,
54
+ isKnownCurrency: () => import_money.isKnownCurrency,
40
55
  isSubscriptionPastDue: () => isSubscriptionPastDue,
41
56
  isSubscriptionTrialing: () => isSubscriptionTrialing,
42
57
  isTerminalSubscription: () => isTerminalSubscription,
43
58
  isThrottleError: () => import_errors2.isThrottleError,
59
+ minorUnitsOf: () => import_money.minorUnitsOf,
60
+ money: () => money,
61
+ moneyValue: () => import_money.moneyValue,
62
+ parseMoney: () => import_money.parseMoney,
63
+ toDecimalString: () => import_money.toDecimalString,
64
+ toMinor: () => import_money.toMinor,
44
65
  useCancelSubscription: () => useCancelSubscription,
45
66
  useChangePlan: () => useChangePlan,
46
67
  useCreateCheckoutSession: () => useCreateCheckoutSession,
@@ -89,7 +110,8 @@ function normalizeSubscription(raw) {
89
110
  nextPaymentAmount: raw?.nextPaymentAmount == null ? null : Number(raw.nextPaymentAmount),
90
111
  amount: Number(raw?.amount ?? 0),
91
112
  quantity: Number(raw?.quantity ?? 1),
92
- currency: optionalString(raw?.currency) ?? "USD",
113
+ // No USD fallback (MC2-R35): a subscription without a currency is a broken response.
114
+ currency: requiredString(raw?.currency, "subscription.currency"),
93
115
  currentPeriodStart: requiredDateString(
94
116
  raw?.currentPeriodStart,
95
117
  "subscription.currentPeriodStart"
@@ -108,7 +130,8 @@ function normalizeSubscription(raw) {
108
130
  paymentMethodId: optionalString(raw?.paymentMethodId),
109
131
  deliveryMethod: raw?.deliveryMethod === "shipment" ? "shipment" : "access_grant",
110
132
  shippingAddress: raw?.shippingAddress && typeof raw.shippingAddress === "object" ? raw.shippingAddress : null,
111
- renewalIssue: normalizeRenewalIssue(raw?.renewalIssue),
133
+ // `currency` above has already been checked.
134
+ renewalIssue: normalizeRenewalIssue(raw?.renewalIssue, raw.currency),
112
135
  proration: raw?.proration ? {
113
136
  creditCents: raw.proration.creditCents,
114
137
  chargedCents: raw.proration.chargedCents,
@@ -131,7 +154,7 @@ function normalizePaymentSchedule(raw) {
131
154
  dueAt: optionalDateString(r?.dueAt)
132
155
  }));
133
156
  }
134
- function normalizeRenewalIssue(raw) {
157
+ function normalizeRenewalIssue(raw, subscriptionCurrency) {
135
158
  if (!raw || typeof raw !== "object") return null;
136
159
  return {
137
160
  kind: raw.kind,
@@ -144,7 +167,7 @@ function normalizeRenewalIssue(raw) {
144
167
  charge: raw.charge ? {
145
168
  transactionId: optionalString(raw.charge.transactionId),
146
169
  amount: Number(raw.charge.amount ?? 0),
147
- currency: optionalString(raw.charge.currency) ?? "USD",
170
+ currency: optionalString(raw.charge.currency) || subscriptionCurrency,
148
171
  periodStart: optionalString(raw.charge.periodStart) ?? void 0
149
172
  } : null
150
173
  };
@@ -1005,8 +1028,13 @@ function DunningBanner({
1005
1028
  }
1006
1029
  );
1007
1030
  }
1031
+
1032
+ // src/index.tsx
1033
+ var money = __toESM(require("@usethrottle/money"), 1);
1034
+ var import_money = require("@usethrottle/money");
1008
1035
  // Annotate the CommonJS export names for ESM import in node:
1009
1036
  0 && (module.exports = {
1037
+ CURRENCIES,
1010
1038
  DunningBanner,
1011
1039
  SubscriptionProvider,
1012
1040
  SubscriptionProviderWithClient,
@@ -1015,6 +1043,7 @@ function DunningBanner({
1015
1043
  ThrottleError,
1016
1044
  ThrottleSubscriptionsError,
1017
1045
  TrialCountdown,
1046
+ UnknownCurrencyError,
1018
1047
  cadenceLabel,
1019
1048
  cadenceNoun,
1020
1049
  canCancelSubscription,
@@ -1022,12 +1051,21 @@ function DunningBanner({
1022
1051
  canResumeSubscription,
1023
1052
  createSubscriptionFetcher,
1024
1053
  createSubscriptionsClient,
1054
+ currencySymbol,
1025
1055
  daysUntil,
1056
+ formatMoney,
1026
1057
  installmentProgress,
1058
+ isKnownCurrency,
1027
1059
  isSubscriptionPastDue,
1028
1060
  isSubscriptionTrialing,
1029
1061
  isTerminalSubscription,
1030
1062
  isThrottleError,
1063
+ minorUnitsOf,
1064
+ money,
1065
+ moneyValue,
1066
+ parseMoney,
1067
+ toDecimalString,
1068
+ toMinor,
1031
1069
  useCancelSubscription,
1032
1070
  useChangePlan,
1033
1071
  useCreateCheckoutSession,