@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 +0,0 @@
1
- {"version":3,"file":"client-DhG2jv34.js","names":[],"sources":["../src/lib/money.ts","../src/types.ts","../src/client/generated/openrails-routes.ts","../src/client/types.ts","../src/client/client.ts"],"sourcesContent":["// Exact money. Every amount the host serves is a signed int64 decimal string\n// of the plan currency's native unit; plan.unit_decimals is that currency's\n// registered scale (OpenRails' currency registry, GET /v1/currencies). Nothing\n// here converts an amount to a JS number: values are scaled with BigInt and\n// only the exact major-unit decimal is handed to Intl.\n\n// Amount is an int64 decimal string, e.g. \"99000000\" (99 USD at 6 decimals).\nexport type Amount = string\n\nconst INT64_MIN = -(1n << 63n)\nconst INT64_MAX = (1n << 63n) - 1n\nexport const MAX_UNIT_DECIMALS = 18\n\n// amountUnits parses an exact int64 decimal string, or null.\nexport function amountUnits(amount: unknown): bigint | null {\n if (typeof amount !== \"string\" || !/^-?\\d{1,19}$/.test(amount)) return null\n const value = BigInt(amount)\n return value < INT64_MIN || value > INT64_MAX ? null : value\n}\n\nexport function isAmount(value: unknown): value is Amount {\n return amountUnits(value) !== null\n}\n\nexport function isUnitDecimals(value: unknown): value is number {\n return (\n typeof value === \"number\" &&\n Number.isInteger(value) &&\n value >= 0 &&\n value <= MAX_UNIT_DECIMALS\n )\n}\n\n// addAmounts sums exact amounts; null when an input or the sum leaves int64.\nexport function addAmounts(...amounts: Amount[]): Amount | null {\n let total = 0n\n for (const amount of amounts) {\n const units = amountUnits(amount)\n if (units === null) return null\n total += units\n }\n return total < INT64_MIN || total > INT64_MAX ? null : total.toString()\n}\n\n// Intl.NumberFormat formats a decimal string exactly only since ECMA-402 2023\n// (Chrome/Edge 106, Firefox 116, Safari 15.4); older engines coerce it through\n// Number. Probed once with 2^53 + 1, which a Number cannot hold.\nexport const intlFormatsDecimalStringsExactly: boolean = (() => {\n try {\n return (\n new Intl.NumberFormat(\"en\", { useGrouping: false }).format(\n \"9007199254740993\" as `${number}`\n ) === \"9007199254740993\"\n )\n } catch {\n return false\n }\n})()\n\n// Below 10^15 native units a Number-coerced decimal still rounds back to the\n// exact digits at every registry scale; from 10^15 the coerced value can differ\n// in the last digit, so a legacy engine refuses instead of misformatting.\nconst LEGACY_EXACT_UNITS = 10n ** 15n\n\nfunction decimalFromUnits(value: bigint, decimals: number): string {\n const absolute = value < 0n ? -value : value\n const scale = 10n ** BigInt(decimals)\n const fraction = (absolute % scale)\n .toString()\n .padStart(decimals, \"0\")\n .replace(/0+$/, \"\")\n return `${value < 0n ? \"-\" : \"\"}${absolute / scale}${fraction ? `.${fraction}` : \"\"}`\n}\n\n// amountToDecimal renders native units as the exact major-unit decimal with\n// trailing zeros trimmed (\"99000000\" at 6 -> \"99\", \"1234567\" -> \"1.234567\"),\n// or null when the amount or scale is invalid.\nexport function amountToDecimal(\n amount: Amount,\n decimals: number\n): string | null {\n const units = amountUnits(amount)\n if (units === null || !isUnitDecimals(decimals)) return null\n return decimalFromUnits(units, decimals)\n}\n\n// formatAmount renders an exact amount in its currency for the buyer. It never\n// passes money through a JS number; an amount it cannot show exactly is\n// refused with a visible notice rather than a rounded figure.\nexport function formatAmount(\n amount: Amount | null | undefined,\n currency: string,\n decimals: number,\n locale?: string\n): string {\n const code = currency.trim().toUpperCase()\n const units = amountUnits(amount)\n if (units === null || !isUnitDecimals(decimals))\n return `${code} amount exceeds the exact display range`\n if (\n !intlFormatsDecimalStringsExactly &&\n (units >= LEGACY_EXACT_UNITS || units <= -LEGACY_EXACT_UNITS)\n )\n return `${code} amount exceeds this browser's exact display range`\n const decimal = decimalFromUnits(units, decimals) as `${number}`\n try {\n return new Intl.NumberFormat(locale, {\n style: \"currency\",\n currency: code,\n maximumFractionDigits: decimals,\n }).format(decimal)\n } catch {\n return `${decimal} ${code}`\n }\n}\n","// Wire types for the hosted checkout session surface, validated at runtime\n// with zod so a drifting API fails loudly at the boundary instead of rendering\n// garbage. OpenRails serves the session (GET /v1/checkout-sessions/{id}) and\n// publishes the same document as Go types (billing.HostedCheckoutSession) and\n// a canonical fixture\n// (testdata/wire/hosted_checkout_session.json) that src/types.test.ts decodes.\nimport { z } from \"zod\"\n\nimport { isAmount, isUnitDecimals, MAX_UNIT_DECIMALS } from \"./lib/money\"\n\n// Money is an exact signed int64 decimal string of the plan currency's native\n// unit (\"99000000\" is 99 USD at unit_decimals 6). A JSON number is refused:\n// it cannot carry every int64 and a scale must never be assumed.\nexport const amountSchema = z\n .string()\n .refine(isAmount, \"amount must be an int64 decimal string\")\n\n// The currency's registered scale from OpenRails' currency registry\n// (openrails.LookupCurrency / GET /v1/currencies), stamped by the host.\nexport const unitDecimalsSchema = z\n .number()\n .refine(\n isUnitDecimals,\n `unit_decimals must be an integer from 0 to ${MAX_UNIT_DECIMALS}`\n )\n\nconst httpsURLSchema = z\n .string()\n .url()\n .refine((value) => {\n try {\n const parsed = new URL(value)\n return (\n parsed.protocol === \"https:\" && !parsed.username && !parsed.password\n )\n } catch {\n return false\n }\n }, \"redirect URL must be HTTPS\")\n\nconst returnURLSchema = z\n .string()\n .url()\n .refine((value) => {\n try {\n const parsed = new URL(value)\n return (\n (parsed.protocol === \"https:\" || parsed.protocol === \"http:\") &&\n !parsed.username &&\n !parsed.password\n )\n } catch {\n return false\n }\n }, \"return URL must be HTTP(S)\")\n\nexport const checkoutSessionStatusSchema = z.enum([\n \"created\",\n \"requires_action\",\n \"processing\",\n \"succeeded\",\n \"failed\",\n \"blocked\",\n \"expired\",\n \"canceled\",\n])\nexport type CheckoutSessionStatus = z.infer<typeof checkoutSessionStatusSchema>\n\n// A definite decline, normalized by OpenRails. `field` places the message\n// next to the card field it concerns (\"\" = the card as a whole).\nexport const paymentFailureSchema = z.object({\n reason: z.string(),\n message: z.string(),\n field: z.string().nullish(),\n})\nexport type PaymentFailure = z.infer<typeof paymentFailureSchema>\n\n// The accepted payment operation; `requires_action` sessions authenticate it.\nexport const checkoutOperationSchema = z.object({\n id: z.string(),\n status: z.string(),\n})\n\nexport const paymentRailOptionSchema = z.object({\n id: z.string().min(1),\n rail: z.string(),\n mode: z.enum([\"one_off\", \"subscription\"]),\n // card: the PSP takes cards on OpenRails itself (card_entry: server); the\n // page posts the card and loads no gateway script.\n driver: z.enum([\n \"collect_js\",\n \"card\",\n \"stripe_elements\",\n \"redirect\",\n \"solana_pay\",\n ]),\n /** The PSP's checkout key; saving a new card names it. */\n psp_key: z.string().optional(),\n // Browser-safe rail config the host serves (nmi: Collect.js\n // tokenization_key + tokenization_url; stripe: publishable_key; driver\n // card: none).\n public_config: z.record(z.string(), z.string()).optional(),\n})\nexport type PaymentRailOption = z.infer<typeof paymentRailOptionSchema>\n\n// A card the session's customer has already stored with this merchant. Display\n// data only — paying with one sends its id, which the host resolves.\nexport const savedPaymentMethodSchema = z.object({\n id: z.string(),\n option_id: z.string(),\n rail: z.string(),\n brand: z.string().optional(),\n last_four: z.string().optional(),\n exp_month: z.number().optional(),\n exp_year: z.number().optional(),\n // Pre-selected in the picker; paying still sends this id explicitly.\n default: z.boolean().optional(),\n})\nexport type SavedPaymentMethod = z.infer<typeof savedPaymentMethodSchema>\n\n// Amounts are in the plan's currency at the plan's unit_decimals.\nexport const checkoutLineItemSchema = z.object({\n label: z.string(),\n sublabel: z.string().optional(),\n amount: amountSchema,\n})\nexport type CheckoutLineItem = z.infer<typeof checkoutLineItemSchema>\n\nexport const checkoutPlanSchema = z.object({\n display_name: z.string(),\n unit_amount: amountSchema,\n currency: z.string().min(1),\n unit_decimals: unitDecimalsSchema,\n period_hours: z.number().nullish(),\n automatically_renews: z.boolean(),\n})\nexport type CheckoutPlan = z.infer<typeof checkoutPlanSchema>\n\nexport const checkoutSessionSchema = z.object({\n id: z.string(),\n status: checkoutSessionStatusSchema,\n merchant: z.object({ display_name: z.string() }),\n plan: checkoutPlanSchema,\n line_items: z.array(checkoutLineItemSchema).optional(),\n tax: amountSchema.optional(),\n due_today: amountSchema.optional(),\n rails: z.array(paymentRailOptionSchema),\n saved_methods: z.array(savedPaymentMethodSchema).optional(),\n transaction_url: z.string().startsWith(\"solana:\").optional(),\n payment_id: z.string().optional(),\n subscription_id: z.string().optional(),\n failure_message: z.string().optional(),\n failure: paymentFailureSchema.nullish(),\n operation: checkoutOperationSchema.nullish(),\n // Present on hosted-page reads so the page host can redirect on success.\n success_url: returnURLSchema.optional(),\n // The origin of the app that framed the payment page: the only origin the\n // page exchanges frame messages with.\n embed_origin: z.string().url().optional(),\n expires_at: z.string().nullish(),\n})\nexport type CheckoutSession = z.infer<typeof checkoutSessionSchema>\n\nexport const payRequestSchema = z.object({\n option_id: z.string(),\n payment_token: z.string().optional(),\n payment_method_id: z.string().optional(),\n // Canonical billing identity. The compact card paths send only their\n // required fields; optional address fields remain available to an explicit\n // provider-specific source that models them.\n email: z.string().optional(),\n name_on_card: z.string().optional(),\n address1: z.string().optional(),\n city: z.string().optional(),\n state: z.string().optional(),\n zip: z.string().optional(),\n country: z.string().optional(),\n // A new card for a rail whose driver is card; never beside payment_token.\n card: z\n .object({\n number: z.string(),\n exp_month: z.number(),\n exp_year: z.number(),\n cvc: z.string(),\n })\n .optional(),\n // Collect.js display metadata for a new card (never the PAN).\n last_four: z.string().optional(),\n card_type: z.string().optional(),\n expiry_date: z.string().optional(),\n token_symbol: z.string().optional(),\n})\nexport type PayRequest = z.infer<typeof payRequestSchema>\n\nexport const payResultSchema = z.object({\n status: checkoutSessionStatusSchema,\n redirect_url: httpsURLSchema.optional(),\n transaction_url: z.string().startsWith(\"solana:\").optional(),\n payment_id: z.string().optional(),\n subscription_id: z.string().optional(),\n failure_message: z.string().optional(),\n failure: paymentFailureSchema.nullish(),\n /** The payment operation to authenticate when status is requires_action. */\n operation_id: z.string().optional(),\n})\nexport type PayResult = z.infer<typeof payResultSchema>\n\n// The lifecycle phases the Checkout component moves through. Superset of\n// session statuses: load/ready concerns are the component's, not the wire's.\nexport type CheckoutPhase =\n | \"loading\"\n | \"ready\"\n | \"processing\"\n | \"succeeded\"\n | \"failed\"\n | \"blocked\"\n | \"expired\"\n | \"unavailable\"\n | \"error\"\n","// Generated by `pnpm contract` from the in-repo OpenRails. Do not edit.\n\nexport type OpenRailsCustomerRoute =\n | \"GET /billing/v1/me/balance\"\n | \"POST /billing/v1/me/billing-portal\"\n | \"POST /billing/v1/me/checkout\"\n | \"POST /billing/v1/me/checkout/sessions\"\n | \"GET /billing/v1/me/checkout/{id}\"\n | \"POST /billing/v1/me/checkout/{id}/confirm\"\n | \"PUT /billing/v1/me/collection-payment-method\"\n | \"PUT /billing/v1/me/default-payment-method\"\n | \"GET /billing/v1/me/entitlements/active\"\n | \"GET /billing/v1/me/invoices\"\n | \"GET /billing/v1/me/invoices/{id}\"\n | \"POST /billing/v1/me/invoices/{id}/pay-now\"\n | \"GET /billing/v1/me/notifications\"\n | \"GET /billing/v1/me/notifications/unread-count\"\n | \"POST /billing/v1/me/notifications/{id}/read\"\n | \"GET /billing/v1/me/payment-methods\"\n | \"POST /billing/v1/me/payment-methods\"\n | \"POST /billing/v1/me/payment-methods/stripe-setup\"\n | \"GET /billing/v1/me/payment-methods/stripe-setup/{id}\"\n | \"POST /billing/v1/me/payment-methods/stripe-setup/{id}/confirm\"\n | \"DELETE /billing/v1/me/payment-methods/{id}\"\n | \"PUT /billing/v1/me/payment-methods/{id}\"\n | \"GET /billing/v1/me/payment-operations/{id}/authentication\"\n | \"POST /billing/v1/me/payment-operations/{id}/authentication/confirm\"\n | \"GET /billing/v1/me/payments\"\n | \"GET /billing/v1/me/products\"\n | \"GET /billing/v1/me/products/{product_id}/access\"\n | \"GET /billing/v1/me/spend-limits\"\n | \"GET /billing/v1/me/status\"\n | \"GET /billing/v1/me/subscriptions\"\n | \"GET /billing/v1/me/subscriptions/{id}\"\n | \"POST /billing/v1/me/subscriptions/{id}/cancel\"\n | \"POST /billing/v1/me/subscriptions/{id}/change-tier\"\n | \"POST /billing/v1/me/subscriptions/{id}/change-tier/preview\"\n | \"PUT /billing/v1/me/subscriptions/{id}/payment-method\"\n | \"GET /billing/v1/me/subscriptions/{id}/provider-cutover\"\n | \"POST /billing/v1/me/subscriptions/{id}/provider-cutover\"\n | \"POST /billing/v1/me/subscriptions/{id}/provider-cutover/preview\"\n | \"POST /billing/v1/me/subscriptions/{id}/resume\"\n | \"POST /billing/v1/me/subscriptions/{id}/retry-now\"\n | \"POST /billing/v1/me/subscriptions/{id}/solana-cancel\"\n | \"POST /billing/v1/me/subscriptions/{id}/solana-cancel-tx\"\n | \"POST /billing/v1/me/subscriptions/{id}/solana-tier-change\"\n | \"POST /billing/v1/me/subscriptions/{id}/solana-tier-change/confirm\"\n | \"GET /billing/v1/me/tier\"\n | \"GET /billing/v1/me/transactions\"\n | \"GET /billing/v1/me/usage\"\n\n// Currency code to native-unit decimals (openrails.Currencies()).\nexport const OPENRAILS_CURRENCY_SCALES: Readonly<Record<string, number>> = {\n EUR: 6,\n JPY: 4,\n USD: 6,\n}\n","// Wire types of the OpenRails customer surface (`/billing/v1/me/*`) and public\n// catalog, validated at the boundary. Money is an int64 string in the\n// currency's native unit; its scale comes from GET /currencies. Fixtures:\n// src/test/fixtures/wire.\nimport { z } from \"zod\"\n\nimport type { CardEntry } from \"../lib/card-entry\"\nimport { isAmount } from \"../lib/money\"\n\nconst amount = z.string().refine(isAmount, \"amount must be an int64 string\")\nconst time = z.string()\n\nexport const pageSchema = <T extends z.ZodType>(item: T) =>\n z.object({\n data: z\n .array(item)\n .nullish()\n .transform((v) => v ?? []),\n total: z.number().nullish(),\n limit: z.number().nullish(),\n offset: z.number().nullish(),\n has_more: z.boolean().nullish(),\n })\n\nexport interface Page<T> {\n data: T[]\n total?: number | null\n limit?: number | null\n offset?: number | null\n has_more?: boolean | null\n}\n\nexport const subscriptionStatusSchema = z.string()\n/** `pending | active | past_due | awaiting_method | unverified | cancelled`; kept open for new values. */\nexport type SubscriptionStatus =\n | \"pending\"\n | \"active\"\n | \"past_due\"\n | \"awaiting_method\"\n | \"unverified\"\n | \"cancelled\"\n | (string & {})\n\nexport const subscriptionPriceSchema = z.object({\n id: z.string(),\n key: z.string().nullish(),\n product_id: z.string().nullish(),\n unit_amount: amount,\n currency: z.string(),\n auto_renew: z.boolean().nullish(),\n access_duration_hours: z.number().nullish(),\n})\nexport type SubscriptionPrice = z.infer<typeof subscriptionPriceSchema>\n\nexport const subscriptionProductSchema = z.object({\n id: z.string(),\n key: z.string().nullish(),\n display_name: z.string().nullish(),\n description: z.string().nullish(),\n tier_group: z.string().nullish(),\n tier_rank: z.number().nullish(),\n})\nexport type SubscriptionProduct = z.infer<typeof subscriptionProductSchema>\n\nexport const cardSummarySchema = z.object({\n brand: z.string().nullish(),\n last4: z.string().nullish(),\n exp_month: z.number().nullish(),\n exp_year: z.number().nullish(),\n})\nexport type CardSummary = z.infer<typeof cardSummarySchema>\n\nexport const paymentOperationSchema = z.object({\n id: z.string(),\n status: z.string(),\n})\nexport type PaymentOperation = z.infer<typeof paymentOperationSchema>\n\nexport const paymentRecoverySchema = z.object({\n last_failure_reason: z.string().nullish(),\n retryable: z.boolean(),\n blocked_reason: z.string().nullish(),\n operation: paymentOperationSchema.nullish(),\n})\nexport type PaymentRecovery = z.infer<typeof paymentRecoverySchema>\n\nexport const subscriptionSchema = z.object({\n id: z.string(),\n status: subscriptionStatusSchema,\n rail: z.string().nullish(),\n product_id: z.string().nullish(),\n price_id: z.string().nullish(),\n psp_id: z.string().nullish(),\n payment_method_id: z.string().nullish(),\n started_at: time.nullish(),\n ended_at: time.nullish(),\n current_period_starts_at: time.nullish(),\n current_period_ends_at: time.nullish(),\n cancelled_at: time.nullish(),\n cancel_type: z.string().nullish(),\n resumable: z.boolean().nullish(),\n cancel_scheduled: z.boolean().nullish(),\n /** `reversible | destructive | external_portal` */\n cancel_mode: z.string().nullish(),\n cancel_portal_url: z.string().nullish(),\n grace_ends_at: time.nullish(),\n next_retry_at: time.nullish(),\n price: subscriptionPriceSchema.nullish(),\n product: subscriptionProductSchema.nullish(),\n scheduled_price: subscriptionPriceSchema.nullish(),\n scheduled_product: subscriptionProductSchema.nullish(),\n card: cardSummarySchema.nullish(),\n recovery: paymentRecoverySchema.nullish(),\n created_at: time.nullish(),\n updated_at: time.nullish(),\n})\nexport type Subscription = z.infer<typeof subscriptionSchema> & {\n status: SubscriptionStatus\n}\n\nexport const paymentMethodSchema = z.object({\n id: z.string(),\n type: z.string().nullish(),\n rail: z.string().nullish(),\n psp_id: z.string().nullish(),\n card: cardSummarySchema.nullish(),\n billing_details: z\n .object({ name: z.string().nullish(), email: z.string().nullish() })\n .nullish(),\n health: z\n .object({\n /** `valid | expiring_soon | expired` */\n expiry_status: z.string().nullish(),\n last_charged_at: time.nullish(),\n last_charge_outcome: z.string().nullish(),\n active: z.boolean().nullish(),\n })\n .nullish(),\n subscriptions: z\n .array(\n z.object({\n id: z.string(),\n display_name: z.string().nullish(),\n })\n )\n .nullish(),\n /** The customer's default card: pre-selected, never charged implicitly. */\n default: z.boolean().nullish(),\n /** Currencies whose invoices collect from this method by default. */\n collection_default_currencies: z.array(z.string()).nullish(),\n created_at: time.nullish(),\n})\nexport type PaymentMethod = z.infer<typeof paymentMethodSchema>\n\nexport const paymentSchema = z.object({\n id: z.string(),\n /** `charge | refund` */\n object: z.string().nullish(),\n /** `succeeded | pending | failed | refunded | partially_refunded` */\n status: z.string().nullish(),\n amount: amount,\n amount_refunded: amount.nullish(),\n currency: z.string(),\n subscription_id: z.string().nullish(),\n rail: z.string().nullish(),\n refunded: z.boolean().nullish(),\n created_at: time,\n price: z\n .object({\n id: z.string().nullish(),\n key: z.string().nullish(),\n product: z.string().nullish(),\n /** `one_time | recurring` */\n type: z.string().nullish(),\n /** Exact hours, e.g. `\"720h\"`. */\n recurring: z.object({ interval: z.string().nullish() }).nullish(),\n })\n .nullish(),\n /** What was bought; OpenRails newer than v0.160.0. */\n product: subscriptionProductSchema.nullish(),\n card: cardSummarySchema.nullish(),\n /** Normalized decline of a failed payment. */\n failure: z\n .object({\n reason: z.string(),\n message: z.string(),\n field: z.string().nullish(),\n })\n .nullish(),\n})\nexport type Payment = z.infer<typeof paymentSchema>\n\nexport const invoiceSchema = z.object({\n id: z.string(),\n currency: z.string(),\n invoice_number: z.string().nullish(),\n period_from: time,\n period_to: time,\n total_amount: amount,\n amount_paid: amount,\n amount_due: amount,\n status: z.string(),\n issued_at: time.nullish(),\n due_at: time.nullish(),\n paid_at: time.nullish(),\n recovery: paymentRecoverySchema.nullish(),\n created_at: time,\n})\nexport type Invoice = z.infer<typeof invoiceSchema>\n\nexport const invoicePageSchema = z.object({\n invoices: z\n .array(invoiceSchema)\n .nullish()\n .transform((v) => v ?? []),\n total: z.number().nullish(),\n limit: z.number().nullish(),\n offset: z.number().nullish(),\n})\n\nexport const billingStatusSchema = z.object({\n has_active_subscription: z.boolean(),\n subscription: subscriptionSchema.nullish(),\n next_renewal_at: time.nullish(),\n entitlements: z\n .array(\n z.object({\n entitlement: z.string(),\n start_at: time.nullish(),\n end_at: time.nullish(),\n revoked_at: time.nullish(),\n })\n )\n .nullish(),\n})\nexport type BillingStatus = z.infer<typeof billingStatusSchema>\n\n/** Currency code (upper case) to its native-unit scale. */\nexport type CurrencyScales = Readonly<Record<string, number>>\n\nexport const currencySchema = z.object({\n code: z.string(),\n /** Native-unit decimals of every amount on the wire. */\n decimals: z.number(),\n /** Decimals the provider settles in. */\n minor_decimals: z.number().nullish(),\n})\nexport type Currency = z.infer<typeof currencySchema>\n\nexport const currencyRegistrySchema = z.object({\n currencies: z.array(currencySchema),\n})\n\n/** A catalog price (`GET /prices`, embedded in `GET /products`). */\nexport const priceSchema = z.object({\n id: z.string(),\n key: z.string().nullish(),\n unit_amount: amount,\n currency: z.string(),\n /** `one_time | recurring` */\n type: z.string().nullish(),\n /** Exact hours, e.g. `\"720h\"`; absent on a one-time price. */\n recurring: z.object({ interval: z.string() }).nullish(),\n /** Product id. */\n product: z.string().nullish(),\n active: z.boolean().nullish(),\n /** PSP keys the price is linked to. */\n providers: z.array(z.string()).nullish(),\n metadata: z.record(z.string(), z.string()).nullish(),\n created_at: time.nullish(),\n})\nexport type Price = z.infer<typeof priceSchema>\n\nexport const productSchema = z.object({\n id: z.string(),\n key: z.string().nullish(),\n name: z.string(),\n description: z.string().nullish(),\n /** Keyed by the entitlements the product grants. */\n entitlements_spec: z.record(z.string(), z.number().nullable()).nullish(),\n /** Products sharing a group are tiers a subscription can change between. */\n tier_group: z.string().nullish(),\n tier_rank: z.number().nullish(),\n active: z.boolean().nullish(),\n metadata: z.record(z.string(), z.string()).nullish(),\n created_at: time.nullish(),\n updated_at: time.nullish(),\n prices: z\n .array(priceSchema)\n .nullish()\n .transform((v) => v ?? []),\n})\nexport type Product = z.infer<typeof productSchema>\n\nexport const tierChangePreviewSchema = z.object({\n /** `upgrade | downgrade` */\n action: z.string(),\n price_id: z.string(),\n rail: z.string().nullish(),\n currency: z.string(),\n /** Charged immediately; `\"0\"` for a downgrade. */\n amount_due_now: amount,\n /** The new price, charged at the next renewal. */\n next_charge_amount: amount,\n next_charge_date: time.nullish(),\n /** `now | period_end` */\n effective: z.string(),\n /** The rail finalizes the exact amount (Stripe upgrades). */\n is_estimate: z.boolean().nullish(),\n message: z.string().nullish(),\n})\nexport type TierChangePreview = z.infer<typeof tierChangePreviewSchema>\n\nexport const tierChangeSchema = z.object({\n /** `succeeded | processing | requires_action | blocked` */\n status: z.string(),\n /** `upgrade | downgrade` */\n action: z.string().nullish(),\n /** `now | period_end` */\n effective: z.string().nullish(),\n price_id: z.string().nullish(),\n /** The subscription now carrying the plan (an upgrade may open a successor). */\n subscription_id: z.string().nullish(),\n url: z.string().nullish(),\n next_action: z\n .object({\n /** `payment_authentication` uses `operation_id`. */\n type: z.string(),\n redirect_to_url: z.object({ url: z.string().nullish() }).nullish(),\n })\n .nullish(),\n /** When a scheduled downgrade takes effect. */\n delayed_start: time.nullish(),\n currency: z.string().nullish(),\n amount_due_now: amount.nullish(),\n next_charge_amount: amount.nullish(),\n next_charge_date: time.nullish(),\n message: z.string().nullish(),\n /** The durable operation: unresolved while `processing`, the payment to authenticate on `requires_action`. */\n operation_id: z.string().nullish(),\n})\nexport type TierChange = z.infer<typeof tierChangeSchema>\n\nexport const solanaCancelTxSchema = z.object({\n transaction: z.string().min(1),\n subscription_pda: z.string().nullish(),\n})\n\nconst tokenUnits = z.string().regex(/^\\d+$/, \"units must be a uint64 string\")\n\nexport const solanaTokenSchema = z.object({\n symbol: z.string(),\n name: z.string().nullish(),\n mint: z.string(),\n decimals: z.number(),\n /** USD price as an exact decimal string; absent without a feed quote. */\n price: z.string().nullish(),\n /** The stablecoin to present first. */\n preferred: z.boolean().nullish(),\n /** Can back a recurring subscription, not only a one-off payment. */\n recurring_eligible: z.boolean().nullish(),\n /** What the requested price costs in this token. */\n quote: z\n .object({\n /** Display decimal of `units`. */\n amount: z.string(),\n /** Exact on-chain base units. */\n units: tokenUnits,\n token_price_usd: z.string().nullish(),\n fx_rate: z.string().nullish(),\n fx_currency: z.string().nullish(),\n quoted_at: time.nullish(),\n expires_at: time.nullish(),\n })\n .nullish(),\n /** The requested wallet's holding. */\n balance: z\n .object({\n amount: z.string(),\n units: tokenUnits,\n /** Covers `quote`. */\n sufficient: z.boolean().nullish(),\n })\n .nullish(),\n})\nexport type SolanaToken = z.infer<typeof solanaTokenSchema>\n\nexport const solanaTokensSchema = z.object({\n tokens: z\n .array(solanaTokenSchema)\n .nullish()\n .transform((v) => v ?? []),\n})\n\nexport const solanaConfigSchema = z.object({\n /** `mainnet | devnet | testnet` */\n network: z.string(),\n /** `solana:<network>` */\n chain: z.string().nullish(),\n /** Never set by OpenRails: wallets bring their own RPC. */\n rpcUrl: z.string().nullish(),\n /** Explorer `?cluster=` value; absent on mainnet. */\n explorerCluster: z.string().nullish(),\n preferredToken: z.string().nullish(),\n tokens: z\n .array(solanaTokenSchema)\n .nullish()\n .transform((v) => v ?? []),\n features: z\n .object({\n solanaPay: z.boolean().nullish(),\n recurringSubscriptions: z.boolean().nullish(),\n solanaPayRecurringSubscriptions: z.boolean().nullish(),\n })\n .nullish(),\n})\nexport type SolanaConfig = z.infer<typeof solanaConfigSchema>\n\nexport const solanaTierChangeTxSchema = z.object({\n /** Base64; partially signed for an upgrade, unsigned for a downgrade. */\n transaction: z.string().min(1),\n /** `upgrade | downgrade` */\n kind: z.string().nullish(),\n new_subscription_pda: z.string().nullish(),\n})\nexport type SolanaTierChangeTx = z.infer<typeof solanaTierChangeTxSchema>\n\nexport const solanaTierChangeSchema = z.object({\n /** The subscription now carrying the plan. */\n subscription_id: z.string().nullish(),\n new_subscription_id: z.string().nullish(),\n /** `upgrade | downgrade` */\n kind: z.string().nullish(),\n status: z.string().nullish(),\n /** An earlier confirm already recorded this change. */\n already_confirmed: z.boolean().nullish(),\n})\nexport type SolanaTierChange = z.infer<typeof solanaTierChangeSchema>\n\n/** An in-page card setup; `payment_method_id` is set once the card is saved. */\nexport const cardSetupSchema = z.object({\n id: z.string(),\n status: z.string(),\n client_secret: z.string().nullish(),\n payment_method_id: z.string().nullish(),\n})\nexport type CardSetup = z.infer<typeof cardSetupSchema>\n\nexport const paymentAuthenticationSchema = z.object({\n client_secret: z.string().nullish(),\n})\nexport type PaymentAuthentication = z.infer<typeof paymentAuthenticationSchema>\n\n/** What a card setup hands the server: tokenized data only, never a PAN. */\ninterface NewCardFields {\n /** OpenRails PSP key the card is saved with (e.g. \"nmi\"); required. */\n provider: string\n name_on_card?: string\n country?: string\n zip?: string\n email?: string\n /** Collect.js display metadata: last four digits, brand, MM/YY. */\n last_four?: string\n card_type?: string\n expiry_date?: string\n}\n\n/**\n * A card to save: a token from the PSP's own fields (`payment_token`), or,\n * for a PSP whose card_entry is server (`cardSetupDriver` \"card\"), the card\n * itself, posted to OpenRails and never kept by this package.\n */\nexport type NewCard = NewCardFields &\n (\n | { payment_token: string; card?: never }\n | { card: CardEntry; payment_token?: never }\n )\n\n/**\n * A minted hosted checkout session. `id` reads and pays it with no other\n * credential (`client.checkoutSource(id)`); hand it to this customer's\n * browser only. `url` is the shared payment page (`<CheckoutFrame url>`),\n * absent when the app renders `<Checkout>` itself.\n */\nexport const hostedCheckoutLinkSchema = z.object({\n id: z.string().startsWith(\"ocs_\"),\n url: z.string().url().optional(),\n expires_at: time,\n})\nexport type HostedCheckoutLink = z.infer<typeof hostedCheckoutLinkSchema>\n","import type { z } from \"zod\"\n\nimport type { CheckoutSource } from \"../source\"\nimport {\n checkoutSessionSchema,\n payResultSchema,\n type PayRequest,\n type PayResult,\n} from \"../types\"\nimport {\n BillingError,\n isBillingError,\n localError,\n readBillingError,\n} from \"./errors\"\nimport { OPENRAILS_CURRENCY_SCALES } from \"./generated/openrails-routes\"\nimport {\n billingStatusSchema,\n cardSetupSchema,\n currencyRegistrySchema,\n hostedCheckoutLinkSchema,\n paymentAuthenticationSchema,\n invoicePageSchema,\n invoiceSchema,\n pageSchema,\n paymentMethodSchema,\n paymentSchema,\n priceSchema,\n productSchema,\n solanaCancelTxSchema,\n solanaConfigSchema,\n solanaTierChangeSchema,\n solanaTierChangeTxSchema,\n solanaTokensSchema,\n subscriptionSchema,\n tierChangePreviewSchema,\n tierChangeSchema,\n type BillingStatus,\n type CardSetup,\n type Currency,\n type HostedCheckoutLink,\n type PaymentAuthentication,\n type CurrencyScales,\n type Invoice,\n type NewCard,\n type Page,\n type Payment,\n type PaymentMethod,\n type Price,\n type Product,\n type SolanaConfig,\n type SolanaTierChange,\n type SolanaTierChangeTx,\n type SolanaToken,\n type Subscription,\n type TierChange,\n type TierChangePreview,\n} from \"./types\"\n\nexport interface BillingClientOptions {\n /** OpenRails embedded mount. Default \"/billing/v1\". */\n baseUrl?: string\n /**\n * Transport. Pass an authenticating fetch (auth-ui's `client.authFetch`)\n * or combine the default with `getToken`.\n */\n fetch?: (input: string, init: RequestInit) => Promise<Response>\n /** Bearer for each request; omit when `fetch` authenticates. */\n getToken?: () =>\n string | null | undefined | Promise<string | null | undefined>\n /** Sent as Accept-Language. */\n language?: () => string | null | undefined\n /**\n * Extra or overriding currency scales (code -> native-unit decimals). The\n * pinned OpenRails registry is built in; `/me` amounts carry no scale.\n */\n currencies?: CurrencyScales\n}\n\nexport interface ListOptions {\n limit?: number\n offset?: number\n signal?: AbortSignal\n}\n\nexport type SolanaCancelStage = \"preparing\" | \"signing\" | \"confirming\"\n\n/**\n * Signs and submits a base64 transaction with the customer's wallet and\n * returns its signature. Throw `WalletRejectedError` when the user declines.\n */\nexport type SendSolanaTransaction = (\n transactionBase64: string\n) => Promise<string>\n\nexport class WalletRejectedError extends Error {\n constructor(message = \"The wallet request was declined.\") {\n super(message)\n this.name = \"WalletRejectedError\"\n }\n}\n\nexport const CANCEL_FEEDBACK_MIN = 4\nexport const CANCEL_FEEDBACK_MAX = 500\n\ntype Query = Record<string, string | number | undefined>\n\ninterface RequestOptions {\n method?: string\n query?: Query\n body?: unknown\n signal?: AbortSignal\n headers?: Record<string, string>\n /** Sends no bearer: the hosted checkout session id is the credential. */\n anonymous?: boolean\n}\n\n/** Total wait a GET may spend on its one retry. */\nexport const RETRY_BUDGET_MS = 2_000\nconst RETRY_DELAY_MS = 300\n\n// The wait before retrying a GET answered with res, or null if it is final.\nfunction retryDelay(res: Response): number | null {\n const retryAfter = parseRetryAfter(res.headers.get(\"Retry-After\"))\n switch (res.status) {\n case 429:\n return retryAfter\n case 503:\n return retryAfter ?? RETRY_DELAY_MS\n case 502:\n case 504:\n return RETRY_DELAY_MS\n default:\n return null\n }\n}\n\nfunction parseRetryAfter(value: string | null): number | null {\n if (!value) return null\n if (/^\\d+$/.test(value.trim())) return Number(value.trim()) * 1000\n const at = Date.parse(value)\n return Number.isNaN(at) ? null : Math.max(0, at - Date.now())\n}\n\nfunction pause(ms: number, signal?: AbortSignal): Promise<number> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(signal.reason)\n const timer = setTimeout(() => {\n signal?.removeEventListener(\"abort\", abort)\n resolve(ms)\n }, ms)\n const abort = () => {\n clearTimeout(timer)\n reject(signal?.reason)\n }\n signal?.addEventListener(\"abort\", abort, { once: true })\n })\n}\n\nexport function createBillingClient(options: BillingClientOptions = {}) {\n const base = (options.baseUrl ?? \"/billing/v1\").replace(/\\/+$/, \"\")\n const doFetch =\n options.fetch ?? ((input: string, init: RequestInit) => fetch(input, init))\n const currencies = normalizeScales({\n ...OPENRAILS_CURRENCY_SCALES,\n ...options.currencies,\n })\n\n function url(path: string, query?: Query): string {\n const qs = new URLSearchParams()\n for (const [k, v] of Object.entries(query ?? {}))\n if (v !== undefined && v !== \"\") qs.set(k, String(v))\n const q = qs.toString()\n return `${base}${path}${q ? `?${q}` : \"\"}`\n }\n\n async function send(\n path: string,\n opts: RequestOptions = {}\n ): Promise<Response> {\n const headers = new Headers({ Accept: \"application/json\", ...opts.headers })\n if (opts.body !== undefined) headers.set(\"Content-Type\", \"application/json\")\n const token = opts.anonymous ? undefined : await options.getToken?.()\n if (token) headers.set(\"Authorization\", `Bearer ${token}`)\n const lang = options.language?.()\n if (lang) headers.set(\"Accept-Language\", lang)\n const method = opts.method ?? \"GET\"\n const init = {\n method,\n headers,\n body: opts.body === undefined ? undefined : JSON.stringify(opts.body),\n signal: opts.signal,\n }\n // Only a GET is retried: once, on a network error or 502/503/504 (and a\n // 429 that names its wait), within RETRY_BUDGET_MS. Writes never are.\n const retries = method === \"GET\" ? 1 : 0\n let waited = 0\n for (let attempt = 0; ; attempt++) {\n let res: Response\n try {\n res = await doFetch(url(path, opts.query), init)\n } catch (cause) {\n const delay = RETRY_DELAY_MS\n if (\n attempt >= retries ||\n opts.signal?.aborted ||\n !(cause instanceof TypeError) ||\n waited + delay > RETRY_BUDGET_MS\n )\n throw cause\n waited += await pause(delay, opts.signal)\n continue\n }\n if (res.ok) return res\n const delay = retryDelay(res)\n if (\n attempt >= retries ||\n delay === null ||\n waited + delay > RETRY_BUDGET_MS\n )\n throw await readBillingError(res)\n await res.body?.cancel().catch(() => undefined)\n waited += await pause(delay, opts.signal)\n }\n }\n\n async function json<S extends z.ZodType>(\n schema: S,\n path: string,\n opts?: RequestOptions\n ): Promise<z.output<S>> {\n const res = await send(path, opts)\n let body: unknown\n try {\n body = await res.json()\n } catch {\n throw localError(\"invalid_response\", `${path}: body is not JSON`)\n }\n const parsed = schema.safeParse(body)\n if (!parsed.success)\n throw localError(\n \"invalid_response\",\n `${path}: ${parsed.error.issues[0]?.path.join(\".\")} ${parsed.error.issues[0]?.message}`\n )\n return parsed.data\n }\n\n const id = (value: string) => encodeURIComponent(value)\n const subscriptionPage = pageSchema(subscriptionSchema)\n const methodPage = pageSchema(paymentMethodSchema)\n const paymentPage = pageSchema(paymentSchema)\n const productPage = pageSchema(productSchema)\n const pricePage = pageSchema(priceSchema)\n\n return {\n baseUrl: base,\n\n listSubscriptions(\n opts: ListOptions & { status?: string } = {}\n ): Promise<Page<Subscription>> {\n return json(subscriptionPage, \"/me/subscriptions\", {\n query: {\n status: opts.status ?? \"all\",\n limit: opts.limit ?? 100,\n offset: opts.offset,\n },\n signal: opts.signal,\n })\n },\n\n /** Includes `recovery` (list rows do not). */\n getSubscription(\n subscriptionId: string,\n signal?: AbortSignal\n ): Promise<Subscription> {\n return json(\n subscriptionSchema,\n `/me/subscriptions/${id(subscriptionId)}`,\n {\n signal,\n }\n )\n },\n\n /**\n * Queues the cancellation (202). Access and resumability follow the\n * rail's cancel mode; re-read the subscription to observe the result.\n */\n async cancelSubscription(\n subscriptionId: string,\n input: { feedback: string }\n ): Promise<void> {\n await send(`/me/subscriptions/${id(subscriptionId)}/cancel`, {\n method: \"POST\",\n body: { feedback: input.feedback.trim() },\n })\n },\n\n /** Queues the resumption (202). */\n async resumeSubscription(subscriptionId: string): Promise<void> {\n await send(`/me/subscriptions/${id(subscriptionId)}/resume`, {\n method: \"POST\",\n body: {},\n })\n },\n\n async setSubscriptionPaymentMethod(\n subscriptionId: string,\n paymentMethodId: string\n ): Promise<void> {\n await send(`/me/subscriptions/${id(subscriptionId)}/payment-method`, {\n method: \"PUT\",\n body: { payment_method_id: paymentMethodId },\n })\n },\n\n /** What `changeTier` would charge now and at the next renewal. */\n previewTierChange(\n subscriptionId: string,\n priceId: string,\n signal?: AbortSignal\n ): Promise<TierChangePreview> {\n return json(\n tierChangePreviewSchema,\n `/me/subscriptions/${id(subscriptionId)}/change-tier/preview`,\n { method: \"POST\", body: { price_id: priceId }, signal }\n )\n },\n\n /**\n * Moves the subscription to another price of its tier group: an upgrade\n * charges the saved card now, a downgrade applies at period end.\n * `idempotencyKey` identifies this attempt; reuse it until the change\n * resolves (`processing`, a `tier_change_in_flight` refusal or a lost\n * response) so the stored result replays instead of charging twice.\n */\n changeTier(\n subscriptionId: string,\n input: { priceId: string; idempotencyKey: string }\n ): Promise<TierChange> {\n return json(\n tierChangeSchema,\n `/me/subscriptions/${id(subscriptionId)}/change-tier`,\n {\n method: \"POST\",\n body: { price_id: input.priceId },\n headers: { \"Idempotency-Key\": input.idempotencyKey },\n }\n )\n },\n\n /**\n * Solana rail: the tier-change transaction for the wallet to sign and\n * send. Pass the resulting signature to `confirmSolanaTierChange`.\n */\n prepareSolanaTierChange(\n subscriptionId: string,\n newPriceId: string\n ): Promise<SolanaTierChangeTx> {\n return json(\n solanaTierChangeTxSchema,\n `/me/subscriptions/${id(subscriptionId)}/solana-tier-change`,\n { method: \"POST\", body: { new_price_id: newPriceId } }\n )\n },\n\n /**\n * Records the landed transaction. Keep the signature until this succeeds:\n * confirming it again replays the result (`already_confirmed`).\n */\n confirmSolanaTierChange(\n subscriptionId: string,\n input: { signature: string; newPriceId: string }\n ): Promise<SolanaTierChange> {\n return json(\n solanaTierChangeSchema,\n `/me/subscriptions/${id(subscriptionId)}/solana-tier-change/confirm`,\n {\n method: \"POST\",\n body: { signature: input.signature, new_price_id: input.newPriceId },\n }\n )\n },\n\n /**\n * On-chain cancellation for the solana rail: the server prepares an\n * unsigned transaction, the wallet signs and submits it, the server\n * verifies the signature and records the cancel.\n */\n async cancelSubscriptionOnChain(\n subscriptionId: string,\n sendTransaction: SendSolanaTransaction,\n onStage?: (stage: SolanaCancelStage) => void\n ): Promise<void> {\n onStage?.(\"preparing\")\n const { transaction } = await json(\n solanaCancelTxSchema,\n `/me/subscriptions/${id(subscriptionId)}/solana-cancel-tx`,\n { method: \"POST\", body: {} }\n )\n onStage?.(\"signing\")\n let signature: string\n try {\n signature = await sendTransaction(transaction)\n } catch (err) {\n if (isWalletRejection(err))\n throw localError(\n \"wallet_rejected\",\n \"The wallet request was declined.\"\n )\n throw err\n }\n if (!signature)\n throw localError(\n \"wallet_no_signature\",\n \"The wallet returned no signature.\"\n )\n onStage?.(\"confirming\")\n await send(`/me/subscriptions/${id(subscriptionId)}/solana-cancel`, {\n method: \"POST\",\n body: { signature },\n })\n },\n\n listPaymentMethods(opts: ListOptions = {}): Promise<Page<PaymentMethod>> {\n return json(methodPage, \"/me/payment-methods\", {\n query: { limit: opts.limit ?? 100, offset: opts.offset },\n signal: opts.signal,\n })\n },\n\n /**\n * Stores a card entered in the page: a Collect.js token\n * (`cardSetupDriver` \"collect_js\") or the card itself (\"card\").\n */\n addPaymentMethod(card: NewCard): Promise<PaymentMethod> {\n return json(paymentMethodSchema, \"/me/payment-methods\", {\n method: \"POST\",\n body: card,\n })\n },\n\n /**\n * Starts an in-page card setup with a PSP whose browser SDK collects the\n * card (see `cardSetupDriver`). `idempotencyKey` identifies this attempt.\n */\n createCardSetup(input: {\n pspId: string\n idempotencyKey: string\n }): Promise<CardSetup> {\n return json(cardSetupSchema, \"/me/payment-methods/stripe-setup\", {\n method: \"POST\",\n body: { psp_id: input.pspId, consent: true },\n headers: { \"Idempotency-Key\": input.idempotencyKey },\n })\n },\n\n getCardSetup(setupId: string, signal?: AbortSignal): Promise<CardSetup> {\n return json(\n cardSetupSchema,\n `/me/payment-methods/stripe-setup/${id(setupId)}`,\n { signal }\n )\n },\n\n /** Verifies the setup with the provider; `payment_method_id` once saved. */\n confirmCardSetup(setupId: string): Promise<CardSetup> {\n return json(\n cardSetupSchema,\n `/me/payment-methods/stripe-setup/${id(setupId)}/confirm`,\n { method: \"POST\", body: {} }\n )\n },\n\n /** The provider challenge a pending payment operation is waiting on. */\n getPaymentAuthentication(\n operationId: string\n ): Promise<PaymentAuthentication> {\n return json(\n paymentAuthenticationSchema,\n `/me/payment-operations/${id(operationId)}/authentication`\n )\n },\n\n async confirmPaymentAuthentication(operationId: string): Promise<void> {\n await send(\n `/me/payment-operations/${id(operationId)}/authentication/confirm`,\n { method: \"POST\", body: {} }\n )\n },\n\n /** `pending` when the provider is still converging (202). */\n async removePaymentMethod(\n paymentMethodId: string\n ): Promise<\"removed\" | \"pending\"> {\n const res = await send(`/me/payment-methods/${id(paymentMethodId)}`, {\n method: \"DELETE\",\n })\n return res.status === 202 ? \"pending\" : \"removed\"\n },\n\n /** Makes the method the default collector for one currency's invoices. */\n async setDefaultPaymentMethod(input: {\n currency: string\n paymentMethodId: string\n }): Promise<void> {\n await send(\"/me/collection-payment-method\", {\n method: \"PUT\",\n body: {\n currency: input.currency.toUpperCase(),\n payment_method_id: input.paymentMethodId,\n },\n })\n },\n\n /** Charges and refunds, newest first. `rail` filters by rail. */\n listPayments(\n opts: ListOptions & { rail?: string } = {}\n ): Promise<Page<Payment>> {\n return json(paymentPage, \"/me/payments\", {\n query: {\n limit: opts.limit ?? 20,\n offset: opts.offset,\n type: opts.rail,\n },\n signal: opts.signal,\n })\n },\n\n async listInvoices(opts: ListOptions = {}): Promise<Page<Invoice>> {\n const page = await json(invoicePageSchema, \"/me/invoices\", {\n query: { limit: opts.limit ?? 20, offset: opts.offset },\n signal: opts.signal,\n })\n const offset = page.offset ?? opts.offset ?? 0\n return {\n data: page.invoices,\n total: page.total,\n limit: page.limit,\n offset,\n has_more:\n page.total != null\n ? offset + page.invoices.length < page.total\n : null,\n }\n },\n\n getInvoice(invoiceId: string, signal?: AbortSignal): Promise<Invoice> {\n return json(invoiceSchema, `/me/invoices/${id(invoiceId)}`, { signal })\n },\n\n getStatus(signal?: AbortSignal): Promise<BillingStatus> {\n return json(billingStatusSchema, \"/me/status\", { signal })\n },\n\n /** Active products with their active prices. */\n listProducts(opts: ListOptions = {}): Promise<Page<Product>> {\n return json(productPage, \"/products\", {\n query: { limit: opts.limit ?? 100, offset: opts.offset },\n signal: opts.signal,\n })\n },\n\n /** Active prices. `product` is a `prod_` id; `type` is `recurring | one_time`. */\n listPrices(\n opts: ListOptions & {\n currency?: string\n product?: string\n type?: string\n } = {}\n ): Promise<Page<Price>> {\n return json(pricePage, \"/prices\", {\n query: {\n currency: opts.currency,\n product: opts.product,\n type: opts.type,\n limit: opts.limit ?? 100,\n offset: opts.offset,\n },\n signal: opts.signal,\n })\n },\n\n /** The server's currency registry; `currencies` is the pinned copy. */\n async listCurrencies(signal?: AbortSignal): Promise<Currency[]> {\n const registry = await json(currencyRegistrySchema, \"/currencies\", {\n signal,\n })\n return registry.currencies\n },\n\n /**\n * Mints a hosted checkout session for the signed-in customer and one\n * price. Render it with `<CheckoutFrame url>` when the session has a\n * `url`, else with `<Checkout source={client.checkoutSource(id)}>`.\n * `successUrl` brings the buyer back from a redirect rail; it must be on\n * one of this app's return origins.\n */\n createCheckoutSession(input: {\n priceKey?: string\n priceId?: string\n successUrl?: string\n }): Promise<HostedCheckoutLink> {\n if (!input.priceKey === !input.priceId)\n return Promise.reject(\n localError(\n \"invalid_request\",\n \"Pass exactly one of priceKey or priceId.\"\n )\n )\n return json(hostedCheckoutLinkSchema, \"/me/checkout/sessions\", {\n method: \"POST\",\n body: {\n price_key: input.priceKey,\n price_id: input.priceId,\n success_url: input.successUrl,\n },\n })\n },\n\n /**\n * Reads and pays one hosted checkout session. The id is the only\n * credential: no bearer is sent. A refusal the buyer can answer (an\n * invalid card form, too many attempts) resolves as `failed`; an expired\n * or unknown session as `expired`.\n */\n checkoutSource(sessionId: string): CheckoutSource {\n const path = `/checkout-sessions/${id(sessionId)}`\n return {\n getSession: () =>\n json(checkoutSessionSchema, path, { anonymous: true }),\n async pay(request: PayRequest): Promise<PayResult> {\n try {\n return await json(payResultSchema, `${path}/pay`, {\n method: \"POST\",\n body: request,\n anonymous: true,\n })\n } catch (err) {\n if (!isBillingError(err)) throw err\n switch (err.status) {\n case 404:\n case 410:\n return { status: \"expired\" }\n case 403:\n return { status: \"blocked\", failure_message: err.message }\n case 422:\n case 429:\n return { status: \"failed\", failure_message: err.message }\n }\n throw err\n }\n },\n }\n },\n\n /** Network and accepted tokens; served only with a Solana PSP. */\n getSolanaConfig(signal?: AbortSignal): Promise<SolanaConfig> {\n return json(solanaConfigSchema, \"/solana/config\", { signal })\n },\n\n /**\n * Accepted tokens with live prices. `priceId` or `checkoutSessionId` adds\n * each token's `quote`; `wallet` adds its `balance`.\n */\n async listSolanaTokens(\n opts: {\n priceId?: string\n checkoutSessionId?: string\n wallet?: string\n signal?: AbortSignal\n } = {}\n ): Promise<SolanaToken[]> {\n const { tokens } = await json(solanaTokensSchema, \"/solana/tokens\", {\n query: {\n price_id: opts.priceId,\n checkout_session_id: opts.checkoutSessionId,\n wallet: opts.wallet,\n },\n signal: opts.signal,\n })\n return tokens\n },\n\n /** Currency code (upper case) to native-unit decimals. */\n currencies,\n }\n}\n\nfunction normalizeScales(scales: CurrencyScales): CurrencyScales {\n return Object.fromEntries(\n Object.entries(scales).map(([code, decimals]) => [\n code.toUpperCase(),\n decimals,\n ])\n )\n}\n\nexport type BillingClient = ReturnType<typeof createBillingClient>\n\nexport const isWalletRejection = (error: unknown): boolean =>\n error instanceof WalletRejectedError ||\n (error instanceof Error && error.name === \"WalletRejectedError\") ||\n (error instanceof BillingError && error.code === \"wallet_rejected\")\n"],"mappings":"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"}
@@ -1,54 +0,0 @@
1
- //#region src/client/errors.ts
2
- var e = class extends Error {
3
- status;
4
- type;
5
- code;
6
- param;
7
- requestId;
8
- metadata;
9
- constructor(e, t) {
10
- super(t.message), this.name = "BillingError", this.status = e, this.type = t.type, this.code = t.code, this.param = t.param, this.requestId = t.request_id, this.metadata = t.metadata ?? {};
11
- }
12
- }, t = (t) => t instanceof e, n = (e) => {
13
- let t = e?.status;
14
- return typeof t == "number" && t >= 500 && t < 600;
15
- };
16
- function r(t, n) {
17
- return new e(0, {
18
- type: "local",
19
- code: t,
20
- message: n
21
- });
22
- }
23
- async function i(t) {
24
- let n;
25
- try {
26
- n = await t.json();
27
- } catch {
28
- n = void 0;
29
- }
30
- let r = n?.error;
31
- if (r && typeof r == "object") {
32
- let n = r;
33
- if (typeof n.code == "string" && n.code) return new e(t.status, {
34
- type: typeof n.type == "string" ? n.type : "",
35
- code: n.code,
36
- message: typeof n.message == "string" ? n.message : n.code,
37
- request_id: typeof n.request_id == "string" ? n.request_id : t.headers.get("X-Request-ID") ?? void 0,
38
- param: typeof n.param == "string" ? n.param : void 0,
39
- metadata: n.metadata && typeof n.metadata == "object" ? n.metadata : void 0
40
- });
41
- }
42
- return new e(t.status, {
43
- type: t.status >= 500 ? "api_error" : "",
44
- code: typeof r == "string" && r ? r : t.status >= 500 ? "server_error" : "unknown_error",
45
- message: `HTTP ${t.status}`
46
- });
47
- }
48
- function a(t) {
49
- return t instanceof e ? t : t instanceof TypeError ? r("network_error", t.message) : r("unknown_error", t instanceof Error ? t.message : String(t));
50
- }
51
- //#endregion
52
- export { i as a, r as i, t as n, a as o, n as r, e as t };
53
-
54
- //# sourceMappingURL=errors-T-PRm3vV.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"errors-T-PRm3vV.js","names":[],"sources":["../src/client/errors.ts"],"sourcesContent":["// Mirrors OpenRails internal/api.ErrorResponse:\n// {\"error\":{\"type\",\"code\",\"message\",\"request_id?\",\"param?\",\"metadata?\"}}.\nexport interface BillingErrorBody {\n type: string\n code: string\n message: string\n request_id?: string\n param?: string\n metadata?: Record<string, unknown>\n}\n\n// Local codes: network_error, invalid_response, unknown_error, and the wallet\n// codes the Solana cancel flow raises.\nexport class BillingError extends Error {\n readonly status: number\n readonly type: string\n readonly code: string\n readonly param?: string\n readonly requestId?: string\n readonly metadata: Record<string, unknown>\n\n constructor(status: number, body: BillingErrorBody) {\n super(body.message)\n this.name = \"BillingError\"\n this.status = status\n this.type = body.type\n this.code = body.code\n this.param = body.param\n this.requestId = body.request_id\n this.metadata = body.metadata ?? {}\n }\n}\n\nexport const isBillingError = (value: unknown): value is BillingError =>\n value instanceof BillingError\n\n/**\n * A server failure (HTTP 5xx) from any client or host source that carries a\n * numeric `status`. It is surfaced at once, never retried behind the caller.\n */\nexport const isServerError = (value: unknown): boolean => {\n const status = (value as { status?: unknown } | null)?.status\n return typeof status === \"number\" && status >= 500 && status < 600\n}\n\nexport function localError(code: string, message: string): BillingError {\n return new BillingError(0, { type: \"local\", code, message })\n}\n\nexport async function readBillingError(res: Response): Promise<BillingError> {\n let body: unknown\n try {\n body = await res.json()\n } catch {\n body = undefined\n }\n const err = (body as { error?: unknown } | undefined)?.error\n if (err && typeof err === \"object\") {\n const e = err as Partial<BillingErrorBody>\n if (typeof e.code === \"string\" && e.code) {\n return new BillingError(res.status, {\n type: typeof e.type === \"string\" ? e.type : \"\",\n code: e.code,\n message: typeof e.message === \"string\" ? e.message : e.code,\n request_id:\n typeof e.request_id === \"string\"\n ? e.request_id\n : (res.headers.get(\"X-Request-ID\") ?? undefined),\n param: typeof e.param === \"string\" ? e.param : undefined,\n metadata:\n e.metadata && typeof e.metadata === \"object\" ? e.metadata : undefined,\n })\n }\n }\n return new BillingError(res.status, {\n type: res.status >= 500 ? \"api_error\" : \"\",\n code:\n typeof err === \"string\" && err\n ? err\n : res.status >= 500\n ? \"server_error\"\n : \"unknown_error\",\n message: `HTTP ${res.status}`,\n })\n}\n\n// Normalizes anything a client call can throw into a BillingError.\nexport function toBillingError(error: unknown): BillingError {\n if (error instanceof BillingError) return error\n if (error instanceof TypeError)\n return localError(\"network_error\", error.message)\n return localError(\n \"unknown_error\",\n error instanceof Error ? error.message : String(error)\n )\n}\n"],"mappings":";AAaA,IAAa,IAAb,cAAkC,MAAM;CACtC;CACA;CACA;CACA;CACA;CACA;CAEA,YAAY,GAAgB,GAAwB;EAQlD,AAPA,MAAM,EAAK,OAAO,GAClB,KAAK,OAAO,gBACZ,KAAK,SAAS,GACd,KAAK,OAAO,EAAK,MACjB,KAAK,OAAO,EAAK,MACjB,KAAK,QAAQ,EAAK,OAClB,KAAK,YAAY,EAAK,YACtB,KAAK,WAAW,EAAK,YAAY,CAAC;CACpC;AACF,GAEa,KAAkB,MAC7B,aAAiB,GAMN,KAAiB,MAA4B;CACxD,IAAM,IAAU,GAAuC;CACvD,OAAO,OAAO,KAAW,YAAY,KAAU,OAAO,IAAS;AACjE;AAEA,SAAgB,EAAW,GAAc,GAA+B;CACtE,OAAO,IAAI,EAAa,GAAG;EAAE,MAAM;EAAS;EAAM;CAAQ,CAAC;AAC7D;AAEA,eAAsB,EAAiB,GAAsC;CAC3E,IAAI;CACJ,IAAI;EACF,IAAO,MAAM,EAAI,KAAK;CACxB,QAAQ;EACN,IAAO,KAAA;CACT;CACA,IAAM,IAAO,GAA0C;CACvD,IAAI,KAAO,OAAO,KAAQ,UAAU;EAClC,IAAM,IAAI;EACV,IAAI,OAAO,EAAE,QAAS,YAAY,EAAE,MAClC,OAAO,IAAI,EAAa,EAAI,QAAQ;GAClC,MAAM,OAAO,EAAE,QAAS,WAAW,EAAE,OAAO;GAC5C,MAAM,EAAE;GACR,SAAS,OAAO,EAAE,WAAY,WAAW,EAAE,UAAU,EAAE;GACvD,YACE,OAAO,EAAE,cAAe,WACpB,EAAE,aACD,EAAI,QAAQ,IAAI,cAAc,KAAK,KAAA;GAC1C,OAAO,OAAO,EAAE,SAAU,WAAW,EAAE,QAAQ,KAAA;GAC/C,UACE,EAAE,YAAY,OAAO,EAAE,YAAa,WAAW,EAAE,WAAW,KAAA;EAChE,CAAC;CAEL;CACA,OAAO,IAAI,EAAa,EAAI,QAAQ;EAClC,MAAM,EAAI,UAAU,MAAM,cAAc;EACxC,MACE,OAAO,KAAQ,YAAY,IACvB,IACA,EAAI,UAAU,MACZ,iBACA;EACR,SAAS,QAAQ,EAAI;CACvB,CAAC;AACH;AAGA,SAAgB,EAAe,GAA8B;CAI3D,OAHI,aAAiB,IAAqB,IACtC,aAAiB,YACZ,EAAW,iBAAiB,EAAM,OAAO,IAC3C,EACL,iBACA,aAAiB,QAAQ,EAAM,UAAU,OAAO,CAAK,CACvD;AACF"}
@@ -1,285 +0,0 @@
1
- import { o as e } from "./errors-T-PRm3vV.js";
2
- import { createContext as t, useCallback as n, useContext as r, useEffect as i, useRef as a, useState as o } from "react";
3
- //#region src/react/context.ts
4
- var s = t(null);
5
- function c() {
6
- let e = r(s);
7
- if (!e) throw Error("billing-ui: wrap the tree in <BillingProvider>");
8
- return e;
9
- }
10
- var l = () => c().client, u = () => c().refresh, d = () => r(s);
11
- //#endregion
12
- //#region src/react/remote.ts
13
- function f(t, r) {
14
- let [s, c] = o(0), l = `${t}|${s}`, [u, d] = o({
15
- request: null,
16
- data: null,
17
- error: null
18
- }), f = a(r);
19
- i(() => {
20
- f.current = r;
21
- }), i(() => {
22
- let t = new AbortController();
23
- return f.current(t.signal).then((e) => d({
24
- request: l,
25
- data: e,
26
- error: null
27
- }), (n) => {
28
- t.signal.aborted || d((t) => ({
29
- request: l,
30
- data: t.data,
31
- error: e(n)
32
- }));
33
- }), () => t.abort();
34
- }, [l]);
35
- let p = n(() => c((e) => e + 1), []), m = n((e) => d((t) => t.data === null ? t : {
36
- ...t,
37
- data: e(t.data)
38
- }), []);
39
- return {
40
- data: u.data,
41
- loading: u.request !== l,
42
- error: u.request === l ? u.error : null,
43
- refetch: p,
44
- replace: m
45
- };
46
- }
47
- var p = (e) => new Promise((t) => setTimeout(t, e)), m = (e) => !!e.cancel_scheduled || e.status === "cancelled" || !!e.resumable, h = (e) => !e.cancel_scheduled && e.status !== "cancelled";
48
- function g() {
49
- let [e, t] = o({});
50
- return [e, n((e, n) => {
51
- t((t) => {
52
- let r = { ...t };
53
- return n ? r[e] = n : delete r[e], r;
54
- });
55
- }, [])];
56
- }
57
- function _(t = {}) {
58
- let { client: r, version: i, notify: a, settle: o } = c(), s = t.status ?? "all", l = t.limit ?? 100, u = f(`${s}|${l}|${i}`, (e) => r.listSubscriptions({
59
- status: s,
60
- limit: l,
61
- signal: e
62
- })), [d, _] = g(), { replace: v } = u, y = n(async (e, t) => {
63
- for (let n = 0; n < o.attempts; n++) {
64
- let n = await r.getSubscription(e).catch(() => null);
65
- if (n && t(n)) return v((t) => ({
66
- ...t,
67
- data: t.data.map((t) => t.id === e ? n : t)
68
- })), !0;
69
- await p(o.intervalMs);
70
- }
71
- return !1;
72
- }, [
73
- r,
74
- v,
75
- o.attempts,
76
- o.intervalMs
77
- ]), b = n(async (t, n, r, i) => {
78
- _(t, n);
79
- try {
80
- let e = await r();
81
- return i?.(e !== !1), null;
82
- } catch (t) {
83
- return e(t);
84
- } finally {
85
- _(t, null);
86
- }
87
- }, [_]), x = n((e, t) => b(e, "cancel", async () => (await r.cancelSubscription(e, { feedback: t }), y(e, m)), (t) => a({
88
- type: "subscription.cancelled",
89
- subscriptionId: e,
90
- settled: t
91
- })), [
92
- b,
93
- r,
94
- a,
95
- y
96
- ]), S = n((e, t) => b(e, "preparing", async () => (await r.cancelSubscriptionOnChain(e, t, (t) => _(e, t)), y(e, m)), (t) => a({
97
- type: "subscription.cancelled",
98
- subscriptionId: e,
99
- settled: t
100
- })), [
101
- b,
102
- r,
103
- _,
104
- a,
105
- y
106
- ]), C = n((e) => b(e, "resume", async () => (await r.resumeSubscription(e), y(e, h)), (t) => a({
107
- type: "subscription.resumed",
108
- subscriptionId: e,
109
- settled: t
110
- })), [
111
- b,
112
- r,
113
- a,
114
- y
115
- ]), w = n((e, t) => b(e, "payment_method", async () => {
116
- await r.setSubscriptionPaymentMethod(e, t), v((n) => ({
117
- ...n,
118
- data: n.data.map((n) => n.id === e ? {
119
- ...n,
120
- payment_method_id: t
121
- } : n)
122
- }));
123
- }, () => a({
124
- type: "subscription.payment_method_changed",
125
- subscriptionId: e,
126
- paymentMethodId: t
127
- })), [
128
- b,
129
- r,
130
- a,
131
- v
132
- ]), T = n(async (t, n) => {
133
- _(t, "change_tier");
134
- try {
135
- let e = await r.changeTier(t, n);
136
- return a({
137
- type: "subscription.tier_changed",
138
- subscriptionId: t,
139
- change: e
140
- }), e;
141
- } catch (t) {
142
- return e(t);
143
- } finally {
144
- _(t, null);
145
- }
146
- }, [
147
- r,
148
- _,
149
- a
150
- ]);
151
- return {
152
- subscriptions: u.data?.data ?? null,
153
- total: u.data?.total ?? null,
154
- loading: u.loading,
155
- error: u.error,
156
- refetch: u.refetch,
157
- pending: d,
158
- cancel: x,
159
- cancelOnChain: S,
160
- resume: C,
161
- setPaymentMethod: w,
162
- changeTier: T
163
- };
164
- }
165
- function v(e = {}) {
166
- let { client: t } = c(), n = e.limit ?? 100, r = f(`${n}`, (e) => t.listProducts({
167
- limit: n,
168
- signal: e
169
- }));
170
- return {
171
- products: r.data?.data ?? null,
172
- total: r.data?.total ?? null,
173
- loading: r.loading,
174
- error: r.error,
175
- refetch: r.refetch
176
- };
177
- }
178
- function y() {
179
- let { client: t, version: r, notify: i } = c(), a = f(`${r}`, (e) => t.listPaymentMethods({ signal: e })), [s, l] = g(), [u, d] = o(!1), { replace: p } = a, m = n(async (n) => {
180
- d(!0);
181
- try {
182
- let e = await t.addPaymentMethod(n);
183
- return p((t) => ({
184
- ...t,
185
- data: [...t.data, e]
186
- })), i({
187
- type: "payment_method.added",
188
- paymentMethodId: e.id
189
- }), null;
190
- } catch (t) {
191
- return e(t);
192
- } finally {
193
- d(!1);
194
- }
195
- }, [
196
- t,
197
- i,
198
- p
199
- ]), h = n(async (n) => {
200
- l(n, "remove");
201
- try {
202
- return await t.removePaymentMethod(n), p((e) => ({
203
- ...e,
204
- data: e.data.filter((e) => e.id !== n)
205
- })), i({
206
- type: "payment_method.removed",
207
- paymentMethodId: n
208
- }), null;
209
- } catch (t) {
210
- return e(t);
211
- } finally {
212
- l(n, null);
213
- }
214
- }, [
215
- t,
216
- l,
217
- i,
218
- p
219
- ]), _ = n(async (n, r) => {
220
- l(n, "default");
221
- try {
222
- await t.setDefaultPaymentMethod({
223
- currency: r,
224
- paymentMethodId: n
225
- });
226
- let e = r.toUpperCase();
227
- return p((t) => ({
228
- ...t,
229
- data: t.data.map((t) => {
230
- let r = (t.collection_default_currencies ?? []).filter((t) => t !== e);
231
- return {
232
- ...t,
233
- collection_default_currencies: t.id === n ? [...r, e] : r
234
- };
235
- })
236
- })), i({
237
- type: "payment_method.default_changed",
238
- paymentMethodId: n
239
- }), null;
240
- } catch (t) {
241
- return e(t);
242
- } finally {
243
- l(n, null);
244
- }
245
- }, [
246
- t,
247
- l,
248
- i,
249
- p
250
- ]);
251
- return {
252
- methods: a.data?.data ?? null,
253
- loading: a.loading,
254
- error: a.error,
255
- refetch: a.refetch,
256
- pending: s,
257
- adding: u,
258
- add: m,
259
- remove: h,
260
- setDefault: _
261
- };
262
- }
263
- function b(e = {}) {
264
- let { client: t, version: r } = c(), i = e.pageSize ?? 20, [a, s] = o(0), l = f(`${i}|${e.rail ?? ""}|${a}|${r}`, (n) => t.listPayments({
265
- limit: i,
266
- offset: a * i,
267
- rail: e.rail,
268
- signal: n
269
- })), u = l.data, d = u?.total ?? null, p = u?.has_more ?? (d === null ? u?.data.length === i : (a + 1) * i < d);
270
- return {
271
- payments: u?.data ?? null,
272
- page: a,
273
- hasMore: !!p,
274
- total: d,
275
- loading: l.loading,
276
- error: l.error,
277
- next: n(() => s((e) => e + 1), []),
278
- previous: n(() => s((e) => Math.max(0, e - 1)), []),
279
- refetch: l.refetch
280
- };
281
- }
282
- //#endregion
283
- export { s as a, u as c, _ as i, d as l, b as n, l as o, v as r, c as s, y as t };
284
-
285
- //# sourceMappingURL=hooks-DLFF-zx5.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"hooks-DLFF-zx5.js","names":[],"sources":["../src/react/context.ts","../src/react/remote.ts","../src/react/hooks.ts"],"sourcesContent":["import { createContext, useContext } from \"react\"\n\nimport type { BillingClient } from \"../client/client\"\nimport type { TierChange } from \"../client/types\"\n\nexport type BillingChange =\n | {\n type: \"subscription.cancelled\" | \"subscription.resumed\"\n subscriptionId: string\n /** False when the server had not applied the queued change yet. */\n settled: boolean\n }\n | {\n type: \"subscription.payment_method_changed\"\n subscriptionId: string\n paymentMethodId: string\n }\n | {\n type: \"subscription.tier_changed\"\n subscriptionId: string\n /** `status` may still be `processing` or `requires_action`. */\n change: TierChange\n }\n | {\n type:\n | \"payment_method.added\"\n | \"payment_method.removed\"\n | \"payment_method.default_changed\"\n paymentMethodId: string\n }\n\nexport interface BillingContextValue {\n client: BillingClient\n /** Bumped after every mutation; hooks refetch on change. */\n version: number\n notify(change: BillingChange): void\n /** Refetch every hook after a host-side change such as a plan switch. */\n refresh(): void\n settle: { intervalMs: number; attempts: number }\n}\n\nexport const BillingContext = createContext<BillingContextValue | null>(null)\n\nexport function useBillingContext(): BillingContextValue {\n const ctx = useContext(BillingContext)\n if (!ctx) throw new Error(\"billing-ui: wrap the tree in <BillingProvider>\")\n return ctx\n}\n\nexport const useBillingClient = (): BillingClient => useBillingContext().client\n\nexport const useBillingRefresh = (): (() => void) => useBillingContext().refresh\n\n/** The billing context when a BillingProvider is present, else null. */\nexport const useOptionalBillingContext = (): BillingContextValue | null =>\n useContext(BillingContext)\n","import { useCallback, useEffect, useRef, useState } from \"react\"\n\nimport { toBillingError, type BillingError } from \"../client/errors\"\n\nexport interface RemoteState<T> {\n data: T | null\n loading: boolean\n error: BillingError | null\n refetch: () => void\n}\n\n// Keyed fetch that keeps the previous data while a newer key loads, so a\n// refetch after a mutation never flashes an empty list.\nexport function useRemote<T>(\n key: string,\n load: (signal: AbortSignal) => Promise<T>\n): RemoteState<T> & { replace: (update: (data: T) => T) => void } {\n const [nonce, setNonce] = useState(0)\n const request = `${key}|${nonce}`\n const [state, setState] = useState<{\n request: string | null\n data: T | null\n error: BillingError | null\n }>({ request: null, data: null, error: null })\n const loadRef = useRef(load)\n useEffect(() => {\n loadRef.current = load\n })\n\n useEffect(() => {\n const ctl = new AbortController()\n loadRef.current(ctl.signal).then(\n (data) => setState({ request, data, error: null }),\n (err: unknown) => {\n if (!ctl.signal.aborted)\n setState((s) => ({\n request,\n data: s.data,\n error: toBillingError(err),\n }))\n }\n )\n return () => ctl.abort()\n }, [request])\n\n const refetch = useCallback(() => setNonce((n) => n + 1), [])\n const replace = useCallback(\n (update: (data: T) => T) =>\n setState((s) => (s.data === null ? s : { ...s, data: update(s.data) })),\n []\n )\n return {\n data: state.data,\n loading: state.request !== request,\n error: state.request === request ? state.error : null,\n refetch,\n replace,\n }\n}\n\nexport const sleep = (ms: number) =>\n new Promise<void>((resolve) => setTimeout(resolve, ms))\n","import { useCallback, useState } from \"react\"\n\nimport type { SendSolanaTransaction, SolanaCancelStage } from \"../client/client\"\nimport { toBillingError, type BillingError } from \"../client/errors\"\nimport type {\n NewCard,\n Payment,\n PaymentMethod,\n Product,\n Subscription,\n TierChange,\n} from \"../client/types\"\nimport { useBillingContext } from \"./context\"\nimport { sleep, useRemote } from \"./remote\"\n\n// Actions never throw: they resolve to null on success or the error.\nexport type ActionResult = Promise<BillingError | null>\n\nexport type SubscriptionAction =\n \"cancel\" | \"resume\" | \"payment_method\" | \"change_tier\" | SolanaCancelStage\n\nexport interface SubscriptionsOptions {\n /** Server filter; default `all`. */\n status?: string\n limit?: number\n}\n\nexport interface SubscriptionsState {\n subscriptions: Subscription[] | null\n total: number | null\n loading: boolean\n error: BillingError | null\n refetch: () => void\n /** In-flight action per subscription id. */\n pending: Readonly<Record<string, SubscriptionAction>>\n cancel: (subscriptionId: string, feedback: string) => ActionResult\n /** Solana rail: the wallet signs the server-prepared cancel transaction. */\n cancelOnChain: (\n subscriptionId: string,\n sendTransaction: SendSolanaTransaction\n ) => ActionResult\n resume: (subscriptionId: string) => ActionResult\n setPaymentMethod: (\n subscriptionId: string,\n paymentMethodId: string\n ) => ActionResult\n /**\n * Card rails: `client.changeTier`. Resolves to the change, whose `status`\n * may still be `processing` or `requires_action`, or to the error.\n */\n changeTier: (\n subscriptionId: string,\n input: { priceId: string; idempotencyKey: string }\n ) => Promise<TierChange | BillingError>\n}\n\nconst cancelApplied = (s: Subscription) =>\n !!s.cancel_scheduled || s.status === \"cancelled\" || !!s.resumable\nconst resumeApplied = (s: Subscription) =>\n !s.cancel_scheduled && s.status !== \"cancelled\"\n\nfunction usePending<A extends string>() {\n const [pending, setPending] = useState<Readonly<Record<string, A>>>({})\n const mark = useCallback((id: string, action: A | null) => {\n setPending((p) => {\n const next = { ...p }\n if (action) next[id] = action\n else delete next[id]\n return next\n })\n }, [])\n return [pending, mark] as const\n}\n\nexport function useSubscriptions(\n options: SubscriptionsOptions = {}\n): SubscriptionsState {\n const { client, version, notify, settle } = useBillingContext()\n const status = options.status ?? \"all\"\n const limit = options.limit ?? 100\n const remote = useRemote(`${status}|${limit}|${version}`, (signal) =>\n client.listSubscriptions({ status, limit, signal })\n )\n const [pending, mark] = usePending<SubscriptionAction>()\n const { replace } = remote\n\n // Re-reads a queued change until it shows, then patches the row.\n const settleRow = useCallback(\n async (id: string, applied: (s: Subscription) => boolean) => {\n for (let i = 0; i < settle.attempts; i++) {\n const next = await client.getSubscription(id).catch(() => null)\n if (next && applied(next)) {\n replace((page) => ({\n ...page,\n data: page.data.map((s) => (s.id === id ? next : s)),\n }))\n return true\n }\n await sleep(settle.intervalMs)\n }\n return false\n },\n [client, replace, settle.attempts, settle.intervalMs]\n )\n\n const act = useCallback(\n async (\n id: string,\n action: SubscriptionAction,\n run: () => Promise<boolean | void>,\n done?: (settled: boolean) => void\n ): ActionResult => {\n mark(id, action)\n try {\n const settled = await run()\n done?.(settled !== false)\n return null\n } catch (err) {\n return toBillingError(err)\n } finally {\n mark(id, null)\n }\n },\n [mark]\n )\n\n const cancel = useCallback(\n (id: string, feedback: string) =>\n act(\n id,\n \"cancel\",\n async () => {\n await client.cancelSubscription(id, { feedback })\n return settleRow(id, cancelApplied)\n },\n (settled) =>\n notify({\n type: \"subscription.cancelled\",\n subscriptionId: id,\n settled,\n })\n ),\n [act, client, notify, settleRow]\n )\n\n // A declined wallet prompt resolves to a `wallet_rejected` error.\n const cancelOnChain = useCallback(\n (id: string, sendTransaction: SendSolanaTransaction) =>\n act(\n id,\n \"preparing\",\n async () => {\n await client.cancelSubscriptionOnChain(id, sendTransaction, (stage) =>\n mark(id, stage)\n )\n return settleRow(id, cancelApplied)\n },\n (settled) =>\n notify({\n type: \"subscription.cancelled\",\n subscriptionId: id,\n settled,\n })\n ),\n [act, client, mark, notify, settleRow]\n )\n\n const resume = useCallback(\n (id: string) =>\n act(\n id,\n \"resume\",\n async () => {\n await client.resumeSubscription(id)\n return settleRow(id, resumeApplied)\n },\n (settled) =>\n notify({ type: \"subscription.resumed\", subscriptionId: id, settled })\n ),\n [act, client, notify, settleRow]\n )\n\n const setPaymentMethod = useCallback(\n (id: string, paymentMethodId: string) =>\n act(\n id,\n \"payment_method\",\n async () => {\n await client.setSubscriptionPaymentMethod(id, paymentMethodId)\n replace((page) => ({\n ...page,\n data: page.data.map((s) =>\n s.id === id ? { ...s, payment_method_id: paymentMethodId } : s\n ),\n }))\n },\n () =>\n notify({\n type: \"subscription.payment_method_changed\",\n subscriptionId: id,\n paymentMethodId,\n })\n ),\n [act, client, notify, replace]\n )\n\n // An upgrade may open a successor subscription: notify refetches the list.\n const changeTier = useCallback(\n async (id: string, input: { priceId: string; idempotencyKey: string }) => {\n mark(id, \"change_tier\")\n try {\n const change = await client.changeTier(id, input)\n notify({\n type: \"subscription.tier_changed\",\n subscriptionId: id,\n change,\n })\n return change\n } catch (err) {\n return toBillingError(err)\n } finally {\n mark(id, null)\n }\n },\n [client, mark, notify]\n )\n\n return {\n subscriptions: remote.data?.data ?? null,\n total: remote.data?.total ?? null,\n loading: remote.loading,\n error: remote.error,\n refetch: remote.refetch,\n pending,\n cancel,\n cancelOnChain,\n resume,\n setPaymentMethod,\n changeTier,\n }\n}\n\nexport interface ProductsState {\n products: Product[] | null\n total: number | null\n loading: boolean\n error: BillingError | null\n refetch: () => void\n}\n\n/** The catalog: active products with their active prices. */\nexport function useProducts(options: { limit?: number } = {}): ProductsState {\n const { client } = useBillingContext()\n const limit = options.limit ?? 100\n const remote = useRemote(`${limit}`, (signal) =>\n client.listProducts({ limit, signal })\n )\n return {\n products: remote.data?.data ?? null,\n total: remote.data?.total ?? null,\n loading: remote.loading,\n error: remote.error,\n refetch: remote.refetch,\n }\n}\n\nexport type PaymentMethodAction = \"remove\" | \"default\"\n\nexport interface PaymentMethodsState {\n methods: PaymentMethod[] | null\n loading: boolean\n error: BillingError | null\n refetch: () => void\n pending: Readonly<Record<string, PaymentMethodAction>>\n adding: boolean\n add: (card: NewCard) => ActionResult\n remove: (paymentMethodId: string) => ActionResult\n /** Default collector for one currency's invoices. */\n setDefault: (paymentMethodId: string, currency: string) => ActionResult\n}\n\nexport function usePaymentMethods(): PaymentMethodsState {\n const { client, version, notify } = useBillingContext()\n const remote = useRemote(`${version}`, (signal) =>\n client.listPaymentMethods({ signal })\n )\n const [pending, mark] = usePending<PaymentMethodAction>()\n const [adding, setAdding] = useState(false)\n const { replace } = remote\n\n const add = useCallback(\n async (card: NewCard): ActionResult => {\n setAdding(true)\n try {\n const method = await client.addPaymentMethod(card)\n replace((page) => ({ ...page, data: [...page.data, method] }))\n notify({ type: \"payment_method.added\", paymentMethodId: method.id })\n return null\n } catch (err) {\n return toBillingError(err)\n } finally {\n setAdding(false)\n }\n },\n [client, notify, replace]\n )\n\n const remove = useCallback(\n async (id: string): ActionResult => {\n mark(id, \"remove\")\n try {\n await client.removePaymentMethod(id)\n replace((page) => ({\n ...page,\n data: page.data.filter((m) => m.id !== id),\n }))\n notify({ type: \"payment_method.removed\", paymentMethodId: id })\n return null\n } catch (err) {\n return toBillingError(err)\n } finally {\n mark(id, null)\n }\n },\n [client, mark, notify, replace]\n )\n\n const setDefault = useCallback(\n async (id: string, currency: string): ActionResult => {\n mark(id, \"default\")\n try {\n await client.setDefaultPaymentMethod({ currency, paymentMethodId: id })\n const code = currency.toUpperCase()\n replace((page) => ({\n ...page,\n data: page.data.map((m) => {\n const others = (m.collection_default_currencies ?? []).filter(\n (c) => c !== code\n )\n return {\n ...m,\n collection_default_currencies:\n m.id === id ? [...others, code] : others,\n }\n }),\n }))\n notify({ type: \"payment_method.default_changed\", paymentMethodId: id })\n return null\n } catch (err) {\n return toBillingError(err)\n } finally {\n mark(id, null)\n }\n },\n [client, mark, notify, replace]\n )\n\n return {\n methods: remote.data?.data ?? null,\n loading: remote.loading,\n error: remote.error,\n refetch: remote.refetch,\n pending,\n adding,\n add,\n remove,\n setDefault,\n }\n}\n\nexport interface PaymentsOptions {\n pageSize?: number\n /** Filter by rail. */\n rail?: string\n}\n\nexport interface PaymentsState {\n payments: Payment[] | null\n /** Zero-based. */\n page: number\n hasMore: boolean\n total: number | null\n loading: boolean\n error: BillingError | null\n next: () => void\n previous: () => void\n refetch: () => void\n}\n\nexport function usePayments(options: PaymentsOptions = {}): PaymentsState {\n const { client, version } = useBillingContext()\n const pageSize = options.pageSize ?? 20\n const [page, setPage] = useState(0)\n const remote = useRemote(\n `${pageSize}|${options.rail ?? \"\"}|${page}|${version}`,\n (signal) =>\n client.listPayments({\n limit: pageSize,\n offset: page * pageSize,\n rail: options.rail,\n signal,\n })\n )\n const data = remote.data\n const total = data?.total ?? null\n const hasMore =\n data?.has_more ??\n (total !== null\n ? (page + 1) * pageSize < total\n : data?.data.length === pageSize)\n return {\n payments: data?.data ?? null,\n page,\n hasMore: !!hasMore,\n total,\n loading: remote.loading,\n error: remote.error,\n next: useCallback(() => setPage((p) => p + 1), []),\n previous: useCallback(() => setPage((p) => Math.max(0, p - 1)), []),\n refetch: remote.refetch,\n }\n}\n"],"mappings":"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"}
@@ -1,28 +0,0 @@
1
- # NMI host integration and pending checkout states
2
-
3
- Owner: `/root/astra_neutral_resume`.
4
- Worktree: `/home/fidika/cozy/.worktrees/billing-ui/1055-nmi-checkout-ui-20260923`.
5
- Branch: `feat/1055-nmi-checkout-ui-20260923`.
6
- Base: `05d6e27` from freshly fetched `origin/master`.
7
-
8
- The demo will reuse this package's existing Collect.js hosted fields through a
9
- custom CheckoutSource that invokes its admitted application checkout wrapper.
10
- It will not enable generic billing checkout creation or send raw card data to the
11
- application. Stripe remains available alongside the explicitly selected NMI PSP.
12
- Only public tokenization configuration reaches the browser.
13
-
14
- Bounded library changes:
15
-
16
- - Represent `processing` as nonterminal server truth. Poll the same source for
17
- progress without repeating pay or tokenization, including after reload. Local
18
- quote expiry must not turn an accepted unresolved payment into a failed sale.
19
- - Expose a tokenized-card form composed from the existing Collect.js driver and
20
- billing fields, for a host's separately consented save-card step. Do not model
21
- card setup as a zero-priced purchase or show a payment-success receipt for it.
22
- - Retain exact string money and existing callbacks. Tests belong to this library;
23
- the demo uses build/lint and manual qualification only.
24
-
25
- The existing metadata rename PR15 and customer billing package PR13 remain
26
- separately owned. Publication uses the GitHub release tarball workflow after review
27
- and CI; no source checkout path ships in a host dependency manifest. Real NMI
28
- iframe/tokenization/provider qualification remains a separate browser gate.