@swell/apps-sdk 1.0.152 → 1.0.153

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
@@ -7858,20 +7858,38 @@ var WorkerCacheProxy = class {
7858
7858
  var CACHE_NAME2 = "swell-html-v1";
7859
7859
  var CACHE_KEY_ORIGIN2 = "https://cache.swell.store";
7860
7860
  var TTL_CONFIG = {
7861
- DEFAULT: 300,
7862
- // 5 minutes
7863
- DEFAULT_SWR: 3600,
7864
- // 1 hour stale-while-revalidate
7865
- HOME: 300,
7866
- // 5 minutes
7867
- PRODUCT: 600,
7868
- // 10 minutes
7869
- COLLECTION: 900,
7870
- // 15 minutes
7871
- PAGE: 3600,
7872
- // 1 hour
7873
- BLOG: 1800
7874
- // 30 minutes
7861
+ LIVE: {
7862
+ DEFAULT: 300,
7863
+ // 5 minutes
7864
+ HOME: 300,
7865
+ // 5 minutes
7866
+ PRODUCT: 600,
7867
+ // 10 minutes
7868
+ COLLECTION: 900,
7869
+ // 15 minutes
7870
+ PAGE: 3600,
7871
+ // 1 hour
7872
+ BLOG: 1800,
7873
+ // 30 minutes
7874
+ SWR: 3600
7875
+ // 1 hour stale-while-revalidate
7876
+ },
7877
+ PREVIEW: {
7878
+ DEFAULT: 5,
7879
+ // 1 minute - faster updates in preview
7880
+ HOME: 5,
7881
+ // 1 minute
7882
+ PRODUCT: 5,
7883
+ // 2 minutes
7884
+ COLLECTION: 5,
7885
+ // 3 minutes
7886
+ PAGE: 5,
7887
+ // 5 minutes
7888
+ BLOG: 5,
7889
+ // 5 minutes
7890
+ SWR: 600
7891
+ // 10 minutes stale-while-revalidate
7892
+ }
7875
7893
  };
7876
7894
  var WorkerHtmlCache = class {
7877
7895
  epoch;
@@ -7898,7 +7916,7 @@ var WorkerHtmlCache = class {
7898
7916
  }
7899
7917
  const age = this.getResponseAge(cached);
7900
7918
  const ttl = parseInt(cached.headers.get("X-Original-TTL") || "") || this.getTTLForRequest(request);
7901
- const swr = parseInt(cached.headers.get("X-Original-SWR") || "") || TTL_CONFIG.DEFAULT_SWR;
7919
+ const swr = parseInt(cached.headers.get("X-Original-SWR") || "") || this.getSWRForRequest(request);
7902
7920
  const isStale = age >= ttl;
7903
7921
  const isExpired = age >= ttl + swr;
7904
7922
  if (!isExpired) {
@@ -7929,6 +7947,56 @@ var WorkerHtmlCache = class {
7929
7947
  return null;
7930
7948
  }
7931
7949
  }
7950
+ // 304 support
7951
+ async getWithConditionals(request) {
7952
+ const result = await this.get(request);
7953
+ if (!result?.found || result.stale) {
7954
+ return result;
7955
+ }
7956
+ const ifModifiedSince = request.headers.get("If-Modified-Since");
7957
+ const ifNoneMatch = request.headers.get("If-None-Match");
7958
+ if ((ifModifiedSince || ifNoneMatch) && result.response) {
7959
+ const lastModified = result.response.headers.get("Last-Modified");
7960
+ const etag = result.response.headers.get("ETag");
7961
+ if (this.checkNotModified(ifModifiedSince, ifNoneMatch, lastModified, etag)) {
7962
+ result.notModified = true;
7963
+ result.conditional304 = new Response(null, {
7964
+ status: 304,
7965
+ headers: {
7966
+ "Last-Modified": lastModified || "",
7967
+ ETag: etag || "",
7968
+ "Cache-Control": result.response.headers.get("Cache-Control") || "",
7969
+ "Cloudflare-CDN-Cache-Control": result.response.headers.get("Cloudflare-CDN-Cache-Control") || "",
7970
+ "X-Cache-Status": "HIT-304"
7971
+ }
7972
+ });
7973
+ }
7974
+ }
7975
+ return result;
7976
+ }
7977
+ checkNotModified(ifModifiedSince, ifNoneMatch, lastModified, etag) {
7978
+ if (ifNoneMatch && etag) {
7979
+ return ifNoneMatch === etag;
7980
+ }
7981
+ if (ifModifiedSince && lastModified) {
7982
+ const ifModDate = new Date(ifModifiedSince);
7983
+ const lastModDate = new Date(lastModified);
7984
+ return !isNaN(ifModDate.getTime()) && !isNaN(lastModDate.getTime()) && ifModDate >= lastModDate;
7985
+ }
7986
+ return false;
7987
+ }
7988
+ createRevalidationRequest(request) {
7989
+ const headers = new Headers(request.headers);
7990
+ headers.set("X-Cache-Bypass", "revalidation");
7991
+ headers.delete("If-None-Match");
7992
+ headers.delete("If-Modified-Since");
7993
+ headers.delete("Cache-Control");
7994
+ headers.delete("Pragma");
7995
+ return new Request(request.url, {
7996
+ method: "GET",
7997
+ headers
7998
+ });
7999
+ }
7932
8000
  async put(request, response) {
7933
8001
  const trace = createTraceId();
7934
8002
  if (request.method !== "GET" || !response.ok) {
@@ -7944,17 +8012,22 @@ var WorkerHtmlCache = class {
7944
8012
  try {
7945
8013
  const cache = await caches.open(CACHE_NAME2 + this.epoch);
7946
8014
  const cacheKey = this.buildCacheKey(request);
8015
+ await cache.delete(cacheKey);
7947
8016
  const ttl = this.getTTLForRequest(request);
7948
- const swr = TTL_CONFIG.DEFAULT_SWR;
8017
+ const swr = this.getSWRForRequest(request);
7949
8018
  const headers = new Headers(response.headers);
7950
8019
  const existingCacheControl = response.headers.get("Cache-Control");
7951
8020
  if (!existingCacheControl || existingCacheControl === "public") {
7952
8021
  const internalMaxAge = ttl + swr;
7953
8022
  headers.set("Cache-Control", `public, max-age=${internalMaxAge}`);
7954
8023
  }
7955
- headers.set("X-Cache-Time", (/* @__PURE__ */ new Date()).toISOString());
8024
+ const cacheTime = (/* @__PURE__ */ new Date()).toISOString();
8025
+ headers.set("X-Cache-Time", cacheTime);
7956
8026
  headers.set("X-Original-TTL", ttl.toString());
7957
8027
  headers.set("X-Original-SWR", swr.toString());
8028
+ if (!headers.get("Last-Modified")) {
8029
+ headers.set("Last-Modified", new Date(cacheTime).toUTCString());
8030
+ }
7958
8031
  const cacheableResponse = new Response(response.body, {
7959
8032
  status: response.status,
7960
8033
  statusText: response.statusText,
@@ -7966,28 +8039,32 @@ var WorkerHtmlCache = class {
7966
8039
  logger.warn("[SDK Html-cache] no put support", { trace });
7967
8040
  }
7968
8041
  }
7969
- /**
7970
- * Build client response with correct headers
7971
- */
7972
8042
  buildClientResponse(cachedResponse, ttl, swr, isStale, age) {
7973
8043
  const headers = new Headers(cachedResponse.headers);
7974
8044
  headers.set(
7975
8045
  "Cache-Control",
7976
8046
  `public, max-age=${ttl}, stale-while-revalidate=${swr}`
7977
8047
  );
8048
+ headers.set(
8049
+ "Cloudflare-CDN-Cache-Control",
8050
+ `public, s-maxage=${ttl}, stale-while-revalidate=${swr}, stale-if-error=60`
8051
+ );
8052
+ const cacheTime = headers.get("X-Cache-Time");
8053
+ if (cacheTime) {
8054
+ const lastModified = new Date(cacheTime).toUTCString();
8055
+ headers.set("Last-Modified", lastModified);
8056
+ }
7978
8057
  headers.set("X-Cache-Status", isStale ? "STALE" : "HIT");
7979
8058
  headers.set("X-Cache-Age", Math.floor(age).toString());
7980
8059
  headers.delete("X-Original-TTL");
7981
8060
  headers.delete("X-Original-SWR");
8061
+ headers.delete("X-Cache-Time");
7982
8062
  return new Response(cachedResponse.body, {
7983
8063
  status: cachedResponse.status,
7984
8064
  statusText: cachedResponse.statusText,
7985
8065
  headers
7986
8066
  });
7987
8067
  }
7988
- /**
7989
- * Build cache key from request using two-level structure
7990
- */
7991
8068
  buildCacheKey(request) {
7992
8069
  const url = new URL(request.url);
7993
8070
  const versionHash = this.generateVersionHash(request.headers);
@@ -8003,22 +8080,11 @@ var WorkerHtmlCache = class {
8003
8080
  headers: sanitizedHeaders
8004
8081
  });
8005
8082
  }
8006
- /**
8007
- * Sanitize headers for cache operations - minimal whitelist approach
8008
- */
8009
8083
  sanitizeHeaders(originalHeaders) {
8010
8084
  const CACHE_RELEVANT_HEADERS = [
8011
8085
  // Content negotiation (affects response format)
8012
8086
  "accept",
8013
- "accept-encoding",
8014
- "accept-language",
8015
- // Cache control directives from client/proxy
8016
- "cache-control",
8017
- "pragma",
8018
- // Legacy cache control
8019
- // Conditional request headers (for 304 responses)
8020
- "if-none-match",
8021
- "if-modified-since"
8087
+ "accept-language"
8022
8088
  ];
8023
8089
  const sanitized = new Headers();
8024
8090
  CACHE_RELEVANT_HEADERS.forEach((header) => {
@@ -8029,15 +8095,13 @@ var WorkerHtmlCache = class {
8029
8095
  });
8030
8096
  return sanitized;
8031
8097
  }
8032
- /**
8033
- * Generate version hash from headers and cookies
8034
- */
8035
8098
  generateVersionHash(headers) {
8036
8099
  const swellData = this.extractSwellData(headers);
8037
8100
  const versionFactors = {
8038
8101
  store: headers.get("swell-storefront-id") || "",
8039
8102
  auth: headers.get("swell-access-token") || "",
8040
8103
  theme: headers.get("swell-theme-version-hash") || "",
8104
+ modified: headers.get("swell-cache-modified") || "",
8041
8105
  currency: swellData["swell-currency"] || "USD",
8042
8106
  locale: headers.get("x-locale") || headers.get("accept-language")?.split(",")[0] || "default",
8043
8107
  context: headers.get("swell-storefront-context"),
@@ -8045,9 +8109,6 @@ var WorkerHtmlCache = class {
8045
8109
  };
8046
8110
  return md5(JSON.stringify(versionFactors));
8047
8111
  }
8048
- /**
8049
- * Extract swell-data from cookies
8050
- */
8051
8112
  extractSwellData(headers) {
8052
8113
  const cookie = headers.get("cookie");
8053
8114
  if (!cookie) return {};
@@ -8083,31 +8144,53 @@ var WorkerHtmlCache = class {
8083
8144
  if (!contentType?.includes("text/html")) {
8084
8145
  return false;
8085
8146
  }
8147
+ if (response.headers.get("set-cookie")) {
8148
+ return false;
8149
+ }
8086
8150
  const cacheControl = response.headers.get("cache-control");
8087
8151
  if (cacheControl?.includes("no-store") || cacheControl?.includes("private")) {
8088
8152
  return false;
8089
8153
  }
8090
8154
  return true;
8091
8155
  }
8156
+ getDeploymentMode(headers) {
8157
+ const mode = headers.get("swell-deployment-mode");
8158
+ if (mode === "preview" || mode === "editor") {
8159
+ return mode;
8160
+ }
8161
+ return "live";
8162
+ }
8092
8163
  getTTLForRequest(request) {
8093
8164
  const url = new URL(request.url);
8094
8165
  const path = url.pathname;
8166
+ const mode = this.getDeploymentMode(request.headers);
8167
+ if (mode === "editor") {
8168
+ return 0;
8169
+ }
8170
+ const config = mode === "preview" ? TTL_CONFIG.PREVIEW : TTL_CONFIG.LIVE;
8095
8171
  if (path === "/") {
8096
- return TTL_CONFIG.HOME;
8172
+ return config.HOME;
8097
8173
  }
8098
8174
  if (path.startsWith("/products/")) {
8099
- return TTL_CONFIG.PRODUCT;
8175
+ return config.PRODUCT;
8100
8176
  }
8101
8177
  if (path.startsWith("/categories/")) {
8102
- return TTL_CONFIG.COLLECTION;
8178
+ return config.COLLECTION;
8103
8179
  }
8104
8180
  if (path.startsWith("/pages/")) {
8105
- return TTL_CONFIG.PAGE;
8181
+ return config.PAGE;
8106
8182
  }
8107
8183
  if (path.startsWith("/blogs/")) {
8108
- return TTL_CONFIG.BLOG;
8184
+ return config.BLOG;
8185
+ }
8186
+ return config.DEFAULT;
8187
+ }
8188
+ getSWRForRequest(request) {
8189
+ const mode = this.getDeploymentMode(request.headers);
8190
+ if (mode === "editor") {
8191
+ return 0;
8109
8192
  }
8110
- return TTL_CONFIG.DEFAULT;
8193
+ return mode === "preview" ? TTL_CONFIG.PREVIEW.SWR : TTL_CONFIG.LIVE.SWR;
8111
8194
  }
8112
8195
  getResponseAge(response) {
8113
8196
  const cacheTime = response.headers.get("X-Cache-Time");
@@ -8121,31 +8204,6 @@ var WorkerHtmlCache = class {
8121
8204
  const age = (Date.now() - cacheDate.getTime()) / 1e3;
8122
8205
  return Math.max(0, age);
8123
8206
  }
8124
- getMaxAge(response) {
8125
- const cacheControl = response.headers.get("Cache-Control");
8126
- if (!cacheControl) {
8127
- return TTL_CONFIG.DEFAULT;
8128
- }
8129
- const maxAgeMatch = cacheControl.match(/max-age=(\d+)/);
8130
- if (maxAgeMatch) {
8131
- return parseInt(maxAgeMatch[1], 10);
8132
- }
8133
- return TTL_CONFIG.DEFAULT;
8134
- }
8135
- getStaleWindow(response) {
8136
- const cacheControl = response.headers.get("Cache-Control");
8137
- if (!cacheControl) {
8138
- return TTL_CONFIG.DEFAULT_SWR;
8139
- }
8140
- const swrMatch = cacheControl.match(/stale-while-revalidate=(\d+)/);
8141
- if (swrMatch) {
8142
- return parseInt(swrMatch[1], 10);
8143
- }
8144
- return TTL_CONFIG.DEFAULT_SWR;
8145
- }
8146
- /**
8147
- * Normalize search params for cache key
8148
- */
8149
8207
  normalizeSearchParams(searchParams) {
8150
8208
  const ignoredParams = [
8151
8209
  "utm_source",