@swell/apps-sdk 1.0.152 → 1.0.154
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 +152 -81
- package/dist/index.cjs.map +2 -2
- package/dist/index.js +152 -81
- package/dist/index.js.map +2 -2
- package/dist/index.mjs +152 -81
- package/dist/index.mjs.map +2 -2
- package/dist/src/cache/worker-html-cache.d.ts +7 -20
- package/dist/src/resources.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -713,18 +713,31 @@ var StorefrontResource = class {
|
|
|
713
713
|
return this._compatibilityProps[prop];
|
|
714
714
|
}
|
|
715
715
|
};
|
|
716
|
+
var RESOURCE_CLONE_PROPS = Object.freeze([
|
|
717
|
+
"_defaultGetter",
|
|
718
|
+
"_getResourceObject",
|
|
719
|
+
"_collection",
|
|
720
|
+
"_swell",
|
|
721
|
+
"_query",
|
|
722
|
+
"_params",
|
|
723
|
+
"_id",
|
|
724
|
+
"_resourceName"
|
|
725
|
+
]);
|
|
716
726
|
function cloneStorefrontResource(input) {
|
|
717
|
-
const resourceName = input._resourceName;
|
|
727
|
+
const resourceName = input._resourceName || input.constructor?.name;
|
|
718
728
|
const ClonedClass = class extends StorefrontResource {
|
|
719
729
|
};
|
|
720
730
|
Object.defineProperty(ClonedClass, "name", {
|
|
721
731
|
value: resourceName
|
|
722
732
|
});
|
|
723
733
|
const clone = new ClonedClass(input._getter);
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
734
|
+
for (const key of RESOURCE_CLONE_PROPS) {
|
|
735
|
+
if (input[key] !== void 0) {
|
|
736
|
+
Object.defineProperty(clone, key, {
|
|
737
|
+
value: input[key]
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
}
|
|
728
741
|
return clone;
|
|
729
742
|
}
|
|
730
743
|
var SwellStorefrontResource = class extends StorefrontResource {
|
|
@@ -743,7 +756,7 @@ var SwellStorefrontResource = class extends StorefrontResource {
|
|
|
743
756
|
_getProxy() {
|
|
744
757
|
return super._getProxy();
|
|
745
758
|
}
|
|
746
|
-
|
|
759
|
+
_getResourceObject() {
|
|
747
760
|
const { _swell, _collection } = this;
|
|
748
761
|
this._resource = (_swell?.storefront)[_collection];
|
|
749
762
|
if (_swell && _collection.startsWith("content/")) {
|
|
@@ -800,7 +813,7 @@ var SwellStorefrontCollection = class _SwellStorefrontCollection extends SwellSt
|
|
|
800
813
|
return properQuery;
|
|
801
814
|
}
|
|
802
815
|
_defaultGetter() {
|
|
803
|
-
const resource = this.
|
|
816
|
+
const resource = this._getResourceObject();
|
|
804
817
|
async function defaultGetter() {
|
|
805
818
|
return resource.list(this._query);
|
|
806
819
|
}
|
|
@@ -927,7 +940,7 @@ var SwellStorefrontRecord = class extends SwellStorefrontResource {
|
|
|
927
940
|
return super._getProxy();
|
|
928
941
|
}
|
|
929
942
|
_defaultGetter() {
|
|
930
|
-
const resource = this.
|
|
943
|
+
const resource = this._getResourceObject();
|
|
931
944
|
async function defaultGetter() {
|
|
932
945
|
return resource.get(this._id, this._query);
|
|
933
946
|
}
|
|
@@ -986,7 +999,7 @@ var SwellStorefrontSingleton = class extends SwellStorefrontResource {
|
|
|
986
999
|
_collection,
|
|
987
1000
|
_swell: { storefrontContext }
|
|
988
1001
|
} = this;
|
|
989
|
-
const resource = this.
|
|
1002
|
+
const resource = this._getResourceObject();
|
|
990
1003
|
async function defaultGetter() {
|
|
991
1004
|
if (storefrontContext[_collection] !== void 0) {
|
|
992
1005
|
return storefrontContext[_collection];
|
|
@@ -7711,20 +7724,38 @@ var WorkerCacheProxy = class {
|
|
|
7711
7724
|
var CACHE_NAME2 = "swell-html-v1";
|
|
7712
7725
|
var CACHE_KEY_ORIGIN2 = "https://cache.swell.store";
|
|
7713
7726
|
var TTL_CONFIG = {
|
|
7714
|
-
|
|
7715
|
-
|
|
7716
|
-
|
|
7717
|
-
|
|
7718
|
-
|
|
7719
|
-
|
|
7720
|
-
|
|
7721
|
-
|
|
7722
|
-
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
|
|
7726
|
-
|
|
7727
|
-
|
|
7727
|
+
LIVE: {
|
|
7728
|
+
DEFAULT: 300,
|
|
7729
|
+
// 5 minutes
|
|
7730
|
+
HOME: 300,
|
|
7731
|
+
// 5 minutes
|
|
7732
|
+
PRODUCT: 600,
|
|
7733
|
+
// 10 minutes
|
|
7734
|
+
COLLECTION: 900,
|
|
7735
|
+
// 15 minutes
|
|
7736
|
+
PAGE: 3600,
|
|
7737
|
+
// 1 hour
|
|
7738
|
+
BLOG: 1800,
|
|
7739
|
+
// 30 minutes
|
|
7740
|
+
SWR: 3600
|
|
7741
|
+
// 1 hour stale-while-revalidate
|
|
7742
|
+
},
|
|
7743
|
+
PREVIEW: {
|
|
7744
|
+
DEFAULT: 5,
|
|
7745
|
+
// 1 minute - faster updates in preview
|
|
7746
|
+
HOME: 5,
|
|
7747
|
+
// 1 minute
|
|
7748
|
+
PRODUCT: 5,
|
|
7749
|
+
// 2 minutes
|
|
7750
|
+
COLLECTION: 5,
|
|
7751
|
+
// 3 minutes
|
|
7752
|
+
PAGE: 5,
|
|
7753
|
+
// 5 minutes
|
|
7754
|
+
BLOG: 5,
|
|
7755
|
+
// 5 minutes
|
|
7756
|
+
SWR: 600
|
|
7757
|
+
// 10 minutes stale-while-revalidate
|
|
7758
|
+
}
|
|
7728
7759
|
};
|
|
7729
7760
|
var WorkerHtmlCache = class {
|
|
7730
7761
|
epoch;
|
|
@@ -7751,7 +7782,7 @@ var WorkerHtmlCache = class {
|
|
|
7751
7782
|
}
|
|
7752
7783
|
const age = this.getResponseAge(cached);
|
|
7753
7784
|
const ttl = parseInt(cached.headers.get("X-Original-TTL") || "") || this.getTTLForRequest(request);
|
|
7754
|
-
const swr = parseInt(cached.headers.get("X-Original-SWR") || "") ||
|
|
7785
|
+
const swr = parseInt(cached.headers.get("X-Original-SWR") || "") || this.getSWRForRequest(request);
|
|
7755
7786
|
const isStale = age >= ttl;
|
|
7756
7787
|
const isExpired = age >= ttl + swr;
|
|
7757
7788
|
if (!isExpired) {
|
|
@@ -7782,6 +7813,56 @@ var WorkerHtmlCache = class {
|
|
|
7782
7813
|
return null;
|
|
7783
7814
|
}
|
|
7784
7815
|
}
|
|
7816
|
+
// 304 support
|
|
7817
|
+
async getWithConditionals(request) {
|
|
7818
|
+
const result = await this.get(request);
|
|
7819
|
+
if (!result?.found || result.stale) {
|
|
7820
|
+
return result;
|
|
7821
|
+
}
|
|
7822
|
+
const ifModifiedSince = request.headers.get("If-Modified-Since");
|
|
7823
|
+
const ifNoneMatch = request.headers.get("If-None-Match");
|
|
7824
|
+
if ((ifModifiedSince || ifNoneMatch) && result.response) {
|
|
7825
|
+
const lastModified = result.response.headers.get("Last-Modified");
|
|
7826
|
+
const etag = result.response.headers.get("ETag");
|
|
7827
|
+
if (this.checkNotModified(ifModifiedSince, ifNoneMatch, lastModified, etag)) {
|
|
7828
|
+
result.notModified = true;
|
|
7829
|
+
result.conditional304 = new Response(null, {
|
|
7830
|
+
status: 304,
|
|
7831
|
+
headers: {
|
|
7832
|
+
"Last-Modified": lastModified || "",
|
|
7833
|
+
ETag: etag || "",
|
|
7834
|
+
"Cache-Control": result.response.headers.get("Cache-Control") || "",
|
|
7835
|
+
"Cloudflare-CDN-Cache-Control": result.response.headers.get("Cloudflare-CDN-Cache-Control") || "",
|
|
7836
|
+
"X-Cache-Status": "HIT-304"
|
|
7837
|
+
}
|
|
7838
|
+
});
|
|
7839
|
+
}
|
|
7840
|
+
}
|
|
7841
|
+
return result;
|
|
7842
|
+
}
|
|
7843
|
+
checkNotModified(ifModifiedSince, ifNoneMatch, lastModified, etag) {
|
|
7844
|
+
if (ifNoneMatch && etag) {
|
|
7845
|
+
return ifNoneMatch === etag;
|
|
7846
|
+
}
|
|
7847
|
+
if (ifModifiedSince && lastModified) {
|
|
7848
|
+
const ifModDate = new Date(ifModifiedSince);
|
|
7849
|
+
const lastModDate = new Date(lastModified);
|
|
7850
|
+
return !isNaN(ifModDate.getTime()) && !isNaN(lastModDate.getTime()) && ifModDate >= lastModDate;
|
|
7851
|
+
}
|
|
7852
|
+
return false;
|
|
7853
|
+
}
|
|
7854
|
+
createRevalidationRequest(request) {
|
|
7855
|
+
const headers = new Headers(request.headers);
|
|
7856
|
+
headers.set("X-Cache-Bypass", "revalidation");
|
|
7857
|
+
headers.delete("If-None-Match");
|
|
7858
|
+
headers.delete("If-Modified-Since");
|
|
7859
|
+
headers.delete("Cache-Control");
|
|
7860
|
+
headers.delete("Pragma");
|
|
7861
|
+
return new Request(request.url, {
|
|
7862
|
+
method: "GET",
|
|
7863
|
+
headers
|
|
7864
|
+
});
|
|
7865
|
+
}
|
|
7785
7866
|
async put(request, response) {
|
|
7786
7867
|
const trace = createTraceId();
|
|
7787
7868
|
if (request.method !== "GET" || !response.ok) {
|
|
@@ -7797,17 +7878,22 @@ var WorkerHtmlCache = class {
|
|
|
7797
7878
|
try {
|
|
7798
7879
|
const cache = await caches.open(CACHE_NAME2 + this.epoch);
|
|
7799
7880
|
const cacheKey = this.buildCacheKey(request);
|
|
7881
|
+
await cache.delete(cacheKey);
|
|
7800
7882
|
const ttl = this.getTTLForRequest(request);
|
|
7801
|
-
const swr =
|
|
7883
|
+
const swr = this.getSWRForRequest(request);
|
|
7802
7884
|
const headers = new Headers(response.headers);
|
|
7803
7885
|
const existingCacheControl = response.headers.get("Cache-Control");
|
|
7804
7886
|
if (!existingCacheControl || existingCacheControl === "public") {
|
|
7805
7887
|
const internalMaxAge = ttl + swr;
|
|
7806
7888
|
headers.set("Cache-Control", `public, max-age=${internalMaxAge}`);
|
|
7807
7889
|
}
|
|
7808
|
-
|
|
7890
|
+
const cacheTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
7891
|
+
headers.set("X-Cache-Time", cacheTime);
|
|
7809
7892
|
headers.set("X-Original-TTL", ttl.toString());
|
|
7810
7893
|
headers.set("X-Original-SWR", swr.toString());
|
|
7894
|
+
if (!headers.get("Last-Modified")) {
|
|
7895
|
+
headers.set("Last-Modified", new Date(cacheTime).toUTCString());
|
|
7896
|
+
}
|
|
7811
7897
|
const cacheableResponse = new Response(response.body, {
|
|
7812
7898
|
status: response.status,
|
|
7813
7899
|
statusText: response.statusText,
|
|
@@ -7819,28 +7905,32 @@ var WorkerHtmlCache = class {
|
|
|
7819
7905
|
logger.warn("[SDK Html-cache] no put support", { trace });
|
|
7820
7906
|
}
|
|
7821
7907
|
}
|
|
7822
|
-
/**
|
|
7823
|
-
* Build client response with correct headers
|
|
7824
|
-
*/
|
|
7825
7908
|
buildClientResponse(cachedResponse, ttl, swr, isStale, age) {
|
|
7826
7909
|
const headers = new Headers(cachedResponse.headers);
|
|
7827
7910
|
headers.set(
|
|
7828
7911
|
"Cache-Control",
|
|
7829
7912
|
`public, max-age=${ttl}, stale-while-revalidate=${swr}`
|
|
7830
7913
|
);
|
|
7914
|
+
headers.set(
|
|
7915
|
+
"Cloudflare-CDN-Cache-Control",
|
|
7916
|
+
`public, s-maxage=${ttl}, stale-while-revalidate=${swr}, stale-if-error=60`
|
|
7917
|
+
);
|
|
7918
|
+
const cacheTime = headers.get("X-Cache-Time");
|
|
7919
|
+
if (cacheTime) {
|
|
7920
|
+
const lastModified = new Date(cacheTime).toUTCString();
|
|
7921
|
+
headers.set("Last-Modified", lastModified);
|
|
7922
|
+
}
|
|
7831
7923
|
headers.set("X-Cache-Status", isStale ? "STALE" : "HIT");
|
|
7832
7924
|
headers.set("X-Cache-Age", Math.floor(age).toString());
|
|
7833
7925
|
headers.delete("X-Original-TTL");
|
|
7834
7926
|
headers.delete("X-Original-SWR");
|
|
7927
|
+
headers.delete("X-Cache-Time");
|
|
7835
7928
|
return new Response(cachedResponse.body, {
|
|
7836
7929
|
status: cachedResponse.status,
|
|
7837
7930
|
statusText: cachedResponse.statusText,
|
|
7838
7931
|
headers
|
|
7839
7932
|
});
|
|
7840
7933
|
}
|
|
7841
|
-
/**
|
|
7842
|
-
* Build cache key from request using two-level structure
|
|
7843
|
-
*/
|
|
7844
7934
|
buildCacheKey(request) {
|
|
7845
7935
|
const url = new URL(request.url);
|
|
7846
7936
|
const versionHash = this.generateVersionHash(request.headers);
|
|
@@ -7856,22 +7946,11 @@ var WorkerHtmlCache = class {
|
|
|
7856
7946
|
headers: sanitizedHeaders
|
|
7857
7947
|
});
|
|
7858
7948
|
}
|
|
7859
|
-
/**
|
|
7860
|
-
* Sanitize headers for cache operations - minimal whitelist approach
|
|
7861
|
-
*/
|
|
7862
7949
|
sanitizeHeaders(originalHeaders) {
|
|
7863
7950
|
const CACHE_RELEVANT_HEADERS = [
|
|
7864
7951
|
// Content negotiation (affects response format)
|
|
7865
7952
|
"accept",
|
|
7866
|
-
"accept-
|
|
7867
|
-
"accept-language",
|
|
7868
|
-
// Cache control directives from client/proxy
|
|
7869
|
-
"cache-control",
|
|
7870
|
-
"pragma",
|
|
7871
|
-
// Legacy cache control
|
|
7872
|
-
// Conditional request headers (for 304 responses)
|
|
7873
|
-
"if-none-match",
|
|
7874
|
-
"if-modified-since"
|
|
7953
|
+
"accept-language"
|
|
7875
7954
|
];
|
|
7876
7955
|
const sanitized = new Headers();
|
|
7877
7956
|
CACHE_RELEVANT_HEADERS.forEach((header) => {
|
|
@@ -7882,15 +7961,13 @@ var WorkerHtmlCache = class {
|
|
|
7882
7961
|
});
|
|
7883
7962
|
return sanitized;
|
|
7884
7963
|
}
|
|
7885
|
-
/**
|
|
7886
|
-
* Generate version hash from headers and cookies
|
|
7887
|
-
*/
|
|
7888
7964
|
generateVersionHash(headers) {
|
|
7889
7965
|
const swellData = this.extractSwellData(headers);
|
|
7890
7966
|
const versionFactors = {
|
|
7891
7967
|
store: headers.get("swell-storefront-id") || "",
|
|
7892
7968
|
auth: headers.get("swell-access-token") || "",
|
|
7893
7969
|
theme: headers.get("swell-theme-version-hash") || "",
|
|
7970
|
+
modified: headers.get("swell-cache-modified") || "",
|
|
7894
7971
|
currency: swellData["swell-currency"] || "USD",
|
|
7895
7972
|
locale: headers.get("x-locale") || headers.get("accept-language")?.split(",")[0] || "default",
|
|
7896
7973
|
context: headers.get("swell-storefront-context"),
|
|
@@ -7898,9 +7975,6 @@ var WorkerHtmlCache = class {
|
|
|
7898
7975
|
};
|
|
7899
7976
|
return md5(JSON.stringify(versionFactors));
|
|
7900
7977
|
}
|
|
7901
|
-
/**
|
|
7902
|
-
* Extract swell-data from cookies
|
|
7903
|
-
*/
|
|
7904
7978
|
extractSwellData(headers) {
|
|
7905
7979
|
const cookie = headers.get("cookie");
|
|
7906
7980
|
if (!cookie) return {};
|
|
@@ -7936,31 +8010,53 @@ var WorkerHtmlCache = class {
|
|
|
7936
8010
|
if (!contentType?.includes("text/html")) {
|
|
7937
8011
|
return false;
|
|
7938
8012
|
}
|
|
8013
|
+
if (response.headers.get("set-cookie")) {
|
|
8014
|
+
return false;
|
|
8015
|
+
}
|
|
7939
8016
|
const cacheControl = response.headers.get("cache-control");
|
|
7940
8017
|
if (cacheControl?.includes("no-store") || cacheControl?.includes("private")) {
|
|
7941
8018
|
return false;
|
|
7942
8019
|
}
|
|
7943
8020
|
return true;
|
|
7944
8021
|
}
|
|
8022
|
+
getDeploymentMode(headers) {
|
|
8023
|
+
const mode = headers.get("swell-deployment-mode");
|
|
8024
|
+
if (mode === "preview" || mode === "editor") {
|
|
8025
|
+
return mode;
|
|
8026
|
+
}
|
|
8027
|
+
return "live";
|
|
8028
|
+
}
|
|
7945
8029
|
getTTLForRequest(request) {
|
|
7946
8030
|
const url = new URL(request.url);
|
|
7947
8031
|
const path = url.pathname;
|
|
8032
|
+
const mode = this.getDeploymentMode(request.headers);
|
|
8033
|
+
if (mode === "editor") {
|
|
8034
|
+
return 0;
|
|
8035
|
+
}
|
|
8036
|
+
const config = mode === "preview" ? TTL_CONFIG.PREVIEW : TTL_CONFIG.LIVE;
|
|
7948
8037
|
if (path === "/") {
|
|
7949
|
-
return
|
|
8038
|
+
return config.HOME;
|
|
7950
8039
|
}
|
|
7951
8040
|
if (path.startsWith("/products/")) {
|
|
7952
|
-
return
|
|
8041
|
+
return config.PRODUCT;
|
|
7953
8042
|
}
|
|
7954
8043
|
if (path.startsWith("/categories/")) {
|
|
7955
|
-
return
|
|
8044
|
+
return config.COLLECTION;
|
|
7956
8045
|
}
|
|
7957
8046
|
if (path.startsWith("/pages/")) {
|
|
7958
|
-
return
|
|
8047
|
+
return config.PAGE;
|
|
7959
8048
|
}
|
|
7960
8049
|
if (path.startsWith("/blogs/")) {
|
|
7961
|
-
return
|
|
8050
|
+
return config.BLOG;
|
|
7962
8051
|
}
|
|
7963
|
-
return
|
|
8052
|
+
return config.DEFAULT;
|
|
8053
|
+
}
|
|
8054
|
+
getSWRForRequest(request) {
|
|
8055
|
+
const mode = this.getDeploymentMode(request.headers);
|
|
8056
|
+
if (mode === "editor") {
|
|
8057
|
+
return 0;
|
|
8058
|
+
}
|
|
8059
|
+
return mode === "preview" ? TTL_CONFIG.PREVIEW.SWR : TTL_CONFIG.LIVE.SWR;
|
|
7964
8060
|
}
|
|
7965
8061
|
getResponseAge(response) {
|
|
7966
8062
|
const cacheTime = response.headers.get("X-Cache-Time");
|
|
@@ -7974,31 +8070,6 @@ var WorkerHtmlCache = class {
|
|
|
7974
8070
|
const age = (Date.now() - cacheDate.getTime()) / 1e3;
|
|
7975
8071
|
return Math.max(0, age);
|
|
7976
8072
|
}
|
|
7977
|
-
getMaxAge(response) {
|
|
7978
|
-
const cacheControl = response.headers.get("Cache-Control");
|
|
7979
|
-
if (!cacheControl) {
|
|
7980
|
-
return TTL_CONFIG.DEFAULT;
|
|
7981
|
-
}
|
|
7982
|
-
const maxAgeMatch = cacheControl.match(/max-age=(\d+)/);
|
|
7983
|
-
if (maxAgeMatch) {
|
|
7984
|
-
return parseInt(maxAgeMatch[1], 10);
|
|
7985
|
-
}
|
|
7986
|
-
return TTL_CONFIG.DEFAULT;
|
|
7987
|
-
}
|
|
7988
|
-
getStaleWindow(response) {
|
|
7989
|
-
const cacheControl = response.headers.get("Cache-Control");
|
|
7990
|
-
if (!cacheControl) {
|
|
7991
|
-
return TTL_CONFIG.DEFAULT_SWR;
|
|
7992
|
-
}
|
|
7993
|
-
const swrMatch = cacheControl.match(/stale-while-revalidate=(\d+)/);
|
|
7994
|
-
if (swrMatch) {
|
|
7995
|
-
return parseInt(swrMatch[1], 10);
|
|
7996
|
-
}
|
|
7997
|
-
return TTL_CONFIG.DEFAULT_SWR;
|
|
7998
|
-
}
|
|
7999
|
-
/**
|
|
8000
|
-
* Normalize search params for cache key
|
|
8001
|
-
*/
|
|
8002
8073
|
normalizeSearchParams(searchParams) {
|
|
8003
8074
|
const ignoredParams = [
|
|
8004
8075
|
"utm_source",
|