perspectapi-ts-sdk 3.5.1 → 3.7.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
@@ -1553,7 +1553,36 @@ var ProductsClient = class extends BaseClient {
1553
1553
  `/products/${productId}/skus`,
1554
1554
  { includeSitesSegment: false }
1555
1555
  );
1556
- return this.create(endpoint, data);
1556
+ const unitAmountCandidate = typeof data.unit_amount === "number" ? data.unit_amount : typeof data.price === "number" ? Math.round(data.price * 100) : void 0;
1557
+ if (typeof unitAmountCandidate !== "number" || !Number.isFinite(unitAmountCandidate)) {
1558
+ throw new Error("createProductSku requires unit_amount or price");
1559
+ }
1560
+ const unitAmount = unitAmountCandidate;
1561
+ const quantityAvailable = data.quantity_available !== void 0 ? data.quantity_available : data.stock_quantity ?? null;
1562
+ const payload = {
1563
+ sku: data.sku ?? null,
1564
+ unit_amount: unitAmount,
1565
+ currency: data.currency || "usd",
1566
+ quantity_available: quantityAvailable,
1567
+ published: data.published,
1568
+ gateway_price_id_test: data.gateway_price_id_test,
1569
+ gateway_price_id_live: data.gateway_price_id_live,
1570
+ value_ids: data.value_ids
1571
+ };
1572
+ if (Object.prototype.hasOwnProperty.call(data, "media_id")) {
1573
+ if (data.media_id === null) {
1574
+ payload.media_id = null;
1575
+ } else if (typeof data.media_id === "string") {
1576
+ const trimmed = data.media_id.trim();
1577
+ if (!trimmed) {
1578
+ throw new Error("createProductSku media_id cannot be empty");
1579
+ }
1580
+ payload.media_id = trimmed;
1581
+ } else if (data.media_id !== void 0) {
1582
+ throw new Error("createProductSku media_id must be a string or null");
1583
+ }
1584
+ }
1585
+ return this.create(endpoint, payload);
1557
1586
  }
1558
1587
  };
1559
1588
 
@@ -2066,11 +2095,123 @@ var NewsletterClient = class extends BaseClient {
2066
2095
  /**
2067
2096
  * Get available newsletter lists
2068
2097
  */
2069
- async getLists(siteName) {
2070
- return this.getSingle(
2071
- this.newsletterEndpoint(siteName, "/newsletter/lists")
2098
+ async getLists(siteName, cachePolicy) {
2099
+ const endpoint = this.newsletterEndpoint(siteName, "/newsletter/lists");
2100
+ const path = this.buildPath(endpoint);
2101
+ return this.fetchWithCache(
2102
+ endpoint,
2103
+ void 0,
2104
+ this.buildNewsletterTags(siteName, [
2105
+ "newsletter:lists",
2106
+ `newsletter:lists:site:${siteName}`
2107
+ ]),
2108
+ cachePolicy,
2109
+ () => this.http.get(path)
2110
+ );
2111
+ }
2112
+ /**
2113
+ * List publicly available (sent) newsletter campaigns
2114
+ */
2115
+ async getPublishedCampaigns(siteName, params, cachePolicy) {
2116
+ const endpoint = this.newsletterEndpoint(siteName, "/newsletter/campaigns");
2117
+ const path = this.buildPath(endpoint);
2118
+ const normalizedParams = params ? { ...params } : void 0;
2119
+ if (normalizedParams) {
2120
+ const validatedLimit = validateOptionalLimit(
2121
+ normalizedParams.limit,
2122
+ "newsletter campaigns query"
2123
+ );
2124
+ if (validatedLimit !== void 0) {
2125
+ normalizedParams.limit = validatedLimit;
2126
+ } else {
2127
+ delete normalizedParams.limit;
2128
+ }
2129
+ if (typeof normalizedParams.search === "string" && normalizedParams.search.trim().length === 0) {
2130
+ delete normalizedParams.search;
2131
+ }
2132
+ }
2133
+ return this.fetchWithCache(
2134
+ endpoint,
2135
+ normalizedParams,
2136
+ this.buildNewsletterTags(siteName, [
2137
+ "newsletter:campaigns",
2138
+ `newsletter:campaigns:list:${siteName}`
2139
+ ]),
2140
+ cachePolicy,
2141
+ () => this.http.get(path, normalizedParams)
2142
+ );
2143
+ }
2144
+ /**
2145
+ * Fetch a publicly available (sent) newsletter campaign by slug
2146
+ */
2147
+ async getPublishedCampaignBySlug(siteName, slug, optionsOrPolicy, cachePolicy) {
2148
+ let normalizedSlug = slug.trim();
2149
+ if (!normalizedSlug) {
2150
+ throw new Error("slug is required");
2151
+ }
2152
+ const isCachePolicyArg = this.isCachePolicy(optionsOrPolicy);
2153
+ const providedSlugPrefix = !isCachePolicyArg && optionsOrPolicy ? this.pickString(optionsOrPolicy, ["slugPrefix", "slug_prefix"]) : void 0;
2154
+ const resolvedCachePolicy = isCachePolicyArg ? optionsOrPolicy : cachePolicy;
2155
+ let slugPrefix = providedSlugPrefix;
2156
+ if (!slugPrefix) {
2157
+ const parts = normalizedSlug.split("/").filter(Boolean);
2158
+ if (parts.length > 1) {
2159
+ slugPrefix = parts.slice(0, -1).join("/");
2160
+ normalizedSlug = parts[parts.length - 1];
2161
+ }
2162
+ }
2163
+ normalizedSlug = normalizedSlug.trim();
2164
+ if (!normalizedSlug) {
2165
+ throw new Error("slug is required");
2166
+ }
2167
+ const endpoint = this.newsletterEndpoint(
2168
+ siteName,
2169
+ `/newsletter/campaigns/${encodeURIComponent(normalizedSlug)}`
2170
+ );
2171
+ const path = this.buildPath(endpoint);
2172
+ const queryParams = slugPrefix ? { slug_prefix: slugPrefix } : void 0;
2173
+ return this.fetchWithCache(
2174
+ endpoint,
2175
+ queryParams,
2176
+ this.buildNewsletterTags(
2177
+ siteName,
2178
+ [
2179
+ "newsletter:campaigns",
2180
+ `newsletter:campaigns:slug:${siteName}:${normalizedSlug}`,
2181
+ `newsletter:campaigns:detail:${siteName}`
2182
+ ],
2183
+ slugPrefix
2184
+ ),
2185
+ resolvedCachePolicy,
2186
+ () => this.http.get(path, queryParams)
2072
2187
  );
2073
2188
  }
2189
+ /**
2190
+ * Invalidate cached published newsletter campaign data from a webhook payload.
2191
+ * Only publish events (and legacy sent aliases) trigger invalidation.
2192
+ */
2193
+ async invalidatePublishedCampaignCacheFromWebhook(payload, fallbackSiteName) {
2194
+ const normalized = this.normalizeNewsletterWebhookPayload(payload, fallbackSiteName);
2195
+ if (!normalized.shouldInvalidate) {
2196
+ return {
2197
+ invalidated: false,
2198
+ tags: [],
2199
+ reason: normalized.reason || "event_not_publish_related"
2200
+ };
2201
+ }
2202
+ const tags = this.buildNewsletterTags(
2203
+ normalized.siteName,
2204
+ [
2205
+ "newsletter:campaigns",
2206
+ `newsletter:campaigns:list:${normalized.siteName}`,
2207
+ normalized.slug ? `newsletter:campaigns:slug:${normalized.siteName}:${normalized.slug}` : "",
2208
+ normalized.campaignId ? `newsletter:campaigns:id:${normalized.siteName}:${normalized.campaignId}` : ""
2209
+ ],
2210
+ normalized.slugPrefix
2211
+ );
2212
+ await this.invalidateCache({ tags });
2213
+ return { invalidated: true, tags };
2214
+ }
2074
2215
  /**
2075
2216
  * Check subscription status by email
2076
2217
  */
@@ -2266,6 +2407,107 @@ var NewsletterClient = class extends BaseClient {
2266
2407
  59
2267
2408
  ]);
2268
2409
  }
2410
+ buildNewsletterTags(siteName, extraTags = [], slugPrefix) {
2411
+ const tags = /* @__PURE__ */ new Set(["newsletter"]);
2412
+ if (siteName) {
2413
+ tags.add(`newsletter:site:${siteName}`);
2414
+ }
2415
+ if (slugPrefix) {
2416
+ tags.add(`newsletter:prefix:${slugPrefix}`);
2417
+ }
2418
+ extraTags.filter(Boolean).forEach((tag) => tags.add(tag));
2419
+ return Array.from(tags.values());
2420
+ }
2421
+ extractSlugPrefix(slug) {
2422
+ const normalized = slug.trim();
2423
+ if (!normalized.includes("/")) {
2424
+ return void 0;
2425
+ }
2426
+ const [prefix] = normalized.split("/").filter(Boolean);
2427
+ return prefix || void 0;
2428
+ }
2429
+ normalizeNewsletterWebhookPayload(payload, fallbackSiteName) {
2430
+ const eventType = (this.pickString(payload, ["event_type", "type"]) || "").toLowerCase();
2431
+ const dataRaw = payload.data;
2432
+ const data = dataRaw && typeof dataRaw === "object" && !Array.isArray(dataRaw) ? dataRaw : payload;
2433
+ const originType = (this.pickString(data, ["origin_type", "originType"]) || "").toLowerCase();
2434
+ const status = (this.pickString(data, ["status", "campaign_status", "campaignStatus"]) || "").toLowerCase();
2435
+ if (!this.isPublishEvent(eventType, status, originType)) {
2436
+ return {
2437
+ shouldInvalidate: false,
2438
+ reason: "not_publish_or_sent_event",
2439
+ siteName: fallbackSiteName || ""
2440
+ };
2441
+ }
2442
+ const siteName = this.pickString(payload, ["site", "site_name", "siteName"]) || this.pickString(data, ["site", "site_name", "siteName"]) || fallbackSiteName || "";
2443
+ if (!siteName) {
2444
+ return {
2445
+ shouldInvalidate: false,
2446
+ reason: "missing_site_name",
2447
+ siteName: ""
2448
+ };
2449
+ }
2450
+ let slug = this.pickString(data, ["slug", "canonical_slug", "canonicalSlug"]) || this.pickString(payload, ["slug", "canonical_slug", "canonicalSlug"]) || void 0;
2451
+ let slugPrefix = this.pickString(data, ["slug_prefix", "slugPrefix"]) || this.pickString(payload, ["slug_prefix", "slugPrefix"]) || (slug ? this.extractSlugPrefix(slug) : void 0);
2452
+ if (slug) {
2453
+ const slugParts = slug.split("/").filter(Boolean);
2454
+ if (slugParts.length > 1) {
2455
+ if (!slugPrefix) {
2456
+ slugPrefix = slugParts.slice(0, -1).join("/");
2457
+ }
2458
+ slug = slugParts[slugParts.length - 1];
2459
+ }
2460
+ }
2461
+ const campaignId = this.pickString(data, ["campaign_id", "campaignId"]) || this.pickString(payload, ["campaign_id", "campaignId"]) || void 0;
2462
+ return {
2463
+ shouldInvalidate: true,
2464
+ siteName,
2465
+ slug,
2466
+ slugPrefix,
2467
+ campaignId
2468
+ };
2469
+ }
2470
+ isPublishEvent(eventType, status, originType) {
2471
+ const knownPublishEvents = /* @__PURE__ */ new Set([
2472
+ "newsletter.published",
2473
+ "newsletter.sent",
2474
+ "newsletter_campaign.published",
2475
+ "newsletter_campaign.sent",
2476
+ "newsletter.campaign.published",
2477
+ "newsletter.campaign.sent",
2478
+ "campaign.published",
2479
+ "campaign.sent"
2480
+ ]);
2481
+ if (knownPublishEvents.has(eventType)) {
2482
+ return true;
2483
+ }
2484
+ if (eventType === "content.published" && originType === "newsletter_campaign") {
2485
+ return true;
2486
+ }
2487
+ if ((eventType.includes("newsletter") || eventType.includes("campaign")) && eventType.endsWith(".updated") && (status === "published" || status === "sent")) {
2488
+ return true;
2489
+ }
2490
+ return false;
2491
+ }
2492
+ pickString(source, keys) {
2493
+ if (!source) {
2494
+ return void 0;
2495
+ }
2496
+ for (const key of keys) {
2497
+ const value = source[key];
2498
+ if (typeof value === "string" && value.trim().length > 0) {
2499
+ return value.trim();
2500
+ }
2501
+ }
2502
+ return void 0;
2503
+ }
2504
+ isCachePolicy(value) {
2505
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
2506
+ return false;
2507
+ }
2508
+ const record = value;
2509
+ return "ttlSeconds" in record || "tags" in record || "metadata" in record || "skipCache" in record;
2510
+ }
2269
2511
  };
2270
2512
 
2271
2513
  // src/client/site-users-client.ts
package/dist/index.mjs CHANGED
@@ -1490,7 +1490,36 @@ var ProductsClient = class extends BaseClient {
1490
1490
  `/products/${productId}/skus`,
1491
1491
  { includeSitesSegment: false }
1492
1492
  );
1493
- return this.create(endpoint, data);
1493
+ const unitAmountCandidate = typeof data.unit_amount === "number" ? data.unit_amount : typeof data.price === "number" ? Math.round(data.price * 100) : void 0;
1494
+ if (typeof unitAmountCandidate !== "number" || !Number.isFinite(unitAmountCandidate)) {
1495
+ throw new Error("createProductSku requires unit_amount or price");
1496
+ }
1497
+ const unitAmount = unitAmountCandidate;
1498
+ const quantityAvailable = data.quantity_available !== void 0 ? data.quantity_available : data.stock_quantity ?? null;
1499
+ const payload = {
1500
+ sku: data.sku ?? null,
1501
+ unit_amount: unitAmount,
1502
+ currency: data.currency || "usd",
1503
+ quantity_available: quantityAvailable,
1504
+ published: data.published,
1505
+ gateway_price_id_test: data.gateway_price_id_test,
1506
+ gateway_price_id_live: data.gateway_price_id_live,
1507
+ value_ids: data.value_ids
1508
+ };
1509
+ if (Object.prototype.hasOwnProperty.call(data, "media_id")) {
1510
+ if (data.media_id === null) {
1511
+ payload.media_id = null;
1512
+ } else if (typeof data.media_id === "string") {
1513
+ const trimmed = data.media_id.trim();
1514
+ if (!trimmed) {
1515
+ throw new Error("createProductSku media_id cannot be empty");
1516
+ }
1517
+ payload.media_id = trimmed;
1518
+ } else if (data.media_id !== void 0) {
1519
+ throw new Error("createProductSku media_id must be a string or null");
1520
+ }
1521
+ }
1522
+ return this.create(endpoint, payload);
1494
1523
  }
1495
1524
  };
1496
1525
 
@@ -2003,11 +2032,123 @@ var NewsletterClient = class extends BaseClient {
2003
2032
  /**
2004
2033
  * Get available newsletter lists
2005
2034
  */
2006
- async getLists(siteName) {
2007
- return this.getSingle(
2008
- this.newsletterEndpoint(siteName, "/newsletter/lists")
2035
+ async getLists(siteName, cachePolicy) {
2036
+ const endpoint = this.newsletterEndpoint(siteName, "/newsletter/lists");
2037
+ const path = this.buildPath(endpoint);
2038
+ return this.fetchWithCache(
2039
+ endpoint,
2040
+ void 0,
2041
+ this.buildNewsletterTags(siteName, [
2042
+ "newsletter:lists",
2043
+ `newsletter:lists:site:${siteName}`
2044
+ ]),
2045
+ cachePolicy,
2046
+ () => this.http.get(path)
2047
+ );
2048
+ }
2049
+ /**
2050
+ * List publicly available (sent) newsletter campaigns
2051
+ */
2052
+ async getPublishedCampaigns(siteName, params, cachePolicy) {
2053
+ const endpoint = this.newsletterEndpoint(siteName, "/newsletter/campaigns");
2054
+ const path = this.buildPath(endpoint);
2055
+ const normalizedParams = params ? { ...params } : void 0;
2056
+ if (normalizedParams) {
2057
+ const validatedLimit = validateOptionalLimit(
2058
+ normalizedParams.limit,
2059
+ "newsletter campaigns query"
2060
+ );
2061
+ if (validatedLimit !== void 0) {
2062
+ normalizedParams.limit = validatedLimit;
2063
+ } else {
2064
+ delete normalizedParams.limit;
2065
+ }
2066
+ if (typeof normalizedParams.search === "string" && normalizedParams.search.trim().length === 0) {
2067
+ delete normalizedParams.search;
2068
+ }
2069
+ }
2070
+ return this.fetchWithCache(
2071
+ endpoint,
2072
+ normalizedParams,
2073
+ this.buildNewsletterTags(siteName, [
2074
+ "newsletter:campaigns",
2075
+ `newsletter:campaigns:list:${siteName}`
2076
+ ]),
2077
+ cachePolicy,
2078
+ () => this.http.get(path, normalizedParams)
2079
+ );
2080
+ }
2081
+ /**
2082
+ * Fetch a publicly available (sent) newsletter campaign by slug
2083
+ */
2084
+ async getPublishedCampaignBySlug(siteName, slug, optionsOrPolicy, cachePolicy) {
2085
+ let normalizedSlug = slug.trim();
2086
+ if (!normalizedSlug) {
2087
+ throw new Error("slug is required");
2088
+ }
2089
+ const isCachePolicyArg = this.isCachePolicy(optionsOrPolicy);
2090
+ const providedSlugPrefix = !isCachePolicyArg && optionsOrPolicy ? this.pickString(optionsOrPolicy, ["slugPrefix", "slug_prefix"]) : void 0;
2091
+ const resolvedCachePolicy = isCachePolicyArg ? optionsOrPolicy : cachePolicy;
2092
+ let slugPrefix = providedSlugPrefix;
2093
+ if (!slugPrefix) {
2094
+ const parts = normalizedSlug.split("/").filter(Boolean);
2095
+ if (parts.length > 1) {
2096
+ slugPrefix = parts.slice(0, -1).join("/");
2097
+ normalizedSlug = parts[parts.length - 1];
2098
+ }
2099
+ }
2100
+ normalizedSlug = normalizedSlug.trim();
2101
+ if (!normalizedSlug) {
2102
+ throw new Error("slug is required");
2103
+ }
2104
+ const endpoint = this.newsletterEndpoint(
2105
+ siteName,
2106
+ `/newsletter/campaigns/${encodeURIComponent(normalizedSlug)}`
2107
+ );
2108
+ const path = this.buildPath(endpoint);
2109
+ const queryParams = slugPrefix ? { slug_prefix: slugPrefix } : void 0;
2110
+ return this.fetchWithCache(
2111
+ endpoint,
2112
+ queryParams,
2113
+ this.buildNewsletterTags(
2114
+ siteName,
2115
+ [
2116
+ "newsletter:campaigns",
2117
+ `newsletter:campaigns:slug:${siteName}:${normalizedSlug}`,
2118
+ `newsletter:campaigns:detail:${siteName}`
2119
+ ],
2120
+ slugPrefix
2121
+ ),
2122
+ resolvedCachePolicy,
2123
+ () => this.http.get(path, queryParams)
2009
2124
  );
2010
2125
  }
2126
+ /**
2127
+ * Invalidate cached published newsletter campaign data from a webhook payload.
2128
+ * Only publish events (and legacy sent aliases) trigger invalidation.
2129
+ */
2130
+ async invalidatePublishedCampaignCacheFromWebhook(payload, fallbackSiteName) {
2131
+ const normalized = this.normalizeNewsletterWebhookPayload(payload, fallbackSiteName);
2132
+ if (!normalized.shouldInvalidate) {
2133
+ return {
2134
+ invalidated: false,
2135
+ tags: [],
2136
+ reason: normalized.reason || "event_not_publish_related"
2137
+ };
2138
+ }
2139
+ const tags = this.buildNewsletterTags(
2140
+ normalized.siteName,
2141
+ [
2142
+ "newsletter:campaigns",
2143
+ `newsletter:campaigns:list:${normalized.siteName}`,
2144
+ normalized.slug ? `newsletter:campaigns:slug:${normalized.siteName}:${normalized.slug}` : "",
2145
+ normalized.campaignId ? `newsletter:campaigns:id:${normalized.siteName}:${normalized.campaignId}` : ""
2146
+ ],
2147
+ normalized.slugPrefix
2148
+ );
2149
+ await this.invalidateCache({ tags });
2150
+ return { invalidated: true, tags };
2151
+ }
2011
2152
  /**
2012
2153
  * Check subscription status by email
2013
2154
  */
@@ -2203,6 +2344,107 @@ var NewsletterClient = class extends BaseClient {
2203
2344
  59
2204
2345
  ]);
2205
2346
  }
2347
+ buildNewsletterTags(siteName, extraTags = [], slugPrefix) {
2348
+ const tags = /* @__PURE__ */ new Set(["newsletter"]);
2349
+ if (siteName) {
2350
+ tags.add(`newsletter:site:${siteName}`);
2351
+ }
2352
+ if (slugPrefix) {
2353
+ tags.add(`newsletter:prefix:${slugPrefix}`);
2354
+ }
2355
+ extraTags.filter(Boolean).forEach((tag) => tags.add(tag));
2356
+ return Array.from(tags.values());
2357
+ }
2358
+ extractSlugPrefix(slug) {
2359
+ const normalized = slug.trim();
2360
+ if (!normalized.includes("/")) {
2361
+ return void 0;
2362
+ }
2363
+ const [prefix] = normalized.split("/").filter(Boolean);
2364
+ return prefix || void 0;
2365
+ }
2366
+ normalizeNewsletterWebhookPayload(payload, fallbackSiteName) {
2367
+ const eventType = (this.pickString(payload, ["event_type", "type"]) || "").toLowerCase();
2368
+ const dataRaw = payload.data;
2369
+ const data = dataRaw && typeof dataRaw === "object" && !Array.isArray(dataRaw) ? dataRaw : payload;
2370
+ const originType = (this.pickString(data, ["origin_type", "originType"]) || "").toLowerCase();
2371
+ const status = (this.pickString(data, ["status", "campaign_status", "campaignStatus"]) || "").toLowerCase();
2372
+ if (!this.isPublishEvent(eventType, status, originType)) {
2373
+ return {
2374
+ shouldInvalidate: false,
2375
+ reason: "not_publish_or_sent_event",
2376
+ siteName: fallbackSiteName || ""
2377
+ };
2378
+ }
2379
+ const siteName = this.pickString(payload, ["site", "site_name", "siteName"]) || this.pickString(data, ["site", "site_name", "siteName"]) || fallbackSiteName || "";
2380
+ if (!siteName) {
2381
+ return {
2382
+ shouldInvalidate: false,
2383
+ reason: "missing_site_name",
2384
+ siteName: ""
2385
+ };
2386
+ }
2387
+ let slug = this.pickString(data, ["slug", "canonical_slug", "canonicalSlug"]) || this.pickString(payload, ["slug", "canonical_slug", "canonicalSlug"]) || void 0;
2388
+ let slugPrefix = this.pickString(data, ["slug_prefix", "slugPrefix"]) || this.pickString(payload, ["slug_prefix", "slugPrefix"]) || (slug ? this.extractSlugPrefix(slug) : void 0);
2389
+ if (slug) {
2390
+ const slugParts = slug.split("/").filter(Boolean);
2391
+ if (slugParts.length > 1) {
2392
+ if (!slugPrefix) {
2393
+ slugPrefix = slugParts.slice(0, -1).join("/");
2394
+ }
2395
+ slug = slugParts[slugParts.length - 1];
2396
+ }
2397
+ }
2398
+ const campaignId = this.pickString(data, ["campaign_id", "campaignId"]) || this.pickString(payload, ["campaign_id", "campaignId"]) || void 0;
2399
+ return {
2400
+ shouldInvalidate: true,
2401
+ siteName,
2402
+ slug,
2403
+ slugPrefix,
2404
+ campaignId
2405
+ };
2406
+ }
2407
+ isPublishEvent(eventType, status, originType) {
2408
+ const knownPublishEvents = /* @__PURE__ */ new Set([
2409
+ "newsletter.published",
2410
+ "newsletter.sent",
2411
+ "newsletter_campaign.published",
2412
+ "newsletter_campaign.sent",
2413
+ "newsletter.campaign.published",
2414
+ "newsletter.campaign.sent",
2415
+ "campaign.published",
2416
+ "campaign.sent"
2417
+ ]);
2418
+ if (knownPublishEvents.has(eventType)) {
2419
+ return true;
2420
+ }
2421
+ if (eventType === "content.published" && originType === "newsletter_campaign") {
2422
+ return true;
2423
+ }
2424
+ if ((eventType.includes("newsletter") || eventType.includes("campaign")) && eventType.endsWith(".updated") && (status === "published" || status === "sent")) {
2425
+ return true;
2426
+ }
2427
+ return false;
2428
+ }
2429
+ pickString(source, keys) {
2430
+ if (!source) {
2431
+ return void 0;
2432
+ }
2433
+ for (const key of keys) {
2434
+ const value = source[key];
2435
+ if (typeof value === "string" && value.trim().length > 0) {
2436
+ return value.trim();
2437
+ }
2438
+ }
2439
+ return void 0;
2440
+ }
2441
+ isCachePolicy(value) {
2442
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
2443
+ return false;
2444
+ }
2445
+ const record = value;
2446
+ return "ttlSeconds" in record || "tags" in record || "metadata" in record || "skipCache" in record;
2447
+ }
2206
2448
  };
2207
2449
 
2208
2450
  // src/client/site-users-client.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "perspectapi-ts-sdk",
3
- "version": "3.5.1",
3
+ "version": "3.7.0",
4
4
  "description": "TypeScript SDK for PerspectAPI - Cloudflare Workers compatible",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",