@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.cjs
CHANGED
|
@@ -94,6 +94,7 @@ __export(index_exports, {
|
|
|
94
94
|
ThemeFont: () => ThemeFont,
|
|
95
95
|
ThemeForm: () => ThemeForm,
|
|
96
96
|
ThemeFormErrors: () => ThemeFormErrors,
|
|
97
|
+
WorkerHtmlCache: () => WorkerHtmlCache,
|
|
97
98
|
adaptShopifyFontData: () => adaptShopifyFontData,
|
|
98
99
|
adaptShopifyFormData: () => adaptShopifyFormData,
|
|
99
100
|
adaptShopifyMenuData: () => adaptShopifyMenuData,
|
|
@@ -160,72 +161,6 @@ var import_qs2 = __toESM(require("qs"), 1);
|
|
|
160
161
|
var import_keyv = require("keyv");
|
|
161
162
|
var import_cache_manager = require("cache-manager");
|
|
162
163
|
|
|
163
|
-
// src/cache/cf-worker-kv-keyv-adapter.ts
|
|
164
|
-
var CFWorkerKVKeyvAdapter = class {
|
|
165
|
-
store;
|
|
166
|
-
namespace;
|
|
167
|
-
// magically passed in from Keyv
|
|
168
|
-
opts;
|
|
169
|
-
constructor(store) {
|
|
170
|
-
this.store = store;
|
|
171
|
-
this.opts = null;
|
|
172
|
-
this.namespace = "dummy";
|
|
173
|
-
}
|
|
174
|
-
async has(key) {
|
|
175
|
-
const stream = await this.store.get(key, "stream");
|
|
176
|
-
if (stream !== null) {
|
|
177
|
-
await stream.cancel();
|
|
178
|
-
return true;
|
|
179
|
-
}
|
|
180
|
-
return false;
|
|
181
|
-
}
|
|
182
|
-
async get(key) {
|
|
183
|
-
const value = await this.store.get(key);
|
|
184
|
-
return value !== null ? value : void 0;
|
|
185
|
-
}
|
|
186
|
-
set(key, value, ttl) {
|
|
187
|
-
if (typeof ttl === "number") {
|
|
188
|
-
ttl = Math.max(60, ttl / 1e3);
|
|
189
|
-
}
|
|
190
|
-
return this.store.put(key, value, { expirationTtl: ttl });
|
|
191
|
-
}
|
|
192
|
-
async delete(key) {
|
|
193
|
-
await this.store.delete(key);
|
|
194
|
-
return true;
|
|
195
|
-
}
|
|
196
|
-
async clear() {
|
|
197
|
-
let cursor = "";
|
|
198
|
-
let complete = false;
|
|
199
|
-
const prefix = `${this.namespace}:`;
|
|
200
|
-
do {
|
|
201
|
-
const response = await this.store.list({
|
|
202
|
-
prefix,
|
|
203
|
-
cursor: cursor || void 0
|
|
204
|
-
});
|
|
205
|
-
cursor = response.cursor ?? "";
|
|
206
|
-
complete = response.list_complete;
|
|
207
|
-
if (response.keys.length > 0) {
|
|
208
|
-
await Promise.all(
|
|
209
|
-
response.keys.map((key) => {
|
|
210
|
-
return this.store.delete(key.name);
|
|
211
|
-
})
|
|
212
|
-
);
|
|
213
|
-
}
|
|
214
|
-
} while (!complete);
|
|
215
|
-
}
|
|
216
|
-
on(_event, _listener) {
|
|
217
|
-
return this;
|
|
218
|
-
}
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
// src/utils/index.ts
|
|
222
|
-
var import_qs = __toESM(require("qs"), 1);
|
|
223
|
-
var import_lodash_es3 = require("lodash-es");
|
|
224
|
-
var import_json52 = __toESM(require("json5"), 1);
|
|
225
|
-
|
|
226
|
-
// src/resources.ts
|
|
227
|
-
var import_lodash_es2 = require("lodash-es");
|
|
228
|
-
|
|
229
164
|
// src/utils/logger.ts
|
|
230
165
|
var logLevels = {
|
|
231
166
|
error: 0,
|
|
@@ -317,6 +252,80 @@ function createTraceId(data) {
|
|
|
317
252
|
return (hash >>> 0).toString(16);
|
|
318
253
|
}
|
|
319
254
|
|
|
255
|
+
// src/cache/cf-worker-kv-keyv-adapter.ts
|
|
256
|
+
var CFWorkerKVKeyvAdapter = class {
|
|
257
|
+
store;
|
|
258
|
+
namespace;
|
|
259
|
+
// magically passed in from Keyv
|
|
260
|
+
opts;
|
|
261
|
+
constructor(store) {
|
|
262
|
+
this.store = store;
|
|
263
|
+
this.opts = null;
|
|
264
|
+
this.namespace = "dummy";
|
|
265
|
+
}
|
|
266
|
+
async has(key) {
|
|
267
|
+
const stream = await this.store.get(key, "stream");
|
|
268
|
+
if (stream !== null) {
|
|
269
|
+
await stream.cancel();
|
|
270
|
+
return true;
|
|
271
|
+
}
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
async get(key) {
|
|
275
|
+
const trace = createTraceId();
|
|
276
|
+
logger.debug("[SDK] kv.get", { key, trace });
|
|
277
|
+
const value = await this.store.get(key);
|
|
278
|
+
const result = value !== null ? value : void 0;
|
|
279
|
+
logger.debug(`[SDK] kv.get ${value !== null ? "HIT" : "MISS"}`, {
|
|
280
|
+
key,
|
|
281
|
+
trace
|
|
282
|
+
});
|
|
283
|
+
return result;
|
|
284
|
+
}
|
|
285
|
+
set(key, value, ttl) {
|
|
286
|
+
if (typeof ttl === "number") {
|
|
287
|
+
ttl = Math.max(60, ttl / 1e3);
|
|
288
|
+
}
|
|
289
|
+
logger.debug("[SDK] kv.set", { key });
|
|
290
|
+
return this.store.put(key, value, { expirationTtl: ttl });
|
|
291
|
+
}
|
|
292
|
+
async delete(key) {
|
|
293
|
+
await this.store.delete(key);
|
|
294
|
+
return true;
|
|
295
|
+
}
|
|
296
|
+
async clear() {
|
|
297
|
+
let cursor = "";
|
|
298
|
+
let complete = false;
|
|
299
|
+
const prefix = `${this.namespace}:`;
|
|
300
|
+
do {
|
|
301
|
+
const response = await this.store.list({
|
|
302
|
+
prefix,
|
|
303
|
+
cursor: cursor || void 0
|
|
304
|
+
});
|
|
305
|
+
cursor = response.cursor ?? "";
|
|
306
|
+
complete = response.list_complete;
|
|
307
|
+
if (response.keys.length > 0) {
|
|
308
|
+
await Promise.all(
|
|
309
|
+
response.keys.map((key) => {
|
|
310
|
+
return this.store.delete(key.name);
|
|
311
|
+
})
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
} while (!complete);
|
|
315
|
+
}
|
|
316
|
+
on(_event, _listener) {
|
|
317
|
+
return this;
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
// src/utils/index.ts
|
|
322
|
+
var import_qs = __toESM(require("qs"), 1);
|
|
323
|
+
var import_lodash_es3 = require("lodash-es");
|
|
324
|
+
var import_json52 = __toESM(require("json5"), 1);
|
|
325
|
+
|
|
326
|
+
// src/resources.ts
|
|
327
|
+
var import_lodash_es2 = require("lodash-es");
|
|
328
|
+
|
|
320
329
|
// src/liquid/utils.ts
|
|
321
330
|
var import_liquidjs = require("liquidjs");
|
|
322
331
|
|
|
@@ -960,6 +969,7 @@ var SwellStorefrontCollection = class _SwellStorefrontCollection extends SwellSt
|
|
|
960
969
|
this._collection,
|
|
961
970
|
this._query,
|
|
962
971
|
this._swell.queryParams,
|
|
972
|
+
// TODO: consider to exlcude
|
|
963
973
|
this._getterHash
|
|
964
974
|
],
|
|
965
975
|
getter,
|
|
@@ -1088,6 +1098,7 @@ var SwellStorefrontRecord = class extends SwellStorefrontResource {
|
|
|
1088
1098
|
this._id,
|
|
1089
1099
|
this._query,
|
|
1090
1100
|
this._swell.queryParams,
|
|
1101
|
+
// TODO: consider to exlcude
|
|
1091
1102
|
this._getterHash
|
|
1092
1103
|
],
|
|
1093
1104
|
getter,
|
|
@@ -7316,8 +7327,6 @@ var Cache = class {
|
|
|
7316
7327
|
* This will always return the cached value immediately if exists
|
|
7317
7328
|
*/
|
|
7318
7329
|
async fetchSWR(key, fetchFn, ttl = DEFAULT_SWR_TTL, isCacheble = true) {
|
|
7319
|
-
const trace = createTraceId();
|
|
7320
|
-
logger.debug("[SDK] Cache fetch start", { key, trace });
|
|
7321
7330
|
const cacheValue = isCacheble ? await this.client.get(key) : void 0;
|
|
7322
7331
|
let promise = SWR_PROMISE_MAP.get(key);
|
|
7323
7332
|
if (promise === void 0) {
|
|
@@ -7325,7 +7334,6 @@ var Cache = class {
|
|
|
7325
7334
|
const isNull = value === null || value === void 0;
|
|
7326
7335
|
if (isCacheble) {
|
|
7327
7336
|
await this.client.set(key, isNull ? NULL_VALUE : value, ttl);
|
|
7328
|
-
logger.debug("[SDK] Cache update done", { key, trace });
|
|
7329
7337
|
}
|
|
7330
7338
|
return value;
|
|
7331
7339
|
}).finally(() => {
|
|
@@ -7337,12 +7345,9 @@ var Cache = class {
|
|
|
7337
7345
|
this.workerCtx.waitUntil(promise);
|
|
7338
7346
|
}
|
|
7339
7347
|
if (cacheValue !== void 0) {
|
|
7340
|
-
logger.debug("[SDK] Cache check done", { status: "HIT", key, trace });
|
|
7341
7348
|
return cacheValue === NULL_VALUE ? null : cacheValue;
|
|
7342
7349
|
}
|
|
7343
|
-
logger.debug("[SDK] Cache check done", { status: "MISS", key, trace });
|
|
7344
7350
|
const result = await promise;
|
|
7345
|
-
logger.debug("[SDK] Cache fetch end", { key, trace });
|
|
7346
7351
|
return result;
|
|
7347
7352
|
}
|
|
7348
7353
|
async get(key) {
|
|
@@ -7849,6 +7854,384 @@ var WorkerCacheProxy = class {
|
|
|
7849
7854
|
}
|
|
7850
7855
|
};
|
|
7851
7856
|
|
|
7857
|
+
// src/cache/worker-html-cache.ts
|
|
7858
|
+
var CACHE_NAME2 = "swell-html-v1";
|
|
7859
|
+
var CACHE_KEY_ORIGIN2 = "https://cache.swell.store";
|
|
7860
|
+
var TTL_CONFIG = {
|
|
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
|
+
}
|
|
7893
|
+
};
|
|
7894
|
+
var WorkerHtmlCache = class {
|
|
7895
|
+
epoch;
|
|
7896
|
+
constructor(epoch) {
|
|
7897
|
+
this.epoch = epoch;
|
|
7898
|
+
}
|
|
7899
|
+
async get(request) {
|
|
7900
|
+
const trace = createTraceId();
|
|
7901
|
+
if (request.method !== "GET") {
|
|
7902
|
+
logger.debug("[SDK Html-cache] non-cacheable", { trace });
|
|
7903
|
+
return { found: false, cacheable: false };
|
|
7904
|
+
}
|
|
7905
|
+
if (!this.isCacheable(request)) {
|
|
7906
|
+
logger.debug("[SDK Html-cache] non-cacheable", { trace });
|
|
7907
|
+
return { found: false, cacheable: false };
|
|
7908
|
+
}
|
|
7909
|
+
try {
|
|
7910
|
+
const cache = await caches.open(CACHE_NAME2 + this.epoch);
|
|
7911
|
+
const cacheKey = this.buildCacheKey(request);
|
|
7912
|
+
const cached = await cache.match(cacheKey);
|
|
7913
|
+
if (!cached) {
|
|
7914
|
+
logger.debug("[SDK Html-cache] cacheable, MISS", { trace });
|
|
7915
|
+
return { found: false, cacheable: true };
|
|
7916
|
+
}
|
|
7917
|
+
const age = this.getResponseAge(cached);
|
|
7918
|
+
const ttl = parseInt(cached.headers.get("X-Original-TTL") || "") || this.getTTLForRequest(request);
|
|
7919
|
+
const swr = parseInt(cached.headers.get("X-Original-SWR") || "") || this.getSWRForRequest(request);
|
|
7920
|
+
const isStale = age >= ttl;
|
|
7921
|
+
const isExpired = age >= ttl + swr;
|
|
7922
|
+
if (!isExpired) {
|
|
7923
|
+
logger.debug("[SDK Html-cache] cacheable, HIT", {
|
|
7924
|
+
stale: isStale,
|
|
7925
|
+
age,
|
|
7926
|
+
trace
|
|
7927
|
+
});
|
|
7928
|
+
const clientResponse = this.buildClientResponse(
|
|
7929
|
+
cached,
|
|
7930
|
+
ttl,
|
|
7931
|
+
swr,
|
|
7932
|
+
isStale,
|
|
7933
|
+
age
|
|
7934
|
+
);
|
|
7935
|
+
return {
|
|
7936
|
+
found: true,
|
|
7937
|
+
stale: isStale,
|
|
7938
|
+
response: clientResponse,
|
|
7939
|
+
cacheable: true,
|
|
7940
|
+
age: Math.floor(age)
|
|
7941
|
+
};
|
|
7942
|
+
}
|
|
7943
|
+
logger.debug("[SDK Html-cache] cacheable, hit, expired", { trace });
|
|
7944
|
+
return { found: false, cacheable: true };
|
|
7945
|
+
} catch (_) {
|
|
7946
|
+
logger.warn("[SDK Html-cache] no get support", { trace });
|
|
7947
|
+
return null;
|
|
7948
|
+
}
|
|
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
|
+
}
|
|
8000
|
+
async put(request, response) {
|
|
8001
|
+
const trace = createTraceId();
|
|
8002
|
+
if (request.method !== "GET" || !response.ok) {
|
|
8003
|
+
logger.debug("[SDK Html-cache] put skipped", { trace });
|
|
8004
|
+
return;
|
|
8005
|
+
}
|
|
8006
|
+
if (!this.isCacheable(request) || !this.isResponseCacheable(response)) {
|
|
8007
|
+
logger.debug("[SDK Html-cache] put skipped, non-cacheable", {
|
|
8008
|
+
trace
|
|
8009
|
+
});
|
|
8010
|
+
return;
|
|
8011
|
+
}
|
|
8012
|
+
try {
|
|
8013
|
+
const cache = await caches.open(CACHE_NAME2 + this.epoch);
|
|
8014
|
+
const cacheKey = this.buildCacheKey(request);
|
|
8015
|
+
await cache.delete(cacheKey);
|
|
8016
|
+
const ttl = this.getTTLForRequest(request);
|
|
8017
|
+
const swr = this.getSWRForRequest(request);
|
|
8018
|
+
const headers = new Headers(response.headers);
|
|
8019
|
+
const existingCacheControl = response.headers.get("Cache-Control");
|
|
8020
|
+
if (!existingCacheControl || existingCacheControl === "public") {
|
|
8021
|
+
const internalMaxAge = ttl + swr;
|
|
8022
|
+
headers.set("Cache-Control", `public, max-age=${internalMaxAge}`);
|
|
8023
|
+
}
|
|
8024
|
+
const cacheTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
8025
|
+
headers.set("X-Cache-Time", cacheTime);
|
|
8026
|
+
headers.set("X-Original-TTL", ttl.toString());
|
|
8027
|
+
headers.set("X-Original-SWR", swr.toString());
|
|
8028
|
+
if (!headers.get("Last-Modified")) {
|
|
8029
|
+
headers.set("Last-Modified", new Date(cacheTime).toUTCString());
|
|
8030
|
+
}
|
|
8031
|
+
const cacheableResponse = new Response(response.body, {
|
|
8032
|
+
status: response.status,
|
|
8033
|
+
statusText: response.statusText,
|
|
8034
|
+
headers
|
|
8035
|
+
});
|
|
8036
|
+
await cache.put(cacheKey, cacheableResponse);
|
|
8037
|
+
logger.debug("[SDK Html-cache] put done", { trace });
|
|
8038
|
+
} catch (_) {
|
|
8039
|
+
logger.warn("[SDK Html-cache] no put support", { trace });
|
|
8040
|
+
}
|
|
8041
|
+
}
|
|
8042
|
+
buildClientResponse(cachedResponse, ttl, swr, isStale, age) {
|
|
8043
|
+
const headers = new Headers(cachedResponse.headers);
|
|
8044
|
+
headers.set(
|
|
8045
|
+
"Cache-Control",
|
|
8046
|
+
`public, max-age=${ttl}, stale-while-revalidate=${swr}`
|
|
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
|
+
}
|
|
8057
|
+
headers.set("X-Cache-Status", isStale ? "STALE" : "HIT");
|
|
8058
|
+
headers.set("X-Cache-Age", Math.floor(age).toString());
|
|
8059
|
+
headers.delete("X-Original-TTL");
|
|
8060
|
+
headers.delete("X-Original-SWR");
|
|
8061
|
+
headers.delete("X-Cache-Time");
|
|
8062
|
+
return new Response(cachedResponse.body, {
|
|
8063
|
+
status: cachedResponse.status,
|
|
8064
|
+
statusText: cachedResponse.statusText,
|
|
8065
|
+
headers
|
|
8066
|
+
});
|
|
8067
|
+
}
|
|
8068
|
+
buildCacheKey(request) {
|
|
8069
|
+
const url = new URL(request.url);
|
|
8070
|
+
const versionHash = this.generateVersionHash(request.headers);
|
|
8071
|
+
const normalizedQuery = this.normalizeSearchParams(url.searchParams);
|
|
8072
|
+
const cacheKeyPath = `${versionHash}${url.pathname}`;
|
|
8073
|
+
const keyUrl = new URL(`${CACHE_KEY_ORIGIN2}${cacheKeyPath}`);
|
|
8074
|
+
if (normalizedQuery) {
|
|
8075
|
+
keyUrl.search = `?${normalizedQuery}`;
|
|
8076
|
+
}
|
|
8077
|
+
const sanitizedHeaders = this.sanitizeHeaders(request.headers);
|
|
8078
|
+
return new Request(keyUrl.toString(), {
|
|
8079
|
+
method: "GET",
|
|
8080
|
+
headers: sanitizedHeaders
|
|
8081
|
+
});
|
|
8082
|
+
}
|
|
8083
|
+
sanitizeHeaders(originalHeaders) {
|
|
8084
|
+
const CACHE_RELEVANT_HEADERS = [
|
|
8085
|
+
// Content negotiation (affects response format)
|
|
8086
|
+
"accept",
|
|
8087
|
+
"accept-language"
|
|
8088
|
+
];
|
|
8089
|
+
const sanitized = new Headers();
|
|
8090
|
+
CACHE_RELEVANT_HEADERS.forEach((header) => {
|
|
8091
|
+
const value = originalHeaders.get(header);
|
|
8092
|
+
if (value) {
|
|
8093
|
+
sanitized.set(header, value);
|
|
8094
|
+
}
|
|
8095
|
+
});
|
|
8096
|
+
return sanitized;
|
|
8097
|
+
}
|
|
8098
|
+
generateVersionHash(headers) {
|
|
8099
|
+
const swellData = this.extractSwellData(headers);
|
|
8100
|
+
const versionFactors = {
|
|
8101
|
+
store: headers.get("swell-storefront-id") || "",
|
|
8102
|
+
auth: headers.get("swell-access-token") || "",
|
|
8103
|
+
theme: headers.get("swell-theme-version-hash") || "",
|
|
8104
|
+
modified: headers.get("swell-cache-modified") || "",
|
|
8105
|
+
currency: swellData["swell-currency"] || "USD",
|
|
8106
|
+
locale: headers.get("x-locale") || headers.get("accept-language")?.split(",")[0] || "default",
|
|
8107
|
+
context: headers.get("swell-storefront-context"),
|
|
8108
|
+
epoch: this.epoch
|
|
8109
|
+
};
|
|
8110
|
+
return md5(JSON.stringify(versionFactors));
|
|
8111
|
+
}
|
|
8112
|
+
extractSwellData(headers) {
|
|
8113
|
+
const cookie = headers.get("cookie");
|
|
8114
|
+
if (!cookie) return {};
|
|
8115
|
+
const swellDataMatch = cookie.match(/swell-data=([^;]+)/);
|
|
8116
|
+
if (!swellDataMatch) return {};
|
|
8117
|
+
try {
|
|
8118
|
+
const parsed = JSON.parse(decodeURIComponent(swellDataMatch[1]));
|
|
8119
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
8120
|
+
return parsed;
|
|
8121
|
+
}
|
|
8122
|
+
return {};
|
|
8123
|
+
} catch {
|
|
8124
|
+
return {};
|
|
8125
|
+
}
|
|
8126
|
+
}
|
|
8127
|
+
isCacheable(request) {
|
|
8128
|
+
const url = new URL(request.url);
|
|
8129
|
+
const headers = request.headers;
|
|
8130
|
+
if (headers.get("swell-deployment-mode") === "editor") {
|
|
8131
|
+
return false;
|
|
8132
|
+
}
|
|
8133
|
+
const skipPaths = ["/checkout"];
|
|
8134
|
+
if (skipPaths.some((path) => url.pathname.startsWith(path))) {
|
|
8135
|
+
return false;
|
|
8136
|
+
}
|
|
8137
|
+
if (headers.get("cache-control")?.includes("no-cache")) {
|
|
8138
|
+
return false;
|
|
8139
|
+
}
|
|
8140
|
+
return true;
|
|
8141
|
+
}
|
|
8142
|
+
isResponseCacheable(response) {
|
|
8143
|
+
const contentType = response.headers.get("content-type");
|
|
8144
|
+
if (!contentType?.includes("text/html")) {
|
|
8145
|
+
return false;
|
|
8146
|
+
}
|
|
8147
|
+
if (response.headers.get("set-cookie")) {
|
|
8148
|
+
return false;
|
|
8149
|
+
}
|
|
8150
|
+
const cacheControl = response.headers.get("cache-control");
|
|
8151
|
+
if (cacheControl?.includes("no-store") || cacheControl?.includes("private")) {
|
|
8152
|
+
return false;
|
|
8153
|
+
}
|
|
8154
|
+
return true;
|
|
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
|
+
}
|
|
8163
|
+
getTTLForRequest(request) {
|
|
8164
|
+
const url = new URL(request.url);
|
|
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;
|
|
8171
|
+
if (path === "/") {
|
|
8172
|
+
return config.HOME;
|
|
8173
|
+
}
|
|
8174
|
+
if (path.startsWith("/products/")) {
|
|
8175
|
+
return config.PRODUCT;
|
|
8176
|
+
}
|
|
8177
|
+
if (path.startsWith("/categories/")) {
|
|
8178
|
+
return config.COLLECTION;
|
|
8179
|
+
}
|
|
8180
|
+
if (path.startsWith("/pages/")) {
|
|
8181
|
+
return config.PAGE;
|
|
8182
|
+
}
|
|
8183
|
+
if (path.startsWith("/blogs/")) {
|
|
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;
|
|
8192
|
+
}
|
|
8193
|
+
return mode === "preview" ? TTL_CONFIG.PREVIEW.SWR : TTL_CONFIG.LIVE.SWR;
|
|
8194
|
+
}
|
|
8195
|
+
getResponseAge(response) {
|
|
8196
|
+
const cacheTime = response.headers.get("X-Cache-Time");
|
|
8197
|
+
if (!cacheTime) {
|
|
8198
|
+
return Infinity;
|
|
8199
|
+
}
|
|
8200
|
+
const cacheDate = new Date(cacheTime);
|
|
8201
|
+
if (isNaN(cacheDate.getTime())) {
|
|
8202
|
+
return Infinity;
|
|
8203
|
+
}
|
|
8204
|
+
const age = (Date.now() - cacheDate.getTime()) / 1e3;
|
|
8205
|
+
return Math.max(0, age);
|
|
8206
|
+
}
|
|
8207
|
+
normalizeSearchParams(searchParams) {
|
|
8208
|
+
const ignoredParams = [
|
|
8209
|
+
"utm_source",
|
|
8210
|
+
"utm_medium",
|
|
8211
|
+
"utm_campaign",
|
|
8212
|
+
"utm_content",
|
|
8213
|
+
"utm_term",
|
|
8214
|
+
"fbclid",
|
|
8215
|
+
"gclid",
|
|
8216
|
+
"gbraid",
|
|
8217
|
+
"wbraid",
|
|
8218
|
+
"ref",
|
|
8219
|
+
"source",
|
|
8220
|
+
"mc_cid",
|
|
8221
|
+
"mc_eid"
|
|
8222
|
+
];
|
|
8223
|
+
const relevantParams = [];
|
|
8224
|
+
searchParams.forEach((value, key) => {
|
|
8225
|
+
if (!ignoredParams.includes(key)) {
|
|
8226
|
+
relevantParams.push(
|
|
8227
|
+
`${encodeURIComponent(key)}=${encodeURIComponent(value)}`
|
|
8228
|
+
);
|
|
8229
|
+
}
|
|
8230
|
+
});
|
|
8231
|
+
return relevantParams.sort().join("&");
|
|
8232
|
+
}
|
|
8233
|
+
};
|
|
8234
|
+
|
|
7852
8235
|
// src/resources/addresses.ts
|
|
7853
8236
|
var SwellAddresses = class extends SwellStorefrontCollection {
|
|
7854
8237
|
constructor(swell, query) {
|
|
@@ -8676,13 +9059,19 @@ var Swell = class _Swell {
|
|
|
8676
9059
|
const storefrontRequest = storefront.request;
|
|
8677
9060
|
return (method, url, id, data, opt) => {
|
|
8678
9061
|
if (this.isStorefrontRequestCacheable(method, url, opt)) {
|
|
8679
|
-
|
|
8680
|
-
|
|
8681
|
-
|
|
8682
|
-
|
|
8683
|
-
|
|
8684
|
-
|
|
8685
|
-
|
|
9062
|
+
const key = getCacheKey("request", [
|
|
9063
|
+
this.instanceId,
|
|
9064
|
+
method,
|
|
9065
|
+
url,
|
|
9066
|
+
id,
|
|
9067
|
+
data,
|
|
9068
|
+
opt
|
|
9069
|
+
]);
|
|
9070
|
+
return this.getRequestCache().fetchSWR(key, () => {
|
|
9071
|
+
const requestUrl = id ? `${url}/${id}` : url;
|
|
9072
|
+
logger.debug("[SDK] Cacheable API request", { url: requestUrl, key });
|
|
9073
|
+
return storefrontRequest(method, url, id, data, opt);
|
|
9074
|
+
});
|
|
8686
9075
|
}
|
|
8687
9076
|
switch (method) {
|
|
8688
9077
|
case "delete":
|
|
@@ -8729,7 +9118,9 @@ var Swell = class _Swell {
|
|
|
8729
9118
|
};
|
|
8730
9119
|
function getCacheKey(key, args) {
|
|
8731
9120
|
if (Array.isArray(args) && args.length > 0) {
|
|
8732
|
-
|
|
9121
|
+
const fullKey = `${key}_${md5(JSON.stringify(args))}`;
|
|
9122
|
+
logger.debug(`[SDK] make cache key: ${fullKey}`);
|
|
9123
|
+
return fullKey;
|
|
8733
9124
|
}
|
|
8734
9125
|
return key;
|
|
8735
9126
|
}
|
|
@@ -22504,6 +22895,7 @@ function getResourceQuery(slug, query) {
|
|
|
22504
22895
|
ThemeFont,
|
|
22505
22896
|
ThemeForm,
|
|
22506
22897
|
ThemeFormErrors,
|
|
22898
|
+
WorkerHtmlCache,
|
|
22507
22899
|
adaptShopifyFontData,
|
|
22508
22900
|
adaptShopifyFormData,
|
|
22509
22901
|
adaptShopifyMenuData,
|