perspectapi-ts-sdk 1.1.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/LICENSE +21 -0
- package/README.md +515 -0
- package/dist/index.d.mts +1770 -0
- package/dist/index.d.ts +1770 -0
- package/dist/index.js +1777 -0
- package/dist/index.mjs +1727 -0
- package/package.json +69 -0
- package/src/client/api-keys-client.ts +103 -0
- package/src/client/auth-client.ts +87 -0
- package/src/client/base-client.ts +100 -0
- package/src/client/categories-client.ts +151 -0
- package/src/client/checkout-client.ts +249 -0
- package/src/client/contact-client.ts +203 -0
- package/src/client/content-client.ts +112 -0
- package/src/client/organizations-client.ts +106 -0
- package/src/client/products-client.ts +247 -0
- package/src/client/sites-client.ts +148 -0
- package/src/client/webhooks-client.ts +199 -0
- package/src/index.ts +74 -0
- package/src/loaders.ts +644 -0
- package/src/perspect-api-client.ts +179 -0
- package/src/types/index.ts +399 -0
- package/src/utils/http-client.ts +268 -0
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "perspectapi-ts-sdk",
|
|
3
|
+
"version": "1.1.1",
|
|
4
|
+
"description": "TypeScript SDK for PerspectAPI - Cloudflare Workers compatible",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.mjs",
|
|
11
|
+
"require": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist/**/*",
|
|
17
|
+
"src/**/*",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
22
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
23
|
+
"test": "node scripts/test-runner.js",
|
|
24
|
+
"test:all": "vitest run",
|
|
25
|
+
"test:watch": "node scripts/test-runner.js watch",
|
|
26
|
+
"test:coverage": "node scripts/test-runner.js coverage",
|
|
27
|
+
"test:unit": "node scripts/test-runner.js unit",
|
|
28
|
+
"test:integration": "node scripts/test-runner.js integration",
|
|
29
|
+
"test:types": "node scripts/test-runner.js types",
|
|
30
|
+
"test:ci": "node scripts/test-runner.js ci",
|
|
31
|
+
"lint": "eslint src --ext .ts",
|
|
32
|
+
"typecheck": "tsc --noEmit",
|
|
33
|
+
"prepublishOnly": "npm run build && npm run test:ci"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"perspectapi",
|
|
37
|
+
"sdk",
|
|
38
|
+
"typescript",
|
|
39
|
+
"cloudflare-workers",
|
|
40
|
+
"headless-cms",
|
|
41
|
+
"api-client"
|
|
42
|
+
],
|
|
43
|
+
"author": "PerspectAPI Team",
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"zod": "^3.22.0"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^20.0.0",
|
|
50
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
51
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
52
|
+
"@vitest/coverage-v8": "^1.6.1",
|
|
53
|
+
"eslint": "^8.0.0",
|
|
54
|
+
"tsup": "^8.0.0",
|
|
55
|
+
"typescript": "^5.0.0",
|
|
56
|
+
"vitest": "^1.0.0"
|
|
57
|
+
},
|
|
58
|
+
"engines": {
|
|
59
|
+
"node": ">=18.0.0"
|
|
60
|
+
},
|
|
61
|
+
"repository": {
|
|
62
|
+
"type": "git",
|
|
63
|
+
"url": "https://github.com/perspectapi/perspectapi-ts-sdk.git"
|
|
64
|
+
},
|
|
65
|
+
"bugs": {
|
|
66
|
+
"url": "https://github.com/perspectapi/perspectapi-ts-sdk/issues"
|
|
67
|
+
},
|
|
68
|
+
"homepage": "https://github.com/perspectapi/perspectapi-ts-sdk#readme"
|
|
69
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Keys Management client for PerspectAPI SDK
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { BaseClient } from './base-client';
|
|
6
|
+
import type {
|
|
7
|
+
ApiKey,
|
|
8
|
+
CreateApiKeyRequest,
|
|
9
|
+
UpdateApiKeyRequest,
|
|
10
|
+
PaginatedResponse,
|
|
11
|
+
ApiResponse,
|
|
12
|
+
} from '../types';
|
|
13
|
+
|
|
14
|
+
export class ApiKeysClient extends BaseClient {
|
|
15
|
+
constructor(http: any) {
|
|
16
|
+
super(http, '/api/v1');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Get all API keys
|
|
21
|
+
*/
|
|
22
|
+
async getApiKeys(params?: { page?: number; limit?: number }): Promise<PaginatedResponse<ApiKey>> {
|
|
23
|
+
return this.getPaginated<ApiKey>('/keys', params);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get API key by ID
|
|
28
|
+
*/
|
|
29
|
+
async getApiKeyById(id: string): Promise<ApiResponse<ApiKey>> {
|
|
30
|
+
return this.getSingle<ApiKey>(`/keys/${id}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Create new API key
|
|
35
|
+
*/
|
|
36
|
+
async createApiKey(data: CreateApiKeyRequest): Promise<ApiResponse<ApiKey & { key: string }>> {
|
|
37
|
+
return this.create<CreateApiKeyRequest, ApiKey & { key: string }>('/keys', data);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Update API key
|
|
42
|
+
*/
|
|
43
|
+
async updateApiKey(id: string, data: UpdateApiKeyRequest): Promise<ApiResponse<ApiKey>> {
|
|
44
|
+
return this.update<UpdateApiKeyRequest, ApiKey>(`/keys/${id}`, data);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Delete API key
|
|
49
|
+
*/
|
|
50
|
+
async deleteApiKey(id: string): Promise<ApiResponse<{ message: string }>> {
|
|
51
|
+
return this.delete<{ message: string }>(`/keys/${id}`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Regenerate API key
|
|
56
|
+
*/
|
|
57
|
+
async regenerateApiKey(id: string): Promise<ApiResponse<ApiKey & { key: string }>> {
|
|
58
|
+
return this.create<Record<string, never>, ApiKey & { key: string }>(`/keys/${id}/regenerate`, {});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Activate API key
|
|
63
|
+
*/
|
|
64
|
+
async activateApiKey(id: string): Promise<ApiResponse<ApiKey>> {
|
|
65
|
+
return this.patch<{ isActive: boolean }, ApiKey>(`/keys/${id}`, { isActive: true });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Deactivate API key
|
|
70
|
+
*/
|
|
71
|
+
async deactivateApiKey(id: string): Promise<ApiResponse<ApiKey>> {
|
|
72
|
+
return this.patch<{ isActive: boolean }, ApiKey>(`/keys/${id}`, { isActive: false });
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Get API key usage statistics
|
|
77
|
+
*/
|
|
78
|
+
async getApiKeyStats(id: string): Promise<ApiResponse<{
|
|
79
|
+
totalRequests: number;
|
|
80
|
+
requestsToday: number;
|
|
81
|
+
requestsThisMonth: number;
|
|
82
|
+
lastUsedAt?: string;
|
|
83
|
+
}>> {
|
|
84
|
+
return this.getSingle(`/keys/${id}/stats`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Test API key validity
|
|
89
|
+
*/
|
|
90
|
+
async testApiKey(key: string): Promise<ApiResponse<{
|
|
91
|
+
valid: boolean;
|
|
92
|
+
keyId?: string;
|
|
93
|
+
permissions?: string[];
|
|
94
|
+
expiresAt?: string;
|
|
95
|
+
}>> {
|
|
96
|
+
return this.create<{ key: string }, {
|
|
97
|
+
valid: boolean;
|
|
98
|
+
keyId?: string;
|
|
99
|
+
permissions?: string[];
|
|
100
|
+
expiresAt?: string;
|
|
101
|
+
}>('/keys/test', { key });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication client for PerspectAPI SDK
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { BaseClient } from './base-client';
|
|
6
|
+
import type {
|
|
7
|
+
SignUpRequest,
|
|
8
|
+
SignInRequest,
|
|
9
|
+
AuthResponse,
|
|
10
|
+
User,
|
|
11
|
+
ApiResponse,
|
|
12
|
+
} from '../types';
|
|
13
|
+
|
|
14
|
+
export class AuthClient extends BaseClient {
|
|
15
|
+
constructor(http: any) {
|
|
16
|
+
super(http, '/api/v1');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Get CSRF token
|
|
21
|
+
*/
|
|
22
|
+
async getCsrfToken(): Promise<ApiResponse<{ token: string }>> {
|
|
23
|
+
return this.http.get<{ token: string }>(this.buildPath('/csrf'));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Sign up a new user
|
|
28
|
+
*/
|
|
29
|
+
async signUp(data: SignUpRequest): Promise<ApiResponse<{ message: string; userId: string }>> {
|
|
30
|
+
return this.create<SignUpRequest, { message: string; userId: string }>('/signup', data);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Sign in user
|
|
35
|
+
*/
|
|
36
|
+
async signIn(data: SignInRequest): Promise<ApiResponse<AuthResponse>> {
|
|
37
|
+
const response = await this.create<SignInRequest, AuthResponse>('/authenticate', data);
|
|
38
|
+
|
|
39
|
+
// Update HTTP client with JWT if provided
|
|
40
|
+
if (response.data && 'token' in response.data && response.data.token) {
|
|
41
|
+
this.http.setAuth(response.data.token);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return response;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Activate user account
|
|
49
|
+
*/
|
|
50
|
+
async activateAccount(activationKey: string): Promise<ApiResponse<{ message: string }>> {
|
|
51
|
+
return this.getSingle<{ message: string }>(`/activate/${activationKey}`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Request password reset
|
|
56
|
+
*/
|
|
57
|
+
async forgotPassword(email: string): Promise<ApiResponse<{ message: string }>> {
|
|
58
|
+
return this.create<{ email: string }, { message: string }>('/forgotpassword', { email });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Reset password with token
|
|
63
|
+
*/
|
|
64
|
+
async resetPassword(
|
|
65
|
+
resetToken: string,
|
|
66
|
+
password: string
|
|
67
|
+
): Promise<ApiResponse<{ message: string }>> {
|
|
68
|
+
return this.create<{ password: string }, { message: string }>(
|
|
69
|
+
`/passwordreset/${resetToken}`,
|
|
70
|
+
{ password }
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Get current user profile
|
|
76
|
+
*/
|
|
77
|
+
async getUserProfile(): Promise<ApiResponse<{ user: User }>> {
|
|
78
|
+
return this.getSingle<{ user: User }>('/userprofile');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Sign out (clear local auth)
|
|
83
|
+
*/
|
|
84
|
+
signOut(): void {
|
|
85
|
+
this.http.clearAuth();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base client class for PerspectAPI SDK
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { HttpClient } from '../utils/http-client';
|
|
6
|
+
import type { ApiResponse } from '../types';
|
|
7
|
+
|
|
8
|
+
export abstract class BaseClient {
|
|
9
|
+
protected http: HttpClient;
|
|
10
|
+
protected basePath: string;
|
|
11
|
+
|
|
12
|
+
constructor(http: HttpClient, basePath: string) {
|
|
13
|
+
this.http = http;
|
|
14
|
+
this.basePath = basePath;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Build a site-scoped endpoint relative to the API base path
|
|
19
|
+
*/
|
|
20
|
+
protected siteScopedEndpoint(
|
|
21
|
+
siteName: string,
|
|
22
|
+
endpoint = '',
|
|
23
|
+
options?: { includeSitesSegment?: boolean }
|
|
24
|
+
): string {
|
|
25
|
+
if (!siteName || !siteName.trim()) {
|
|
26
|
+
throw new Error('siteName is required');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const encodedSiteName = encodeURIComponent(siteName.trim());
|
|
30
|
+
const cleanEndpoint = endpoint.replace(/^\//, '');
|
|
31
|
+
const includeSitesSegment = options?.includeSitesSegment ?? true;
|
|
32
|
+
const baseSegment = includeSitesSegment ? `sites/${encodedSiteName}` : encodedSiteName;
|
|
33
|
+
const suffix = cleanEndpoint ? `/${cleanEndpoint}` : '';
|
|
34
|
+
|
|
35
|
+
return `/${baseSegment}${suffix}`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Build endpoint path
|
|
40
|
+
*/
|
|
41
|
+
protected buildPath(endpoint: string): string {
|
|
42
|
+
const cleanBasePath = this.basePath.replace(/\/$/, '');
|
|
43
|
+
const cleanEndpoint = endpoint.replace(/^\//, '');
|
|
44
|
+
return `${cleanBasePath}/${cleanEndpoint}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Handle paginated responses
|
|
49
|
+
*/
|
|
50
|
+
protected async getPaginated<T>(
|
|
51
|
+
endpoint: string,
|
|
52
|
+
params?: Record<string, any>
|
|
53
|
+
): Promise<ApiResponse<T[]>> {
|
|
54
|
+
return this.http.get<T[]>(this.buildPath(endpoint), params);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Handle single resource responses
|
|
59
|
+
*/
|
|
60
|
+
protected async getSingle<T>(endpoint: string): Promise<ApiResponse<T>> {
|
|
61
|
+
return this.http.get<T>(this.buildPath(endpoint));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Handle create operations
|
|
66
|
+
*/
|
|
67
|
+
protected async create<T, R = T>(
|
|
68
|
+
endpoint: string,
|
|
69
|
+
data: T
|
|
70
|
+
): Promise<ApiResponse<R>> {
|
|
71
|
+
return this.http.post<R>(this.buildPath(endpoint), data);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Handle update operations
|
|
76
|
+
*/
|
|
77
|
+
protected async update<T, R = T>(
|
|
78
|
+
endpoint: string,
|
|
79
|
+
data: T
|
|
80
|
+
): Promise<ApiResponse<R>> {
|
|
81
|
+
return this.http.put<R>(this.buildPath(endpoint), data);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Handle partial update operations
|
|
86
|
+
*/
|
|
87
|
+
protected async patch<T, R = T>(
|
|
88
|
+
endpoint: string,
|
|
89
|
+
data: T
|
|
90
|
+
): Promise<ApiResponse<R>> {
|
|
91
|
+
return this.http.patch<R>(this.buildPath(endpoint), data);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Handle delete operations
|
|
96
|
+
*/
|
|
97
|
+
protected async delete<T = any>(endpoint: string): Promise<ApiResponse<T>> {
|
|
98
|
+
return this.http.delete<T>(this.buildPath(endpoint));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Categories Management client for PerspectAPI SDK
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { BaseClient } from './base-client';
|
|
6
|
+
import type {
|
|
7
|
+
Category,
|
|
8
|
+
CreateCategoryRequest,
|
|
9
|
+
PaginatedResponse,
|
|
10
|
+
ApiResponse,
|
|
11
|
+
} from '../types';
|
|
12
|
+
|
|
13
|
+
export class CategoriesClient extends BaseClient {
|
|
14
|
+
constructor(http: any) {
|
|
15
|
+
super(http, '/api/v1');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Get all categories
|
|
20
|
+
*/
|
|
21
|
+
async getCategories(params?: {
|
|
22
|
+
page?: number;
|
|
23
|
+
limit?: number;
|
|
24
|
+
parentId?: number;
|
|
25
|
+
organizationId?: number;
|
|
26
|
+
}): Promise<PaginatedResponse<Category>> {
|
|
27
|
+
return this.getPaginated<Category>('/categories', params);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Get category by ID
|
|
32
|
+
*/
|
|
33
|
+
async getCategoryById(id: number): Promise<ApiResponse<Category>> {
|
|
34
|
+
return this.getSingle<Category>(`/categories/${id}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Get category by slug
|
|
39
|
+
*/
|
|
40
|
+
async getCategoryBySlug(slug: string): Promise<ApiResponse<Category>> {
|
|
41
|
+
return this.getSingle<Category>(`/categories/slug/${slug}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get product category by slug (for products)
|
|
46
|
+
*/
|
|
47
|
+
async getProductCategoryBySlug(siteName: string, slug: string): Promise<ApiResponse<Category>> {
|
|
48
|
+
return this.http.get(this.buildPath(
|
|
49
|
+
this.siteScopedEndpoint(siteName, `/product_category/slug/${encodeURIComponent(slug)}`)
|
|
50
|
+
));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Create new category
|
|
55
|
+
*/
|
|
56
|
+
async createCategory(data: CreateCategoryRequest): Promise<ApiResponse<Category>> {
|
|
57
|
+
return this.create<CreateCategoryRequest, Category>('/categories', data);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Update category
|
|
62
|
+
*/
|
|
63
|
+
async updateCategory(id: number, data: Partial<CreateCategoryRequest>): Promise<ApiResponse<Category>> {
|
|
64
|
+
return this.update<Partial<CreateCategoryRequest>, Category>(`/categories/${id}`, data);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Delete category
|
|
69
|
+
*/
|
|
70
|
+
async deleteCategory(id: number): Promise<ApiResponse<{ message: string }>> {
|
|
71
|
+
return this.delete<{ message: string }>(`/categories/${id}`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Get category tree (hierarchical structure)
|
|
76
|
+
*/
|
|
77
|
+
async getCategoryTree(rootId?: number): Promise<ApiResponse<Array<Category & {
|
|
78
|
+
children: Category[];
|
|
79
|
+
}>>> {
|
|
80
|
+
const endpoint = rootId ? `/categories/tree/${rootId}` : '/categories/tree';
|
|
81
|
+
return this.getSingle(endpoint);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Get category children
|
|
86
|
+
*/
|
|
87
|
+
async getCategoryChildren(id: number): Promise<ApiResponse<Category[]>> {
|
|
88
|
+
return this.getSingle<Category[]>(`/categories/${id}/children`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Get category parent
|
|
93
|
+
*/
|
|
94
|
+
async getCategoryParent(id: number): Promise<ApiResponse<Category | null>> {
|
|
95
|
+
return this.getSingle<Category | null>(`/categories/${id}/parent`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Move category to new parent
|
|
100
|
+
*/
|
|
101
|
+
async moveCategoryToParent(id: number, parentId: number | null): Promise<ApiResponse<Category>> {
|
|
102
|
+
return this.patch<{ parentId: number | null }, Category>(`/categories/${id}`, { parentId });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Get category breadcrumb path
|
|
107
|
+
*/
|
|
108
|
+
async getCategoryBreadcrumb(id: number): Promise<ApiResponse<Array<{
|
|
109
|
+
id: number;
|
|
110
|
+
name: string;
|
|
111
|
+
slug: string;
|
|
112
|
+
}>>> {
|
|
113
|
+
return this.getSingle(`/categories/${id}/breadcrumb`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Get category content/products
|
|
118
|
+
*/
|
|
119
|
+
async getCategoryContent(id: number, params?: {
|
|
120
|
+
page?: number;
|
|
121
|
+
limit?: number;
|
|
122
|
+
type?: 'content' | 'products' | 'all';
|
|
123
|
+
}): Promise<ApiResponse<{
|
|
124
|
+
content: any[];
|
|
125
|
+
products: any[];
|
|
126
|
+
total: number;
|
|
127
|
+
}>> {
|
|
128
|
+
return this.http.get(`/categories/${id}/content`, params);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Bulk update category order
|
|
133
|
+
*/
|
|
134
|
+
async updateCategoryOrder(updates: Array<{
|
|
135
|
+
id: number;
|
|
136
|
+
order: number;
|
|
137
|
+
parentId?: number;
|
|
138
|
+
}>): Promise<ApiResponse<{ message: string }>> {
|
|
139
|
+
return this.create('/categories/reorder', { updates });
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Search categories
|
|
144
|
+
*/
|
|
145
|
+
async searchCategories(query: string, params?: {
|
|
146
|
+
limit?: number;
|
|
147
|
+
organizationId?: number;
|
|
148
|
+
}): Promise<ApiResponse<Category[]>> {
|
|
149
|
+
return this.http.get(`/categories/search`, { q: query, ...params });
|
|
150
|
+
}
|
|
151
|
+
}
|