@swell/apps-sdk 1.0.159 → 1.0.161

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