perspectapi-ts-sdk 2.6.0 → 2.8.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/README.md +14 -1
- package/dist/index.d.mts +370 -2
- package/dist/index.d.ts +370 -2
- package/dist/index.js +377 -2
- package/dist/index.mjs +376 -2
- package/package.json +1 -1
- package/src/client/content-client.ts +67 -1
- package/src/client/products-client.ts +123 -0
- package/src/client/site-users-client.ts +352 -0
- package/src/index.ts +13 -1
- package/src/perspect-api-client.ts +3 -0
- package/src/types/index.ts +106 -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.`);
|
|
@@ -902,6 +903,50 @@ var ContentClient = class extends BaseClient {
|
|
|
902
903
|
() => this.http.get(path)
|
|
903
904
|
);
|
|
904
905
|
}
|
|
906
|
+
/**
|
|
907
|
+
* Get content by category slug for a site
|
|
908
|
+
*/
|
|
909
|
+
async getContentByCategorySlug(siteName, categorySlug, params, cachePolicy) {
|
|
910
|
+
const endpoint = this.siteScopedEndpoint(
|
|
911
|
+
siteName,
|
|
912
|
+
`/category/${encodeURIComponent(categorySlug)}`
|
|
913
|
+
);
|
|
914
|
+
const path = this.buildPath(endpoint);
|
|
915
|
+
const normalizedParams = params ? { ...params } : void 0;
|
|
916
|
+
if (normalizedParams) {
|
|
917
|
+
const validatedLimit = validateOptionalLimit(
|
|
918
|
+
normalizedParams.limit,
|
|
919
|
+
"content category query"
|
|
920
|
+
);
|
|
921
|
+
if (validatedLimit !== void 0) {
|
|
922
|
+
normalizedParams.limit = validatedLimit;
|
|
923
|
+
} else {
|
|
924
|
+
delete normalizedParams.limit;
|
|
925
|
+
}
|
|
926
|
+
const validatedPageType = validateOptionalContentType(
|
|
927
|
+
normalizedParams.page_type,
|
|
928
|
+
"content category query"
|
|
929
|
+
);
|
|
930
|
+
if (validatedPageType !== void 0) {
|
|
931
|
+
normalizedParams.page_type = validatedPageType;
|
|
932
|
+
} else {
|
|
933
|
+
delete normalizedParams.page_type;
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
return this.fetchWithCache(
|
|
937
|
+
endpoint,
|
|
938
|
+
normalizedParams,
|
|
939
|
+
this.buildContentTags(
|
|
940
|
+
siteName,
|
|
941
|
+
void 0,
|
|
942
|
+
void 0,
|
|
943
|
+
normalizedParams?.slug_prefix,
|
|
944
|
+
categorySlug
|
|
945
|
+
),
|
|
946
|
+
cachePolicy,
|
|
947
|
+
() => this.http.get(path, normalizedParams)
|
|
948
|
+
);
|
|
949
|
+
}
|
|
905
950
|
/**
|
|
906
951
|
* Get content by slug for a site
|
|
907
952
|
*/
|
|
@@ -977,7 +1022,7 @@ var ContentClient = class extends BaseClient {
|
|
|
977
1022
|
async duplicateContent(id) {
|
|
978
1023
|
return this.create(`/content/${id}/duplicate`, {});
|
|
979
1024
|
}
|
|
980
|
-
buildContentTags(siteName, slug, id, slugPrefix) {
|
|
1025
|
+
buildContentTags(siteName, slug, id, slugPrefix, categorySlug) {
|
|
981
1026
|
const tags = /* @__PURE__ */ new Set(["content"]);
|
|
982
1027
|
if (siteName) {
|
|
983
1028
|
tags.add(`content:site:${siteName}`);
|
|
@@ -991,6 +1036,10 @@ var ContentClient = class extends BaseClient {
|
|
|
991
1036
|
if (slugPrefix) {
|
|
992
1037
|
tags.add(`content:prefix:${slugPrefix}`);
|
|
993
1038
|
}
|
|
1039
|
+
if (categorySlug && siteName) {
|
|
1040
|
+
tags.add("content:category");
|
|
1041
|
+
tags.add(`content:category:${siteName}:${categorySlug}`);
|
|
1042
|
+
}
|
|
994
1043
|
return Array.from(tags.values());
|
|
995
1044
|
}
|
|
996
1045
|
/**
|
|
@@ -1474,6 +1523,64 @@ var ProductsClient = class extends BaseClient {
|
|
|
1474
1523
|
}
|
|
1475
1524
|
return void 0;
|
|
1476
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
|
+
}
|
|
1477
1584
|
};
|
|
1478
1585
|
|
|
1479
1586
|
// src/client/categories-client.ts
|
|
@@ -2188,6 +2295,271 @@ var NewsletterClient = class extends BaseClient {
|
|
|
2188
2295
|
}
|
|
2189
2296
|
};
|
|
2190
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
|
+
|
|
2191
2563
|
// src/perspect-api-client.ts
|
|
2192
2564
|
var PerspectApiClient = class {
|
|
2193
2565
|
http;
|
|
@@ -2204,6 +2576,7 @@ var PerspectApiClient = class {
|
|
|
2204
2576
|
checkout;
|
|
2205
2577
|
contact;
|
|
2206
2578
|
newsletter;
|
|
2579
|
+
siteUsers;
|
|
2207
2580
|
constructor(config) {
|
|
2208
2581
|
if (!config.baseUrl) {
|
|
2209
2582
|
throw new Error("baseUrl is required in PerspectApiConfig");
|
|
@@ -2221,6 +2594,7 @@ var PerspectApiClient = class {
|
|
|
2221
2594
|
this.checkout = new CheckoutClient(this.http, this.cache);
|
|
2222
2595
|
this.contact = new ContactClient(this.http, this.cache);
|
|
2223
2596
|
this.newsletter = new NewsletterClient(this.http, this.cache);
|
|
2597
|
+
this.siteUsers = new SiteUsersClient(this.http, this.cache);
|
|
2224
2598
|
}
|
|
2225
2599
|
/**
|
|
2226
2600
|
* Update authentication token
|
|
@@ -2910,6 +3284,7 @@ async function createCheckoutSession(options) {
|
|
|
2910
3284
|
OrganizationsClient,
|
|
2911
3285
|
PerspectApiClient,
|
|
2912
3286
|
ProductsClient,
|
|
3287
|
+
SiteUsersClient,
|
|
2913
3288
|
SitesClient,
|
|
2914
3289
|
WebhooksClient,
|
|
2915
3290
|
buildImageUrl,
|