perspectapi-ts-sdk 2.8.3 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +46 -114
- package/dist/index.d.ts +46 -114
- package/dist/index.js +74 -112
- package/dist/index.mjs +74 -112
- package/package.json +1 -1
- package/src/client/auth-client.ts +3 -51
- package/src/client/categories-client.ts +126 -107
- package/src/types/index.ts +4 -19
|
@@ -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
|
@@ -29,25 +29,7 @@ export interface PaginatedResponse<T> extends ApiResponse<T[]> {
|
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
// Authentication
|
|
33
|
-
export interface SignUpRequest {
|
|
34
|
-
email: string;
|
|
35
|
-
password: string;
|
|
36
|
-
firstName?: string;
|
|
37
|
-
lastName?: string;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface SignInRequest {
|
|
41
|
-
email: string;
|
|
42
|
-
password: string;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface AuthResponse {
|
|
46
|
-
message: string;
|
|
47
|
-
user?: User;
|
|
48
|
-
token?: string;
|
|
49
|
-
}
|
|
50
|
-
|
|
32
|
+
// Authentication (OTP-based)
|
|
51
33
|
export interface User {
|
|
52
34
|
id: string;
|
|
53
35
|
email: string;
|
|
@@ -480,6 +462,8 @@ export interface CreateCheckoutSessionRequest {
|
|
|
480
462
|
// Either use existing Stripe price ID
|
|
481
463
|
price?: string;
|
|
482
464
|
quantity: number;
|
|
465
|
+
// SKU-based checkout (variant products)
|
|
466
|
+
sku_id?: number;
|
|
483
467
|
// Or define price data inline
|
|
484
468
|
price_data?: {
|
|
485
469
|
currency: string;
|
|
@@ -499,6 +483,7 @@ export interface CreateCheckoutSessionRequest {
|
|
|
499
483
|
cancelUrl?: string; // Alternative naming
|
|
500
484
|
customer_email?: string;
|
|
501
485
|
customerEmail?: string; // Alternative naming
|
|
486
|
+
site_user_id?: string; // Authenticated site user — enables checkout prefill
|
|
502
487
|
currency?: string;
|
|
503
488
|
metadata?: CheckoutMetadata;
|
|
504
489
|
mode?: 'payment' | 'subscription' | 'setup';
|