@openrails/billing-ui 0.0.0-stage → 0.230.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/CHANGELOG.md +257 -0
- package/LICENSE +21 -0
- package/README.md +211 -2
- package/dist/account/account-billing.d.ts +19 -0
- package/dist/account/cancel-dialog.d.ts +18 -0
- package/dist/account/change-card-dialog.d.ts +14 -0
- package/dist/account/format.d.ts +25 -0
- package/dist/account/notice.d.ts +3 -0
- package/dist/account/payment-history.d.ts +8 -0
- package/dist/account/payment-methods-panel.d.ts +19 -0
- package/dist/account/section.d.ts +25 -0
- package/dist/account/status-badge.d.ts +8 -0
- package/dist/account/subscriptions-panel.d.ts +19 -0
- package/dist/appearance.d.ts +23 -0
- package/dist/authenticate.d.ts +8 -0
- package/dist/checkout-frame.d.ts +17 -0
- package/dist/checkout-page.d.ts +16 -0
- package/dist/checkout.d.ts +24 -0
- package/dist/client/client.d.ts +167 -0
- package/dist/client/errors.d.ts +26 -0
- package/dist/client/generated/openrails-routes.d.ts +2 -0
- package/dist/client/index.d.ts +4 -0
- package/dist/client/types.d.ts +754 -0
- package/dist/client-DhG2jv34.js +771 -0
- package/dist/client-DhG2jv34.js.map +1 -0
- package/dist/client.js +3 -0
- package/dist/components/billing-fields.d.ts +39 -0
- package/dist/components/card-brands.d.ts +6 -0
- package/dist/components/card-fields.d.ts +29 -0
- package/dist/components/ccbill-fields.d.ts +8 -0
- package/dist/components/methods.d.ts +13 -0
- package/dist/components/pay-button.d.ts +6 -0
- package/dist/components/qr.d.ts +6 -0
- package/dist/components/saved-methods.d.ts +9 -0
- package/dist/components/states.d.ts +10 -0
- package/dist/components/stripe-card.d.ts +17 -0
- package/dist/components/summary.d.ts +12 -0
- package/dist/components/ui/alert-dialog.d.ts +18 -0
- package/dist/components/ui/badge.d.ts +7 -0
- package/dist/components/ui/button.d.ts +8 -0
- package/dist/components/ui/card.d.ts +11 -0
- package/dist/components/ui/dialog.d.ts +17 -0
- package/dist/components/ui/input.d.ts +3 -0
- package/dist/components/ui/label.d.ts +3 -0
- package/dist/components/ui/radio-group.d.ts +5 -0
- package/dist/components/ui/separator.d.ts +3 -0
- package/dist/components/ui/skeleton.d.ts +2 -0
- package/dist/components/ui/spinner.d.ts +3 -0
- package/dist/components/ui/textarea.d.ts +3 -0
- package/dist/dist-CslWupfi.js +3311 -0
- package/dist/dist-CslWupfi.js.map +1 -0
- package/dist/errors-T-PRm3vV.js +54 -0
- package/dist/errors-T-PRm3vV.js.map +1 -0
- package/dist/fixtures.d.ts +9 -0
- package/dist/frame.d.ts +47 -0
- package/dist/hooks-DLFF-zx5.js +285 -0
- package/dist/hooks-DLFF-zx5.js.map +1 -0
- package/dist/i18n/context.d.ts +4 -0
- package/dist/i18n/index.d.ts +2 -0
- package/dist/i18n/messages.d.ts +58 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +4182 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/billing.d.ts +25 -0
- package/dist/lib/card-brands.d.ts +2 -0
- package/dist/lib/card-entry.d.ts +46 -0
- package/dist/lib/ccbill.d.ts +8 -0
- package/dist/lib/collect.d.ts +51 -0
- package/dist/lib/money.d.ts +9 -0
- package/dist/lib/period.d.ts +15 -0
- package/dist/lib/rail-meta.d.ts +15 -0
- package/dist/lib/redirect.d.ts +2 -0
- package/dist/lib/stripe-appearance.d.ts +2 -0
- package/dist/lib/stripe.d.ts +2 -0
- package/dist/locales/de.d.ts +2 -0
- package/dist/locales/de.js +204 -0
- package/dist/locales/de.js.map +1 -0
- package/dist/locales/en.d.ts +201 -0
- package/dist/locales/en.js +204 -0
- package/dist/locales/en.js.map +1 -0
- package/dist/locales/es.d.ts +2 -0
- package/dist/locales/es.js +204 -0
- package/dist/locales/es.js.map +1 -0
- package/dist/locales/ja.d.ts +2 -0
- package/dist/locales/ja.js +195 -0
- package/dist/locales/ja.js.map +1 -0
- package/dist/locales/ko.d.ts +2 -0
- package/dist/locales/ko.js +195 -0
- package/dist/locales/ko.js.map +1 -0
- package/dist/locales/zh.d.ts +2 -0
- package/dist/locales/zh.js +195 -0
- package/dist/locales/zh.js.map +1 -0
- package/dist/modal.d.ts +12 -0
- package/dist/provider.d.ts +18 -0
- package/dist/psp.d.ts +46 -0
- package/dist/react/context.d.ts +38 -0
- package/dist/react/hooks.d.ts +76 -0
- package/dist/react/index.d.ts +3 -0
- package/dist/react/provider.d.ts +18 -0
- package/dist/react/remote.d.ts +11 -0
- package/dist/react.js +37 -0
- package/dist/react.js.map +1 -0
- package/dist/save-payment-method.d.ts +26 -0
- package/dist/scope-context.d.ts +17 -0
- package/dist/scope.d.ts +6 -0
- package/dist/source.d.ts +14 -0
- package/dist/styles.css +3 -0
- package/dist/tokenized-card-form.d.ts +24 -0
- package/dist/types.d.ts +191 -0
- package/docs/1055-nmi-host-integration.md +28 -0
- package/docs/payment-form-contract.md +153 -0
- package/package.json +112 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Hosted checkout sessions (openrails#1124)
|
|
4
|
+
|
|
5
|
+
- OpenRails serves the checkout session; hosts no longer write
|
|
6
|
+
`/api/v1/checkout/sessions` routes. `client.createCheckoutSession()` mints
|
|
7
|
+
one for the signed-in customer (`priceKey` or `priceId`, `successUrl`) and
|
|
8
|
+
`client.checkoutSource(id)` reads and pays it with the id alone (no bearer).
|
|
9
|
+
A refusal the buyer can act on resolves as a `failed`, `blocked` or
|
|
10
|
+
`expired` result. A `card` rail pays through the shared page too.
|
|
11
|
+
- `<CheckoutFrame url onComplete theme>` frames the shared payment page and
|
|
12
|
+
`<CheckoutPage>` is that page; they speak an origin-checked frame protocol
|
|
13
|
+
(`ready`, `resize`, `complete`, `redirect`; `init {theme}`).
|
|
14
|
+
- `<Checkout onRedirect>` replaces the top-window navigation of redirect rails.
|
|
15
|
+
- The session document gains `embed_origin`.
|
|
16
|
+
|
|
17
|
+
## Server card entry (openrails#1129)
|
|
18
|
+
|
|
19
|
+
- Driver `card` (a PSP declared `card_entry: server`, flow `card`): `<Checkout>`
|
|
20
|
+
and `SavePaymentMethod` render plain card inputs with the Collect.js form's
|
|
21
|
+
layout and field errors, load no gateway script, and send
|
|
22
|
+
`card: {number, exp_month, exp_year, cvc}`. Inside a `BillingProvider` the
|
|
23
|
+
card is saved first (`addPaymentMethod({ provider, card })`) and charged by
|
|
24
|
+
id; a page without one sends `card` in `PayRequest`. The inputs are cleared
|
|
25
|
+
once the card is sent.
|
|
26
|
+
- `cardSetupDriver` may return `"card"`; `NewCard` takes `payment_token` or
|
|
27
|
+
`card`, never both.
|
|
28
|
+
|
|
29
|
+
## Catalog and plan-change client (openrails#1128)
|
|
30
|
+
|
|
31
|
+
- `@openrails/billing-ui/client` gains the public catalog (`listProducts`,
|
|
32
|
+
`listPrices`, `listCurrencies`), plan change (`previewTierChange`,
|
|
33
|
+
`changeTier`) and Solana (`getSolanaConfig`, `listSolanaTokens`,
|
|
34
|
+
`prepareSolanaTierChange`, `confirmSolanaTierChange`) calls, with the types
|
|
35
|
+
`Product`, `Price`, `Currency`, `TierChangePreview`, `TierChange`,
|
|
36
|
+
`SolanaConfig`, `SolanaToken`, `SolanaTierChangeTx` and `SolanaTierChange`.
|
|
37
|
+
`changeTier` requires an `idempotencyKey`; reuse it until the change
|
|
38
|
+
resolves.
|
|
39
|
+
- React: `useProducts`, and `useSubscriptions().changeTier` (per-row `pending`
|
|
40
|
+
`"change_tier"`, `onChange` `subscription.tier_changed`), which resolves to
|
|
41
|
+
the `TierChange` or a `BillingError`.
|
|
42
|
+
|
|
43
|
+
## Explicit payment method, fail-fast errors (openrails#1087, #1088)
|
|
44
|
+
|
|
45
|
+
- The checkout pre-selects the customer's default card (`PaymentMethod.default`,
|
|
46
|
+
`SavedPaymentMethod.default`) and always sends the chosen card's id.
|
|
47
|
+
OpenRails refuses a charge that names no method with
|
|
48
|
+
`payment_method_required` (400).
|
|
49
|
+
- A server error (5xx) from `pay` is shown at once and the panel returns to
|
|
50
|
+
ready; hosts keep their idempotency key so paying again replays. A host
|
|
51
|
+
source signals it by throwing an error with a numeric `status`
|
|
52
|
+
(`CheckoutSourceError`, or any error carrying `status`).
|
|
53
|
+
- The client never retries a write. A GET retries once, only on a network
|
|
54
|
+
error or 502/503/504 (429/503 with `Retry-After`), within `RETRY_BUDGET_MS`
|
|
55
|
+
(2 s). New `isServerError`; a 5xx without an error envelope has code
|
|
56
|
+
`server_error`.
|
|
57
|
+
|
|
58
|
+
## One-click card subscriptions (openrails#1085)
|
|
59
|
+
|
|
60
|
+
- A checkout host relays a card subscription's pay request with OpenRails'
|
|
61
|
+
`CreateCheckoutSessionRequest.Confirm`; a new Collect.js token subscribes in
|
|
62
|
+
one call. No package API change.
|
|
63
|
+
|
|
64
|
+
## Advertised checkout rails (openrails#1078)
|
|
65
|
+
|
|
66
|
+
- Breaking: `checkoutRails(offers)` takes OpenRails' checkout options alone.
|
|
67
|
+
Each option carries the `driver` and `public_config` OpenRails derived from
|
|
68
|
+
the armed PSP (Solana: `token_symbol`, `token_name`, `network`); the package
|
|
69
|
+
no longer derives drivers from `psps`. `CheckoutRailOffer` gains `selector`,
|
|
70
|
+
`driver` and `public_config`.
|
|
71
|
+
|
|
72
|
+
## Moved into OpenRails
|
|
73
|
+
|
|
74
|
+
The package now lives in `open-rails/openrails` under `sdk/billing-ui` and
|
|
75
|
+
takes the OpenRails version: each OpenRails release `vX.Y.Z` attaches
|
|
76
|
+
`openrails-billing-ui-X.Y.Z.tgz`. The e2e server and generated contract build
|
|
77
|
+
the OpenRails at the same commit. `OPENRAILS_VERSION` is gone from the
|
|
78
|
+
generated contract.
|
|
79
|
+
|
|
80
|
+
## 0.9.0
|
|
81
|
+
|
|
82
|
+
One embedded card panel for one-time purchases and subscriptions, on every
|
|
83
|
+
card PSP (openrails#1064). Requires OpenRails v0.164.0.
|
|
84
|
+
|
|
85
|
+
- Stripe Elements checkout rail (`driver: "stripe_elements"`, from a PSP with
|
|
86
|
+
`flow: "elements"`): saved Stripe cards or a new card in the page, 3-D
|
|
87
|
+
Secure via `authenticatePayment`; no redirect to hosted Checkout. The
|
|
88
|
+
Payment Element is cards only (no Link bank tab or wallets).
|
|
89
|
+
- One screen: saved cards (brand •••• last4 · MM/YY, most recent first),
|
|
90
|
+
inline "Use a new card", one "Pay $X" / "Subscribe for $X every <period>"
|
|
91
|
+
button with the agreement line. No provider chooser for a single rail.
|
|
92
|
+
- New cards are always saved to the account (no consent checkbox) before
|
|
93
|
+
paying by id; Collect.js display metadata (`last_four`, `card_type`,
|
|
94
|
+
`expiry_date`) is sent with every token.
|
|
95
|
+
- Declines stay on the panel: `PayResult.failure` / `CheckoutSession.failure`
|
|
96
|
+
(`{ reason, message, field }`) render next to the card field; retry with
|
|
97
|
+
another card. `requires_action` + `operation_id` authenticates in the page.
|
|
98
|
+
- Collect.js `validationCallback`: inline number/expiry/CVC errors; the
|
|
99
|
+
button waits for three valid fields. Stripe Elements and Collect.js fields
|
|
100
|
+
are themed from the page tokens.
|
|
101
|
+
- `defaultCountry` on Checkout / SavePaymentMethod / AccountBilling /
|
|
102
|
+
TokenizedCardForm; fallback: the browser locale's region
|
|
103
|
+
(`initialCountry`, `browserCountry`).
|
|
104
|
+
- `PspConfig.checkout`; `checkoutPsps(psps)` — only checkout PSPs take new
|
|
105
|
+
cards. `isCardRail`, `useOptionalBillingContext`.
|
|
106
|
+
- `CheckoutModal`: always closable; `gate` renders host content (sign-in)
|
|
107
|
+
in place of the checkout.
|
|
108
|
+
- Account: card labels read "Visa •••• 4242 · 12/30"; failed payments show
|
|
109
|
+
`payment.failure.message`.
|
|
110
|
+
- Breaking: `paymentMethods.consent`/`enterCard` messages are replaced by
|
|
111
|
+
`paymentMethods.saveNotice`; `cardLabel` is "{brand} •••• {last4}".
|
|
112
|
+
|
|
113
|
+
## 0.8.0
|
|
114
|
+
|
|
115
|
+
Provider-neutral hosts: a host passes OpenRails's browser PSP configs through
|
|
116
|
+
and never branches on Stripe, NMI or any other provider.
|
|
117
|
+
|
|
118
|
+
- `checkoutRails(offers, psps)` / `savedMethodsFor(methods, rails)` derive the
|
|
119
|
+
checkout rails and chargeable saved cards from each PSP's `flow` and public
|
|
120
|
+
config.
|
|
121
|
+
- `SavePaymentMethod`: consented in-page card saving with any PSP — Collect.js
|
|
122
|
+
tokenization or Stripe Elements card setup (Stripe.js is loaded on first
|
|
123
|
+
use). `canSavePaymentMethod`, `cardSetupDriver`.
|
|
124
|
+
- `authenticatePayment(client, operationId, psp)`: 3-D Secure for a pending
|
|
125
|
+
payment operation. `canAuthenticatePayment`.
|
|
126
|
+
- Client: `createCardSetup`, `getCardSetup`, `confirmCardSetup`,
|
|
127
|
+
`getPaymentAuthentication`, `confirmPaymentAuthentication`.
|
|
128
|
+
- Breaking: `AccountBilling`/`PaymentMethodsPanel` take `psps` (and optional
|
|
129
|
+
`cardSetupReturnURL`) instead of `cardSetup`; `CardSetupConfig` is removed.
|
|
130
|
+
Stripe card setup needs OpenRails serving Stripe's `publishable_key`
|
|
131
|
+
(openrails#1062).
|
|
132
|
+
|
|
133
|
+
## 0.7.0
|
|
134
|
+
|
|
135
|
+
- Periods are exact. OpenRails windows are hours, so a 720h price reads
|
|
136
|
+
"every 30 days" (was "every month") and 8760h "every 365 days"; only exact
|
|
137
|
+
weeks, days or hours are named, in the account panels and the checkout
|
|
138
|
+
summary, in all six locales.
|
|
139
|
+
- Plural messages: `interval.every|per|access.<hour|day|week>` are CLDR plural
|
|
140
|
+
nodes (`{ one, other }`, exact `"1"` for 毎日-style forms) chosen by the
|
|
141
|
+
provider's `locale`; `Translator.plural(key, count)`. Breaking for hosts
|
|
142
|
+
overriding the removed `interval.day|week|month|year|days|hours` keys.
|
|
143
|
+
- Payment history names what was bought: the product's `display_name` from
|
|
144
|
+
OpenRails (`payment.product`, OpenRails after v0.160.0) and the renewal
|
|
145
|
+
period; older servers fall back to "Subscription"/"Purchase".
|
|
146
|
+
- Checkout summary copy ("Renews {period}") is a message: `checkout.renews`.
|
|
147
|
+
- The e2e harness and route contract pin OpenRails master `78039ea` (first
|
|
148
|
+
commit serving `payment.product`; untagged, after v0.160.0).
|
|
149
|
+
|
|
150
|
+
## 0.6.0
|
|
151
|
+
|
|
152
|
+
- "Add card" works against real OpenRails, which requires the PSP that
|
|
153
|
+
tokenized the card: `CardSetupConfig.provider` (the PSP key, e.g. `"nmi"`)
|
|
154
|
+
is required and sent as `NewCard.provider`. Before, every add was refused
|
|
155
|
+
with 400 `provider is required`.
|
|
156
|
+
|
|
157
|
+
## 0.5.2
|
|
158
|
+
|
|
159
|
+
- `renderSubscriptionFooter` (on `SubscriptionsPanel` and `AccountBilling`)
|
|
160
|
+
renders host content under a subscription row, e.g. a plan-change control.
|
|
161
|
+
- `useBillingRefresh()` (from `./react`) refetches every hook after a
|
|
162
|
+
host-side change such as a plan switch.
|
|
163
|
+
- The cancel and change-card dialogs use the panel's `appearance`; they read
|
|
164
|
+
only the provider's, so `AccountBilling appearance` missed them.
|
|
165
|
+
|
|
166
|
+
## 0.5.1
|
|
167
|
+
|
|
168
|
+
- `appearance.theme: "inherit"`: no bundled palette; components use the host
|
|
169
|
+
page's shadcn tokens and follow its `.dark` class.
|
|
170
|
+
- `SubscriptionsPanel`: "Change card" switches the saved card an active NMI
|
|
171
|
+
subscription renews on (`useSubscriptions().setPaymentMethod`), which now
|
|
172
|
+
notifies `subscription.payment_method_changed`.
|
|
173
|
+
|
|
174
|
+
## 0.5.0
|
|
175
|
+
|
|
176
|
+
Account billing, alongside checkout. No change to checkout's API.
|
|
177
|
+
|
|
178
|
+
- `@openrails/billing-ui/client`: `createBillingClient` for the OpenRails
|
|
179
|
+
customer surface (`/billing/v1/me/*`): subscriptions (list, get, cancel with
|
|
180
|
+
feedback, resume, payment method, Solana on-chain cancel), payment methods
|
|
181
|
+
(list, add tokenized card, remove, per-currency default), payments, invoices,
|
|
182
|
+
status. zod-validated responses, `BillingError` from the error envelope, the
|
|
183
|
+
pinned currency registry for exact money.
|
|
184
|
+
- `@openrails/billing-ui/react`: `BillingProvider` (`onChange` for host cache
|
|
185
|
+
invalidation), `useSubscriptions`, `usePaymentMethods`, `usePayments`.
|
|
186
|
+
- Styled: `AccountBilling`, `SubscriptionsPanel` with cancel/resume dialog and
|
|
187
|
+
provider-portal links, `PaymentMethodsPanel` (adding a card uses
|
|
188
|
+
`TokenizedCardForm`), `PaymentHistory`, `BillingStatusBadge`,
|
|
189
|
+
`BillingUiProvider`, `BillingUiRoot`.
|
|
190
|
+
- Messages: typed bundles with `en de es ja ko zh` under `./locales/*`.
|
|
191
|
+
- `formatAmount` takes an optional locale.
|
|
192
|
+
- The route contract and e2e suite run against real OpenRails v0.159.0.
|
|
193
|
+
|
|
194
|
+
## 0.4.2
|
|
195
|
+
|
|
196
|
+
No API or visual change.
|
|
197
|
+
|
|
198
|
+
- Components import `cn` from the [`cn`](https://github.com/shadcn-ui/cn)
|
|
199
|
+
package (pinned `0.4.0`), replacing `clsx` and `tailwind-merge`.
|
|
200
|
+
|
|
201
|
+
## 0.4.1
|
|
202
|
+
|
|
203
|
+
Visual only; no API change.
|
|
204
|
+
|
|
205
|
+
- UI primitives regenerated as shadcn `base-vega` on a zinc palette.
|
|
206
|
+
- Theme tokens now map to Tailwind colors, so token utilities (`bg-primary`,
|
|
207
|
+
`text-muted-foreground`, `border-input`, …) render; in 0.4.0 they emitted no
|
|
208
|
+
CSS, leaving the pay button and selected radios unstyled.
|
|
209
|
+
- `dark:` variants follow `appearance.theme` instead of the OS alone.
|
|
210
|
+
- `CheckoutModal` now paints its popover panel; buttons inside `.orck` drop the
|
|
211
|
+
UA button face.
|
|
212
|
+
|
|
213
|
+
## 0.4.0
|
|
214
|
+
|
|
215
|
+
Breaking: the package is renamed `openrails-checkout` → `@openrails/billing-ui`.
|
|
216
|
+
|
|
217
|
+
- Import from `@openrails/billing-ui` and `@openrails/billing-ui/styles.css`.
|
|
218
|
+
- The injected stylesheet is `<style id="billing-ui-styles" data-billing-ui>`.
|
|
219
|
+
- Releases attach the packed tarball to the GitHub release instead of
|
|
220
|
+
publishing to npm:
|
|
221
|
+
`https://github.com/open-rails/billing-ui/releases/download/v0.4.0/openrails-billing-ui-0.4.0.tgz`.
|
|
222
|
+
|
|
223
|
+
## 0.3.0
|
|
224
|
+
|
|
225
|
+
Breaking: the session document carries exact money.
|
|
226
|
+
|
|
227
|
+
- Accepted `processing` outcomes poll the same source without repeating payment
|
|
228
|
+
or tokenization. Ambiguous pay errors retain that pending attempt; local expiry
|
|
229
|
+
cannot turn it into a failure. Pending sessions may omit/null `expires_at`.
|
|
230
|
+
- Export `TokenizedCardForm` for separately consented NMI card setup, reusing the
|
|
231
|
+
existing hosted fields without presenting setup as a payment.
|
|
232
|
+
- Source changes fence late payment callbacks from the previous checkout.
|
|
233
|
+
|
|
234
|
+
- `plan.unit_amount`, `line_items[].amount`, `tax` and `due_today` are int64
|
|
235
|
+
decimal strings of `plan.currency`'s native unit; `plan.unit_decimals` (the
|
|
236
|
+
currency's registered scale) is required. Numeric amounts are refused as an
|
|
237
|
+
unavailable session. Replaces `unit_amount_micros`, `amount_micros`,
|
|
238
|
+
`tax_micros` and `due_today_micros`, which were JSON numbers at an assumed
|
|
239
|
+
six decimals.
|
|
240
|
+
- Rendering never passes money through a JS number (`BigInt` scaling, exact
|
|
241
|
+
Intl decimal formatting, refusal instead of rounding). `formatAmount`,
|
|
242
|
+
`amountToDecimal`, `addAmounts`, `isAmount`, `amountSchema` and
|
|
243
|
+
`unitDecimalsSchema` are exported.
|
|
244
|
+
- Hosts build the plan with `openrails.NewHostedCheckoutPlan` (OpenRails
|
|
245
|
+
`HostedCheckoutSession` types); the package decodes OpenRails' canonical
|
|
246
|
+
`hosted_checkout_session.json` fixture.
|
|
247
|
+
|
|
248
|
+
## 0.2.5
|
|
249
|
+
|
|
250
|
+
- A Solana option is named after the host-bound token and network; the former
|
|
251
|
+
`USDC` default is removed.
|
|
252
|
+
- Releases publish to npm through the GitHub release workflow.
|
|
253
|
+
|
|
254
|
+
## 0.2.4
|
|
255
|
+
|
|
256
|
+
- Hosts must accept `name_on_card` on the pay endpoint; `first_name` and
|
|
257
|
+
`last_name` are no longer emitted.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 OpenRails and Paul Fidika
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,212 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @openrails/billing-ui
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Embeddable OpenRails billing UI: the checkout flow and the customer's account
|
|
4
|
+
billing (subscriptions, saved cards, payment history).
|
|
5
|
+
|
|
6
|
+
| Import | Contents |
|
|
7
|
+
| --------------------------------- | ---------------------------------------------------------------------------------- |
|
|
8
|
+
| `@openrails/billing-ui/client` | Framework-free typed client for `/billing/v1/me/*` and the catalog, `BillingError` |
|
|
9
|
+
| `@openrails/billing-ui/react` | `BillingProvider` and headless hooks |
|
|
10
|
+
| `@openrails/billing-ui` | Styled checkout and account components, `BillingUiProvider`, i18n |
|
|
11
|
+
| `@openrails/billing-ui/locales/*` | `en de es ja ko zh` message bundles |
|
|
12
|
+
|
|
13
|
+
The checkout owns the browser payment flow. OpenRails holds the checkout
|
|
14
|
+
session: the signed-in customer mints one for a price, and its `ocs_` id alone
|
|
15
|
+
reads and pays it. Card data is tokenized in NMI-hosted Collect.js iframes and
|
|
16
|
+
never enters the host application, unless the PSP takes cards on OpenRails
|
|
17
|
+
itself (`card_entry: server`, driver `card`).
|
|
18
|
+
|
|
19
|
+
See [Payment form contract](docs/payment-form-contract.md) for the exact-money
|
|
20
|
+
session document, billing fields, browser-autofill behavior, and the checkout
|
|
21
|
+
request schema.
|
|
22
|
+
|
|
23
|
+
The package lives in the OpenRails repository and shares its version: each
|
|
24
|
+
OpenRails release `vX.Y.Z` attaches `openrails-billing-ui-X.Y.Z.tgz`.
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
pnpm add https://github.com/open-rails/openrails/releases/download/vX.Y.Z/openrails-billing-ui-X.Y.Z.tgz
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Checkout
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import { createBillingClient } from "@openrails/billing-ui/client"
|
|
34
|
+
import { Checkout, CheckoutFrame } from "@openrails/billing-ui"
|
|
35
|
+
import "@openrails/billing-ui/styles.css"
|
|
36
|
+
|
|
37
|
+
const billing = createBillingClient({ fetch: auth.authFetch })
|
|
38
|
+
const session = await billing.createCheckoutSession({ priceKey: "pro-monthly" })
|
|
39
|
+
|
|
40
|
+
// A shared payment page (Config.HTTP.Checkout.PageURL) answers with a url:
|
|
41
|
+
<CheckoutFrame url={session.url} theme="dark" onComplete={() => refetchAccess()} />
|
|
42
|
+
// Without one, the app renders the checkout itself:
|
|
43
|
+
<Checkout source={billing.checkoutSource(session.id)} onComplete={() => refetchAccess()} />
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`onComplete` is a hint: confirm access from your own authenticated API before
|
|
47
|
+
granting anything. Pass `successUrl` to return the buyer from a redirect rail
|
|
48
|
+
(CCBill, Stripe hosted); it must be on one of your app's return origins.
|
|
49
|
+
|
|
50
|
+
The payment host serves `<CheckoutPage>` from one HTML entry at `PageURL`,
|
|
51
|
+
behind its adapter's `CheckoutFramePolicy` (only the sites in
|
|
52
|
+
`Config.HTTP.Checkout.EmbedOrigins` may frame it):
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
import { BillingUiProvider, CheckoutPage } from "@openrails/billing-ui"
|
|
56
|
+
|
|
57
|
+
createRoot(root).render(
|
|
58
|
+
<BillingUiProvider>
|
|
59
|
+
<CheckoutPage appearance={{ variables: brand }} />
|
|
60
|
+
</BillingUiProvider>
|
|
61
|
+
)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The page reads the session id from its URL fragment and talks to its frame
|
|
65
|
+
with `postMessage`, origin-checked both ways: page to app `ready`,
|
|
66
|
+
`resize {height}`, `complete {status}` and `redirect {url}` (a nested frame
|
|
67
|
+
cannot navigate the top window, so the app does); app to page
|
|
68
|
+
`init {theme}`. The page messages only the app origin recorded on its session.
|
|
69
|
+
|
|
70
|
+
## Account billing
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
import { createBillingClient } from "@openrails/billing-ui/client"
|
|
74
|
+
import { BillingProvider } from "@openrails/billing-ui/react"
|
|
75
|
+
import { AccountBilling, BillingUiProvider } from "@openrails/billing-ui"
|
|
76
|
+
import { de } from "@openrails/billing-ui/locales/de"
|
|
77
|
+
|
|
78
|
+
// auth-ui's authFetch attaches the bearer and retries once after a refresh;
|
|
79
|
+
// `getToken: () => token` works for any other auth.
|
|
80
|
+
const billing = createBillingClient({ baseUrl: "/billing/v1", fetch: auth.authFetch })
|
|
81
|
+
|
|
82
|
+
<BillingUiProvider appearance={{ theme: "auto" }} messages={de} locale="de" navigate={navigate}>
|
|
83
|
+
<BillingProvider client={billing} onChange={() => queryClient.invalidateQueries({ queryKey: ["billing"] })}>
|
|
84
|
+
<AccountBilling
|
|
85
|
+
plansHref="/plans"
|
|
86
|
+
psps={checkoutConfig.psps} // OpenRails checkout config; enables "Add card"
|
|
87
|
+
defaultCurrency="USD" // enables "Make default"
|
|
88
|
+
sendSolanaTransaction={(tx) => wallet.signAndSend(tx)} // Solana-rail cancel
|
|
89
|
+
/>
|
|
90
|
+
</BillingProvider>
|
|
91
|
+
</BillingUiProvider>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Catalog and plan changes
|
|
95
|
+
|
|
96
|
+
The client also reads the public catalog and changes a subscription's plan.
|
|
97
|
+
No UI ships for these; hosts render their own. The catalog, currency and
|
|
98
|
+
Solana reads are public routes, served only when the host mounts OpenRails'
|
|
99
|
+
checkout routes.
|
|
100
|
+
|
|
101
|
+
| Call | Route |
|
|
102
|
+
| --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
|
|
103
|
+
| `listProducts()`, `listPrices({ currency, product, type })` | `GET /products`, `GET /prices` |
|
|
104
|
+
| `listCurrencies()` (`client.currencies` is the pinned copy) | `GET /currencies` |
|
|
105
|
+
| `previewTierChange(id, priceId)` | `POST /me/subscriptions/{id}/change-tier/preview` |
|
|
106
|
+
| `changeTier(id, { priceId, idempotencyKey })` | `POST /me/subscriptions/{id}/change-tier` |
|
|
107
|
+
| `getSolanaConfig()`, `listSolanaTokens({ priceId, wallet })` | `GET /solana/config`, `GET /solana/tokens` |
|
|
108
|
+
| `prepareSolanaTierChange(id, newPriceId)`, `confirmSolanaTierChange(id, { signature, newPriceId })` | `POST /me/subscriptions/{id}/solana-tier-change`, `.../confirm` |
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
const preview = await billing.previewTierChange(sub.id, price.id) // amount_due_now, effective
|
|
112
|
+
const change = await billing.changeTier(sub.id, {
|
|
113
|
+
priceId: price.id,
|
|
114
|
+
idempotencyKey,
|
|
115
|
+
})
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
- `changeTier` is a money write. Mint one `idempotencyKey` per attempt and
|
|
119
|
+
reuse it until the change resolves (`status: "processing"`, a
|
|
120
|
+
`tier_change_in_flight` refusal naming `metadata.operation_id`, a 5xx or a
|
|
121
|
+
lost response), so OpenRails replays the stored result instead of charging
|
|
122
|
+
twice. `requires_action` carries `operation_id` for `authenticatePayment`;
|
|
123
|
+
replay the same key afterwards.
|
|
124
|
+
- Solana rail: the wallet signs and sends `prepareSolanaTierChange`'s
|
|
125
|
+
`transaction`; pass its signature to `confirmSolanaTierChange`. Keep the
|
|
126
|
+
signature until the confirm succeeds; confirming again replays the result.
|
|
127
|
+
|
|
128
|
+
## Provider-neutral flows
|
|
129
|
+
|
|
130
|
+
Hosts pass OpenRails's browser PSP configs (`GET /checkout-config`, `psps`)
|
|
131
|
+
through unchanged; the PSP's `flow` and public `config` pick the browser flow
|
|
132
|
+
(Collect.js, native card inputs, Stripe Elements, redirect, wallet). Hosts never branch on a
|
|
133
|
+
provider:
|
|
134
|
+
|
|
135
|
+
- `checkoutRails(offers)` and `savedMethodsFor(methods, rails)` build a
|
|
136
|
+
`CheckoutSource`'s `rails` and `saved_methods` (the default card first, pre-selected; paying sends
|
|
137
|
+
the chosen card's id explicitly).
|
|
138
|
+
`offers` is OpenRails' `ListCheckoutRailOptions` result, passed through: it
|
|
139
|
+
lists exactly the armed PSPs whose rail can make this sale (Solana when it is
|
|
140
|
+
configured, never CCBill for a new subscription), each with its `driver` and
|
|
141
|
+
`public_config`. An offer without a driver is not rendered.
|
|
142
|
+
Card rails (`collect_js`, `card`, `stripe_elements`) render one panel: saved cards,
|
|
143
|
+
an inline new card and one Pay/Subscribe button, which is the payer's
|
|
144
|
+
confirmation of the displayed terms. No provider chooser with one rail.
|
|
145
|
+
- Inside a `BillingProvider`, a new card is always saved to the account first
|
|
146
|
+
and the source is paid with `payment_method_id`; `requires_action` results
|
|
147
|
+
carrying `operation_id` run 3-D Secure in the page. A `failed` result stays
|
|
148
|
+
on the panel with `failure.message` next to its `field`, so the buyer can
|
|
149
|
+
pick another card; the host gives each new attempt a new idempotency key.
|
|
150
|
+
- Only PSPs with `checkout !== false` (`checkoutPsps`) take new cards; others
|
|
151
|
+
stay listed so existing cards and subscriptions keep working.
|
|
152
|
+
- `<SavePaymentMethod psp={psp} onSaved={(id) => ...} />` saves a card in the
|
|
153
|
+
page (needs `BillingProvider`); `canSavePaymentMethod(psp)` filters PSPs
|
|
154
|
+
that support it. After an off-page verification the provider returns to
|
|
155
|
+
`returnURL(setupId)`; confirm with `client.confirmCardSetup(id)`.
|
|
156
|
+
- `authenticatePayment(client, operationId, psp)` completes a pending
|
|
157
|
+
payment's 3-D Secure challenge when `canAuthenticatePayment(psp)`.
|
|
158
|
+
- `defaultCountry` (Checkout, SavePaymentMethod, AccountBilling) preselects
|
|
159
|
+
the billing country, else the browser locale's region.
|
|
160
|
+
- `CheckoutModal gate={<SignIn />}` renders host content (e.g. sign-in) in
|
|
161
|
+
the modal instead of the checkout until cleared.
|
|
162
|
+
|
|
163
|
+
- Panels: `SubscriptionsPanel` (cancel, resume, change card),
|
|
164
|
+
`PaymentMethodsPanel`, `PaymentHistory`, `BillingStatusBadge`,
|
|
165
|
+
`CancelSubscriptionDialog`; `AccountBilling` stacks them.
|
|
166
|
+
- `renderSubscriptionFooter={(s) => ...}` adds host content under a
|
|
167
|
+
subscription row; `useBillingRefresh()` refetches after host-side changes.
|
|
168
|
+
- Hooks: `useSubscriptions` (`cancel`, `cancelOnChain`, `resume`,
|
|
169
|
+
`setPaymentMethod`, `changeTier`, per-row `pending`), `usePaymentMethods`
|
|
170
|
+
(`add`, `remove`, `setDefault`), `usePayments` (offset pages), `useProducts`
|
|
171
|
+
(the catalog). Actions resolve to `null` or a `BillingError`; they never
|
|
172
|
+
throw. `changeTier` resolves to the `TierChange` instead of `null`. Cancel
|
|
173
|
+
and resume are queued by OpenRails (202); hooks re-read the subscription
|
|
174
|
+
until the change shows.
|
|
175
|
+
- Money is exact: `/me` amounts are int64 native-unit strings, scaled by the
|
|
176
|
+
OpenRails currency registry (`currencies` option to extend it).
|
|
177
|
+
- Messages: English is complete and the fallback; `messages` layers bundles,
|
|
178
|
+
`t` lets the host's i18n win. `useMessages().error(err)` maps error codes.
|
|
179
|
+
Count-dependent messages are CLDR plural nodes (`{ one, other }`, plus an
|
|
180
|
+
exact `"1"` like ICU `=1`), selected with `locale`.
|
|
181
|
+
- Periods are exact: OpenRails windows are hours, so 720h reads "every 30
|
|
182
|
+
days", never "monthly"; only exact weeks, days or hours are named.
|
|
183
|
+
- Styles are scoped under `.orck`; `appearance.theme` is `light`, `dark`,
|
|
184
|
+
`auto` or `inherit`. `inherit` bundles no palette: the host page's shadcn
|
|
185
|
+
tokens (`--background`, `--primary`, ...) and its `.dark` class apply.
|
|
186
|
+
|
|
187
|
+
## UI primitives
|
|
188
|
+
|
|
189
|
+
`src/components/ui/*` is shadcn (`base-vega`, zinc; see `components.json`),
|
|
190
|
+
managed with `pnpm dlx shadcn@4.21.0 add <name> --overwrite`, importing `cn`
|
|
191
|
+
from the [`cn`](https://github.com/shadcn-ui/cn) package.
|
|
192
|
+
|
|
193
|
+
## E2E against real OpenRails
|
|
194
|
+
|
|
195
|
+
`e2e/server` is a Go module that builds the OpenRails at this commit (`replace`
|
|
196
|
+
to the repository root) with AuthKit. It serves the
|
|
197
|
+
embedded `/billing/v1` API and `/auth/v1` on a throwaway `postgres:18-alpine`
|
|
198
|
+
container (Docker and Go required), with test-only `POST /__test/users` (user +
|
|
199
|
+
access token) and `POST /__test/users/{id}/billing` (imported subscription,
|
|
200
|
+
sale and saved card on a credential-less NMI PSP).
|
|
201
|
+
|
|
202
|
+
```sh
|
|
203
|
+
pnpm test:e2e # Playwright against the real server
|
|
204
|
+
pnpm contract # regenerate src/client/generated from the in-repo OpenRails
|
|
205
|
+
pnpm contract:check # fail if the generated contract is stale
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
`e2e/openrails/account.spec.ts` drives the packaged `AccountBilling` (built from
|
|
209
|
+
`dist/`) through list, cancel, resume, the in-use card refusal and history. Set
|
|
210
|
+
`BILLING_UI_SCREENSHOTS=<dir>` to capture light, dark and mobile screenshots.
|
|
211
|
+
Card deletion calls NMI, which the harness has no credentials for; jsdom tests
|
|
212
|
+
cover it.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { CheckoutAppearance } from '../appearance';
|
|
2
|
+
import { SendSolanaTransaction } from '../client/client';
|
|
3
|
+
import { PaymentMethodsPanelProps } from './payment-methods-panel';
|
|
4
|
+
import { SubscriptionsPanelProps } from './subscriptions-panel';
|
|
5
|
+
export interface AccountBillingProps {
|
|
6
|
+
psps?: PaymentMethodsPanelProps["psps"];
|
|
7
|
+
cardSetupReturnURL?: PaymentMethodsPanelProps["cardSetupReturnURL"];
|
|
8
|
+
defaultCurrency?: string;
|
|
9
|
+
/** Billing country to preselect when adding a card. */
|
|
10
|
+
defaultCountry?: string;
|
|
11
|
+
sendSolanaTransaction?: SendSolanaTransaction;
|
|
12
|
+
plansHref?: string;
|
|
13
|
+
renderSubscriptionFooter?: SubscriptionsPanelProps["renderSubscriptionFooter"];
|
|
14
|
+
historyPageSize?: number;
|
|
15
|
+
appearance?: CheckoutAppearance;
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
/** Subscriptions, payment methods and history in one column. */
|
|
19
|
+
export declare function AccountBilling({ psps, cardSetupReturnURL, defaultCurrency, defaultCountry, sendSolanaTransaction, plansHref, renderSubscriptionFooter, historyPageSize, appearance, className, }: AccountBillingProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { CheckoutAppearance } from '../appearance';
|
|
2
|
+
import { BillingError } from '../client/errors';
|
|
3
|
+
import { SubscriptionAction } from '../react/hooks';
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
export interface CancelSubscriptionDialogProps {
|
|
6
|
+
open: boolean;
|
|
7
|
+
onOpenChange: (open: boolean) => void;
|
|
8
|
+
/** Subscription display name. */
|
|
9
|
+
name: string;
|
|
10
|
+
/** On-chain (Solana) cancel: no feedback, the wallet signs. */
|
|
11
|
+
onChain?: boolean;
|
|
12
|
+
/** In-flight stage, when cancelling. */
|
|
13
|
+
pending?: SubscriptionAction;
|
|
14
|
+
/** Resolves null on success; the dialog then closes. */
|
|
15
|
+
onConfirm: (feedback: string) => Promise<BillingError | null>;
|
|
16
|
+
appearance?: CheckoutAppearance;
|
|
17
|
+
}
|
|
18
|
+
export declare function CancelSubscriptionDialog({ open, onOpenChange, name, onChain, pending, onConfirm, appearance, }: CancelSubscriptionDialogProps): React.JSX.Element;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { CheckoutAppearance } from '../appearance';
|
|
2
|
+
import { BillingError } from '../client/errors';
|
|
3
|
+
import { Subscription } from '../client/types';
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
export interface ChangeCardDialogProps {
|
|
6
|
+
subscription: Subscription | null;
|
|
7
|
+
name: string;
|
|
8
|
+
onOpenChange: (open: boolean) => void;
|
|
9
|
+
pending: boolean;
|
|
10
|
+
/** Resolves null on success; the dialog then closes. */
|
|
11
|
+
onConfirm: (paymentMethodId: string) => Promise<BillingError | null>;
|
|
12
|
+
appearance?: CheckoutAppearance;
|
|
13
|
+
}
|
|
14
|
+
export declare function ChangeCardDialog({ subscription, name, onOpenChange, pending, onConfirm, appearance, }: ChangeCardDialogProps): React.JSX.Element;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { CardSummary, CurrencyScales, Payment, Subscription, SubscriptionPrice } from '../client/types';
|
|
2
|
+
import { Translator } from '../i18n/messages';
|
|
3
|
+
export declare function formatDate(value: string | null | undefined, locale?: string): string | null;
|
|
4
|
+
/** Exact money, or null while the currency's scale is unknown. */
|
|
5
|
+
export declare function formatMoney(amount: string | null | undefined, currency: string, scales: CurrencyScales, locale?: string): string | null;
|
|
6
|
+
/** "every 30 days", "30 days of access" or "one-time". */
|
|
7
|
+
export declare function intervalLabel(price: SubscriptionPrice | null | undefined, m: Translator): string | null;
|
|
8
|
+
export declare function subscriptionName(s: Subscription, { t }: Translator): string;
|
|
9
|
+
/** What a payment bought: the product's name, else its kind, plus its cadence. */
|
|
10
|
+
export declare function paymentItem(p: Payment, m: Translator): {
|
|
11
|
+
name: string;
|
|
12
|
+
detail: string | null;
|
|
13
|
+
};
|
|
14
|
+
export declare function brandName(brand: string | null | undefined, fallback: string): string;
|
|
15
|
+
/** "Visa •••• 4242 · 12/30"; the brand alone when no digits are known. */
|
|
16
|
+
export declare function cardText(card: CardSummary | null | undefined, m: Translator): string;
|
|
17
|
+
export declare function expiry(card: CardSummary | null | undefined): string | null;
|
|
18
|
+
export declare const LIVE_STATUSES: Set<string>;
|
|
19
|
+
/** Still grants access: live, or cancelled with the paid period running. */
|
|
20
|
+
export declare const isLive: (s: Subscription) => boolean;
|
|
21
|
+
/** Access ends at period end and nothing renews it. */
|
|
22
|
+
export declare const isEnding: (s: Subscription) => boolean;
|
|
23
|
+
export type StatusTone = "success" | "warning" | "destructive" | "neutral";
|
|
24
|
+
export declare const statusTone: (status: string) => StatusTone;
|
|
25
|
+
export declare const RESET = "[&_h2]:m-0 [&_p]:m-0 [&_ul]:m-0 [&_ul]:list-none [&_ul]:p-0 [&_table]:border-spacing-0";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { CheckoutAppearance } from '../appearance';
|
|
2
|
+
import { PaymentsOptions } from '../react/hooks';
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
export interface PaymentHistoryProps extends PaymentsOptions {
|
|
5
|
+
appearance?: CheckoutAppearance;
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function PaymentHistory({ appearance, className, ...options }: PaymentHistoryProps): React.JSX.Element;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { CheckoutAppearance } from '../appearance';
|
|
2
|
+
import { PspConfig } from '../psp';
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
export interface PaymentMethodsPanelProps {
|
|
5
|
+
/**
|
|
6
|
+
* OpenRails's browser PSP configs (checkout config). "Add card" offers
|
|
7
|
+
* each one a card can be saved with in the page.
|
|
8
|
+
*/
|
|
9
|
+
psps?: readonly PspConfig[];
|
|
10
|
+
/** Return target after off-page card verification; see `SavePaymentMethod`. */
|
|
11
|
+
cardSetupReturnURL?: (setupId: string) => string;
|
|
12
|
+
/** Enables "Make default" for this currency's invoice collection. */
|
|
13
|
+
defaultCurrency?: string;
|
|
14
|
+
/** Billing country to preselect when adding a card. */
|
|
15
|
+
defaultCountry?: string;
|
|
16
|
+
appearance?: CheckoutAppearance;
|
|
17
|
+
className?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function PaymentMethodsPanel({ psps, cardSetupReturnURL, defaultCurrency, defaultCountry, appearance, className, }: PaymentMethodsPanelProps): React.JSX.Element;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { CheckoutAppearance } from '../appearance';
|
|
2
|
+
import { BillingError } from '../client/errors';
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
export interface SectionProps {
|
|
5
|
+
title: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
action?: React.ReactNode;
|
|
8
|
+
appearance?: CheckoutAppearance;
|
|
9
|
+
className?: string;
|
|
10
|
+
children?: React.ReactNode;
|
|
11
|
+
"data-testid"?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function Section({ title, description, action, appearance, className, children, ...rest }: SectionProps): React.JSX.Element;
|
|
14
|
+
export declare function ListSkeleton({ rows }: {
|
|
15
|
+
rows?: number;
|
|
16
|
+
}): React.JSX.Element;
|
|
17
|
+
export declare function EmptyState({ title, description, action, }: {
|
|
18
|
+
title: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
action?: React.ReactNode;
|
|
21
|
+
}): React.JSX.Element;
|
|
22
|
+
export declare function ErrorState({ error, onRetry, }: {
|
|
23
|
+
error: BillingError;
|
|
24
|
+
onRetry: () => void;
|
|
25
|
+
}): React.JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface BillingStatusBadgeProps {
|
|
2
|
+
/** Subscription, payment or card-health status. */
|
|
3
|
+
status: string;
|
|
4
|
+
/** Overrides the translated label. */
|
|
5
|
+
label?: string;
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function BillingStatusBadge({ status, label, className, }: BillingStatusBadgeProps): import("react").JSX.Element;
|