@umituz/web-polar-payment 1.0.19 → 1.0.20

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.
package/dist/index.d.mts CHANGED
@@ -76,41 +76,6 @@ interface PolarContextValue {
76
76
  }
77
77
  declare function usePolarBilling(): PolarContextValue;
78
78
 
79
- interface FirebaseAdapterConfig {
80
- functions: unknown;
81
- firestore: unknown;
82
- callables?: {
83
- createCheckout?: string;
84
- syncSubscription?: string;
85
- getBillingHistory?: string;
86
- cancelSubscription?: string;
87
- getPortalUrl?: string;
88
- };
89
- db?: {
90
- usersCollection?: string;
91
- planField?: string;
92
- billingCycleField?: string;
93
- subscriptionIdField?: string;
94
- subscriptionStatusField?: string;
95
- polarCustomerIdField?: string;
96
- cancelAtPeriodEndField?: string;
97
- currentPeriodEndField?: string;
98
- };
99
- }
100
- declare function createFirebaseAdapter(config: FirebaseAdapterConfig): PolarAdapter;
101
-
102
- declare const SUBSCRIPTION_STATUS: Readonly<{
103
- ACTIVE: "active";
104
- CANCELED: "canceled";
105
- REVOKED: "revoked";
106
- TRIALING: "trialing";
107
- PAST_DUE: "past_due";
108
- INCOMPLETE: "incomplete";
109
- INCOMPLETE_EXPIRED: "incomplete_expired";
110
- UNPAID: "unpaid";
111
- NONE: "none";
112
- }>;
113
-
114
79
  /**
115
80
  * Product Entity
116
81
  *
@@ -162,6 +127,73 @@ interface ProductListParams {
162
127
  limit?: number;
163
128
  }
164
129
 
130
+ /**
131
+ * usePolarProducts Hook
132
+ *
133
+ * Fetch and manage products from Polar.sh API
134
+ */
135
+
136
+ interface UsePolarProductsOptions {
137
+ apiToken: string;
138
+ organizationId?: string;
139
+ isRecurring?: boolean;
140
+ enabled?: boolean;
141
+ }
142
+ interface UsePolarProductsResult {
143
+ products: PolarProduct[];
144
+ loading: boolean;
145
+ error: string | null;
146
+ refetch: () => Promise<void>;
147
+ }
148
+ /**
149
+ * Fetch products from Polar.sh API
150
+ *
151
+ * @example
152
+ * ```tsx
153
+ * const { products, loading, error } = usePolarProducts({
154
+ * apiToken: polarApiToken,
155
+ * organizationId: polarOrgId,
156
+ * isRecurring: true,
157
+ * });
158
+ * ```
159
+ */
160
+ declare function usePolarProducts(options: UsePolarProductsOptions): UsePolarProductsResult;
161
+
162
+ interface FirebaseAdapterConfig {
163
+ functions: unknown;
164
+ firestore: unknown;
165
+ callables?: {
166
+ createCheckout?: string;
167
+ syncSubscription?: string;
168
+ getBillingHistory?: string;
169
+ cancelSubscription?: string;
170
+ getPortalUrl?: string;
171
+ };
172
+ db?: {
173
+ usersCollection?: string;
174
+ planField?: string;
175
+ billingCycleField?: string;
176
+ subscriptionIdField?: string;
177
+ subscriptionStatusField?: string;
178
+ polarCustomerIdField?: string;
179
+ cancelAtPeriodEndField?: string;
180
+ currentPeriodEndField?: string;
181
+ };
182
+ }
183
+ declare function createFirebaseAdapter(config: FirebaseAdapterConfig): PolarAdapter;
184
+
185
+ declare const SUBSCRIPTION_STATUS: Readonly<{
186
+ ACTIVE: "active";
187
+ CANCELED: "canceled";
188
+ REVOKED: "revoked";
189
+ TRIALING: "trialing";
190
+ PAST_DUE: "past_due";
191
+ INCOMPLETE: "incomplete";
192
+ INCOMPLETE_EXPIRED: "incomplete_expired";
193
+ UNPAID: "unpaid";
194
+ NONE: "none";
195
+ }>;
196
+
165
197
  /**
166
198
  * Polar API Service
167
199
  *
@@ -212,4 +244,4 @@ declare function getProductById(config: PolarApiConfig, productId: string): Prom
212
244
  */
213
245
  declare function getAllProducts(config: PolarApiConfig, params?: Omit<ProductListParams, 'page' | 'limit'>): Promise<PolarProduct[]>;
214
246
 
215
- export { type BillingCycle, type CancelResult, type CancellationReason, type CheckoutParams, type CheckoutResult, type FirebaseAdapterConfig, type OrderItem, type PolarAdapter, type PolarApiConfig, type PolarContextValue, type PolarPrice, type PolarProduct, PolarProvider, type PriceType, type ProductListParams, type ProductListResponse, type RecurringInterval, SUBSCRIPTION_STATUS, type SubscriptionStatus, type SubscriptionStatusValue, type SyncResult, createFirebaseAdapter, getAllProducts, getProductById, getProducts, usePolarBilling };
247
+ export { type BillingCycle, type CancelResult, type CancellationReason, type CheckoutParams, type CheckoutResult, type FirebaseAdapterConfig, type OrderItem, type PolarAdapter, type PolarApiConfig, type PolarContextValue, type PolarPrice, type PolarProduct, PolarProvider, type PriceType, type ProductListParams, type ProductListResponse, type RecurringInterval, SUBSCRIPTION_STATUS, type SubscriptionStatus, type SubscriptionStatusValue, type SyncResult, type UsePolarProductsOptions, type UsePolarProductsResult, createFirebaseAdapter, getAllProducts, getProductById, getProducts, usePolarBilling, usePolarProducts };
package/dist/index.d.ts CHANGED
@@ -76,41 +76,6 @@ interface PolarContextValue {
76
76
  }
77
77
  declare function usePolarBilling(): PolarContextValue;
78
78
 
79
- interface FirebaseAdapterConfig {
80
- functions: unknown;
81
- firestore: unknown;
82
- callables?: {
83
- createCheckout?: string;
84
- syncSubscription?: string;
85
- getBillingHistory?: string;
86
- cancelSubscription?: string;
87
- getPortalUrl?: string;
88
- };
89
- db?: {
90
- usersCollection?: string;
91
- planField?: string;
92
- billingCycleField?: string;
93
- subscriptionIdField?: string;
94
- subscriptionStatusField?: string;
95
- polarCustomerIdField?: string;
96
- cancelAtPeriodEndField?: string;
97
- currentPeriodEndField?: string;
98
- };
99
- }
100
- declare function createFirebaseAdapter(config: FirebaseAdapterConfig): PolarAdapter;
101
-
102
- declare const SUBSCRIPTION_STATUS: Readonly<{
103
- ACTIVE: "active";
104
- CANCELED: "canceled";
105
- REVOKED: "revoked";
106
- TRIALING: "trialing";
107
- PAST_DUE: "past_due";
108
- INCOMPLETE: "incomplete";
109
- INCOMPLETE_EXPIRED: "incomplete_expired";
110
- UNPAID: "unpaid";
111
- NONE: "none";
112
- }>;
113
-
114
79
  /**
115
80
  * Product Entity
116
81
  *
@@ -162,6 +127,73 @@ interface ProductListParams {
162
127
  limit?: number;
163
128
  }
164
129
 
130
+ /**
131
+ * usePolarProducts Hook
132
+ *
133
+ * Fetch and manage products from Polar.sh API
134
+ */
135
+
136
+ interface UsePolarProductsOptions {
137
+ apiToken: string;
138
+ organizationId?: string;
139
+ isRecurring?: boolean;
140
+ enabled?: boolean;
141
+ }
142
+ interface UsePolarProductsResult {
143
+ products: PolarProduct[];
144
+ loading: boolean;
145
+ error: string | null;
146
+ refetch: () => Promise<void>;
147
+ }
148
+ /**
149
+ * Fetch products from Polar.sh API
150
+ *
151
+ * @example
152
+ * ```tsx
153
+ * const { products, loading, error } = usePolarProducts({
154
+ * apiToken: polarApiToken,
155
+ * organizationId: polarOrgId,
156
+ * isRecurring: true,
157
+ * });
158
+ * ```
159
+ */
160
+ declare function usePolarProducts(options: UsePolarProductsOptions): UsePolarProductsResult;
161
+
162
+ interface FirebaseAdapterConfig {
163
+ functions: unknown;
164
+ firestore: unknown;
165
+ callables?: {
166
+ createCheckout?: string;
167
+ syncSubscription?: string;
168
+ getBillingHistory?: string;
169
+ cancelSubscription?: string;
170
+ getPortalUrl?: string;
171
+ };
172
+ db?: {
173
+ usersCollection?: string;
174
+ planField?: string;
175
+ billingCycleField?: string;
176
+ subscriptionIdField?: string;
177
+ subscriptionStatusField?: string;
178
+ polarCustomerIdField?: string;
179
+ cancelAtPeriodEndField?: string;
180
+ currentPeriodEndField?: string;
181
+ };
182
+ }
183
+ declare function createFirebaseAdapter(config: FirebaseAdapterConfig): PolarAdapter;
184
+
185
+ declare const SUBSCRIPTION_STATUS: Readonly<{
186
+ ACTIVE: "active";
187
+ CANCELED: "canceled";
188
+ REVOKED: "revoked";
189
+ TRIALING: "trialing";
190
+ PAST_DUE: "past_due";
191
+ INCOMPLETE: "incomplete";
192
+ INCOMPLETE_EXPIRED: "incomplete_expired";
193
+ UNPAID: "unpaid";
194
+ NONE: "none";
195
+ }>;
196
+
165
197
  /**
166
198
  * Polar API Service
167
199
  *
@@ -212,4 +244,4 @@ declare function getProductById(config: PolarApiConfig, productId: string): Prom
212
244
  */
213
245
  declare function getAllProducts(config: PolarApiConfig, params?: Omit<ProductListParams, 'page' | 'limit'>): Promise<PolarProduct[]>;
214
246
 
215
- export { type BillingCycle, type CancelResult, type CancellationReason, type CheckoutParams, type CheckoutResult, type FirebaseAdapterConfig, type OrderItem, type PolarAdapter, type PolarApiConfig, type PolarContextValue, type PolarPrice, type PolarProduct, PolarProvider, type PriceType, type ProductListParams, type ProductListResponse, type RecurringInterval, SUBSCRIPTION_STATUS, type SubscriptionStatus, type SubscriptionStatusValue, type SyncResult, createFirebaseAdapter, getAllProducts, getProductById, getProducts, usePolarBilling };
247
+ export { type BillingCycle, type CancelResult, type CancellationReason, type CheckoutParams, type CheckoutResult, type FirebaseAdapterConfig, type OrderItem, type PolarAdapter, type PolarApiConfig, type PolarContextValue, type PolarPrice, type PolarProduct, PolarProvider, type PriceType, type ProductListParams, type ProductListResponse, type RecurringInterval, SUBSCRIPTION_STATUS, type SubscriptionStatus, type SubscriptionStatusValue, type SyncResult, type UsePolarProductsOptions, type UsePolarProductsResult, createFirebaseAdapter, getAllProducts, getProductById, getProducts, usePolarBilling, usePolarProducts };
package/dist/index.js CHANGED
@@ -36,7 +36,8 @@ __export(index_exports, {
36
36
  getAllProducts: () => getAllProducts,
37
37
  getProductById: () => getProductById,
38
38
  getProducts: () => getProducts,
39
- usePolarBilling: () => usePolarBilling
39
+ usePolarBilling: () => usePolarBilling,
40
+ usePolarProducts: () => usePolarProducts
40
41
  });
41
42
  module.exports = __toCommonJS(index_exports);
42
43
 
@@ -168,6 +169,123 @@ function PolarProvider({ adapter, userId, children }) {
168
169
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PolarContext.Provider, { value, children });
169
170
  }
170
171
 
172
+ // src/presentation/hooks/usePolarProducts.ts
173
+ var import_react3 = require("react");
174
+
175
+ // src/infrastructure/services/polar-api.service.ts
176
+ async function getProducts(config, params) {
177
+ const baseUrl = config.baseUrl || "https://api.polar.sh/v1";
178
+ const url = new URL(`${baseUrl}/products`);
179
+ if (params?.organizationId) {
180
+ url.searchParams.set("organization_id", params.organizationId);
181
+ }
182
+ if (params?.isRecurring !== void 0) {
183
+ url.searchParams.set("is_recurring", String(params.isRecurring));
184
+ }
185
+ if (params?.page) {
186
+ url.searchParams.set("page", String(params.page));
187
+ }
188
+ if (params?.limit) {
189
+ url.searchParams.set("limit", String(Math.min(params.limit, 100)));
190
+ }
191
+ const response = await fetch(url.toString(), {
192
+ method: "GET",
193
+ headers: {
194
+ "Authorization": `Bearer ${config.apiToken}`,
195
+ "Accept": "application/json"
196
+ }
197
+ });
198
+ if (!response.ok) {
199
+ const error = await response.text();
200
+ throw new Error(
201
+ `Polar API error: ${response.status} ${response.statusText}
202
+ ${error}`
203
+ );
204
+ }
205
+ const data = await response.json();
206
+ return data;
207
+ }
208
+ async function getProductById(config, productId) {
209
+ const baseUrl = config.baseUrl || "https://api.polar.sh/v1";
210
+ const url = `${baseUrl}/products/${productId}`;
211
+ const response = await fetch(url, {
212
+ method: "GET",
213
+ headers: {
214
+ "Authorization": `Bearer ${config.apiToken}`,
215
+ "Accept": "application/json"
216
+ }
217
+ });
218
+ if (response.status === 404) {
219
+ return null;
220
+ }
221
+ if (!response.ok) {
222
+ const error = await response.text();
223
+ throw new Error(
224
+ `Polar API error: ${response.status} ${response.statusText}
225
+ ${error}`
226
+ );
227
+ }
228
+ const data = await response.json();
229
+ return data;
230
+ }
231
+ async function getAllProducts(config, params) {
232
+ const allProducts = [];
233
+ let page = 1;
234
+ let maxPage = 1;
235
+ do {
236
+ const response = await getProducts(config, {
237
+ ...params,
238
+ page,
239
+ limit: 100
240
+ });
241
+ allProducts.push(...response.items);
242
+ maxPage = response.pagination.max_page;
243
+ page++;
244
+ } while (page <= maxPage);
245
+ return allProducts;
246
+ }
247
+
248
+ // src/presentation/hooks/usePolarProducts.ts
249
+ function usePolarProducts(options) {
250
+ const { apiToken, organizationId, isRecurring = true, enabled = true } = options;
251
+ const [products, setProducts] = (0, import_react3.useState)([]);
252
+ const [loading, setLoading] = (0, import_react3.useState)(true);
253
+ const [error, setError] = (0, import_react3.useState)(null);
254
+ const fetchProducts = async () => {
255
+ if (!enabled) {
256
+ setLoading(false);
257
+ return;
258
+ }
259
+ try {
260
+ setLoading(true);
261
+ setError(null);
262
+ const params = {
263
+ isRecurring
264
+ };
265
+ if (organizationId) {
266
+ params.organizationId = organizationId;
267
+ }
268
+ const data = await getAllProducts({ apiToken }, params);
269
+ setProducts(data);
270
+ } catch (err) {
271
+ const message = err instanceof Error ? err.message : "Failed to fetch products";
272
+ setError(message);
273
+ console.error("usePolarProducts error:", err);
274
+ } finally {
275
+ setLoading(false);
276
+ }
277
+ };
278
+ (0, import_react3.useEffect)(() => {
279
+ fetchProducts();
280
+ }, [apiToken, organizationId, isRecurring, enabled]);
281
+ return {
282
+ products,
283
+ loading,
284
+ error,
285
+ refetch: fetchProducts
286
+ };
287
+ }
288
+
171
289
  // src/infrastructure/constants/billing.constants.ts
172
290
  var SUBSCRIPTION_STATUS = Object.freeze({
173
291
  ACTIVE: "active",
@@ -315,79 +433,6 @@ function createFirebaseAdapter(config) {
315
433
  }
316
434
  };
317
435
  }
318
-
319
- // src/infrastructure/services/polar-api.service.ts
320
- async function getProducts(config, params) {
321
- const baseUrl = config.baseUrl || "https://api.polar.sh/v1";
322
- const url = new URL(`${baseUrl}/products`);
323
- if (params?.organizationId) {
324
- url.searchParams.set("organization_id", params.organizationId);
325
- }
326
- if (params?.isRecurring !== void 0) {
327
- url.searchParams.set("is_recurring", String(params.isRecurring));
328
- }
329
- if (params?.page) {
330
- url.searchParams.set("page", String(params.page));
331
- }
332
- if (params?.limit) {
333
- url.searchParams.set("limit", String(Math.min(params.limit, 100)));
334
- }
335
- const response = await fetch(url.toString(), {
336
- method: "GET",
337
- headers: {
338
- "Authorization": `Bearer ${config.apiToken}`,
339
- "Accept": "application/json"
340
- }
341
- });
342
- if (!response.ok) {
343
- const error = await response.text();
344
- throw new Error(
345
- `Polar API error: ${response.status} ${response.statusText}
346
- ${error}`
347
- );
348
- }
349
- const data = await response.json();
350
- return data;
351
- }
352
- async function getProductById(config, productId) {
353
- const baseUrl = config.baseUrl || "https://api.polar.sh/v1";
354
- const url = `${baseUrl}/products/${productId}`;
355
- const response = await fetch(url, {
356
- method: "GET",
357
- headers: {
358
- "Authorization": `Bearer ${config.apiToken}`,
359
- "Accept": "application/json"
360
- }
361
- });
362
- if (response.status === 404) {
363
- return null;
364
- }
365
- if (!response.ok) {
366
- const error = await response.text();
367
- throw new Error(
368
- `Polar API error: ${response.status} ${response.statusText}
369
- ${error}`
370
- );
371
- }
372
- const data = await response.json();
373
- return data;
374
- }
375
- async function getAllProducts(config, params) {
376
- const allProducts = [];
377
- let page = 1;
378
- let maxPage = 1;
379
- do {
380
- const response = await getProducts(config, {
381
- ...params,
382
- page,
383
- limit: 100
384
- });
385
- allProducts.push(...response.items);
386
- maxPage = response.pagination.max_page;
387
- page++;
388
- } while (page <= maxPage);
389
- return allProducts;
390
- }
391
436
  // Annotate the CommonJS export names for ESM import in node:
392
437
  0 && (module.exports = {
393
438
  PolarProvider,
@@ -396,5 +441,6 @@ async function getAllProducts(config, params) {
396
441
  getAllProducts,
397
442
  getProductById,
398
443
  getProducts,
399
- usePolarBilling
444
+ usePolarBilling,
445
+ usePolarProducts
400
446
  });
package/dist/index.mjs CHANGED
@@ -132,6 +132,123 @@ function PolarProvider({ adapter, userId, children }) {
132
132
  return /* @__PURE__ */ jsx(PolarContext.Provider, { value, children });
133
133
  }
134
134
 
135
+ // src/presentation/hooks/usePolarProducts.ts
136
+ import { useState as useState2, useEffect as useEffect2 } from "react";
137
+
138
+ // src/infrastructure/services/polar-api.service.ts
139
+ async function getProducts(config, params) {
140
+ const baseUrl = config.baseUrl || "https://api.polar.sh/v1";
141
+ const url = new URL(`${baseUrl}/products`);
142
+ if (params?.organizationId) {
143
+ url.searchParams.set("organization_id", params.organizationId);
144
+ }
145
+ if (params?.isRecurring !== void 0) {
146
+ url.searchParams.set("is_recurring", String(params.isRecurring));
147
+ }
148
+ if (params?.page) {
149
+ url.searchParams.set("page", String(params.page));
150
+ }
151
+ if (params?.limit) {
152
+ url.searchParams.set("limit", String(Math.min(params.limit, 100)));
153
+ }
154
+ const response = await fetch(url.toString(), {
155
+ method: "GET",
156
+ headers: {
157
+ "Authorization": `Bearer ${config.apiToken}`,
158
+ "Accept": "application/json"
159
+ }
160
+ });
161
+ if (!response.ok) {
162
+ const error = await response.text();
163
+ throw new Error(
164
+ `Polar API error: ${response.status} ${response.statusText}
165
+ ${error}`
166
+ );
167
+ }
168
+ const data = await response.json();
169
+ return data;
170
+ }
171
+ async function getProductById(config, productId) {
172
+ const baseUrl = config.baseUrl || "https://api.polar.sh/v1";
173
+ const url = `${baseUrl}/products/${productId}`;
174
+ const response = await fetch(url, {
175
+ method: "GET",
176
+ headers: {
177
+ "Authorization": `Bearer ${config.apiToken}`,
178
+ "Accept": "application/json"
179
+ }
180
+ });
181
+ if (response.status === 404) {
182
+ return null;
183
+ }
184
+ if (!response.ok) {
185
+ const error = await response.text();
186
+ throw new Error(
187
+ `Polar API error: ${response.status} ${response.statusText}
188
+ ${error}`
189
+ );
190
+ }
191
+ const data = await response.json();
192
+ return data;
193
+ }
194
+ async function getAllProducts(config, params) {
195
+ const allProducts = [];
196
+ let page = 1;
197
+ let maxPage = 1;
198
+ do {
199
+ const response = await getProducts(config, {
200
+ ...params,
201
+ page,
202
+ limit: 100
203
+ });
204
+ allProducts.push(...response.items);
205
+ maxPage = response.pagination.max_page;
206
+ page++;
207
+ } while (page <= maxPage);
208
+ return allProducts;
209
+ }
210
+
211
+ // src/presentation/hooks/usePolarProducts.ts
212
+ function usePolarProducts(options) {
213
+ const { apiToken, organizationId, isRecurring = true, enabled = true } = options;
214
+ const [products, setProducts] = useState2([]);
215
+ const [loading, setLoading] = useState2(true);
216
+ const [error, setError] = useState2(null);
217
+ const fetchProducts = async () => {
218
+ if (!enabled) {
219
+ setLoading(false);
220
+ return;
221
+ }
222
+ try {
223
+ setLoading(true);
224
+ setError(null);
225
+ const params = {
226
+ isRecurring
227
+ };
228
+ if (organizationId) {
229
+ params.organizationId = organizationId;
230
+ }
231
+ const data = await getAllProducts({ apiToken }, params);
232
+ setProducts(data);
233
+ } catch (err) {
234
+ const message = err instanceof Error ? err.message : "Failed to fetch products";
235
+ setError(message);
236
+ console.error("usePolarProducts error:", err);
237
+ } finally {
238
+ setLoading(false);
239
+ }
240
+ };
241
+ useEffect2(() => {
242
+ fetchProducts();
243
+ }, [apiToken, organizationId, isRecurring, enabled]);
244
+ return {
245
+ products,
246
+ loading,
247
+ error,
248
+ refetch: fetchProducts
249
+ };
250
+ }
251
+
135
252
  // src/infrastructure/constants/billing.constants.ts
136
253
  var SUBSCRIPTION_STATUS = Object.freeze({
137
254
  ACTIVE: "active",
@@ -279,79 +396,6 @@ function createFirebaseAdapter(config) {
279
396
  }
280
397
  };
281
398
  }
282
-
283
- // src/infrastructure/services/polar-api.service.ts
284
- async function getProducts(config, params) {
285
- const baseUrl = config.baseUrl || "https://api.polar.sh/v1";
286
- const url = new URL(`${baseUrl}/products`);
287
- if (params?.organizationId) {
288
- url.searchParams.set("organization_id", params.organizationId);
289
- }
290
- if (params?.isRecurring !== void 0) {
291
- url.searchParams.set("is_recurring", String(params.isRecurring));
292
- }
293
- if (params?.page) {
294
- url.searchParams.set("page", String(params.page));
295
- }
296
- if (params?.limit) {
297
- url.searchParams.set("limit", String(Math.min(params.limit, 100)));
298
- }
299
- const response = await fetch(url.toString(), {
300
- method: "GET",
301
- headers: {
302
- "Authorization": `Bearer ${config.apiToken}`,
303
- "Accept": "application/json"
304
- }
305
- });
306
- if (!response.ok) {
307
- const error = await response.text();
308
- throw new Error(
309
- `Polar API error: ${response.status} ${response.statusText}
310
- ${error}`
311
- );
312
- }
313
- const data = await response.json();
314
- return data;
315
- }
316
- async function getProductById(config, productId) {
317
- const baseUrl = config.baseUrl || "https://api.polar.sh/v1";
318
- const url = `${baseUrl}/products/${productId}`;
319
- const response = await fetch(url, {
320
- method: "GET",
321
- headers: {
322
- "Authorization": `Bearer ${config.apiToken}`,
323
- "Accept": "application/json"
324
- }
325
- });
326
- if (response.status === 404) {
327
- return null;
328
- }
329
- if (!response.ok) {
330
- const error = await response.text();
331
- throw new Error(
332
- `Polar API error: ${response.status} ${response.statusText}
333
- ${error}`
334
- );
335
- }
336
- const data = await response.json();
337
- return data;
338
- }
339
- async function getAllProducts(config, params) {
340
- const allProducts = [];
341
- let page = 1;
342
- let maxPage = 1;
343
- do {
344
- const response = await getProducts(config, {
345
- ...params,
346
- page,
347
- limit: 100
348
- });
349
- allProducts.push(...response.items);
350
- maxPage = response.pagination.max_page;
351
- page++;
352
- } while (page <= maxPage);
353
- return allProducts;
354
- }
355
399
  export {
356
400
  PolarProvider,
357
401
  SUBSCRIPTION_STATUS,
@@ -359,5 +403,6 @@ export {
359
403
  getAllProducts,
360
404
  getProductById,
361
405
  getProducts,
362
- usePolarBilling
406
+ usePolarBilling,
407
+ usePolarProducts
363
408
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/web-polar-payment",
3
- "version": "1.0.19",
3
+ "version": "1.0.20",
4
4
  "description": "Universal Polar.sh subscription billing — Firebase adapter",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
package/src/index.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  export { PolarProvider } from './presentation/components/PolarProvider';
2
2
  export { usePolarBilling } from './presentation/hooks/usePolarBilling';
3
+ export { usePolarProducts } from './presentation/hooks/usePolarProducts';
3
4
  export type { PolarContextValue } from './presentation/hooks/usePolarBilling';
5
+ export type { UsePolarProductsOptions, UsePolarProductsResult } from './presentation/hooks/usePolarProducts';
4
6
  export { createFirebaseAdapter } from './infrastructure/services/firebase-billing.service';
5
7
  export type { FirebaseAdapterConfig } from './infrastructure/services/firebase-billing.service';
6
8
  export { SUBSCRIPTION_STATUS } from './infrastructure/constants/billing.constants';
@@ -0,0 +1,83 @@
1
+ /**
2
+ * usePolarProducts Hook
3
+ *
4
+ * Fetch and manage products from Polar.sh API
5
+ */
6
+
7
+ import { useState, useEffect } from 'react';
8
+ import { getAllProducts } from '../../infrastructure/services/polar-api.service';
9
+ import type { PolarProduct, ProductListParams } from '../../domain/entities/product.entity';
10
+
11
+ export interface UsePolarProductsOptions {
12
+ apiToken: string;
13
+ organizationId?: string;
14
+ isRecurring?: boolean;
15
+ enabled?: boolean;
16
+ }
17
+
18
+ export interface UsePolarProductsResult {
19
+ products: PolarProduct[];
20
+ loading: boolean;
21
+ error: string | null;
22
+ refetch: () => Promise<void>;
23
+ }
24
+
25
+ /**
26
+ * Fetch products from Polar.sh API
27
+ *
28
+ * @example
29
+ * ```tsx
30
+ * const { products, loading, error } = usePolarProducts({
31
+ * apiToken: polarApiToken,
32
+ * organizationId: polarOrgId,
33
+ * isRecurring: true,
34
+ * });
35
+ * ```
36
+ */
37
+ export function usePolarProducts(options: UsePolarProductsOptions): UsePolarProductsResult {
38
+ const { apiToken, organizationId, isRecurring = true, enabled = true } = options;
39
+
40
+ const [products, setProducts] = useState<PolarProduct[]>([]);
41
+ const [loading, setLoading] = useState(true);
42
+ const [error, setError] = useState<string | null>(null);
43
+
44
+ const fetchProducts = async () => {
45
+ if (!enabled) {
46
+ setLoading(false);
47
+ return;
48
+ }
49
+
50
+ try {
51
+ setLoading(true);
52
+ setError(null);
53
+
54
+ const params: ProductListParams = {
55
+ isRecurring,
56
+ };
57
+
58
+ if (organizationId) {
59
+ params.organizationId = organizationId;
60
+ }
61
+
62
+ const data = await getAllProducts({ apiToken }, params);
63
+ setProducts(data);
64
+ } catch (err) {
65
+ const message = err instanceof Error ? err.message : 'Failed to fetch products';
66
+ setError(message);
67
+ console.error('usePolarProducts error:', err);
68
+ } finally {
69
+ setLoading(false);
70
+ }
71
+ };
72
+
73
+ useEffect(() => {
74
+ fetchProducts();
75
+ }, [apiToken, organizationId, isRecurring, enabled]);
76
+
77
+ return {
78
+ products,
79
+ loading,
80
+ error,
81
+ refetch: fetchProducts,
82
+ };
83
+ }