perspectapi-ts-sdk 2.8.2 → 2.9.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.
- package/README.md +95 -0
- package/dist/index.d.mts +41 -69
- package/dist/index.d.ts +41 -69
- package/dist/index.js +74 -75
- package/dist/index.mjs +74 -75
- package/package.json +1 -1
- package/src/client/categories-client.ts +126 -107
- package/src/types/index.ts +1 -0
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@ A comprehensive TypeScript SDK for PerspectAPI, designed to work seamlessly with
|
|
|
13
13
|
- 📊 **Comprehensive Coverage** - All PerspectAPI endpoints supported
|
|
14
14
|
- 🧩 **High-Level Loaders** - Drop-in helpers for products, content, and checkout flows with fallbacks
|
|
15
15
|
- 📧 **Newsletter Management** - Complete newsletter subscription system with double opt-in, preferences, and lists
|
|
16
|
+
- 👥 **Site Users** - OTP-based customer accounts with metadata, profiles, orders, and subscriptions
|
|
16
17
|
|
|
17
18
|
## Installation
|
|
18
19
|
|
|
@@ -734,6 +735,100 @@ console.log('Imported:', importResult.data.imported);
|
|
|
734
735
|
console.log('Failed:', importResult.data.failed);
|
|
735
736
|
```
|
|
736
737
|
|
|
738
|
+
> 📚 **For complete newsletter documentation**, see [docs/newsletter.md](docs/newsletter.md)
|
|
739
|
+
|
|
740
|
+
### Site Users (Customer Accounts)
|
|
741
|
+
|
|
742
|
+
Site users are per-site customer accounts with OTP-based authentication, separate from admin users.
|
|
743
|
+
|
|
744
|
+
```typescript
|
|
745
|
+
const siteName = 'your-site-name';
|
|
746
|
+
|
|
747
|
+
// Request OTP for login/signup (with optional metadata)
|
|
748
|
+
await client.siteUsers.requestOtp(
|
|
749
|
+
siteName,
|
|
750
|
+
{
|
|
751
|
+
email: 'user@example.com',
|
|
752
|
+
waitlist: true, // Optional: mark as waitlist signup
|
|
753
|
+
metadata: { // Optional: set metadata at signup time
|
|
754
|
+
signupSource: 'landing-page',
|
|
755
|
+
referralCode: 'FRIEND123',
|
|
756
|
+
interests: ['product-updates']
|
|
757
|
+
}
|
|
758
|
+
},
|
|
759
|
+
csrfToken
|
|
760
|
+
);
|
|
761
|
+
|
|
762
|
+
// Verify OTP and get JWT token
|
|
763
|
+
const response = await client.siteUsers.verifyOtp(
|
|
764
|
+
siteName,
|
|
765
|
+
{ email: 'user@example.com', code: '123456' },
|
|
766
|
+
csrfToken
|
|
767
|
+
);
|
|
768
|
+
|
|
769
|
+
const { token, user } = response.data;
|
|
770
|
+
client.setAuth(token); // Set auth for subsequent requests
|
|
771
|
+
|
|
772
|
+
// Get current user profile
|
|
773
|
+
const { data } = await client.siteUsers.getMe(siteName);
|
|
774
|
+
console.log(data.user); // Basic user fields + metadata
|
|
775
|
+
console.log(data.profile); // Key-value profile data
|
|
776
|
+
|
|
777
|
+
// Update user profile and metadata
|
|
778
|
+
await client.siteUsers.updateMe(
|
|
779
|
+
siteName,
|
|
780
|
+
{
|
|
781
|
+
first_name: 'John',
|
|
782
|
+
last_name: 'Doe',
|
|
783
|
+
metadata: {
|
|
784
|
+
preferences: { theme: 'dark' },
|
|
785
|
+
tags: ['premium'],
|
|
786
|
+
customField: 'value'
|
|
787
|
+
}
|
|
788
|
+
},
|
|
789
|
+
csrfToken
|
|
790
|
+
);
|
|
791
|
+
|
|
792
|
+
// Set profile key-values (phone, addresses, etc.)
|
|
793
|
+
await client.siteUsers.setProfileValue(
|
|
794
|
+
siteName,
|
|
795
|
+
'phone',
|
|
796
|
+
'+1-555-0123',
|
|
797
|
+
csrfToken
|
|
798
|
+
);
|
|
799
|
+
|
|
800
|
+
await client.siteUsers.setProfileValue(
|
|
801
|
+
siteName,
|
|
802
|
+
'address_shipping',
|
|
803
|
+
JSON.stringify({
|
|
804
|
+
line1: '123 Main St',
|
|
805
|
+
city: 'San Francisco',
|
|
806
|
+
state: 'CA',
|
|
807
|
+
postal_code: '94102',
|
|
808
|
+
country: 'US'
|
|
809
|
+
}),
|
|
810
|
+
csrfToken
|
|
811
|
+
);
|
|
812
|
+
|
|
813
|
+
// Get order history
|
|
814
|
+
const orders = await client.siteUsers.getOrders(siteName, {
|
|
815
|
+
limit: 50,
|
|
816
|
+
offset: 0
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
// Get subscriptions
|
|
820
|
+
const subscriptions = await client.siteUsers.getSubscriptions(siteName);
|
|
821
|
+
|
|
822
|
+
// Cancel subscription
|
|
823
|
+
await client.siteUsers.cancelSubscription(siteName, 'sub_123', csrfToken);
|
|
824
|
+
|
|
825
|
+
// Logout
|
|
826
|
+
await client.siteUsers.logout(siteName);
|
|
827
|
+
client.setAuth(null);
|
|
828
|
+
```
|
|
829
|
+
|
|
830
|
+
> 📚 **For complete site users documentation** including waitlist management, metadata patterns, cross-domain authentication, and complete examples, see [docs/site-users.md](docs/site-users.md)
|
|
831
|
+
|
|
737
832
|
## Configuration Options
|
|
738
833
|
|
|
739
834
|
```typescript
|
package/dist/index.d.mts
CHANGED
|
@@ -627,6 +627,7 @@ interface SiteUserOrder {
|
|
|
627
627
|
interface RequestOtpRequest {
|
|
628
628
|
email: string;
|
|
629
629
|
waitlist?: boolean;
|
|
630
|
+
metadata?: Record<string, any>;
|
|
630
631
|
}
|
|
631
632
|
interface VerifyOtpRequest {
|
|
632
633
|
email: string;
|
|
@@ -1410,95 +1411,66 @@ declare class ProductsClient extends BaseClient {
|
|
|
1410
1411
|
declare class CategoriesClient extends BaseClient {
|
|
1411
1412
|
constructor(http: any, cache?: CacheManager);
|
|
1412
1413
|
/**
|
|
1413
|
-
* Get all categories
|
|
1414
|
-
*/
|
|
1415
|
-
getCategories(params?: {
|
|
1416
|
-
page?: number;
|
|
1417
|
-
limit?: number;
|
|
1418
|
-
parentId?: number;
|
|
1419
|
-
organizationId?: number;
|
|
1420
|
-
}): Promise<PaginatedResponse<Category>>;
|
|
1421
|
-
/**
|
|
1422
|
-
* Get category by ID
|
|
1414
|
+
* Get all categories for a site
|
|
1423
1415
|
*/
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
*/
|
|
1432
|
-
getProductCategoryBySlug(siteName: string, slug: string, cachePolicy?: CachePolicy): Promise<ApiResponse<Category>>;
|
|
1416
|
+
getCategories(siteName: string, params?: {
|
|
1417
|
+
category_type?: 'post' | 'product';
|
|
1418
|
+
parent_id?: string;
|
|
1419
|
+
include_subcategories?: 'true' | 'false';
|
|
1420
|
+
}, cachePolicy?: CachePolicy): Promise<ApiResponse<{
|
|
1421
|
+
categories: Category[];
|
|
1422
|
+
}>>;
|
|
1433
1423
|
/**
|
|
1434
|
-
*
|
|
1424
|
+
* Get category by ID (validates it belongs to the site)
|
|
1435
1425
|
*/
|
|
1436
|
-
|
|
1426
|
+
getCategoryById(siteName: string, id: number, cachePolicy?: CachePolicy): Promise<ApiResponse<{
|
|
1427
|
+
category: Category;
|
|
1428
|
+
}>>;
|
|
1437
1429
|
/**
|
|
1438
|
-
*
|
|
1430
|
+
* Get product categories for a site
|
|
1439
1431
|
*/
|
|
1440
|
-
|
|
1432
|
+
getProductCategories(siteName: string, params?: {
|
|
1433
|
+
parent_id?: string;
|
|
1434
|
+
include_subcategories?: 'true' | 'false';
|
|
1435
|
+
}, cachePolicy?: CachePolicy): Promise<ApiResponse<{
|
|
1436
|
+
categories: Category[];
|
|
1437
|
+
}>>;
|
|
1441
1438
|
/**
|
|
1442
|
-
*
|
|
1439
|
+
* Create new category for a site
|
|
1443
1440
|
*/
|
|
1444
|
-
|
|
1441
|
+
createCategory(siteName: string, data: CreateCategoryRequest, csrfToken?: string): Promise<ApiResponse<{
|
|
1445
1442
|
message: string;
|
|
1443
|
+
category_id: number;
|
|
1446
1444
|
}>>;
|
|
1447
1445
|
/**
|
|
1448
|
-
*
|
|
1449
|
-
*/
|
|
1450
|
-
getCategoryTree(rootId?: number): Promise<ApiResponse<Array<Category & {
|
|
1451
|
-
children: Category[];
|
|
1452
|
-
}>>>;
|
|
1453
|
-
/**
|
|
1454
|
-
* Get category children
|
|
1446
|
+
* Create new product category for a site
|
|
1455
1447
|
*/
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
getCategoryParent(id: number): Promise<ApiResponse<Category | null>>;
|
|
1461
|
-
/**
|
|
1462
|
-
* Move category to new parent
|
|
1463
|
-
*/
|
|
1464
|
-
moveCategoryToParent(id: number, parentId: number | null): Promise<ApiResponse<Category>>;
|
|
1465
|
-
/**
|
|
1466
|
-
* Get category breadcrumb path
|
|
1467
|
-
*/
|
|
1468
|
-
getCategoryBreadcrumb(id: number): Promise<ApiResponse<Array<{
|
|
1469
|
-
id: number;
|
|
1470
|
-
name: string;
|
|
1471
|
-
slug: string;
|
|
1472
|
-
}>>>;
|
|
1448
|
+
createProductCategory(siteName: string, data: Omit<CreateCategoryRequest, 'category_type'>, csrfToken?: string): Promise<ApiResponse<{
|
|
1449
|
+
message: string;
|
|
1450
|
+
category_id: number;
|
|
1451
|
+
}>>;
|
|
1473
1452
|
/**
|
|
1474
|
-
*
|
|
1453
|
+
* Update category (validates it belongs to the site)
|
|
1475
1454
|
*/
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
limit?: number;
|
|
1479
|
-
type?: 'content' | 'products' | 'all';
|
|
1480
|
-
}): Promise<ApiResponse<{
|
|
1481
|
-
content: any[];
|
|
1482
|
-
products: any[];
|
|
1483
|
-
total: number;
|
|
1455
|
+
updateCategory(siteName: string, id: number, data: Partial<CreateCategoryRequest>, csrfToken?: string): Promise<ApiResponse<{
|
|
1456
|
+
message: string;
|
|
1484
1457
|
}>>;
|
|
1485
1458
|
/**
|
|
1486
|
-
*
|
|
1459
|
+
* Delete category (validates it belongs to the site)
|
|
1487
1460
|
*/
|
|
1488
|
-
|
|
1489
|
-
id: number;
|
|
1490
|
-
order: number;
|
|
1491
|
-
parentId?: number;
|
|
1492
|
-
}>): Promise<ApiResponse<{
|
|
1461
|
+
deleteCategory(siteName: string, id: number, csrfToken?: string): Promise<ApiResponse<{
|
|
1493
1462
|
message: string;
|
|
1494
1463
|
}>>;
|
|
1495
1464
|
/**
|
|
1496
|
-
*
|
|
1465
|
+
* Associate pages or products with categories
|
|
1497
1466
|
*/
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1467
|
+
associateCategories(siteName: string, data: {
|
|
1468
|
+
entity_id: number;
|
|
1469
|
+
entity_type: 'page' | 'product';
|
|
1470
|
+
category_ids: number[];
|
|
1471
|
+
}, csrfToken?: string): Promise<ApiResponse<{
|
|
1472
|
+
message: string;
|
|
1473
|
+
}>>;
|
|
1502
1474
|
private buildCategoryTags;
|
|
1503
1475
|
}
|
|
1504
1476
|
|
package/dist/index.d.ts
CHANGED
|
@@ -627,6 +627,7 @@ interface SiteUserOrder {
|
|
|
627
627
|
interface RequestOtpRequest {
|
|
628
628
|
email: string;
|
|
629
629
|
waitlist?: boolean;
|
|
630
|
+
metadata?: Record<string, any>;
|
|
630
631
|
}
|
|
631
632
|
interface VerifyOtpRequest {
|
|
632
633
|
email: string;
|
|
@@ -1410,95 +1411,66 @@ declare class ProductsClient extends BaseClient {
|
|
|
1410
1411
|
declare class CategoriesClient extends BaseClient {
|
|
1411
1412
|
constructor(http: any, cache?: CacheManager);
|
|
1412
1413
|
/**
|
|
1413
|
-
* Get all categories
|
|
1414
|
-
*/
|
|
1415
|
-
getCategories(params?: {
|
|
1416
|
-
page?: number;
|
|
1417
|
-
limit?: number;
|
|
1418
|
-
parentId?: number;
|
|
1419
|
-
organizationId?: number;
|
|
1420
|
-
}): Promise<PaginatedResponse<Category>>;
|
|
1421
|
-
/**
|
|
1422
|
-
* Get category by ID
|
|
1414
|
+
* Get all categories for a site
|
|
1423
1415
|
*/
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
*/
|
|
1432
|
-
getProductCategoryBySlug(siteName: string, slug: string, cachePolicy?: CachePolicy): Promise<ApiResponse<Category>>;
|
|
1416
|
+
getCategories(siteName: string, params?: {
|
|
1417
|
+
category_type?: 'post' | 'product';
|
|
1418
|
+
parent_id?: string;
|
|
1419
|
+
include_subcategories?: 'true' | 'false';
|
|
1420
|
+
}, cachePolicy?: CachePolicy): Promise<ApiResponse<{
|
|
1421
|
+
categories: Category[];
|
|
1422
|
+
}>>;
|
|
1433
1423
|
/**
|
|
1434
|
-
*
|
|
1424
|
+
* Get category by ID (validates it belongs to the site)
|
|
1435
1425
|
*/
|
|
1436
|
-
|
|
1426
|
+
getCategoryById(siteName: string, id: number, cachePolicy?: CachePolicy): Promise<ApiResponse<{
|
|
1427
|
+
category: Category;
|
|
1428
|
+
}>>;
|
|
1437
1429
|
/**
|
|
1438
|
-
*
|
|
1430
|
+
* Get product categories for a site
|
|
1439
1431
|
*/
|
|
1440
|
-
|
|
1432
|
+
getProductCategories(siteName: string, params?: {
|
|
1433
|
+
parent_id?: string;
|
|
1434
|
+
include_subcategories?: 'true' | 'false';
|
|
1435
|
+
}, cachePolicy?: CachePolicy): Promise<ApiResponse<{
|
|
1436
|
+
categories: Category[];
|
|
1437
|
+
}>>;
|
|
1441
1438
|
/**
|
|
1442
|
-
*
|
|
1439
|
+
* Create new category for a site
|
|
1443
1440
|
*/
|
|
1444
|
-
|
|
1441
|
+
createCategory(siteName: string, data: CreateCategoryRequest, csrfToken?: string): Promise<ApiResponse<{
|
|
1445
1442
|
message: string;
|
|
1443
|
+
category_id: number;
|
|
1446
1444
|
}>>;
|
|
1447
1445
|
/**
|
|
1448
|
-
*
|
|
1449
|
-
*/
|
|
1450
|
-
getCategoryTree(rootId?: number): Promise<ApiResponse<Array<Category & {
|
|
1451
|
-
children: Category[];
|
|
1452
|
-
}>>>;
|
|
1453
|
-
/**
|
|
1454
|
-
* Get category children
|
|
1446
|
+
* Create new product category for a site
|
|
1455
1447
|
*/
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
getCategoryParent(id: number): Promise<ApiResponse<Category | null>>;
|
|
1461
|
-
/**
|
|
1462
|
-
* Move category to new parent
|
|
1463
|
-
*/
|
|
1464
|
-
moveCategoryToParent(id: number, parentId: number | null): Promise<ApiResponse<Category>>;
|
|
1465
|
-
/**
|
|
1466
|
-
* Get category breadcrumb path
|
|
1467
|
-
*/
|
|
1468
|
-
getCategoryBreadcrumb(id: number): Promise<ApiResponse<Array<{
|
|
1469
|
-
id: number;
|
|
1470
|
-
name: string;
|
|
1471
|
-
slug: string;
|
|
1472
|
-
}>>>;
|
|
1448
|
+
createProductCategory(siteName: string, data: Omit<CreateCategoryRequest, 'category_type'>, csrfToken?: string): Promise<ApiResponse<{
|
|
1449
|
+
message: string;
|
|
1450
|
+
category_id: number;
|
|
1451
|
+
}>>;
|
|
1473
1452
|
/**
|
|
1474
|
-
*
|
|
1453
|
+
* Update category (validates it belongs to the site)
|
|
1475
1454
|
*/
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
limit?: number;
|
|
1479
|
-
type?: 'content' | 'products' | 'all';
|
|
1480
|
-
}): Promise<ApiResponse<{
|
|
1481
|
-
content: any[];
|
|
1482
|
-
products: any[];
|
|
1483
|
-
total: number;
|
|
1455
|
+
updateCategory(siteName: string, id: number, data: Partial<CreateCategoryRequest>, csrfToken?: string): Promise<ApiResponse<{
|
|
1456
|
+
message: string;
|
|
1484
1457
|
}>>;
|
|
1485
1458
|
/**
|
|
1486
|
-
*
|
|
1459
|
+
* Delete category (validates it belongs to the site)
|
|
1487
1460
|
*/
|
|
1488
|
-
|
|
1489
|
-
id: number;
|
|
1490
|
-
order: number;
|
|
1491
|
-
parentId?: number;
|
|
1492
|
-
}>): Promise<ApiResponse<{
|
|
1461
|
+
deleteCategory(siteName: string, id: number, csrfToken?: string): Promise<ApiResponse<{
|
|
1493
1462
|
message: string;
|
|
1494
1463
|
}>>;
|
|
1495
1464
|
/**
|
|
1496
|
-
*
|
|
1465
|
+
* Associate pages or products with categories
|
|
1497
1466
|
*/
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1467
|
+
associateCategories(siteName: string, data: {
|
|
1468
|
+
entity_id: number;
|
|
1469
|
+
entity_type: 'page' | 'product';
|
|
1470
|
+
category_ids: number[];
|
|
1471
|
+
}, csrfToken?: string): Promise<ApiResponse<{
|
|
1472
|
+
message: string;
|
|
1473
|
+
}>>;
|
|
1502
1474
|
private buildCategoryTags;
|
|
1503
1475
|
}
|
|
1504
1476
|
|
package/dist/index.js
CHANGED
|
@@ -1589,115 +1589,114 @@ var CategoriesClient = class extends BaseClient {
|
|
|
1589
1589
|
super(http, "/api/v1", cache);
|
|
1590
1590
|
}
|
|
1591
1591
|
/**
|
|
1592
|
-
* Get all categories
|
|
1592
|
+
* Get all categories for a site
|
|
1593
1593
|
*/
|
|
1594
|
-
async getCategories(params) {
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
* Get category by slug
|
|
1605
|
-
*/
|
|
1606
|
-
async getCategoryBySlug(slug) {
|
|
1607
|
-
return this.getSingle(`/categories/slug/${slug}`);
|
|
1594
|
+
async getCategories(siteName, params, cachePolicy) {
|
|
1595
|
+
const endpoint = this.siteScopedEndpoint(siteName, "/categories", { includeSitesSegment: false });
|
|
1596
|
+
const path = this.buildPath(endpoint);
|
|
1597
|
+
return this.fetchWithCache(
|
|
1598
|
+
endpoint,
|
|
1599
|
+
params,
|
|
1600
|
+
this.buildCategoryTags(siteName),
|
|
1601
|
+
cachePolicy,
|
|
1602
|
+
() => this.http.get(path, params)
|
|
1603
|
+
);
|
|
1608
1604
|
}
|
|
1609
1605
|
/**
|
|
1610
|
-
* Get
|
|
1606
|
+
* Get category by ID (validates it belongs to the site)
|
|
1611
1607
|
*/
|
|
1612
|
-
async
|
|
1613
|
-
const endpoint = this.siteScopedEndpoint(
|
|
1614
|
-
siteName,
|
|
1615
|
-
`/product_category/slug/${encodeURIComponent(slug)}`,
|
|
1616
|
-
{ includeSitesSegment: false }
|
|
1617
|
-
);
|
|
1608
|
+
async getCategoryById(siteName, id, cachePolicy) {
|
|
1609
|
+
const endpoint = this.siteScopedEndpoint(siteName, `/categories/${id}`, { includeSitesSegment: false });
|
|
1618
1610
|
const path = this.buildPath(endpoint);
|
|
1619
1611
|
return this.fetchWithCache(
|
|
1620
1612
|
endpoint,
|
|
1621
1613
|
void 0,
|
|
1622
|
-
this.buildCategoryTags(siteName,
|
|
1614
|
+
this.buildCategoryTags(siteName, `categories:id:${id}`),
|
|
1623
1615
|
cachePolicy,
|
|
1624
1616
|
() => this.http.get(path)
|
|
1625
1617
|
);
|
|
1626
1618
|
}
|
|
1627
1619
|
/**
|
|
1628
|
-
*
|
|
1620
|
+
* Get product categories for a site
|
|
1629
1621
|
*/
|
|
1630
|
-
async
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
* Delete category
|
|
1641
|
-
*/
|
|
1642
|
-
async deleteCategory(id) {
|
|
1643
|
-
return this.delete(`/categories/${id}`);
|
|
1644
|
-
}
|
|
1645
|
-
/**
|
|
1646
|
-
* Get category tree (hierarchical structure)
|
|
1647
|
-
*/
|
|
1648
|
-
async getCategoryTree(rootId) {
|
|
1649
|
-
const endpoint = rootId ? `/categories/tree/${rootId}` : "/categories/tree";
|
|
1650
|
-
return this.getSingle(endpoint);
|
|
1651
|
-
}
|
|
1652
|
-
/**
|
|
1653
|
-
* Get category children
|
|
1654
|
-
*/
|
|
1655
|
-
async getCategoryChildren(id) {
|
|
1656
|
-
return this.getSingle(`/categories/${id}/children`);
|
|
1657
|
-
}
|
|
1658
|
-
/**
|
|
1659
|
-
* Get category parent
|
|
1660
|
-
*/
|
|
1661
|
-
async getCategoryParent(id) {
|
|
1662
|
-
return this.getSingle(`/categories/${id}/parent`);
|
|
1622
|
+
async getProductCategories(siteName, params, cachePolicy) {
|
|
1623
|
+
const endpoint = this.siteScopedEndpoint(siteName, "/categories/product", { includeSitesSegment: false });
|
|
1624
|
+
const path = this.buildPath(endpoint);
|
|
1625
|
+
return this.fetchWithCache(
|
|
1626
|
+
endpoint,
|
|
1627
|
+
params,
|
|
1628
|
+
this.buildCategoryTags(siteName, "categories:product"),
|
|
1629
|
+
cachePolicy,
|
|
1630
|
+
() => this.http.get(path, params)
|
|
1631
|
+
);
|
|
1663
1632
|
}
|
|
1664
1633
|
/**
|
|
1665
|
-
*
|
|
1634
|
+
* Create new category for a site
|
|
1666
1635
|
*/
|
|
1667
|
-
async
|
|
1668
|
-
|
|
1636
|
+
async createCategory(siteName, data, csrfToken) {
|
|
1637
|
+
const endpoint = this.siteScopedEndpoint(siteName, "/categories", { includeSitesSegment: false });
|
|
1638
|
+
const path = this.buildPath(endpoint);
|
|
1639
|
+
const result = await this.http.post(path, data, { csrfToken });
|
|
1640
|
+
if (this.cache) {
|
|
1641
|
+
await this.cache.invalidate({ tags: this.buildCategoryTags(siteName) });
|
|
1642
|
+
}
|
|
1643
|
+
return result;
|
|
1669
1644
|
}
|
|
1670
1645
|
/**
|
|
1671
|
-
*
|
|
1646
|
+
* Create new product category for a site
|
|
1672
1647
|
*/
|
|
1673
|
-
async
|
|
1674
|
-
|
|
1648
|
+
async createProductCategory(siteName, data, csrfToken) {
|
|
1649
|
+
const endpoint = this.siteScopedEndpoint(siteName, "/categories/product", { includeSitesSegment: false });
|
|
1650
|
+
const path = this.buildPath(endpoint);
|
|
1651
|
+
const result = await this.http.post(path, data, { csrfToken });
|
|
1652
|
+
if (this.cache) {
|
|
1653
|
+
await this.cache.invalidate({ tags: this.buildCategoryTags(siteName, "categories:product") });
|
|
1654
|
+
}
|
|
1655
|
+
return result;
|
|
1675
1656
|
}
|
|
1676
1657
|
/**
|
|
1677
|
-
*
|
|
1658
|
+
* Update category (validates it belongs to the site)
|
|
1678
1659
|
*/
|
|
1679
|
-
async
|
|
1680
|
-
|
|
1660
|
+
async updateCategory(siteName, id, data, csrfToken) {
|
|
1661
|
+
const endpoint = this.siteScopedEndpoint(siteName, `/categories/${id}`, { includeSitesSegment: false });
|
|
1662
|
+
const path = this.buildPath(endpoint);
|
|
1663
|
+
const result = await this.http.put(path, data, { csrfToken });
|
|
1664
|
+
if (this.cache) {
|
|
1665
|
+
await this.cache.invalidate({ tags: this.buildCategoryTags(siteName, `categories:id:${id}`) });
|
|
1666
|
+
}
|
|
1667
|
+
return result;
|
|
1681
1668
|
}
|
|
1682
1669
|
/**
|
|
1683
|
-
*
|
|
1670
|
+
* Delete category (validates it belongs to the site)
|
|
1684
1671
|
*/
|
|
1685
|
-
async
|
|
1686
|
-
|
|
1672
|
+
async deleteCategory(siteName, id, csrfToken) {
|
|
1673
|
+
const endpoint = this.siteScopedEndpoint(siteName, `/categories/${id}`, { includeSitesSegment: false });
|
|
1674
|
+
const path = this.buildPath(endpoint);
|
|
1675
|
+
const result = await this.http.delete(path, { csrfToken });
|
|
1676
|
+
if (this.cache) {
|
|
1677
|
+
await this.cache.invalidate({ tags: this.buildCategoryTags(siteName) });
|
|
1678
|
+
}
|
|
1679
|
+
return result;
|
|
1687
1680
|
}
|
|
1688
1681
|
/**
|
|
1689
|
-
*
|
|
1682
|
+
* Associate pages or products with categories
|
|
1690
1683
|
*/
|
|
1691
|
-
async
|
|
1692
|
-
|
|
1684
|
+
async associateCategories(siteName, data, csrfToken) {
|
|
1685
|
+
const endpoint = this.siteScopedEndpoint(siteName, "/categories/associate", { includeSitesSegment: false });
|
|
1686
|
+
const path = this.buildPath(endpoint);
|
|
1687
|
+
const result = await this.http.post(path, data, { csrfToken });
|
|
1688
|
+
if (this.cache) {
|
|
1689
|
+
await this.cache.invalidate({ tags: this.buildCategoryTags(siteName) });
|
|
1690
|
+
}
|
|
1691
|
+
return result;
|
|
1693
1692
|
}
|
|
1694
|
-
buildCategoryTags(siteName,
|
|
1693
|
+
buildCategoryTags(siteName, extraTag) {
|
|
1695
1694
|
const tags = /* @__PURE__ */ new Set(["categories"]);
|
|
1696
1695
|
if (siteName) {
|
|
1697
1696
|
tags.add(`categories:site:${siteName}`);
|
|
1698
1697
|
}
|
|
1699
|
-
if (
|
|
1700
|
-
tags.add(
|
|
1698
|
+
if (extraTag) {
|
|
1699
|
+
tags.add(extraTag);
|
|
1701
1700
|
}
|
|
1702
1701
|
return Array.from(tags.values());
|
|
1703
1702
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -1527,115 +1527,114 @@ var CategoriesClient = class extends BaseClient {
|
|
|
1527
1527
|
super(http, "/api/v1", cache);
|
|
1528
1528
|
}
|
|
1529
1529
|
/**
|
|
1530
|
-
* Get all categories
|
|
1530
|
+
* Get all categories for a site
|
|
1531
1531
|
*/
|
|
1532
|
-
async getCategories(params) {
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
* Get category by slug
|
|
1543
|
-
*/
|
|
1544
|
-
async getCategoryBySlug(slug) {
|
|
1545
|
-
return this.getSingle(`/categories/slug/${slug}`);
|
|
1532
|
+
async getCategories(siteName, params, cachePolicy) {
|
|
1533
|
+
const endpoint = this.siteScopedEndpoint(siteName, "/categories", { includeSitesSegment: false });
|
|
1534
|
+
const path = this.buildPath(endpoint);
|
|
1535
|
+
return this.fetchWithCache(
|
|
1536
|
+
endpoint,
|
|
1537
|
+
params,
|
|
1538
|
+
this.buildCategoryTags(siteName),
|
|
1539
|
+
cachePolicy,
|
|
1540
|
+
() => this.http.get(path, params)
|
|
1541
|
+
);
|
|
1546
1542
|
}
|
|
1547
1543
|
/**
|
|
1548
|
-
* Get
|
|
1544
|
+
* Get category by ID (validates it belongs to the site)
|
|
1549
1545
|
*/
|
|
1550
|
-
async
|
|
1551
|
-
const endpoint = this.siteScopedEndpoint(
|
|
1552
|
-
siteName,
|
|
1553
|
-
`/product_category/slug/${encodeURIComponent(slug)}`,
|
|
1554
|
-
{ includeSitesSegment: false }
|
|
1555
|
-
);
|
|
1546
|
+
async getCategoryById(siteName, id, cachePolicy) {
|
|
1547
|
+
const endpoint = this.siteScopedEndpoint(siteName, `/categories/${id}`, { includeSitesSegment: false });
|
|
1556
1548
|
const path = this.buildPath(endpoint);
|
|
1557
1549
|
return this.fetchWithCache(
|
|
1558
1550
|
endpoint,
|
|
1559
1551
|
void 0,
|
|
1560
|
-
this.buildCategoryTags(siteName,
|
|
1552
|
+
this.buildCategoryTags(siteName, `categories:id:${id}`),
|
|
1561
1553
|
cachePolicy,
|
|
1562
1554
|
() => this.http.get(path)
|
|
1563
1555
|
);
|
|
1564
1556
|
}
|
|
1565
1557
|
/**
|
|
1566
|
-
*
|
|
1558
|
+
* Get product categories for a site
|
|
1567
1559
|
*/
|
|
1568
|
-
async
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
* Delete category
|
|
1579
|
-
*/
|
|
1580
|
-
async deleteCategory(id) {
|
|
1581
|
-
return this.delete(`/categories/${id}`);
|
|
1582
|
-
}
|
|
1583
|
-
/**
|
|
1584
|
-
* Get category tree (hierarchical structure)
|
|
1585
|
-
*/
|
|
1586
|
-
async getCategoryTree(rootId) {
|
|
1587
|
-
const endpoint = rootId ? `/categories/tree/${rootId}` : "/categories/tree";
|
|
1588
|
-
return this.getSingle(endpoint);
|
|
1589
|
-
}
|
|
1590
|
-
/**
|
|
1591
|
-
* Get category children
|
|
1592
|
-
*/
|
|
1593
|
-
async getCategoryChildren(id) {
|
|
1594
|
-
return this.getSingle(`/categories/${id}/children`);
|
|
1595
|
-
}
|
|
1596
|
-
/**
|
|
1597
|
-
* Get category parent
|
|
1598
|
-
*/
|
|
1599
|
-
async getCategoryParent(id) {
|
|
1600
|
-
return this.getSingle(`/categories/${id}/parent`);
|
|
1560
|
+
async getProductCategories(siteName, params, cachePolicy) {
|
|
1561
|
+
const endpoint = this.siteScopedEndpoint(siteName, "/categories/product", { includeSitesSegment: false });
|
|
1562
|
+
const path = this.buildPath(endpoint);
|
|
1563
|
+
return this.fetchWithCache(
|
|
1564
|
+
endpoint,
|
|
1565
|
+
params,
|
|
1566
|
+
this.buildCategoryTags(siteName, "categories:product"),
|
|
1567
|
+
cachePolicy,
|
|
1568
|
+
() => this.http.get(path, params)
|
|
1569
|
+
);
|
|
1601
1570
|
}
|
|
1602
1571
|
/**
|
|
1603
|
-
*
|
|
1572
|
+
* Create new category for a site
|
|
1604
1573
|
*/
|
|
1605
|
-
async
|
|
1606
|
-
|
|
1574
|
+
async createCategory(siteName, data, csrfToken) {
|
|
1575
|
+
const endpoint = this.siteScopedEndpoint(siteName, "/categories", { includeSitesSegment: false });
|
|
1576
|
+
const path = this.buildPath(endpoint);
|
|
1577
|
+
const result = await this.http.post(path, data, { csrfToken });
|
|
1578
|
+
if (this.cache) {
|
|
1579
|
+
await this.cache.invalidate({ tags: this.buildCategoryTags(siteName) });
|
|
1580
|
+
}
|
|
1581
|
+
return result;
|
|
1607
1582
|
}
|
|
1608
1583
|
/**
|
|
1609
|
-
*
|
|
1584
|
+
* Create new product category for a site
|
|
1610
1585
|
*/
|
|
1611
|
-
async
|
|
1612
|
-
|
|
1586
|
+
async createProductCategory(siteName, data, csrfToken) {
|
|
1587
|
+
const endpoint = this.siteScopedEndpoint(siteName, "/categories/product", { includeSitesSegment: false });
|
|
1588
|
+
const path = this.buildPath(endpoint);
|
|
1589
|
+
const result = await this.http.post(path, data, { csrfToken });
|
|
1590
|
+
if (this.cache) {
|
|
1591
|
+
await this.cache.invalidate({ tags: this.buildCategoryTags(siteName, "categories:product") });
|
|
1592
|
+
}
|
|
1593
|
+
return result;
|
|
1613
1594
|
}
|
|
1614
1595
|
/**
|
|
1615
|
-
*
|
|
1596
|
+
* Update category (validates it belongs to the site)
|
|
1616
1597
|
*/
|
|
1617
|
-
async
|
|
1618
|
-
|
|
1598
|
+
async updateCategory(siteName, id, data, csrfToken) {
|
|
1599
|
+
const endpoint = this.siteScopedEndpoint(siteName, `/categories/${id}`, { includeSitesSegment: false });
|
|
1600
|
+
const path = this.buildPath(endpoint);
|
|
1601
|
+
const result = await this.http.put(path, data, { csrfToken });
|
|
1602
|
+
if (this.cache) {
|
|
1603
|
+
await this.cache.invalidate({ tags: this.buildCategoryTags(siteName, `categories:id:${id}`) });
|
|
1604
|
+
}
|
|
1605
|
+
return result;
|
|
1619
1606
|
}
|
|
1620
1607
|
/**
|
|
1621
|
-
*
|
|
1608
|
+
* Delete category (validates it belongs to the site)
|
|
1622
1609
|
*/
|
|
1623
|
-
async
|
|
1624
|
-
|
|
1610
|
+
async deleteCategory(siteName, id, csrfToken) {
|
|
1611
|
+
const endpoint = this.siteScopedEndpoint(siteName, `/categories/${id}`, { includeSitesSegment: false });
|
|
1612
|
+
const path = this.buildPath(endpoint);
|
|
1613
|
+
const result = await this.http.delete(path, { csrfToken });
|
|
1614
|
+
if (this.cache) {
|
|
1615
|
+
await this.cache.invalidate({ tags: this.buildCategoryTags(siteName) });
|
|
1616
|
+
}
|
|
1617
|
+
return result;
|
|
1625
1618
|
}
|
|
1626
1619
|
/**
|
|
1627
|
-
*
|
|
1620
|
+
* Associate pages or products with categories
|
|
1628
1621
|
*/
|
|
1629
|
-
async
|
|
1630
|
-
|
|
1622
|
+
async associateCategories(siteName, data, csrfToken) {
|
|
1623
|
+
const endpoint = this.siteScopedEndpoint(siteName, "/categories/associate", { includeSitesSegment: false });
|
|
1624
|
+
const path = this.buildPath(endpoint);
|
|
1625
|
+
const result = await this.http.post(path, data, { csrfToken });
|
|
1626
|
+
if (this.cache) {
|
|
1627
|
+
await this.cache.invalidate({ tags: this.buildCategoryTags(siteName) });
|
|
1628
|
+
}
|
|
1629
|
+
return result;
|
|
1631
1630
|
}
|
|
1632
|
-
buildCategoryTags(siteName,
|
|
1631
|
+
buildCategoryTags(siteName, extraTag) {
|
|
1633
1632
|
const tags = /* @__PURE__ */ new Set(["categories"]);
|
|
1634
1633
|
if (siteName) {
|
|
1635
1634
|
tags.add(`categories:site:${siteName}`);
|
|
1636
1635
|
}
|
|
1637
|
-
if (
|
|
1638
|
-
tags.add(
|
|
1636
|
+
if (extraTag) {
|
|
1637
|
+
tags.add(extraTag);
|
|
1639
1638
|
}
|
|
1640
1639
|
return Array.from(tags.values());
|
|
1641
1640
|
}
|
package/package.json
CHANGED
|
@@ -8,7 +8,6 @@ import type { CachePolicy } from '../cache/types';
|
|
|
8
8
|
import type {
|
|
9
9
|
Category,
|
|
10
10
|
CreateCategoryRequest,
|
|
11
|
-
PaginatedResponse,
|
|
12
11
|
ApiResponse,
|
|
13
12
|
} from '../types';
|
|
14
13
|
|
|
@@ -18,161 +17,181 @@ export class CategoriesClient extends BaseClient {
|
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
/**
|
|
21
|
-
* Get all categories
|
|
20
|
+
* Get all categories for a site
|
|
22
21
|
*/
|
|
23
|
-
async getCategories(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
async getCategories(
|
|
23
|
+
siteName: string,
|
|
24
|
+
params?: {
|
|
25
|
+
category_type?: 'post' | 'product';
|
|
26
|
+
parent_id?: string;
|
|
27
|
+
include_subcategories?: 'true' | 'false';
|
|
28
|
+
},
|
|
29
|
+
cachePolicy?: CachePolicy
|
|
30
|
+
): Promise<ApiResponse<{ categories: Category[] }>> {
|
|
31
|
+
const endpoint = this.siteScopedEndpoint(siteName, '/categories', { includeSitesSegment: false });
|
|
32
|
+
const path = this.buildPath(endpoint);
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
return this.fetchWithCache<ApiResponse<{ categories: Category[] }>>(
|
|
35
|
+
endpoint,
|
|
36
|
+
params,
|
|
37
|
+
this.buildCategoryTags(siteName),
|
|
38
|
+
cachePolicy,
|
|
39
|
+
() => this.http.get<{ categories: Category[] }>(path, params)
|
|
40
|
+
);
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
/**
|
|
40
|
-
* Get category by
|
|
44
|
+
* Get category by ID (validates it belongs to the site)
|
|
41
45
|
*/
|
|
42
|
-
async
|
|
43
|
-
|
|
46
|
+
async getCategoryById(siteName: string, id: number, cachePolicy?: CachePolicy): Promise<ApiResponse<{ category: Category }>> {
|
|
47
|
+
const endpoint = this.siteScopedEndpoint(siteName, `/categories/${id}`, { includeSitesSegment: false });
|
|
48
|
+
const path = this.buildPath(endpoint);
|
|
49
|
+
|
|
50
|
+
return this.fetchWithCache<ApiResponse<{ category: Category }>>(
|
|
51
|
+
endpoint,
|
|
52
|
+
undefined,
|
|
53
|
+
this.buildCategoryTags(siteName, `categories:id:${id}`),
|
|
54
|
+
cachePolicy,
|
|
55
|
+
() => this.http.get<{ category: Category }>(path)
|
|
56
|
+
);
|
|
44
57
|
}
|
|
45
58
|
|
|
46
59
|
/**
|
|
47
|
-
* Get product
|
|
60
|
+
* Get product categories for a site
|
|
48
61
|
*/
|
|
49
|
-
async
|
|
62
|
+
async getProductCategories(
|
|
50
63
|
siteName: string,
|
|
51
|
-
|
|
64
|
+
params?: {
|
|
65
|
+
parent_id?: string;
|
|
66
|
+
include_subcategories?: 'true' | 'false';
|
|
67
|
+
},
|
|
52
68
|
cachePolicy?: CachePolicy
|
|
53
|
-
): Promise<ApiResponse<Category>> {
|
|
54
|
-
const endpoint = this.siteScopedEndpoint(
|
|
55
|
-
siteName,
|
|
56
|
-
`/product_category/slug/${encodeURIComponent(slug)}`,
|
|
57
|
-
{ includeSitesSegment: false }
|
|
58
|
-
);
|
|
69
|
+
): Promise<ApiResponse<{ categories: Category[] }>> {
|
|
70
|
+
const endpoint = this.siteScopedEndpoint(siteName, '/categories/product', { includeSitesSegment: false });
|
|
59
71
|
const path = this.buildPath(endpoint);
|
|
60
72
|
|
|
61
|
-
return this.fetchWithCache<ApiResponse<Category>>(
|
|
73
|
+
return this.fetchWithCache<ApiResponse<{ categories: Category[] }>>(
|
|
62
74
|
endpoint,
|
|
63
|
-
|
|
64
|
-
this.buildCategoryTags(siteName,
|
|
75
|
+
params,
|
|
76
|
+
this.buildCategoryTags(siteName, 'categories:product'),
|
|
65
77
|
cachePolicy,
|
|
66
|
-
() => this.http.get<Category>(path)
|
|
78
|
+
() => this.http.get<{ categories: Category[] }>(path, params)
|
|
67
79
|
);
|
|
68
80
|
}
|
|
69
81
|
|
|
70
82
|
/**
|
|
71
|
-
* Create new category
|
|
83
|
+
* Create new category for a site
|
|
72
84
|
*/
|
|
73
|
-
async createCategory(
|
|
74
|
-
|
|
75
|
-
|
|
85
|
+
async createCategory(
|
|
86
|
+
siteName: string,
|
|
87
|
+
data: CreateCategoryRequest,
|
|
88
|
+
csrfToken?: string
|
|
89
|
+
): Promise<ApiResponse<{ message: string; category_id: number }>> {
|
|
90
|
+
const endpoint = this.siteScopedEndpoint(siteName, '/categories', { includeSitesSegment: false });
|
|
91
|
+
const path = this.buildPath(endpoint);
|
|
76
92
|
|
|
77
|
-
|
|
78
|
-
* Update category
|
|
79
|
-
*/
|
|
80
|
-
async updateCategory(id: number, data: Partial<CreateCategoryRequest>): Promise<ApiResponse<Category>> {
|
|
81
|
-
return this.update<Partial<CreateCategoryRequest>, Category>(`/categories/${id}`, data);
|
|
82
|
-
}
|
|
93
|
+
const result = await this.http.post<{ message: string; category_id: number }>(path, data, { csrfToken });
|
|
83
94
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return this.delete<{ message: string }>(`/categories/${id}`);
|
|
89
|
-
}
|
|
95
|
+
// Invalidate cache after creation
|
|
96
|
+
if (this.cache) {
|
|
97
|
+
await this.cache.invalidate({ tags: this.buildCategoryTags(siteName) });
|
|
98
|
+
}
|
|
90
99
|
|
|
91
|
-
|
|
92
|
-
* Get category tree (hierarchical structure)
|
|
93
|
-
*/
|
|
94
|
-
async getCategoryTree(rootId?: number): Promise<ApiResponse<Array<Category & {
|
|
95
|
-
children: Category[];
|
|
96
|
-
}>>> {
|
|
97
|
-
const endpoint = rootId ? `/categories/tree/${rootId}` : '/categories/tree';
|
|
98
|
-
return this.getSingle(endpoint);
|
|
100
|
+
return result;
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
/**
|
|
102
|
-
*
|
|
104
|
+
* Create new product category for a site
|
|
103
105
|
*/
|
|
104
|
-
async
|
|
105
|
-
|
|
106
|
-
|
|
106
|
+
async createProductCategory(
|
|
107
|
+
siteName: string,
|
|
108
|
+
data: Omit<CreateCategoryRequest, 'category_type'>,
|
|
109
|
+
csrfToken?: string
|
|
110
|
+
): Promise<ApiResponse<{ message: string; category_id: number }>> {
|
|
111
|
+
const endpoint = this.siteScopedEndpoint(siteName, '/categories/product', { includeSitesSegment: false });
|
|
112
|
+
const path = this.buildPath(endpoint);
|
|
107
113
|
|
|
108
|
-
|
|
109
|
-
* Get category parent
|
|
110
|
-
*/
|
|
111
|
-
async getCategoryParent(id: number): Promise<ApiResponse<Category | null>> {
|
|
112
|
-
return this.getSingle<Category | null>(`/categories/${id}/parent`);
|
|
113
|
-
}
|
|
114
|
+
const result = await this.http.post<{ message: string; category_id: number }>(path, data, { csrfToken });
|
|
114
115
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
return this.patch<{ parentId: number | null }, Category>(`/categories/${id}`, { parentId });
|
|
120
|
-
}
|
|
116
|
+
// Invalidate cache after creation
|
|
117
|
+
if (this.cache) {
|
|
118
|
+
await this.cache.invalidate({ tags: this.buildCategoryTags(siteName, 'categories:product') });
|
|
119
|
+
}
|
|
121
120
|
|
|
122
|
-
|
|
123
|
-
* Get category breadcrumb path
|
|
124
|
-
*/
|
|
125
|
-
async getCategoryBreadcrumb(id: number): Promise<ApiResponse<Array<{
|
|
126
|
-
id: number;
|
|
127
|
-
name: string;
|
|
128
|
-
slug: string;
|
|
129
|
-
}>>> {
|
|
130
|
-
return this.getSingle(`/categories/${id}/breadcrumb`);
|
|
121
|
+
return result;
|
|
131
122
|
}
|
|
132
123
|
|
|
133
124
|
/**
|
|
134
|
-
*
|
|
125
|
+
* Update category (validates it belongs to the site)
|
|
135
126
|
*/
|
|
136
|
-
async
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
127
|
+
async updateCategory(
|
|
128
|
+
siteName: string,
|
|
129
|
+
id: number,
|
|
130
|
+
data: Partial<CreateCategoryRequest>,
|
|
131
|
+
csrfToken?: string
|
|
132
|
+
): Promise<ApiResponse<{ message: string }>> {
|
|
133
|
+
const endpoint = this.siteScopedEndpoint(siteName, `/categories/${id}`, { includeSitesSegment: false });
|
|
134
|
+
const path = this.buildPath(endpoint);
|
|
135
|
+
|
|
136
|
+
const result = await this.http.put<{ message: string }>(path, data, { csrfToken });
|
|
137
|
+
|
|
138
|
+
// Invalidate cache after update
|
|
139
|
+
if (this.cache) {
|
|
140
|
+
await this.cache.invalidate({ tags: this.buildCategoryTags(siteName, `categories:id:${id}`) });
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return result;
|
|
146
144
|
}
|
|
147
145
|
|
|
148
146
|
/**
|
|
149
|
-
*
|
|
147
|
+
* Delete category (validates it belongs to the site)
|
|
150
148
|
*/
|
|
151
|
-
async
|
|
152
|
-
id:
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
149
|
+
async deleteCategory(siteName: string, id: number, csrfToken?: string): Promise<ApiResponse<{ message: string }>> {
|
|
150
|
+
const endpoint = this.siteScopedEndpoint(siteName, `/categories/${id}`, { includeSitesSegment: false });
|
|
151
|
+
const path = this.buildPath(endpoint);
|
|
152
|
+
|
|
153
|
+
const result = await this.http.delete<{ message: string }>(path, { csrfToken });
|
|
154
|
+
|
|
155
|
+
// Invalidate cache after deletion
|
|
156
|
+
if (this.cache) {
|
|
157
|
+
await this.cache.invalidate({ tags: this.buildCategoryTags(siteName) });
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return result;
|
|
157
161
|
}
|
|
158
162
|
|
|
159
163
|
/**
|
|
160
|
-
*
|
|
164
|
+
* Associate pages or products with categories
|
|
161
165
|
*/
|
|
162
|
-
async
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
166
|
+
async associateCategories(
|
|
167
|
+
siteName: string,
|
|
168
|
+
data: {
|
|
169
|
+
entity_id: number;
|
|
170
|
+
entity_type: 'page' | 'product';
|
|
171
|
+
category_ids: number[];
|
|
172
|
+
},
|
|
173
|
+
csrfToken?: string
|
|
174
|
+
): Promise<ApiResponse<{ message: string }>> {
|
|
175
|
+
const endpoint = this.siteScopedEndpoint(siteName, '/categories/associate', { includeSitesSegment: false });
|
|
176
|
+
const path = this.buildPath(endpoint);
|
|
177
|
+
|
|
178
|
+
const result = await this.http.post<{ message: string }>(path, data, { csrfToken });
|
|
179
|
+
|
|
180
|
+
// Invalidate cache after association
|
|
181
|
+
if (this.cache) {
|
|
182
|
+
await this.cache.invalidate({ tags: this.buildCategoryTags(siteName) });
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return result;
|
|
167
186
|
}
|
|
168
187
|
|
|
169
|
-
private buildCategoryTags(siteName: string,
|
|
188
|
+
private buildCategoryTags(siteName: string, extraTag?: string): string[] {
|
|
170
189
|
const tags = new Set<string>(['categories']);
|
|
171
190
|
if (siteName) {
|
|
172
191
|
tags.add(`categories:site:${siteName}`);
|
|
173
192
|
}
|
|
174
|
-
if (
|
|
175
|
-
tags.add(
|
|
193
|
+
if (extraTag) {
|
|
194
|
+
tags.add(extraTag);
|
|
176
195
|
}
|
|
177
196
|
return Array.from(tags.values());
|
|
178
197
|
}
|
package/src/types/index.ts
CHANGED
|
@@ -638,6 +638,7 @@ export interface SiteUserOrder {
|
|
|
638
638
|
export interface RequestOtpRequest {
|
|
639
639
|
email: string;
|
|
640
640
|
waitlist?: boolean; // Mark user as waitlist signup
|
|
641
|
+
metadata?: Record<string, any>; // Optional metadata to set on user creation/update
|
|
641
642
|
}
|
|
642
643
|
|
|
643
644
|
export interface VerifyOtpRequest {
|