@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.cjs
CHANGED
|
@@ -860,18 +860,31 @@ var StorefrontResource = class {
|
|
|
860
860
|
return this._compatibilityProps[prop];
|
|
861
861
|
}
|
|
862
862
|
};
|
|
863
|
+
var RESOURCE_CLONE_PROPS = Object.freeze([
|
|
864
|
+
"_defaultGetter",
|
|
865
|
+
"_getResourceObject",
|
|
866
|
+
"_collection",
|
|
867
|
+
"_swell",
|
|
868
|
+
"_query",
|
|
869
|
+
"_params",
|
|
870
|
+
"_id",
|
|
871
|
+
"_resourceName"
|
|
872
|
+
]);
|
|
863
873
|
function cloneStorefrontResource(input) {
|
|
864
|
-
const resourceName = input._resourceName;
|
|
874
|
+
const resourceName = input._resourceName || input.constructor?.name;
|
|
865
875
|
const ClonedClass = class extends StorefrontResource {
|
|
866
876
|
};
|
|
867
877
|
Object.defineProperty(ClonedClass, "name", {
|
|
868
878
|
value: resourceName
|
|
869
879
|
});
|
|
870
880
|
const clone = new ClonedClass(input._getter);
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
881
|
+
for (const key of RESOURCE_CLONE_PROPS) {
|
|
882
|
+
if (input[key] !== void 0) {
|
|
883
|
+
Object.defineProperty(clone, key, {
|
|
884
|
+
value: input[key]
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
}
|
|
875
888
|
return clone;
|
|
876
889
|
}
|
|
877
890
|
var SwellStorefrontResource = class extends StorefrontResource {
|
|
@@ -890,7 +903,7 @@ var SwellStorefrontResource = class extends StorefrontResource {
|
|
|
890
903
|
_getProxy() {
|
|
891
904
|
return super._getProxy();
|
|
892
905
|
}
|
|
893
|
-
|
|
906
|
+
_getResourceObject() {
|
|
894
907
|
const { _swell, _collection } = this;
|
|
895
908
|
this._resource = (_swell?.storefront)[_collection];
|
|
896
909
|
if (_swell && _collection.startsWith("content/")) {
|
|
@@ -947,7 +960,7 @@ var SwellStorefrontCollection = class _SwellStorefrontCollection extends SwellSt
|
|
|
947
960
|
return properQuery;
|
|
948
961
|
}
|
|
949
962
|
_defaultGetter() {
|
|
950
|
-
const resource = this.
|
|
963
|
+
const resource = this._getResourceObject();
|
|
951
964
|
async function defaultGetter() {
|
|
952
965
|
return resource.list(this._query);
|
|
953
966
|
}
|
|
@@ -1074,7 +1087,7 @@ var SwellStorefrontRecord = class extends SwellStorefrontResource {
|
|
|
1074
1087
|
return super._getProxy();
|
|
1075
1088
|
}
|
|
1076
1089
|
_defaultGetter() {
|
|
1077
|
-
const resource = this.
|
|
1090
|
+
const resource = this._getResourceObject();
|
|
1078
1091
|
async function defaultGetter() {
|
|
1079
1092
|
return resource.get(this._id, this._query);
|
|
1080
1093
|
}
|
|
@@ -1133,7 +1146,7 @@ var SwellStorefrontSingleton = class extends SwellStorefrontResource {
|
|
|
1133
1146
|
_collection,
|
|
1134
1147
|
_swell: { storefrontContext }
|
|
1135
1148
|
} = this;
|
|
1136
|
-
const resource = this.
|
|
1149
|
+
const resource = this._getResourceObject();
|
|
1137
1150
|
async function defaultGetter() {
|
|
1138
1151
|
if (storefrontContext[_collection] !== void 0) {
|
|
1139
1152
|
return storefrontContext[_collection];
|
|
@@ -7858,20 +7871,38 @@ var WorkerCacheProxy = class {
|
|
|
7858
7871
|
var CACHE_NAME2 = "swell-html-v1";
|
|
7859
7872
|
var CACHE_KEY_ORIGIN2 = "https://cache.swell.store";
|
|
7860
7873
|
var TTL_CONFIG = {
|
|
7861
|
-
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
|
|
7865
|
-
|
|
7866
|
-
|
|
7867
|
-
|
|
7868
|
-
|
|
7869
|
-
|
|
7870
|
-
|
|
7871
|
-
|
|
7872
|
-
|
|
7873
|
-
|
|
7874
|
-
|
|
7874
|
+
LIVE: {
|
|
7875
|
+
DEFAULT: 300,
|
|
7876
|
+
// 5 minutes
|
|
7877
|
+
HOME: 300,
|
|
7878
|
+
// 5 minutes
|
|
7879
|
+
PRODUCT: 600,
|
|
7880
|
+
// 10 minutes
|
|
7881
|
+
COLLECTION: 900,
|
|
7882
|
+
// 15 minutes
|
|
7883
|
+
PAGE: 3600,
|
|
7884
|
+
// 1 hour
|
|
7885
|
+
BLOG: 1800,
|
|
7886
|
+
// 30 minutes
|
|
7887
|
+
SWR: 3600
|
|
7888
|
+
// 1 hour stale-while-revalidate
|
|
7889
|
+
},
|
|
7890
|
+
PREVIEW: {
|
|
7891
|
+
DEFAULT: 5,
|
|
7892
|
+
// 1 minute - faster updates in preview
|
|
7893
|
+
HOME: 5,
|
|
7894
|
+
// 1 minute
|
|
7895
|
+
PRODUCT: 5,
|
|
7896
|
+
// 2 minutes
|
|
7897
|
+
COLLECTION: 5,
|
|
7898
|
+
// 3 minutes
|
|
7899
|
+
PAGE: 5,
|
|
7900
|
+
// 5 minutes
|
|
7901
|
+
BLOG: 5,
|
|
7902
|
+
// 5 minutes
|
|
7903
|
+
SWR: 600
|
|
7904
|
+
// 10 minutes stale-while-revalidate
|
|
7905
|
+
}
|
|
7875
7906
|
};
|
|
7876
7907
|
var WorkerHtmlCache = class {
|
|
7877
7908
|
epoch;
|
|
@@ -7898,7 +7929,7 @@ var WorkerHtmlCache = class {
|
|
|
7898
7929
|
}
|
|
7899
7930
|
const age = this.getResponseAge(cached);
|
|
7900
7931
|
const ttl = parseInt(cached.headers.get("X-Original-TTL") || "") || this.getTTLForRequest(request);
|
|
7901
|
-
const swr = parseInt(cached.headers.get("X-Original-SWR") || "") ||
|
|
7932
|
+
const swr = parseInt(cached.headers.get("X-Original-SWR") || "") || this.getSWRForRequest(request);
|
|
7902
7933
|
const isStale = age >= ttl;
|
|
7903
7934
|
const isExpired = age >= ttl + swr;
|
|
7904
7935
|
if (!isExpired) {
|
|
@@ -7929,6 +7960,56 @@ var WorkerHtmlCache = class {
|
|
|
7929
7960
|
return null;
|
|
7930
7961
|
}
|
|
7931
7962
|
}
|
|
7963
|
+
// 304 support
|
|
7964
|
+
async getWithConditionals(request) {
|
|
7965
|
+
const result = await this.get(request);
|
|
7966
|
+
if (!result?.found || result.stale) {
|
|
7967
|
+
return result;
|
|
7968
|
+
}
|
|
7969
|
+
const ifModifiedSince = request.headers.get("If-Modified-Since");
|
|
7970
|
+
const ifNoneMatch = request.headers.get("If-None-Match");
|
|
7971
|
+
if ((ifModifiedSince || ifNoneMatch) && result.response) {
|
|
7972
|
+
const lastModified = result.response.headers.get("Last-Modified");
|
|
7973
|
+
const etag = result.response.headers.get("ETag");
|
|
7974
|
+
if (this.checkNotModified(ifModifiedSince, ifNoneMatch, lastModified, etag)) {
|
|
7975
|
+
result.notModified = true;
|
|
7976
|
+
result.conditional304 = new Response(null, {
|
|
7977
|
+
status: 304,
|
|
7978
|
+
headers: {
|
|
7979
|
+
"Last-Modified": lastModified || "",
|
|
7980
|
+
ETag: etag || "",
|
|
7981
|
+
"Cache-Control": result.response.headers.get("Cache-Control") || "",
|
|
7982
|
+
"Cloudflare-CDN-Cache-Control": result.response.headers.get("Cloudflare-CDN-Cache-Control") || "",
|
|
7983
|
+
"X-Cache-Status": "HIT-304"
|
|
7984
|
+
}
|
|
7985
|
+
});
|
|
7986
|
+
}
|
|
7987
|
+
}
|
|
7988
|
+
return result;
|
|
7989
|
+
}
|
|
7990
|
+
checkNotModified(ifModifiedSince, ifNoneMatch, lastModified, etag) {
|
|
7991
|
+
if (ifNoneMatch && etag) {
|
|
7992
|
+
return ifNoneMatch === etag;
|
|
7993
|
+
}
|
|
7994
|
+
if (ifModifiedSince && lastModified) {
|
|
7995
|
+
const ifModDate = new Date(ifModifiedSince);
|
|
7996
|
+
const lastModDate = new Date(lastModified);
|
|
7997
|
+
return !isNaN(ifModDate.getTime()) && !isNaN(lastModDate.getTime()) && ifModDate >= lastModDate;
|
|
7998
|
+
}
|
|
7999
|
+
return false;
|
|
8000
|
+
}
|
|
8001
|
+
createRevalidationRequest(request) {
|
|
8002
|
+
const headers = new Headers(request.headers);
|
|
8003
|
+
headers.set("X-Cache-Bypass", "revalidation");
|
|
8004
|
+
headers.delete("If-None-Match");
|
|
8005
|
+
headers.delete("If-Modified-Since");
|
|
8006
|
+
headers.delete("Cache-Control");
|
|
8007
|
+
headers.delete("Pragma");
|
|
8008
|
+
return new Request(request.url, {
|
|
8009
|
+
method: "GET",
|
|
8010
|
+
headers
|
|
8011
|
+
});
|
|
8012
|
+
}
|
|
7932
8013
|
async put(request, response) {
|
|
7933
8014
|
const trace = createTraceId();
|
|
7934
8015
|
if (request.method !== "GET" || !response.ok) {
|
|
@@ -7944,17 +8025,22 @@ var WorkerHtmlCache = class {
|
|
|
7944
8025
|
try {
|
|
7945
8026
|
const cache = await caches.open(CACHE_NAME2 + this.epoch);
|
|
7946
8027
|
const cacheKey = this.buildCacheKey(request);
|
|
8028
|
+
await cache.delete(cacheKey);
|
|
7947
8029
|
const ttl = this.getTTLForRequest(request);
|
|
7948
|
-
const swr =
|
|
8030
|
+
const swr = this.getSWRForRequest(request);
|
|
7949
8031
|
const headers = new Headers(response.headers);
|
|
7950
8032
|
const existingCacheControl = response.headers.get("Cache-Control");
|
|
7951
8033
|
if (!existingCacheControl || existingCacheControl === "public") {
|
|
7952
8034
|
const internalMaxAge = ttl + swr;
|
|
7953
8035
|
headers.set("Cache-Control", `public, max-age=${internalMaxAge}`);
|
|
7954
8036
|
}
|
|
7955
|
-
|
|
8037
|
+
const cacheTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
8038
|
+
headers.set("X-Cache-Time", cacheTime);
|
|
7956
8039
|
headers.set("X-Original-TTL", ttl.toString());
|
|
7957
8040
|
headers.set("X-Original-SWR", swr.toString());
|
|
8041
|
+
if (!headers.get("Last-Modified")) {
|
|
8042
|
+
headers.set("Last-Modified", new Date(cacheTime).toUTCString());
|
|
8043
|
+
}
|
|
7958
8044
|
const cacheableResponse = new Response(response.body, {
|
|
7959
8045
|
status: response.status,
|
|
7960
8046
|
statusText: response.statusText,
|
|
@@ -7966,28 +8052,32 @@ var WorkerHtmlCache = class {
|
|
|
7966
8052
|
logger.warn("[SDK Html-cache] no put support", { trace });
|
|
7967
8053
|
}
|
|
7968
8054
|
}
|
|
7969
|
-
/**
|
|
7970
|
-
* Build client response with correct headers
|
|
7971
|
-
*/
|
|
7972
8055
|
buildClientResponse(cachedResponse, ttl, swr, isStale, age) {
|
|
7973
8056
|
const headers = new Headers(cachedResponse.headers);
|
|
7974
8057
|
headers.set(
|
|
7975
8058
|
"Cache-Control",
|
|
7976
8059
|
`public, max-age=${ttl}, stale-while-revalidate=${swr}`
|
|
7977
8060
|
);
|
|
8061
|
+
headers.set(
|
|
8062
|
+
"Cloudflare-CDN-Cache-Control",
|
|
8063
|
+
`public, s-maxage=${ttl}, stale-while-revalidate=${swr}, stale-if-error=60`
|
|
8064
|
+
);
|
|
8065
|
+
const cacheTime = headers.get("X-Cache-Time");
|
|
8066
|
+
if (cacheTime) {
|
|
8067
|
+
const lastModified = new Date(cacheTime).toUTCString();
|
|
8068
|
+
headers.set("Last-Modified", lastModified);
|
|
8069
|
+
}
|
|
7978
8070
|
headers.set("X-Cache-Status", isStale ? "STALE" : "HIT");
|
|
7979
8071
|
headers.set("X-Cache-Age", Math.floor(age).toString());
|
|
7980
8072
|
headers.delete("X-Original-TTL");
|
|
7981
8073
|
headers.delete("X-Original-SWR");
|
|
8074
|
+
headers.delete("X-Cache-Time");
|
|
7982
8075
|
return new Response(cachedResponse.body, {
|
|
7983
8076
|
status: cachedResponse.status,
|
|
7984
8077
|
statusText: cachedResponse.statusText,
|
|
7985
8078
|
headers
|
|
7986
8079
|
});
|
|
7987
8080
|
}
|
|
7988
|
-
/**
|
|
7989
|
-
* Build cache key from request using two-level structure
|
|
7990
|
-
*/
|
|
7991
8081
|
buildCacheKey(request) {
|
|
7992
8082
|
const url = new URL(request.url);
|
|
7993
8083
|
const versionHash = this.generateVersionHash(request.headers);
|
|
@@ -8003,22 +8093,11 @@ var WorkerHtmlCache = class {
|
|
|
8003
8093
|
headers: sanitizedHeaders
|
|
8004
8094
|
});
|
|
8005
8095
|
}
|
|
8006
|
-
/**
|
|
8007
|
-
* Sanitize headers for cache operations - minimal whitelist approach
|
|
8008
|
-
*/
|
|
8009
8096
|
sanitizeHeaders(originalHeaders) {
|
|
8010
8097
|
const CACHE_RELEVANT_HEADERS = [
|
|
8011
8098
|
// Content negotiation (affects response format)
|
|
8012
8099
|
"accept",
|
|
8013
|
-
"accept-
|
|
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"
|
|
8100
|
+
"accept-language"
|
|
8022
8101
|
];
|
|
8023
8102
|
const sanitized = new Headers();
|
|
8024
8103
|
CACHE_RELEVANT_HEADERS.forEach((header) => {
|
|
@@ -8029,15 +8108,13 @@ var WorkerHtmlCache = class {
|
|
|
8029
8108
|
});
|
|
8030
8109
|
return sanitized;
|
|
8031
8110
|
}
|
|
8032
|
-
/**
|
|
8033
|
-
* Generate version hash from headers and cookies
|
|
8034
|
-
*/
|
|
8035
8111
|
generateVersionHash(headers) {
|
|
8036
8112
|
const swellData = this.extractSwellData(headers);
|
|
8037
8113
|
const versionFactors = {
|
|
8038
8114
|
store: headers.get("swell-storefront-id") || "",
|
|
8039
8115
|
auth: headers.get("swell-access-token") || "",
|
|
8040
8116
|
theme: headers.get("swell-theme-version-hash") || "",
|
|
8117
|
+
modified: headers.get("swell-cache-modified") || "",
|
|
8041
8118
|
currency: swellData["swell-currency"] || "USD",
|
|
8042
8119
|
locale: headers.get("x-locale") || headers.get("accept-language")?.split(",")[0] || "default",
|
|
8043
8120
|
context: headers.get("swell-storefront-context"),
|
|
@@ -8045,9 +8122,6 @@ var WorkerHtmlCache = class {
|
|
|
8045
8122
|
};
|
|
8046
8123
|
return md5(JSON.stringify(versionFactors));
|
|
8047
8124
|
}
|
|
8048
|
-
/**
|
|
8049
|
-
* Extract swell-data from cookies
|
|
8050
|
-
*/
|
|
8051
8125
|
extractSwellData(headers) {
|
|
8052
8126
|
const cookie = headers.get("cookie");
|
|
8053
8127
|
if (!cookie) return {};
|
|
@@ -8083,31 +8157,53 @@ var WorkerHtmlCache = class {
|
|
|
8083
8157
|
if (!contentType?.includes("text/html")) {
|
|
8084
8158
|
return false;
|
|
8085
8159
|
}
|
|
8160
|
+
if (response.headers.get("set-cookie")) {
|
|
8161
|
+
return false;
|
|
8162
|
+
}
|
|
8086
8163
|
const cacheControl = response.headers.get("cache-control");
|
|
8087
8164
|
if (cacheControl?.includes("no-store") || cacheControl?.includes("private")) {
|
|
8088
8165
|
return false;
|
|
8089
8166
|
}
|
|
8090
8167
|
return true;
|
|
8091
8168
|
}
|
|
8169
|
+
getDeploymentMode(headers) {
|
|
8170
|
+
const mode = headers.get("swell-deployment-mode");
|
|
8171
|
+
if (mode === "preview" || mode === "editor") {
|
|
8172
|
+
return mode;
|
|
8173
|
+
}
|
|
8174
|
+
return "live";
|
|
8175
|
+
}
|
|
8092
8176
|
getTTLForRequest(request) {
|
|
8093
8177
|
const url = new URL(request.url);
|
|
8094
8178
|
const path = url.pathname;
|
|
8179
|
+
const mode = this.getDeploymentMode(request.headers);
|
|
8180
|
+
if (mode === "editor") {
|
|
8181
|
+
return 0;
|
|
8182
|
+
}
|
|
8183
|
+
const config = mode === "preview" ? TTL_CONFIG.PREVIEW : TTL_CONFIG.LIVE;
|
|
8095
8184
|
if (path === "/") {
|
|
8096
|
-
return
|
|
8185
|
+
return config.HOME;
|
|
8097
8186
|
}
|
|
8098
8187
|
if (path.startsWith("/products/")) {
|
|
8099
|
-
return
|
|
8188
|
+
return config.PRODUCT;
|
|
8100
8189
|
}
|
|
8101
8190
|
if (path.startsWith("/categories/")) {
|
|
8102
|
-
return
|
|
8191
|
+
return config.COLLECTION;
|
|
8103
8192
|
}
|
|
8104
8193
|
if (path.startsWith("/pages/")) {
|
|
8105
|
-
return
|
|
8194
|
+
return config.PAGE;
|
|
8106
8195
|
}
|
|
8107
8196
|
if (path.startsWith("/blogs/")) {
|
|
8108
|
-
return
|
|
8197
|
+
return config.BLOG;
|
|
8109
8198
|
}
|
|
8110
|
-
return
|
|
8199
|
+
return config.DEFAULT;
|
|
8200
|
+
}
|
|
8201
|
+
getSWRForRequest(request) {
|
|
8202
|
+
const mode = this.getDeploymentMode(request.headers);
|
|
8203
|
+
if (mode === "editor") {
|
|
8204
|
+
return 0;
|
|
8205
|
+
}
|
|
8206
|
+
return mode === "preview" ? TTL_CONFIG.PREVIEW.SWR : TTL_CONFIG.LIVE.SWR;
|
|
8111
8207
|
}
|
|
8112
8208
|
getResponseAge(response) {
|
|
8113
8209
|
const cacheTime = response.headers.get("X-Cache-Time");
|
|
@@ -8121,31 +8217,6 @@ var WorkerHtmlCache = class {
|
|
|
8121
8217
|
const age = (Date.now() - cacheDate.getTime()) / 1e3;
|
|
8122
8218
|
return Math.max(0, age);
|
|
8123
8219
|
}
|
|
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
8220
|
normalizeSearchParams(searchParams) {
|
|
8150
8221
|
const ignoredParams = [
|
|
8151
8222
|
"utm_source",
|