perspectapi-ts-sdk 2.7.0 → 2.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +352 -2
- package/dist/index.d.ts +352 -2
- package/dist/index.js +328 -1
- package/dist/index.mjs +327 -1
- package/package.json +1 -1
- package/src/client/products-client.ts +123 -0
- package/src/client/site-users-client.ts +352 -0
- package/src/index.ts +10 -0
- package/src/perspect-api-client.ts +3 -0
- package/src/types/index.ts +90 -1
- package/src/utils/validators.ts +1 -2
package/dist/index.js
CHANGED
|
@@ -36,6 +36,7 @@ __export(index_exports, {
|
|
|
36
36
|
OrganizationsClient: () => OrganizationsClient,
|
|
37
37
|
PerspectApiClient: () => PerspectApiClient,
|
|
38
38
|
ProductsClient: () => ProductsClient,
|
|
39
|
+
SiteUsersClient: () => SiteUsersClient,
|
|
39
40
|
SitesClient: () => SitesClient,
|
|
40
41
|
WebhooksClient: () => WebhooksClient,
|
|
41
42
|
buildImageUrl: () => buildImageUrl,
|
|
@@ -768,7 +769,7 @@ var AuthClient = class extends BaseClient {
|
|
|
768
769
|
|
|
769
770
|
// src/utils/validators.ts
|
|
770
771
|
var MAX_API_QUERY_LIMIT = 100;
|
|
771
|
-
var ALLOWED_CONTENT_TYPES = ["post", "page"];
|
|
772
|
+
var ALLOWED_CONTENT_TYPES = ["post", "page", "block"];
|
|
772
773
|
function validateLimit(limit, context) {
|
|
773
774
|
if (typeof limit !== "number" || Number.isNaN(limit) || !Number.isFinite(limit)) {
|
|
774
775
|
throw new Error(`[PerspectAPI] ${context} limit must be a finite number.`);
|
|
@@ -1522,6 +1523,64 @@ var ProductsClient = class extends BaseClient {
|
|
|
1522
1523
|
}
|
|
1523
1524
|
return void 0;
|
|
1524
1525
|
}
|
|
1526
|
+
// ============================================================================
|
|
1527
|
+
// PRODUCT OPTIONS AND SKUS (for variants)
|
|
1528
|
+
// ============================================================================
|
|
1529
|
+
/**
|
|
1530
|
+
* Get all options (and their values) for a product
|
|
1531
|
+
*/
|
|
1532
|
+
async getProductOptions(siteName, productId) {
|
|
1533
|
+
const endpoint = this.siteScopedEndpoint(
|
|
1534
|
+
siteName,
|
|
1535
|
+
`/products/${productId}/options`,
|
|
1536
|
+
{ includeSitesSegment: false }
|
|
1537
|
+
);
|
|
1538
|
+
return this.getSingle(endpoint);
|
|
1539
|
+
}
|
|
1540
|
+
/**
|
|
1541
|
+
* Create a new product option (e.g., "Size", "Color")
|
|
1542
|
+
*/
|
|
1543
|
+
async createProductOption(siteName, productId, data) {
|
|
1544
|
+
const endpoint = this.siteScopedEndpoint(
|
|
1545
|
+
siteName,
|
|
1546
|
+
`/products/${productId}/options`,
|
|
1547
|
+
{ includeSitesSegment: false }
|
|
1548
|
+
);
|
|
1549
|
+
return this.create(endpoint, data);
|
|
1550
|
+
}
|
|
1551
|
+
/**
|
|
1552
|
+
* Create a new value for a product option (e.g., "Small", "Red")
|
|
1553
|
+
*/
|
|
1554
|
+
async createProductOptionValue(siteName, productId, optionId, data) {
|
|
1555
|
+
const endpoint = this.siteScopedEndpoint(
|
|
1556
|
+
siteName,
|
|
1557
|
+
`/products/${productId}/options/${optionId}/values`,
|
|
1558
|
+
{ includeSitesSegment: false }
|
|
1559
|
+
);
|
|
1560
|
+
return this.create(endpoint, data);
|
|
1561
|
+
}
|
|
1562
|
+
/**
|
|
1563
|
+
* Get all SKUs for a product (with their option value combinations)
|
|
1564
|
+
*/
|
|
1565
|
+
async getProductSkus(siteName, productId) {
|
|
1566
|
+
const endpoint = this.siteScopedEndpoint(
|
|
1567
|
+
siteName,
|
|
1568
|
+
`/products/${productId}/skus`,
|
|
1569
|
+
{ includeSitesSegment: false }
|
|
1570
|
+
);
|
|
1571
|
+
return this.getSingle(endpoint);
|
|
1572
|
+
}
|
|
1573
|
+
/**
|
|
1574
|
+
* Create or update a SKU for a product variant combination
|
|
1575
|
+
*/
|
|
1576
|
+
async createProductSku(siteName, productId, data) {
|
|
1577
|
+
const endpoint = this.siteScopedEndpoint(
|
|
1578
|
+
siteName,
|
|
1579
|
+
`/products/${productId}/skus`,
|
|
1580
|
+
{ includeSitesSegment: false }
|
|
1581
|
+
);
|
|
1582
|
+
return this.create(endpoint, data);
|
|
1583
|
+
}
|
|
1525
1584
|
};
|
|
1526
1585
|
|
|
1527
1586
|
// src/client/categories-client.ts
|
|
@@ -2236,6 +2295,271 @@ var NewsletterClient = class extends BaseClient {
|
|
|
2236
2295
|
}
|
|
2237
2296
|
};
|
|
2238
2297
|
|
|
2298
|
+
// src/client/site-users-client.ts
|
|
2299
|
+
var SiteUsersClient = class extends BaseClient {
|
|
2300
|
+
constructor(http, cache) {
|
|
2301
|
+
super(http, "/api/v1", cache);
|
|
2302
|
+
}
|
|
2303
|
+
/**
|
|
2304
|
+
* Build a site user endpoint scoped to a site (without /sites prefix)
|
|
2305
|
+
*/
|
|
2306
|
+
siteUserEndpoint(siteName, endpoint) {
|
|
2307
|
+
return this.siteScopedEndpoint(siteName, endpoint, { includeSitesSegment: false });
|
|
2308
|
+
}
|
|
2309
|
+
// ============================================================================
|
|
2310
|
+
// PUBLIC ENDPOINTS (OTP authentication)
|
|
2311
|
+
// ============================================================================
|
|
2312
|
+
/**
|
|
2313
|
+
* Request OTP for login/signup
|
|
2314
|
+
* @param siteName - The site name
|
|
2315
|
+
* @param data - Email address
|
|
2316
|
+
* @param csrfToken - CSRF token (required for browser-based submissions)
|
|
2317
|
+
*/
|
|
2318
|
+
async requestOtp(siteName, data, csrfToken) {
|
|
2319
|
+
if (typeof window !== "undefined" && !csrfToken) {
|
|
2320
|
+
console.warn("CSRF token recommended for browser-based OTP requests");
|
|
2321
|
+
}
|
|
2322
|
+
return this.create(
|
|
2323
|
+
this.siteUserEndpoint(siteName, "/users/request-otp"),
|
|
2324
|
+
data,
|
|
2325
|
+
csrfToken
|
|
2326
|
+
);
|
|
2327
|
+
}
|
|
2328
|
+
/**
|
|
2329
|
+
* Verify OTP and get JWT token
|
|
2330
|
+
*
|
|
2331
|
+
* For cross-domain authentication, you must manually set the token after verification:
|
|
2332
|
+
* ```typescript
|
|
2333
|
+
* const response = await client.siteUsers.verifyOtp('mysite', { email, code });
|
|
2334
|
+
* const { token, user } = response.data;
|
|
2335
|
+
*
|
|
2336
|
+
* // Store token securely (choose one):
|
|
2337
|
+
* // Option 1: Memory (lost on refresh, most secure)
|
|
2338
|
+
* client.setAuth(token);
|
|
2339
|
+
*
|
|
2340
|
+
* // Option 2: httpOnly cookie on YOUR domain (recommended for production)
|
|
2341
|
+
* await fetch('/your-api/set-auth-cookie', {
|
|
2342
|
+
* method: 'POST',
|
|
2343
|
+
* body: JSON.stringify({ token })
|
|
2344
|
+
* });
|
|
2345
|
+
* client.setAuth(token);
|
|
2346
|
+
*
|
|
2347
|
+
* // Option 3: localStorage (vulnerable to XSS, not recommended)
|
|
2348
|
+
* localStorage.setItem('site_user_token', token);
|
|
2349
|
+
* client.setAuth(token);
|
|
2350
|
+
* ```
|
|
2351
|
+
*
|
|
2352
|
+
* For convenience, use `verifyOtpAndSetAuth()` to automatically set the token in memory.
|
|
2353
|
+
*
|
|
2354
|
+
* @param siteName - The site name
|
|
2355
|
+
* @param data - Email and code
|
|
2356
|
+
* @param csrfToken - CSRF token (required for browser-based submissions)
|
|
2357
|
+
*/
|
|
2358
|
+
async verifyOtp(siteName, data, csrfToken) {
|
|
2359
|
+
if (typeof window !== "undefined" && !csrfToken) {
|
|
2360
|
+
console.warn("CSRF token recommended for browser-based OTP verification");
|
|
2361
|
+
}
|
|
2362
|
+
return this.create(
|
|
2363
|
+
this.siteUserEndpoint(siteName, "/users/verify-otp"),
|
|
2364
|
+
data,
|
|
2365
|
+
csrfToken
|
|
2366
|
+
);
|
|
2367
|
+
}
|
|
2368
|
+
/**
|
|
2369
|
+
* Verify OTP and automatically set the token for subsequent requests
|
|
2370
|
+
*
|
|
2371
|
+
* Convenience method that:
|
|
2372
|
+
* 1. Verifies the OTP
|
|
2373
|
+
* 2. Automatically calls setAuth() with the returned token
|
|
2374
|
+
*
|
|
2375
|
+
* Note: Token is stored in memory only and will be lost on page refresh.
|
|
2376
|
+
* For persistent auth, use verifyOtp() and store the token yourself.
|
|
2377
|
+
*
|
|
2378
|
+
* @param siteName - The site name
|
|
2379
|
+
* @param data - Email and code
|
|
2380
|
+
* @param csrfToken - CSRF token (required for browser-based submissions)
|
|
2381
|
+
*/
|
|
2382
|
+
async verifyOtpAndSetAuth(siteName, data, csrfToken) {
|
|
2383
|
+
const response = await this.verifyOtp(siteName, data, csrfToken);
|
|
2384
|
+
if (response.data?.token) {
|
|
2385
|
+
this.http.setAuth(response.data.token);
|
|
2386
|
+
}
|
|
2387
|
+
return response;
|
|
2388
|
+
}
|
|
2389
|
+
/**
|
|
2390
|
+
* Logout (clear session cookie)
|
|
2391
|
+
* @param siteName - The site name
|
|
2392
|
+
*/
|
|
2393
|
+
async logout(siteName) {
|
|
2394
|
+
return this.create(
|
|
2395
|
+
this.siteUserEndpoint(siteName, "/users/logout"),
|
|
2396
|
+
{}
|
|
2397
|
+
);
|
|
2398
|
+
}
|
|
2399
|
+
// ============================================================================
|
|
2400
|
+
// AUTHENTICATED ENDPOINTS (site user JWT required)
|
|
2401
|
+
// ============================================================================
|
|
2402
|
+
/**
|
|
2403
|
+
* Get current user profile
|
|
2404
|
+
* @param siteName - The site name
|
|
2405
|
+
*/
|
|
2406
|
+
async getMe(siteName) {
|
|
2407
|
+
return this.getSingle(
|
|
2408
|
+
this.siteUserEndpoint(siteName, "/users/me")
|
|
2409
|
+
);
|
|
2410
|
+
}
|
|
2411
|
+
/**
|
|
2412
|
+
* Update current user profile
|
|
2413
|
+
* @param siteName - The site name
|
|
2414
|
+
* @param data - Fields to update
|
|
2415
|
+
* @param csrfToken - CSRF token (required)
|
|
2416
|
+
*/
|
|
2417
|
+
async updateMe(siteName, data, csrfToken) {
|
|
2418
|
+
return this.patch(
|
|
2419
|
+
this.siteUserEndpoint(siteName, "/users/me"),
|
|
2420
|
+
data,
|
|
2421
|
+
csrfToken
|
|
2422
|
+
);
|
|
2423
|
+
}
|
|
2424
|
+
/**
|
|
2425
|
+
* Get all profile key-values
|
|
2426
|
+
* @param siteName - The site name
|
|
2427
|
+
*/
|
|
2428
|
+
async getProfile(siteName) {
|
|
2429
|
+
return this.getSingle(
|
|
2430
|
+
this.siteUserEndpoint(siteName, "/users/me/profile")
|
|
2431
|
+
);
|
|
2432
|
+
}
|
|
2433
|
+
/**
|
|
2434
|
+
* Set a profile key-value
|
|
2435
|
+
* @param siteName - The site name
|
|
2436
|
+
* @param key - Profile key (e.g., 'phone', 'whatsapp', 'address_shipping')
|
|
2437
|
+
* @param value - Profile value (string or JSON string)
|
|
2438
|
+
* @param csrfToken - CSRF token (required)
|
|
2439
|
+
*/
|
|
2440
|
+
async setProfileValue(siteName, key, value, csrfToken) {
|
|
2441
|
+
return this.update(
|
|
2442
|
+
this.siteUserEndpoint(siteName, `/users/me/profile/${encodeURIComponent(key)}`),
|
|
2443
|
+
{ value },
|
|
2444
|
+
csrfToken
|
|
2445
|
+
);
|
|
2446
|
+
}
|
|
2447
|
+
/**
|
|
2448
|
+
* Delete a profile key-value
|
|
2449
|
+
* @param siteName - The site name
|
|
2450
|
+
* @param key - Profile key to delete
|
|
2451
|
+
* @param csrfToken - CSRF token (required)
|
|
2452
|
+
*/
|
|
2453
|
+
async deleteProfileValue(siteName, key, csrfToken) {
|
|
2454
|
+
return this.delete(
|
|
2455
|
+
this.siteUserEndpoint(siteName, `/users/me/profile/${encodeURIComponent(key)}`),
|
|
2456
|
+
csrfToken
|
|
2457
|
+
);
|
|
2458
|
+
}
|
|
2459
|
+
/**
|
|
2460
|
+
* Get transaction/order history
|
|
2461
|
+
* @param siteName - The site name
|
|
2462
|
+
* @param params - Pagination params
|
|
2463
|
+
*/
|
|
2464
|
+
async getOrders(siteName, params) {
|
|
2465
|
+
return this.http.get(
|
|
2466
|
+
this.buildPath(this.siteUserEndpoint(siteName, "/users/me/orders")),
|
|
2467
|
+
params
|
|
2468
|
+
);
|
|
2469
|
+
}
|
|
2470
|
+
/**
|
|
2471
|
+
* Get single order detail
|
|
2472
|
+
* @param siteName - The site name
|
|
2473
|
+
* @param orderId - Order ID or session ID
|
|
2474
|
+
*/
|
|
2475
|
+
async getOrder(siteName, orderId) {
|
|
2476
|
+
return this.getSingle(
|
|
2477
|
+
this.siteUserEndpoint(siteName, `/users/me/orders/${encodeURIComponent(orderId)}`)
|
|
2478
|
+
);
|
|
2479
|
+
}
|
|
2480
|
+
/**
|
|
2481
|
+
* Get payment subscriptions
|
|
2482
|
+
* @param siteName - The site name
|
|
2483
|
+
* @param params - Pagination params
|
|
2484
|
+
*/
|
|
2485
|
+
async getSubscriptions(siteName, params) {
|
|
2486
|
+
return this.http.get(
|
|
2487
|
+
this.buildPath(this.siteUserEndpoint(siteName, "/users/me/subscriptions")),
|
|
2488
|
+
params
|
|
2489
|
+
);
|
|
2490
|
+
}
|
|
2491
|
+
/**
|
|
2492
|
+
* Get single subscription detail
|
|
2493
|
+
* @param siteName - The site name
|
|
2494
|
+
* @param id - Subscription ID
|
|
2495
|
+
*/
|
|
2496
|
+
async getSubscription(siteName, id) {
|
|
2497
|
+
return this.getSingle(
|
|
2498
|
+
this.siteUserEndpoint(siteName, `/users/me/subscriptions/${encodeURIComponent(id)}`)
|
|
2499
|
+
);
|
|
2500
|
+
}
|
|
2501
|
+
/**
|
|
2502
|
+
* Cancel a subscription (marks for cancellation at period end)
|
|
2503
|
+
* @param siteName - The site name
|
|
2504
|
+
* @param id - Subscription ID
|
|
2505
|
+
* @param csrfToken - CSRF token (required)
|
|
2506
|
+
*/
|
|
2507
|
+
async cancelSubscription(siteName, id, csrfToken) {
|
|
2508
|
+
return this.create(
|
|
2509
|
+
this.siteUserEndpoint(siteName, `/users/me/subscriptions/${encodeURIComponent(id)}/cancel`),
|
|
2510
|
+
{},
|
|
2511
|
+
csrfToken
|
|
2512
|
+
);
|
|
2513
|
+
}
|
|
2514
|
+
/**
|
|
2515
|
+
* Get linked newsletter subscriptions
|
|
2516
|
+
* @param siteName - The site name
|
|
2517
|
+
*/
|
|
2518
|
+
async getNewsletterSubscriptions(siteName) {
|
|
2519
|
+
return this.getSingle(
|
|
2520
|
+
this.siteUserEndpoint(siteName, "/users/me/newsletters")
|
|
2521
|
+
);
|
|
2522
|
+
}
|
|
2523
|
+
// ============================================================================
|
|
2524
|
+
// ADMIN ENDPOINTS (API key auth required)
|
|
2525
|
+
// ============================================================================
|
|
2526
|
+
/**
|
|
2527
|
+
* List all site users (admin only)
|
|
2528
|
+
* @param siteName - The site name
|
|
2529
|
+
* @param params - Query params (limit, offset, status)
|
|
2530
|
+
*/
|
|
2531
|
+
async listUsers(siteName, params) {
|
|
2532
|
+
return this.http.get(
|
|
2533
|
+
this.buildPath(this.siteUserEndpoint(siteName, "/users")),
|
|
2534
|
+
params
|
|
2535
|
+
);
|
|
2536
|
+
}
|
|
2537
|
+
/**
|
|
2538
|
+
* Get user detail (admin only)
|
|
2539
|
+
* @param siteName - The site name
|
|
2540
|
+
* @param userId - User ID
|
|
2541
|
+
*/
|
|
2542
|
+
async getUser(siteName, userId) {
|
|
2543
|
+
return this.getSingle(
|
|
2544
|
+
this.siteUserEndpoint(siteName, `/users/${encodeURIComponent(userId)}`)
|
|
2545
|
+
);
|
|
2546
|
+
}
|
|
2547
|
+
/**
|
|
2548
|
+
* Update user status (admin only)
|
|
2549
|
+
* @param siteName - The site name
|
|
2550
|
+
* @param userId - User ID
|
|
2551
|
+
* @param status - New status
|
|
2552
|
+
* @param csrfToken - CSRF token (required)
|
|
2553
|
+
*/
|
|
2554
|
+
async updateUserStatus(siteName, userId, status, csrfToken) {
|
|
2555
|
+
return this.patch(
|
|
2556
|
+
this.siteUserEndpoint(siteName, `/users/${encodeURIComponent(userId)}/status`),
|
|
2557
|
+
{ status },
|
|
2558
|
+
csrfToken
|
|
2559
|
+
);
|
|
2560
|
+
}
|
|
2561
|
+
};
|
|
2562
|
+
|
|
2239
2563
|
// src/perspect-api-client.ts
|
|
2240
2564
|
var PerspectApiClient = class {
|
|
2241
2565
|
http;
|
|
@@ -2252,6 +2576,7 @@ var PerspectApiClient = class {
|
|
|
2252
2576
|
checkout;
|
|
2253
2577
|
contact;
|
|
2254
2578
|
newsletter;
|
|
2579
|
+
siteUsers;
|
|
2255
2580
|
constructor(config) {
|
|
2256
2581
|
if (!config.baseUrl) {
|
|
2257
2582
|
throw new Error("baseUrl is required in PerspectApiConfig");
|
|
@@ -2269,6 +2594,7 @@ var PerspectApiClient = class {
|
|
|
2269
2594
|
this.checkout = new CheckoutClient(this.http, this.cache);
|
|
2270
2595
|
this.contact = new ContactClient(this.http, this.cache);
|
|
2271
2596
|
this.newsletter = new NewsletterClient(this.http, this.cache);
|
|
2597
|
+
this.siteUsers = new SiteUsersClient(this.http, this.cache);
|
|
2272
2598
|
}
|
|
2273
2599
|
/**
|
|
2274
2600
|
* Update authentication token
|
|
@@ -2958,6 +3284,7 @@ async function createCheckoutSession(options) {
|
|
|
2958
3284
|
OrganizationsClient,
|
|
2959
3285
|
PerspectApiClient,
|
|
2960
3286
|
ProductsClient,
|
|
3287
|
+
SiteUsersClient,
|
|
2961
3288
|
SitesClient,
|
|
2962
3289
|
WebhooksClient,
|
|
2963
3290
|
buildImageUrl,
|