perspectapi-ts-sdk 5.4.5 → 6.0.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/dist/index.js CHANGED
@@ -399,11 +399,7 @@ var CacheManager = class {
399
399
  async getOrSet(key, resolveValue, policy) {
400
400
  if (!this.enabled || policy?.skipCache) {
401
401
  console.log("[Cache] Cache disabled or skipped", { key, enabled: this.enabled, skipCache: policy?.skipCache });
402
- const value2 = await resolveValue();
403
- if (this.enabled && !policy?.skipCache && policy?.ttlSeconds !== 0) {
404
- await this.set(key, value2, policy);
405
- }
406
- return value2;
402
+ return resolveValue();
407
403
  }
408
404
  const namespacedKey = this.namespacedKey(key);
409
405
  const cachedRaw = await this.adapter.get(namespacedKey);
@@ -426,7 +422,7 @@ var CacheManager = class {
426
422
  return value;
427
423
  }
428
424
  async set(key, value, options) {
429
- if (!this.enabled || options?.ttlSeconds === 0) {
425
+ if (!this.enabled) {
430
426
  return;
431
427
  }
432
428
  const namespacedKey = this.namespacedKey(key);
@@ -3422,6 +3418,11 @@ var BaseV2Client = class {
3422
3418
  const response = await this.http.patch(path, body);
3423
3419
  return this.extractData(response);
3424
3420
  }
3421
+ /** PUT to upsert a resource. */
3422
+ async putOne(path, body) {
3423
+ const response = await this.http.put(path, body);
3424
+ return this.extractData(response);
3425
+ }
3425
3426
  /** DELETE a resource. */
3426
3427
  async deleteOne(path) {
3427
3428
  const response = await this.http.delete(path);
@@ -3495,13 +3496,47 @@ var BaseV2Client = class {
3495
3496
  // src/v2/client/content-client.ts
3496
3497
  var ContentV2Client = class extends BaseV2Client {
3497
3498
  async list(siteName, params, cachePolicy) {
3498
- return this.getList(this.sitePath(siteName, "content"), params, cachePolicy);
3499
+ return this.getList(
3500
+ this.sitePath(siteName, "content"),
3501
+ params,
3502
+ this.withContentTags(siteName, cachePolicy, {
3503
+ category: params?.category,
3504
+ slugPrefix: params?.slug_prefix,
3505
+ type: params?.type
3506
+ })
3507
+ );
3499
3508
  }
3500
- async *listAutoPaginated(siteName, params) {
3501
- yield* this.listAutoPaginate(this.sitePath(siteName, "content"), params);
3509
+ async *listAutoPaginated(siteName, params, cachePolicy) {
3510
+ let startingAfter;
3511
+ let hasMore = true;
3512
+ while (hasMore) {
3513
+ const queryParams = { ...params ?? {} };
3514
+ if (startingAfter) {
3515
+ queryParams.starting_after = startingAfter;
3516
+ }
3517
+ const page = await this.list(siteName, queryParams, cachePolicy);
3518
+ for (const item of page.data) {
3519
+ yield item;
3520
+ }
3521
+ hasMore = page.has_more;
3522
+ if (page.data.length > 0) {
3523
+ startingAfter = page.data[page.data.length - 1].id;
3524
+ } else {
3525
+ hasMore = false;
3526
+ }
3527
+ }
3502
3528
  }
3503
3529
  async get(siteName, idOrSlug, cachePolicy) {
3504
- return this.getOne(this.sitePath(siteName, "content", idOrSlug), void 0, cachePolicy);
3530
+ const isContentId = this.isContentId(idOrSlug);
3531
+ return this.getOne(
3532
+ this.sitePath(siteName, "content", idOrSlug),
3533
+ void 0,
3534
+ this.withContentTags(siteName, cachePolicy, {
3535
+ id: isContentId ? idOrSlug : void 0,
3536
+ slug: isContentId ? void 0 : idOrSlug,
3537
+ slugPrefix: isContentId ? void 0 : this.extractSlugPrefix(idOrSlug)
3538
+ })
3539
+ );
3505
3540
  }
3506
3541
  async create(siteName, data) {
3507
3542
  return this.post(this.sitePath(siteName, "content"), data);
@@ -3518,6 +3553,56 @@ var ContentV2Client = class extends BaseV2Client {
3518
3553
  async unpublish(siteName, id) {
3519
3554
  return this.post(this.sitePath(siteName, "content", `${id}/unpublish`));
3520
3555
  }
3556
+ withContentTags(siteName, cachePolicy, options) {
3557
+ const tags = new Set(cachePolicy?.tags ?? []);
3558
+ for (const tag of this.buildContentTags(siteName, options)) {
3559
+ tags.add(tag);
3560
+ }
3561
+ return {
3562
+ ...cachePolicy,
3563
+ tags: Array.from(tags)
3564
+ };
3565
+ }
3566
+ buildContentTags(siteName, options) {
3567
+ const tags = /* @__PURE__ */ new Set(["content", `content:site:${siteName}`]);
3568
+ const normalizedPrefix = this.normalizeTagPart(options.slugPrefix);
3569
+ const normalizedCategory = this.normalizeTagPart(options.category);
3570
+ const normalizedType = this.normalizeTagPart(options.type);
3571
+ if (options.slug) {
3572
+ tags.add(`content:slug:${siteName}:${options.slug}`);
3573
+ }
3574
+ if (options.id) {
3575
+ tags.add(`content:id:${options.id}`);
3576
+ }
3577
+ if (normalizedPrefix) {
3578
+ tags.add(`content:prefix:${normalizedPrefix}`);
3579
+ }
3580
+ if (normalizedType) {
3581
+ tags.add(`content:${normalizedType}`);
3582
+ }
3583
+ if (normalizedCategory) {
3584
+ tags.add("content:category");
3585
+ tags.add(`content:category:${siteName}:${normalizedCategory}`);
3586
+ }
3587
+ return Array.from(tags);
3588
+ }
3589
+ normalizeTagPart(value) {
3590
+ if (typeof value !== "string") {
3591
+ return void 0;
3592
+ }
3593
+ const normalized = value.trim().toLowerCase();
3594
+ return normalized === "" ? void 0 : normalized;
3595
+ }
3596
+ extractSlugPrefix(slug) {
3597
+ const slashIndex = slug.indexOf("/");
3598
+ if (slashIndex > 0) {
3599
+ return slug.slice(0, slashIndex);
3600
+ }
3601
+ return void 0;
3602
+ }
3603
+ isContentId(idOrSlug) {
3604
+ return /^cnt_/i.test(idOrSlug);
3605
+ }
3521
3606
  };
3522
3607
 
3523
3608
  // src/v2/client/products-client.ts
@@ -3614,18 +3699,38 @@ var OrdersV2Client = class extends BaseV2Client {
3614
3699
  async get(siteName, id, cachePolicy) {
3615
3700
  return this.getOne(this.sitePath(siteName, "orders", id), void 0, cachePolicy);
3616
3701
  }
3702
+ /**
3703
+ * Create a checkout session via Stripe. Returns the session ID and a
3704
+ * `checkout_url` that the client should redirect to (or open in a new tab).
3705
+ *
3706
+ * This replaces the v1 `checkout.createCheckoutSession()` + `getCsrfToken()`
3707
+ * dance — v2 is API-key-only and requires no CSRF token.
3708
+ */
3709
+ async create(siteName, data) {
3710
+ return this.post(
3711
+ this.sitePath(siteName, "orders"),
3712
+ data
3713
+ );
3714
+ }
3715
+ /** Update fulfillment status, tracking number, and/or notes on an order. */
3716
+ async updateFulfillment(siteName, id, data) {
3717
+ return this.patchOne(
3718
+ this.sitePath(siteName, "orders", `${id}/fulfillment`),
3719
+ data
3720
+ );
3721
+ }
3617
3722
  };
3618
3723
 
3619
3724
  // src/v2/client/site-users-client.ts
3620
3725
  var SiteUsersV2Client = class extends BaseV2Client {
3621
- // --- OTP Auth ---
3726
+ // --- OTP Auth (public, API-key-scoped) ---
3622
3727
  async requestOtp(siteName, data) {
3623
3728
  return this.post(this.sitePath(siteName, "users", "request-otp"), data);
3624
3729
  }
3625
3730
  async verifyOtp(siteName, data) {
3626
3731
  return this.post(this.sitePath(siteName, "users", "verify-otp"), data);
3627
3732
  }
3628
- // --- Admin ---
3733
+ // --- Admin (API key) ---
3629
3734
  async list(siteName, params) {
3630
3735
  return this.getList(this.sitePath(siteName, "users"), params);
3631
3736
  }
@@ -3638,6 +3743,48 @@ var SiteUsersV2Client = class extends BaseV2Client {
3638
3743
  async update(siteName, id, data) {
3639
3744
  return this.patchOne(this.sitePath(siteName, "users", id), data);
3640
3745
  }
3746
+ // --- Authenticated "me" endpoints (site-user JWT) ---
3747
+ /**
3748
+ * Load the currently-authenticated site user's canonical record plus their
3749
+ * profile KV map. Requires `client.setAuth(jwt)` to have been called with
3750
+ * the token returned from `verifyOtp`.
3751
+ */
3752
+ async getMe(siteName) {
3753
+ return this.getOne(
3754
+ this.sitePath(siteName, "users", "me")
3755
+ );
3756
+ }
3757
+ /** Update the authenticated user's own fields. */
3758
+ async updateMe(siteName, data) {
3759
+ return this.patchOne(
3760
+ this.sitePath(siteName, "users", "me"),
3761
+ data
3762
+ );
3763
+ }
3764
+ /** Fetch the profile KV map as a dedicated `site_user_profile` envelope. */
3765
+ async getProfile(siteName) {
3766
+ return this.getOne(
3767
+ this.sitePath(siteName, "users", "me/profile")
3768
+ );
3769
+ }
3770
+ /**
3771
+ * Set a single profile key. The value is persisted verbatim — callers wanting
3772
+ * structured data should JSON-stringify their value first.
3773
+ */
3774
+ async setProfileValue(siteName, key, value) {
3775
+ const encoded = encodeURIComponent(key);
3776
+ return this.putOne(
3777
+ this.sitePath(siteName, "users", `me/profile/${encoded}`),
3778
+ { value }
3779
+ );
3780
+ }
3781
+ /** Delete a single profile key. */
3782
+ async deleteProfileValue(siteName, key) {
3783
+ const encoded = encodeURIComponent(key);
3784
+ return this.deleteOne(
3785
+ this.sitePath(siteName, "users", `me/profile/${encoded}`)
3786
+ );
3787
+ }
3641
3788
  };
3642
3789
 
3643
3790
  // src/v2/client/newsletter-client.ts
@@ -3709,6 +3856,61 @@ var NewsletterV2Client = class extends BaseV2Client {
3709
3856
  cachePolicy
3710
3857
  );
3711
3858
  }
3859
+ // --- Admin writes: Lists CRUD ---
3860
+ async createList(siteName, data) {
3861
+ return this.post(
3862
+ this.sitePath(siteName, "newsletter", "lists"),
3863
+ data
3864
+ );
3865
+ }
3866
+ async updateList(siteName, id, data) {
3867
+ return this.patchOne(
3868
+ this.sitePath(siteName, "newsletter", `lists/${id}`),
3869
+ data
3870
+ );
3871
+ }
3872
+ async deleteList(siteName, id) {
3873
+ return this.deleteOne(
3874
+ this.sitePath(siteName, "newsletter", `lists/${id}`)
3875
+ );
3876
+ }
3877
+ // --- Admin writes: Subscription sync / membership / import ---
3878
+ /**
3879
+ * Upsert a subscription by email and (optionally) replace its list
3880
+ * memberships. Returns a `newsletter_sync_result` envelope with the
3881
+ * outcome (created / updated / resubscribed / already-unsubscribed).
3882
+ */
3883
+ async syncSubscription(siteName, data) {
3884
+ return this.post(
3885
+ this.sitePath(siteName, "newsletter", "subscriptions/sync"),
3886
+ data
3887
+ );
3888
+ }
3889
+ /**
3890
+ * Add/remove/replace the list memberships for an existing subscription.
3891
+ * Returns the refreshed subscription record.
3892
+ */
3893
+ async updateSubscriptionListMembership(siteName, subscriptionId, data) {
3894
+ return this.post(
3895
+ this.sitePath(
3896
+ siteName,
3897
+ "newsletter",
3898
+ `subscriptions/${subscriptionId}/list-membership`
3899
+ ),
3900
+ data
3901
+ );
3902
+ }
3903
+ /**
3904
+ * Bulk import subscriptions. Each row is upserted via the same sync
3905
+ * path; `refreshListCounts` is deferred until after all rows are
3906
+ * processed on the server.
3907
+ */
3908
+ async importSubscriptions(siteName, data) {
3909
+ return this.post(
3910
+ this.sitePath(siteName, "newsletter", "subscriptions/import"),
3911
+ data
3912
+ );
3913
+ }
3712
3914
  };
3713
3915
 
3714
3916
  // src/v2/client/contacts-client.ts
@@ -3776,6 +3978,102 @@ var WebhooksV2Client = class extends BaseV2Client {
3776
3978
  }
3777
3979
  };
3778
3980
 
3981
+ // src/v2/client/subscriptions-client.ts
3982
+ var SubscriptionsV2Client = class extends BaseV2Client {
3983
+ // --- Authenticated "me" endpoints (site-user JWT) ---
3984
+ /** List all subscriptions for the authenticated user. */
3985
+ async listMySubscriptions(siteName) {
3986
+ return this.getList(
3987
+ this.sitePath(siteName, "users", "me/subscriptions")
3988
+ );
3989
+ }
3990
+ /** Pause a subscription. */
3991
+ async pauseSubscription(siteName, subId, params) {
3992
+ return this.post(
3993
+ this.sitePath(siteName, "users", `me/subscriptions/${subId}/pause`),
3994
+ params ?? {}
3995
+ );
3996
+ }
3997
+ /** Resume a paused subscription. */
3998
+ async resumeSubscription(siteName, subId) {
3999
+ return this.post(
4000
+ this.sitePath(siteName, "users", `me/subscriptions/${subId}/resume`)
4001
+ );
4002
+ }
4003
+ /** Cancel a subscription. */
4004
+ async cancelSubscription(siteName, subId, params) {
4005
+ return this.post(
4006
+ this.sitePath(siteName, "users", `me/subscriptions/${subId}/cancel`),
4007
+ params ?? {}
4008
+ );
4009
+ }
4010
+ /** Change the plan (price) of a subscription. */
4011
+ async changeSubscriptionPlan(siteName, subId, params) {
4012
+ return this.post(
4013
+ this.sitePath(siteName, "users", `me/subscriptions/${subId}/change-plan`),
4014
+ params
4015
+ );
4016
+ }
4017
+ // --- Admin endpoints (API key) ---
4018
+ /** List subscriptions for a specific user (admin). */
4019
+ async listUserSubscriptions(siteName, userId) {
4020
+ return this.getList(
4021
+ this.sitePath(siteName, "users", `${userId}/subscriptions`)
4022
+ );
4023
+ }
4024
+ /** Pause a user's subscription (admin). */
4025
+ async pauseUserSubscription(siteName, userId, subId, params) {
4026
+ return this.post(
4027
+ this.sitePath(siteName, "users", `${userId}/subscriptions/${subId}/pause`),
4028
+ params ?? {}
4029
+ );
4030
+ }
4031
+ /** Resume a user's paused subscription (admin). */
4032
+ async resumeUserSubscription(siteName, userId, subId) {
4033
+ return this.post(
4034
+ this.sitePath(siteName, "users", `${userId}/subscriptions/${subId}/resume`)
4035
+ );
4036
+ }
4037
+ /** Cancel a user's subscription (admin). */
4038
+ async cancelUserSubscription(siteName, userId, subId, params) {
4039
+ return this.post(
4040
+ this.sitePath(siteName, "users", `${userId}/subscriptions/${subId}/cancel`),
4041
+ params ?? {}
4042
+ );
4043
+ }
4044
+ };
4045
+
4046
+ // src/v2/client/credits-client.ts
4047
+ var CreditsV2Client = class extends BaseV2Client {
4048
+ // --- Authenticated "me" endpoints (site-user JWT) ---
4049
+ /** Get the current credit balance for the authenticated user. */
4050
+ async getMyBalance(siteName) {
4051
+ return this.getOne(
4052
+ this.sitePath(siteName, "users", "me/credits/balance")
4053
+ );
4054
+ }
4055
+ /** Get credit balance and transaction history for the authenticated user. */
4056
+ async getMyCredits(siteName) {
4057
+ return this.getOne(
4058
+ this.sitePath(siteName, "users", "me/credits")
4059
+ );
4060
+ }
4061
+ // --- Admin endpoints (API key) ---
4062
+ /** Get the credit balance for a specific user (admin). */
4063
+ async getUserBalance(siteName, userId) {
4064
+ return this.getOne(
4065
+ this.sitePath(siteName, "users", `${userId}/credits/balance`)
4066
+ );
4067
+ }
4068
+ /** Grant credit to a specific user (admin). */
4069
+ async grantCredit(siteName, userId, data) {
4070
+ return this.post(
4071
+ this.sitePath(siteName, "users", `${userId}/credits/grant`),
4072
+ data
4073
+ );
4074
+ }
4075
+ };
4076
+
3779
4077
  // src/v2/index.ts
3780
4078
  var PerspectApiV2Client = class {
3781
4079
  http;
@@ -3792,6 +4090,8 @@ var PerspectApiV2Client = class {
3792
4090
  sites;
3793
4091
  apiKeys;
3794
4092
  webhooks;
4093
+ subscriptions;
4094
+ credits;
3795
4095
  constructor(config) {
3796
4096
  const baseUrl = config.baseUrl.replace(/\/+$/, "");
3797
4097
  const v2BaseUrl = baseUrl.endsWith("/api/v2") ? baseUrl : `${baseUrl}/api/v2`;
@@ -3811,6 +4111,8 @@ var PerspectApiV2Client = class {
3811
4111
  this.sites = new SitesV2Client(this.http, basePath, cache);
3812
4112
  this.apiKeys = new ApiKeysV2Client(this.http, basePath, cache);
3813
4113
  this.webhooks = new WebhooksV2Client(this.http, basePath, cache);
4114
+ this.subscriptions = new SubscriptionsV2Client(this.http, basePath, cache);
4115
+ this.credits = new CreditsV2Client(this.http, basePath, cache);
3814
4116
  }
3815
4117
  /** Update the JWT token for authenticated requests. */
3816
4118
  setAuth(jwt) {