@openrails/billing-ui 0.230.0 → 0.234.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/CHANGELOG.md +117 -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 +81 -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 +764 -0
  13. package/dist/client/generated/wire.d.ts +772 -0
  14. package/dist/client/index.d.ts +3 -3
  15. package/dist/client/types.d.ts +498 -393
  16. package/dist/client-CWX6QpLa.js +920 -0
  17. package/dist/client-CWX6QpLa.js.map +1 -0
  18. package/dist/client.js +2 -3
  19. package/dist/components/methods.d.ts +3 -3
  20. package/dist/config-DZ97SQG2.js +341 -0
  21. package/dist/config-DZ97SQG2.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 { Account, 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,62 @@ 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>>;
133
+ /**
134
+ * The customer's summary: balance and amount owed per currency, the card
135
+ * that pays each currency, and unread notices.
136
+ */
137
+ getAccount(signal?: AbortSignal): Promise<Account>;
120
138
  getInvoice(invoiceId: string, signal?: AbortSignal): Promise<Invoice>;
121
- getStatus(signal?: AbortSignal): Promise<BillingStatus>;
122
- /** Active products with their active prices. */
139
+ /** Products on sale, each with its current prices. */
123
140
  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
141
  /**
133
142
  * Mints a hosted checkout session for the signed-in customer and one
134
143
  * price. Render it with `<CheckoutFrame url>` when the session has a
135
144
  * `url`, else with `<Checkout source={client.checkoutSource(id)}>`.
145
+ * Select a price by `priceId`, or by both `productKey` and `priceKey`.
136
146
  * `successUrl` brings the buyer back from a redirect rail; it must be on
137
147
  * one of this app's return origins.
138
148
  */
139
149
  createCheckoutSession(input: {
140
150
  priceKey?: string;
151
+ productKey?: string;
141
152
  priceId?: string;
153
+ /** Customer-selected deposit in the price currency’s native units. */
154
+ amount?: string;
155
+ /** Defaults to true for recurring prices; false buys the initial term only. */
156
+ autoRenew?: boolean;
142
157
  successUrl?: string;
143
- }): Promise<HostedCheckoutLink>;
158
+ }): Promise<CheckoutSessionLink>;
159
+ /**
160
+ * Reads and pays one hosted checkout session. By default the id is the
161
+ * only credential: no bearer is sent. With `customerBase` the session's
162
+ * customer reads and pays it on that customer surface, signed in. A
163
+ * refusal the buyer can answer (an invalid card form, too many attempts)
164
+ * resolves as `failed`; an expired or unknown session as `expired`.
165
+ */
166
+ checkoutSource(sessionId: string, opts?: CheckoutSourceOptions): CheckoutSource;
144
167
  /**
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`.
168
+ * The deployment's public configuration: what the mount serves, the
169
+ * currency registry and the merchant's payment setup. React components
170
+ * share one copy through `useConfig()`.
149
171
  */
150
- checkoutSource(sessionId: string): CheckoutSource;
151
- /** Network and accepted tokens; served only with a Solana PSP. */
152
- getSolanaConfig(signal?: AbortSignal): Promise<SolanaConfig>;
172
+ getConfig(signal?: AbortSignal): Promise<PublicConfig>;
153
173
  /**
154
- * Accepted tokens with live prices. `priceId` or `checkoutSessionId` adds
155
- * each token's `quote`; `wallet` adds its `balance`.
174
+ * Accepted tokens with live prices. `priceId` adds each token's `quote`;
175
+ * `wallet` adds its `balance`.
156
176
  */
157
177
  listSolanaTokens(opts?: {
158
178
  priceId?: string;
159
- checkoutSessionId?: string;
160
179
  wallet?: string;
161
180
  signal?: AbortSignal;
162
181
  }): 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" | "already_owned" | "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_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_in_use" | "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_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" | "order_has_recurring_line" | "order_line_unavailable" | "order_not_cancelable" | "order_not_payable" | "order_payment_in_progress" | "order_total_changed" | "payment_duplicate_refused" | "payment_exceeds_due" | "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_option_unavailable" | "payment_provider_rejected" | "permission_required" | "price_change_currency_mismatch" | "price_change_target_archived" | "price_increase_notice_too_short" | "price_key_cadence_conflict" | "price_key_not_found" | "price_migration_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_cancel_held" | "provider_operation_conflict" | "provider_operation_has_billing_evidence" | "provider_operation_not_found" | "provider_operation_not_open" | "provider_operation_not_refused" | "provider_operation_refused" | "provider_outcome_unknown" | "psp_claim_requires_proof" | "psp_credentials_rejected" | "psp_exists" | "psp_key_taken" | "psp_last_active" | "psp_not_found" | "purchase_review_resolved" | "quantity_not_allowed" | "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" | "request_body_too_large" | "resource_access_denied" | "resource_conflict" | "resource_not_found" | "role_escalation" | "route_not_found" | "scheduled_change_exists" | "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
+ }>>;