@swell/apps-sdk 1.0.160 → 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,10 +42,12 @@ __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,
48
49
  GEO_DATA: () => GEO_DATA,
50
+ HtmlCache: () => HtmlCache,
49
51
  LANG_TO_COUNTRY_CODES: () => LANG_TO_COUNTRY_CODES,
50
52
  LiquidSwell: () => LiquidSwell30,
51
53
  MAX_QUERY_PAGE_LIMIT: () => MAX_QUERY_PAGE_LIMIT,
@@ -93,7 +95,6 @@ __export(index_exports, {
93
95
  ThemeForm: () => ThemeForm,
94
96
  ThemeFormErrors: () => ThemeFormErrors,
95
97
  VariantResource: () => VariantResource,
96
- WorkerHtmlCache: () => WorkerHtmlCache,
97
98
  adaptShopifyFontData: () => adaptShopifyFontData,
98
99
  adaptShopifyFormData: () => adaptShopifyFormData,
99
100
  adaptShopifyMenuData: () => adaptShopifyMenuData,
@@ -121,6 +122,7 @@ __export(index_exports, {
121
122
  getEasyblocksComponentDefinitions: () => getEasyblocksComponentDefinitions,
122
123
  getEasyblocksPagePropsWithConfigs: () => getEasyblocksPagePropsWithConfigs,
123
124
  getEasyblocksPageTemplate: () => getEasyblocksPageTemplate,
125
+ getHtmlCache: () => getHtmlCache,
124
126
  getKVFlavor: () => getKVFlavor,
125
127
  getLayoutSectionGroups: () => getLayoutSectionGroups,
126
128
  getMenuItemStorefrontUrl: () => getMenuItemStorefrontUrl,
@@ -7437,12 +7439,7 @@ var ThemeCache = class extends Cache {
7437
7439
  }
7438
7440
  };
7439
7441
 
7440
- // src/cache/theme-file-storage.ts
7441
- var import_bluebird2 = __toESM(require("bluebird"), 1);
7442
-
7443
7442
  // src/cache/kv-variety.ts
7444
- var import_bluebird = __toESM(require("bluebird"), 1);
7445
- var { Promise: Promise2 } = import_bluebird.default;
7446
7443
  var CFKV = class {
7447
7444
  constructor(kv) {
7448
7445
  this.kv = kv;
@@ -7474,13 +7471,11 @@ var MiniflareKV = class {
7474
7471
  return /* @__PURE__ */ new Map();
7475
7472
  }
7476
7473
  const result = /* @__PURE__ */ new Map();
7477
- await Promise2.map(
7478
- keys,
7479
- async (key) => {
7474
+ await Promise.all(
7475
+ keys.map(async (key) => {
7480
7476
  const value = await this.kv.get(key, "text");
7481
7477
  result.set(key, value);
7482
- },
7483
- { concurrency: 50 }
7478
+ })
7484
7479
  );
7485
7480
  return result;
7486
7481
  }
@@ -7512,16 +7507,13 @@ function createClientKV(env, flavor = "cf") {
7512
7507
  return new MemoryKV();
7513
7508
  }
7514
7509
 
7515
- // src/cache/theme-file-storage.ts
7516
- var { Promise: Promise3 } = import_bluebird2.default;
7517
- var ThemeFileStorage = class {
7510
+ // src/cache/theme-file-cache.ts
7511
+ var ThemeFileCache = class {
7518
7512
  kv;
7519
- maxConcurrency;
7520
7513
  maxBatchSize = 20 * 1024 * 1024;
7521
7514
  // 20MB safety margin
7522
7515
  constructor(env, flavor = "cf") {
7523
7516
  this.kv = createClientKV(env, flavor);
7524
- this.maxConcurrency = flavor === "miniflare" ? 50 : 6;
7525
7517
  }
7526
7518
  /**
7527
7519
  * Build a KV storage key from a file hash
@@ -7614,10 +7606,8 @@ var ThemeFileStorage = class {
7614
7606
  totalSize,
7615
7607
  trace
7616
7608
  });
7617
- const results = await Promise3.map(
7618
- batches,
7619
- (batch) => this.loadBatch(batch),
7620
- { concurrency: Math.min(this.maxConcurrency, batches.length) }
7609
+ const results = await Promise.all(
7610
+ batches.map((batch) => this.loadBatch(batch))
7621
7611
  );
7622
7612
  const mergedConfigs = this.mergeResults(configs, results);
7623
7613
  const loadedCount = mergedConfigs.filter((c) => c.file_data).length;
@@ -7682,10 +7672,8 @@ var ThemeFileStorage = class {
7682
7672
  }
7683
7673
  const existing = /* @__PURE__ */ new Set();
7684
7674
  const batches = this.planGetBatches(configs);
7685
- const results = await Promise3.map(
7686
- batches,
7687
- (batch) => this.kv.get(batch.keys),
7688
- { concurrency: this.maxConcurrency }
7675
+ const results = await Promise.all(
7676
+ batches.map((batch) => this.kv.get(batch.keys))
7689
7677
  );
7690
7678
  for (const batchResult of results) {
7691
7679
  for (const [key, value] of batchResult.entries()) {
@@ -7749,15 +7737,13 @@ var ThemeFileStorage = class {
7749
7737
  skippedExisting: existing.size,
7750
7738
  trace
7751
7739
  });
7752
- await Promise3.map(
7753
- toWrite,
7754
- async (config) => {
7740
+ await Promise.all(
7741
+ toWrite.map(async (config) => {
7755
7742
  const key = this.buildKey(config.hash);
7756
7743
  const metadata = config.file?.content_type ? { content_type: config.file.content_type } : void 0;
7757
- await this.kv.put(key, config.file_data, metadata);
7744
+ await this.kv.put(key, config.file_data, { metadata });
7758
7745
  result.written++;
7759
- },
7760
- { concurrency: this.maxConcurrency }
7746
+ })
7761
7747
  );
7762
7748
  }
7763
7749
  logger.info("[ThemeFileStorage] Put files complete", {
@@ -7771,378 +7757,6 @@ var ThemeFileStorage = class {
7771
7757
  }
7772
7758
  };
7773
7759
 
7774
- // src/cache/constants.ts
7775
- var SECOND = 1e3;
7776
- var MINUTE = 60 * SECOND;
7777
- var HOUR = 60 * MINUTE;
7778
- var DAY = 24 * HOUR;
7779
- var YEAR = 365 * DAY;
7780
- var SHORT_TTL = 5 * SECOND;
7781
-
7782
- // src/cache/worker-html-cache.ts
7783
- var CACHE_NAME = "swell-html-v0";
7784
- var CACHE_KEY_ORIGIN = "https://cache.swell.store";
7785
- var TTL_CONFIG = {
7786
- LIVE: {
7787
- DEFAULT: 20,
7788
- HOME: 20,
7789
- PRODUCT: 20,
7790
- COLLECTION: 20,
7791
- PAGE: 20,
7792
- BLOG: 20,
7793
- SWR: 180
7794
- },
7795
- PREVIEW: {
7796
- DEFAULT: 20,
7797
- HOME: 20,
7798
- PRODUCT: 20,
7799
- COLLECTION: 20,
7800
- PAGE: 20,
7801
- BLOG: 20,
7802
- SWR: 180
7803
- }
7804
- };
7805
- var WorkerHtmlCache = class {
7806
- epoch;
7807
- constructor(epoch) {
7808
- this.epoch = epoch;
7809
- }
7810
- async get(request) {
7811
- const trace = createTraceId();
7812
- if (request.method !== "GET") {
7813
- logger.debug("[SDK Html-cache] non-cacheable", { trace });
7814
- return { found: false, cacheable: false };
7815
- }
7816
- if (!this.isCacheable(request)) {
7817
- logger.debug("[SDK Html-cache] non-cacheable", { trace });
7818
- return { found: false, cacheable: false };
7819
- }
7820
- try {
7821
- const cache = await caches.open(CACHE_NAME + this.epoch);
7822
- const cacheKey = this.buildCacheKey(request);
7823
- const cached = await cache.match(cacheKey);
7824
- if (!cached) {
7825
- logger.debug("[SDK Html-cache] cacheable, MISS", { trace });
7826
- return { found: false, cacheable: true };
7827
- }
7828
- const age = this.getResponseAge(cached);
7829
- const ttl = parseInt(cached.headers.get("X-Original-TTL") || "") || this.getTTLForRequest(request);
7830
- const swr = parseInt(cached.headers.get("X-Original-SWR") || "") || this.getSWRForRequest(request);
7831
- const isStale = age >= ttl;
7832
- const isExpired = age >= ttl + swr;
7833
- if (!isExpired) {
7834
- logger.debug("[SDK Html-cache] cacheable, HIT", {
7835
- stale: isStale,
7836
- age,
7837
- trace
7838
- });
7839
- const clientResponse = this.buildClientResponse(
7840
- cached,
7841
- ttl,
7842
- swr,
7843
- isStale,
7844
- age
7845
- );
7846
- return {
7847
- found: true,
7848
- stale: isStale,
7849
- response: clientResponse,
7850
- cacheable: true,
7851
- age: Math.floor(age)
7852
- };
7853
- }
7854
- logger.debug("[SDK Html-cache] cacheable, hit, expired", { trace });
7855
- return { found: false, cacheable: true };
7856
- } catch (_) {
7857
- logger.warn("[SDK Html-cache] no get support", { trace });
7858
- return null;
7859
- }
7860
- }
7861
- // 304 support
7862
- async getWithConditionals(request) {
7863
- const result = await this.get(request);
7864
- if (!result?.found || result.stale) {
7865
- return result;
7866
- }
7867
- const ifModifiedSince = request.headers.get("If-Modified-Since");
7868
- const ifNoneMatch = request.headers.get("If-None-Match");
7869
- if ((ifModifiedSince || ifNoneMatch) && result.response) {
7870
- const lastModified = result.response.headers.get("Last-Modified");
7871
- const etag = result.response.headers.get("ETag");
7872
- if (this.checkNotModified(ifModifiedSince, ifNoneMatch, lastModified, etag)) {
7873
- result.notModified = true;
7874
- result.conditional304 = new Response(null, {
7875
- status: 304,
7876
- headers: {
7877
- "Last-Modified": lastModified || "",
7878
- ETag: etag || "",
7879
- "Cache-Control": result.response.headers.get("Cache-Control") || "",
7880
- "Cloudflare-CDN-Cache-Control": result.response.headers.get("Cloudflare-CDN-Cache-Control") || "",
7881
- "X-Cache-Status": "HIT-304"
7882
- }
7883
- });
7884
- }
7885
- }
7886
- return result;
7887
- }
7888
- checkNotModified(ifModifiedSince, ifNoneMatch, lastModified, etag) {
7889
- if (ifNoneMatch && etag) {
7890
- return ifNoneMatch === etag;
7891
- }
7892
- if (ifModifiedSince && lastModified) {
7893
- const ifModDate = new Date(ifModifiedSince);
7894
- const lastModDate = new Date(lastModified);
7895
- return !isNaN(ifModDate.getTime()) && !isNaN(lastModDate.getTime()) && ifModDate >= lastModDate;
7896
- }
7897
- return false;
7898
- }
7899
- createRevalidationRequest(request) {
7900
- const headers = new Headers(request.headers);
7901
- headers.set("X-Cache-Bypass", "revalidation");
7902
- headers.delete("If-None-Match");
7903
- headers.delete("If-Modified-Since");
7904
- headers.delete("Cache-Control");
7905
- headers.delete("Pragma");
7906
- return new Request(request.url, {
7907
- method: "GET",
7908
- headers
7909
- });
7910
- }
7911
- async put(request, response) {
7912
- const trace = createTraceId();
7913
- if (request.method !== "GET" || !response.ok) {
7914
- logger.debug("[SDK Html-cache] put skipped", { trace });
7915
- return;
7916
- }
7917
- if (!this.isCacheable(request) || !this.isResponseCacheable(response)) {
7918
- logger.debug("[SDK Html-cache] put skipped, non-cacheable", {
7919
- trace
7920
- });
7921
- return;
7922
- }
7923
- try {
7924
- const cache = await caches.open(CACHE_NAME + this.epoch);
7925
- const cacheKey = this.buildCacheKey(request);
7926
- await cache.delete(cacheKey);
7927
- const ttl = this.getTTLForRequest(request);
7928
- const swr = this.getSWRForRequest(request);
7929
- const headers = new Headers(response.headers);
7930
- const existingCacheControl = response.headers.get("Cache-Control");
7931
- if (!existingCacheControl || existingCacheControl === "public") {
7932
- const internalMaxAge = ttl + swr;
7933
- headers.set("Cache-Control", `public, max-age=${internalMaxAge}`);
7934
- }
7935
- const cacheTime = (/* @__PURE__ */ new Date()).toISOString();
7936
- headers.set("X-Cache-Time", cacheTime);
7937
- headers.set("X-Original-TTL", ttl.toString());
7938
- headers.set("X-Original-SWR", swr.toString());
7939
- if (!headers.get("Last-Modified")) {
7940
- headers.set("Last-Modified", new Date(cacheTime).toUTCString());
7941
- }
7942
- const cacheableResponse = new Response(response.body, {
7943
- status: response.status,
7944
- statusText: response.statusText,
7945
- headers
7946
- });
7947
- await cache.put(cacheKey, cacheableResponse);
7948
- logger.debug("[SDK Html-cache] put done", { trace });
7949
- } catch (_) {
7950
- logger.warn("[SDK Html-cache] no put support", { trace });
7951
- }
7952
- }
7953
- buildClientResponse(cachedResponse, ttl, swr, isStale, age) {
7954
- const headers = new Headers(cachedResponse.headers);
7955
- headers.set(
7956
- "Cache-Control",
7957
- `public, max-age=${ttl}, stale-while-revalidate=${swr}`
7958
- );
7959
- headers.set(
7960
- "Cloudflare-CDN-Cache-Control",
7961
- `public, s-maxage=${ttl}, stale-while-revalidate=${swr}, stale-if-error=60`
7962
- );
7963
- const cacheTime = headers.get("X-Cache-Time");
7964
- if (cacheTime) {
7965
- const lastModified = new Date(cacheTime).toUTCString();
7966
- headers.set("Last-Modified", lastModified);
7967
- }
7968
- headers.set("X-Cache-Status", isStale ? "STALE" : "HIT");
7969
- headers.set("X-Cache-Age", Math.floor(age).toString());
7970
- headers.delete("X-Original-TTL");
7971
- headers.delete("X-Original-SWR");
7972
- headers.delete("X-Cache-Time");
7973
- return new Response(cachedResponse.body, {
7974
- status: cachedResponse.status,
7975
- statusText: cachedResponse.statusText,
7976
- headers
7977
- });
7978
- }
7979
- buildCacheKey(request) {
7980
- const url = new URL(request.url);
7981
- const versionHash = this.generateVersionHash(request.headers);
7982
- const normalizedQuery = this.normalizeSearchParams(url.searchParams);
7983
- const cacheKeyPath = `${versionHash}${url.pathname}`;
7984
- const keyUrl = new URL(`${CACHE_KEY_ORIGIN}${cacheKeyPath}`);
7985
- if (normalizedQuery) {
7986
- keyUrl.search = `?${normalizedQuery}`;
7987
- }
7988
- const sanitizedHeaders = this.sanitizeHeaders(request.headers);
7989
- return new Request(keyUrl.toString(), {
7990
- method: "GET",
7991
- headers: sanitizedHeaders
7992
- });
7993
- }
7994
- sanitizeHeaders(originalHeaders) {
7995
- const CACHE_RELEVANT_HEADERS = [
7996
- // Content negotiation (affects response format)
7997
- "accept",
7998
- "accept-language"
7999
- ];
8000
- const sanitized = new Headers();
8001
- CACHE_RELEVANT_HEADERS.forEach((header) => {
8002
- const value = originalHeaders.get(header);
8003
- if (value) {
8004
- sanitized.set(header, value);
8005
- }
8006
- });
8007
- return sanitized;
8008
- }
8009
- generateVersionHash(headers) {
8010
- const swellData = this.extractSwellData(headers);
8011
- const versionFactors = {
8012
- store: headers.get("swell-storefront-id") || "",
8013
- auth: headers.get("swell-access-token") || "",
8014
- theme: headers.get("swell-theme-version-hash") || "",
8015
- modified: headers.get("swell-cache-modified") || "",
8016
- currency: swellData["swell-currency"] || "USD",
8017
- locale: headers.get("x-locale") || headers.get("accept-language")?.split(",")[0] || "default",
8018
- context: headers.get("swell-storefront-context"),
8019
- epoch: this.epoch
8020
- };
8021
- return md5(JSON.stringify(versionFactors));
8022
- }
8023
- extractSwellData(headers) {
8024
- const cookie = headers.get("cookie");
8025
- if (!cookie) return {};
8026
- const swellDataMatch = cookie.match(/swell-data=([^;]+)/);
8027
- if (!swellDataMatch) return {};
8028
- try {
8029
- const parsed = JSON.parse(decodeURIComponent(swellDataMatch[1]));
8030
- if (typeof parsed === "object" && parsed !== null) {
8031
- return parsed;
8032
- }
8033
- return {};
8034
- } catch {
8035
- return {};
8036
- }
8037
- }
8038
- isCacheable(request) {
8039
- const url = new URL(request.url);
8040
- const headers = request.headers;
8041
- if (headers.get("swell-deployment-mode") === "editor") {
8042
- return false;
8043
- }
8044
- const skipPaths = ["/checkout"];
8045
- if (skipPaths.some((path) => url.pathname.startsWith(path))) {
8046
- return false;
8047
- }
8048
- if (headers.get("cache-control")?.includes("no-cache")) {
8049
- return false;
8050
- }
8051
- return true;
8052
- }
8053
- isResponseCacheable(response) {
8054
- const contentType = response.headers.get("content-type");
8055
- if (!contentType?.includes("text/html")) {
8056
- return false;
8057
- }
8058
- if (response.headers.get("set-cookie")) {
8059
- return false;
8060
- }
8061
- const cacheControl = response.headers.get("cache-control");
8062
- if (cacheControl?.includes("no-store") || cacheControl?.includes("private")) {
8063
- return false;
8064
- }
8065
- return true;
8066
- }
8067
- getDeploymentMode(headers) {
8068
- const mode = headers.get("swell-deployment-mode");
8069
- if (mode === "preview" || mode === "editor") {
8070
- return mode;
8071
- }
8072
- return "live";
8073
- }
8074
- getTTLForRequest(request) {
8075
- const url = new URL(request.url);
8076
- const path = url.pathname;
8077
- const mode = this.getDeploymentMode(request.headers);
8078
- if (mode === "editor") {
8079
- return 0;
8080
- }
8081
- const config = mode === "preview" ? TTL_CONFIG.PREVIEW : TTL_CONFIG.LIVE;
8082
- if (path === "/") {
8083
- return config.HOME;
8084
- }
8085
- if (path.startsWith("/products/")) {
8086
- return config.PRODUCT;
8087
- }
8088
- if (path.startsWith("/categories/")) {
8089
- return config.COLLECTION;
8090
- }
8091
- if (path.startsWith("/pages/")) {
8092
- return config.PAGE;
8093
- }
8094
- if (path.startsWith("/blogs/")) {
8095
- return config.BLOG;
8096
- }
8097
- return config.DEFAULT;
8098
- }
8099
- getSWRForRequest(request) {
8100
- const mode = this.getDeploymentMode(request.headers);
8101
- if (mode === "editor") {
8102
- return 0;
8103
- }
8104
- return mode === "preview" ? TTL_CONFIG.PREVIEW.SWR : TTL_CONFIG.LIVE.SWR;
8105
- }
8106
- getResponseAge(response) {
8107
- const cacheTime = response.headers.get("X-Cache-Time");
8108
- if (!cacheTime) {
8109
- return Infinity;
8110
- }
8111
- const cacheDate = new Date(cacheTime);
8112
- if (isNaN(cacheDate.getTime())) {
8113
- return Infinity;
8114
- }
8115
- const age = (Date.now() - cacheDate.getTime()) / 1e3;
8116
- return Math.max(0, age);
8117
- }
8118
- normalizeSearchParams(searchParams) {
8119
- const ignoredParams = [
8120
- "utm_source",
8121
- "utm_medium",
8122
- "utm_campaign",
8123
- "utm_content",
8124
- "utm_term",
8125
- "fbclid",
8126
- "gclid",
8127
- "gbraid",
8128
- "wbraid",
8129
- "ref",
8130
- "source",
8131
- "mc_cid",
8132
- "mc_eid"
8133
- ];
8134
- const relevantParams = [];
8135
- searchParams.forEach((value, key) => {
8136
- if (!ignoredParams.includes(key)) {
8137
- relevantParams.push(
8138
- `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
8139
- );
8140
- }
8141
- });
8142
- return relevantParams.sort().join("&");
8143
- }
8144
- };
8145
-
8146
7760
  // src/resources/addresses.ts
8147
7761
  var SwellAddresses = class extends SwellStorefrontCollection {
8148
7762
  constructor(swell, query) {
@@ -16408,7 +16022,7 @@ function ShopifyAddress(instance, address, account) {
16408
16022
  function joinAddressLines(...props) {
16409
16023
  return props.filter(Boolean).join("\n");
16410
16024
  }
16411
- function ShopifyCountry(_instance, countryCode) {
16025
+ function ShopifyCountry(_instance2, countryCode) {
16412
16026
  const currencyCode = getCurrencyByCountry(countryCode) || "USD";
16413
16027
  return new ShopifyResource(
16414
16028
  {
@@ -16741,7 +16355,7 @@ async function resolveLastOrder(instance, account) {
16741
16355
  }
16742
16356
 
16743
16357
  // src/compatibility/shopify-objects/font.ts
16744
- function ShopifyFont(_instance, font) {
16358
+ function ShopifyFont(_instance2, font) {
16745
16359
  if (font instanceof ShopifyResource) {
16746
16360
  return font.clone();
16747
16361
  }
@@ -16752,7 +16366,7 @@ function ShopifyFont(_instance, font) {
16752
16366
  family: font.family,
16753
16367
  style: font.style,
16754
16368
  "system?": font.system,
16755
- variants: font.variants.map((variant) => ShopifyFont(_instance, variant)),
16369
+ variants: font.variants.map((variant) => ShopifyFont(_instance2, variant)),
16756
16370
  weight: font.weight
16757
16371
  });
16758
16372
  }
@@ -16765,7 +16379,7 @@ var SHOPIFY_FORMS = {
16765
16379
  })
16766
16380
  }
16767
16381
  };
16768
- function ShopifyForm(_instance, form) {
16382
+ function ShopifyForm(_instance2, form) {
16769
16383
  if (form instanceof ShopifyResource) {
16770
16384
  return form.clone();
16771
16385
  }
@@ -17062,7 +16676,7 @@ function ShopifyRecommendations(instance, product) {
17062
16676
  }
17063
16677
 
17064
16678
  // src/compatibility/shopify-objects/page.ts
17065
- function ShopifyPage(_instance, page) {
16679
+ function ShopifyPage(_instance2, page) {
17066
16680
  if (page instanceof ShopifyResource) {
17067
16681
  return page.clone();
17068
16682
  }
@@ -18274,7 +17888,7 @@ ${injects.join("\n")}</script>`;
18274
17888
  };
18275
17889
 
18276
17890
  // src/compatibility/shopify-objects/template.ts
18277
- function ShopifyTemplate(_instance, template) {
17891
+ function ShopifyTemplate(_instance2, template) {
18278
17892
  return new ShopifyResource(
18279
17893
  {
18280
17894
  directory: template.path,
@@ -20586,7 +20200,7 @@ var ThemeLoader = class _ThemeLoader {
20586
20200
  flavor,
20587
20201
  trace
20588
20202
  });
20589
- const storage = new ThemeFileStorage(this.swell.workerEnv, flavor);
20203
+ const storage = new ThemeFileCache(this.swell.workerEnv, flavor);
20590
20204
  const result = await storage.putFiles(configs);
20591
20205
  if (result.warnings.length > 0) {
20592
20206
  logger.warn("[ThemeLoader] Theme cache updated with warnings", {
@@ -20624,7 +20238,7 @@ var ThemeLoader = class _ThemeLoader {
20624
20238
  total: configMetadata.length
20625
20239
  });
20626
20240
  const flavor = getKVFlavor(this.swell.workerEnv);
20627
- const storage = new ThemeFileStorage(this.swell.workerEnv, flavor);
20241
+ const storage = new ThemeFileCache(this.swell.workerEnv, flavor);
20628
20242
  const kvHydrated = await storage.getFiles(configMetadata);
20629
20243
  const completeConfigs = await this.ensureConfigsHaveData(kvHydrated);
20630
20244
  for (const config of completeConfigs) {
@@ -21206,12 +20820,7 @@ var SwellTheme3 = class {
21206
20820
  // Default value (always StorefrontResource)
21207
20821
  () => this.fetchCart()
21208
20822
  ),
21209
- this.fetchSingletonResourceCached(
21210
- "account",
21211
- () => this.fetchAccount(),
21212
- () => null,
21213
- false
21214
- )
20823
+ this.fetchAccount()
21215
20824
  ]);
21216
20825
  if (!cart) {
21217
20826
  throw new Error("Failed to fetch cart");
@@ -22846,6 +22455,551 @@ function getResourceQuery(slug, query) {
22846
22455
  ...query
22847
22456
  };
22848
22457
  }
22458
+
22459
+ // src/cache/html-cache/html-cache.ts
22460
+ var CACHE_KEY_ORIGIN = "https://cache.swell.store";
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
+ ]
22471
+ };
22472
+ var HtmlCache = class {
22473
+ epoch;
22474
+ backend;
22475
+ cacheRules;
22476
+ constructor(epoch, backend, cacheRules = DEFAULT_CACHE_RULES) {
22477
+ this.epoch = epoch;
22478
+ this.backend = backend;
22479
+ this.cacheRules = cacheRules;
22480
+ }
22481
+ async get(request) {
22482
+ const trace = createTraceId();
22483
+ if (!this.canReadFromCache(request)) {
22484
+ logger.debug("[SDK Html-cache] non-cacheable request", { trace });
22485
+ return { found: false, cacheable: false };
22486
+ }
22487
+ try {
22488
+ const cacheKey = this.buildCacheKey(request);
22489
+ const entry = await this.backend.read(cacheKey);
22490
+ if (!entry) {
22491
+ logger.debug("[SDK Html-cache] cacheable, MISS", { trace });
22492
+ return { found: false, cacheable: true };
22493
+ }
22494
+ const age = this.getEntryAge(entry);
22495
+ const { ttl, swr } = entry;
22496
+ const isStale = age >= ttl;
22497
+ const isExpired = age >= ttl + swr;
22498
+ if (!isExpired) {
22499
+ logger.debug("[SDK Html-cache] cacheable, HIT", {
22500
+ stale: isStale,
22501
+ age,
22502
+ trace
22503
+ });
22504
+ const clientResponse = this.buildClientResponse(entry, isStale, age);
22505
+ return {
22506
+ found: true,
22507
+ stale: isStale,
22508
+ response: clientResponse,
22509
+ cacheable: true,
22510
+ age: Math.floor(age)
22511
+ };
22512
+ }
22513
+ logger.debug("[SDK Html-cache] cacheable, hit, expired", { trace });
22514
+ return { found: false, cacheable: true };
22515
+ } catch (e) {
22516
+ logger.warn("[SDK Html-cache] get failed", {
22517
+ trace,
22518
+ error: e instanceof Error ? e.message : String(e)
22519
+ });
22520
+ return null;
22521
+ }
22522
+ }
22523
+ async getWithConditionals(request) {
22524
+ const result = await this.get(request);
22525
+ if (!result?.found || result.stale) {
22526
+ return result;
22527
+ }
22528
+ const ifModifiedSince = request.headers.get("If-Modified-Since");
22529
+ const ifNoneMatch = request.headers.get("If-None-Match");
22530
+ if ((ifModifiedSince || ifNoneMatch) && result.response) {
22531
+ const lastModified = result.response.headers.get("Last-Modified");
22532
+ const etag = result.response.headers.get("ETag");
22533
+ if (this.checkNotModified(ifModifiedSince, ifNoneMatch, lastModified, etag)) {
22534
+ result.notModified = true;
22535
+ result.conditional304 = new Response(null, {
22536
+ status: 304,
22537
+ headers: {
22538
+ "Last-Modified": lastModified || "",
22539
+ ETag: etag || "",
22540
+ "Cache-Control": result.response.headers.get("Cache-Control") || "",
22541
+ "Cloudflare-CDN-Cache-Control": result.response.headers.get("Cloudflare-CDN-Cache-Control") || "",
22542
+ "X-Cache-Status": "HIT-304"
22543
+ }
22544
+ });
22545
+ }
22546
+ }
22547
+ return result;
22548
+ }
22549
+ async put(request, response) {
22550
+ const trace = createTraceId();
22551
+ if (!this.canWriteToCache(request, response)) {
22552
+ logger.debug("[SDK Html-cache] put skipped, non-cacheable", { trace });
22553
+ return;
22554
+ }
22555
+ try {
22556
+ const cacheKey = this.buildCacheKey(request);
22557
+ const ttl = this.getTTLForRequest(request);
22558
+ const swr = this.getSWRForRequest(request);
22559
+ const body = await response.text();
22560
+ const cacheTimeISO = (/* @__PURE__ */ new Date()).toISOString();
22561
+ const headers = this.normalizeHeaders(response.headers);
22562
+ const entry = {
22563
+ status: response.status,
22564
+ statusText: response.statusText,
22565
+ headers,
22566
+ body,
22567
+ cacheTimeISO,
22568
+ ttl,
22569
+ swr,
22570
+ etag: this.quoteETag(headers["etag"] || md5(body)),
22571
+ lastModifiedUTC: headers["last-modified"] || new Date(cacheTimeISO).toUTCString()
22572
+ };
22573
+ const hardExpireSeconds = ttl + swr;
22574
+ await this.backend.write(cacheKey, entry, hardExpireSeconds);
22575
+ logger.debug("[SDK Html-cache] put done", { trace });
22576
+ } catch (e) {
22577
+ logger.warn("[SDK Html-cache] put failed", {
22578
+ trace,
22579
+ error: e instanceof Error ? e.message : String(e)
22580
+ });
22581
+ }
22582
+ }
22583
+ async delete(requestOrKey) {
22584
+ try {
22585
+ const key = typeof requestOrKey === "string" ? requestOrKey : this.buildCacheKey(requestOrKey);
22586
+ if (this.backend.delete) {
22587
+ await this.backend.delete(key);
22588
+ }
22589
+ } catch (e) {
22590
+ logger.warn("[SDK Html-cache] delete failed", {
22591
+ error: e instanceof Error ? e.message : String(e)
22592
+ });
22593
+ }
22594
+ }
22595
+ canReadFromCache(request) {
22596
+ const method = request.method.toUpperCase();
22597
+ return (method === "GET" || method === "HEAD") && this.isRequestCacheable(request);
22598
+ }
22599
+ canWriteToCache(request, response) {
22600
+ const method = request.method.toUpperCase();
22601
+ return method === "GET" && response.ok && this.isRequestCacheable(request) && this.isResponseCacheable(response);
22602
+ }
22603
+ createRevalidationRequest(request) {
22604
+ const headers = new Headers(request.headers);
22605
+ headers.set("X-Cache-Bypass", "revalidation");
22606
+ headers.delete("If-None-Match");
22607
+ headers.delete("If-Modified-Since");
22608
+ headers.delete("Cache-Control");
22609
+ headers.delete("Pragma");
22610
+ return new Request(request.url, {
22611
+ method: "GET",
22612
+ headers
22613
+ });
22614
+ }
22615
+ buildClientResponse(entry, isStale, age) {
22616
+ const headers = new Headers(entry.headers);
22617
+ headers.set("Cache-Control", "public, max-age=0, must-revalidate");
22618
+ headers.set(
22619
+ "Cloudflare-CDN-Cache-Control",
22620
+ `public, s-maxage=${entry.ttl}, stale-while-revalidate=${entry.swr}, stale-if-error=60`
22621
+ );
22622
+ if (entry.lastModifiedUTC) {
22623
+ headers.set("Last-Modified", entry.lastModifiedUTC);
22624
+ }
22625
+ if (entry.etag) {
22626
+ headers.set("ETag", entry.etag);
22627
+ }
22628
+ headers.set("X-Cache-Status", isStale ? "STALE" : "HIT");
22629
+ headers.set("X-Cache-Age", Math.floor(age).toString());
22630
+ this.sanitizeClientHeaders(headers);
22631
+ return new Response(entry.body, {
22632
+ status: entry.status,
22633
+ statusText: entry.statusText,
22634
+ headers
22635
+ });
22636
+ }
22637
+ buildCacheKey(request) {
22638
+ const url = new URL(request.url);
22639
+ const versionHash = this.generateVersionHash(request.headers);
22640
+ const normalizedQuery = this.normalizeSearchParams(url.searchParams);
22641
+ const cacheKeyPath = `${versionHash}${url.pathname}`;
22642
+ const keyUrl = new URL(`${CACHE_KEY_ORIGIN}${cacheKeyPath}`);
22643
+ if (normalizedQuery) {
22644
+ keyUrl.search = `?${normalizedQuery}`;
22645
+ }
22646
+ return keyUrl.toString();
22647
+ }
22648
+ checkNotModified(ifModifiedSince, ifNoneMatch, lastModified, etag) {
22649
+ if (this.ifNoneMatchMatches(ifNoneMatch, etag)) {
22650
+ return true;
22651
+ }
22652
+ if (ifModifiedSince && lastModified) {
22653
+ try {
22654
+ const ifModDate = new Date(ifModifiedSince);
22655
+ const lastModDate = new Date(lastModified);
22656
+ if (isNaN(ifModDate.getTime()) || isNaN(lastModDate.getTime())) {
22657
+ return false;
22658
+ }
22659
+ return ifModDate >= lastModDate;
22660
+ } catch {
22661
+ return false;
22662
+ }
22663
+ }
22664
+ return false;
22665
+ }
22666
+ ifNoneMatchMatches(ifNoneMatch, etag) {
22667
+ if (!ifNoneMatch || !etag) return false;
22668
+ const header = ifNoneMatch.trim();
22669
+ if (header === "*") return true;
22670
+ const tokens = header.split(",").map((t) => t.trim());
22671
+ const normalizedEtag = etag.replace(/^W\//, "");
22672
+ for (const token of tokens) {
22673
+ if (token === etag) return true;
22674
+ const normalizedToken = token.replace(/^W\//, "");
22675
+ if (normalizedToken === normalizedEtag) return true;
22676
+ }
22677
+ return false;
22678
+ }
22679
+ quoteETag(value) {
22680
+ if (!value) return value;
22681
+ if (value.startsWith('"') || value.startsWith('W/"')) return value;
22682
+ if (value.startsWith("W/")) return `W/"${value.slice(2)}"`;
22683
+ return `"${value}"`;
22684
+ }
22685
+ sanitizeClientHeaders(headers) {
22686
+ const HOP_BY_HOP = [
22687
+ "connection",
22688
+ "proxy-connection",
22689
+ "keep-alive",
22690
+ "transfer-encoding",
22691
+ "upgrade",
22692
+ "proxy-authenticate",
22693
+ "proxy-authorization",
22694
+ "te",
22695
+ "trailers",
22696
+ "via",
22697
+ "alt-svc",
22698
+ "content-length"
22699
+ ];
22700
+ for (const h of HOP_BY_HOP) headers.delete(h);
22701
+ headers.delete("content-encoding");
22702
+ headers.delete("x-original-ttl");
22703
+ headers.delete("x-original-swr");
22704
+ headers.delete("x-cache-time");
22705
+ }
22706
+ generateVersionHash(headers) {
22707
+ const swellData = this.extractSwellData(headers);
22708
+ const acceptLang = headers.get("accept-language") || "";
22709
+ const accept = headers.get("accept") || "";
22710
+ const versionFactors = {
22711
+ store: headers.get("swell-storefront-id") || "",
22712
+ app: (headers.get("swell-app-id") || "") + "@" + (swellData["swell-app-version"] || ""),
22713
+ auth: headers.get("swell-access-token") || "",
22714
+ theme: headers.get("swell-theme-version-hash") || "",
22715
+ modified: headers.get("swell-cache-modified") || "",
22716
+ currency: swellData["swell-currency"] || "USD",
22717
+ locale: headers.get("x-locale") || acceptLang.split(",")[0].trim().toLowerCase() || "default",
22718
+ context: headers.get("swell-storefront-context"),
22719
+ accept,
22720
+ epoch: this.epoch
22721
+ };
22722
+ return md5(JSON.stringify(versionFactors));
22723
+ }
22724
+ extractSwellData(headers) {
22725
+ const cookie = headers.get("cookie");
22726
+ if (!cookie) return {};
22727
+ const swellDataMatch = cookie.match(/swell-data=([^;]+)/);
22728
+ if (!swellDataMatch) return {};
22729
+ try {
22730
+ return JSON.parse(decodeURIComponent(swellDataMatch[1])) || {};
22731
+ } catch {
22732
+ return {};
22733
+ }
22734
+ }
22735
+ isRequestCacheable(request) {
22736
+ const url = new URL(request.url);
22737
+ if (request.headers.get("swell-deployment-mode") === "editor") 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
+ }
22745
+ if (request.headers.get("cache-control")?.includes("no-cache"))
22746
+ return false;
22747
+ return true;
22748
+ }
22749
+ isResponseCacheable(response) {
22750
+ if (!response.headers.get("content-type")?.includes("text/html"))
22751
+ return false;
22752
+ if (response.headers.get("set-cookie")) return false;
22753
+ const cacheControl = response.headers.get("cache-control");
22754
+ if (cacheControl?.includes("no-store") || cacheControl?.includes("private"))
22755
+ return false;
22756
+ return true;
22757
+ }
22758
+ getDeploymentMode(headers) {
22759
+ const mode = headers.get("swell-deployment-mode");
22760
+ return mode === "preview" ? "preview" : "live";
22761
+ }
22762
+ getTTLForRequest(request) {
22763
+ const url = new URL(request.url);
22764
+ const mode = this.getDeploymentMode(request.headers);
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;
22774
+ }
22775
+ getSWRForRequest(request) {
22776
+ const url = new URL(request.url);
22777
+ const mode = this.getDeploymentMode(request.headers);
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;
22787
+ }
22788
+ getEntryAge(entry) {
22789
+ const t = Date.parse(entry.cacheTimeISO);
22790
+ if (Number.isNaN(t)) return Infinity;
22791
+ const age = (Date.now() - t) / 1e3;
22792
+ return age < 0 ? 0 : age;
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
+ }
22810
+ normalizeSearchParams(searchParams) {
22811
+ const ignoredParams = [
22812
+ "utm_source",
22813
+ "utm_medium",
22814
+ "utm_campaign",
22815
+ "utm_content",
22816
+ "utm_term",
22817
+ "fbclid",
22818
+ "gclid",
22819
+ "gbraid",
22820
+ "wbraid",
22821
+ "ref",
22822
+ "source",
22823
+ "mc_cid",
22824
+ "mc_eid"
22825
+ ];
22826
+ const relevantParams = [];
22827
+ searchParams.forEach((value, key) => {
22828
+ if (!ignoredParams.includes(key)) {
22829
+ relevantParams.push(
22830
+ `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
22831
+ );
22832
+ }
22833
+ });
22834
+ return relevantParams.sort().join("&");
22835
+ }
22836
+ };
22837
+
22838
+ // src/cache/html-cache/html-cache-kv.ts
22839
+ var KVCacheBackend = class {
22840
+ kv;
22841
+ prefix;
22842
+ hashKeys;
22843
+ maxValueBytes;
22844
+ constructor(kv, opts = {}) {
22845
+ this.kv = kv;
22846
+ this.prefix = opts.prefix;
22847
+ this.hashKeys = opts.hashKeys !== false;
22848
+ this.maxValueBytes = opts.maxValueBytes ?? Math.floor(24.5 * 1024 * 1024);
22849
+ }
22850
+ async read(key) {
22851
+ const kvKey = this.makeKey(key);
22852
+ const value = await this.kv.get(kvKey, "json");
22853
+ if (!value) return null;
22854
+ const entry = {
22855
+ status: value.status,
22856
+ statusText: value.statusText,
22857
+ headers: value.headers,
22858
+ body: value.body,
22859
+ cacheTimeISO: value.cacheTimeISO,
22860
+ ttl: value.ttl,
22861
+ swr: value.swr,
22862
+ etag: value.etag,
22863
+ lastModifiedUTC: value.lastModifiedUTC
22864
+ };
22865
+ return entry;
22866
+ }
22867
+ async write(key, entry, hardExpireSeconds) {
22868
+ const kvKey = this.makeKey(key);
22869
+ const payload = {
22870
+ v: 1,
22871
+ status: entry.status,
22872
+ statusText: entry.statusText,
22873
+ headers: entry.headers,
22874
+ body: entry.body,
22875
+ cacheTimeISO: entry.cacheTimeISO,
22876
+ ttl: entry.ttl,
22877
+ swr: entry.swr,
22878
+ etag: entry.etag,
22879
+ lastModifiedUTC: entry.lastModifiedUTC
22880
+ };
22881
+ const json = JSON.stringify(payload);
22882
+ this.assertSize(json);
22883
+ const metadata = {
22884
+ v: 1,
22885
+ cacheTimeISO: entry.cacheTimeISO,
22886
+ ttl: entry.ttl,
22887
+ swr: entry.swr,
22888
+ etag: entry.etag,
22889
+ lastModifiedUTC: entry.lastModifiedUTC
22890
+ };
22891
+ await this.kv.put(kvKey, json, {
22892
+ expirationTtl: hardExpireSeconds + 60,
22893
+ // natural hard expiry after SWR + grace period
22894
+ metadata
22895
+ });
22896
+ }
22897
+ async delete(key) {
22898
+ const kvKey = this.makeKey(key);
22899
+ await this.kv.delete(kvKey);
22900
+ }
22901
+ // ---- private helpers ----
22902
+ makeKey(raw) {
22903
+ const core = this.hashKeys ? md5(raw) : raw;
22904
+ return this.prefix ? `${this.prefix}:${core}` : core;
22905
+ }
22906
+ assertSize(json) {
22907
+ const bytes = typeof TextEncoder !== "undefined" ? new TextEncoder().encode(json).length : this.approxUtf8Bytes(json);
22908
+ if (bytes > this.maxValueBytes) {
22909
+ throw new Error(
22910
+ `KV value too large: ${bytes} bytes exceeds limit ${this.maxValueBytes} bytes`
22911
+ );
22912
+ }
22913
+ }
22914
+ approxUtf8Bytes(str) {
22915
+ let count = 0;
22916
+ for (let i = 0; i < str.length; i++) {
22917
+ const code = str.charCodeAt(i);
22918
+ if (code <= 127) count += 1;
22919
+ else if (code <= 2047) count += 2;
22920
+ else count += 3;
22921
+ }
22922
+ return count;
22923
+ }
22924
+ };
22925
+
22926
+ // src/cache/html-cache/html-cache-worker.ts
22927
+ var CACHE_NAME_PREFIX = "swell-html-v0";
22928
+ var WorkerCacheBackend = class {
22929
+ cacheName;
22930
+ constructor(epoch) {
22931
+ this.cacheName = CACHE_NAME_PREFIX + epoch;
22932
+ }
22933
+ async read(key) {
22934
+ const cache = await caches.open(this.cacheName);
22935
+ const request = new Request(key);
22936
+ const response = await cache.match(request);
22937
+ if (!response) return null;
22938
+ const headers = {};
22939
+ response.headers.forEach((value, name) => {
22940
+ headers[name.toLowerCase()] = value;
22941
+ });
22942
+ return {
22943
+ status: response.status,
22944
+ statusText: response.statusText,
22945
+ headers,
22946
+ body: await response.text(),
22947
+ cacheTimeISO: response.headers.get("x-cache-time") || (/* @__PURE__ */ new Date(0)).toISOString(),
22948
+ ttl: parseInt(response.headers.get("x-original-ttl") || "0", 10),
22949
+ swr: parseInt(response.headers.get("x-original-swr") || "0", 10),
22950
+ etag: response.headers.get("etag") || void 0,
22951
+ lastModifiedUTC: response.headers.get("last-modified") || void 0
22952
+ };
22953
+ }
22954
+ async write(key, entry, _hardExpireSeconds) {
22955
+ const cache = await caches.open(this.cacheName);
22956
+ const request = new Request(key);
22957
+ const headers = new Headers(entry.headers);
22958
+ if (entry.lastModifiedUTC && !headers.get("Last-Modified")) {
22959
+ headers.set("Last-Modified", entry.lastModifiedUTC);
22960
+ }
22961
+ if (entry.etag && !headers.get("ETag")) {
22962
+ headers.set("ETag", entry.etag);
22963
+ }
22964
+ headers.set("X-Cache-Time", entry.cacheTimeISO);
22965
+ headers.set("X-Original-TTL", String(entry.ttl));
22966
+ headers.set("X-Original-SWR", String(entry.swr));
22967
+ headers.delete("content-encoding");
22968
+ headers.delete("content-length");
22969
+ const existing = headers.get("Cache-Control");
22970
+ if (!existing || existing.trim().toLowerCase() === "public") {
22971
+ headers.set("Cache-Control", `public, max-age=${entry.ttl + entry.swr}`);
22972
+ }
22973
+ const response = new Response(entry.body, {
22974
+ status: entry.status,
22975
+ statusText: entry.statusText,
22976
+ headers
22977
+ });
22978
+ await cache.delete(request);
22979
+ await cache.put(request, response);
22980
+ }
22981
+ async delete(key) {
22982
+ const cache = await caches.open(this.cacheName);
22983
+ const request = new Request(key);
22984
+ await cache.delete(request);
22985
+ }
22986
+ };
22987
+
22988
+ // src/cache/html-cache/html-cache-factory.ts
22989
+ var _instance = null;
22990
+ function getHtmlCache(env, cacheRules) {
22991
+ const epoch = env?.HTML_CACHE_EPOCH;
22992
+ if (typeof epoch !== "string" || !epoch) return null;
22993
+ if (_instance) return _instance;
22994
+ const kv = env?.NAMESPACE;
22995
+ const rules = cacheRules || env?.HTML_CACHE_RULES;
22996
+ if (env?.HTML_CACHE_BACKEND !== "worker" && kv) {
22997
+ _instance = new HtmlCache(epoch, new KVCacheBackend(kv), rules);
22998
+ return _instance;
22999
+ }
23000
+ _instance = new HtmlCache(epoch, new WorkerCacheBackend(epoch), rules);
23001
+ return _instance;
23002
+ }
22849
23003
  // Annotate the CommonJS export names for ESM import in node:
22850
23004
  0 && (module.exports = {
22851
23005
  AccountAddressesResource,
@@ -22860,10 +23014,12 @@ function getResourceQuery(slug, query) {
22860
23014
  CartResource,
22861
23015
  CategoriesResource,
22862
23016
  CategoryResource,
23017
+ DEFAULT_CACHE_RULES,
22863
23018
  DEFAULT_QUERY_PAGE_LIMIT,
22864
23019
  DeferredShopifyResource,
22865
23020
  FILE_DATA_INCLUDE_QUERY,
22866
23021
  GEO_DATA,
23022
+ HtmlCache,
22867
23023
  LANG_TO_COUNTRY_CODES,
22868
23024
  LiquidSwell,
22869
23025
  MAX_QUERY_PAGE_LIMIT,
@@ -22911,7 +23067,6 @@ function getResourceQuery(slug, query) {
22911
23067
  ThemeForm,
22912
23068
  ThemeFormErrors,
22913
23069
  VariantResource,
22914
- WorkerHtmlCache,
22915
23070
  adaptShopifyFontData,
22916
23071
  adaptShopifyFormData,
22917
23072
  adaptShopifyMenuData,
@@ -22939,6 +23094,7 @@ function getResourceQuery(slug, query) {
22939
23094
  getEasyblocksComponentDefinitions,
22940
23095
  getEasyblocksPagePropsWithConfigs,
22941
23096
  getEasyblocksPageTemplate,
23097
+ getHtmlCache,
22942
23098
  getKVFlavor,
22943
23099
  getLayoutSectionGroups,
22944
23100
  getMenuItemStorefrontUrl,