@openrails/billing-ui 0.230.0 → 0.233.2

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 (65) hide show
  1. package/CHANGELOG.md +103 -9
  2. package/README.md +88 -39
  3. package/dist/account/account-billing.d.ts +3 -3
  4. package/dist/account/cancel-dialog.d.ts +2 -2
  5. package/dist/account/format.d.ts +4 -4
  6. package/dist/account/payment-methods-panel.d.ts +7 -9
  7. package/dist/account/section.d.ts +3 -1
  8. package/dist/checkout-page.d.ts +6 -1
  9. package/dist/client/client.d.ts +76 -62
  10. package/dist/client/generated/currencies.d.ts +1 -0
  11. package/dist/client/generated/error-codes.d.ts +7 -0
  12. package/dist/client/generated/routes.d.ts +775 -0
  13. package/dist/client/generated/wire.d.ts +682 -0
  14. package/dist/client/index.d.ts +3 -3
  15. package/dist/client/types.d.ts +425 -379
  16. package/dist/client-DXUPzA8C.js +889 -0
  17. package/dist/client-DXUPzA8C.js.map +1 -0
  18. package/dist/client.js +2 -3
  19. package/dist/components/methods.d.ts +3 -3
  20. package/dist/config-BQELtBh4.js +341 -0
  21. package/dist/config-BQELtBh4.js.map +1 -0
  22. package/dist/frame.d.ts +1 -1
  23. package/dist/index.d.ts +4 -4
  24. package/dist/index.js +1447 -1539
  25. package/dist/index.js.map +1 -1
  26. package/dist/lib/billing.d.ts +14 -0
  27. package/dist/lib/money.d.ts +1 -0
  28. package/dist/lib/period.d.ts +0 -2
  29. package/dist/lib/rail-meta.d.ts +4 -4
  30. package/dist/locales/de.js +11 -8
  31. package/dist/locales/de.js.map +1 -1
  32. package/dist/locales/en.d.ts +8 -5
  33. package/dist/locales/en.js +11 -8
  34. package/dist/locales/en.js.map +1 -1
  35. package/dist/locales/es.js +11 -8
  36. package/dist/locales/es.js.map +1 -1
  37. package/dist/locales/ja.js +11 -8
  38. package/dist/locales/ja.js.map +1 -1
  39. package/dist/locales/ko.js +11 -8
  40. package/dist/locales/ko.js.map +1 -1
  41. package/dist/locales/zh.js +11 -8
  42. package/dist/locales/zh.js.map +1 -1
  43. package/dist/psp.d.ts +10 -21
  44. package/dist/react/config.d.ts +34 -0
  45. package/dist/react/context.d.ts +5 -8
  46. package/dist/react/hooks.d.ts +20 -14
  47. package/dist/react/index.d.ts +1 -0
  48. package/dist/react/provider.d.ts +1 -9
  49. package/dist/react/remote.d.ts +0 -1
  50. package/dist/react.js +24 -28
  51. package/dist/react.js.map +1 -1
  52. package/dist/save-payment-method.d.ts +1 -1
  53. package/dist/source.d.ts +0 -9
  54. package/dist/styles.css +1 -1
  55. package/dist/types.d.ts +114 -55
  56. package/docs/payment-form-contract.md +23 -40
  57. package/package.json +3 -3
  58. package/dist/client/generated/openrails-routes.d.ts +0 -2
  59. package/dist/client-DhG2jv34.js +0 -771
  60. package/dist/client-DhG2jv34.js.map +0 -1
  61. package/dist/errors-T-PRm3vV.js +0 -54
  62. package/dist/errors-T-PRm3vV.js.map +0 -1
  63. package/dist/hooks-DLFF-zx5.js +0 -285
  64. package/dist/hooks-DLFF-zx5.js.map +0 -1
  65. package/docs/1055-nmi-host-integration.md +0 -28
@@ -1,5 +1,5 @@
1
1
  import { CheckoutSource } from '../source';
2
- import { BillingStatus, CardSetup, Currency, HostedCheckoutLink, PaymentAuthentication, CurrencyScales, Invoice, NewCard, Page, Payment, PaymentMethod, Price, Product, SolanaConfig, SolanaTierChange, SolanaTierChangeTx, SolanaToken, Subscription, TierChange, TierChangePreview } from './types';
2
+ import { CardSetup, CheckoutSessionLink, PublicConfig, PaymentAuthentication, CurrencyScales, Invoice, ListPage, NewCard, NextAction, Page, Payment, PaymentMethod, Product, SolanaToken, Subscription, TierChange, TierChangePreview } from './types';
3
3
  export interface BillingClientOptions {
4
4
  /** OpenRails embedded mount. Default "/billing/v1". */
5
5
  baseUrl?: string;
@@ -18,12 +18,29 @@ export interface BillingClientOptions {
18
18
  */
19
19
  currencies?: CurrencyScales;
20
20
  }
21
+ export interface CheckoutSourceOptions {
22
+ /**
23
+ * A customer surface's base: its `/me` prefix, such as `/billing/v1/me` or
24
+ * a host's own `/api/v1/merchants/acme/billing/me`. The session is read and
25
+ * paid there with this client's credential, which proves the session's
26
+ * customer, so its saved cards pay. Default: the session id alone, at
27
+ * `{baseUrl}/checkout-sessions`.
28
+ */
29
+ customerBase?: string;
30
+ }
21
31
  export interface ListOptions {
22
32
  limit?: number;
23
33
  offset?: number;
34
+ /** A cursor list's next page: the previous page's `next_cursor`. */
35
+ cursor?: string;
36
+ signal?: AbortSignal;
37
+ }
38
+ /** A cursor list read: pass the previous page's `next_cursor` for the next. */
39
+ export interface CursorOptions {
40
+ limit?: number;
41
+ cursor?: string | null;
24
42
  signal?: AbortSignal;
25
43
  }
26
- export type SolanaCancelStage = "preparing" | "signing" | "confirming";
27
44
  /**
28
45
  * Signs and submits a base64 transaction with the customer's wallet and
29
46
  * returns its signature. Throw `WalletRejectedError` when the user declines.
@@ -32,27 +49,39 @@ export type SendSolanaTransaction = (transactionBase64: string) => Promise<strin
32
49
  export declare class WalletRejectedError extends Error {
33
50
  constructor(message?: string);
34
51
  }
35
- export declare const CANCEL_FEEDBACK_MIN = 4;
36
- export declare const CANCEL_FEEDBACK_MAX = 500;
52
+ export declare const CANCEL_REASON_MIN = 4;
53
+ export declare const CANCEL_REASON_MAX = 500;
54
+ /** A next action the customer's wallet completes. */
55
+ export declare const isWalletAction: (next: NextAction | null | undefined) => boolean;
56
+ /**
57
+ * Signs and sends a `solana_sign_transactions` next action's transactions in
58
+ * order and returns the last signature, the value the action is repeated
59
+ * with. A declined prompt is a local `wallet_rejected` error.
60
+ */
61
+ export declare function signWalletAction(next: NextAction, sendTransaction: SendSolanaTransaction): Promise<string>;
37
62
  /** Total wait a GET may spend on its one retry. */
38
63
  export declare const RETRY_BUDGET_MS = 2000;
39
64
  export declare function createBillingClient(options?: BillingClientOptions): {
40
65
  baseUrl: string;
41
- listSubscriptions(opts?: ListOptions & {
66
+ /** One page of the customer's subscriptions, newest first. */
67
+ listSubscriptions(opts?: CursorOptions & {
42
68
  status?: string;
43
- }): Promise<Page<Subscription>>;
69
+ }): Promise<ListPage<Subscription>>;
44
70
  /** Includes `recovery` (list rows do not). */
45
71
  getSubscription(subscriptionId: string, signal?: AbortSignal): Promise<Subscription>;
46
72
  /**
47
- * Queues the cancellation (202). Access and resumability follow the
48
- * rail's cancel mode; re-read the subscription to observe the result.
73
+ * Cancels at period end and answers the subscription. When the rail needs
74
+ * the customer's step (`next_action`, a Solana wallet signature), the
75
+ * subscription is unchanged: complete it with `signWalletAction` and
76
+ * repeat with `signature`.
49
77
  */
50
78
  cancelSubscription(subscriptionId: string, input: {
51
- feedback: string;
52
- }): Promise<void>;
53
- /** Queues the resumption (202). */
54
- resumeSubscription(subscriptionId: string): Promise<void>;
55
- setSubscriptionPaymentMethod(subscriptionId: string, paymentMethodId: string): Promise<void>;
79
+ reason: string;
80
+ signature?: string;
81
+ }): Promise<Subscription>;
82
+ /** Undoes a scheduled cancel before the period ends. */
83
+ resumeSubscription(subscriptionId: string): Promise<Subscription>;
84
+ setSubscriptionPaymentMethod(subscriptionId: string, paymentMethodId: string): Promise<Subscription>;
56
85
  /** What `changeTier` would charge now and at the next renewal. */
57
86
  previewTierChange(subscriptionId: string, priceId: string, signal?: AbortSignal): Promise<TierChangePreview>;
58
87
  /**
@@ -60,35 +89,19 @@ export declare function createBillingClient(options?: BillingClientOptions): {
60
89
  * charges the saved card now, a downgrade applies at period end.
61
90
  * `idempotencyKey` identifies this attempt; reuse it until the change
62
91
  * resolves (`processing`, a `tier_change_in_flight` refusal or a lost
63
- * response) so the stored result replays instead of charging twice.
92
+ * response) so the stored result replays instead of charging twice. A
93
+ * wallet next action (Solana) is completed with `signWalletAction` and
94
+ * the change repeated with `signature`.
64
95
  */
65
96
  changeTier(subscriptionId: string, input: {
66
97
  priceId: string;
67
98
  idempotencyKey: string;
99
+ signature?: string;
68
100
  }): Promise<TierChange>;
101
+ listPaymentMethods(opts?: CursorOptions): Promise<ListPage<PaymentMethod>>;
69
102
  /**
70
- * Solana rail: the tier-change transaction for the wallet to sign and
71
- * send. Pass the resulting signature to `confirmSolanaTierChange`.
72
- */
73
- prepareSolanaTierChange(subscriptionId: string, newPriceId: string): Promise<SolanaTierChangeTx>;
74
- /**
75
- * Records the landed transaction. Keep the signature until this succeeds:
76
- * confirming it again replays the result (`already_confirmed`).
77
- */
78
- confirmSolanaTierChange(subscriptionId: string, input: {
79
- signature: string;
80
- newPriceId: string;
81
- }): Promise<SolanaTierChange>;
82
- /**
83
- * On-chain cancellation for the solana rail: the server prepares an
84
- * unsigned transaction, the wallet signs and submits it, the server
85
- * verifies the signature and records the cancel.
86
- */
87
- cancelSubscriptionOnChain(subscriptionId: string, sendTransaction: SendSolanaTransaction, onStage?: (stage: SolanaCancelStage) => void): Promise<void>;
88
- listPaymentMethods(opts?: ListOptions): Promise<Page<PaymentMethod>>;
89
- /**
90
- * Stores a card entered in the page: a Collect.js token
91
- * (`cardSetupDriver` "collect_js") or the card itself ("card").
103
+ * Stores a card entered in the page with the PSP `psp_id`: a Collect.js
104
+ * token (`cardSetupDriver` "collect_js") or the card itself ("card").
92
105
  */
93
106
  addPaymentMethod(card: NewCard): Promise<PaymentMethod>;
94
107
  /**
@@ -107,56 +120,57 @@ export declare function createBillingClient(options?: BillingClientOptions): {
107
120
  confirmPaymentAuthentication(operationId: string): Promise<void>;
108
121
  /** `pending` when the provider is still converging (202). */
109
122
  removePaymentMethod(paymentMethodId: string): Promise<"removed" | "pending">;
110
- /** Makes the method the default collector for one currency's invoices. */
111
- setDefaultPaymentMethod(input: {
123
+ /** Makes the card the one that collects one currency's invoices. */
124
+ setCollectionPaymentMethod(input: {
112
125
  currency: string;
113
126
  paymentMethodId: string;
114
127
  }): Promise<void>;
115
128
  /** Charges and refunds, newest first. `rail` filters by rail. */
116
- listPayments(opts?: ListOptions & {
129
+ listPayments(opts?: CursorOptions & {
117
130
  rail?: string;
118
- }): Promise<Page<Payment>>;
119
- listInvoices(opts?: ListOptions): Promise<Page<Invoice>>;
131
+ }): Promise<ListPage<Payment>>;
132
+ listInvoices(opts?: CursorOptions): Promise<ListPage<Invoice>>;
120
133
  getInvoice(invoiceId: string, signal?: AbortSignal): Promise<Invoice>;
121
- getStatus(signal?: AbortSignal): Promise<BillingStatus>;
122
- /** Active products with their active prices. */
134
+ /** Products on sale, each with its current prices. */
123
135
  listProducts(opts?: ListOptions): Promise<Page<Product>>;
124
- /** Active prices. `product` is a `prod_` id; `type` is `recurring | one_time`. */
125
- listPrices(opts?: ListOptions & {
126
- currency?: string;
127
- product?: string;
128
- type?: string;
129
- }): Promise<Page<Price>>;
130
- /** The server's currency registry; `currencies` is the pinned copy. */
131
- listCurrencies(signal?: AbortSignal): Promise<Currency[]>;
132
136
  /**
133
137
  * Mints a hosted checkout session for the signed-in customer and one
134
138
  * price. Render it with `<CheckoutFrame url>` when the session has a
135
139
  * `url`, else with `<Checkout source={client.checkoutSource(id)}>`.
140
+ * Select a price by `priceId`, or by both `productKey` and `priceKey`.
136
141
  * `successUrl` brings the buyer back from a redirect rail; it must be on
137
142
  * one of this app's return origins.
138
143
  */
139
144
  createCheckoutSession(input: {
140
145
  priceKey?: string;
146
+ productKey?: string;
141
147
  priceId?: string;
148
+ /** Customer-selected deposit in the price currency’s native units. */
149
+ amount?: string;
150
+ /** Defaults to true for recurring prices; false buys the initial term only. */
151
+ autoRenew?: boolean;
142
152
  successUrl?: string;
143
- }): Promise<HostedCheckoutLink>;
153
+ }): Promise<CheckoutSessionLink>;
154
+ /**
155
+ * Reads and pays one hosted checkout session. By default the id is the
156
+ * only credential: no bearer is sent. With `customerBase` the session's
157
+ * customer reads and pays it on that customer surface, signed in. A
158
+ * refusal the buyer can answer (an invalid card form, too many attempts)
159
+ * resolves as `failed`; an expired or unknown session as `expired`.
160
+ */
161
+ checkoutSource(sessionId: string, opts?: CheckoutSourceOptions): CheckoutSource;
144
162
  /**
145
- * Reads and pays one hosted checkout session. The id is the only
146
- * credential: no bearer is sent. A refusal the buyer can answer (an
147
- * invalid card form, too many attempts) resolves as `failed`; an expired
148
- * or unknown session as `expired`.
163
+ * The deployment's public configuration: what the mount serves, the
164
+ * currency registry and the merchant's payment setup. React components
165
+ * share one copy through `useConfig()`.
149
166
  */
150
- checkoutSource(sessionId: string): CheckoutSource;
151
- /** Network and accepted tokens; served only with a Solana PSP. */
152
- getSolanaConfig(signal?: AbortSignal): Promise<SolanaConfig>;
167
+ getConfig(signal?: AbortSignal): Promise<PublicConfig>;
153
168
  /**
154
- * Accepted tokens with live prices. `priceId` or `checkoutSessionId` adds
155
- * each token's `quote`; `wallet` adds its `balance`.
169
+ * Accepted tokens with live prices. `priceId` adds each token's `quote`;
170
+ * `wallet` adds its `balance`.
156
171
  */
157
172
  listSolanaTokens(opts?: {
158
173
  priceId?: string;
159
- checkoutSessionId?: string;
160
174
  wallet?: string;
161
175
  signal?: AbortSignal;
162
176
  }): Promise<SolanaToken[]>;
@@ -0,0 +1 @@
1
+ export declare const OPENRAILS_CURRENCY_SCALES: Readonly<Record<string, number>>;
@@ -0,0 +1,7 @@
1
+ export type OpenRailsErrorCode = "access_token_invalid" | "access_token_issuer_unknown" | "access_token_merchant_not_bound" | "admission_captured" | "admission_not_found" | "allowance_meter_not_found" | "allowance_source_in_use" | "allowance_source_invalid" | "api_host_claim_missing" | "api_host_reserved" | "api_host_taken" | "api_host_unproven" | "as_of_required" | "authentication_required" | "authentication_unavailable" | "authorization_unavailable" | "billing_archive_integrity" | "billing_archive_invalid_artifact" | "billing_archive_merchant_mismatch" | "billing_archive_not_empty" | "billing_archive_unavailable" | "billing_archive_unsupported_state" | "billing_policy_not_found" | "cancel_unsupported_on_rail" | "captcha_invalid" | "captcha_required" | "card_attempts_blocked" | "card_declined" | "card_not_saved" | "card_requires_https" | "catalog_benefit_overlap" | "catalog_revision_conflict" | "catalog_updates_disabled" | "checkout_attempt_closed" | "checkout_attempt_expired" | "checkout_offer_unavailable" | "checkout_payment_in_progress" | "checkout_request_invalid" | "checkout_session_expired" | "checkout_session_not_found" | "checkout_session_unavailable" | "collection_payment_method_invalid" | "collection_payment_method_required" | "creation_refused" | "credential_custody_transition_required" | "credential_expired" | "credential_identity_mismatch" | "credential_operation_conflict" | "credential_revoked" | "credential_source_read_only" | "credential_store_read_only" | "credentials_manage_required" | "credit_grant_held" | "credit_grant_not_found" | "credit_grant_unavailable" | "csrf_origin_denied" | "currency_unsupported" | "custodian_capture_unavailable" | "customer_action_required" | "customer_blocked" | "customer_email_required" | "customer_not_found" | "customer_payment_unsupported" | "customer_proof_required" | "customer_session_required" | "dashboard_invalid" | "database_busy" | "default_rate_card_not_found" | "default_rate_card_required" | "delegated_principal_invalid" | "email_unverified" | "finding_action_failed" | "finding_not_actionable" | "hold_not_found" | "host_event_not_found" | "host_merchant_mismatch" | "host_principal_invalid" | "idempotency_key_required" | "idempotency_key_reused" | "insufficient_credits" | "insufficient_funds" | "insufficient_scope" | "internal_error" | "invalid_api_host" | "invalid_cursor" | "invalid_customer_id" | "invalid_email" | "invalid_host_event_request" | "invalid_name" | "invalid_param" | "invalid_payment_method" | "invalid_psp_reference" | "invalid_query" | "invalid_request_body" | "invalid_settlement_status_request" | "invalid_user" | "invites_disabled" | "invoice_action_not_allowed" | "invoice_not_retryable" | "invoice_payment_exceeds_due" | "invoice_payment_invalid" | "invoice_payment_reference_used" | "invoice_retry_idempotency_conflict" | "invoice_retry_in_progress" | "invoice_retry_outcome_unknown" | "invoker_scoped_principal" | "last_owner" | "members_manage_required" | "merchant_binding_mismatch" | "merchant_configuration_application_conflict" | "merchant_configuration_revision_conflict" | "merchant_context_mismatch" | "merchant_creation_payment_method_required" | "merchant_directory_unavailable" | "merchant_not_found" | "merchant_selector_invalid" | "merchant_unresolved" | "meter_in_use" | "meter_rate_card_conflict" | "method_not_allowed" | "metrics_query_invalid" | "model_unavailable" | "name_reserved" | "name_taken" | "operation_authorization_conflict" | "operation_authorization_has_billing_evidence" | "operation_authorization_not_found" | "operation_authorization_not_open" | "payment_duplicate_refused" | "payment_failed" | "payment_idempotency_conflict" | "payment_in_progress" | "payment_method_delete_failed" | "payment_method_delete_unsupported" | "payment_method_not_psp_vaulted" | "payment_method_not_usable" | "payment_method_psp_mismatch" | "payment_method_required" | "payment_method_same_vault" | "payment_method_stale" | "payment_method_update_failed" | "payment_method_update_retry_required" | "payment_method_update_unsupported" | "payment_not_found" | "payment_not_refundable" | "payment_not_retryable" | "payment_provider_rejected" | "permission_required" | "price_key_cadence_conflict" | "price_key_not_found" | "price_not_found" | "price_not_sellable" | "product_not_found" | "product_tier_group_conflict" | "product_tier_group_in_use" | "provider_billing_observation_conflict" | "provider_billing_qualification_not_found" | "provider_billing_qualification_not_refused" | "provider_billing_qualification_refused" | "provider_billing_refusal_conflict" | "provider_billing_resolution_conflict" | "provider_cancel_held" | "provider_outcome_unknown" | "psp_claim_requires_proof" | "psp_credentials_rejected" | "psp_exists" | "psp_key_taken" | "psp_last_active" | "psp_not_found" | "purchase_review_resolved" | "rate_card_currency_mismatch" | "rate_card_has_overrides" | "rate_card_product_not_found" | "rate_limit_exceeded" | "rebill_terms_committed" | "refund_failed" | "refund_rail_unavailable" | "refund_unsupported" | "rename_too_soon" | "renames_disabled" | "reprice_already_scheduled" | "reprice_cross_currency" | "reprice_cross_product" | "reprice_inactive_price" | "reprice_not_found" | "reprice_not_scheduled" | "reprice_notice_window_violation" | "reprice_price_key_not_found" | "reprice_target_price_not_found" | "request_body_too_large" | "resource_access_denied" | "resource_conflict" | "resource_not_found" | "role_escalation" | "route_not_found" | "sender_proof_required" | "service_credential_customer_scope_denied" | "service_credential_invalid" | "service_credential_merchant_unresolved" | "service_credential_resource_scope_denied" | "service_unavailable" | "solana_rpc_unavailable" | "solana_transaction_refused" | "spend_delegation_not_found" | "step_up_required" | "step_up_unavailable" | "subscription_not_active" | "subscription_not_found" | "subscription_paid_through" | "subscription_resumable" | "tier_change_already_scheduled" | "tier_change_cadence_unsupported" | "tier_change_credit_exceeds_price" | "tier_change_cycle_unknown" | "tier_change_idempotency_conflict" | "tier_change_idempotency_key_required" | "tier_change_in_flight" | "tier_change_period_unknown" | "tier_change_provider_conflict" | "tier_change_refused" | "tier_change_renewal_due" | "tier_change_requires_linked_plan" | "tier_change_target_inactive" | "tier_change_unsupported_on_rail" | "trial_unsupported_on_rail" | "unknown_field" | "unknown_role" | "unsupported_media_type" | "usage_meter_invalid" | "usage_meter_not_found" | "usage_rate_card_invalid" | "use_dpop_nonce" | "webhook_account_mismatch" | "webhook_invalid" | "widget_generation_invalid";
2
+ export type OpenRailsErrorType = "api_error" | "authentication_error" | "authorization_error" | "card_error" | "invalid_request_error" | "rate_limit_error";
3
+ export declare const OPENRAILS_ERROR_CODES: Readonly<Record<OpenRailsErrorCode, {
4
+ status: number;
5
+ type: OpenRailsErrorType;
6
+ meaning: string;
7
+ }>>;