@swell/apps-sdk 1.0.151 → 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 +472 -80
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +470 -80
- package/dist/index.js.map +4 -4
- package/dist/index.mjs +471 -80
- package/dist/index.mjs.map +4 -4
- package/dist/src/cache/cache-api-stub.d.ts +25 -0
- package/dist/src/cache/index.d.ts +2 -0
- package/dist/src/cache/worker-html-cache.d.ts +30 -0
- package/dist/src/index.d.ts +3 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -41,72 +41,6 @@
|
|
|
41
41
|
var import_keyv = __require("keyv");
|
|
42
42
|
var import_cache_manager = __require("cache-manager");
|
|
43
43
|
|
|
44
|
-
// src/cache/cf-worker-kv-keyv-adapter.ts
|
|
45
|
-
var CFWorkerKVKeyvAdapter = class {
|
|
46
|
-
store;
|
|
47
|
-
namespace;
|
|
48
|
-
// magically passed in from Keyv
|
|
49
|
-
opts;
|
|
50
|
-
constructor(store) {
|
|
51
|
-
this.store = store;
|
|
52
|
-
this.opts = null;
|
|
53
|
-
this.namespace = "dummy";
|
|
54
|
-
}
|
|
55
|
-
async has(key) {
|
|
56
|
-
const stream = await this.store.get(key, "stream");
|
|
57
|
-
if (stream !== null) {
|
|
58
|
-
await stream.cancel();
|
|
59
|
-
return true;
|
|
60
|
-
}
|
|
61
|
-
return false;
|
|
62
|
-
}
|
|
63
|
-
async get(key) {
|
|
64
|
-
const value = await this.store.get(key);
|
|
65
|
-
return value !== null ? value : void 0;
|
|
66
|
-
}
|
|
67
|
-
set(key, value, ttl) {
|
|
68
|
-
if (typeof ttl === "number") {
|
|
69
|
-
ttl = Math.max(60, ttl / 1e3);
|
|
70
|
-
}
|
|
71
|
-
return this.store.put(key, value, { expirationTtl: ttl });
|
|
72
|
-
}
|
|
73
|
-
async delete(key) {
|
|
74
|
-
await this.store.delete(key);
|
|
75
|
-
return true;
|
|
76
|
-
}
|
|
77
|
-
async clear() {
|
|
78
|
-
let cursor = "";
|
|
79
|
-
let complete = false;
|
|
80
|
-
const prefix = `${this.namespace}:`;
|
|
81
|
-
do {
|
|
82
|
-
const response = await this.store.list({
|
|
83
|
-
prefix,
|
|
84
|
-
cursor: cursor || void 0
|
|
85
|
-
});
|
|
86
|
-
cursor = response.cursor ?? "";
|
|
87
|
-
complete = response.list_complete;
|
|
88
|
-
if (response.keys.length > 0) {
|
|
89
|
-
await Promise.all(
|
|
90
|
-
response.keys.map((key) => {
|
|
91
|
-
return this.store.delete(key.name);
|
|
92
|
-
})
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
} while (!complete);
|
|
96
|
-
}
|
|
97
|
-
on(_event, _listener) {
|
|
98
|
-
return this;
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
// src/utils/index.ts
|
|
103
|
-
var import_qs = __toESM(__require("qs"), 1);
|
|
104
|
-
var import_lodash_es3 = __require("lodash-es");
|
|
105
|
-
var import_json52 = __toESM(__require("json5"), 1);
|
|
106
|
-
|
|
107
|
-
// src/resources.ts
|
|
108
|
-
var import_lodash_es2 = __require("lodash-es");
|
|
109
|
-
|
|
110
44
|
// src/utils/logger.ts
|
|
111
45
|
var logLevels = {
|
|
112
46
|
error: 0,
|
|
@@ -198,6 +132,80 @@
|
|
|
198
132
|
return (hash >>> 0).toString(16);
|
|
199
133
|
}
|
|
200
134
|
|
|
135
|
+
// src/cache/cf-worker-kv-keyv-adapter.ts
|
|
136
|
+
var CFWorkerKVKeyvAdapter = class {
|
|
137
|
+
store;
|
|
138
|
+
namespace;
|
|
139
|
+
// magically passed in from Keyv
|
|
140
|
+
opts;
|
|
141
|
+
constructor(store) {
|
|
142
|
+
this.store = store;
|
|
143
|
+
this.opts = null;
|
|
144
|
+
this.namespace = "dummy";
|
|
145
|
+
}
|
|
146
|
+
async has(key) {
|
|
147
|
+
const stream = await this.store.get(key, "stream");
|
|
148
|
+
if (stream !== null) {
|
|
149
|
+
await stream.cancel();
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
async get(key) {
|
|
155
|
+
const trace = createTraceId();
|
|
156
|
+
logger.debug("[SDK] kv.get", { key, trace });
|
|
157
|
+
const value = await this.store.get(key);
|
|
158
|
+
const result = value !== null ? value : void 0;
|
|
159
|
+
logger.debug(`[SDK] kv.get ${value !== null ? "HIT" : "MISS"}`, {
|
|
160
|
+
key,
|
|
161
|
+
trace
|
|
162
|
+
});
|
|
163
|
+
return result;
|
|
164
|
+
}
|
|
165
|
+
set(key, value, ttl) {
|
|
166
|
+
if (typeof ttl === "number") {
|
|
167
|
+
ttl = Math.max(60, ttl / 1e3);
|
|
168
|
+
}
|
|
169
|
+
logger.debug("[SDK] kv.set", { key });
|
|
170
|
+
return this.store.put(key, value, { expirationTtl: ttl });
|
|
171
|
+
}
|
|
172
|
+
async delete(key) {
|
|
173
|
+
await this.store.delete(key);
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
async clear() {
|
|
177
|
+
let cursor = "";
|
|
178
|
+
let complete = false;
|
|
179
|
+
const prefix = `${this.namespace}:`;
|
|
180
|
+
do {
|
|
181
|
+
const response = await this.store.list({
|
|
182
|
+
prefix,
|
|
183
|
+
cursor: cursor || void 0
|
|
184
|
+
});
|
|
185
|
+
cursor = response.cursor ?? "";
|
|
186
|
+
complete = response.list_complete;
|
|
187
|
+
if (response.keys.length > 0) {
|
|
188
|
+
await Promise.all(
|
|
189
|
+
response.keys.map((key) => {
|
|
190
|
+
return this.store.delete(key.name);
|
|
191
|
+
})
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
} while (!complete);
|
|
195
|
+
}
|
|
196
|
+
on(_event, _listener) {
|
|
197
|
+
return this;
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
// src/utils/index.ts
|
|
202
|
+
var import_qs = __toESM(__require("qs"), 1);
|
|
203
|
+
var import_lodash_es3 = __require("lodash-es");
|
|
204
|
+
var import_json52 = __toESM(__require("json5"), 1);
|
|
205
|
+
|
|
206
|
+
// src/resources.ts
|
|
207
|
+
var import_lodash_es2 = __require("lodash-es");
|
|
208
|
+
|
|
201
209
|
// src/liquid/utils.ts
|
|
202
210
|
var import_liquidjs = __require("liquidjs");
|
|
203
211
|
|
|
@@ -841,6 +849,7 @@
|
|
|
841
849
|
this._collection,
|
|
842
850
|
this._query,
|
|
843
851
|
this._swell.queryParams,
|
|
852
|
+
// TODO: consider to exlcude
|
|
844
853
|
this._getterHash
|
|
845
854
|
],
|
|
846
855
|
getter,
|
|
@@ -969,6 +978,7 @@
|
|
|
969
978
|
this._id,
|
|
970
979
|
this._query,
|
|
971
980
|
this._swell.queryParams,
|
|
981
|
+
// TODO: consider to exlcude
|
|
972
982
|
this._getterHash
|
|
973
983
|
],
|
|
974
984
|
getter,
|
|
@@ -7197,8 +7207,6 @@
|
|
|
7197
7207
|
* This will always return the cached value immediately if exists
|
|
7198
7208
|
*/
|
|
7199
7209
|
async fetchSWR(key, fetchFn, ttl = DEFAULT_SWR_TTL, isCacheble = true) {
|
|
7200
|
-
const trace = createTraceId();
|
|
7201
|
-
logger.debug("[SDK] Cache fetch start", { key, trace });
|
|
7202
7210
|
const cacheValue = isCacheble ? await this.client.get(key) : void 0;
|
|
7203
7211
|
let promise = SWR_PROMISE_MAP.get(key);
|
|
7204
7212
|
if (promise === void 0) {
|
|
@@ -7206,7 +7214,6 @@
|
|
|
7206
7214
|
const isNull = value === null || value === void 0;
|
|
7207
7215
|
if (isCacheble) {
|
|
7208
7216
|
await this.client.set(key, isNull ? NULL_VALUE : value, ttl);
|
|
7209
|
-
logger.debug("[SDK] Cache update done", { key, trace });
|
|
7210
7217
|
}
|
|
7211
7218
|
return value;
|
|
7212
7219
|
}).finally(() => {
|
|
@@ -7218,12 +7225,9 @@
|
|
|
7218
7225
|
this.workerCtx.waitUntil(promise);
|
|
7219
7226
|
}
|
|
7220
7227
|
if (cacheValue !== void 0) {
|
|
7221
|
-
logger.debug("[SDK] Cache check done", { status: "HIT", key, trace });
|
|
7222
7228
|
return cacheValue === NULL_VALUE ? null : cacheValue;
|
|
7223
7229
|
}
|
|
7224
|
-
logger.debug("[SDK] Cache check done", { status: "MISS", key, trace });
|
|
7225
7230
|
const result = await promise;
|
|
7226
|
-
logger.debug("[SDK] Cache fetch end", { key, trace });
|
|
7227
7231
|
return result;
|
|
7228
7232
|
}
|
|
7229
7233
|
async get(key) {
|
|
@@ -7730,6 +7734,384 @@
|
|
|
7730
7734
|
}
|
|
7731
7735
|
};
|
|
7732
7736
|
|
|
7737
|
+
// src/cache/worker-html-cache.ts
|
|
7738
|
+
var CACHE_NAME2 = "swell-html-v1";
|
|
7739
|
+
var CACHE_KEY_ORIGIN2 = "https://cache.swell.store";
|
|
7740
|
+
var TTL_CONFIG = {
|
|
7741
|
+
LIVE: {
|
|
7742
|
+
DEFAULT: 300,
|
|
7743
|
+
// 5 minutes
|
|
7744
|
+
HOME: 300,
|
|
7745
|
+
// 5 minutes
|
|
7746
|
+
PRODUCT: 600,
|
|
7747
|
+
// 10 minutes
|
|
7748
|
+
COLLECTION: 900,
|
|
7749
|
+
// 15 minutes
|
|
7750
|
+
PAGE: 3600,
|
|
7751
|
+
// 1 hour
|
|
7752
|
+
BLOG: 1800,
|
|
7753
|
+
// 30 minutes
|
|
7754
|
+
SWR: 3600
|
|
7755
|
+
// 1 hour stale-while-revalidate
|
|
7756
|
+
},
|
|
7757
|
+
PREVIEW: {
|
|
7758
|
+
DEFAULT: 5,
|
|
7759
|
+
// 1 minute - faster updates in preview
|
|
7760
|
+
HOME: 5,
|
|
7761
|
+
// 1 minute
|
|
7762
|
+
PRODUCT: 5,
|
|
7763
|
+
// 2 minutes
|
|
7764
|
+
COLLECTION: 5,
|
|
7765
|
+
// 3 minutes
|
|
7766
|
+
PAGE: 5,
|
|
7767
|
+
// 5 minutes
|
|
7768
|
+
BLOG: 5,
|
|
7769
|
+
// 5 minutes
|
|
7770
|
+
SWR: 600
|
|
7771
|
+
// 10 minutes stale-while-revalidate
|
|
7772
|
+
}
|
|
7773
|
+
};
|
|
7774
|
+
var WorkerHtmlCache = class {
|
|
7775
|
+
epoch;
|
|
7776
|
+
constructor(epoch) {
|
|
7777
|
+
this.epoch = epoch;
|
|
7778
|
+
}
|
|
7779
|
+
async get(request) {
|
|
7780
|
+
const trace = createTraceId();
|
|
7781
|
+
if (request.method !== "GET") {
|
|
7782
|
+
logger.debug("[SDK Html-cache] non-cacheable", { trace });
|
|
7783
|
+
return { found: false, cacheable: false };
|
|
7784
|
+
}
|
|
7785
|
+
if (!this.isCacheable(request)) {
|
|
7786
|
+
logger.debug("[SDK Html-cache] non-cacheable", { trace });
|
|
7787
|
+
return { found: false, cacheable: false };
|
|
7788
|
+
}
|
|
7789
|
+
try {
|
|
7790
|
+
const cache = await caches.open(CACHE_NAME2 + this.epoch);
|
|
7791
|
+
const cacheKey = this.buildCacheKey(request);
|
|
7792
|
+
const cached = await cache.match(cacheKey);
|
|
7793
|
+
if (!cached) {
|
|
7794
|
+
logger.debug("[SDK Html-cache] cacheable, MISS", { trace });
|
|
7795
|
+
return { found: false, cacheable: true };
|
|
7796
|
+
}
|
|
7797
|
+
const age = this.getResponseAge(cached);
|
|
7798
|
+
const ttl = parseInt(cached.headers.get("X-Original-TTL") || "") || this.getTTLForRequest(request);
|
|
7799
|
+
const swr = parseInt(cached.headers.get("X-Original-SWR") || "") || this.getSWRForRequest(request);
|
|
7800
|
+
const isStale = age >= ttl;
|
|
7801
|
+
const isExpired = age >= ttl + swr;
|
|
7802
|
+
if (!isExpired) {
|
|
7803
|
+
logger.debug("[SDK Html-cache] cacheable, HIT", {
|
|
7804
|
+
stale: isStale,
|
|
7805
|
+
age,
|
|
7806
|
+
trace
|
|
7807
|
+
});
|
|
7808
|
+
const clientResponse = this.buildClientResponse(
|
|
7809
|
+
cached,
|
|
7810
|
+
ttl,
|
|
7811
|
+
swr,
|
|
7812
|
+
isStale,
|
|
7813
|
+
age
|
|
7814
|
+
);
|
|
7815
|
+
return {
|
|
7816
|
+
found: true,
|
|
7817
|
+
stale: isStale,
|
|
7818
|
+
response: clientResponse,
|
|
7819
|
+
cacheable: true,
|
|
7820
|
+
age: Math.floor(age)
|
|
7821
|
+
};
|
|
7822
|
+
}
|
|
7823
|
+
logger.debug("[SDK Html-cache] cacheable, hit, expired", { trace });
|
|
7824
|
+
return { found: false, cacheable: true };
|
|
7825
|
+
} catch (_) {
|
|
7826
|
+
logger.warn("[SDK Html-cache] no get support", { trace });
|
|
7827
|
+
return null;
|
|
7828
|
+
}
|
|
7829
|
+
}
|
|
7830
|
+
// 304 support
|
|
7831
|
+
async getWithConditionals(request) {
|
|
7832
|
+
const result = await this.get(request);
|
|
7833
|
+
if (!result?.found || result.stale) {
|
|
7834
|
+
return result;
|
|
7835
|
+
}
|
|
7836
|
+
const ifModifiedSince = request.headers.get("If-Modified-Since");
|
|
7837
|
+
const ifNoneMatch = request.headers.get("If-None-Match");
|
|
7838
|
+
if ((ifModifiedSince || ifNoneMatch) && result.response) {
|
|
7839
|
+
const lastModified = result.response.headers.get("Last-Modified");
|
|
7840
|
+
const etag = result.response.headers.get("ETag");
|
|
7841
|
+
if (this.checkNotModified(ifModifiedSince, ifNoneMatch, lastModified, etag)) {
|
|
7842
|
+
result.notModified = true;
|
|
7843
|
+
result.conditional304 = new Response(null, {
|
|
7844
|
+
status: 304,
|
|
7845
|
+
headers: {
|
|
7846
|
+
"Last-Modified": lastModified || "",
|
|
7847
|
+
ETag: etag || "",
|
|
7848
|
+
"Cache-Control": result.response.headers.get("Cache-Control") || "",
|
|
7849
|
+
"Cloudflare-CDN-Cache-Control": result.response.headers.get("Cloudflare-CDN-Cache-Control") || "",
|
|
7850
|
+
"X-Cache-Status": "HIT-304"
|
|
7851
|
+
}
|
|
7852
|
+
});
|
|
7853
|
+
}
|
|
7854
|
+
}
|
|
7855
|
+
return result;
|
|
7856
|
+
}
|
|
7857
|
+
checkNotModified(ifModifiedSince, ifNoneMatch, lastModified, etag) {
|
|
7858
|
+
if (ifNoneMatch && etag) {
|
|
7859
|
+
return ifNoneMatch === etag;
|
|
7860
|
+
}
|
|
7861
|
+
if (ifModifiedSince && lastModified) {
|
|
7862
|
+
const ifModDate = new Date(ifModifiedSince);
|
|
7863
|
+
const lastModDate = new Date(lastModified);
|
|
7864
|
+
return !isNaN(ifModDate.getTime()) && !isNaN(lastModDate.getTime()) && ifModDate >= lastModDate;
|
|
7865
|
+
}
|
|
7866
|
+
return false;
|
|
7867
|
+
}
|
|
7868
|
+
createRevalidationRequest(request) {
|
|
7869
|
+
const headers = new Headers(request.headers);
|
|
7870
|
+
headers.set("X-Cache-Bypass", "revalidation");
|
|
7871
|
+
headers.delete("If-None-Match");
|
|
7872
|
+
headers.delete("If-Modified-Since");
|
|
7873
|
+
headers.delete("Cache-Control");
|
|
7874
|
+
headers.delete("Pragma");
|
|
7875
|
+
return new Request(request.url, {
|
|
7876
|
+
method: "GET",
|
|
7877
|
+
headers
|
|
7878
|
+
});
|
|
7879
|
+
}
|
|
7880
|
+
async put(request, response) {
|
|
7881
|
+
const trace = createTraceId();
|
|
7882
|
+
if (request.method !== "GET" || !response.ok) {
|
|
7883
|
+
logger.debug("[SDK Html-cache] put skipped", { trace });
|
|
7884
|
+
return;
|
|
7885
|
+
}
|
|
7886
|
+
if (!this.isCacheable(request) || !this.isResponseCacheable(response)) {
|
|
7887
|
+
logger.debug("[SDK Html-cache] put skipped, non-cacheable", {
|
|
7888
|
+
trace
|
|
7889
|
+
});
|
|
7890
|
+
return;
|
|
7891
|
+
}
|
|
7892
|
+
try {
|
|
7893
|
+
const cache = await caches.open(CACHE_NAME2 + this.epoch);
|
|
7894
|
+
const cacheKey = this.buildCacheKey(request);
|
|
7895
|
+
await cache.delete(cacheKey);
|
|
7896
|
+
const ttl = this.getTTLForRequest(request);
|
|
7897
|
+
const swr = this.getSWRForRequest(request);
|
|
7898
|
+
const headers = new Headers(response.headers);
|
|
7899
|
+
const existingCacheControl = response.headers.get("Cache-Control");
|
|
7900
|
+
if (!existingCacheControl || existingCacheControl === "public") {
|
|
7901
|
+
const internalMaxAge = ttl + swr;
|
|
7902
|
+
headers.set("Cache-Control", `public, max-age=${internalMaxAge}`);
|
|
7903
|
+
}
|
|
7904
|
+
const cacheTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
7905
|
+
headers.set("X-Cache-Time", cacheTime);
|
|
7906
|
+
headers.set("X-Original-TTL", ttl.toString());
|
|
7907
|
+
headers.set("X-Original-SWR", swr.toString());
|
|
7908
|
+
if (!headers.get("Last-Modified")) {
|
|
7909
|
+
headers.set("Last-Modified", new Date(cacheTime).toUTCString());
|
|
7910
|
+
}
|
|
7911
|
+
const cacheableResponse = new Response(response.body, {
|
|
7912
|
+
status: response.status,
|
|
7913
|
+
statusText: response.statusText,
|
|
7914
|
+
headers
|
|
7915
|
+
});
|
|
7916
|
+
await cache.put(cacheKey, cacheableResponse);
|
|
7917
|
+
logger.debug("[SDK Html-cache] put done", { trace });
|
|
7918
|
+
} catch (_) {
|
|
7919
|
+
logger.warn("[SDK Html-cache] no put support", { trace });
|
|
7920
|
+
}
|
|
7921
|
+
}
|
|
7922
|
+
buildClientResponse(cachedResponse, ttl, swr, isStale, age) {
|
|
7923
|
+
const headers = new Headers(cachedResponse.headers);
|
|
7924
|
+
headers.set(
|
|
7925
|
+
"Cache-Control",
|
|
7926
|
+
`public, max-age=${ttl}, stale-while-revalidate=${swr}`
|
|
7927
|
+
);
|
|
7928
|
+
headers.set(
|
|
7929
|
+
"Cloudflare-CDN-Cache-Control",
|
|
7930
|
+
`public, s-maxage=${ttl}, stale-while-revalidate=${swr}, stale-if-error=60`
|
|
7931
|
+
);
|
|
7932
|
+
const cacheTime = headers.get("X-Cache-Time");
|
|
7933
|
+
if (cacheTime) {
|
|
7934
|
+
const lastModified = new Date(cacheTime).toUTCString();
|
|
7935
|
+
headers.set("Last-Modified", lastModified);
|
|
7936
|
+
}
|
|
7937
|
+
headers.set("X-Cache-Status", isStale ? "STALE" : "HIT");
|
|
7938
|
+
headers.set("X-Cache-Age", Math.floor(age).toString());
|
|
7939
|
+
headers.delete("X-Original-TTL");
|
|
7940
|
+
headers.delete("X-Original-SWR");
|
|
7941
|
+
headers.delete("X-Cache-Time");
|
|
7942
|
+
return new Response(cachedResponse.body, {
|
|
7943
|
+
status: cachedResponse.status,
|
|
7944
|
+
statusText: cachedResponse.statusText,
|
|
7945
|
+
headers
|
|
7946
|
+
});
|
|
7947
|
+
}
|
|
7948
|
+
buildCacheKey(request) {
|
|
7949
|
+
const url = new URL(request.url);
|
|
7950
|
+
const versionHash = this.generateVersionHash(request.headers);
|
|
7951
|
+
const normalizedQuery = this.normalizeSearchParams(url.searchParams);
|
|
7952
|
+
const cacheKeyPath = `${versionHash}${url.pathname}`;
|
|
7953
|
+
const keyUrl = new URL(`${CACHE_KEY_ORIGIN2}${cacheKeyPath}`);
|
|
7954
|
+
if (normalizedQuery) {
|
|
7955
|
+
keyUrl.search = `?${normalizedQuery}`;
|
|
7956
|
+
}
|
|
7957
|
+
const sanitizedHeaders = this.sanitizeHeaders(request.headers);
|
|
7958
|
+
return new Request(keyUrl.toString(), {
|
|
7959
|
+
method: "GET",
|
|
7960
|
+
headers: sanitizedHeaders
|
|
7961
|
+
});
|
|
7962
|
+
}
|
|
7963
|
+
sanitizeHeaders(originalHeaders) {
|
|
7964
|
+
const CACHE_RELEVANT_HEADERS = [
|
|
7965
|
+
// Content negotiation (affects response format)
|
|
7966
|
+
"accept",
|
|
7967
|
+
"accept-language"
|
|
7968
|
+
];
|
|
7969
|
+
const sanitized = new Headers();
|
|
7970
|
+
CACHE_RELEVANT_HEADERS.forEach((header) => {
|
|
7971
|
+
const value = originalHeaders.get(header);
|
|
7972
|
+
if (value) {
|
|
7973
|
+
sanitized.set(header, value);
|
|
7974
|
+
}
|
|
7975
|
+
});
|
|
7976
|
+
return sanitized;
|
|
7977
|
+
}
|
|
7978
|
+
generateVersionHash(headers) {
|
|
7979
|
+
const swellData = this.extractSwellData(headers);
|
|
7980
|
+
const versionFactors = {
|
|
7981
|
+
store: headers.get("swell-storefront-id") || "",
|
|
7982
|
+
auth: headers.get("swell-access-token") || "",
|
|
7983
|
+
theme: headers.get("swell-theme-version-hash") || "",
|
|
7984
|
+
modified: headers.get("swell-cache-modified") || "",
|
|
7985
|
+
currency: swellData["swell-currency"] || "USD",
|
|
7986
|
+
locale: headers.get("x-locale") || headers.get("accept-language")?.split(",")[0] || "default",
|
|
7987
|
+
context: headers.get("swell-storefront-context"),
|
|
7988
|
+
epoch: this.epoch
|
|
7989
|
+
};
|
|
7990
|
+
return md5(JSON.stringify(versionFactors));
|
|
7991
|
+
}
|
|
7992
|
+
extractSwellData(headers) {
|
|
7993
|
+
const cookie = headers.get("cookie");
|
|
7994
|
+
if (!cookie) return {};
|
|
7995
|
+
const swellDataMatch = cookie.match(/swell-data=([^;]+)/);
|
|
7996
|
+
if (!swellDataMatch) return {};
|
|
7997
|
+
try {
|
|
7998
|
+
const parsed = JSON.parse(decodeURIComponent(swellDataMatch[1]));
|
|
7999
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
8000
|
+
return parsed;
|
|
8001
|
+
}
|
|
8002
|
+
return {};
|
|
8003
|
+
} catch {
|
|
8004
|
+
return {};
|
|
8005
|
+
}
|
|
8006
|
+
}
|
|
8007
|
+
isCacheable(request) {
|
|
8008
|
+
const url = new URL(request.url);
|
|
8009
|
+
const headers = request.headers;
|
|
8010
|
+
if (headers.get("swell-deployment-mode") === "editor") {
|
|
8011
|
+
return false;
|
|
8012
|
+
}
|
|
8013
|
+
const skipPaths = ["/checkout"];
|
|
8014
|
+
if (skipPaths.some((path) => url.pathname.startsWith(path))) {
|
|
8015
|
+
return false;
|
|
8016
|
+
}
|
|
8017
|
+
if (headers.get("cache-control")?.includes("no-cache")) {
|
|
8018
|
+
return false;
|
|
8019
|
+
}
|
|
8020
|
+
return true;
|
|
8021
|
+
}
|
|
8022
|
+
isResponseCacheable(response) {
|
|
8023
|
+
const contentType = response.headers.get("content-type");
|
|
8024
|
+
if (!contentType?.includes("text/html")) {
|
|
8025
|
+
return false;
|
|
8026
|
+
}
|
|
8027
|
+
if (response.headers.get("set-cookie")) {
|
|
8028
|
+
return false;
|
|
8029
|
+
}
|
|
8030
|
+
const cacheControl = response.headers.get("cache-control");
|
|
8031
|
+
if (cacheControl?.includes("no-store") || cacheControl?.includes("private")) {
|
|
8032
|
+
return false;
|
|
8033
|
+
}
|
|
8034
|
+
return true;
|
|
8035
|
+
}
|
|
8036
|
+
getDeploymentMode(headers) {
|
|
8037
|
+
const mode = headers.get("swell-deployment-mode");
|
|
8038
|
+
if (mode === "preview" || mode === "editor") {
|
|
8039
|
+
return mode;
|
|
8040
|
+
}
|
|
8041
|
+
return "live";
|
|
8042
|
+
}
|
|
8043
|
+
getTTLForRequest(request) {
|
|
8044
|
+
const url = new URL(request.url);
|
|
8045
|
+
const path = url.pathname;
|
|
8046
|
+
const mode = this.getDeploymentMode(request.headers);
|
|
8047
|
+
if (mode === "editor") {
|
|
8048
|
+
return 0;
|
|
8049
|
+
}
|
|
8050
|
+
const config = mode === "preview" ? TTL_CONFIG.PREVIEW : TTL_CONFIG.LIVE;
|
|
8051
|
+
if (path === "/") {
|
|
8052
|
+
return config.HOME;
|
|
8053
|
+
}
|
|
8054
|
+
if (path.startsWith("/products/")) {
|
|
8055
|
+
return config.PRODUCT;
|
|
8056
|
+
}
|
|
8057
|
+
if (path.startsWith("/categories/")) {
|
|
8058
|
+
return config.COLLECTION;
|
|
8059
|
+
}
|
|
8060
|
+
if (path.startsWith("/pages/")) {
|
|
8061
|
+
return config.PAGE;
|
|
8062
|
+
}
|
|
8063
|
+
if (path.startsWith("/blogs/")) {
|
|
8064
|
+
return config.BLOG;
|
|
8065
|
+
}
|
|
8066
|
+
return config.DEFAULT;
|
|
8067
|
+
}
|
|
8068
|
+
getSWRForRequest(request) {
|
|
8069
|
+
const mode = this.getDeploymentMode(request.headers);
|
|
8070
|
+
if (mode === "editor") {
|
|
8071
|
+
return 0;
|
|
8072
|
+
}
|
|
8073
|
+
return mode === "preview" ? TTL_CONFIG.PREVIEW.SWR : TTL_CONFIG.LIVE.SWR;
|
|
8074
|
+
}
|
|
8075
|
+
getResponseAge(response) {
|
|
8076
|
+
const cacheTime = response.headers.get("X-Cache-Time");
|
|
8077
|
+
if (!cacheTime) {
|
|
8078
|
+
return Infinity;
|
|
8079
|
+
}
|
|
8080
|
+
const cacheDate = new Date(cacheTime);
|
|
8081
|
+
if (isNaN(cacheDate.getTime())) {
|
|
8082
|
+
return Infinity;
|
|
8083
|
+
}
|
|
8084
|
+
const age = (Date.now() - cacheDate.getTime()) / 1e3;
|
|
8085
|
+
return Math.max(0, age);
|
|
8086
|
+
}
|
|
8087
|
+
normalizeSearchParams(searchParams) {
|
|
8088
|
+
const ignoredParams = [
|
|
8089
|
+
"utm_source",
|
|
8090
|
+
"utm_medium",
|
|
8091
|
+
"utm_campaign",
|
|
8092
|
+
"utm_content",
|
|
8093
|
+
"utm_term",
|
|
8094
|
+
"fbclid",
|
|
8095
|
+
"gclid",
|
|
8096
|
+
"gbraid",
|
|
8097
|
+
"wbraid",
|
|
8098
|
+
"ref",
|
|
8099
|
+
"source",
|
|
8100
|
+
"mc_cid",
|
|
8101
|
+
"mc_eid"
|
|
8102
|
+
];
|
|
8103
|
+
const relevantParams = [];
|
|
8104
|
+
searchParams.forEach((value, key) => {
|
|
8105
|
+
if (!ignoredParams.includes(key)) {
|
|
8106
|
+
relevantParams.push(
|
|
8107
|
+
`${encodeURIComponent(key)}=${encodeURIComponent(value)}`
|
|
8108
|
+
);
|
|
8109
|
+
}
|
|
8110
|
+
});
|
|
8111
|
+
return relevantParams.sort().join("&");
|
|
8112
|
+
}
|
|
8113
|
+
};
|
|
8114
|
+
|
|
7733
8115
|
// src/resources/addresses.ts
|
|
7734
8116
|
var SwellAddresses = class extends SwellStorefrontCollection {
|
|
7735
8117
|
constructor(swell, query) {
|
|
@@ -8557,13 +8939,19 @@
|
|
|
8557
8939
|
const storefrontRequest = storefront.request;
|
|
8558
8940
|
return (method, url, id, data, opt) => {
|
|
8559
8941
|
if (this.isStorefrontRequestCacheable(method, url, opt)) {
|
|
8560
|
-
|
|
8561
|
-
|
|
8562
|
-
|
|
8563
|
-
|
|
8564
|
-
|
|
8565
|
-
|
|
8566
|
-
|
|
8942
|
+
const key = getCacheKey("request", [
|
|
8943
|
+
this.instanceId,
|
|
8944
|
+
method,
|
|
8945
|
+
url,
|
|
8946
|
+
id,
|
|
8947
|
+
data,
|
|
8948
|
+
opt
|
|
8949
|
+
]);
|
|
8950
|
+
return this.getRequestCache().fetchSWR(key, () => {
|
|
8951
|
+
const requestUrl = id ? `${url}/${id}` : url;
|
|
8952
|
+
logger.debug("[SDK] Cacheable API request", { url: requestUrl, key });
|
|
8953
|
+
return storefrontRequest(method, url, id, data, opt);
|
|
8954
|
+
});
|
|
8567
8955
|
}
|
|
8568
8956
|
switch (method) {
|
|
8569
8957
|
case "delete":
|
|
@@ -8610,7 +8998,9 @@
|
|
|
8610
8998
|
};
|
|
8611
8999
|
function getCacheKey(key, args) {
|
|
8612
9000
|
if (Array.isArray(args) && args.length > 0) {
|
|
8613
|
-
|
|
9001
|
+
const fullKey = `${key}_${md5(JSON.stringify(args))}`;
|
|
9002
|
+
logger.debug(`[SDK] make cache key: ${fullKey}`);
|
|
9003
|
+
return fullKey;
|
|
8614
9004
|
}
|
|
8615
9005
|
return key;
|
|
8616
9006
|
}
|