perspectapi-ts-sdk 5.0.2 → 5.1.0

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.js CHANGED
@@ -27,6 +27,7 @@ __export(index_exports, {
27
27
  CacheManager: () => CacheManager,
28
28
  CategoriesClient: () => CategoriesClient,
29
29
  CheckoutClient: () => CheckoutClient,
30
+ CloudflareKVCacheAdapter: () => CloudflareKVCacheAdapter,
30
31
  ContactClient: () => ContactClient,
31
32
  ContentClient: () => ContentClient,
32
33
  DEFAULT_IMAGE_SIZES: () => DEFAULT_IMAGE_SIZES,
@@ -3342,9 +3343,11 @@ var PerspectV2Error = class extends Error {
3342
3343
  var BaseV2Client = class {
3343
3344
  http;
3344
3345
  basePath;
3345
- constructor(http, basePath) {
3346
+ cache;
3347
+ constructor(http, basePath, cache) {
3346
3348
  this.http = http;
3347
3349
  this.basePath = basePath;
3350
+ this.cache = cache && cache.isEnabled() ? cache : void 0;
3348
3351
  }
3349
3352
  buildPath(endpoint) {
3350
3353
  const clean = endpoint.replace(/^\//, "");
@@ -3386,15 +3389,21 @@ var BaseV2Client = class {
3386
3389
  }
3387
3390
  return payload;
3388
3391
  }
3389
- /** GET a single resource. */
3390
- async getOne(path, params) {
3391
- const response = await this.http.get(path, this.toParams(params));
3392
- return this.extractData(response);
3392
+ /** GET a single resource, with optional caching. */
3393
+ async getOne(path, params, cachePolicy) {
3394
+ const fetcher = async () => {
3395
+ const response = await this.http.get(path, this.toParams(params));
3396
+ return this.extractData(response);
3397
+ };
3398
+ return this.fetchWithCache(path, params, cachePolicy, fetcher);
3393
3399
  }
3394
- /** GET a list of resources with cursor pagination. */
3395
- async getList(path, params) {
3396
- const response = await this.http.get(path, this.toParams(params));
3397
- return this.extractData(response);
3400
+ /** GET a list of resources with cursor pagination, with optional caching. */
3401
+ async getList(path, params, cachePolicy) {
3402
+ const fetcher = async () => {
3403
+ const response = await this.http.get(path, this.toParams(params));
3404
+ return this.extractData(response);
3405
+ };
3406
+ return this.fetchWithCache(path, params, cachePolicy, fetcher);
3398
3407
  }
3399
3408
  /** POST to create a resource. */
3400
3409
  async post(path, body) {
@@ -3411,6 +3420,33 @@ var BaseV2Client = class {
3411
3420
  const response = await this.http.delete(path);
3412
3421
  return this.extractData(response);
3413
3422
  }
3423
+ /** Fetch with optional cache. Bypasses cache for writes or when no cache is configured. */
3424
+ async fetchWithCache(path, params, policy, fetcher) {
3425
+ if (!this.cache || policy?.skipCache) {
3426
+ return fetcher();
3427
+ }
3428
+ const key = this.buildCacheKey(path, params);
3429
+ return this.cache.getOrSet(key, fetcher, policy);
3430
+ }
3431
+ /** Invalidate cache entries by keys or tags. */
3432
+ async invalidateCache(options) {
3433
+ if (!this.cache) return;
3434
+ await this.cache.invalidate(options);
3435
+ }
3436
+ buildCacheKey(path, params) {
3437
+ const parts = [path];
3438
+ if (params && Object.keys(params).length > 0) {
3439
+ const sorted = {};
3440
+ for (const key of Object.keys(params).sort()) {
3441
+ sorted[key] = params[key];
3442
+ }
3443
+ parts.push(sorted);
3444
+ }
3445
+ if (this.cache) {
3446
+ return this.cache.buildKey(parts);
3447
+ }
3448
+ return parts.map((p) => typeof p === "string" ? p : JSON.stringify(p)).join(":");
3449
+ }
3414
3450
  /**
3415
3451
  * Auto-paginating async generator.
3416
3452
  * Yields every item across all pages.
@@ -3451,14 +3487,14 @@ var BaseV2Client = class {
3451
3487
 
3452
3488
  // src/v2/client/content-client.ts
3453
3489
  var ContentV2Client = class extends BaseV2Client {
3454
- async list(siteName, params) {
3455
- return this.getList(this.sitePath(siteName, "content"), params);
3490
+ async list(siteName, params, cachePolicy) {
3491
+ return this.getList(this.sitePath(siteName, "content"), params, cachePolicy);
3456
3492
  }
3457
3493
  async *listAutoPaginated(siteName, params) {
3458
3494
  yield* this.listAutoPaginate(this.sitePath(siteName, "content"), params);
3459
3495
  }
3460
- async get(siteName, idOrSlug) {
3461
- return this.getOne(this.sitePath(siteName, "content", idOrSlug));
3496
+ async get(siteName, idOrSlug, cachePolicy) {
3497
+ return this.getOne(this.sitePath(siteName, "content", idOrSlug), void 0, cachePolicy);
3462
3498
  }
3463
3499
  async create(siteName, data) {
3464
3500
  return this.post(this.sitePath(siteName, "content"), data);
@@ -3479,14 +3515,14 @@ var ContentV2Client = class extends BaseV2Client {
3479
3515
 
3480
3516
  // src/v2/client/products-client.ts
3481
3517
  var ProductsV2Client = class extends BaseV2Client {
3482
- async list(siteName, params) {
3483
- return this.getList(this.sitePath(siteName, "products"), params);
3518
+ async list(siteName, params, cachePolicy) {
3519
+ return this.getList(this.sitePath(siteName, "products"), params, cachePolicy);
3484
3520
  }
3485
3521
  async *listAutoPaginated(siteName, params) {
3486
3522
  yield* this.listAutoPaginate(this.sitePath(siteName, "products"), params);
3487
3523
  }
3488
- async get(siteName, idOrSlug) {
3489
- return this.getOne(this.sitePath(siteName, "products", idOrSlug));
3524
+ async get(siteName, idOrSlug, cachePolicy) {
3525
+ return this.getOne(this.sitePath(siteName, "products", idOrSlug), void 0, cachePolicy);
3490
3526
  }
3491
3527
  async create(siteName, data) {
3492
3528
  return this.post(this.sitePath(siteName, "products"), data);
@@ -3501,11 +3537,11 @@ var ProductsV2Client = class extends BaseV2Client {
3501
3537
 
3502
3538
  // src/v2/client/categories-client.ts
3503
3539
  var CategoriesV2Client = class extends BaseV2Client {
3504
- async list(siteName, params) {
3505
- return this.getList(this.sitePath(siteName, "categories"), params);
3540
+ async list(siteName, params, cachePolicy) {
3541
+ return this.getList(this.sitePath(siteName, "categories"), params, cachePolicy);
3506
3542
  }
3507
- async get(siteName, id) {
3508
- return this.getOne(this.sitePath(siteName, "categories", id));
3543
+ async get(siteName, id, cachePolicy) {
3544
+ return this.getOne(this.sitePath(siteName, "categories", id), void 0, cachePolicy);
3509
3545
  }
3510
3546
  async create(siteName, data) {
3511
3547
  return this.post(this.sitePath(siteName, "categories"), data);
@@ -3562,14 +3598,14 @@ var CollectionsV2Client = class extends BaseV2Client {
3562
3598
 
3563
3599
  // src/v2/client/orders-client.ts
3564
3600
  var OrdersV2Client = class extends BaseV2Client {
3565
- async list(siteName, params) {
3566
- return this.getList(this.sitePath(siteName, "orders"), params);
3601
+ async list(siteName, params, cachePolicy) {
3602
+ return this.getList(this.sitePath(siteName, "orders"), params, cachePolicy);
3567
3603
  }
3568
3604
  async *listAutoPaginated(siteName, params) {
3569
3605
  yield* this.listAutoPaginate(this.sitePath(siteName, "orders"), params);
3570
3606
  }
3571
- async get(siteName, id) {
3572
- return this.getOne(this.sitePath(siteName, "orders", id));
3607
+ async get(siteName, id, cachePolicy) {
3608
+ return this.getOne(this.sitePath(siteName, "orders", id), void 0, cachePolicy);
3573
3609
  }
3574
3610
  };
3575
3611
 
@@ -3617,34 +3653,53 @@ var NewsletterV2Client = class extends BaseV2Client {
3617
3653
  data
3618
3654
  );
3619
3655
  }
3656
+ async trackOpen(siteName, token) {
3657
+ return this.post(
3658
+ this.sitePath(siteName, "newsletter", `track/open/${encodeURIComponent(token)}`)
3659
+ );
3660
+ }
3661
+ async trackClick(siteName, token, url) {
3662
+ return this.post(
3663
+ this.sitePath(siteName, "newsletter", `track/click/${encodeURIComponent(token)}`),
3664
+ { url }
3665
+ );
3666
+ }
3620
3667
  // --- Subscriptions (admin) ---
3621
- async listSubscriptions(siteName, params) {
3668
+ async listSubscriptions(siteName, params, cachePolicy) {
3622
3669
  return this.getList(
3623
3670
  this.sitePath(siteName, "newsletter", "subscriptions"),
3624
- params
3671
+ params,
3672
+ cachePolicy
3625
3673
  );
3626
3674
  }
3627
- async getSubscription(siteName, id) {
3675
+ async getSubscription(siteName, id, cachePolicy) {
3628
3676
  return this.getOne(
3629
- this.sitePath(siteName, "newsletter", `subscriptions/${id}`)
3677
+ this.sitePath(siteName, "newsletter", `subscriptions/${id}`),
3678
+ void 0,
3679
+ cachePolicy
3630
3680
  );
3631
3681
  }
3632
3682
  // --- Lists ---
3633
- async listLists(siteName) {
3683
+ async listLists(siteName, cachePolicy) {
3634
3684
  return this.getList(
3635
- this.sitePath(siteName, "newsletter", "lists")
3685
+ this.sitePath(siteName, "newsletter", "lists"),
3686
+ void 0,
3687
+ cachePolicy
3636
3688
  );
3637
3689
  }
3638
3690
  // --- Campaigns ---
3639
- async listCampaigns(siteName, params) {
3691
+ async listCampaigns(siteName, params, cachePolicy) {
3640
3692
  return this.getList(
3641
3693
  this.sitePath(siteName, "newsletter", "campaigns"),
3642
- params
3694
+ params,
3695
+ cachePolicy
3643
3696
  );
3644
3697
  }
3645
- async getCampaign(siteName, idOrSlug) {
3698
+ async getCampaign(siteName, idOrSlug, cachePolicy) {
3646
3699
  return this.getOne(
3647
- this.sitePath(siteName, "newsletter", `campaigns/${idOrSlug}`)
3700
+ this.sitePath(siteName, "newsletter", `campaigns/${idOrSlug}`),
3701
+ void 0,
3702
+ cachePolicy
3648
3703
  );
3649
3704
  }
3650
3705
  };
@@ -3717,6 +3772,7 @@ var WebhooksV2Client = class extends BaseV2Client {
3717
3772
  // src/v2/index.ts
3718
3773
  var PerspectApiV2Client = class {
3719
3774
  http;
3775
+ cache;
3720
3776
  content;
3721
3777
  products;
3722
3778
  categories;
@@ -3733,19 +3789,21 @@ var PerspectApiV2Client = class {
3733
3789
  const baseUrl = config.baseUrl.replace(/\/+$/, "");
3734
3790
  const v2BaseUrl = baseUrl.endsWith("/api/v2") ? baseUrl : `${baseUrl}/api/v2`;
3735
3791
  this.http = new HttpClient({ ...config, baseUrl: v2BaseUrl });
3792
+ this.cache = new CacheManager(config.cache);
3736
3793
  const basePath = "";
3737
- this.content = new ContentV2Client(this.http, basePath);
3738
- this.products = new ProductsV2Client(this.http, basePath);
3739
- this.categories = new CategoriesV2Client(this.http, basePath);
3740
- this.collections = new CollectionsV2Client(this.http, basePath);
3741
- this.orders = new OrdersV2Client(this.http, basePath);
3742
- this.siteUsers = new SiteUsersV2Client(this.http, basePath);
3743
- this.newsletter = new NewsletterV2Client(this.http, basePath);
3744
- this.contacts = new ContactsV2Client(this.http, basePath);
3745
- this.organizations = new OrganizationsV2Client(this.http, basePath);
3746
- this.sites = new SitesV2Client(this.http, basePath);
3747
- this.apiKeys = new ApiKeysV2Client(this.http, basePath);
3748
- this.webhooks = new WebhooksV2Client(this.http, basePath);
3794
+ const cache = this.cache;
3795
+ this.content = new ContentV2Client(this.http, basePath, cache);
3796
+ this.products = new ProductsV2Client(this.http, basePath, cache);
3797
+ this.categories = new CategoriesV2Client(this.http, basePath, cache);
3798
+ this.collections = new CollectionsV2Client(this.http, basePath, cache);
3799
+ this.orders = new OrdersV2Client(this.http, basePath, cache);
3800
+ this.siteUsers = new SiteUsersV2Client(this.http, basePath, cache);
3801
+ this.newsletter = new NewsletterV2Client(this.http, basePath, cache);
3802
+ this.contacts = new ContactsV2Client(this.http, basePath, cache);
3803
+ this.organizations = new OrganizationsV2Client(this.http, basePath, cache);
3804
+ this.sites = new SitesV2Client(this.http, basePath, cache);
3805
+ this.apiKeys = new ApiKeysV2Client(this.http, basePath, cache);
3806
+ this.webhooks = new WebhooksV2Client(this.http, basePath, cache);
3749
3807
  }
3750
3808
  /** Update the JWT token for authenticated requests. */
3751
3809
  setAuth(jwt) {
@@ -3764,6 +3822,35 @@ function createPerspectApiV2Client(config) {
3764
3822
  return new PerspectApiV2Client(config);
3765
3823
  }
3766
3824
 
3825
+ // src/cache/cloudflare-kv-adapter.ts
3826
+ var CloudflareKVCacheAdapter = class {
3827
+ kv;
3828
+ constructor(kv) {
3829
+ this.kv = kv;
3830
+ }
3831
+ async get(key) {
3832
+ return this.kv.get(key);
3833
+ }
3834
+ async set(key, value, options) {
3835
+ await this.kv.put(key, value, options?.ttlSeconds ? { expirationTtl: options.ttlSeconds } : void 0);
3836
+ }
3837
+ async delete(key) {
3838
+ await this.kv.delete(key);
3839
+ }
3840
+ async deleteMany(keys) {
3841
+ if (this.kv.deleteMultiple) {
3842
+ await this.kv.deleteMultiple(keys);
3843
+ } else {
3844
+ await Promise.all(keys.map((k) => this.kv.delete(k)));
3845
+ }
3846
+ }
3847
+ async clear() {
3848
+ if (this.kv.clear) {
3849
+ await this.kv.clear();
3850
+ }
3851
+ }
3852
+ };
3853
+
3767
3854
  // src/utils/image-transform.ts
3768
3855
  var DEFAULT_IMAGE_SIZES = {
3769
3856
  thumbnail: {
@@ -4379,6 +4466,7 @@ async function createCheckoutSession(options) {
4379
4466
  CacheManager,
4380
4467
  CategoriesClient,
4381
4468
  CheckoutClient,
4469
+ CloudflareKVCacheAdapter,
4382
4470
  ContactClient,
4383
4471
  ContentClient,
4384
4472
  DEFAULT_IMAGE_SIZES,
package/dist/index.mjs CHANGED
@@ -3275,9 +3275,11 @@ var PerspectV2Error = class extends Error {
3275
3275
  var BaseV2Client = class {
3276
3276
  http;
3277
3277
  basePath;
3278
- constructor(http, basePath) {
3278
+ cache;
3279
+ constructor(http, basePath, cache) {
3279
3280
  this.http = http;
3280
3281
  this.basePath = basePath;
3282
+ this.cache = cache && cache.isEnabled() ? cache : void 0;
3281
3283
  }
3282
3284
  buildPath(endpoint) {
3283
3285
  const clean = endpoint.replace(/^\//, "");
@@ -3319,15 +3321,21 @@ var BaseV2Client = class {
3319
3321
  }
3320
3322
  return payload;
3321
3323
  }
3322
- /** GET a single resource. */
3323
- async getOne(path, params) {
3324
- const response = await this.http.get(path, this.toParams(params));
3325
- return this.extractData(response);
3324
+ /** GET a single resource, with optional caching. */
3325
+ async getOne(path, params, cachePolicy) {
3326
+ const fetcher = async () => {
3327
+ const response = await this.http.get(path, this.toParams(params));
3328
+ return this.extractData(response);
3329
+ };
3330
+ return this.fetchWithCache(path, params, cachePolicy, fetcher);
3326
3331
  }
3327
- /** GET a list of resources with cursor pagination. */
3328
- async getList(path, params) {
3329
- const response = await this.http.get(path, this.toParams(params));
3330
- return this.extractData(response);
3332
+ /** GET a list of resources with cursor pagination, with optional caching. */
3333
+ async getList(path, params, cachePolicy) {
3334
+ const fetcher = async () => {
3335
+ const response = await this.http.get(path, this.toParams(params));
3336
+ return this.extractData(response);
3337
+ };
3338
+ return this.fetchWithCache(path, params, cachePolicy, fetcher);
3331
3339
  }
3332
3340
  /** POST to create a resource. */
3333
3341
  async post(path, body) {
@@ -3344,6 +3352,33 @@ var BaseV2Client = class {
3344
3352
  const response = await this.http.delete(path);
3345
3353
  return this.extractData(response);
3346
3354
  }
3355
+ /** Fetch with optional cache. Bypasses cache for writes or when no cache is configured. */
3356
+ async fetchWithCache(path, params, policy, fetcher) {
3357
+ if (!this.cache || policy?.skipCache) {
3358
+ return fetcher();
3359
+ }
3360
+ const key = this.buildCacheKey(path, params);
3361
+ return this.cache.getOrSet(key, fetcher, policy);
3362
+ }
3363
+ /** Invalidate cache entries by keys or tags. */
3364
+ async invalidateCache(options) {
3365
+ if (!this.cache) return;
3366
+ await this.cache.invalidate(options);
3367
+ }
3368
+ buildCacheKey(path, params) {
3369
+ const parts = [path];
3370
+ if (params && Object.keys(params).length > 0) {
3371
+ const sorted = {};
3372
+ for (const key of Object.keys(params).sort()) {
3373
+ sorted[key] = params[key];
3374
+ }
3375
+ parts.push(sorted);
3376
+ }
3377
+ if (this.cache) {
3378
+ return this.cache.buildKey(parts);
3379
+ }
3380
+ return parts.map((p) => typeof p === "string" ? p : JSON.stringify(p)).join(":");
3381
+ }
3347
3382
  /**
3348
3383
  * Auto-paginating async generator.
3349
3384
  * Yields every item across all pages.
@@ -3384,14 +3419,14 @@ var BaseV2Client = class {
3384
3419
 
3385
3420
  // src/v2/client/content-client.ts
3386
3421
  var ContentV2Client = class extends BaseV2Client {
3387
- async list(siteName, params) {
3388
- return this.getList(this.sitePath(siteName, "content"), params);
3422
+ async list(siteName, params, cachePolicy) {
3423
+ return this.getList(this.sitePath(siteName, "content"), params, cachePolicy);
3389
3424
  }
3390
3425
  async *listAutoPaginated(siteName, params) {
3391
3426
  yield* this.listAutoPaginate(this.sitePath(siteName, "content"), params);
3392
3427
  }
3393
- async get(siteName, idOrSlug) {
3394
- return this.getOne(this.sitePath(siteName, "content", idOrSlug));
3428
+ async get(siteName, idOrSlug, cachePolicy) {
3429
+ return this.getOne(this.sitePath(siteName, "content", idOrSlug), void 0, cachePolicy);
3395
3430
  }
3396
3431
  async create(siteName, data) {
3397
3432
  return this.post(this.sitePath(siteName, "content"), data);
@@ -3412,14 +3447,14 @@ var ContentV2Client = class extends BaseV2Client {
3412
3447
 
3413
3448
  // src/v2/client/products-client.ts
3414
3449
  var ProductsV2Client = class extends BaseV2Client {
3415
- async list(siteName, params) {
3416
- return this.getList(this.sitePath(siteName, "products"), params);
3450
+ async list(siteName, params, cachePolicy) {
3451
+ return this.getList(this.sitePath(siteName, "products"), params, cachePolicy);
3417
3452
  }
3418
3453
  async *listAutoPaginated(siteName, params) {
3419
3454
  yield* this.listAutoPaginate(this.sitePath(siteName, "products"), params);
3420
3455
  }
3421
- async get(siteName, idOrSlug) {
3422
- return this.getOne(this.sitePath(siteName, "products", idOrSlug));
3456
+ async get(siteName, idOrSlug, cachePolicy) {
3457
+ return this.getOne(this.sitePath(siteName, "products", idOrSlug), void 0, cachePolicy);
3423
3458
  }
3424
3459
  async create(siteName, data) {
3425
3460
  return this.post(this.sitePath(siteName, "products"), data);
@@ -3434,11 +3469,11 @@ var ProductsV2Client = class extends BaseV2Client {
3434
3469
 
3435
3470
  // src/v2/client/categories-client.ts
3436
3471
  var CategoriesV2Client = class extends BaseV2Client {
3437
- async list(siteName, params) {
3438
- return this.getList(this.sitePath(siteName, "categories"), params);
3472
+ async list(siteName, params, cachePolicy) {
3473
+ return this.getList(this.sitePath(siteName, "categories"), params, cachePolicy);
3439
3474
  }
3440
- async get(siteName, id) {
3441
- return this.getOne(this.sitePath(siteName, "categories", id));
3475
+ async get(siteName, id, cachePolicy) {
3476
+ return this.getOne(this.sitePath(siteName, "categories", id), void 0, cachePolicy);
3442
3477
  }
3443
3478
  async create(siteName, data) {
3444
3479
  return this.post(this.sitePath(siteName, "categories"), data);
@@ -3495,14 +3530,14 @@ var CollectionsV2Client = class extends BaseV2Client {
3495
3530
 
3496
3531
  // src/v2/client/orders-client.ts
3497
3532
  var OrdersV2Client = class extends BaseV2Client {
3498
- async list(siteName, params) {
3499
- return this.getList(this.sitePath(siteName, "orders"), params);
3533
+ async list(siteName, params, cachePolicy) {
3534
+ return this.getList(this.sitePath(siteName, "orders"), params, cachePolicy);
3500
3535
  }
3501
3536
  async *listAutoPaginated(siteName, params) {
3502
3537
  yield* this.listAutoPaginate(this.sitePath(siteName, "orders"), params);
3503
3538
  }
3504
- async get(siteName, id) {
3505
- return this.getOne(this.sitePath(siteName, "orders", id));
3539
+ async get(siteName, id, cachePolicy) {
3540
+ return this.getOne(this.sitePath(siteName, "orders", id), void 0, cachePolicy);
3506
3541
  }
3507
3542
  };
3508
3543
 
@@ -3550,34 +3585,53 @@ var NewsletterV2Client = class extends BaseV2Client {
3550
3585
  data
3551
3586
  );
3552
3587
  }
3588
+ async trackOpen(siteName, token) {
3589
+ return this.post(
3590
+ this.sitePath(siteName, "newsletter", `track/open/${encodeURIComponent(token)}`)
3591
+ );
3592
+ }
3593
+ async trackClick(siteName, token, url) {
3594
+ return this.post(
3595
+ this.sitePath(siteName, "newsletter", `track/click/${encodeURIComponent(token)}`),
3596
+ { url }
3597
+ );
3598
+ }
3553
3599
  // --- Subscriptions (admin) ---
3554
- async listSubscriptions(siteName, params) {
3600
+ async listSubscriptions(siteName, params, cachePolicy) {
3555
3601
  return this.getList(
3556
3602
  this.sitePath(siteName, "newsletter", "subscriptions"),
3557
- params
3603
+ params,
3604
+ cachePolicy
3558
3605
  );
3559
3606
  }
3560
- async getSubscription(siteName, id) {
3607
+ async getSubscription(siteName, id, cachePolicy) {
3561
3608
  return this.getOne(
3562
- this.sitePath(siteName, "newsletter", `subscriptions/${id}`)
3609
+ this.sitePath(siteName, "newsletter", `subscriptions/${id}`),
3610
+ void 0,
3611
+ cachePolicy
3563
3612
  );
3564
3613
  }
3565
3614
  // --- Lists ---
3566
- async listLists(siteName) {
3615
+ async listLists(siteName, cachePolicy) {
3567
3616
  return this.getList(
3568
- this.sitePath(siteName, "newsletter", "lists")
3617
+ this.sitePath(siteName, "newsletter", "lists"),
3618
+ void 0,
3619
+ cachePolicy
3569
3620
  );
3570
3621
  }
3571
3622
  // --- Campaigns ---
3572
- async listCampaigns(siteName, params) {
3623
+ async listCampaigns(siteName, params, cachePolicy) {
3573
3624
  return this.getList(
3574
3625
  this.sitePath(siteName, "newsletter", "campaigns"),
3575
- params
3626
+ params,
3627
+ cachePolicy
3576
3628
  );
3577
3629
  }
3578
- async getCampaign(siteName, idOrSlug) {
3630
+ async getCampaign(siteName, idOrSlug, cachePolicy) {
3579
3631
  return this.getOne(
3580
- this.sitePath(siteName, "newsletter", `campaigns/${idOrSlug}`)
3632
+ this.sitePath(siteName, "newsletter", `campaigns/${idOrSlug}`),
3633
+ void 0,
3634
+ cachePolicy
3581
3635
  );
3582
3636
  }
3583
3637
  };
@@ -3650,6 +3704,7 @@ var WebhooksV2Client = class extends BaseV2Client {
3650
3704
  // src/v2/index.ts
3651
3705
  var PerspectApiV2Client = class {
3652
3706
  http;
3707
+ cache;
3653
3708
  content;
3654
3709
  products;
3655
3710
  categories;
@@ -3666,19 +3721,21 @@ var PerspectApiV2Client = class {
3666
3721
  const baseUrl = config.baseUrl.replace(/\/+$/, "");
3667
3722
  const v2BaseUrl = baseUrl.endsWith("/api/v2") ? baseUrl : `${baseUrl}/api/v2`;
3668
3723
  this.http = new HttpClient({ ...config, baseUrl: v2BaseUrl });
3724
+ this.cache = new CacheManager(config.cache);
3669
3725
  const basePath = "";
3670
- this.content = new ContentV2Client(this.http, basePath);
3671
- this.products = new ProductsV2Client(this.http, basePath);
3672
- this.categories = new CategoriesV2Client(this.http, basePath);
3673
- this.collections = new CollectionsV2Client(this.http, basePath);
3674
- this.orders = new OrdersV2Client(this.http, basePath);
3675
- this.siteUsers = new SiteUsersV2Client(this.http, basePath);
3676
- this.newsletter = new NewsletterV2Client(this.http, basePath);
3677
- this.contacts = new ContactsV2Client(this.http, basePath);
3678
- this.organizations = new OrganizationsV2Client(this.http, basePath);
3679
- this.sites = new SitesV2Client(this.http, basePath);
3680
- this.apiKeys = new ApiKeysV2Client(this.http, basePath);
3681
- this.webhooks = new WebhooksV2Client(this.http, basePath);
3726
+ const cache = this.cache;
3727
+ this.content = new ContentV2Client(this.http, basePath, cache);
3728
+ this.products = new ProductsV2Client(this.http, basePath, cache);
3729
+ this.categories = new CategoriesV2Client(this.http, basePath, cache);
3730
+ this.collections = new CollectionsV2Client(this.http, basePath, cache);
3731
+ this.orders = new OrdersV2Client(this.http, basePath, cache);
3732
+ this.siteUsers = new SiteUsersV2Client(this.http, basePath, cache);
3733
+ this.newsletter = new NewsletterV2Client(this.http, basePath, cache);
3734
+ this.contacts = new ContactsV2Client(this.http, basePath, cache);
3735
+ this.organizations = new OrganizationsV2Client(this.http, basePath, cache);
3736
+ this.sites = new SitesV2Client(this.http, basePath, cache);
3737
+ this.apiKeys = new ApiKeysV2Client(this.http, basePath, cache);
3738
+ this.webhooks = new WebhooksV2Client(this.http, basePath, cache);
3682
3739
  }
3683
3740
  /** Update the JWT token for authenticated requests. */
3684
3741
  setAuth(jwt) {
@@ -3697,6 +3754,35 @@ function createPerspectApiV2Client(config) {
3697
3754
  return new PerspectApiV2Client(config);
3698
3755
  }
3699
3756
 
3757
+ // src/cache/cloudflare-kv-adapter.ts
3758
+ var CloudflareKVCacheAdapter = class {
3759
+ kv;
3760
+ constructor(kv) {
3761
+ this.kv = kv;
3762
+ }
3763
+ async get(key) {
3764
+ return this.kv.get(key);
3765
+ }
3766
+ async set(key, value, options) {
3767
+ await this.kv.put(key, value, options?.ttlSeconds ? { expirationTtl: options.ttlSeconds } : void 0);
3768
+ }
3769
+ async delete(key) {
3770
+ await this.kv.delete(key);
3771
+ }
3772
+ async deleteMany(keys) {
3773
+ if (this.kv.deleteMultiple) {
3774
+ await this.kv.deleteMultiple(keys);
3775
+ } else {
3776
+ await Promise.all(keys.map((k) => this.kv.delete(k)));
3777
+ }
3778
+ }
3779
+ async clear() {
3780
+ if (this.kv.clear) {
3781
+ await this.kv.clear();
3782
+ }
3783
+ }
3784
+ };
3785
+
3700
3786
  // src/utils/image-transform.ts
3701
3787
  var DEFAULT_IMAGE_SIZES = {
3702
3788
  thumbnail: {
@@ -4311,6 +4397,7 @@ export {
4311
4397
  CacheManager,
4312
4398
  CategoriesClient,
4313
4399
  CheckoutClient,
4400
+ CloudflareKVCacheAdapter,
4314
4401
  ContactClient,
4315
4402
  ContentClient,
4316
4403
  DEFAULT_IMAGE_SIZES,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "perspectapi-ts-sdk",
3
- "version": "5.0.2",
3
+ "version": "5.1.0",
4
4
  "description": "TypeScript SDK for PerspectAPI - Cloudflare Workers compatible",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Adapter that bridges a CacheStorage-compatible KV implementation
3
+ * (e.g. CloudflareKvAdapter from @perspect/shared) to the SDK's CacheAdapter interface.
4
+ *
5
+ * Usage:
6
+ * import { CloudflareKvAdapter } from '@perspect/shared';
7
+ * import { CloudflareKVCacheAdapter } from 'perspectapi-ts-sdk';
8
+ *
9
+ * const kvAdapter = new CloudflareKvAdapter(env.CACHE_KV);
10
+ * const cacheAdapter = new CloudflareKVCacheAdapter(kvAdapter);
11
+ *
12
+ * Or pass any object with get/put/delete methods matching Cloudflare KV semantics.
13
+ */
14
+
15
+ import type { CacheAdapter } from './types';
16
+
17
+ /** Minimal interface matching CloudflareKvAdapter / CacheStorage from @perspect/shared. */
18
+ export interface KVLike {
19
+ get(key: string): Promise<string | null>;
20
+ put(key: string, value: string, options?: { expirationTtl?: number }): Promise<void>;
21
+ delete(key: string): Promise<void>;
22
+ deleteMultiple?(keys: string[]): Promise<void>;
23
+ clear?(): Promise<void>;
24
+ }
25
+
26
+ export class CloudflareKVCacheAdapter implements CacheAdapter {
27
+ private kv: KVLike;
28
+
29
+ constructor(kv: KVLike) {
30
+ this.kv = kv;
31
+ }
32
+
33
+ async get(key: string): Promise<string | null> {
34
+ return this.kv.get(key);
35
+ }
36
+
37
+ async set(key: string, value: string, options?: { ttlSeconds?: number }): Promise<void> {
38
+ await this.kv.put(key, value, options?.ttlSeconds ? { expirationTtl: options.ttlSeconds } : undefined);
39
+ }
40
+
41
+ async delete(key: string): Promise<void> {
42
+ await this.kv.delete(key);
43
+ }
44
+
45
+ async deleteMany(keys: string[]): Promise<void> {
46
+ if (this.kv.deleteMultiple) {
47
+ await this.kv.deleteMultiple(keys);
48
+ } else {
49
+ await Promise.all(keys.map((k) => this.kv.delete(k)));
50
+ }
51
+ }
52
+
53
+ async clear(): Promise<void> {
54
+ if (this.kv.clear) {
55
+ await this.kv.clear();
56
+ }
57
+ }
58
+ }
package/src/index.ts CHANGED
@@ -35,6 +35,7 @@ export { HttpClient, createApiError } from './utils/http-client';
35
35
 
36
36
  // Cache utilities
37
37
  export { CacheManager } from './cache/cache-manager';
38
+ export { CloudflareKVCacheAdapter } from './cache/cloudflare-kv-adapter';
38
39
  export { InMemoryCacheAdapter } from './cache/in-memory-adapter';
39
40
  export { NoopCacheAdapter } from './cache/noop-adapter';
40
41