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/dist/index.js
ADDED
|
@@ -0,0 +1,1777 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
ApiKeysClient: () => ApiKeysClient,
|
|
24
|
+
AuthClient: () => AuthClient,
|
|
25
|
+
BaseClient: () => BaseClient,
|
|
26
|
+
CategoriesClient: () => CategoriesClient,
|
|
27
|
+
CheckoutClient: () => CheckoutClient,
|
|
28
|
+
ContactClient: () => ContactClient,
|
|
29
|
+
ContentClient: () => ContentClient,
|
|
30
|
+
HttpClient: () => HttpClient,
|
|
31
|
+
OrganizationsClient: () => OrganizationsClient,
|
|
32
|
+
PerspectApiClient: () => PerspectApiClient,
|
|
33
|
+
ProductsClient: () => ProductsClient,
|
|
34
|
+
SitesClient: () => SitesClient,
|
|
35
|
+
WebhooksClient: () => WebhooksClient,
|
|
36
|
+
createApiError: () => createApiError,
|
|
37
|
+
createCheckoutSession: () => createCheckoutSession,
|
|
38
|
+
createPerspectApiClient: () => createPerspectApiClient,
|
|
39
|
+
default: () => perspect_api_client_default,
|
|
40
|
+
loadAllContent: () => loadAllContent,
|
|
41
|
+
loadContentBySlug: () => loadContentBySlug,
|
|
42
|
+
loadPages: () => loadPages,
|
|
43
|
+
loadPosts: () => loadPosts,
|
|
44
|
+
loadProductBySlug: () => loadProductBySlug,
|
|
45
|
+
loadProducts: () => loadProducts,
|
|
46
|
+
transformContent: () => transformContent,
|
|
47
|
+
transformProduct: () => transformProduct
|
|
48
|
+
});
|
|
49
|
+
module.exports = __toCommonJS(index_exports);
|
|
50
|
+
|
|
51
|
+
// src/utils/http-client.ts
|
|
52
|
+
var HttpClient = class {
|
|
53
|
+
baseUrl;
|
|
54
|
+
defaultHeaders;
|
|
55
|
+
timeout;
|
|
56
|
+
retries;
|
|
57
|
+
constructor(config) {
|
|
58
|
+
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
59
|
+
this.timeout = config.timeout || 3e4;
|
|
60
|
+
this.retries = config.retries || 3;
|
|
61
|
+
this.defaultHeaders = {
|
|
62
|
+
"Content-Type": "application/json",
|
|
63
|
+
"User-Agent": "perspectapi-ts-sdk/1.0.0",
|
|
64
|
+
...config.headers
|
|
65
|
+
};
|
|
66
|
+
if (config.apiKey) {
|
|
67
|
+
this.defaultHeaders["X-API-Key"] = config.apiKey;
|
|
68
|
+
}
|
|
69
|
+
if (config.jwt) {
|
|
70
|
+
this.defaultHeaders["Authorization"] = `Bearer ${config.jwt}`;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Update authentication token
|
|
75
|
+
*/
|
|
76
|
+
setAuth(jwt) {
|
|
77
|
+
this.defaultHeaders["Authorization"] = `Bearer ${jwt}`;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Update API key
|
|
81
|
+
*/
|
|
82
|
+
setApiKey(apiKey) {
|
|
83
|
+
this.defaultHeaders["X-API-Key"] = apiKey;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Remove authentication
|
|
87
|
+
*/
|
|
88
|
+
clearAuth() {
|
|
89
|
+
delete this.defaultHeaders["Authorization"];
|
|
90
|
+
delete this.defaultHeaders["X-API-Key"];
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Make HTTP request with retry logic
|
|
94
|
+
*/
|
|
95
|
+
async request(endpoint, options = {}) {
|
|
96
|
+
const url = this.buildUrl(endpoint, options.params);
|
|
97
|
+
const requestOptions = this.buildRequestOptions(options);
|
|
98
|
+
console.log(`[HTTP Client] Making ${options.method || "GET"} request to: ${url}`);
|
|
99
|
+
console.log(`[HTTP Client] Base URL: ${this.baseUrl}`);
|
|
100
|
+
console.log(`[HTTP Client] Endpoint: ${endpoint}`);
|
|
101
|
+
console.log(`[HTTP Client] Full URL: ${url}`);
|
|
102
|
+
if (options.params) {
|
|
103
|
+
console.log(`[HTTP Client] Query params:`, options.params);
|
|
104
|
+
}
|
|
105
|
+
let lastError;
|
|
106
|
+
for (let attempt = 0; attempt <= this.retries; attempt++) {
|
|
107
|
+
try {
|
|
108
|
+
const response = await this.fetchWithTimeout(url, requestOptions);
|
|
109
|
+
return await this.handleResponse(response);
|
|
110
|
+
} catch (error) {
|
|
111
|
+
lastError = error;
|
|
112
|
+
if (error && typeof error === "object" && "status" in error && typeof error.status === "number" && error.status < 500) {
|
|
113
|
+
throw error;
|
|
114
|
+
}
|
|
115
|
+
if (attempt === this.retries) {
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
await this.delay(Math.pow(2, attempt) * 1e3);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
throw lastError;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* GET request
|
|
125
|
+
*/
|
|
126
|
+
async get(endpoint, params) {
|
|
127
|
+
return this.request(endpoint, { method: "GET", params });
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* POST request
|
|
131
|
+
*/
|
|
132
|
+
async post(endpoint, body) {
|
|
133
|
+
return this.request(endpoint, { method: "POST", body });
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* PUT request
|
|
137
|
+
*/
|
|
138
|
+
async put(endpoint, body) {
|
|
139
|
+
return this.request(endpoint, { method: "PUT", body });
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* DELETE request
|
|
143
|
+
*/
|
|
144
|
+
async delete(endpoint) {
|
|
145
|
+
return this.request(endpoint, { method: "DELETE" });
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* PATCH request
|
|
149
|
+
*/
|
|
150
|
+
async patch(endpoint, body) {
|
|
151
|
+
return this.request(endpoint, { method: "PATCH", body });
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Build full URL with query parameters
|
|
155
|
+
*/
|
|
156
|
+
buildUrl(endpoint, params) {
|
|
157
|
+
const url = `${this.baseUrl}${endpoint.startsWith("/") ? "" : "/"}${endpoint}`;
|
|
158
|
+
if (!params || Object.keys(params).length === 0) {
|
|
159
|
+
return url;
|
|
160
|
+
}
|
|
161
|
+
const searchParams = new URLSearchParams();
|
|
162
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
163
|
+
if (value !== void 0 && value !== null) {
|
|
164
|
+
searchParams.append(key, String(value));
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
return `${url}?${searchParams.toString()}`;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Build request options
|
|
171
|
+
*/
|
|
172
|
+
buildRequestOptions(options) {
|
|
173
|
+
const headers = {
|
|
174
|
+
...this.defaultHeaders,
|
|
175
|
+
...options.headers
|
|
176
|
+
};
|
|
177
|
+
const requestOptions = {
|
|
178
|
+
method: options.method || "GET",
|
|
179
|
+
headers
|
|
180
|
+
};
|
|
181
|
+
if (options.body && options.method !== "GET") {
|
|
182
|
+
if (typeof options.body === "string") {
|
|
183
|
+
requestOptions.body = options.body;
|
|
184
|
+
} else {
|
|
185
|
+
requestOptions.body = JSON.stringify(options.body);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return requestOptions;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Fetch with timeout support
|
|
192
|
+
*/
|
|
193
|
+
async fetchWithTimeout(url, options) {
|
|
194
|
+
const controller = new AbortController();
|
|
195
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
196
|
+
try {
|
|
197
|
+
const response = await fetch(url, {
|
|
198
|
+
...options,
|
|
199
|
+
signal: controller.signal
|
|
200
|
+
});
|
|
201
|
+
return response;
|
|
202
|
+
} finally {
|
|
203
|
+
clearTimeout(timeoutId);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Handle response and errors
|
|
208
|
+
*/
|
|
209
|
+
async handleResponse(response) {
|
|
210
|
+
const contentType = response.headers.get("content-type");
|
|
211
|
+
const isJson = contentType?.includes("application/json");
|
|
212
|
+
let data;
|
|
213
|
+
try {
|
|
214
|
+
data = isJson ? await response.json() : await response.text();
|
|
215
|
+
} catch (error) {
|
|
216
|
+
data = null;
|
|
217
|
+
}
|
|
218
|
+
if (!response.ok) {
|
|
219
|
+
const error = {
|
|
220
|
+
message: data?.error || data?.message || `HTTP ${response.status}: ${response.statusText}`,
|
|
221
|
+
status: response.status,
|
|
222
|
+
code: data?.code,
|
|
223
|
+
details: data
|
|
224
|
+
};
|
|
225
|
+
throw error;
|
|
226
|
+
}
|
|
227
|
+
if (isJson && typeof data === "object") {
|
|
228
|
+
if ("data" in data || "message" in data || "error" in data) {
|
|
229
|
+
return data;
|
|
230
|
+
}
|
|
231
|
+
return { data, success: true };
|
|
232
|
+
}
|
|
233
|
+
return { data, success: true };
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Delay utility for retries
|
|
237
|
+
*/
|
|
238
|
+
delay(ms) {
|
|
239
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
function createApiError(error) {
|
|
243
|
+
if (error instanceof Error) {
|
|
244
|
+
return error;
|
|
245
|
+
}
|
|
246
|
+
if (error && typeof error === "object" && "message" in error) {
|
|
247
|
+
return error;
|
|
248
|
+
}
|
|
249
|
+
return {
|
|
250
|
+
message: "Unknown error occurred",
|
|
251
|
+
details: error
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// src/client/base-client.ts
|
|
256
|
+
var BaseClient = class {
|
|
257
|
+
http;
|
|
258
|
+
basePath;
|
|
259
|
+
constructor(http, basePath) {
|
|
260
|
+
this.http = http;
|
|
261
|
+
this.basePath = basePath;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Build a site-scoped endpoint relative to the API base path
|
|
265
|
+
*/
|
|
266
|
+
siteScopedEndpoint(siteName, endpoint = "", options) {
|
|
267
|
+
if (!siteName || !siteName.trim()) {
|
|
268
|
+
throw new Error("siteName is required");
|
|
269
|
+
}
|
|
270
|
+
const encodedSiteName = encodeURIComponent(siteName.trim());
|
|
271
|
+
const cleanEndpoint = endpoint.replace(/^\//, "");
|
|
272
|
+
const includeSitesSegment = options?.includeSitesSegment ?? true;
|
|
273
|
+
const baseSegment = includeSitesSegment ? `sites/${encodedSiteName}` : encodedSiteName;
|
|
274
|
+
const suffix = cleanEndpoint ? `/${cleanEndpoint}` : "";
|
|
275
|
+
return `/${baseSegment}${suffix}`;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Build endpoint path
|
|
279
|
+
*/
|
|
280
|
+
buildPath(endpoint) {
|
|
281
|
+
const cleanBasePath = this.basePath.replace(/\/$/, "");
|
|
282
|
+
const cleanEndpoint = endpoint.replace(/^\//, "");
|
|
283
|
+
return `${cleanBasePath}/${cleanEndpoint}`;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Handle paginated responses
|
|
287
|
+
*/
|
|
288
|
+
async getPaginated(endpoint, params) {
|
|
289
|
+
return this.http.get(this.buildPath(endpoint), params);
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Handle single resource responses
|
|
293
|
+
*/
|
|
294
|
+
async getSingle(endpoint) {
|
|
295
|
+
return this.http.get(this.buildPath(endpoint));
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Handle create operations
|
|
299
|
+
*/
|
|
300
|
+
async create(endpoint, data) {
|
|
301
|
+
return this.http.post(this.buildPath(endpoint), data);
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Handle update operations
|
|
305
|
+
*/
|
|
306
|
+
async update(endpoint, data) {
|
|
307
|
+
return this.http.put(this.buildPath(endpoint), data);
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Handle partial update operations
|
|
311
|
+
*/
|
|
312
|
+
async patch(endpoint, data) {
|
|
313
|
+
return this.http.patch(this.buildPath(endpoint), data);
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Handle delete operations
|
|
317
|
+
*/
|
|
318
|
+
async delete(endpoint) {
|
|
319
|
+
return this.http.delete(this.buildPath(endpoint));
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
// src/client/auth-client.ts
|
|
324
|
+
var AuthClient = class extends BaseClient {
|
|
325
|
+
constructor(http) {
|
|
326
|
+
super(http, "/api/v1");
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Get CSRF token
|
|
330
|
+
*/
|
|
331
|
+
async getCsrfToken() {
|
|
332
|
+
return this.http.get(this.buildPath("/csrf"));
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Sign up a new user
|
|
336
|
+
*/
|
|
337
|
+
async signUp(data) {
|
|
338
|
+
return this.create("/signup", data);
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Sign in user
|
|
342
|
+
*/
|
|
343
|
+
async signIn(data) {
|
|
344
|
+
const response = await this.create("/authenticate", data);
|
|
345
|
+
if (response.data && "token" in response.data && response.data.token) {
|
|
346
|
+
this.http.setAuth(response.data.token);
|
|
347
|
+
}
|
|
348
|
+
return response;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Activate user account
|
|
352
|
+
*/
|
|
353
|
+
async activateAccount(activationKey) {
|
|
354
|
+
return this.getSingle(`/activate/${activationKey}`);
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Request password reset
|
|
358
|
+
*/
|
|
359
|
+
async forgotPassword(email) {
|
|
360
|
+
return this.create("/forgotpassword", { email });
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Reset password with token
|
|
364
|
+
*/
|
|
365
|
+
async resetPassword(resetToken, password) {
|
|
366
|
+
return this.create(
|
|
367
|
+
`/passwordreset/${resetToken}`,
|
|
368
|
+
{ password }
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Get current user profile
|
|
373
|
+
*/
|
|
374
|
+
async getUserProfile() {
|
|
375
|
+
return this.getSingle("/userprofile");
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Sign out (clear local auth)
|
|
379
|
+
*/
|
|
380
|
+
signOut() {
|
|
381
|
+
this.http.clearAuth();
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
// src/client/content-client.ts
|
|
386
|
+
var ContentClient = class extends BaseClient {
|
|
387
|
+
constructor(http) {
|
|
388
|
+
super(http, "/api/v1");
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Get all content with pagination and filtering for a site
|
|
392
|
+
*/
|
|
393
|
+
async getContent(siteName, params) {
|
|
394
|
+
return this.http.get(this.buildPath(this.siteScopedEndpoint(siteName)), params);
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Get content by ID
|
|
398
|
+
*/
|
|
399
|
+
async getContentById(id) {
|
|
400
|
+
return this.getSingle(`/content/${id}`);
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Get content by slug for a site
|
|
404
|
+
*/
|
|
405
|
+
async getContentBySlug(siteName, slug) {
|
|
406
|
+
return this.http.get(this.buildPath(
|
|
407
|
+
this.siteScopedEndpoint(siteName, `/slug/${encodeURIComponent(slug)}`)
|
|
408
|
+
));
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Create new content
|
|
412
|
+
*/
|
|
413
|
+
async createContent(data) {
|
|
414
|
+
return this.create("/content", data);
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Update content
|
|
418
|
+
*/
|
|
419
|
+
async updateContent(id, data) {
|
|
420
|
+
return this.update(`/content/${id}`, data);
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Partially update content
|
|
424
|
+
*/
|
|
425
|
+
async patchContent(id, data) {
|
|
426
|
+
return this.patch(`/content/${id}`, data);
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Delete content
|
|
430
|
+
*/
|
|
431
|
+
async deleteContent(id) {
|
|
432
|
+
return this.delete(`/content/${id}`);
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Publish content
|
|
436
|
+
*/
|
|
437
|
+
async publishContent(id) {
|
|
438
|
+
return this.create(`/content/${id}/publish`, { action: "publish" });
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Unpublish content
|
|
442
|
+
*/
|
|
443
|
+
async unpublishContent(id) {
|
|
444
|
+
return this.create(`/content/${id}/publish`, { action: "unpublish" });
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Move content to trash
|
|
448
|
+
*/
|
|
449
|
+
async trashContent(id) {
|
|
450
|
+
return this.create(`/content/${id}/publish`, { action: "trash" });
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Restore content from trash
|
|
454
|
+
*/
|
|
455
|
+
async restoreContent(id) {
|
|
456
|
+
return this.create(`/content/${id}/publish`, { action: "restore" });
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Get content revisions
|
|
460
|
+
*/
|
|
461
|
+
async getContentRevisions(id) {
|
|
462
|
+
return this.getSingle(`/content/${id}/revisions`);
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Duplicate content
|
|
466
|
+
*/
|
|
467
|
+
async duplicateContent(id) {
|
|
468
|
+
return this.create(`/content/${id}/duplicate`, {});
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
// src/client/api-keys-client.ts
|
|
473
|
+
var ApiKeysClient = class extends BaseClient {
|
|
474
|
+
constructor(http) {
|
|
475
|
+
super(http, "/api/v1");
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Get all API keys
|
|
479
|
+
*/
|
|
480
|
+
async getApiKeys(params) {
|
|
481
|
+
return this.getPaginated("/keys", params);
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Get API key by ID
|
|
485
|
+
*/
|
|
486
|
+
async getApiKeyById(id) {
|
|
487
|
+
return this.getSingle(`/keys/${id}`);
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Create new API key
|
|
491
|
+
*/
|
|
492
|
+
async createApiKey(data) {
|
|
493
|
+
return this.create("/keys", data);
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Update API key
|
|
497
|
+
*/
|
|
498
|
+
async updateApiKey(id, data) {
|
|
499
|
+
return this.update(`/keys/${id}`, data);
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Delete API key
|
|
503
|
+
*/
|
|
504
|
+
async deleteApiKey(id) {
|
|
505
|
+
return this.delete(`/keys/${id}`);
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Regenerate API key
|
|
509
|
+
*/
|
|
510
|
+
async regenerateApiKey(id) {
|
|
511
|
+
return this.create(`/keys/${id}/regenerate`, {});
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Activate API key
|
|
515
|
+
*/
|
|
516
|
+
async activateApiKey(id) {
|
|
517
|
+
return this.patch(`/keys/${id}`, { isActive: true });
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Deactivate API key
|
|
521
|
+
*/
|
|
522
|
+
async deactivateApiKey(id) {
|
|
523
|
+
return this.patch(`/keys/${id}`, { isActive: false });
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Get API key usage statistics
|
|
527
|
+
*/
|
|
528
|
+
async getApiKeyStats(id) {
|
|
529
|
+
return this.getSingle(`/keys/${id}/stats`);
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Test API key validity
|
|
533
|
+
*/
|
|
534
|
+
async testApiKey(key) {
|
|
535
|
+
return this.create("/keys/test", { key });
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
// src/client/organizations-client.ts
|
|
540
|
+
var OrganizationsClient = class extends BaseClient {
|
|
541
|
+
constructor(http) {
|
|
542
|
+
super(http, "/api/v1");
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* Get all organizations
|
|
546
|
+
*/
|
|
547
|
+
async getOrganizations(params) {
|
|
548
|
+
return this.getPaginated("/organizations", params);
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Get organization by ID
|
|
552
|
+
*/
|
|
553
|
+
async getOrganizationById(id) {
|
|
554
|
+
return this.getSingle(`/organizations/${id}`);
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* Create new organization
|
|
558
|
+
*/
|
|
559
|
+
async createOrganization(data) {
|
|
560
|
+
return this.create("/organizations", data);
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Update organization
|
|
564
|
+
*/
|
|
565
|
+
async updateOrganization(id, data) {
|
|
566
|
+
return this.update(`/organizations/${id}`, data);
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* Delete organization
|
|
570
|
+
*/
|
|
571
|
+
async deleteOrganization(id) {
|
|
572
|
+
return this.delete(`/organizations/${id}`);
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Get organization members
|
|
576
|
+
*/
|
|
577
|
+
async getOrganizationMembers(id) {
|
|
578
|
+
return this.getSingle(`/organizations/${id}/members`);
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* Add member to organization
|
|
582
|
+
*/
|
|
583
|
+
async addOrganizationMember(id, data) {
|
|
584
|
+
return this.create(`/organizations/${id}/members`, data);
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Update organization member role
|
|
588
|
+
*/
|
|
589
|
+
async updateOrganizationMember(id, userId, data) {
|
|
590
|
+
return this.update(`/organizations/${id}/members/${userId}`, data);
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Remove member from organization
|
|
594
|
+
*/
|
|
595
|
+
async removeOrganizationMember(id, userId) {
|
|
596
|
+
return this.delete(`/organizations/${id}/members/${userId}`);
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Get organization settings
|
|
600
|
+
*/
|
|
601
|
+
async getOrganizationSettings(id) {
|
|
602
|
+
return this.getSingle(`/organizations/${id}/settings`);
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Update organization settings
|
|
606
|
+
*/
|
|
607
|
+
async updateOrganizationSettings(id, settings) {
|
|
608
|
+
return this.update(`/organizations/${id}/settings`, settings);
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
// src/client/sites-client.ts
|
|
613
|
+
var SitesClient = class extends BaseClient {
|
|
614
|
+
constructor(http) {
|
|
615
|
+
super(http, "/api/v1");
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Get all sites
|
|
619
|
+
*/
|
|
620
|
+
async getSites(params) {
|
|
621
|
+
return this.getPaginated("/sites", params);
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* Get site by ID
|
|
625
|
+
*/
|
|
626
|
+
async getSiteById(id) {
|
|
627
|
+
return this.getSingle(`/sites/${id}`);
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Get site by name
|
|
631
|
+
*/
|
|
632
|
+
async getSiteByName(name) {
|
|
633
|
+
return this.getSingle(`/sites/name/${name}`);
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Create new site
|
|
637
|
+
*/
|
|
638
|
+
async createSite(data) {
|
|
639
|
+
return this.create("/sites", data);
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Update site
|
|
643
|
+
*/
|
|
644
|
+
async updateSite(id, data) {
|
|
645
|
+
return this.update(`/sites/${id}`, data);
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* Delete site
|
|
649
|
+
*/
|
|
650
|
+
async deleteSite(id) {
|
|
651
|
+
return this.delete(`/sites/${id}`);
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Activate site
|
|
655
|
+
*/
|
|
656
|
+
async activateSite(id) {
|
|
657
|
+
return this.patch(`/sites/${id}`, { isActive: true });
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Deactivate site
|
|
661
|
+
*/
|
|
662
|
+
async deactivateSite(id) {
|
|
663
|
+
return this.patch(`/sites/${id}`, { isActive: false });
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* Get site configuration
|
|
667
|
+
*/
|
|
668
|
+
async getSiteConfig(id) {
|
|
669
|
+
return this.getSingle(`/sites/${id}/config`);
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Update site configuration
|
|
673
|
+
*/
|
|
674
|
+
async updateSiteConfig(id, config) {
|
|
675
|
+
return this.update(`/sites/${id}/config`, config);
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* Get site analytics
|
|
679
|
+
*/
|
|
680
|
+
async getSiteAnalytics(id, params) {
|
|
681
|
+
return this.http.get(`/sites/${id}/analytics`, params);
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* Get site domains
|
|
685
|
+
*/
|
|
686
|
+
async getSiteDomains(id) {
|
|
687
|
+
return this.getSingle(`/sites/${id}/domains`);
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Add domain to site
|
|
691
|
+
*/
|
|
692
|
+
async addSiteDomain(id, data) {
|
|
693
|
+
return this.create(`/sites/${id}/domains`, data);
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Remove domain from site
|
|
697
|
+
*/
|
|
698
|
+
async removeSiteDomain(id, domain) {
|
|
699
|
+
return this.delete(`/sites/${id}/domains/${encodeURIComponent(domain)}`);
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* Verify domain ownership
|
|
703
|
+
*/
|
|
704
|
+
async verifySiteDomain(id, domain) {
|
|
705
|
+
return this.create(`/sites/${id}/domains/${encodeURIComponent(domain)}/verify`, {});
|
|
706
|
+
}
|
|
707
|
+
};
|
|
708
|
+
|
|
709
|
+
// src/client/products-client.ts
|
|
710
|
+
var ProductsClient = class extends BaseClient {
|
|
711
|
+
constructor(http) {
|
|
712
|
+
super(http, "/api/v1");
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Get all products for a site
|
|
716
|
+
*/
|
|
717
|
+
async getProducts(siteName, params) {
|
|
718
|
+
const normalizeList = (value) => {
|
|
719
|
+
if (value === void 0 || value === null) {
|
|
720
|
+
return void 0;
|
|
721
|
+
}
|
|
722
|
+
const values = Array.isArray(value) ? value : [value];
|
|
723
|
+
const normalized = values.map((item) => String(item).trim()).filter((item) => item.length > 0);
|
|
724
|
+
return normalized.length > 0 ? normalized.join(",") : void 0;
|
|
725
|
+
};
|
|
726
|
+
const normalizedParams = params ? { ...params } : void 0;
|
|
727
|
+
if (normalizedParams) {
|
|
728
|
+
const normalizedCategories = normalizeList(normalizedParams.category);
|
|
729
|
+
if (normalizedCategories !== void 0) {
|
|
730
|
+
normalizedParams.category = normalizedCategories;
|
|
731
|
+
} else {
|
|
732
|
+
delete normalizedParams.category;
|
|
733
|
+
}
|
|
734
|
+
const normalizedCategoryIds = normalizeList(normalizedParams.category_id);
|
|
735
|
+
if (normalizedCategoryIds !== void 0) {
|
|
736
|
+
normalizedParams.category_id = normalizedCategoryIds;
|
|
737
|
+
} else {
|
|
738
|
+
delete normalizedParams.category_id;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
return this.http.get(this.buildPath(this.siteScopedEndpoint(siteName, "/products")), normalizedParams);
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* Get product by ID
|
|
745
|
+
*/
|
|
746
|
+
async getProductById(id) {
|
|
747
|
+
return this.getSingle(`/products/${id}`);
|
|
748
|
+
}
|
|
749
|
+
/**
|
|
750
|
+
* Get product by SKU
|
|
751
|
+
*/
|
|
752
|
+
async getProductBySku(sku) {
|
|
753
|
+
return this.getSingle(`/products/sku/${sku}`);
|
|
754
|
+
}
|
|
755
|
+
/**
|
|
756
|
+
* Get product by slug and site name
|
|
757
|
+
*/
|
|
758
|
+
async getProductBySlug(siteName, slug) {
|
|
759
|
+
return this.http.get(this.buildPath(
|
|
760
|
+
this.siteScopedEndpoint(siteName, `/products/slug/${encodeURIComponent(slug)}`)
|
|
761
|
+
));
|
|
762
|
+
}
|
|
763
|
+
/**
|
|
764
|
+
* Create new product
|
|
765
|
+
*/
|
|
766
|
+
async createProduct(data) {
|
|
767
|
+
return this.create("/products", data);
|
|
768
|
+
}
|
|
769
|
+
/**
|
|
770
|
+
* Update product
|
|
771
|
+
*/
|
|
772
|
+
async updateProduct(id, data) {
|
|
773
|
+
return this.update(`/products/${id}`, data);
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* Delete product
|
|
777
|
+
*/
|
|
778
|
+
async deleteProduct(id) {
|
|
779
|
+
return this.delete(`/products/${id}`);
|
|
780
|
+
}
|
|
781
|
+
/**
|
|
782
|
+
* Activate product
|
|
783
|
+
*/
|
|
784
|
+
async activateProduct(id) {
|
|
785
|
+
return this.patch(`/products/${id}`, { isActive: true });
|
|
786
|
+
}
|
|
787
|
+
/**
|
|
788
|
+
* Deactivate product
|
|
789
|
+
*/
|
|
790
|
+
async deactivateProduct(id) {
|
|
791
|
+
return this.patch(`/products/${id}`, { isActive: false });
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* Get product variants
|
|
795
|
+
*/
|
|
796
|
+
async getProductVariants(id) {
|
|
797
|
+
return this.getSingle(`/products/${id}/variants`);
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* Add product variant
|
|
801
|
+
*/
|
|
802
|
+
async addProductVariant(id, data) {
|
|
803
|
+
return this.create(`/products/${id}/variants`, data);
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Update product variant
|
|
807
|
+
*/
|
|
808
|
+
async updateProductVariant(id, variantId, data) {
|
|
809
|
+
return this.update(`/products/${id}/variants/${variantId}`, data);
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* Delete product variant
|
|
813
|
+
*/
|
|
814
|
+
async deleteProductVariant(id, variantId) {
|
|
815
|
+
return this.delete(`/products/${id}/variants/${variantId}`);
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* Get product inventory
|
|
819
|
+
*/
|
|
820
|
+
async getProductInventory(id) {
|
|
821
|
+
return this.getSingle(`/products/${id}/inventory`);
|
|
822
|
+
}
|
|
823
|
+
/**
|
|
824
|
+
* Update product inventory
|
|
825
|
+
*/
|
|
826
|
+
async updateProductInventory(id, data) {
|
|
827
|
+
return this.create(`/products/${id}/inventory`, data);
|
|
828
|
+
}
|
|
829
|
+
/**
|
|
830
|
+
* Get product categories
|
|
831
|
+
*/
|
|
832
|
+
async getProductCategories(id) {
|
|
833
|
+
return this.getSingle(`/products/${id}/categories`);
|
|
834
|
+
}
|
|
835
|
+
/**
|
|
836
|
+
* Add product to category
|
|
837
|
+
*/
|
|
838
|
+
async addProductToCategory(id, categoryId) {
|
|
839
|
+
return this.create(`/products/${id}/categories`, { categoryId });
|
|
840
|
+
}
|
|
841
|
+
/**
|
|
842
|
+
* Remove product from category
|
|
843
|
+
*/
|
|
844
|
+
async removeProductFromCategory(id, categoryId) {
|
|
845
|
+
return this.delete(`/products/${id}/categories/${categoryId}`);
|
|
846
|
+
}
|
|
847
|
+
/**
|
|
848
|
+
* Get products by category slug
|
|
849
|
+
*/
|
|
850
|
+
async getProductsByCategorySlug(siteName, categorySlug, params) {
|
|
851
|
+
const queryParams = params ? {
|
|
852
|
+
limit: params.limit,
|
|
853
|
+
offset: params.page ? (params.page - 1) * (params.limit || 20) : void 0,
|
|
854
|
+
published: params.published,
|
|
855
|
+
search: params.search
|
|
856
|
+
} : void 0;
|
|
857
|
+
return this.http.get(this.buildPath(
|
|
858
|
+
this.siteScopedEndpoint(siteName, `/products/category/${encodeURIComponent(categorySlug)}`)
|
|
859
|
+
), queryParams);
|
|
860
|
+
}
|
|
861
|
+
};
|
|
862
|
+
|
|
863
|
+
// src/client/categories-client.ts
|
|
864
|
+
var CategoriesClient = class extends BaseClient {
|
|
865
|
+
constructor(http) {
|
|
866
|
+
super(http, "/api/v1");
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* Get all categories
|
|
870
|
+
*/
|
|
871
|
+
async getCategories(params) {
|
|
872
|
+
return this.getPaginated("/categories", params);
|
|
873
|
+
}
|
|
874
|
+
/**
|
|
875
|
+
* Get category by ID
|
|
876
|
+
*/
|
|
877
|
+
async getCategoryById(id) {
|
|
878
|
+
return this.getSingle(`/categories/${id}`);
|
|
879
|
+
}
|
|
880
|
+
/**
|
|
881
|
+
* Get category by slug
|
|
882
|
+
*/
|
|
883
|
+
async getCategoryBySlug(slug) {
|
|
884
|
+
return this.getSingle(`/categories/slug/${slug}`);
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
* Get product category by slug (for products)
|
|
888
|
+
*/
|
|
889
|
+
async getProductCategoryBySlug(siteName, slug) {
|
|
890
|
+
return this.http.get(this.buildPath(
|
|
891
|
+
this.siteScopedEndpoint(siteName, `/product_category/slug/${encodeURIComponent(slug)}`)
|
|
892
|
+
));
|
|
893
|
+
}
|
|
894
|
+
/**
|
|
895
|
+
* Create new category
|
|
896
|
+
*/
|
|
897
|
+
async createCategory(data) {
|
|
898
|
+
return this.create("/categories", data);
|
|
899
|
+
}
|
|
900
|
+
/**
|
|
901
|
+
* Update category
|
|
902
|
+
*/
|
|
903
|
+
async updateCategory(id, data) {
|
|
904
|
+
return this.update(`/categories/${id}`, data);
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
907
|
+
* Delete category
|
|
908
|
+
*/
|
|
909
|
+
async deleteCategory(id) {
|
|
910
|
+
return this.delete(`/categories/${id}`);
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* Get category tree (hierarchical structure)
|
|
914
|
+
*/
|
|
915
|
+
async getCategoryTree(rootId) {
|
|
916
|
+
const endpoint = rootId ? `/categories/tree/${rootId}` : "/categories/tree";
|
|
917
|
+
return this.getSingle(endpoint);
|
|
918
|
+
}
|
|
919
|
+
/**
|
|
920
|
+
* Get category children
|
|
921
|
+
*/
|
|
922
|
+
async getCategoryChildren(id) {
|
|
923
|
+
return this.getSingle(`/categories/${id}/children`);
|
|
924
|
+
}
|
|
925
|
+
/**
|
|
926
|
+
* Get category parent
|
|
927
|
+
*/
|
|
928
|
+
async getCategoryParent(id) {
|
|
929
|
+
return this.getSingle(`/categories/${id}/parent`);
|
|
930
|
+
}
|
|
931
|
+
/**
|
|
932
|
+
* Move category to new parent
|
|
933
|
+
*/
|
|
934
|
+
async moveCategoryToParent(id, parentId) {
|
|
935
|
+
return this.patch(`/categories/${id}`, { parentId });
|
|
936
|
+
}
|
|
937
|
+
/**
|
|
938
|
+
* Get category breadcrumb path
|
|
939
|
+
*/
|
|
940
|
+
async getCategoryBreadcrumb(id) {
|
|
941
|
+
return this.getSingle(`/categories/${id}/breadcrumb`);
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* Get category content/products
|
|
945
|
+
*/
|
|
946
|
+
async getCategoryContent(id, params) {
|
|
947
|
+
return this.http.get(`/categories/${id}/content`, params);
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* Bulk update category order
|
|
951
|
+
*/
|
|
952
|
+
async updateCategoryOrder(updates) {
|
|
953
|
+
return this.create("/categories/reorder", { updates });
|
|
954
|
+
}
|
|
955
|
+
/**
|
|
956
|
+
* Search categories
|
|
957
|
+
*/
|
|
958
|
+
async searchCategories(query, params) {
|
|
959
|
+
return this.http.get(`/categories/search`, { q: query, ...params });
|
|
960
|
+
}
|
|
961
|
+
};
|
|
962
|
+
|
|
963
|
+
// src/client/webhooks-client.ts
|
|
964
|
+
var WebhooksClient = class extends BaseClient {
|
|
965
|
+
constructor(http) {
|
|
966
|
+
super(http, "/api/v1");
|
|
967
|
+
}
|
|
968
|
+
/**
|
|
969
|
+
* Get all webhooks
|
|
970
|
+
*/
|
|
971
|
+
async getWebhooks(params) {
|
|
972
|
+
return this.getPaginated("/webhooks", params);
|
|
973
|
+
}
|
|
974
|
+
/**
|
|
975
|
+
* Get webhook by ID
|
|
976
|
+
*/
|
|
977
|
+
async getWebhookById(id) {
|
|
978
|
+
return this.getSingle(`/webhooks/${id}`);
|
|
979
|
+
}
|
|
980
|
+
/**
|
|
981
|
+
* Create new webhook
|
|
982
|
+
*/
|
|
983
|
+
async createWebhook(data) {
|
|
984
|
+
return this.create("/webhooks", data);
|
|
985
|
+
}
|
|
986
|
+
/**
|
|
987
|
+
* Update webhook
|
|
988
|
+
*/
|
|
989
|
+
async updateWebhook(id, data) {
|
|
990
|
+
return this.update(`/webhooks/${id}`, data);
|
|
991
|
+
}
|
|
992
|
+
/**
|
|
993
|
+
* Delete webhook
|
|
994
|
+
*/
|
|
995
|
+
async deleteWebhook(id) {
|
|
996
|
+
return this.delete(`/webhooks/${id}`);
|
|
997
|
+
}
|
|
998
|
+
/**
|
|
999
|
+
* Activate webhook
|
|
1000
|
+
*/
|
|
1001
|
+
async activateWebhook(id) {
|
|
1002
|
+
return this.patch(`/webhooks/${id}`, { isActive: true });
|
|
1003
|
+
}
|
|
1004
|
+
/**
|
|
1005
|
+
* Deactivate webhook
|
|
1006
|
+
*/
|
|
1007
|
+
async deactivateWebhook(id) {
|
|
1008
|
+
return this.patch(`/webhooks/${id}`, { isActive: false });
|
|
1009
|
+
}
|
|
1010
|
+
/**
|
|
1011
|
+
* Test webhook
|
|
1012
|
+
*/
|
|
1013
|
+
async testWebhook(id, data) {
|
|
1014
|
+
return this.create(`/webhooks/${id}/test`, data || {});
|
|
1015
|
+
}
|
|
1016
|
+
/**
|
|
1017
|
+
* Get webhook events
|
|
1018
|
+
*/
|
|
1019
|
+
async getWebhookEvents(id, params) {
|
|
1020
|
+
return this.getPaginated(`/webhooks/${id}/events`, params);
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
1023
|
+
* Get webhook logs
|
|
1024
|
+
*/
|
|
1025
|
+
async getWebhookLogs(id, params) {
|
|
1026
|
+
return this.getPaginated(`/webhooks/${id}/logs`, params);
|
|
1027
|
+
}
|
|
1028
|
+
/**
|
|
1029
|
+
* Get webhook statistics
|
|
1030
|
+
*/
|
|
1031
|
+
async getWebhookStats(id) {
|
|
1032
|
+
const endpoint = id ? `/webhooks/${id}/stats` : "/webhooks/stats";
|
|
1033
|
+
return this.getSingle(endpoint);
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* Get supported webhook providers
|
|
1037
|
+
*/
|
|
1038
|
+
async getWebhookProviders() {
|
|
1039
|
+
return this.getSingle("/webhooks/providers");
|
|
1040
|
+
}
|
|
1041
|
+
/**
|
|
1042
|
+
* Retry failed webhook event
|
|
1043
|
+
*/
|
|
1044
|
+
async retryWebhookEvent(webhookId, eventId) {
|
|
1045
|
+
return this.create(`/webhooks/${webhookId}/events/${eventId}/retry`, {});
|
|
1046
|
+
}
|
|
1047
|
+
/**
|
|
1048
|
+
* Bulk retry failed webhook events
|
|
1049
|
+
*/
|
|
1050
|
+
async bulkRetryWebhookEvents(webhookId, eventIds) {
|
|
1051
|
+
return this.create(`/webhooks/${webhookId}/events/bulk-retry`, { eventIds });
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Get webhook delivery attempts
|
|
1055
|
+
*/
|
|
1056
|
+
async getWebhookDeliveryAttempts(webhookId, eventId) {
|
|
1057
|
+
return this.getSingle(`/webhooks/${webhookId}/events/${eventId}/attempts`);
|
|
1058
|
+
}
|
|
1059
|
+
};
|
|
1060
|
+
|
|
1061
|
+
// src/client/checkout-client.ts
|
|
1062
|
+
var CheckoutClient = class extends BaseClient {
|
|
1063
|
+
constructor(http) {
|
|
1064
|
+
super(http, "/api/v1");
|
|
1065
|
+
}
|
|
1066
|
+
/**
|
|
1067
|
+
* Get CSRF token for a specific site
|
|
1068
|
+
* @param siteName - The site name to get CSRF token for
|
|
1069
|
+
*/
|
|
1070
|
+
async getCsrfToken(siteName) {
|
|
1071
|
+
return this.http.get(`/api/v1/csrf/token/${siteName}`);
|
|
1072
|
+
}
|
|
1073
|
+
/**
|
|
1074
|
+
* Create Stripe checkout session with CSRF protection
|
|
1075
|
+
* @param siteName - The site name for the checkout session
|
|
1076
|
+
* @param data - Checkout session data (can include priceId for single item or line_items for multiple)
|
|
1077
|
+
* @param csrfToken - Optional CSRF token (if not provided, will fetch automatically)
|
|
1078
|
+
*/
|
|
1079
|
+
async createCheckoutSession(siteName, data, csrfToken) {
|
|
1080
|
+
let token = csrfToken;
|
|
1081
|
+
if (!token) {
|
|
1082
|
+
const csrfResponse = await this.getCsrfToken(siteName);
|
|
1083
|
+
const csrfToken2 = csrfResponse.data?.csrf_token;
|
|
1084
|
+
if (!csrfToken2) {
|
|
1085
|
+
throw new Error("Failed to obtain CSRF token");
|
|
1086
|
+
}
|
|
1087
|
+
token = csrfToken2;
|
|
1088
|
+
}
|
|
1089
|
+
return this.http.request(this.buildPath(
|
|
1090
|
+
this.siteScopedEndpoint(siteName, "/checkout/create-session")
|
|
1091
|
+
), {
|
|
1092
|
+
method: "POST",
|
|
1093
|
+
body: data,
|
|
1094
|
+
headers: {
|
|
1095
|
+
"X-CSRF-Token": token
|
|
1096
|
+
}
|
|
1097
|
+
});
|
|
1098
|
+
}
|
|
1099
|
+
/**
|
|
1100
|
+
* Get checkout session by ID
|
|
1101
|
+
*/
|
|
1102
|
+
async getCheckoutSession(sessionId) {
|
|
1103
|
+
return this.getSingle(`/checkout/sessions/${sessionId}`);
|
|
1104
|
+
}
|
|
1105
|
+
/**
|
|
1106
|
+
* Get checkout sessions for organization
|
|
1107
|
+
*/
|
|
1108
|
+
async getCheckoutSessions(params) {
|
|
1109
|
+
return this.getPaginated("/checkout/sessions", params);
|
|
1110
|
+
}
|
|
1111
|
+
/**
|
|
1112
|
+
* Cancel checkout session
|
|
1113
|
+
*/
|
|
1114
|
+
async cancelCheckoutSession(sessionId) {
|
|
1115
|
+
return this.create(`/checkout/sessions/${sessionId}/cancel`, {});
|
|
1116
|
+
}
|
|
1117
|
+
/**
|
|
1118
|
+
* Expire checkout session
|
|
1119
|
+
*/
|
|
1120
|
+
async expireCheckoutSession(sessionId) {
|
|
1121
|
+
return this.create(`/checkout/sessions/${sessionId}/expire`, {});
|
|
1122
|
+
}
|
|
1123
|
+
/**
|
|
1124
|
+
* Get Stripe publishable key
|
|
1125
|
+
*/
|
|
1126
|
+
async getStripePublishableKey() {
|
|
1127
|
+
return this.getSingle("/checkout/stripe/config");
|
|
1128
|
+
}
|
|
1129
|
+
/**
|
|
1130
|
+
* Create payment intent (for custom checkout flows)
|
|
1131
|
+
*/
|
|
1132
|
+
async createPaymentIntent(data) {
|
|
1133
|
+
return this.create("/checkout/payment-intent", data);
|
|
1134
|
+
}
|
|
1135
|
+
/**
|
|
1136
|
+
* Confirm payment intent
|
|
1137
|
+
*/
|
|
1138
|
+
async confirmPaymentIntent(paymentIntentId, data) {
|
|
1139
|
+
return this.create(`/checkout/payment-intent/${paymentIntentId}/confirm`, data);
|
|
1140
|
+
}
|
|
1141
|
+
/**
|
|
1142
|
+
* Get payment methods for customer
|
|
1143
|
+
*/
|
|
1144
|
+
async getPaymentMethods(customerId) {
|
|
1145
|
+
return this.getSingle(`/checkout/customers/${customerId}/payment-methods`);
|
|
1146
|
+
}
|
|
1147
|
+
/**
|
|
1148
|
+
* Create customer
|
|
1149
|
+
*/
|
|
1150
|
+
async createCustomer(data) {
|
|
1151
|
+
return this.create("/checkout/customers", data);
|
|
1152
|
+
}
|
|
1153
|
+
/**
|
|
1154
|
+
* Get customer by ID
|
|
1155
|
+
*/
|
|
1156
|
+
async getCustomer(customerId) {
|
|
1157
|
+
return this.getSingle(`/checkout/customers/${customerId}`);
|
|
1158
|
+
}
|
|
1159
|
+
/**
|
|
1160
|
+
* Update customer
|
|
1161
|
+
*/
|
|
1162
|
+
async updateCustomer(customerId, data) {
|
|
1163
|
+
return this.update(`/checkout/customers/${customerId}`, data);
|
|
1164
|
+
}
|
|
1165
|
+
/**
|
|
1166
|
+
* Get invoices for customer
|
|
1167
|
+
*/
|
|
1168
|
+
async getCustomerInvoices(customerId, params) {
|
|
1169
|
+
return this.getPaginated(`/checkout/customers/${customerId}/invoices`, params);
|
|
1170
|
+
}
|
|
1171
|
+
};
|
|
1172
|
+
|
|
1173
|
+
// src/client/contact-client.ts
|
|
1174
|
+
var ContactClient = class extends BaseClient {
|
|
1175
|
+
constructor(http) {
|
|
1176
|
+
super(http, "/api/v1");
|
|
1177
|
+
}
|
|
1178
|
+
/**
|
|
1179
|
+
* Build a contact endpoint scoped to a site (without /sites prefix)
|
|
1180
|
+
*/
|
|
1181
|
+
contactEndpoint(siteName, endpoint) {
|
|
1182
|
+
return this.siteScopedEndpoint(siteName, endpoint, { includeSitesSegment: false });
|
|
1183
|
+
}
|
|
1184
|
+
/**
|
|
1185
|
+
* Submit contact form
|
|
1186
|
+
*/
|
|
1187
|
+
async submitContact(siteName, data) {
|
|
1188
|
+
return this.create(this.contactEndpoint(siteName, "/contact/submit"), data);
|
|
1189
|
+
}
|
|
1190
|
+
/**
|
|
1191
|
+
* Get contact submission status
|
|
1192
|
+
*/
|
|
1193
|
+
async getContactStatus(siteName, id) {
|
|
1194
|
+
return this.getSingle(this.contactEndpoint(siteName, `/contact/status/${encodeURIComponent(id)}`));
|
|
1195
|
+
}
|
|
1196
|
+
/**
|
|
1197
|
+
* Get all contact submissions (admin only)
|
|
1198
|
+
*/
|
|
1199
|
+
async getContactSubmissions(siteName, params) {
|
|
1200
|
+
return this.getPaginated(this.contactEndpoint(siteName, "/contact/list"), params);
|
|
1201
|
+
}
|
|
1202
|
+
/**
|
|
1203
|
+
* Get contact submission by ID (admin only)
|
|
1204
|
+
*/
|
|
1205
|
+
async getContactSubmissionById(siteName, id) {
|
|
1206
|
+
return this.getSingle(this.contactEndpoint(siteName, `/contact/${encodeURIComponent(id)}`));
|
|
1207
|
+
}
|
|
1208
|
+
/**
|
|
1209
|
+
* Update contact submission status (admin only)
|
|
1210
|
+
*/
|
|
1211
|
+
async updateContactStatus(siteName, id, status, notes) {
|
|
1212
|
+
return this.patch(this.contactEndpoint(siteName, `/contact/${encodeURIComponent(id)}`), { status, notes });
|
|
1213
|
+
}
|
|
1214
|
+
/**
|
|
1215
|
+
* Mark contact as read (admin only)
|
|
1216
|
+
*/
|
|
1217
|
+
async markContactAsRead(siteName, id) {
|
|
1218
|
+
return this.patch(this.contactEndpoint(siteName, `/contact/${encodeURIComponent(id)}`), { status: "read" });
|
|
1219
|
+
}
|
|
1220
|
+
/**
|
|
1221
|
+
* Mark contact as unread (admin only)
|
|
1222
|
+
*/
|
|
1223
|
+
async markContactAsUnread(siteName, id) {
|
|
1224
|
+
return this.patch(this.contactEndpoint(siteName, `/contact/${encodeURIComponent(id)}`), { status: "unread" });
|
|
1225
|
+
}
|
|
1226
|
+
/**
|
|
1227
|
+
* Archive contact submission (admin only)
|
|
1228
|
+
*/
|
|
1229
|
+
async archiveContact(siteName, id) {
|
|
1230
|
+
return this.patch(this.contactEndpoint(siteName, `/contact/${encodeURIComponent(id)}`), { status: "archived" });
|
|
1231
|
+
}
|
|
1232
|
+
/**
|
|
1233
|
+
* Delete contact submission (admin only)
|
|
1234
|
+
*/
|
|
1235
|
+
async deleteContact(siteName, id) {
|
|
1236
|
+
return this.delete(this.contactEndpoint(siteName, `/contact/${encodeURIComponent(id)}`));
|
|
1237
|
+
}
|
|
1238
|
+
/**
|
|
1239
|
+
* Bulk update contact submissions (admin only)
|
|
1240
|
+
*/
|
|
1241
|
+
async bulkUpdateContacts(siteName, data) {
|
|
1242
|
+
return this.create(this.contactEndpoint(siteName, "/contact/bulk-update"), data);
|
|
1243
|
+
}
|
|
1244
|
+
/**
|
|
1245
|
+
* Get contact form statistics (admin only)
|
|
1246
|
+
*/
|
|
1247
|
+
async getContactStats(siteName, params) {
|
|
1248
|
+
return this.http.get(this.buildPath(this.contactEndpoint(siteName, "/contact/stats")), params);
|
|
1249
|
+
}
|
|
1250
|
+
/**
|
|
1251
|
+
* Export contact submissions (admin only)
|
|
1252
|
+
*/
|
|
1253
|
+
async exportContacts(siteName, params) {
|
|
1254
|
+
return this.create(this.contactEndpoint(siteName, "/contact/export"), params || {});
|
|
1255
|
+
}
|
|
1256
|
+
/**
|
|
1257
|
+
* Get contact form configuration
|
|
1258
|
+
*/
|
|
1259
|
+
async getContactConfig(siteName) {
|
|
1260
|
+
return this.getSingle(this.contactEndpoint(siteName, "/contact/config"));
|
|
1261
|
+
}
|
|
1262
|
+
/**
|
|
1263
|
+
* Update contact form configuration (admin only)
|
|
1264
|
+
*/
|
|
1265
|
+
async updateContactConfig(siteName, data) {
|
|
1266
|
+
return this.update(this.contactEndpoint(siteName, "/contact/config"), data);
|
|
1267
|
+
}
|
|
1268
|
+
};
|
|
1269
|
+
|
|
1270
|
+
// src/perspect-api-client.ts
|
|
1271
|
+
var PerspectApiClient = class {
|
|
1272
|
+
http;
|
|
1273
|
+
// Service clients
|
|
1274
|
+
auth;
|
|
1275
|
+
content;
|
|
1276
|
+
apiKeys;
|
|
1277
|
+
organizations;
|
|
1278
|
+
sites;
|
|
1279
|
+
products;
|
|
1280
|
+
categories;
|
|
1281
|
+
webhooks;
|
|
1282
|
+
checkout;
|
|
1283
|
+
contact;
|
|
1284
|
+
constructor(config) {
|
|
1285
|
+
if (!config.baseUrl) {
|
|
1286
|
+
throw new Error("baseUrl is required in PerspectApiConfig");
|
|
1287
|
+
}
|
|
1288
|
+
this.http = new HttpClient(config);
|
|
1289
|
+
this.auth = new AuthClient(this.http);
|
|
1290
|
+
this.content = new ContentClient(this.http);
|
|
1291
|
+
this.apiKeys = new ApiKeysClient(this.http);
|
|
1292
|
+
this.organizations = new OrganizationsClient(this.http);
|
|
1293
|
+
this.sites = new SitesClient(this.http);
|
|
1294
|
+
this.products = new ProductsClient(this.http);
|
|
1295
|
+
this.categories = new CategoriesClient(this.http);
|
|
1296
|
+
this.webhooks = new WebhooksClient(this.http);
|
|
1297
|
+
this.checkout = new CheckoutClient(this.http);
|
|
1298
|
+
this.contact = new ContactClient(this.http);
|
|
1299
|
+
}
|
|
1300
|
+
/**
|
|
1301
|
+
* Update authentication token
|
|
1302
|
+
*/
|
|
1303
|
+
setAuth(jwt) {
|
|
1304
|
+
this.http.setAuth(jwt);
|
|
1305
|
+
}
|
|
1306
|
+
/**
|
|
1307
|
+
* Update API key
|
|
1308
|
+
*/
|
|
1309
|
+
setApiKey(apiKey) {
|
|
1310
|
+
this.http.setApiKey(apiKey);
|
|
1311
|
+
}
|
|
1312
|
+
/**
|
|
1313
|
+
* Clear authentication
|
|
1314
|
+
*/
|
|
1315
|
+
clearAuth() {
|
|
1316
|
+
this.http.clearAuth();
|
|
1317
|
+
}
|
|
1318
|
+
/**
|
|
1319
|
+
* Health check endpoint
|
|
1320
|
+
*/
|
|
1321
|
+
async health() {
|
|
1322
|
+
return this.http.get("/health");
|
|
1323
|
+
}
|
|
1324
|
+
/**
|
|
1325
|
+
* Get API version info
|
|
1326
|
+
*/
|
|
1327
|
+
async getVersion() {
|
|
1328
|
+
return this.http.get("/api/v1/version");
|
|
1329
|
+
}
|
|
1330
|
+
/**
|
|
1331
|
+
* Get API status and statistics
|
|
1332
|
+
*/
|
|
1333
|
+
async getStatus() {
|
|
1334
|
+
return this.http.get("/api/v1/status");
|
|
1335
|
+
}
|
|
1336
|
+
/**
|
|
1337
|
+
* Test API connectivity and authentication
|
|
1338
|
+
*/
|
|
1339
|
+
async test() {
|
|
1340
|
+
return this.http.get("/api/v1/test");
|
|
1341
|
+
}
|
|
1342
|
+
/**
|
|
1343
|
+
* Get CSRF token (for form submissions)
|
|
1344
|
+
* @param siteName - Optional site name for site-specific token (recommended for development)
|
|
1345
|
+
*/
|
|
1346
|
+
async getCsrfToken(siteName) {
|
|
1347
|
+
if (siteName) {
|
|
1348
|
+
return this.http.get(`/api/v1/csrf/token/${siteName}`);
|
|
1349
|
+
}
|
|
1350
|
+
return this.http.get("/api/v1/csrf/token");
|
|
1351
|
+
}
|
|
1352
|
+
/**
|
|
1353
|
+
* Validate CSRF token
|
|
1354
|
+
*/
|
|
1355
|
+
async validateCsrfToken(token) {
|
|
1356
|
+
return this.http.post("/api/v1/csrf/validate", { token });
|
|
1357
|
+
}
|
|
1358
|
+
};
|
|
1359
|
+
function createPerspectApiClient(config) {
|
|
1360
|
+
return new PerspectApiClient(config);
|
|
1361
|
+
}
|
|
1362
|
+
var perspect_api_client_default = PerspectApiClient;
|
|
1363
|
+
|
|
1364
|
+
// src/loaders.ts
|
|
1365
|
+
var noopLogger = {};
|
|
1366
|
+
var log = (logger, level, ...args) => {
|
|
1367
|
+
const target = logger?.[level];
|
|
1368
|
+
if (typeof target === "function") {
|
|
1369
|
+
target(...args);
|
|
1370
|
+
}
|
|
1371
|
+
};
|
|
1372
|
+
var isMediaItem = (value) => {
|
|
1373
|
+
if (!value || typeof value !== "object") {
|
|
1374
|
+
return false;
|
|
1375
|
+
}
|
|
1376
|
+
const media = value;
|
|
1377
|
+
return typeof media.link === "string" && typeof media.media_id === "string";
|
|
1378
|
+
};
|
|
1379
|
+
var normalizeMediaList = (rawMedia) => {
|
|
1380
|
+
if (!Array.isArray(rawMedia)) {
|
|
1381
|
+
return [];
|
|
1382
|
+
}
|
|
1383
|
+
if (rawMedia.length > 0 && Array.isArray(rawMedia[0])) {
|
|
1384
|
+
return rawMedia.flat().filter(isMediaItem);
|
|
1385
|
+
}
|
|
1386
|
+
return rawMedia.filter(isMediaItem);
|
|
1387
|
+
};
|
|
1388
|
+
var normalizeQueryParamList = (value) => {
|
|
1389
|
+
if (value === void 0 || value === null) {
|
|
1390
|
+
return void 0;
|
|
1391
|
+
}
|
|
1392
|
+
const values = Array.isArray(value) ? value : [value];
|
|
1393
|
+
const normalized = values.map((item) => String(item).trim()).filter((item) => item.length > 0);
|
|
1394
|
+
return normalized.length > 0 ? normalized.join(",") : void 0;
|
|
1395
|
+
};
|
|
1396
|
+
var transformProduct = (perspectProduct, logger) => {
|
|
1397
|
+
const rawProduct = perspectProduct ?? {};
|
|
1398
|
+
const productId = rawProduct.product_id ?? rawProduct.id ?? rawProduct.sku ?? "unknown";
|
|
1399
|
+
const productName = rawProduct.product ?? rawProduct.name ?? rawProduct.title ?? "Untitled";
|
|
1400
|
+
const productSlug = rawProduct.slug ?? rawProduct.product_slug ?? (productId ? `product-${productId}` : "product");
|
|
1401
|
+
const slugPrefix = rawProduct.slug_prefix ?? rawProduct.slugPrefix ?? rawProduct.category ?? "artwork";
|
|
1402
|
+
const mediaItems = normalizeMediaList(rawProduct.media);
|
|
1403
|
+
const primaryImage = mediaItems[0]?.link ?? rawProduct.image ?? rawProduct.image_url ?? rawProduct.thumbnail ?? "";
|
|
1404
|
+
log(logger, "debug", "[PerspectAPI] Transform product", {
|
|
1405
|
+
productId,
|
|
1406
|
+
productSlug,
|
|
1407
|
+
mediaCount: mediaItems.length
|
|
1408
|
+
});
|
|
1409
|
+
return {
|
|
1410
|
+
id: typeof productId === "string" ? productId : String(productId),
|
|
1411
|
+
product: productName,
|
|
1412
|
+
name: productName,
|
|
1413
|
+
slug: productSlug,
|
|
1414
|
+
slug_prefix: slugPrefix,
|
|
1415
|
+
price: typeof rawProduct.price === "number" ? rawProduct.price : Number(rawProduct.price ?? 0),
|
|
1416
|
+
currency: rawProduct.currency ?? "USD",
|
|
1417
|
+
description: rawProduct.description ?? "",
|
|
1418
|
+
description_markdown: rawProduct.description_markdown ?? rawProduct.description ?? "",
|
|
1419
|
+
image: primaryImage,
|
|
1420
|
+
media: mediaItems,
|
|
1421
|
+
gateway_product_id_live: rawProduct.gateway_product_id_live,
|
|
1422
|
+
gateway_product_id_test: rawProduct.gateway_product_id_test,
|
|
1423
|
+
stripe_product_id_live: rawProduct.stripe_product_id_live,
|
|
1424
|
+
stripe_product_id_test: rawProduct.stripe_product_id_test,
|
|
1425
|
+
isActive: rawProduct.isActive ?? rawProduct.is_active ?? true,
|
|
1426
|
+
// Preserve original payload for advanced consumers
|
|
1427
|
+
...rawProduct
|
|
1428
|
+
};
|
|
1429
|
+
};
|
|
1430
|
+
var transformContent = (perspectContent) => {
|
|
1431
|
+
const raw = perspectContent ?? {};
|
|
1432
|
+
return {
|
|
1433
|
+
id: typeof raw.id === "string" ? raw.id : String(raw.id ?? ""),
|
|
1434
|
+
slug: raw.slug ?? `post-${raw.id ?? "unknown"}`,
|
|
1435
|
+
slug_prefix: raw.slug_prefix ?? (raw.pageType === "post" ? "blog" : "page"),
|
|
1436
|
+
page_type: raw.pageType,
|
|
1437
|
+
title: raw.pageTitle,
|
|
1438
|
+
content: raw.pageContent,
|
|
1439
|
+
excerpt: typeof raw.pageContent === "string" ? `${raw.pageContent.slice(0, 200)}...` : void 0,
|
|
1440
|
+
published: raw.pageStatus === "publish",
|
|
1441
|
+
created_at: raw.createdAt,
|
|
1442
|
+
updated_at: raw.updatedAt,
|
|
1443
|
+
description: raw.description,
|
|
1444
|
+
published_date: raw.published_date,
|
|
1445
|
+
author: raw.author,
|
|
1446
|
+
tags: raw.tags,
|
|
1447
|
+
image: raw.image
|
|
1448
|
+
};
|
|
1449
|
+
};
|
|
1450
|
+
var getDefaultFallbackProducts = (siteName) => {
|
|
1451
|
+
const safeSite = siteName.replace(/\s+/g, "-").toLowerCase();
|
|
1452
|
+
const mediaSamples = [
|
|
1453
|
+
{
|
|
1454
|
+
media_id: `${safeSite}-media-1`,
|
|
1455
|
+
attachment_id: 1001,
|
|
1456
|
+
file_name: "sample-artwork-1.jpg",
|
|
1457
|
+
link: "https://picsum.photos/1200/800?random=1",
|
|
1458
|
+
content_type: "image/jpeg",
|
|
1459
|
+
width: 1200,
|
|
1460
|
+
height: 800,
|
|
1461
|
+
filesize: 245760,
|
|
1462
|
+
r2_key: `${safeSite}/artwork-1.jpg`,
|
|
1463
|
+
site_name: siteName
|
|
1464
|
+
},
|
|
1465
|
+
{
|
|
1466
|
+
media_id: `${safeSite}-media-2`,
|
|
1467
|
+
attachment_id: 1002,
|
|
1468
|
+
file_name: "sample-artwork-2.jpg",
|
|
1469
|
+
link: "https://picsum.photos/1200/800?random=2",
|
|
1470
|
+
content_type: "image/jpeg",
|
|
1471
|
+
width: 1200,
|
|
1472
|
+
height: 800,
|
|
1473
|
+
filesize: 312480,
|
|
1474
|
+
r2_key: `${safeSite}/artwork-2.jpg`,
|
|
1475
|
+
site_name: siteName
|
|
1476
|
+
}
|
|
1477
|
+
];
|
|
1478
|
+
return [
|
|
1479
|
+
{
|
|
1480
|
+
id: `${safeSite}-product-1`,
|
|
1481
|
+
product: `${siteName} Sample Artwork 1`,
|
|
1482
|
+
slug: `${safeSite}-sample-artwork-1`,
|
|
1483
|
+
slug_prefix: "artwork",
|
|
1484
|
+
price: 299,
|
|
1485
|
+
description: `Beautiful artwork from ${siteName}`,
|
|
1486
|
+
description_markdown: `Beautiful artwork from **${siteName}**`,
|
|
1487
|
+
image: "https://picsum.photos/800/600?random=1",
|
|
1488
|
+
media: mediaSamples
|
|
1489
|
+
},
|
|
1490
|
+
{
|
|
1491
|
+
id: `${safeSite}-product-2`,
|
|
1492
|
+
product: `${siteName} Sample Artwork 2`,
|
|
1493
|
+
slug: `${safeSite}-sample-artwork-2`,
|
|
1494
|
+
slug_prefix: "artwork",
|
|
1495
|
+
price: 499,
|
|
1496
|
+
description: `Exquisite piece from ${siteName} collection`,
|
|
1497
|
+
description_markdown: `Exquisite piece from **${siteName}** collection`,
|
|
1498
|
+
image: "https://picsum.photos/800/600?random=2",
|
|
1499
|
+
media: mediaSamples
|
|
1500
|
+
}
|
|
1501
|
+
];
|
|
1502
|
+
};
|
|
1503
|
+
var getDefaultFallbackPosts = (siteName) => {
|
|
1504
|
+
return [
|
|
1505
|
+
{
|
|
1506
|
+
id: `${siteName}-post-1`,
|
|
1507
|
+
slug: "welcome-post",
|
|
1508
|
+
slug_prefix: "blog",
|
|
1509
|
+
page_type: "post",
|
|
1510
|
+
title: `Welcome to ${siteName}`,
|
|
1511
|
+
content: `<p>Welcome to our ${siteName} blog. Here you'll find articles about art, culture, and our collections.</p>`,
|
|
1512
|
+
excerpt: `Welcome to our ${siteName} blog.`,
|
|
1513
|
+
published: true,
|
|
1514
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1515
|
+
}
|
|
1516
|
+
];
|
|
1517
|
+
};
|
|
1518
|
+
var resolveFallbackProducts = ({ siteName, fallbackProducts }) => {
|
|
1519
|
+
if (fallbackProducts && fallbackProducts.length > 0) {
|
|
1520
|
+
return fallbackProducts;
|
|
1521
|
+
}
|
|
1522
|
+
return getDefaultFallbackProducts(siteName);
|
|
1523
|
+
};
|
|
1524
|
+
var resolveFallbackPosts = ({ siteName, fallbackPosts }) => {
|
|
1525
|
+
if (fallbackPosts && fallbackPosts.length > 0) {
|
|
1526
|
+
return fallbackPosts;
|
|
1527
|
+
}
|
|
1528
|
+
return getDefaultFallbackPosts(siteName);
|
|
1529
|
+
};
|
|
1530
|
+
async function loadProducts(options) {
|
|
1531
|
+
const {
|
|
1532
|
+
client,
|
|
1533
|
+
siteName,
|
|
1534
|
+
logger = noopLogger,
|
|
1535
|
+
fallbackProducts,
|
|
1536
|
+
limit = 100,
|
|
1537
|
+
offset,
|
|
1538
|
+
search,
|
|
1539
|
+
category,
|
|
1540
|
+
categoryIds
|
|
1541
|
+
} = options;
|
|
1542
|
+
if (!client) {
|
|
1543
|
+
log(logger, "warn", "[PerspectAPI] No client configured, using fallback products");
|
|
1544
|
+
return resolveFallbackProducts({ siteName, fallbackProducts });
|
|
1545
|
+
}
|
|
1546
|
+
try {
|
|
1547
|
+
log(logger, "info", `[PerspectAPI] Loading products for site "${siteName}"`);
|
|
1548
|
+
const queryParams = {
|
|
1549
|
+
isActive: true,
|
|
1550
|
+
limit,
|
|
1551
|
+
offset,
|
|
1552
|
+
search
|
|
1553
|
+
};
|
|
1554
|
+
const normalizedCategory = normalizeQueryParamList(category);
|
|
1555
|
+
if (normalizedCategory) {
|
|
1556
|
+
queryParams.category = normalizedCategory;
|
|
1557
|
+
}
|
|
1558
|
+
const normalizedCategoryIds = normalizeQueryParamList(categoryIds);
|
|
1559
|
+
if (normalizedCategoryIds) {
|
|
1560
|
+
queryParams.category_id = normalizedCategoryIds;
|
|
1561
|
+
}
|
|
1562
|
+
const response = await client.products.getProducts(siteName, queryParams);
|
|
1563
|
+
if (!response.data) {
|
|
1564
|
+
log(logger, "warn", "[PerspectAPI] Products response missing data, returning fallback set");
|
|
1565
|
+
return resolveFallbackProducts({ siteName, fallbackProducts });
|
|
1566
|
+
}
|
|
1567
|
+
log(logger, "debug", `[PerspectAPI] Found ${response.data.length} products, transforming...`);
|
|
1568
|
+
return response.data.map((product) => transformProduct(product, logger));
|
|
1569
|
+
} catch (error) {
|
|
1570
|
+
log(logger, "error", "[PerspectAPI] Error loading products", error);
|
|
1571
|
+
return resolveFallbackProducts({ siteName, fallbackProducts });
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
async function loadProductBySlug(options) {
|
|
1575
|
+
const {
|
|
1576
|
+
client,
|
|
1577
|
+
siteName,
|
|
1578
|
+
slug,
|
|
1579
|
+
logger = noopLogger,
|
|
1580
|
+
fallbackProducts
|
|
1581
|
+
} = options;
|
|
1582
|
+
if (!client) {
|
|
1583
|
+
log(logger, "warn", "[PerspectAPI] No client configured, searching fallback products");
|
|
1584
|
+
const fallback = resolveFallbackProducts({ siteName, fallbackProducts });
|
|
1585
|
+
return fallback.find((product) => product.slug === slug) ?? null;
|
|
1586
|
+
}
|
|
1587
|
+
try {
|
|
1588
|
+
log(logger, "info", `[PerspectAPI] Loading product "${slug}" for site "${siteName}"`);
|
|
1589
|
+
const response = await client.products.getProductBySlug(siteName, slug);
|
|
1590
|
+
if (!response.data) {
|
|
1591
|
+
log(logger, "warn", `[PerspectAPI] Product not found for slug "${slug}"`);
|
|
1592
|
+
return null;
|
|
1593
|
+
}
|
|
1594
|
+
return transformProduct(response.data, logger);
|
|
1595
|
+
} catch (error) {
|
|
1596
|
+
log(logger, "error", `[PerspectAPI] Error loading product slug "${slug}"`, error);
|
|
1597
|
+
return null;
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
async function loadPages(options) {
|
|
1601
|
+
const { client, siteName, logger = noopLogger, params, fallbackPosts } = options;
|
|
1602
|
+
if (!client) {
|
|
1603
|
+
log(logger, "warn", "[PerspectAPI] No client configured, using fallback posts for pages");
|
|
1604
|
+
return resolveFallbackPosts({ siteName, fallbackPosts }).filter(
|
|
1605
|
+
(post) => post.page_type !== "post"
|
|
1606
|
+
);
|
|
1607
|
+
}
|
|
1608
|
+
try {
|
|
1609
|
+
log(logger, "info", `[PerspectAPI] Loading pages for site "${siteName}"`);
|
|
1610
|
+
const response = await client.content.getContent(
|
|
1611
|
+
siteName,
|
|
1612
|
+
{
|
|
1613
|
+
...params,
|
|
1614
|
+
page_status: params?.page_status ?? "publish",
|
|
1615
|
+
page_type: params?.page_type ?? "page",
|
|
1616
|
+
limit: options.limit ?? params?.limit ?? 100
|
|
1617
|
+
}
|
|
1618
|
+
);
|
|
1619
|
+
if (!response.data) {
|
|
1620
|
+
return [];
|
|
1621
|
+
}
|
|
1622
|
+
return response.data.map((content) => transformContent(content));
|
|
1623
|
+
} catch (error) {
|
|
1624
|
+
log(logger, "error", "[PerspectAPI] Error loading pages", error);
|
|
1625
|
+
return [];
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
async function loadPosts(options) {
|
|
1629
|
+
const { client, siteName, logger = noopLogger, params, fallbackPosts } = options;
|
|
1630
|
+
if (!client) {
|
|
1631
|
+
log(logger, "warn", "[PerspectAPI] No client configured, using fallback posts");
|
|
1632
|
+
return resolveFallbackPosts({ siteName, fallbackPosts });
|
|
1633
|
+
}
|
|
1634
|
+
try {
|
|
1635
|
+
log(logger, "info", `[PerspectAPI] Loading posts for site "${siteName}"`);
|
|
1636
|
+
const response = await client.content.getContent(
|
|
1637
|
+
siteName,
|
|
1638
|
+
{
|
|
1639
|
+
...params,
|
|
1640
|
+
page_status: params?.page_status ?? "publish",
|
|
1641
|
+
page_type: params?.page_type ?? "post",
|
|
1642
|
+
limit: options.limit ?? params?.limit ?? 100
|
|
1643
|
+
}
|
|
1644
|
+
);
|
|
1645
|
+
if (!response.data) {
|
|
1646
|
+
log(logger, "warn", "[PerspectAPI] Posts response missing data");
|
|
1647
|
+
return [];
|
|
1648
|
+
}
|
|
1649
|
+
return response.data.map((content) => transformContent(content));
|
|
1650
|
+
} catch (error) {
|
|
1651
|
+
log(logger, "error", "[PerspectAPI] Error loading posts", error);
|
|
1652
|
+
return [];
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
async function loadContentBySlug(options) {
|
|
1656
|
+
const {
|
|
1657
|
+
client,
|
|
1658
|
+
siteName,
|
|
1659
|
+
slug,
|
|
1660
|
+
logger = noopLogger,
|
|
1661
|
+
fallbackPosts
|
|
1662
|
+
} = options;
|
|
1663
|
+
if (!client) {
|
|
1664
|
+
log(logger, "warn", "[PerspectAPI] No client configured, searching fallback posts");
|
|
1665
|
+
const fallback = resolveFallbackPosts({ siteName, fallbackPosts });
|
|
1666
|
+
return fallback.find((post) => post.slug === slug) ?? null;
|
|
1667
|
+
}
|
|
1668
|
+
try {
|
|
1669
|
+
log(logger, "info", `[PerspectAPI] Loading content slug "${slug}" for site "${siteName}"`);
|
|
1670
|
+
const response = await client.content.getContentBySlug(siteName, slug);
|
|
1671
|
+
if (!response.data) {
|
|
1672
|
+
log(logger, "warn", `[PerspectAPI] Content not found for slug "${slug}"`);
|
|
1673
|
+
return null;
|
|
1674
|
+
}
|
|
1675
|
+
return transformContent(response.data);
|
|
1676
|
+
} catch (error) {
|
|
1677
|
+
log(logger, "error", `[PerspectAPI] Error loading content slug "${slug}"`, error);
|
|
1678
|
+
return null;
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
async function loadAllContent(options) {
|
|
1682
|
+
const { logger = noopLogger } = options;
|
|
1683
|
+
const [pages, posts] = await Promise.all([
|
|
1684
|
+
loadPages(options),
|
|
1685
|
+
loadPosts(options)
|
|
1686
|
+
]);
|
|
1687
|
+
log(logger, "debug", `[PerspectAPI] Loaded ${pages.length + posts.length} total content items`);
|
|
1688
|
+
return [...pages, ...posts];
|
|
1689
|
+
}
|
|
1690
|
+
async function createCheckoutSession(options) {
|
|
1691
|
+
const {
|
|
1692
|
+
client,
|
|
1693
|
+
siteName,
|
|
1694
|
+
items,
|
|
1695
|
+
successUrl,
|
|
1696
|
+
cancelUrl,
|
|
1697
|
+
customerEmail,
|
|
1698
|
+
mode = "live",
|
|
1699
|
+
logger = noopLogger,
|
|
1700
|
+
fallbackProducts,
|
|
1701
|
+
metadata,
|
|
1702
|
+
priceIdResolver
|
|
1703
|
+
} = options;
|
|
1704
|
+
if (!client) {
|
|
1705
|
+
log(logger, "error", "[PerspectAPI] Cannot create checkout session without SDK client");
|
|
1706
|
+
return { error: "PerspectAPI client not configured" };
|
|
1707
|
+
}
|
|
1708
|
+
try {
|
|
1709
|
+
const products = await loadProducts({
|
|
1710
|
+
client,
|
|
1711
|
+
siteName,
|
|
1712
|
+
logger,
|
|
1713
|
+
limit: 200,
|
|
1714
|
+
fallbackProducts
|
|
1715
|
+
});
|
|
1716
|
+
const productMap = new Map(
|
|
1717
|
+
products.map((product) => [String(product.id), product])
|
|
1718
|
+
);
|
|
1719
|
+
const line_items = items.map((item) => {
|
|
1720
|
+
const product = productMap.get(String(item.productId));
|
|
1721
|
+
if (!product) {
|
|
1722
|
+
throw new Error(`Product ${item.productId} not found while building checkout session`);
|
|
1723
|
+
}
|
|
1724
|
+
const resolvedPrice = priceIdResolver?.(product, mode) ?? (mode === "test" ? product.stripe_product_id_test ?? product.gateway_product_id_test : product.stripe_product_id_live ?? product.gateway_product_id_live);
|
|
1725
|
+
if (!resolvedPrice) {
|
|
1726
|
+
throw new Error(`Missing Stripe price ID for product ${item.productId} (${product.product ?? product.name ?? "unknown"})`);
|
|
1727
|
+
}
|
|
1728
|
+
return {
|
|
1729
|
+
price: resolvedPrice,
|
|
1730
|
+
quantity: item.quantity
|
|
1731
|
+
};
|
|
1732
|
+
});
|
|
1733
|
+
const checkoutData = {
|
|
1734
|
+
line_items,
|
|
1735
|
+
successUrl,
|
|
1736
|
+
cancelUrl,
|
|
1737
|
+
success_url: successUrl,
|
|
1738
|
+
cancel_url: cancelUrl,
|
|
1739
|
+
customerEmail,
|
|
1740
|
+
customer_email: customerEmail,
|
|
1741
|
+
mode: mode === "test" ? "payment" : "payment",
|
|
1742
|
+
metadata
|
|
1743
|
+
};
|
|
1744
|
+
log(logger, "info", "[PerspectAPI] Creating checkout session");
|
|
1745
|
+
return client.checkout.createCheckoutSession(siteName, checkoutData);
|
|
1746
|
+
} catch (error) {
|
|
1747
|
+
log(logger, "error", "[PerspectAPI] Failed to create checkout session", error);
|
|
1748
|
+
return { error: error instanceof Error ? error.message : "Unknown error creating checkout session" };
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1752
|
+
0 && (module.exports = {
|
|
1753
|
+
ApiKeysClient,
|
|
1754
|
+
AuthClient,
|
|
1755
|
+
BaseClient,
|
|
1756
|
+
CategoriesClient,
|
|
1757
|
+
CheckoutClient,
|
|
1758
|
+
ContactClient,
|
|
1759
|
+
ContentClient,
|
|
1760
|
+
HttpClient,
|
|
1761
|
+
OrganizationsClient,
|
|
1762
|
+
PerspectApiClient,
|
|
1763
|
+
ProductsClient,
|
|
1764
|
+
SitesClient,
|
|
1765
|
+
WebhooksClient,
|
|
1766
|
+
createApiError,
|
|
1767
|
+
createCheckoutSession,
|
|
1768
|
+
createPerspectApiClient,
|
|
1769
|
+
loadAllContent,
|
|
1770
|
+
loadContentBySlug,
|
|
1771
|
+
loadPages,
|
|
1772
|
+
loadPosts,
|
|
1773
|
+
loadProductBySlug,
|
|
1774
|
+
loadProducts,
|
|
1775
|
+
transformContent,
|
|
1776
|
+
transformProduct
|
|
1777
|
+
});
|