@umituz/web-payment 0.0.0-stage → 1.0.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 (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,30 @@
1
+ // src/domain/utils/minor-units.ts
2
+ var MINOR_UNIT_DIVISOR = 100;
3
+ var ZERO_DECIMAL_CURRENCIES = /* @__PURE__ */ new Set([
4
+ "JPY",
5
+ "KRW",
6
+ "VND",
7
+ "CLP",
8
+ "PYG",
9
+ "XAF",
10
+ "XOF",
11
+ "BIF",
12
+ "DJF",
13
+ "GNF",
14
+ "XPF"
15
+ ]);
16
+ function minorUnitDivisor(currency) {
17
+ return ZERO_DECIMAL_CURRENCIES.has(currency.toUpperCase()) ? 1 : MINOR_UNIT_DIVISOR;
18
+ }
19
+ function toMajorUnits(amount, currency) {
20
+ return amount / minorUnitDivisor(currency);
21
+ }
22
+ function toMinorUnits(amount, currency) {
23
+ return Math.round(amount * minorUnitDivisor(currency));
24
+ }
25
+
26
+ export {
27
+ minorUnitDivisor,
28
+ toMajorUnits,
29
+ toMinorUnits
30
+ };
@@ -0,0 +1,33 @@
1
+ // src/infrastructure/config/billing-env.ts
2
+ var CHECKOUT_ID_PARAM = "checkout_id";
3
+ var CHECKOUT_ID_PLACEHOLDER = "{CHECKOUT_ID}";
4
+ function parseProductIds(raw) {
5
+ const map = /* @__PURE__ */ new Map();
6
+ if (typeof raw !== "string" || raw.length === 0) return map;
7
+ let parsed;
8
+ try {
9
+ parsed = JSON.parse(raw);
10
+ } catch {
11
+ return map;
12
+ }
13
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return map;
14
+ for (const [key, value] of Object.entries(parsed)) {
15
+ if (typeof value === "string" && value.length > 0) map.set(key, value);
16
+ }
17
+ return map;
18
+ }
19
+ function productIdOf(ids, productKey) {
20
+ return ids.get(productKey) ?? null;
21
+ }
22
+ function successUrlWithCheckoutId(origin, returnPath) {
23
+ const separator = returnPath.includes("?") ? "&" : "?";
24
+ return `${origin}${returnPath}${separator}${CHECKOUT_ID_PARAM}=${CHECKOUT_ID_PLACEHOLDER}`;
25
+ }
26
+
27
+ export {
28
+ CHECKOUT_ID_PARAM,
29
+ CHECKOUT_ID_PLACEHOLDER,
30
+ parseProductIds,
31
+ productIdOf,
32
+ successUrlWithCheckoutId
33
+ };
@@ -0,0 +1,30 @@
1
+ // src/domain/enums/billing-cycle.enum.ts
2
+ var BILLING_CYCLE = Object.freeze({
3
+ MONTHLY: "monthly",
4
+ YEARLY: "yearly"
5
+ });
6
+ var BILLING_CYCLE_VALUES = Object.freeze([
7
+ BILLING_CYCLE.MONTHLY,
8
+ BILLING_CYCLE.YEARLY
9
+ ]);
10
+ var CANONICAL_BILLING_CYCLES = new Set(BILLING_CYCLE_VALUES);
11
+ var BILLING_CYCLE_ALIASES = /* @__PURE__ */ new Map([
12
+ [BILLING_CYCLE.MONTHLY, BILLING_CYCLE.MONTHLY],
13
+ ["month", BILLING_CYCLE.MONTHLY],
14
+ [BILLING_CYCLE.YEARLY, BILLING_CYCLE.YEARLY],
15
+ ["year", BILLING_CYCLE.YEARLY]
16
+ ]);
17
+ function isKnownBillingCycle(value) {
18
+ return typeof value === "string" && CANONICAL_BILLING_CYCLES.has(value.toLowerCase());
19
+ }
20
+ function parseBillingCycle(value) {
21
+ if (typeof value !== "string") return null;
22
+ return BILLING_CYCLE_ALIASES.get(value.toLowerCase()) ?? null;
23
+ }
24
+
25
+ export {
26
+ BILLING_CYCLE,
27
+ BILLING_CYCLE_VALUES,
28
+ isKnownBillingCycle,
29
+ parseBillingCycle
30
+ };
@@ -0,0 +1,110 @@
1
+ import {
2
+ parseBillingCycle
3
+ } from "./chunk-RQTMBR74.mjs";
4
+
5
+ // src/domain/enums/subscription-status.enum.ts
6
+ var SUBSCRIPTION_STATUS = {
7
+ ACTIVE: "active",
8
+ CANCELED: "canceled",
9
+ REVOKED: "revoked",
10
+ TRIALING: "trialing",
11
+ PAST_DUE: "past_due",
12
+ INCOMPLETE: "incomplete",
13
+ INCOMPLETE_EXPIRED: "incomplete_expired",
14
+ UNPAID: "unpaid",
15
+ NONE: "none"
16
+ };
17
+ var SUBSCRIPTION_STATUS_VALUES = Object.freeze([
18
+ SUBSCRIPTION_STATUS.ACTIVE,
19
+ SUBSCRIPTION_STATUS.CANCELED,
20
+ SUBSCRIPTION_STATUS.REVOKED,
21
+ SUBSCRIPTION_STATUS.TRIALING,
22
+ SUBSCRIPTION_STATUS.PAST_DUE,
23
+ SUBSCRIPTION_STATUS.INCOMPLETE,
24
+ SUBSCRIPTION_STATUS.INCOMPLETE_EXPIRED,
25
+ SUBSCRIPTION_STATUS.UNPAID,
26
+ SUBSCRIPTION_STATUS.NONE
27
+ ]);
28
+ var SUBSCRIPTION_STATUS_SET = new Set(SUBSCRIPTION_STATUS_VALUES);
29
+ function isKnownSubscriptionStatus(value) {
30
+ return typeof value === "string" && SUBSCRIPTION_STATUS_SET.has(value.toLowerCase());
31
+ }
32
+
33
+ // src/domain/mappers/product.mapper.ts
34
+ var KNOWN_AMOUNT_TYPES = /* @__PURE__ */ new Set([
35
+ "fixed",
36
+ "custom",
37
+ "free",
38
+ "seat_based",
39
+ "metered_unit"
40
+ ]);
41
+ function toAmountType(raw) {
42
+ if (raw && KNOWN_AMOUNT_TYPES.has(raw)) return raw;
43
+ return "fixed";
44
+ }
45
+ function toBillingCycle(interval) {
46
+ return parseBillingCycle(interval);
47
+ }
48
+ function asRecord(value) {
49
+ return value && typeof value === "object" ? value : {};
50
+ }
51
+ function toPrice(dto) {
52
+ return {
53
+ id: String(dto.id),
54
+ type: toAmountType(dto.type),
55
+ amountType: toAmountType(dto.amount_type),
56
+ amount: typeof dto.amount === "number" ? dto.amount : void 0,
57
+ currency: String(dto.currency),
58
+ recurringInterval: toBillingCycle(dto.recurring_interval) ?? void 0,
59
+ isArchived: Boolean(dto.is_archived),
60
+ productId: String(dto.product_id),
61
+ legacy: Boolean(dto.legacy)
62
+ };
63
+ }
64
+ function toBenefit(dto) {
65
+ return {
66
+ id: String(dto.id),
67
+ type: String(dto.type),
68
+ description: dto.description ?? null,
69
+ properties: asRecord(dto.properties)
70
+ };
71
+ }
72
+ function mapProduct(dto) {
73
+ if (!dto || typeof dto !== "object") {
74
+ throw new TypeError("mapProduct: expected a product DTO object");
75
+ }
76
+ return {
77
+ id: String(dto.id),
78
+ name: String(dto.name),
79
+ description: dto.description ?? null,
80
+ isRecurring: Boolean(dto.is_recurring),
81
+ recurringInterval: toBillingCycle(dto.recurring_interval),
82
+ isArchived: Boolean(dto.is_archived),
83
+ organizationId: String(dto.organization_id),
84
+ prices: Array.isArray(dto.prices) ? dto.prices.map(toPrice) : [],
85
+ benefits: Array.isArray(dto.benefits) ? dto.benefits.map(toBenefit) : [],
86
+ metadata: asRecord(dto.metadata),
87
+ createdAt: String(dto.created_at),
88
+ modifiedAt: dto.modified_at ?? null
89
+ };
90
+ }
91
+ function mapProductList(dto) {
92
+ if (!dto || typeof dto !== "object") {
93
+ return { items: [], pagination: { totalCount: 0, maxPage: 1 } };
94
+ }
95
+ return {
96
+ items: Array.isArray(dto.items) ? dto.items.map(mapProduct) : [],
97
+ pagination: {
98
+ totalCount: Number(dto.pagination?.total_count ?? 0),
99
+ maxPage: Number(dto.pagination?.max_page ?? 1)
100
+ }
101
+ };
102
+ }
103
+
104
+ export {
105
+ SUBSCRIPTION_STATUS,
106
+ SUBSCRIPTION_STATUS_VALUES,
107
+ isKnownSubscriptionStatus,
108
+ mapProduct,
109
+ mapProductList
110
+ };
File without changes
@@ -0,0 +1,252 @@
1
+ import {
2
+ mapProduct,
3
+ mapProductList
4
+ } from "./chunk-U45FS4FF.mjs";
5
+
6
+ // src/infrastructure/constants/billing.constants.ts
7
+ var API_BASE_URL = "https://api.polar.sh/v1";
8
+ var API_MAX_PAGE_SIZE = 100;
9
+
10
+ // src/infrastructure/http/http-client.ts
11
+ var DEFAULT_TIMEOUT_MS = 15e3;
12
+ var FetchHttpClient = class {
13
+ async request(request) {
14
+ const init = {
15
+ method: request.method,
16
+ headers: {
17
+ Accept: "application/json",
18
+ ...request.headers ?? {}
19
+ }
20
+ };
21
+ if (request.body !== void 0) {
22
+ init.body = JSON.stringify(request.body);
23
+ init.headers["Content-Type"] = "application/json";
24
+ }
25
+ const timeoutMs = request.timeoutMs ?? DEFAULT_TIMEOUT_MS;
26
+ const controller = new AbortController();
27
+ let timedOut = false;
28
+ const timer = setTimeout(() => {
29
+ timedOut = true;
30
+ controller.abort();
31
+ }, timeoutMs);
32
+ const forwardAbort = () => controller.abort();
33
+ if (request.signal) {
34
+ if (request.signal.aborted) controller.abort();
35
+ else request.signal.addEventListener("abort", forwardAbort);
36
+ }
37
+ init.signal = controller.signal;
38
+ let response;
39
+ try {
40
+ response = await fetch(request.url, init);
41
+ } catch (error) {
42
+ if (timedOut && error instanceof Error && error.name === "AbortError") {
43
+ throw new DOMException(`Request timed out after ${timeoutMs}ms`, "TimeoutError");
44
+ }
45
+ throw error;
46
+ } finally {
47
+ clearTimeout(timer);
48
+ request.signal?.removeEventListener("abort", forwardAbort);
49
+ }
50
+ const bodyText = await response.text();
51
+ let data = null;
52
+ if (bodyText.length > 0) {
53
+ try {
54
+ data = JSON.parse(bodyText);
55
+ } catch {
56
+ data = null;
57
+ }
58
+ }
59
+ return {
60
+ status: response.status,
61
+ ok: response.ok,
62
+ data,
63
+ text: async () => bodyText
64
+ };
65
+ }
66
+ };
67
+
68
+ // src/infrastructure/query/query-builder.ts
69
+ var QueryBuilder = class {
70
+ params;
71
+ constructor(initial) {
72
+ this.params = new URLSearchParams();
73
+ if (initial) this.setMany(initial);
74
+ }
75
+ set(key, value) {
76
+ if (value === void 0 || value === null) return this;
77
+ this.params.set(key, String(value));
78
+ return this;
79
+ }
80
+ setMany(values) {
81
+ for (const [key, value] of Object.entries(values)) {
82
+ this.set(key, value);
83
+ }
84
+ return this;
85
+ }
86
+ toString() {
87
+ return this.params.toString();
88
+ }
89
+ };
90
+
91
+ // src/infrastructure/pagination/page-iterator.ts
92
+ var PageIterator = class {
93
+ fetcher;
94
+ limit;
95
+ signal;
96
+ constructor(fetcher, options = {}) {
97
+ this.fetcher = fetcher;
98
+ this.limit = options.limit ?? 100;
99
+ this.signal = options.signal;
100
+ }
101
+ async *[Symbol.asyncIterator]() {
102
+ let page = 1;
103
+ while (true) {
104
+ if (this.signal?.aborted) return;
105
+ const current = await this.fetcher.fetchPage(page, this.limit);
106
+ for (const item of current.items) {
107
+ if (this.signal?.aborted) return;
108
+ yield item;
109
+ }
110
+ if (current.isLast || page >= current.maxPage) return;
111
+ page++;
112
+ }
113
+ }
114
+ };
115
+
116
+ // src/infrastructure/utils/pagination-clamp.ts
117
+ var MIN_PAGE_SIZE = 1;
118
+ var PaginationClamp = class {
119
+ static pageSize(raw, max = API_MAX_PAGE_SIZE) {
120
+ if (raw === void 0) return max;
121
+ return Math.min(Math.max(MIN_PAGE_SIZE, raw), max);
122
+ }
123
+ };
124
+
125
+ // src/infrastructure/services/product.repository.ts
126
+ var BillingApiError = class _BillingApiError extends Error {
127
+ constructor(message, status, body) {
128
+ super(message);
129
+ this.status = status;
130
+ this.body = body;
131
+ this.name = "BillingApiError";
132
+ Object.setPrototypeOf(this, _BillingApiError.prototype);
133
+ }
134
+ };
135
+ function isBillingApiError(error) {
136
+ return error instanceof BillingApiError;
137
+ }
138
+ var ProductRepository = class {
139
+ http;
140
+ apiToken;
141
+ baseUrl;
142
+ constructor(config, http = new FetchHttpClient()) {
143
+ this.http = http;
144
+ this.apiToken = config.apiToken;
145
+ this.baseUrl = config.baseUrl ?? API_BASE_URL;
146
+ }
147
+ async list(params, options) {
148
+ const query = new QueryBuilder({
149
+ organization_id: params?.organizationId,
150
+ is_recurring: params?.isRecurring,
151
+ page: params?.page,
152
+ limit: this.clampLimit(params?.limit)
153
+ });
154
+ const url = `${this.baseUrl}/products?${query.toString()}`;
155
+ const response = await this.http.request({
156
+ method: "GET",
157
+ url,
158
+ headers: this.authHeaders(),
159
+ signal: options?.signal,
160
+ timeoutMs: options?.timeoutMs
161
+ });
162
+ if (!response.ok) {
163
+ const body = await response.text();
164
+ throw new BillingApiError(
165
+ `Billing API error: ${response.status}`,
166
+ response.status,
167
+ body
168
+ );
169
+ }
170
+ return mapProductList(response.data);
171
+ }
172
+ async findById(productId, options) {
173
+ const url = `${this.baseUrl}/products/${encodeURIComponent(productId)}`;
174
+ const response = await this.http.request({
175
+ method: "GET",
176
+ url,
177
+ headers: this.authHeaders(),
178
+ signal: options?.signal,
179
+ timeoutMs: options?.timeoutMs
180
+ });
181
+ if (response.status === 404) return null;
182
+ if (!response.ok) {
183
+ const body = await response.text();
184
+ throw new BillingApiError(
185
+ `Billing API error: ${response.status}`,
186
+ response.status,
187
+ body
188
+ );
189
+ }
190
+ if (!response.data) {
191
+ throw new BillingApiError(
192
+ "Billing API returned an empty product body",
193
+ response.status
194
+ );
195
+ }
196
+ return mapProduct(response.data);
197
+ }
198
+ iterateAll(params, options = {}) {
199
+ const limit = this.clampLimit(options.limit);
200
+ const fetcher = {
201
+ fetchPage: async (page, pageLimit) => {
202
+ const response = await this.list(
203
+ { ...params, page, limit: pageLimit },
204
+ { signal: options.signal }
205
+ );
206
+ const pageData = {
207
+ items: response.items,
208
+ page,
209
+ totalCount: response.pagination.totalCount,
210
+ maxPage: response.pagination.maxPage,
211
+ isLast: page >= response.pagination.maxPage
212
+ };
213
+ return pageData;
214
+ }
215
+ };
216
+ return new PageIterator(fetcher, { limit, signal: options.signal });
217
+ }
218
+ async listAll(params, options = {}) {
219
+ const out = [];
220
+ for await (const product of this.iterateAll(params, options)) {
221
+ out.push(product);
222
+ }
223
+ return out;
224
+ }
225
+ authHeaders() {
226
+ return { Authorization: `Bearer ${this.apiToken}` };
227
+ }
228
+ clampLimit(limit) {
229
+ return PaginationClamp.pageSize(limit, API_MAX_PAGE_SIZE);
230
+ }
231
+ };
232
+ var defaultClient = new FetchHttpClient();
233
+ async function getProducts(config, params, options) {
234
+ return new ProductRepository(config, defaultClient).list(params, options);
235
+ }
236
+ async function getProductById(config, productId, options) {
237
+ return new ProductRepository(config, defaultClient).findById(productId, options);
238
+ }
239
+ async function getAllProducts(config, params, options = {}) {
240
+ return new ProductRepository(config, defaultClient).listAll(params, options);
241
+ }
242
+
243
+ export {
244
+ API_BASE_URL,
245
+ FetchHttpClient,
246
+ BillingApiError,
247
+ isBillingApiError,
248
+ ProductRepository,
249
+ getProducts,
250
+ getProductById,
251
+ getAllProducts
252
+ };
@@ -0,0 +1,17 @@
1
+ export { B as BuildCheckoutMetadataInput, C as CheckoutOrderMetadata, P as PAYMENT_PROVIDER, a as PAYMENT_PROVIDER_VALUES, b as PaymentProvider, c as buildCheckoutMetadata, f as formatReceiptNumber, i as isKnownPaymentProvider, r as readCheckoutMetadata } from './checkout-metadata-D7Wp_DAD.mjs';
2
+ export { B as BillingAdapter, C as CANCELLATION_REASON, a as CANCELLATION_REASON_VALUES, b as CancelResult, c as CancellationReason, d as CheckoutParams, e as CheckoutResult, F as FREE_SUBSCRIPTION_STATUS, O as OrderItem, S as SUBSCRIPTION_STATUS, f as SUBSCRIPTION_STATUS_VALUES, g as SubscriptionStatus, h as SubscriptionStatusValue, i as SyncResult, j as isActiveSubscription, k as isKnownSubscriptionStatus } from './billing-adapter.interface-CDkeeowZ.mjs';
3
+ export { B as BILLING_CYCLE, a as BILLING_CYCLE_VALUES, b as BillingCycle, i as isKnownBillingCycle, p as parseBillingCycle } from './billing-cycle.enum--hJRYlgP.mjs';
4
+ export { A as AmountType, P as POLAR_AMOUNT_TYPE, a as Product, b as ProductBenefit, c as ProductBenefitDto, d as ProductDto, e as ProductListParams, f as ProductListResponse, g as ProductListResponseDto, h as ProductPrice, i as ProductPriceDto, m as mapProduct, j as mapProductList } from './product.mapper-noVl-sel.mjs';
5
+ export { MemoryAdapterConfig, createMemoryBillingAdapter } from './memory.mjs';
6
+
7
+ type RecurringInterval = 'day' | 'week' | 'month' | 'year';
8
+ type PriceType = 'fixed' | 'custom' | 'free' | 'seat_based' | 'metered_unit';
9
+
10
+ declare function minorUnitDivisor(currency: string): number;
11
+ declare function toMajorUnits(amount: number, currency: string): number;
12
+ declare function toMinorUnits(amount: number, currency: string): number;
13
+
14
+ declare function normalizeCouponCode(code: unknown): string | null;
15
+ declare function applyPercentDiscount(baseAmount: number, percent: number, minimumAmount: number): number;
16
+
17
+ export { type PriceType, type RecurringInterval, applyPercentDiscount, minorUnitDivisor, normalizeCouponCode, toMajorUnits, toMinorUnits };
package/dist/core.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ export { B as BuildCheckoutMetadataInput, C as CheckoutOrderMetadata, P as PAYMENT_PROVIDER, a as PAYMENT_PROVIDER_VALUES, b as PaymentProvider, c as buildCheckoutMetadata, f as formatReceiptNumber, i as isKnownPaymentProvider, r as readCheckoutMetadata } from './checkout-metadata-D7Wp_DAD.js';
2
+ export { B as BillingAdapter, C as CANCELLATION_REASON, a as CANCELLATION_REASON_VALUES, b as CancelResult, c as CancellationReason, d as CheckoutParams, e as CheckoutResult, F as FREE_SUBSCRIPTION_STATUS, O as OrderItem, S as SUBSCRIPTION_STATUS, f as SUBSCRIPTION_STATUS_VALUES, g as SubscriptionStatus, h as SubscriptionStatusValue, i as SyncResult, j as isActiveSubscription, k as isKnownSubscriptionStatus } from './billing-adapter.interface-m7yE50I0.js';
3
+ export { B as BILLING_CYCLE, a as BILLING_CYCLE_VALUES, b as BillingCycle, i as isKnownBillingCycle, p as parseBillingCycle } from './billing-cycle.enum--hJRYlgP.js';
4
+ export { A as AmountType, P as POLAR_AMOUNT_TYPE, a as Product, b as ProductBenefit, c as ProductBenefitDto, d as ProductDto, e as ProductListParams, f as ProductListResponse, g as ProductListResponseDto, h as ProductPrice, i as ProductPriceDto, m as mapProduct, j as mapProductList } from './product.mapper-CnY1ISOp.js';
5
+ export { MemoryAdapterConfig, createMemoryBillingAdapter } from './memory.js';
6
+
7
+ type RecurringInterval = 'day' | 'week' | 'month' | 'year';
8
+ type PriceType = 'fixed' | 'custom' | 'free' | 'seat_based' | 'metered_unit';
9
+
10
+ declare function minorUnitDivisor(currency: string): number;
11
+ declare function toMajorUnits(amount: number, currency: string): number;
12
+ declare function toMinorUnits(amount: number, currency: string): number;
13
+
14
+ declare function normalizeCouponCode(code: unknown): string | null;
15
+ declare function applyPercentDiscount(baseAmount: number, percent: number, minimumAmount: number): number;
16
+
17
+ export { type PriceType, type RecurringInterval, applyPercentDiscount, minorUnitDivisor, normalizeCouponCode, toMajorUnits, toMinorUnits };