@swell/apps-sdk 1.0.161 → 1.0.162

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.cjs CHANGED
@@ -42,6 +42,7 @@ __export(index_exports, {
42
42
  CartResource: () => CartResource,
43
43
  CategoriesResource: () => CategoriesResource,
44
44
  CategoryResource: () => CategoryResource,
45
+ DEFAULT_CACHE_RULES: () => DEFAULT_CACHE_RULES,
45
46
  DEFAULT_QUERY_PAGE_LIMIT: () => DEFAULT_QUERY_PAGE_LIMIT,
46
47
  DeferredShopifyResource: () => DeferredShopifyResource,
47
48
  FILE_DATA_INCLUDE_QUERY: () => FILE_DATA_INCLUDE_QUERY,
@@ -20819,12 +20820,7 @@ var SwellTheme3 = class {
20819
20820
  // Default value (always StorefrontResource)
20820
20821
  () => this.fetchCart()
20821
20822
  ),
20822
- this.fetchSingletonResourceCached(
20823
- "account",
20824
- () => this.fetchAccount(),
20825
- () => null,
20826
- false
20827
- )
20823
+ this.fetchAccount()
20828
20824
  ]);
20829
20825
  if (!cart) {
20830
20826
  throw new Error("Failed to fetch cart");
@@ -22462,42 +22458,29 @@ function getResourceQuery(slug, query) {
22462
22458
 
22463
22459
  // src/cache/html-cache/html-cache.ts
22464
22460
  var CACHE_KEY_ORIGIN = "https://cache.swell.store";
22465
- var TTL_CONFIG = {
22466
- LIVE: {
22467
- DEFAULT: 20,
22468
- HOME: 20,
22469
- PRODUCT: 20,
22470
- COLLECTION: 20,
22471
- PAGE: 20,
22472
- BLOG: 20,
22473
- SWR: 60 * 60 * 24 * 7
22474
- // 1 week
22475
- },
22476
- PREVIEW: {
22477
- DEFAULT: 10,
22478
- HOME: 10,
22479
- PRODUCT: 10,
22480
- COLLECTION: 10,
22481
- PAGE: 10,
22482
- BLOG: 10,
22483
- SWR: 60 * 60 * 24 * 7
22484
- // 1 week
22485
- }
22461
+ var DEFAULT_CACHE_RULES = {
22462
+ defaults: {
22463
+ live: { ttl: 20, swr: 60 * 60 * 24 * 7 },
22464
+ // 20s TTL, 1 week SWR
22465
+ preview: { ttl: 10, swr: 60 * 60 * 24 * 7 }
22466
+ // 10s TTL, 1 week SWR
22467
+ },
22468
+ pathRules: [
22469
+ { path: "/checkout/*", skip: true }
22470
+ ]
22486
22471
  };
22487
22472
  var HtmlCache = class {
22488
22473
  epoch;
22489
22474
  backend;
22490
- constructor(epoch, backend) {
22475
+ cacheRules;
22476
+ constructor(epoch, backend, cacheRules = DEFAULT_CACHE_RULES) {
22491
22477
  this.epoch = epoch;
22492
22478
  this.backend = backend;
22479
+ this.cacheRules = cacheRules;
22493
22480
  }
22494
22481
  async get(request) {
22495
22482
  const trace = createTraceId();
22496
- if (request.method !== "GET") {
22497
- logger.debug("[SDK Html-cache] non-cacheable method", { trace });
22498
- return { found: false, cacheable: false };
22499
- }
22500
- if (!this.isCacheable(request)) {
22483
+ if (!this.canReadFromCache(request)) {
22501
22484
  logger.debug("[SDK Html-cache] non-cacheable request", { trace });
22502
22485
  return { found: false, cacheable: false };
22503
22486
  }
@@ -22565,31 +22548,17 @@ var HtmlCache = class {
22565
22548
  }
22566
22549
  async put(request, response) {
22567
22550
  const trace = createTraceId();
22568
- if (request.method !== "GET" || !response.ok) {
22569
- logger.debug("[SDK Html-cache] put skipped, invalid method or response", {
22570
- trace
22571
- });
22572
- return;
22573
- }
22574
- if (!this.isCacheable(request) || !this.isResponseCacheable(response)) {
22551
+ if (!this.canWriteToCache(request, response)) {
22575
22552
  logger.debug("[SDK Html-cache] put skipped, non-cacheable", { trace });
22576
22553
  return;
22577
22554
  }
22578
22555
  try {
22579
- let lowercaseHeaders2 = function(headers2) {
22580
- const out = {};
22581
- headers2.forEach((value, key) => {
22582
- out[key.toLowerCase()] = value;
22583
- });
22584
- return out;
22585
- };
22586
- var lowercaseHeaders = lowercaseHeaders2;
22587
22556
  const cacheKey = this.buildCacheKey(request);
22588
22557
  const ttl = this.getTTLForRequest(request);
22589
22558
  const swr = this.getSWRForRequest(request);
22590
22559
  const body = await response.text();
22591
22560
  const cacheTimeISO = (/* @__PURE__ */ new Date()).toISOString();
22592
- const headers = lowercaseHeaders2(response.headers);
22561
+ const headers = this.normalizeHeaders(response.headers);
22593
22562
  const entry = {
22594
22563
  status: response.status,
22595
22564
  statusText: response.statusText,
@@ -22623,14 +22592,13 @@ var HtmlCache = class {
22623
22592
  });
22624
22593
  }
22625
22594
  }
22626
- isReadCacheCandidate(request) {
22627
- const m = request.method.toUpperCase();
22628
- return (m === "GET" || m === "HEAD") && this.isCacheable(request);
22595
+ canReadFromCache(request) {
22596
+ const method = request.method.toUpperCase();
22597
+ return (method === "GET" || method === "HEAD") && this.isRequestCacheable(request);
22629
22598
  }
22630
- isWriteCacheCandidate(request, response) {
22631
- if (request.method.toUpperCase() !== "GET") return false;
22632
- if (!this.isCacheable(request)) return false;
22633
- return this.isResponseCacheable(response);
22599
+ canWriteToCache(request, response) {
22600
+ const method = request.method.toUpperCase();
22601
+ return method === "GET" && response.ok && this.isRequestCacheable(request) && this.isResponseCacheable(response);
22634
22602
  }
22635
22603
  createRevalidationRequest(request) {
22636
22604
  const headers = new Headers(request.headers);
@@ -22741,6 +22709,7 @@ var HtmlCache = class {
22741
22709
  const accept = headers.get("accept") || "";
22742
22710
  const versionFactors = {
22743
22711
  store: headers.get("swell-storefront-id") || "",
22712
+ app: (headers.get("swell-app-id") || "") + "@" + (swellData["swell-app-version"] || ""),
22744
22713
  auth: headers.get("swell-access-token") || "",
22745
22714
  theme: headers.get("swell-theme-version-hash") || "",
22746
22715
  modified: headers.get("swell-cache-modified") || "",
@@ -22763,11 +22732,16 @@ var HtmlCache = class {
22763
22732
  return {};
22764
22733
  }
22765
22734
  }
22766
- isCacheable(request) {
22735
+ isRequestCacheable(request) {
22767
22736
  const url = new URL(request.url);
22768
22737
  if (request.headers.get("swell-deployment-mode") === "editor") return false;
22769
- const skipPaths = ["/checkout"];
22770
- if (skipPaths.some((path) => url.pathname.startsWith(path))) return false;
22738
+ if (this.cacheRules.pathRules) {
22739
+ for (const rule of this.cacheRules.pathRules) {
22740
+ if (this.pathMatches(rule.path, url.pathname) && rule.skip) {
22741
+ return false;
22742
+ }
22743
+ }
22744
+ }
22771
22745
  if (request.headers.get("cache-control")?.includes("no-cache"))
22772
22746
  return false;
22773
22747
  return true;
@@ -22783,24 +22757,33 @@ var HtmlCache = class {
22783
22757
  }
22784
22758
  getDeploymentMode(headers) {
22785
22759
  const mode = headers.get("swell-deployment-mode");
22786
- return mode === "preview" || mode === "editor" ? mode : "live";
22760
+ return mode === "preview" ? "preview" : "live";
22787
22761
  }
22788
22762
  getTTLForRequest(request) {
22789
22763
  const url = new URL(request.url);
22790
22764
  const mode = this.getDeploymentMode(request.headers);
22791
- if (mode === "editor") return 0;
22792
- const config = mode === "preview" ? TTL_CONFIG.PREVIEW : TTL_CONFIG.LIVE;
22793
- if (url.pathname === "/") return config.HOME;
22794
- if (url.pathname.startsWith("/products/")) return config.PRODUCT;
22795
- if (url.pathname.startsWith("/categories/")) return config.COLLECTION;
22796
- if (url.pathname.startsWith("/pages/")) return config.PAGE;
22797
- if (url.pathname.startsWith("/blogs/")) return config.BLOG;
22798
- return config.DEFAULT;
22765
+ if (this.cacheRules.pathRules) {
22766
+ for (const rule of this.cacheRules.pathRules) {
22767
+ if (this.pathMatches(rule.path, url.pathname) && rule.ttl !== void 0) {
22768
+ return rule.ttl;
22769
+ }
22770
+ }
22771
+ }
22772
+ const defaults = this.cacheRules.defaults?.[mode];
22773
+ return defaults?.ttl ?? DEFAULT_CACHE_RULES.defaults[mode].ttl;
22799
22774
  }
22800
22775
  getSWRForRequest(request) {
22776
+ const url = new URL(request.url);
22801
22777
  const mode = this.getDeploymentMode(request.headers);
22802
- if (mode === "editor") return 0;
22803
- return mode === "preview" ? TTL_CONFIG.PREVIEW.SWR : TTL_CONFIG.LIVE.SWR;
22778
+ if (this.cacheRules.pathRules) {
22779
+ for (const rule of this.cacheRules.pathRules) {
22780
+ if (this.pathMatches(rule.path, url.pathname) && rule.swr !== void 0) {
22781
+ return rule.swr;
22782
+ }
22783
+ }
22784
+ }
22785
+ const defaults = this.cacheRules.defaults?.[mode];
22786
+ return defaults?.swr ?? DEFAULT_CACHE_RULES.defaults[mode].swr;
22804
22787
  }
22805
22788
  getEntryAge(entry) {
22806
22789
  const t = Date.parse(entry.cacheTimeISO);
@@ -22808,6 +22791,22 @@ var HtmlCache = class {
22808
22791
  const age = (Date.now() - t) / 1e3;
22809
22792
  return age < 0 ? 0 : age;
22810
22793
  }
22794
+ /**
22795
+ * Converts wildcard pattern to regex and tests against path.
22796
+ * - * matches any characters except /
22797
+ * - ** matches any characters including /
22798
+ */
22799
+ pathMatches(pattern, path) {
22800
+ const regex = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "___DOUBLE_STAR___").replace(/\*/g, "[^/]*").replace(/___DOUBLE_STAR___/g, ".*");
22801
+ return new RegExp(`^${regex}$`).test(path);
22802
+ }
22803
+ normalizeHeaders(headers) {
22804
+ const normalized = {};
22805
+ headers.forEach((value, key) => {
22806
+ normalized[key.toLowerCase()] = value;
22807
+ });
22808
+ return normalized;
22809
+ }
22811
22810
  normalizeSearchParams(searchParams) {
22812
22811
  const ignoredParams = [
22813
22812
  "utm_source",
@@ -22988,16 +22987,17 @@ var WorkerCacheBackend = class {
22988
22987
 
22989
22988
  // src/cache/html-cache/html-cache-factory.ts
22990
22989
  var _instance = null;
22991
- function getHtmlCache(env) {
22990
+ function getHtmlCache(env, cacheRules) {
22992
22991
  const epoch = env?.HTML_CACHE_EPOCH;
22993
22992
  if (typeof epoch !== "string" || !epoch) return null;
22994
22993
  if (_instance) return _instance;
22995
22994
  const kv = env?.NAMESPACE;
22995
+ const rules = cacheRules || env?.HTML_CACHE_RULES;
22996
22996
  if (env?.HTML_CACHE_BACKEND !== "worker" && kv) {
22997
- _instance = new HtmlCache(epoch, new KVCacheBackend(kv));
22997
+ _instance = new HtmlCache(epoch, new KVCacheBackend(kv), rules);
22998
22998
  return _instance;
22999
22999
  }
23000
- _instance = new HtmlCache(epoch, new WorkerCacheBackend(epoch));
23000
+ _instance = new HtmlCache(epoch, new WorkerCacheBackend(epoch), rules);
23001
23001
  return _instance;
23002
23002
  }
23003
23003
  // Annotate the CommonJS export names for ESM import in node:
@@ -23014,6 +23014,7 @@ function getHtmlCache(env) {
23014
23014
  CartResource,
23015
23015
  CategoriesResource,
23016
23016
  CategoryResource,
23017
+ DEFAULT_CACHE_RULES,
23017
23018
  DEFAULT_QUERY_PAGE_LIMIT,
23018
23019
  DeferredShopifyResource,
23019
23020
  FILE_DATA_INCLUDE_QUERY,