@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.mjs
CHANGED
|
@@ -14,72 +14,6 @@ import {
|
|
|
14
14
|
createCache
|
|
15
15
|
} from "cache-manager";
|
|
16
16
|
|
|
17
|
-
// src/cache/cf-worker-kv-keyv-adapter.ts
|
|
18
|
-
var CFWorkerKVKeyvAdapter = class {
|
|
19
|
-
store;
|
|
20
|
-
namespace;
|
|
21
|
-
// magically passed in from Keyv
|
|
22
|
-
opts;
|
|
23
|
-
constructor(store) {
|
|
24
|
-
this.store = store;
|
|
25
|
-
this.opts = null;
|
|
26
|
-
this.namespace = "dummy";
|
|
27
|
-
}
|
|
28
|
-
async has(key) {
|
|
29
|
-
const stream = await this.store.get(key, "stream");
|
|
30
|
-
if (stream !== null) {
|
|
31
|
-
await stream.cancel();
|
|
32
|
-
return true;
|
|
33
|
-
}
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
async get(key) {
|
|
37
|
-
const value = await this.store.get(key);
|
|
38
|
-
return value !== null ? value : void 0;
|
|
39
|
-
}
|
|
40
|
-
set(key, value, ttl) {
|
|
41
|
-
if (typeof ttl === "number") {
|
|
42
|
-
ttl = Math.max(60, ttl / 1e3);
|
|
43
|
-
}
|
|
44
|
-
return this.store.put(key, value, { expirationTtl: ttl });
|
|
45
|
-
}
|
|
46
|
-
async delete(key) {
|
|
47
|
-
await this.store.delete(key);
|
|
48
|
-
return true;
|
|
49
|
-
}
|
|
50
|
-
async clear() {
|
|
51
|
-
let cursor = "";
|
|
52
|
-
let complete = false;
|
|
53
|
-
const prefix = `${this.namespace}:`;
|
|
54
|
-
do {
|
|
55
|
-
const response = await this.store.list({
|
|
56
|
-
prefix,
|
|
57
|
-
cursor: cursor || void 0
|
|
58
|
-
});
|
|
59
|
-
cursor = response.cursor ?? "";
|
|
60
|
-
complete = response.list_complete;
|
|
61
|
-
if (response.keys.length > 0) {
|
|
62
|
-
await Promise.all(
|
|
63
|
-
response.keys.map((key) => {
|
|
64
|
-
return this.store.delete(key.name);
|
|
65
|
-
})
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
} while (!complete);
|
|
69
|
-
}
|
|
70
|
-
on(_event, _listener) {
|
|
71
|
-
return this;
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
// src/utils/index.ts
|
|
76
|
-
import qs from "qs";
|
|
77
|
-
import { cloneDeep as cloneDeep3, reduce } from "lodash-es";
|
|
78
|
-
import JSON52 from "json5";
|
|
79
|
-
|
|
80
|
-
// src/resources.ts
|
|
81
|
-
import { cloneDeep as cloneDeep2 } from "lodash-es";
|
|
82
|
-
|
|
83
17
|
// src/utils/logger.ts
|
|
84
18
|
var logLevels = {
|
|
85
19
|
error: 0,
|
|
@@ -171,6 +105,80 @@ function createTraceId(data) {
|
|
|
171
105
|
return (hash >>> 0).toString(16);
|
|
172
106
|
}
|
|
173
107
|
|
|
108
|
+
// src/cache/cf-worker-kv-keyv-adapter.ts
|
|
109
|
+
var CFWorkerKVKeyvAdapter = class {
|
|
110
|
+
store;
|
|
111
|
+
namespace;
|
|
112
|
+
// magically passed in from Keyv
|
|
113
|
+
opts;
|
|
114
|
+
constructor(store) {
|
|
115
|
+
this.store = store;
|
|
116
|
+
this.opts = null;
|
|
117
|
+
this.namespace = "dummy";
|
|
118
|
+
}
|
|
119
|
+
async has(key) {
|
|
120
|
+
const stream = await this.store.get(key, "stream");
|
|
121
|
+
if (stream !== null) {
|
|
122
|
+
await stream.cancel();
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
async get(key) {
|
|
128
|
+
const trace = createTraceId();
|
|
129
|
+
logger.debug("[SDK] kv.get", { key, trace });
|
|
130
|
+
const value = await this.store.get(key);
|
|
131
|
+
const result = value !== null ? value : void 0;
|
|
132
|
+
logger.debug(`[SDK] kv.get ${value !== null ? "HIT" : "MISS"}`, {
|
|
133
|
+
key,
|
|
134
|
+
trace
|
|
135
|
+
});
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
set(key, value, ttl) {
|
|
139
|
+
if (typeof ttl === "number") {
|
|
140
|
+
ttl = Math.max(60, ttl / 1e3);
|
|
141
|
+
}
|
|
142
|
+
logger.debug("[SDK] kv.set", { key });
|
|
143
|
+
return this.store.put(key, value, { expirationTtl: ttl });
|
|
144
|
+
}
|
|
145
|
+
async delete(key) {
|
|
146
|
+
await this.store.delete(key);
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
async clear() {
|
|
150
|
+
let cursor = "";
|
|
151
|
+
let complete = false;
|
|
152
|
+
const prefix = `${this.namespace}:`;
|
|
153
|
+
do {
|
|
154
|
+
const response = await this.store.list({
|
|
155
|
+
prefix,
|
|
156
|
+
cursor: cursor || void 0
|
|
157
|
+
});
|
|
158
|
+
cursor = response.cursor ?? "";
|
|
159
|
+
complete = response.list_complete;
|
|
160
|
+
if (response.keys.length > 0) {
|
|
161
|
+
await Promise.all(
|
|
162
|
+
response.keys.map((key) => {
|
|
163
|
+
return this.store.delete(key.name);
|
|
164
|
+
})
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
} while (!complete);
|
|
168
|
+
}
|
|
169
|
+
on(_event, _listener) {
|
|
170
|
+
return this;
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
// src/utils/index.ts
|
|
175
|
+
import qs from "qs";
|
|
176
|
+
import { cloneDeep as cloneDeep3, reduce } from "lodash-es";
|
|
177
|
+
import JSON52 from "json5";
|
|
178
|
+
|
|
179
|
+
// src/resources.ts
|
|
180
|
+
import { cloneDeep as cloneDeep2 } from "lodash-es";
|
|
181
|
+
|
|
174
182
|
// src/liquid/utils.ts
|
|
175
183
|
import { Drop } from "liquidjs";
|
|
176
184
|
|
|
@@ -814,6 +822,7 @@ var SwellStorefrontCollection = class _SwellStorefrontCollection extends SwellSt
|
|
|
814
822
|
this._collection,
|
|
815
823
|
this._query,
|
|
816
824
|
this._swell.queryParams,
|
|
825
|
+
// TODO: consider to exlcude
|
|
817
826
|
this._getterHash
|
|
818
827
|
],
|
|
819
828
|
getter,
|
|
@@ -942,6 +951,7 @@ var SwellStorefrontRecord = class extends SwellStorefrontResource {
|
|
|
942
951
|
this._id,
|
|
943
952
|
this._query,
|
|
944
953
|
this._swell.queryParams,
|
|
954
|
+
// TODO: consider to exlcude
|
|
945
955
|
this._getterHash
|
|
946
956
|
],
|
|
947
957
|
getter,
|
|
@@ -7170,8 +7180,6 @@ var Cache = class {
|
|
|
7170
7180
|
* This will always return the cached value immediately if exists
|
|
7171
7181
|
*/
|
|
7172
7182
|
async fetchSWR(key, fetchFn, ttl = DEFAULT_SWR_TTL, isCacheble = true) {
|
|
7173
|
-
const trace = createTraceId();
|
|
7174
|
-
logger.debug("[SDK] Cache fetch start", { key, trace });
|
|
7175
7183
|
const cacheValue = isCacheble ? await this.client.get(key) : void 0;
|
|
7176
7184
|
let promise = SWR_PROMISE_MAP.get(key);
|
|
7177
7185
|
if (promise === void 0) {
|
|
@@ -7179,7 +7187,6 @@ var Cache = class {
|
|
|
7179
7187
|
const isNull = value === null || value === void 0;
|
|
7180
7188
|
if (isCacheble) {
|
|
7181
7189
|
await this.client.set(key, isNull ? NULL_VALUE : value, ttl);
|
|
7182
|
-
logger.debug("[SDK] Cache update done", { key, trace });
|
|
7183
7190
|
}
|
|
7184
7191
|
return value;
|
|
7185
7192
|
}).finally(() => {
|
|
@@ -7191,12 +7198,9 @@ var Cache = class {
|
|
|
7191
7198
|
this.workerCtx.waitUntil(promise);
|
|
7192
7199
|
}
|
|
7193
7200
|
if (cacheValue !== void 0) {
|
|
7194
|
-
logger.debug("[SDK] Cache check done", { status: "HIT", key, trace });
|
|
7195
7201
|
return cacheValue === NULL_VALUE ? null : cacheValue;
|
|
7196
7202
|
}
|
|
7197
|
-
logger.debug("[SDK] Cache check done", { status: "MISS", key, trace });
|
|
7198
7203
|
const result = await promise;
|
|
7199
|
-
logger.debug("[SDK] Cache fetch end", { key, trace });
|
|
7200
7204
|
return result;
|
|
7201
7205
|
}
|
|
7202
7206
|
async get(key) {
|
|
@@ -7703,6 +7707,384 @@ var WorkerCacheProxy = class {
|
|
|
7703
7707
|
}
|
|
7704
7708
|
};
|
|
7705
7709
|
|
|
7710
|
+
// src/cache/worker-html-cache.ts
|
|
7711
|
+
var CACHE_NAME2 = "swell-html-v1";
|
|
7712
|
+
var CACHE_KEY_ORIGIN2 = "https://cache.swell.store";
|
|
7713
|
+
var TTL_CONFIG = {
|
|
7714
|
+
LIVE: {
|
|
7715
|
+
DEFAULT: 300,
|
|
7716
|
+
// 5 minutes
|
|
7717
|
+
HOME: 300,
|
|
7718
|
+
// 5 minutes
|
|
7719
|
+
PRODUCT: 600,
|
|
7720
|
+
// 10 minutes
|
|
7721
|
+
COLLECTION: 900,
|
|
7722
|
+
// 15 minutes
|
|
7723
|
+
PAGE: 3600,
|
|
7724
|
+
// 1 hour
|
|
7725
|
+
BLOG: 1800,
|
|
7726
|
+
// 30 minutes
|
|
7727
|
+
SWR: 3600
|
|
7728
|
+
// 1 hour stale-while-revalidate
|
|
7729
|
+
},
|
|
7730
|
+
PREVIEW: {
|
|
7731
|
+
DEFAULT: 5,
|
|
7732
|
+
// 1 minute - faster updates in preview
|
|
7733
|
+
HOME: 5,
|
|
7734
|
+
// 1 minute
|
|
7735
|
+
PRODUCT: 5,
|
|
7736
|
+
// 2 minutes
|
|
7737
|
+
COLLECTION: 5,
|
|
7738
|
+
// 3 minutes
|
|
7739
|
+
PAGE: 5,
|
|
7740
|
+
// 5 minutes
|
|
7741
|
+
BLOG: 5,
|
|
7742
|
+
// 5 minutes
|
|
7743
|
+
SWR: 600
|
|
7744
|
+
// 10 minutes stale-while-revalidate
|
|
7745
|
+
}
|
|
7746
|
+
};
|
|
7747
|
+
var WorkerHtmlCache = class {
|
|
7748
|
+
epoch;
|
|
7749
|
+
constructor(epoch) {
|
|
7750
|
+
this.epoch = epoch;
|
|
7751
|
+
}
|
|
7752
|
+
async get(request) {
|
|
7753
|
+
const trace = createTraceId();
|
|
7754
|
+
if (request.method !== "GET") {
|
|
7755
|
+
logger.debug("[SDK Html-cache] non-cacheable", { trace });
|
|
7756
|
+
return { found: false, cacheable: false };
|
|
7757
|
+
}
|
|
7758
|
+
if (!this.isCacheable(request)) {
|
|
7759
|
+
logger.debug("[SDK Html-cache] non-cacheable", { trace });
|
|
7760
|
+
return { found: false, cacheable: false };
|
|
7761
|
+
}
|
|
7762
|
+
try {
|
|
7763
|
+
const cache = await caches.open(CACHE_NAME2 + this.epoch);
|
|
7764
|
+
const cacheKey = this.buildCacheKey(request);
|
|
7765
|
+
const cached = await cache.match(cacheKey);
|
|
7766
|
+
if (!cached) {
|
|
7767
|
+
logger.debug("[SDK Html-cache] cacheable, MISS", { trace });
|
|
7768
|
+
return { found: false, cacheable: true };
|
|
7769
|
+
}
|
|
7770
|
+
const age = this.getResponseAge(cached);
|
|
7771
|
+
const ttl = parseInt(cached.headers.get("X-Original-TTL") || "") || this.getTTLForRequest(request);
|
|
7772
|
+
const swr = parseInt(cached.headers.get("X-Original-SWR") || "") || this.getSWRForRequest(request);
|
|
7773
|
+
const isStale = age >= ttl;
|
|
7774
|
+
const isExpired = age >= ttl + swr;
|
|
7775
|
+
if (!isExpired) {
|
|
7776
|
+
logger.debug("[SDK Html-cache] cacheable, HIT", {
|
|
7777
|
+
stale: isStale,
|
|
7778
|
+
age,
|
|
7779
|
+
trace
|
|
7780
|
+
});
|
|
7781
|
+
const clientResponse = this.buildClientResponse(
|
|
7782
|
+
cached,
|
|
7783
|
+
ttl,
|
|
7784
|
+
swr,
|
|
7785
|
+
isStale,
|
|
7786
|
+
age
|
|
7787
|
+
);
|
|
7788
|
+
return {
|
|
7789
|
+
found: true,
|
|
7790
|
+
stale: isStale,
|
|
7791
|
+
response: clientResponse,
|
|
7792
|
+
cacheable: true,
|
|
7793
|
+
age: Math.floor(age)
|
|
7794
|
+
};
|
|
7795
|
+
}
|
|
7796
|
+
logger.debug("[SDK Html-cache] cacheable, hit, expired", { trace });
|
|
7797
|
+
return { found: false, cacheable: true };
|
|
7798
|
+
} catch (_) {
|
|
7799
|
+
logger.warn("[SDK Html-cache] no get support", { trace });
|
|
7800
|
+
return null;
|
|
7801
|
+
}
|
|
7802
|
+
}
|
|
7803
|
+
// 304 support
|
|
7804
|
+
async getWithConditionals(request) {
|
|
7805
|
+
const result = await this.get(request);
|
|
7806
|
+
if (!result?.found || result.stale) {
|
|
7807
|
+
return result;
|
|
7808
|
+
}
|
|
7809
|
+
const ifModifiedSince = request.headers.get("If-Modified-Since");
|
|
7810
|
+
const ifNoneMatch = request.headers.get("If-None-Match");
|
|
7811
|
+
if ((ifModifiedSince || ifNoneMatch) && result.response) {
|
|
7812
|
+
const lastModified = result.response.headers.get("Last-Modified");
|
|
7813
|
+
const etag = result.response.headers.get("ETag");
|
|
7814
|
+
if (this.checkNotModified(ifModifiedSince, ifNoneMatch, lastModified, etag)) {
|
|
7815
|
+
result.notModified = true;
|
|
7816
|
+
result.conditional304 = new Response(null, {
|
|
7817
|
+
status: 304,
|
|
7818
|
+
headers: {
|
|
7819
|
+
"Last-Modified": lastModified || "",
|
|
7820
|
+
ETag: etag || "",
|
|
7821
|
+
"Cache-Control": result.response.headers.get("Cache-Control") || "",
|
|
7822
|
+
"Cloudflare-CDN-Cache-Control": result.response.headers.get("Cloudflare-CDN-Cache-Control") || "",
|
|
7823
|
+
"X-Cache-Status": "HIT-304"
|
|
7824
|
+
}
|
|
7825
|
+
});
|
|
7826
|
+
}
|
|
7827
|
+
}
|
|
7828
|
+
return result;
|
|
7829
|
+
}
|
|
7830
|
+
checkNotModified(ifModifiedSince, ifNoneMatch, lastModified, etag) {
|
|
7831
|
+
if (ifNoneMatch && etag) {
|
|
7832
|
+
return ifNoneMatch === etag;
|
|
7833
|
+
}
|
|
7834
|
+
if (ifModifiedSince && lastModified) {
|
|
7835
|
+
const ifModDate = new Date(ifModifiedSince);
|
|
7836
|
+
const lastModDate = new Date(lastModified);
|
|
7837
|
+
return !isNaN(ifModDate.getTime()) && !isNaN(lastModDate.getTime()) && ifModDate >= lastModDate;
|
|
7838
|
+
}
|
|
7839
|
+
return false;
|
|
7840
|
+
}
|
|
7841
|
+
createRevalidationRequest(request) {
|
|
7842
|
+
const headers = new Headers(request.headers);
|
|
7843
|
+
headers.set("X-Cache-Bypass", "revalidation");
|
|
7844
|
+
headers.delete("If-None-Match");
|
|
7845
|
+
headers.delete("If-Modified-Since");
|
|
7846
|
+
headers.delete("Cache-Control");
|
|
7847
|
+
headers.delete("Pragma");
|
|
7848
|
+
return new Request(request.url, {
|
|
7849
|
+
method: "GET",
|
|
7850
|
+
headers
|
|
7851
|
+
});
|
|
7852
|
+
}
|
|
7853
|
+
async put(request, response) {
|
|
7854
|
+
const trace = createTraceId();
|
|
7855
|
+
if (request.method !== "GET" || !response.ok) {
|
|
7856
|
+
logger.debug("[SDK Html-cache] put skipped", { trace });
|
|
7857
|
+
return;
|
|
7858
|
+
}
|
|
7859
|
+
if (!this.isCacheable(request) || !this.isResponseCacheable(response)) {
|
|
7860
|
+
logger.debug("[SDK Html-cache] put skipped, non-cacheable", {
|
|
7861
|
+
trace
|
|
7862
|
+
});
|
|
7863
|
+
return;
|
|
7864
|
+
}
|
|
7865
|
+
try {
|
|
7866
|
+
const cache = await caches.open(CACHE_NAME2 + this.epoch);
|
|
7867
|
+
const cacheKey = this.buildCacheKey(request);
|
|
7868
|
+
await cache.delete(cacheKey);
|
|
7869
|
+
const ttl = this.getTTLForRequest(request);
|
|
7870
|
+
const swr = this.getSWRForRequest(request);
|
|
7871
|
+
const headers = new Headers(response.headers);
|
|
7872
|
+
const existingCacheControl = response.headers.get("Cache-Control");
|
|
7873
|
+
if (!existingCacheControl || existingCacheControl === "public") {
|
|
7874
|
+
const internalMaxAge = ttl + swr;
|
|
7875
|
+
headers.set("Cache-Control", `public, max-age=${internalMaxAge}`);
|
|
7876
|
+
}
|
|
7877
|
+
const cacheTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
7878
|
+
headers.set("X-Cache-Time", cacheTime);
|
|
7879
|
+
headers.set("X-Original-TTL", ttl.toString());
|
|
7880
|
+
headers.set("X-Original-SWR", swr.toString());
|
|
7881
|
+
if (!headers.get("Last-Modified")) {
|
|
7882
|
+
headers.set("Last-Modified", new Date(cacheTime).toUTCString());
|
|
7883
|
+
}
|
|
7884
|
+
const cacheableResponse = new Response(response.body, {
|
|
7885
|
+
status: response.status,
|
|
7886
|
+
statusText: response.statusText,
|
|
7887
|
+
headers
|
|
7888
|
+
});
|
|
7889
|
+
await cache.put(cacheKey, cacheableResponse);
|
|
7890
|
+
logger.debug("[SDK Html-cache] put done", { trace });
|
|
7891
|
+
} catch (_) {
|
|
7892
|
+
logger.warn("[SDK Html-cache] no put support", { trace });
|
|
7893
|
+
}
|
|
7894
|
+
}
|
|
7895
|
+
buildClientResponse(cachedResponse, ttl, swr, isStale, age) {
|
|
7896
|
+
const headers = new Headers(cachedResponse.headers);
|
|
7897
|
+
headers.set(
|
|
7898
|
+
"Cache-Control",
|
|
7899
|
+
`public, max-age=${ttl}, stale-while-revalidate=${swr}`
|
|
7900
|
+
);
|
|
7901
|
+
headers.set(
|
|
7902
|
+
"Cloudflare-CDN-Cache-Control",
|
|
7903
|
+
`public, s-maxage=${ttl}, stale-while-revalidate=${swr}, stale-if-error=60`
|
|
7904
|
+
);
|
|
7905
|
+
const cacheTime = headers.get("X-Cache-Time");
|
|
7906
|
+
if (cacheTime) {
|
|
7907
|
+
const lastModified = new Date(cacheTime).toUTCString();
|
|
7908
|
+
headers.set("Last-Modified", lastModified);
|
|
7909
|
+
}
|
|
7910
|
+
headers.set("X-Cache-Status", isStale ? "STALE" : "HIT");
|
|
7911
|
+
headers.set("X-Cache-Age", Math.floor(age).toString());
|
|
7912
|
+
headers.delete("X-Original-TTL");
|
|
7913
|
+
headers.delete("X-Original-SWR");
|
|
7914
|
+
headers.delete("X-Cache-Time");
|
|
7915
|
+
return new Response(cachedResponse.body, {
|
|
7916
|
+
status: cachedResponse.status,
|
|
7917
|
+
statusText: cachedResponse.statusText,
|
|
7918
|
+
headers
|
|
7919
|
+
});
|
|
7920
|
+
}
|
|
7921
|
+
buildCacheKey(request) {
|
|
7922
|
+
const url = new URL(request.url);
|
|
7923
|
+
const versionHash = this.generateVersionHash(request.headers);
|
|
7924
|
+
const normalizedQuery = this.normalizeSearchParams(url.searchParams);
|
|
7925
|
+
const cacheKeyPath = `${versionHash}${url.pathname}`;
|
|
7926
|
+
const keyUrl = new URL(`${CACHE_KEY_ORIGIN2}${cacheKeyPath}`);
|
|
7927
|
+
if (normalizedQuery) {
|
|
7928
|
+
keyUrl.search = `?${normalizedQuery}`;
|
|
7929
|
+
}
|
|
7930
|
+
const sanitizedHeaders = this.sanitizeHeaders(request.headers);
|
|
7931
|
+
return new Request(keyUrl.toString(), {
|
|
7932
|
+
method: "GET",
|
|
7933
|
+
headers: sanitizedHeaders
|
|
7934
|
+
});
|
|
7935
|
+
}
|
|
7936
|
+
sanitizeHeaders(originalHeaders) {
|
|
7937
|
+
const CACHE_RELEVANT_HEADERS = [
|
|
7938
|
+
// Content negotiation (affects response format)
|
|
7939
|
+
"accept",
|
|
7940
|
+
"accept-language"
|
|
7941
|
+
];
|
|
7942
|
+
const sanitized = new Headers();
|
|
7943
|
+
CACHE_RELEVANT_HEADERS.forEach((header) => {
|
|
7944
|
+
const value = originalHeaders.get(header);
|
|
7945
|
+
if (value) {
|
|
7946
|
+
sanitized.set(header, value);
|
|
7947
|
+
}
|
|
7948
|
+
});
|
|
7949
|
+
return sanitized;
|
|
7950
|
+
}
|
|
7951
|
+
generateVersionHash(headers) {
|
|
7952
|
+
const swellData = this.extractSwellData(headers);
|
|
7953
|
+
const versionFactors = {
|
|
7954
|
+
store: headers.get("swell-storefront-id") || "",
|
|
7955
|
+
auth: headers.get("swell-access-token") || "",
|
|
7956
|
+
theme: headers.get("swell-theme-version-hash") || "",
|
|
7957
|
+
modified: headers.get("swell-cache-modified") || "",
|
|
7958
|
+
currency: swellData["swell-currency"] || "USD",
|
|
7959
|
+
locale: headers.get("x-locale") || headers.get("accept-language")?.split(",")[0] || "default",
|
|
7960
|
+
context: headers.get("swell-storefront-context"),
|
|
7961
|
+
epoch: this.epoch
|
|
7962
|
+
};
|
|
7963
|
+
return md5(JSON.stringify(versionFactors));
|
|
7964
|
+
}
|
|
7965
|
+
extractSwellData(headers) {
|
|
7966
|
+
const cookie = headers.get("cookie");
|
|
7967
|
+
if (!cookie) return {};
|
|
7968
|
+
const swellDataMatch = cookie.match(/swell-data=([^;]+)/);
|
|
7969
|
+
if (!swellDataMatch) return {};
|
|
7970
|
+
try {
|
|
7971
|
+
const parsed = JSON.parse(decodeURIComponent(swellDataMatch[1]));
|
|
7972
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
7973
|
+
return parsed;
|
|
7974
|
+
}
|
|
7975
|
+
return {};
|
|
7976
|
+
} catch {
|
|
7977
|
+
return {};
|
|
7978
|
+
}
|
|
7979
|
+
}
|
|
7980
|
+
isCacheable(request) {
|
|
7981
|
+
const url = new URL(request.url);
|
|
7982
|
+
const headers = request.headers;
|
|
7983
|
+
if (headers.get("swell-deployment-mode") === "editor") {
|
|
7984
|
+
return false;
|
|
7985
|
+
}
|
|
7986
|
+
const skipPaths = ["/checkout"];
|
|
7987
|
+
if (skipPaths.some((path) => url.pathname.startsWith(path))) {
|
|
7988
|
+
return false;
|
|
7989
|
+
}
|
|
7990
|
+
if (headers.get("cache-control")?.includes("no-cache")) {
|
|
7991
|
+
return false;
|
|
7992
|
+
}
|
|
7993
|
+
return true;
|
|
7994
|
+
}
|
|
7995
|
+
isResponseCacheable(response) {
|
|
7996
|
+
const contentType = response.headers.get("content-type");
|
|
7997
|
+
if (!contentType?.includes("text/html")) {
|
|
7998
|
+
return false;
|
|
7999
|
+
}
|
|
8000
|
+
if (response.headers.get("set-cookie")) {
|
|
8001
|
+
return false;
|
|
8002
|
+
}
|
|
8003
|
+
const cacheControl = response.headers.get("cache-control");
|
|
8004
|
+
if (cacheControl?.includes("no-store") || cacheControl?.includes("private")) {
|
|
8005
|
+
return false;
|
|
8006
|
+
}
|
|
8007
|
+
return true;
|
|
8008
|
+
}
|
|
8009
|
+
getDeploymentMode(headers) {
|
|
8010
|
+
const mode = headers.get("swell-deployment-mode");
|
|
8011
|
+
if (mode === "preview" || mode === "editor") {
|
|
8012
|
+
return mode;
|
|
8013
|
+
}
|
|
8014
|
+
return "live";
|
|
8015
|
+
}
|
|
8016
|
+
getTTLForRequest(request) {
|
|
8017
|
+
const url = new URL(request.url);
|
|
8018
|
+
const path = url.pathname;
|
|
8019
|
+
const mode = this.getDeploymentMode(request.headers);
|
|
8020
|
+
if (mode === "editor") {
|
|
8021
|
+
return 0;
|
|
8022
|
+
}
|
|
8023
|
+
const config = mode === "preview" ? TTL_CONFIG.PREVIEW : TTL_CONFIG.LIVE;
|
|
8024
|
+
if (path === "/") {
|
|
8025
|
+
return config.HOME;
|
|
8026
|
+
}
|
|
8027
|
+
if (path.startsWith("/products/")) {
|
|
8028
|
+
return config.PRODUCT;
|
|
8029
|
+
}
|
|
8030
|
+
if (path.startsWith("/categories/")) {
|
|
8031
|
+
return config.COLLECTION;
|
|
8032
|
+
}
|
|
8033
|
+
if (path.startsWith("/pages/")) {
|
|
8034
|
+
return config.PAGE;
|
|
8035
|
+
}
|
|
8036
|
+
if (path.startsWith("/blogs/")) {
|
|
8037
|
+
return config.BLOG;
|
|
8038
|
+
}
|
|
8039
|
+
return config.DEFAULT;
|
|
8040
|
+
}
|
|
8041
|
+
getSWRForRequest(request) {
|
|
8042
|
+
const mode = this.getDeploymentMode(request.headers);
|
|
8043
|
+
if (mode === "editor") {
|
|
8044
|
+
return 0;
|
|
8045
|
+
}
|
|
8046
|
+
return mode === "preview" ? TTL_CONFIG.PREVIEW.SWR : TTL_CONFIG.LIVE.SWR;
|
|
8047
|
+
}
|
|
8048
|
+
getResponseAge(response) {
|
|
8049
|
+
const cacheTime = response.headers.get("X-Cache-Time");
|
|
8050
|
+
if (!cacheTime) {
|
|
8051
|
+
return Infinity;
|
|
8052
|
+
}
|
|
8053
|
+
const cacheDate = new Date(cacheTime);
|
|
8054
|
+
if (isNaN(cacheDate.getTime())) {
|
|
8055
|
+
return Infinity;
|
|
8056
|
+
}
|
|
8057
|
+
const age = (Date.now() - cacheDate.getTime()) / 1e3;
|
|
8058
|
+
return Math.max(0, age);
|
|
8059
|
+
}
|
|
8060
|
+
normalizeSearchParams(searchParams) {
|
|
8061
|
+
const ignoredParams = [
|
|
8062
|
+
"utm_source",
|
|
8063
|
+
"utm_medium",
|
|
8064
|
+
"utm_campaign",
|
|
8065
|
+
"utm_content",
|
|
8066
|
+
"utm_term",
|
|
8067
|
+
"fbclid",
|
|
8068
|
+
"gclid",
|
|
8069
|
+
"gbraid",
|
|
8070
|
+
"wbraid",
|
|
8071
|
+
"ref",
|
|
8072
|
+
"source",
|
|
8073
|
+
"mc_cid",
|
|
8074
|
+
"mc_eid"
|
|
8075
|
+
];
|
|
8076
|
+
const relevantParams = [];
|
|
8077
|
+
searchParams.forEach((value, key) => {
|
|
8078
|
+
if (!ignoredParams.includes(key)) {
|
|
8079
|
+
relevantParams.push(
|
|
8080
|
+
`${encodeURIComponent(key)}=${encodeURIComponent(value)}`
|
|
8081
|
+
);
|
|
8082
|
+
}
|
|
8083
|
+
});
|
|
8084
|
+
return relevantParams.sort().join("&");
|
|
8085
|
+
}
|
|
8086
|
+
};
|
|
8087
|
+
|
|
7706
8088
|
// src/resources/addresses.ts
|
|
7707
8089
|
var SwellAddresses = class extends SwellStorefrontCollection {
|
|
7708
8090
|
constructor(swell, query) {
|
|
@@ -8530,13 +8912,19 @@ var Swell = class _Swell {
|
|
|
8530
8912
|
const storefrontRequest = storefront.request;
|
|
8531
8913
|
return (method, url, id, data, opt) => {
|
|
8532
8914
|
if (this.isStorefrontRequestCacheable(method, url, opt)) {
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
8536
|
-
|
|
8537
|
-
|
|
8538
|
-
|
|
8539
|
-
|
|
8915
|
+
const key = getCacheKey("request", [
|
|
8916
|
+
this.instanceId,
|
|
8917
|
+
method,
|
|
8918
|
+
url,
|
|
8919
|
+
id,
|
|
8920
|
+
data,
|
|
8921
|
+
opt
|
|
8922
|
+
]);
|
|
8923
|
+
return this.getRequestCache().fetchSWR(key, () => {
|
|
8924
|
+
const requestUrl = id ? `${url}/${id}` : url;
|
|
8925
|
+
logger.debug("[SDK] Cacheable API request", { url: requestUrl, key });
|
|
8926
|
+
return storefrontRequest(method, url, id, data, opt);
|
|
8927
|
+
});
|
|
8540
8928
|
}
|
|
8541
8929
|
switch (method) {
|
|
8542
8930
|
case "delete":
|
|
@@ -8583,7 +8971,9 @@ var Swell = class _Swell {
|
|
|
8583
8971
|
};
|
|
8584
8972
|
function getCacheKey(key, args) {
|
|
8585
8973
|
if (Array.isArray(args) && args.length > 0) {
|
|
8586
|
-
|
|
8974
|
+
const fullKey = `${key}_${md5(JSON.stringify(args))}`;
|
|
8975
|
+
logger.debug(`[SDK] make cache key: ${fullKey}`);
|
|
8976
|
+
return fullKey;
|
|
8587
8977
|
}
|
|
8588
8978
|
return key;
|
|
8589
8979
|
}
|
|
@@ -22365,6 +22755,7 @@ export {
|
|
|
22365
22755
|
ThemeFont,
|
|
22366
22756
|
ThemeForm,
|
|
22367
22757
|
ThemeFormErrors,
|
|
22758
|
+
WorkerHtmlCache,
|
|
22368
22759
|
adaptShopifyFontData,
|
|
22369
22760
|
adaptShopifyFormData,
|
|
22370
22761
|
adaptShopifyMenuData,
|