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.
@@ -0,0 +1,247 @@
1
+ /**
2
+ * Products Management client for PerspectAPI SDK
3
+ */
4
+
5
+ import { BaseClient } from './base-client';
6
+ import type {
7
+ Product,
8
+ CreateProductRequest,
9
+ PaginatedResponse,
10
+ ApiResponse,
11
+ ProductQueryParams,
12
+ } from '../types';
13
+
14
+ export class ProductsClient extends BaseClient {
15
+ constructor(http: any) {
16
+ super(http, '/api/v1');
17
+ }
18
+
19
+ /**
20
+ * Get all products for a site
21
+ */
22
+ async getProducts(siteName: string, params?: ProductQueryParams): Promise<PaginatedResponse<Product>> {
23
+ const normalizeList = (value: string | number | Array<string | number> | undefined): string | undefined => {
24
+ if (value === undefined || value === null) {
25
+ return undefined;
26
+ }
27
+ const values = Array.isArray(value) ? value : [value];
28
+ const normalized = values
29
+ .map(item => String(item).trim())
30
+ .filter(item => item.length > 0);
31
+
32
+ return normalized.length > 0 ? normalized.join(',') : undefined;
33
+ };
34
+
35
+ const normalizedParams: ProductQueryParams | undefined = params ? { ...params } : undefined;
36
+
37
+ if (normalizedParams) {
38
+ const normalizedCategories = normalizeList(normalizedParams.category as any);
39
+ if (normalizedCategories !== undefined) {
40
+ normalizedParams.category = normalizedCategories;
41
+ } else {
42
+ delete normalizedParams.category;
43
+ }
44
+
45
+ const normalizedCategoryIds = normalizeList(normalizedParams.category_id as any);
46
+ if (normalizedCategoryIds !== undefined) {
47
+ normalizedParams.category_id = normalizedCategoryIds;
48
+ } else {
49
+ delete normalizedParams.category_id;
50
+ }
51
+ }
52
+
53
+ return this.http.get(this.buildPath(this.siteScopedEndpoint(siteName, '/products')), normalizedParams);
54
+ }
55
+
56
+ /**
57
+ * Get product by ID
58
+ */
59
+ async getProductById(id: number): Promise<ApiResponse<Product>> {
60
+ return this.getSingle<Product>(`/products/${id}`);
61
+ }
62
+
63
+ /**
64
+ * Get product by SKU
65
+ */
66
+ async getProductBySku(sku: string): Promise<ApiResponse<Product>> {
67
+ return this.getSingle<Product>(`/products/sku/${sku}`);
68
+ }
69
+
70
+ /**
71
+ * Get product by slug and site name
72
+ */
73
+ async getProductBySlug(siteName: string, slug: string): Promise<ApiResponse<Product & { variants?: any[] }>> {
74
+ return this.http.get(this.buildPath(
75
+ this.siteScopedEndpoint(siteName, `/products/slug/${encodeURIComponent(slug)}`)
76
+ ));
77
+ }
78
+
79
+ /**
80
+ * Create new product
81
+ */
82
+ async createProduct(data: CreateProductRequest): Promise<ApiResponse<Product>> {
83
+ return this.create<CreateProductRequest, Product>('/products', data);
84
+ }
85
+
86
+ /**
87
+ * Update product
88
+ */
89
+ async updateProduct(id: number, data: Partial<CreateProductRequest>): Promise<ApiResponse<Product>> {
90
+ return this.update<Partial<CreateProductRequest>, Product>(`/products/${id}`, data);
91
+ }
92
+
93
+ /**
94
+ * Delete product
95
+ */
96
+ async deleteProduct(id: number): Promise<ApiResponse<{ message: string }>> {
97
+ return this.delete<{ message: string }>(`/products/${id}`);
98
+ }
99
+
100
+ /**
101
+ * Activate product
102
+ */
103
+ async activateProduct(id: number): Promise<ApiResponse<Product>> {
104
+ return this.patch<{ isActive: boolean }, Product>(`/products/${id}`, { isActive: true });
105
+ }
106
+
107
+ /**
108
+ * Deactivate product
109
+ */
110
+ async deactivateProduct(id: number): Promise<ApiResponse<Product>> {
111
+ return this.patch<{ isActive: boolean }, Product>(`/products/${id}`, { isActive: false });
112
+ }
113
+
114
+ /**
115
+ * Get product variants
116
+ */
117
+ async getProductVariants(id: number): Promise<ApiResponse<Array<{
118
+ id: number;
119
+ name: string;
120
+ sku: string;
121
+ price: number;
122
+ inventory: number;
123
+ attributes: Record<string, any>;
124
+ }>>> {
125
+ return this.getSingle(`/products/${id}/variants`);
126
+ }
127
+
128
+ /**
129
+ * Add product variant
130
+ */
131
+ async addProductVariant(id: number, data: {
132
+ name: string;
133
+ sku: string;
134
+ price: number;
135
+ inventory?: number;
136
+ attributes?: Record<string, any>;
137
+ }): Promise<ApiResponse<{ message: string }>> {
138
+ return this.create(`/products/${id}/variants`, data);
139
+ }
140
+
141
+ /**
142
+ * Update product variant
143
+ */
144
+ async updateProductVariant(id: number, variantId: number, data: {
145
+ name?: string;
146
+ sku?: string;
147
+ price?: number;
148
+ inventory?: number;
149
+ attributes?: Record<string, any>;
150
+ }): Promise<ApiResponse<{ message: string }>> {
151
+ return this.update(`/products/${id}/variants/${variantId}`, data);
152
+ }
153
+
154
+ /**
155
+ * Delete product variant
156
+ */
157
+ async deleteProductVariant(id: number, variantId: number): Promise<ApiResponse<{ message: string }>> {
158
+ return this.delete<{ message: string }>(`/products/${id}/variants/${variantId}`);
159
+ }
160
+
161
+ /**
162
+ * Get product inventory
163
+ */
164
+ async getProductInventory(id: number): Promise<ApiResponse<{
165
+ totalStock: number;
166
+ availableStock: number;
167
+ reservedStock: number;
168
+ lowStockThreshold: number;
169
+ isLowStock: boolean;
170
+ }>> {
171
+ return this.getSingle(`/products/${id}/inventory`);
172
+ }
173
+
174
+ /**
175
+ * Update product inventory
176
+ */
177
+ async updateProductInventory(id: number, data: {
178
+ quantity: number;
179
+ operation: 'add' | 'subtract' | 'set';
180
+ reason?: string;
181
+ }): Promise<ApiResponse<{ message: string; newQuantity: number }>> {
182
+ return this.create(`/products/${id}/inventory`, data);
183
+ }
184
+
185
+ /**
186
+ * Get product categories
187
+ */
188
+ async getProductCategories(id: number): Promise<ApiResponse<Array<{
189
+ id: number;
190
+ name: string;
191
+ slug: string;
192
+ }>>> {
193
+ return this.getSingle(`/products/${id}/categories`);
194
+ }
195
+
196
+ /**
197
+ * Add product to category
198
+ */
199
+ async addProductToCategory(id: number, categoryId: number): Promise<ApiResponse<{ message: string }>> {
200
+ return this.create(`/products/${id}/categories`, { categoryId });
201
+ }
202
+
203
+ /**
204
+ * Remove product from category
205
+ */
206
+ async removeProductFromCategory(id: number, categoryId: number): Promise<ApiResponse<{ message: string }>> {
207
+ return this.delete<{ message: string }>(`/products/${id}/categories/${categoryId}`);
208
+ }
209
+
210
+ /**
211
+ * Get products by category slug
212
+ */
213
+ async getProductsByCategorySlug(
214
+ siteName: string,
215
+ categorySlug: string,
216
+ params?: {
217
+ page?: number;
218
+ limit?: number;
219
+ published?: boolean;
220
+ search?: string;
221
+ }
222
+ ): Promise<ApiResponse<{
223
+ data: Product[];
224
+ category: {
225
+ id: number;
226
+ name: string;
227
+ slug: string;
228
+ description?: string;
229
+ };
230
+ meta: {
231
+ count: number;
232
+ limit?: number;
233
+ offset?: number;
234
+ };
235
+ }>> {
236
+ const queryParams = params ? {
237
+ limit: params.limit,
238
+ offset: params.page ? (params.page - 1) * (params.limit || 20) : undefined,
239
+ published: params.published,
240
+ search: params.search
241
+ } : undefined;
242
+
243
+ return this.http.get(this.buildPath(
244
+ this.siteScopedEndpoint(siteName, `/products/category/${encodeURIComponent(categorySlug)}`)
245
+ ), queryParams);
246
+ }
247
+ }
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Sites Management client for PerspectAPI SDK
3
+ */
4
+
5
+ import { BaseClient } from './base-client';
6
+ import type {
7
+ Site,
8
+ CreateSiteRequest,
9
+ PaginatedResponse,
10
+ ApiResponse,
11
+ } from '../types';
12
+
13
+ export class SitesClient extends BaseClient {
14
+ constructor(http: any) {
15
+ super(http, '/api/v1');
16
+ }
17
+
18
+ /**
19
+ * Get all sites
20
+ */
21
+ async getSites(params?: {
22
+ page?: number;
23
+ limit?: number;
24
+ organizationId?: number;
25
+ }): Promise<PaginatedResponse<Site>> {
26
+ return this.getPaginated<Site>('/sites', params);
27
+ }
28
+
29
+ /**
30
+ * Get site by ID
31
+ */
32
+ async getSiteById(id: number): Promise<ApiResponse<Site>> {
33
+ return this.getSingle<Site>(`/sites/${id}`);
34
+ }
35
+
36
+ /**
37
+ * Get site by name
38
+ */
39
+ async getSiteByName(name: string): Promise<ApiResponse<Site>> {
40
+ return this.getSingle<Site>(`/sites/name/${name}`);
41
+ }
42
+
43
+ /**
44
+ * Create new site
45
+ */
46
+ async createSite(data: CreateSiteRequest): Promise<ApiResponse<Site>> {
47
+ return this.create<CreateSiteRequest, Site>('/sites', data);
48
+ }
49
+
50
+ /**
51
+ * Update site
52
+ */
53
+ async updateSite(id: number, data: Partial<CreateSiteRequest>): Promise<ApiResponse<Site>> {
54
+ return this.update<Partial<CreateSiteRequest>, Site>(`/sites/${id}`, data);
55
+ }
56
+
57
+ /**
58
+ * Delete site
59
+ */
60
+ async deleteSite(id: number): Promise<ApiResponse<{ message: string }>> {
61
+ return this.delete<{ message: string }>(`/sites/${id}`);
62
+ }
63
+
64
+ /**
65
+ * Activate site
66
+ */
67
+ async activateSite(id: number): Promise<ApiResponse<Site>> {
68
+ return this.patch<{ isActive: boolean }, Site>(`/sites/${id}`, { isActive: true });
69
+ }
70
+
71
+ /**
72
+ * Deactivate site
73
+ */
74
+ async deactivateSite(id: number): Promise<ApiResponse<Site>> {
75
+ return this.patch<{ isActive: boolean }, Site>(`/sites/${id}`, { isActive: false });
76
+ }
77
+
78
+ /**
79
+ * Get site configuration
80
+ */
81
+ async getSiteConfig(id: number): Promise<ApiResponse<Record<string, any>>> {
82
+ return this.getSingle<Record<string, any>>(`/sites/${id}/config`);
83
+ }
84
+
85
+ /**
86
+ * Update site configuration
87
+ */
88
+ async updateSiteConfig(id: number, config: Record<string, any>): Promise<ApiResponse<Record<string, any>>> {
89
+ return this.update<Record<string, any>>(`/sites/${id}/config`, config);
90
+ }
91
+
92
+ /**
93
+ * Get site analytics
94
+ */
95
+ async getSiteAnalytics(id: number, params?: {
96
+ startDate?: string;
97
+ endDate?: string;
98
+ metrics?: string[];
99
+ }): Promise<ApiResponse<{
100
+ pageViews: number;
101
+ uniqueVisitors: number;
102
+ bounceRate: number;
103
+ avgSessionDuration: number;
104
+ topPages: Array<{ path: string; views: number }>;
105
+ }>> {
106
+ return this.http.get(`/sites/${id}/analytics`, params);
107
+ }
108
+
109
+ /**
110
+ * Get site domains
111
+ */
112
+ async getSiteDomains(id: number): Promise<ApiResponse<Array<{
113
+ domain: string;
114
+ isPrimary: boolean;
115
+ isVerified: boolean;
116
+ createdAt: string;
117
+ }>>> {
118
+ return this.getSingle(`/sites/${id}/domains`);
119
+ }
120
+
121
+ /**
122
+ * Add domain to site
123
+ */
124
+ async addSiteDomain(id: number, data: {
125
+ domain: string;
126
+ isPrimary?: boolean;
127
+ }): Promise<ApiResponse<{ message: string }>> {
128
+ return this.create(`/sites/${id}/domains`, data);
129
+ }
130
+
131
+ /**
132
+ * Remove domain from site
133
+ */
134
+ async removeSiteDomain(id: number, domain: string): Promise<ApiResponse<{ message: string }>> {
135
+ return this.delete<{ message: string }>(`/sites/${id}/domains/${encodeURIComponent(domain)}`);
136
+ }
137
+
138
+ /**
139
+ * Verify domain ownership
140
+ */
141
+ async verifySiteDomain(id: number, domain: string): Promise<ApiResponse<{
142
+ verified: boolean;
143
+ verificationMethod: string;
144
+ verificationValue: string;
145
+ }>> {
146
+ return this.create(`/sites/${id}/domains/${encodeURIComponent(domain)}/verify`, {});
147
+ }
148
+ }
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Webhooks Management client for PerspectAPI SDK
3
+ */
4
+
5
+ import { BaseClient } from './base-client';
6
+ import type {
7
+ Webhook,
8
+ CreateWebhookRequest,
9
+ PaginatedResponse,
10
+ ApiResponse,
11
+ } from '../types';
12
+
13
+ export class WebhooksClient extends BaseClient {
14
+ constructor(http: any) {
15
+ super(http, '/api/v1');
16
+ }
17
+
18
+ /**
19
+ * Get all webhooks
20
+ */
21
+ async getWebhooks(params?: {
22
+ page?: number;
23
+ limit?: number;
24
+ provider?: string;
25
+ isActive?: boolean;
26
+ }): Promise<PaginatedResponse<Webhook>> {
27
+ return this.getPaginated<Webhook>('/webhooks', params);
28
+ }
29
+
30
+ /**
31
+ * Get webhook by ID
32
+ */
33
+ async getWebhookById(id: string): Promise<ApiResponse<Webhook>> {
34
+ return this.getSingle<Webhook>(`/webhooks/${id}`);
35
+ }
36
+
37
+ /**
38
+ * Create new webhook
39
+ */
40
+ async createWebhook(data: CreateWebhookRequest): Promise<ApiResponse<Webhook>> {
41
+ return this.create<CreateWebhookRequest, Webhook>('/webhooks', data);
42
+ }
43
+
44
+ /**
45
+ * Update webhook
46
+ */
47
+ async updateWebhook(id: string, data: Partial<CreateWebhookRequest>): Promise<ApiResponse<Webhook>> {
48
+ return this.update<Partial<CreateWebhookRequest>, Webhook>(`/webhooks/${id}`, data);
49
+ }
50
+
51
+ /**
52
+ * Delete webhook
53
+ */
54
+ async deleteWebhook(id: string): Promise<ApiResponse<{ message: string }>> {
55
+ return this.delete<{ message: string }>(`/webhooks/${id}`);
56
+ }
57
+
58
+ /**
59
+ * Activate webhook
60
+ */
61
+ async activateWebhook(id: string): Promise<ApiResponse<Webhook>> {
62
+ return this.patch<{ isActive: boolean }, Webhook>(`/webhooks/${id}`, { isActive: true });
63
+ }
64
+
65
+ /**
66
+ * Deactivate webhook
67
+ */
68
+ async deactivateWebhook(id: string): Promise<ApiResponse<Webhook>> {
69
+ return this.patch<{ isActive: boolean }, Webhook>(`/webhooks/${id}`, { isActive: false });
70
+ }
71
+
72
+ /**
73
+ * Test webhook
74
+ */
75
+ async testWebhook(id: string, data?: any): Promise<ApiResponse<{
76
+ success: boolean;
77
+ statusCode: number;
78
+ response: any;
79
+ duration: number;
80
+ }>> {
81
+ return this.create(`/webhooks/${id}/test`, data || {});
82
+ }
83
+
84
+ /**
85
+ * Get webhook events
86
+ */
87
+ async getWebhookEvents(id: string, params?: {
88
+ page?: number;
89
+ limit?: number;
90
+ status?: 'pending' | 'processing' | 'completed' | 'failed';
91
+ startDate?: string;
92
+ endDate?: string;
93
+ }): Promise<PaginatedResponse<{
94
+ id: string;
95
+ eventType: string;
96
+ status: string;
97
+ payload: any;
98
+ response?: any;
99
+ attempts: number;
100
+ createdAt: string;
101
+ processedAt?: string;
102
+ }>> {
103
+ return this.getPaginated(`/webhooks/${id}/events`, params);
104
+ }
105
+
106
+ /**
107
+ * Get webhook logs
108
+ */
109
+ async getWebhookLogs(id: string, params?: {
110
+ page?: number;
111
+ limit?: number;
112
+ level?: 'info' | 'warn' | 'error';
113
+ startDate?: string;
114
+ endDate?: string;
115
+ }): Promise<PaginatedResponse<{
116
+ id: string;
117
+ level: string;
118
+ message: string;
119
+ metadata?: any;
120
+ createdAt: string;
121
+ }>> {
122
+ return this.getPaginated(`/webhooks/${id}/logs`, params);
123
+ }
124
+
125
+ /**
126
+ * Get webhook statistics
127
+ */
128
+ async getWebhookStats(id?: string): Promise<ApiResponse<{
129
+ totalWebhooks: number;
130
+ activeWebhooks: number;
131
+ totalEvents: number;
132
+ successfulEvents: number;
133
+ failedEvents: number;
134
+ averageResponseTime: number;
135
+ eventsByProvider: Record<string, number>;
136
+ recentActivity: Array<{
137
+ date: string;
138
+ events: number;
139
+ successes: number;
140
+ failures: number;
141
+ }>;
142
+ }>> {
143
+ const endpoint = id ? `/webhooks/${id}/stats` : '/webhooks/stats';
144
+ return this.getSingle(endpoint);
145
+ }
146
+
147
+ /**
148
+ * Get supported webhook providers
149
+ */
150
+ async getWebhookProviders(): Promise<ApiResponse<Array<{
151
+ name: string;
152
+ displayName: string;
153
+ description: string;
154
+ supportedEvents: string[];
155
+ configurationFields: Array<{
156
+ name: string;
157
+ type: string;
158
+ required: boolean;
159
+ description: string;
160
+ }>;
161
+ }>>> {
162
+ return this.getSingle('/webhooks/providers');
163
+ }
164
+
165
+ /**
166
+ * Retry failed webhook event
167
+ */
168
+ async retryWebhookEvent(webhookId: string, eventId: string): Promise<ApiResponse<{
169
+ success: boolean;
170
+ message: string;
171
+ }>> {
172
+ return this.create(`/webhooks/${webhookId}/events/${eventId}/retry`, {});
173
+ }
174
+
175
+ /**
176
+ * Bulk retry failed webhook events
177
+ */
178
+ async bulkRetryWebhookEvents(webhookId: string, eventIds: string[]): Promise<ApiResponse<{
179
+ success: boolean;
180
+ retriedCount: number;
181
+ failedCount: number;
182
+ }>> {
183
+ return this.create(`/webhooks/${webhookId}/events/bulk-retry`, { eventIds });
184
+ }
185
+
186
+ /**
187
+ * Get webhook delivery attempts
188
+ */
189
+ async getWebhookDeliveryAttempts(webhookId: string, eventId: string): Promise<ApiResponse<Array<{
190
+ id: string;
191
+ attempt: number;
192
+ statusCode: number;
193
+ response: any;
194
+ duration: number;
195
+ createdAt: string;
196
+ }>>> {
197
+ return this.getSingle(`/webhooks/${webhookId}/events/${eventId}/attempts`);
198
+ }
199
+ }
package/src/index.ts ADDED
@@ -0,0 +1,74 @@
1
+ /**
2
+ * PerspectAPI TypeScript SDK
3
+ * Cloudflare Workers compatible SDK for PerspectAPI
4
+ */
5
+
6
+ // Main client
7
+ export { PerspectApiClient, createPerspectApiClient } from './perspect-api-client';
8
+ export { default } from './perspect-api-client';
9
+
10
+ // Individual clients (for advanced usage)
11
+ export { AuthClient } from './client/auth-client';
12
+ export { ContentClient } from './client/content-client';
13
+ export { ApiKeysClient } from './client/api-keys-client';
14
+ export { OrganizationsClient } from './client/organizations-client';
15
+ export { SitesClient } from './client/sites-client';
16
+ export { ProductsClient } from './client/products-client';
17
+ export { CategoriesClient } from './client/categories-client';
18
+ export { WebhooksClient } from './client/webhooks-client';
19
+ export { CheckoutClient } from './client/checkout-client';
20
+ export { ContactClient } from './client/contact-client';
21
+
22
+ // Base classes
23
+ export { BaseClient } from './client/base-client';
24
+
25
+ // Utilities
26
+ export { HttpClient, createApiError } from './utils/http-client';
27
+
28
+ // High-level data loaders
29
+ export {
30
+ loadProducts,
31
+ loadProductBySlug,
32
+ loadPosts,
33
+ loadPages,
34
+ loadContentBySlug,
35
+ loadAllContent,
36
+ createCheckoutSession,
37
+ transformProduct,
38
+ transformContent
39
+ } from './loaders';
40
+
41
+ export type {
42
+ LoaderOptions,
43
+ LoadProductsOptions,
44
+ LoadProductBySlugOptions,
45
+ LoadContentOptions,
46
+ LoadContentBySlugOptions,
47
+ CheckoutSessionOptions,
48
+ LoaderLogger
49
+ } from './loaders';
50
+
51
+ // Types
52
+ export type * from './types';
53
+
54
+ // Re-export commonly used types for convenience
55
+ export type {
56
+ PerspectApiConfig,
57
+ ApiResponse,
58
+ PaginatedResponse,
59
+ ApiError,
60
+ User,
61
+ Content,
62
+ Product,
63
+ ProductQueryParams,
64
+ MediaItem,
65
+ BlogPost,
66
+ Category,
67
+ Organization,
68
+ Site,
69
+ ApiKey,
70
+ Webhook,
71
+ ContactSubmission,
72
+ CheckoutSession,
73
+ PaymentGateway,
74
+ } from './types';