@umituz/web-payment 0.0.0-stage → 1.0.1

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 (150) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +349 -2
  3. package/dist/billing-adapter.interface-CDkeeowZ.d.mts +94 -0
  4. package/dist/billing-adapter.interface-m7yE50I0.d.ts +94 -0
  5. package/dist/billing-cycle.enum--hJRYlgP.d.mts +10 -0
  6. package/dist/billing-cycle.enum--hJRYlgP.d.ts +10 -0
  7. package/dist/billing-env-D4YjvA3M.d.mts +8 -0
  8. package/dist/billing-env-D4YjvA3M.d.ts +8 -0
  9. package/dist/checkout-metadata-D7Wp_DAD.d.mts +27 -0
  10. package/dist/checkout-metadata-D7Wp_DAD.d.ts +27 -0
  11. package/dist/chunk-2KV7JFYF.mjs +61 -0
  12. package/dist/chunk-2NH5DOLT.mjs +101 -0
  13. package/dist/chunk-3AXPZOCV.mjs +106 -0
  14. package/dist/chunk-4N3BASZ6.mjs +51 -0
  15. package/dist/chunk-NHKK3ENU.mjs +1128 -0
  16. package/dist/chunk-PIWNUAKW.mjs +30 -0
  17. package/dist/chunk-QFB7AOSQ.mjs +33 -0
  18. package/dist/chunk-RQTMBR74.mjs +30 -0
  19. package/dist/chunk-U45FS4FF.mjs +110 -0
  20. package/dist/chunk-X6R76FZT.mjs +0 -0
  21. package/dist/chunk-XQ2HJTTA.mjs +252 -0
  22. package/dist/core.d.mts +17 -0
  23. package/dist/core.d.ts +17 -0
  24. package/dist/core.js +425 -0
  25. package/dist/core.mjs +66 -0
  26. package/dist/http.d.mts +12 -0
  27. package/dist/http.d.ts +12 -0
  28. package/dist/http.js +115 -0
  29. package/dist/http.mjs +88 -0
  30. package/dist/index.d.mts +17 -0
  31. package/dist/index.d.ts +17 -0
  32. package/dist/index.js +1929 -0
  33. package/dist/index.mjs +153 -0
  34. package/dist/memory.d.mts +14 -0
  35. package/dist/memory.d.ts +14 -0
  36. package/dist/memory.js +130 -0
  37. package/dist/memory.mjs +6 -0
  38. package/dist/portal.d.mts +445 -0
  39. package/dist/portal.d.ts +445 -0
  40. package/dist/portal.js +2927 -0
  41. package/dist/portal.mjs +2737 -0
  42. package/dist/product.mapper-CnY1ISOp.d.ts +97 -0
  43. package/dist/product.mapper-noVl-sel.d.mts +97 -0
  44. package/dist/products.d.mts +64 -0
  45. package/dist/products.d.ts +64 -0
  46. package/dist/products.js +370 -0
  47. package/dist/products.mjs +21 -0
  48. package/dist/react.d.mts +182 -0
  49. package/dist/react.d.ts +182 -0
  50. package/dist/react.js +1874 -0
  51. package/dist/react.mjs +105 -0
  52. package/dist/server.d.mts +177 -0
  53. package/dist/server.d.ts +177 -0
  54. package/dist/server.js +622 -0
  55. package/dist/server.mjs +417 -0
  56. package/dist/visual-tokens-BCLVR85G.d.mts +94 -0
  57. package/dist/visual-tokens-BCLVR85G.d.ts +94 -0
  58. package/package.json +122 -4
  59. package/src/core.ts +81 -0
  60. package/src/domain/entities/cancellation.entity.ts +28 -0
  61. package/src/domain/entities/checkout.entity.ts +21 -0
  62. package/src/domain/entities/index.ts +10 -0
  63. package/src/domain/entities/order.entity.ts +15 -0
  64. package/src/domain/entities/product.entity.ts +16 -0
  65. package/src/domain/entities/subscription.entity.ts +24 -0
  66. package/src/domain/entities/sync.entity.ts +4 -0
  67. package/src/domain/enums/amount-type.enum.ts +10 -0
  68. package/src/domain/enums/billing-cycle.enum.ts +30 -0
  69. package/src/domain/enums/index.ts +5 -0
  70. package/src/domain/enums/payment-provider.enum.ts +14 -0
  71. package/src/domain/enums/subscription-status.enum.ts +32 -0
  72. package/src/domain/index.ts +5 -0
  73. package/src/domain/interfaces/billing-adapter.interface.ts +18 -0
  74. package/src/domain/interfaces/index.ts +1 -0
  75. package/src/domain/mappers/product.mapper.ts +176 -0
  76. package/src/domain/utils/minor-units.ts +20 -0
  77. package/src/domain/utils/percent-discount.ts +17 -0
  78. package/src/http.ts +3 -0
  79. package/src/index.ts +12 -0
  80. package/src/infrastructure/browser/hosted-checkout.ts +26 -0
  81. package/src/infrastructure/config/billing-env.ts +31 -0
  82. package/src/infrastructure/constants/billing.constants.ts +10 -0
  83. package/src/infrastructure/http/http-client.ts +83 -0
  84. package/src/infrastructure/pagination/page-iterator.ts +43 -0
  85. package/src/infrastructure/query/query-builder.ts +26 -0
  86. package/src/infrastructure/services/billing.client.ts +300 -0
  87. package/src/infrastructure/services/create-billing-client.ts +23 -0
  88. package/src/infrastructure/services/http/create-http-adapter.ts +123 -0
  89. package/src/infrastructure/services/memory/create-memory-adapter.ts +126 -0
  90. package/src/infrastructure/services/product.repository.ts +198 -0
  91. package/src/infrastructure/utils/checkout-metadata.ts +55 -0
  92. package/src/infrastructure/utils/date-renderer.ts +53 -0
  93. package/src/infrastructure/utils/money-formatter.ts +39 -0
  94. package/src/infrastructure/utils/normalization.util.ts +22 -0
  95. package/src/infrastructure/utils/pagination-clamp.ts +11 -0
  96. package/src/infrastructure/utils/receipt.util.ts +6 -0
  97. package/src/infrastructure/utils/security.util.ts +23 -0
  98. package/src/infrastructure/utils/type-guards.util.ts +23 -0
  99. package/src/infrastructure/utils/validation.util.ts +10 -0
  100. package/src/infrastructure/webhook/parse-event.ts +135 -0
  101. package/src/infrastructure/webhook/verify-webhook.ts +124 -0
  102. package/src/memory.ts +3 -0
  103. package/src/portal.ts +2 -0
  104. package/src/presentation/components/BillingHistoryList.tsx +172 -0
  105. package/src/presentation/components/BillingProvider.tsx +179 -0
  106. package/src/presentation/components/CancelSubscriptionButton.tsx +155 -0
  107. package/src/presentation/components/CheckoutButton.tsx +76 -0
  108. package/src/presentation/components/CustomerPortalLink.tsx +71 -0
  109. package/src/presentation/components/PricingTable.tsx +225 -0
  110. package/src/presentation/components/SubscriptionStatusBadge.tsx +102 -0
  111. package/src/presentation/context/billing-context.ts +30 -0
  112. package/src/presentation/hooks/useBilling.ts +3 -0
  113. package/src/presentation/hooks/useCancelSubscription.ts +47 -0
  114. package/src/presentation/hooks/useCheckoutButton.ts +49 -0
  115. package/src/presentation/hooks/useProducts.ts +76 -0
  116. package/src/presentation/navigation/navigation.strategy.ts +16 -0
  117. package/src/presentation/portal/TurnkeyBillingPage.tsx +144 -0
  118. package/src/presentation/portal/components/BillingLayout.tsx +163 -0
  119. package/src/presentation/portal/components/BillingPage.tsx +22 -0
  120. package/src/presentation/portal/components/BillingPortal.tsx +248 -0
  121. package/src/presentation/portal/components/InvoiceCard.tsx +275 -0
  122. package/src/presentation/portal/components/OverviewTab.tsx +137 -0
  123. package/src/presentation/portal/components/PaymentMethodsList.tsx +268 -0
  124. package/src/presentation/portal/components/PlanComparison.tsx +405 -0
  125. package/src/presentation/portal/components/PlanTab.tsx +197 -0
  126. package/src/presentation/portal/components/PortalButton.tsx +89 -0
  127. package/src/presentation/portal/components/PortalSpinner.tsx +30 -0
  128. package/src/presentation/portal/components/UsageCard.tsx +158 -0
  129. package/src/presentation/portal/components/index.ts +11 -0
  130. package/src/presentation/portal/constants.ts +44 -0
  131. package/src/presentation/portal/create-portal-client.ts +202 -0
  132. package/src/presentation/portal/hooks/index.ts +3 -0
  133. package/src/presentation/portal/hooks/useBilling.ts +240 -0
  134. package/src/presentation/portal/index.ts +97 -0
  135. package/src/presentation/portal/labels.tsx +218 -0
  136. package/src/presentation/portal/styles.ts +70 -0
  137. package/src/presentation/portal/types.ts +213 -0
  138. package/src/presentation/portal/utils/billing.ts +193 -0
  139. package/src/presentation/portal/utils/index.ts +27 -0
  140. package/src/presentation/portal/utils/plans.ts +71 -0
  141. package/src/presentation/theme/visual-tokens.ts +103 -0
  142. package/src/presentation/utils/cancellation-reason-catalog.ts +18 -0
  143. package/src/presentation/utils/checkout-button-visual.ts +50 -0
  144. package/src/presentation/utils/inline-error-visual.ts +21 -0
  145. package/src/presentation/utils/product-pricing.ts +33 -0
  146. package/src/presentation/utils/status-label.ts +23 -0
  147. package/src/presentation/utils/status-tone.ts +25 -0
  148. package/src/products.ts +20 -0
  149. package/src/react.tsx +63 -0
  150. package/src/server.ts +79 -0
@@ -0,0 +1,27 @@
1
+
2
+ export {
3
+ formatNumber,
4
+ formatPrice,
5
+ calculateDiscount,
6
+ calculateProratedAmount,
7
+ getPlanPrice,
8
+ calculateUsagePercentage,
9
+ isNearLimit,
10
+ getStatusTone,
11
+ getStatusLabel,
12
+ getInvoiceStatusTone,
13
+ getInvoiceStatusLabel,
14
+ formatCardNumber,
15
+ formatExpiry,
16
+ getDaysRemaining,
17
+ isTrialExpiringSoon,
18
+ getNextBillingDate,
19
+ groupInvoicesByStatus,
20
+ calculateInvoiceTotal,
21
+ sortInvoicesByDate,
22
+ formatFeature,
23
+ isPopularPlan,
24
+ getTrialDaysText,
25
+ } from './billing';
26
+
27
+ export { transformProductToPlan, transformProducts } from './plans';
@@ -0,0 +1,71 @@
1
+
2
+ import type { ProductPrice, Product } from '../../../domain/entities';
3
+ import type { PlanTier } from '../types';
4
+ import { CURRENCY, type Currency } from '../constants';
5
+
6
+ const MONTHS_IN_YEAR = 12;
7
+
8
+ const KNOWN_CURRENCIES: ReadonlySet<string> = new Set(Object.values(CURRENCY));
9
+
10
+ const productFeatures = (product: Product): string[] =>
11
+ product.benefits
12
+ .map((benefit) => benefit.description ?? '')
13
+ .filter((description) => description.length > 0);
14
+
15
+ const toCurrency = (raw: string): Currency => {
16
+ const upper = raw.toUpperCase();
17
+ if (KNOWN_CURRENCIES.has(upper)) return upper as Currency;
18
+ throw new Error(`Unsupported currency: ${raw}`);
19
+ };
20
+
21
+ const toMonthlyAmount = (amount: number, interval: string | undefined): number => {
22
+ if (interval === 'monthly') return amount;
23
+ if (interval === 'yearly') return amount / MONTHS_IN_YEAR;
24
+ throw new Error(
25
+ `Cannot convert price to monthly: unsupported interval "${interval ?? 'undefined'}"`,
26
+ );
27
+ };
28
+
29
+ export function transformProductToPlan(product: Product, price: ProductPrice): PlanTier {
30
+ const interval = price.recurringInterval;
31
+ const monthlyAmount = toMonthlyAmount(price.amount ?? 0, interval);
32
+ const yearlyAmount = interval === 'yearly' ? price.amount ?? 0 : (price.amount ?? 0) * MONTHS_IN_YEAR;
33
+
34
+ return {
35
+ id: product.id,
36
+ name: product.name,
37
+ description: product.description ?? '',
38
+ monthlyPrice: Math.round(monthlyAmount),
39
+ yearlyPrice: Math.round(yearlyAmount),
40
+ currency: toCurrency(price.currency),
41
+ features: productFeatures(product),
42
+ };
43
+ }
44
+
45
+ export function transformProducts(products: Product[]): PlanTier[] {
46
+ const tiers: PlanTier[] = [];
47
+ for (const product of products) {
48
+ if (product.isArchived) continue;
49
+ const recurring = product.prices.filter(
50
+ (price) => !price.isArchived && price.recurringInterval !== undefined,
51
+ );
52
+ const monthly = recurring.find((price) => price.recurringInterval === 'monthly');
53
+ const yearly = recurring.find((price) => price.recurringInterval === 'yearly');
54
+ if (monthly && yearly) {
55
+ tiers.push({
56
+ id: product.id,
57
+ name: product.name,
58
+ description: product.description ?? '',
59
+ monthlyPrice: Math.round(monthly.amount ?? 0),
60
+ yearlyPrice: Math.round(yearly.amount ?? 0),
61
+ currency: toCurrency(monthly.currency),
62
+ features: productFeatures(product),
63
+ });
64
+ } else if (monthly) {
65
+ tiers.push(transformProductToPlan(product, monthly));
66
+ } else if (yearly) {
67
+ tiers.push(transformProductToPlan(product, yearly));
68
+ }
69
+ }
70
+ return tiers;
71
+ }
@@ -0,0 +1,103 @@
1
+
2
+ export const VisualTokens = Object.freeze({
3
+ spacing: Object.freeze({
4
+ none: 0,
5
+ xs: 4,
6
+ sm: 6,
7
+ md: 8,
8
+ lg: 12,
9
+ xl: 16,
10
+ xxl: 20,
11
+ section: 24,
12
+ page: 32,
13
+ }),
14
+
15
+ radius: Object.freeze({
16
+ sm: 6,
17
+ md: 8,
18
+ lg: 12,
19
+ pill: 999,
20
+ }),
21
+
22
+ fontSize: Object.freeze({
23
+ caption: 12,
24
+ body: 14,
25
+ title: 18,
26
+ display: 24,
27
+ }),
28
+
29
+ fontWeight: Object.freeze({
30
+ regular: 400,
31
+ medium: 500,
32
+ strong: 600,
33
+ }),
34
+
35
+ lineHeight: Object.freeze({
36
+ tight: 1.25,
37
+ normal: 1.5,
38
+ }),
39
+
40
+ opacity: Object.freeze({
41
+ muted: 0.7,
42
+ disabled: 0.6,
43
+ hover: 0.85,
44
+ }),
45
+
46
+ color: Object.freeze({
47
+ textPrimary: '#111827',
48
+ textMuted: '#6b7280',
49
+ textOnPrimary: '#ffffff',
50
+ textInverse: '#ffffff',
51
+ textError: '#b91c1c',
52
+ textOnError: '#ffffff',
53
+
54
+ surfacePrimary: '#ffffff',
55
+ surfaceMuted: '#f9fafb',
56
+ surfaceSubtle: '#f3f4f6',
57
+ surfaceWarning: '#fef3c7',
58
+ surfaceDanger: '#fee2e2',
59
+ surfaceDangerMuted: '#fef2f2',
60
+
61
+ borderSubtle: '#e5e7eb',
62
+ borderStrong: '#d1d5db',
63
+ borderWarning: '#fecaca',
64
+
65
+ brandPrimary: '#2563eb',
66
+ brandPrimaryHover: '#1d4ed8',
67
+ brandDanger: '#dc2626',
68
+ brandDangerHover: '#b91c1c',
69
+ brandDangerText: '#991b1b',
70
+
71
+ badgeNeutralBg: '#e5e7eb',
72
+ badgeNeutralFg: '#111827',
73
+ badgeActiveBg: '#dcfce7',
74
+ badgeActiveFg: '#166534',
75
+ badgeWarningBg: '#fef3c7',
76
+ badgeWarningFg: '#92400e',
77
+ badgeDangerBg: '#fee2e2',
78
+ badgeDangerFg: '#991b1b',
79
+ }),
80
+
81
+ transition: Object.freeze({
82
+ instant: '120ms ease',
83
+ }),
84
+
85
+ layout: Object.freeze({
86
+ cardMinWidth: 260,
87
+ benefitListMax: 5,
88
+ }),
89
+ } as const);
90
+
91
+ export type VisualTone = 'neutral' | 'active' | 'warning' | 'danger';
92
+
93
+ export interface VisualTonePair {
94
+ readonly bg: string;
95
+ readonly fg: string;
96
+ }
97
+
98
+ export const TONE_PAIRS: Readonly<Record<VisualTone, VisualTonePair>> = Object.freeze({
99
+ neutral: { bg: VisualTokens.color.badgeNeutralBg, fg: VisualTokens.color.badgeNeutralFg },
100
+ active: { bg: VisualTokens.color.badgeActiveBg, fg: VisualTokens.color.badgeActiveFg },
101
+ warning: { bg: VisualTokens.color.badgeWarningBg, fg: VisualTokens.color.badgeWarningFg },
102
+ danger: { bg: VisualTokens.color.badgeDangerBg, fg: VisualTokens.color.badgeDangerFg },
103
+ });
@@ -0,0 +1,18 @@
1
+
2
+ import type { CancellationReason } from '../../domain/entities/cancellation.entity';
3
+
4
+ export interface CancellationReasonOption {
5
+ readonly value: CancellationReason;
6
+ readonly label: string;
7
+ }
8
+
9
+ export const CANCELLATION_REASON_CATALOG: ReadonlyArray<CancellationReasonOption> = Object.freeze([
10
+ { value: 'too_expensive', label: 'Too expensive' },
11
+ { value: 'missing_features', label: 'Missing features' },
12
+ { value: 'switched_service', label: 'Switched to a different service' },
13
+ { value: 'unused', label: 'Not using it' },
14
+ { value: 'customer_service', label: 'Poor customer service' },
15
+ { value: 'low_quality', label: 'Quality is too low' },
16
+ { value: 'too_complex', label: 'Too complex' },
17
+ { value: 'other', label: 'Other' },
18
+ ]);
@@ -0,0 +1,50 @@
1
+
2
+ import { VisualTokens } from '../theme/visual-tokens';
3
+ import type { CheckoutButtonVariant } from '../components/CheckoutButton';
4
+
5
+ export interface CheckoutButtonVisualInput {
6
+ variant: CheckoutButtonVariant;
7
+ disabled: boolean;
8
+ loading: boolean;
9
+ }
10
+
11
+ interface ButtonColorScheme {
12
+ backgroundColor: string;
13
+ color: string;
14
+ border: string;
15
+ }
16
+
17
+ const VARIANT_COLOR_SCHEMES: Readonly<Record<CheckoutButtonVariant, ButtonColorScheme>> = Object.freeze({
18
+ primary: Object.freeze({
19
+ backgroundColor: VisualTokens.color.brandPrimary,
20
+ color: VisualTokens.color.textOnPrimary,
21
+ border: `1px solid ${VisualTokens.color.brandPrimary}`,
22
+ }),
23
+ secondary: Object.freeze({
24
+ backgroundColor: VisualTokens.color.surfacePrimary,
25
+ color: VisualTokens.color.textPrimary,
26
+ border: `1px solid ${VisualTokens.color.borderStrong}`,
27
+ }),
28
+ danger: Object.freeze({
29
+ backgroundColor: VisualTokens.color.brandDanger,
30
+ color: VisualTokens.color.textOnPrimary,
31
+ border: `1px solid ${VisualTokens.color.brandDanger}`,
32
+ }),
33
+ });
34
+
35
+ export class CheckoutButtonVisual {
36
+ static resolve({ variant, disabled, loading }: CheckoutButtonVisualInput): React.CSSProperties {
37
+ const scheme = VARIANT_COLOR_SCHEMES[variant];
38
+ const isInactive = disabled || loading;
39
+ return {
40
+ ...scheme,
41
+ padding: `${VisualTokens.spacing.lg}px ${VisualTokens.spacing.xl}px`,
42
+ fontSize: VisualTokens.fontSize.body,
43
+ fontWeight: VisualTokens.fontWeight.strong,
44
+ borderRadius: VisualTokens.radius.md,
45
+ cursor: isInactive ? 'not-allowed' : 'pointer',
46
+ opacity: isInactive ? VisualTokens.opacity.disabled : 1,
47
+ transition: VisualTokens.transition.instant,
48
+ };
49
+ }
50
+ }
@@ -0,0 +1,21 @@
1
+
2
+ import { createElement, type CSSProperties, type ReactNode } from 'react';
3
+ import { VisualTokens } from '../theme/visual-tokens';
4
+
5
+ export class InlineErrorVisual {
6
+ static style(): CSSProperties {
7
+ return {
8
+ color: VisualTokens.color.textError,
9
+ fontSize: VisualTokens.fontSize.caption,
10
+ };
11
+ }
12
+
13
+ static element(message: string | null | undefined): ReactNode {
14
+ if (!message) return null;
15
+ return createElement(
16
+ 'span',
17
+ { role: 'alert', style: InlineErrorVisual.style() },
18
+ message,
19
+ );
20
+ }
21
+ }
@@ -0,0 +1,33 @@
1
+
2
+ import type { BillingCycle, Product, ProductPrice } from '../../domain/entities';
3
+
4
+ export const FALLBACK_PRICE_LABEL = 'Custom';
5
+
6
+ export class ProductPricing {
7
+ static recurringPrice(product: Product, cycle?: BillingCycle): ProductPrice | null {
8
+ const recurring = product.prices.filter(
9
+ (p) => p.recurringInterval !== undefined,
10
+ );
11
+ if (recurring.length === 0) {
12
+ return product.prices[0] ?? null;
13
+ }
14
+ if (cycle) {
15
+ const match = recurring.find((p) => p.recurringInterval === cycle);
16
+ if (match) return match;
17
+ }
18
+ return recurring[0] ?? null;
19
+ }
20
+
21
+ static displayLine(
22
+ product: Product,
23
+ formatter: (amount: number | undefined, currency: string | undefined) => string,
24
+ cycle?: BillingCycle,
25
+ ): { amount: string; interval: string | null } {
26
+ const price = ProductPricing.recurringPrice(product, cycle);
27
+ if (!price) {
28
+ return { amount: FALLBACK_PRICE_LABEL, interval: null };
29
+ }
30
+ const amount = formatter(price.amount, price.currency);
31
+ return { amount, interval: price.recurringInterval ?? null };
32
+ }
33
+ }
@@ -0,0 +1,23 @@
1
+
2
+ import type { SubscriptionStatusValue } from '../../domain/enums/subscription-status.enum';
3
+
4
+ export class StatusLabel {
5
+ private static readonly MAP: Readonly<Record<SubscriptionStatusValue, string>> = Object.freeze({
6
+ active: 'Active',
7
+ trialing: 'Trial',
8
+ past_due: 'Past due',
9
+ incomplete: 'Incomplete',
10
+ canceled: 'Canceled',
11
+ revoked: 'Revoked',
12
+ unpaid: 'Unpaid',
13
+ incomplete_expired: 'Expired',
14
+ none: 'Free',
15
+ });
16
+
17
+ static forStatus(
18
+ status: SubscriptionStatusValue,
19
+ overrides?: Partial<Record<SubscriptionStatusValue, string>>,
20
+ ): string {
21
+ return overrides?.[status] ?? StatusLabel.MAP[status] ?? 'Free';
22
+ }
23
+ }
@@ -0,0 +1,25 @@
1
+
2
+ import { TONE_PAIRS, type VisualTone, type VisualTonePair } from '../theme/visual-tokens';
3
+ import type { SubscriptionStatusValue } from '../../domain/enums/subscription-status.enum';
4
+
5
+ export class StatusTone {
6
+ private static readonly MAP: Readonly<Record<SubscriptionStatusValue, VisualTone>> = Object.freeze({
7
+ active: 'active',
8
+ trialing: 'active',
9
+ past_due: 'warning',
10
+ incomplete: 'warning',
11
+ canceled: 'danger',
12
+ revoked: 'danger',
13
+ unpaid: 'danger',
14
+ incomplete_expired: 'danger',
15
+ none: 'neutral',
16
+ });
17
+
18
+ static forStatus(status: SubscriptionStatusValue): VisualTone {
19
+ return StatusTone.MAP[status] ?? 'neutral';
20
+ }
21
+
22
+ static pairFor(status: SubscriptionStatusValue): VisualTonePair {
23
+ return TONE_PAIRS[StatusTone.forStatus(status)];
24
+ }
25
+ }
@@ -0,0 +1,20 @@
1
+
2
+ export {
3
+ ProductRepository,
4
+ BillingApiError,
5
+ isBillingApiError,
6
+ getProducts,
7
+ getProductById,
8
+ getAllProducts,
9
+ } from './infrastructure/services/product.repository';
10
+ export type {
11
+ ProductApiConfig,
12
+ ProductRequestOptions,
13
+ } from './infrastructure/services/product.repository';
14
+
15
+ export { FetchHttpClient } from './infrastructure/http/http-client';
16
+ export type {
17
+ HttpClient,
18
+ HttpRequest,
19
+ HttpResponse,
20
+ } from './infrastructure/http/http-client';
package/src/react.tsx ADDED
@@ -0,0 +1,63 @@
1
+
2
+ export * from './core';
3
+
4
+ export { BillingProvider } from './presentation/components/BillingProvider';
5
+ export type { BillingProviderProps } from './presentation/components/BillingProvider';
6
+ export { CheckoutButton } from './presentation/components/CheckoutButton';
7
+ export type {
8
+ CheckoutButtonProps,
9
+ CheckoutButtonVariant,
10
+ CheckoutButtonLabels,
11
+ } from './presentation/components/CheckoutButton';
12
+ export { SubscriptionStatusBadge } from './presentation/components/SubscriptionStatusBadge';
13
+ export type {
14
+ SubscriptionStatusBadgeProps,
15
+ SubscriptionStatusBadgeLabels,
16
+ } from './presentation/components/SubscriptionStatusBadge';
17
+ export { PricingTable } from './presentation/components/PricingTable';
18
+ export type { PricingTableProps, PricingTableLabels } from './presentation/components/PricingTable';
19
+ export { BillingHistoryList } from './presentation/components/BillingHistoryList';
20
+ export type {
21
+ BillingHistoryListProps,
22
+ BillingHistoryListLabels,
23
+ } from './presentation/components/BillingHistoryList';
24
+ export { CustomerPortalLink } from './presentation/components/CustomerPortalLink';
25
+ export type {
26
+ CustomerPortalLinkProps,
27
+ CustomerPortalLinkLabels,
28
+ } from './presentation/components/CustomerPortalLink';
29
+ export { CancelSubscriptionButton } from './presentation/components/CancelSubscriptionButton';
30
+ export type {
31
+ CancelSubscriptionButtonProps,
32
+ CancelSubscriptionButtonLabels,
33
+ } from './presentation/components/CancelSubscriptionButton';
34
+
35
+ export { BillingContext, useBilling } from './presentation/context/billing-context';
36
+ export type { BillingContextValue } from './presentation/context/billing-context';
37
+ export { useCheckoutButton } from './presentation/hooks/useCheckoutButton';
38
+ export type {
39
+ UseCheckoutButtonOptions,
40
+ UseCheckoutButtonResult,
41
+ } from './presentation/hooks/useCheckoutButton';
42
+ export { useCancelSubscription } from './presentation/hooks/useCancelSubscription';
43
+ export type {
44
+ UseCancelSubscriptionOptions,
45
+ UseCancelSubscriptionResult,
46
+ } from './presentation/hooks/useCancelSubscription';
47
+ export { useProducts } from './presentation/hooks/useProducts';
48
+ export type {
49
+ UseProductsOptions,
50
+ UseProductsResult,
51
+ } from './presentation/hooks/useProducts';
52
+
53
+ export {
54
+ WindowNavigationStrategy,
55
+ NoopNavigationStrategy,
56
+ } from './presentation/navigation/navigation.strategy';
57
+ export type { NavigationStrategy } from './presentation/navigation/navigation.strategy';
58
+
59
+ export { VisualTokens, TONE_PAIRS } from './presentation/theme/visual-tokens';
60
+ export type { VisualTone, VisualTonePair } from './presentation/theme/visual-tokens';
61
+
62
+ export { CANCELLATION_REASON_CATALOG } from './presentation/utils/cancellation-reason-catalog';
63
+ export type { CancellationReasonOption } from './presentation/utils/cancellation-reason-catalog';
package/src/server.ts ADDED
@@ -0,0 +1,79 @@
1
+ export {
2
+ BillingClient,
3
+ PolarBillingClient,
4
+ createPaymentClient,
5
+ SANDBOX_API_BASE_URL,
6
+ } from './infrastructure/services/billing.client';
7
+ export type {
8
+ BillingClientConfig,
9
+ PaymentClientConfig,
10
+ PaymentServerClient,
11
+ CheckoutSessionParams,
12
+ CheckoutSession,
13
+ CheckoutMetadata,
14
+ CreateProductParams,
15
+ CreatedProduct,
16
+ SubscriptionRecord,
17
+ PortalSession,
18
+ } from './infrastructure/services/billing.client';
19
+
20
+ export {
21
+ PAYMENT_PROVIDER,
22
+ PAYMENT_PROVIDER_VALUES,
23
+ isKnownPaymentProvider,
24
+ } from './domain/enums/payment-provider.enum';
25
+ export type { PaymentProvider } from './domain/enums/payment-provider.enum';
26
+
27
+ export {
28
+ DEFAULT_WEBHOOK_TOLERANCE_MS,
29
+ verifyWebhook,
30
+ verifyPolarWebhook,
31
+ } from './infrastructure/webhook/verify-webhook';
32
+ export type {
33
+ WebhookHeadersLike,
34
+ VerifyWebhookOptions,
35
+ } from './infrastructure/webhook/verify-webhook';
36
+
37
+ export {
38
+ parseWebhookEvent,
39
+ parsePolarWebhookEvent,
40
+ asCheckoutCompleted,
41
+ asSubscriptionChanged,
42
+ asOrderPaid,
43
+ } from './infrastructure/webhook/parse-event';
44
+ export type {
45
+ WebhookEvent,
46
+ CheckoutCompleted,
47
+ SubscriptionChanged,
48
+ OrderPaid,
49
+ } from './infrastructure/webhook/parse-event';
50
+
51
+ export { BillingApiError, isBillingApiError } from './infrastructure/services/product.repository';
52
+ export { API_BASE_URL } from './infrastructure/constants/billing.constants';
53
+
54
+ export {
55
+ CHECKOUT_ID_PARAM,
56
+ CHECKOUT_ID_PLACEHOLDER,
57
+ parseProductIds,
58
+ productIdOf,
59
+ successUrlWithCheckoutId,
60
+ } from './infrastructure/config/billing-env';
61
+ export type { ProductIdMap } from './infrastructure/config/billing-env';
62
+
63
+ export {
64
+ createBillingClient,
65
+ createPolarClient,
66
+ sandboxEnabled,
67
+ } from './infrastructure/services/create-billing-client';
68
+
69
+ export {
70
+ buildCheckoutMetadata,
71
+ readCheckoutMetadata,
72
+ } from './infrastructure/utils/checkout-metadata';
73
+ export type {
74
+ BuildCheckoutMetadataInput,
75
+ CheckoutOrderMetadata,
76
+ } from './infrastructure/utils/checkout-metadata';
77
+
78
+ export { formatReceiptNumber } from './infrastructure/utils/receipt.util';
79
+