@umituz/web-polar-payment 1.0.18 → 1.0.19
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 +102 -1
- package/dist/index.d.ts +102 -1
- package/dist/index.js +79 -0
- package/dist/index.mjs +76 -0
- package/package.json +1 -1
- package/src/domain/entities/product.entity.ts +56 -0
- package/src/index.ts +5 -0
- package/src/infrastructure/services/polar-api.service.ts +147 -0
package/dist/index.d.mts
CHANGED
|
@@ -111,4 +111,105 @@ declare const SUBSCRIPTION_STATUS: Readonly<{
|
|
|
111
111
|
NONE: "none";
|
|
112
112
|
}>;
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
/**
|
|
115
|
+
* Product Entity
|
|
116
|
+
*
|
|
117
|
+
* Represents a Polar.sh product with pricing information
|
|
118
|
+
*/
|
|
119
|
+
type RecurringInterval = 'day' | 'week' | 'month' | 'year';
|
|
120
|
+
type PriceType = 'fixed' | 'custom' | 'free' | 'seat_based' | 'metered_unit';
|
|
121
|
+
interface PolarPrice {
|
|
122
|
+
id: string;
|
|
123
|
+
type: PriceType;
|
|
124
|
+
amount_type: string;
|
|
125
|
+
amount?: number;
|
|
126
|
+
currency: string;
|
|
127
|
+
recurring_interval?: RecurringInterval;
|
|
128
|
+
is_archived: boolean;
|
|
129
|
+
product_id: string;
|
|
130
|
+
legacy?: boolean;
|
|
131
|
+
}
|
|
132
|
+
interface PolarProduct {
|
|
133
|
+
id: string;
|
|
134
|
+
name: string;
|
|
135
|
+
description: string | null;
|
|
136
|
+
is_recurring: boolean;
|
|
137
|
+
recurring_interval: RecurringInterval | null;
|
|
138
|
+
is_archived: boolean;
|
|
139
|
+
organization_id: string;
|
|
140
|
+
prices: PolarPrice[];
|
|
141
|
+
benefits: Array<{
|
|
142
|
+
id: string;
|
|
143
|
+
type: string;
|
|
144
|
+
description: string | null;
|
|
145
|
+
properties: Record<string, unknown>;
|
|
146
|
+
}>;
|
|
147
|
+
metadata: Record<string, unknown>;
|
|
148
|
+
created_at: string;
|
|
149
|
+
modified_at: string | null;
|
|
150
|
+
}
|
|
151
|
+
interface ProductListResponse {
|
|
152
|
+
items: PolarProduct[];
|
|
153
|
+
pagination: {
|
|
154
|
+
total_count: number;
|
|
155
|
+
max_page: number;
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
interface ProductListParams {
|
|
159
|
+
organizationId?: string;
|
|
160
|
+
isRecurring?: boolean;
|
|
161
|
+
page?: number;
|
|
162
|
+
limit?: number;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Polar API Service
|
|
167
|
+
*
|
|
168
|
+
* Direct client-side calls to Polar.sh API using OAT authentication
|
|
169
|
+
* Note: OAT tokens should only be used server-side in production
|
|
170
|
+
* This service is intended for server-side or edge function usage
|
|
171
|
+
*/
|
|
172
|
+
|
|
173
|
+
interface PolarApiConfig {
|
|
174
|
+
apiToken: string;
|
|
175
|
+
baseUrl?: string;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Fetch products from Polar.sh API
|
|
179
|
+
*
|
|
180
|
+
* @param config - Polar API configuration with OAT token
|
|
181
|
+
* @param params - Query parameters for filtering products
|
|
182
|
+
* @returns Paginated list of products
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* ```ts
|
|
186
|
+
* const products = await getProducts({
|
|
187
|
+
* apiToken: 'polar_oat_xxx',
|
|
188
|
+
* baseUrl: 'https://api.polar.sh/v1'
|
|
189
|
+
* }, {
|
|
190
|
+
* organizationId: 'org-123',
|
|
191
|
+
* isRecurring: true,
|
|
192
|
+
* page: 1,
|
|
193
|
+
* limit: 100
|
|
194
|
+
* });
|
|
195
|
+
* ```
|
|
196
|
+
*/
|
|
197
|
+
declare function getProducts(config: PolarApiConfig, params?: ProductListParams): Promise<ProductListResponse>;
|
|
198
|
+
/**
|
|
199
|
+
* Fetch a single product by ID
|
|
200
|
+
*
|
|
201
|
+
* @param config - Polar API configuration
|
|
202
|
+
* @param productId - Product ID to fetch
|
|
203
|
+
* @returns Product details or null if not found
|
|
204
|
+
*/
|
|
205
|
+
declare function getProductById(config: PolarApiConfig, productId: string): Promise<PolarProduct | null>;
|
|
206
|
+
/**
|
|
207
|
+
* Fetch all products with automatic pagination
|
|
208
|
+
*
|
|
209
|
+
* @param config - Polar API configuration
|
|
210
|
+
* @param params - Query parameters for filtering
|
|
211
|
+
* @returns All products matching the criteria
|
|
212
|
+
*/
|
|
213
|
+
declare function getAllProducts(config: PolarApiConfig, params?: Omit<ProductListParams, 'page' | 'limit'>): Promise<PolarProduct[]>;
|
|
214
|
+
|
|
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -111,4 +111,105 @@ declare const SUBSCRIPTION_STATUS: Readonly<{
|
|
|
111
111
|
NONE: "none";
|
|
112
112
|
}>;
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
/**
|
|
115
|
+
* Product Entity
|
|
116
|
+
*
|
|
117
|
+
* Represents a Polar.sh product with pricing information
|
|
118
|
+
*/
|
|
119
|
+
type RecurringInterval = 'day' | 'week' | 'month' | 'year';
|
|
120
|
+
type PriceType = 'fixed' | 'custom' | 'free' | 'seat_based' | 'metered_unit';
|
|
121
|
+
interface PolarPrice {
|
|
122
|
+
id: string;
|
|
123
|
+
type: PriceType;
|
|
124
|
+
amount_type: string;
|
|
125
|
+
amount?: number;
|
|
126
|
+
currency: string;
|
|
127
|
+
recurring_interval?: RecurringInterval;
|
|
128
|
+
is_archived: boolean;
|
|
129
|
+
product_id: string;
|
|
130
|
+
legacy?: boolean;
|
|
131
|
+
}
|
|
132
|
+
interface PolarProduct {
|
|
133
|
+
id: string;
|
|
134
|
+
name: string;
|
|
135
|
+
description: string | null;
|
|
136
|
+
is_recurring: boolean;
|
|
137
|
+
recurring_interval: RecurringInterval | null;
|
|
138
|
+
is_archived: boolean;
|
|
139
|
+
organization_id: string;
|
|
140
|
+
prices: PolarPrice[];
|
|
141
|
+
benefits: Array<{
|
|
142
|
+
id: string;
|
|
143
|
+
type: string;
|
|
144
|
+
description: string | null;
|
|
145
|
+
properties: Record<string, unknown>;
|
|
146
|
+
}>;
|
|
147
|
+
metadata: Record<string, unknown>;
|
|
148
|
+
created_at: string;
|
|
149
|
+
modified_at: string | null;
|
|
150
|
+
}
|
|
151
|
+
interface ProductListResponse {
|
|
152
|
+
items: PolarProduct[];
|
|
153
|
+
pagination: {
|
|
154
|
+
total_count: number;
|
|
155
|
+
max_page: number;
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
interface ProductListParams {
|
|
159
|
+
organizationId?: string;
|
|
160
|
+
isRecurring?: boolean;
|
|
161
|
+
page?: number;
|
|
162
|
+
limit?: number;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Polar API Service
|
|
167
|
+
*
|
|
168
|
+
* Direct client-side calls to Polar.sh API using OAT authentication
|
|
169
|
+
* Note: OAT tokens should only be used server-side in production
|
|
170
|
+
* This service is intended for server-side or edge function usage
|
|
171
|
+
*/
|
|
172
|
+
|
|
173
|
+
interface PolarApiConfig {
|
|
174
|
+
apiToken: string;
|
|
175
|
+
baseUrl?: string;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Fetch products from Polar.sh API
|
|
179
|
+
*
|
|
180
|
+
* @param config - Polar API configuration with OAT token
|
|
181
|
+
* @param params - Query parameters for filtering products
|
|
182
|
+
* @returns Paginated list of products
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* ```ts
|
|
186
|
+
* const products = await getProducts({
|
|
187
|
+
* apiToken: 'polar_oat_xxx',
|
|
188
|
+
* baseUrl: 'https://api.polar.sh/v1'
|
|
189
|
+
* }, {
|
|
190
|
+
* organizationId: 'org-123',
|
|
191
|
+
* isRecurring: true,
|
|
192
|
+
* page: 1,
|
|
193
|
+
* limit: 100
|
|
194
|
+
* });
|
|
195
|
+
* ```
|
|
196
|
+
*/
|
|
197
|
+
declare function getProducts(config: PolarApiConfig, params?: ProductListParams): Promise<ProductListResponse>;
|
|
198
|
+
/**
|
|
199
|
+
* Fetch a single product by ID
|
|
200
|
+
*
|
|
201
|
+
* @param config - Polar API configuration
|
|
202
|
+
* @param productId - Product ID to fetch
|
|
203
|
+
* @returns Product details or null if not found
|
|
204
|
+
*/
|
|
205
|
+
declare function getProductById(config: PolarApiConfig, productId: string): Promise<PolarProduct | null>;
|
|
206
|
+
/**
|
|
207
|
+
* Fetch all products with automatic pagination
|
|
208
|
+
*
|
|
209
|
+
* @param config - Polar API configuration
|
|
210
|
+
* @param params - Query parameters for filtering
|
|
211
|
+
* @returns All products matching the criteria
|
|
212
|
+
*/
|
|
213
|
+
declare function getAllProducts(config: PolarApiConfig, params?: Omit<ProductListParams, 'page' | 'limit'>): Promise<PolarProduct[]>;
|
|
214
|
+
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -33,6 +33,9 @@ __export(index_exports, {
|
|
|
33
33
|
PolarProvider: () => PolarProvider,
|
|
34
34
|
SUBSCRIPTION_STATUS: () => SUBSCRIPTION_STATUS,
|
|
35
35
|
createFirebaseAdapter: () => createFirebaseAdapter,
|
|
36
|
+
getAllProducts: () => getAllProducts,
|
|
37
|
+
getProductById: () => getProductById,
|
|
38
|
+
getProducts: () => getProducts,
|
|
36
39
|
usePolarBilling: () => usePolarBilling
|
|
37
40
|
});
|
|
38
41
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -312,10 +315,86 @@ function createFirebaseAdapter(config) {
|
|
|
312
315
|
}
|
|
313
316
|
};
|
|
314
317
|
}
|
|
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
|
+
}
|
|
315
391
|
// Annotate the CommonJS export names for ESM import in node:
|
|
316
392
|
0 && (module.exports = {
|
|
317
393
|
PolarProvider,
|
|
318
394
|
SUBSCRIPTION_STATUS,
|
|
319
395
|
createFirebaseAdapter,
|
|
396
|
+
getAllProducts,
|
|
397
|
+
getProductById,
|
|
398
|
+
getProducts,
|
|
320
399
|
usePolarBilling
|
|
321
400
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -279,9 +279,85 @@ function createFirebaseAdapter(config) {
|
|
|
279
279
|
}
|
|
280
280
|
};
|
|
281
281
|
}
|
|
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
|
+
}
|
|
282
355
|
export {
|
|
283
356
|
PolarProvider,
|
|
284
357
|
SUBSCRIPTION_STATUS,
|
|
285
358
|
createFirebaseAdapter,
|
|
359
|
+
getAllProducts,
|
|
360
|
+
getProductById,
|
|
361
|
+
getProducts,
|
|
286
362
|
usePolarBilling
|
|
287
363
|
};
|
package/package.json
CHANGED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Product Entity
|
|
3
|
+
*
|
|
4
|
+
* Represents a Polar.sh product with pricing information
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export type RecurringInterval = 'day' | 'week' | 'month' | 'year';
|
|
8
|
+
|
|
9
|
+
export type PriceType = 'fixed' | 'custom' | 'free' | 'seat_based' | 'metered_unit';
|
|
10
|
+
|
|
11
|
+
export interface PolarPrice {
|
|
12
|
+
id: string;
|
|
13
|
+
type: PriceType;
|
|
14
|
+
amount_type: string;
|
|
15
|
+
amount?: number;
|
|
16
|
+
currency: string;
|
|
17
|
+
recurring_interval?: RecurringInterval;
|
|
18
|
+
is_archived: boolean;
|
|
19
|
+
product_id: string;
|
|
20
|
+
legacy?: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface PolarProduct {
|
|
24
|
+
id: string;
|
|
25
|
+
name: string;
|
|
26
|
+
description: string | null;
|
|
27
|
+
is_recurring: boolean;
|
|
28
|
+
recurring_interval: RecurringInterval | null;
|
|
29
|
+
is_archived: boolean;
|
|
30
|
+
organization_id: string;
|
|
31
|
+
prices: PolarPrice[];
|
|
32
|
+
benefits: Array<{
|
|
33
|
+
id: string;
|
|
34
|
+
type: string;
|
|
35
|
+
description: string | null;
|
|
36
|
+
properties: Record<string, unknown>;
|
|
37
|
+
}>;
|
|
38
|
+
metadata: Record<string, unknown>;
|
|
39
|
+
created_at: string;
|
|
40
|
+
modified_at: string | null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface ProductListResponse {
|
|
44
|
+
items: PolarProduct[];
|
|
45
|
+
pagination: {
|
|
46
|
+
total_count: number;
|
|
47
|
+
max_page: number;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface ProductListParams {
|
|
52
|
+
organizationId?: string;
|
|
53
|
+
isRecurring?: boolean;
|
|
54
|
+
page?: number;
|
|
55
|
+
limit?: number;
|
|
56
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -7,3 +7,8 @@ export { SUBSCRIPTION_STATUS } from './infrastructure/constants/billing.constant
|
|
|
7
7
|
export type { SubscriptionStatusValue, BillingCycle } from './domain/entities/subscription.entity';
|
|
8
8
|
export type { SubscriptionStatus, CheckoutParams, CheckoutResult, OrderItem, CancellationReason, CancelResult, SyncResult } from './domain/entities';
|
|
9
9
|
export type { PolarAdapter } from './domain/interfaces';
|
|
10
|
+
|
|
11
|
+
// Product API
|
|
12
|
+
export { getProducts, getProductById, getAllProducts } from './infrastructure/services/polar-api.service';
|
|
13
|
+
export type { PolarApiConfig } from './infrastructure/services/polar-api.service';
|
|
14
|
+
export type { PolarProduct, PolarPrice, ProductListResponse, ProductListParams, RecurringInterval, PriceType } from './domain/entities/product.entity';
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Polar API Service
|
|
3
|
+
*
|
|
4
|
+
* Direct client-side calls to Polar.sh API using OAT authentication
|
|
5
|
+
* Note: OAT tokens should only be used server-side in production
|
|
6
|
+
* This service is intended for server-side or edge function usage
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type {
|
|
10
|
+
PolarProduct,
|
|
11
|
+
ProductListResponse,
|
|
12
|
+
ProductListParams
|
|
13
|
+
} from '../../domain/entities/product.entity';
|
|
14
|
+
|
|
15
|
+
export interface PolarApiConfig {
|
|
16
|
+
apiToken: string;
|
|
17
|
+
baseUrl?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Fetch products from Polar.sh API
|
|
22
|
+
*
|
|
23
|
+
* @param config - Polar API configuration with OAT token
|
|
24
|
+
* @param params - Query parameters for filtering products
|
|
25
|
+
* @returns Paginated list of products
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* const products = await getProducts({
|
|
30
|
+
* apiToken: 'polar_oat_xxx',
|
|
31
|
+
* baseUrl: 'https://api.polar.sh/v1'
|
|
32
|
+
* }, {
|
|
33
|
+
* organizationId: 'org-123',
|
|
34
|
+
* isRecurring: true,
|
|
35
|
+
* page: 1,
|
|
36
|
+
* limit: 100
|
|
37
|
+
* });
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export async function getProducts(
|
|
41
|
+
config: PolarApiConfig,
|
|
42
|
+
params?: ProductListParams
|
|
43
|
+
): Promise<ProductListResponse> {
|
|
44
|
+
const baseUrl = config.baseUrl || 'https://api.polar.sh/v1';
|
|
45
|
+
const url = new URL(`${baseUrl}/products`);
|
|
46
|
+
|
|
47
|
+
if (params?.organizationId) {
|
|
48
|
+
url.searchParams.set('organization_id', params.organizationId);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (params?.isRecurring !== undefined) {
|
|
52
|
+
url.searchParams.set('is_recurring', String(params.isRecurring));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (params?.page) {
|
|
56
|
+
url.searchParams.set('page', String(params.page));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (params?.limit) {
|
|
60
|
+
url.searchParams.set('limit', String(Math.min(params.limit, 100)));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const response = await fetch(url.toString(), {
|
|
64
|
+
method: 'GET',
|
|
65
|
+
headers: {
|
|
66
|
+
'Authorization': `Bearer ${config.apiToken}`,
|
|
67
|
+
'Accept': 'application/json',
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
if (!response.ok) {
|
|
72
|
+
const error = await response.text();
|
|
73
|
+
throw new Error(
|
|
74
|
+
`Polar API error: ${response.status} ${response.statusText}\n${error}`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const data = await response.json();
|
|
79
|
+
return data as ProductListResponse;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Fetch a single product by ID
|
|
84
|
+
*
|
|
85
|
+
* @param config - Polar API configuration
|
|
86
|
+
* @param productId - Product ID to fetch
|
|
87
|
+
* @returns Product details or null if not found
|
|
88
|
+
*/
|
|
89
|
+
export async function getProductById(
|
|
90
|
+
config: PolarApiConfig,
|
|
91
|
+
productId: string
|
|
92
|
+
): Promise<PolarProduct | null> {
|
|
93
|
+
const baseUrl = config.baseUrl || 'https://api.polar.sh/v1';
|
|
94
|
+
const url = `${baseUrl}/products/${productId}`;
|
|
95
|
+
|
|
96
|
+
const response = await fetch(url, {
|
|
97
|
+
method: 'GET',
|
|
98
|
+
headers: {
|
|
99
|
+
'Authorization': `Bearer ${config.apiToken}`,
|
|
100
|
+
'Accept': 'application/json',
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
if (response.status === 404) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (!response.ok) {
|
|
109
|
+
const error = await response.text();
|
|
110
|
+
throw new Error(
|
|
111
|
+
`Polar API error: ${response.status} ${response.statusText}\n${error}`
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const data = await response.json();
|
|
116
|
+
return data as PolarProduct;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Fetch all products with automatic pagination
|
|
121
|
+
*
|
|
122
|
+
* @param config - Polar API configuration
|
|
123
|
+
* @param params - Query parameters for filtering
|
|
124
|
+
* @returns All products matching the criteria
|
|
125
|
+
*/
|
|
126
|
+
export async function getAllProducts(
|
|
127
|
+
config: PolarApiConfig,
|
|
128
|
+
params?: Omit<ProductListParams, 'page' | 'limit'>
|
|
129
|
+
): Promise<PolarProduct[]> {
|
|
130
|
+
const allProducts: PolarProduct[] = [];
|
|
131
|
+
let page = 1;
|
|
132
|
+
let maxPage = 1;
|
|
133
|
+
|
|
134
|
+
do {
|
|
135
|
+
const response = await getProducts(config, {
|
|
136
|
+
...params,
|
|
137
|
+
page,
|
|
138
|
+
limit: 100,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
allProducts.push(...response.items);
|
|
142
|
+
maxPage = response.pagination.max_page;
|
|
143
|
+
page++;
|
|
144
|
+
} while (page <= maxPage);
|
|
145
|
+
|
|
146
|
+
return allProducts;
|
|
147
|
+
}
|