@usethrottle/catalog 1.2.0 → 1.4.0
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/CHANGELOG.md +27 -0
- package/README.md +111 -15
- package/dist/admin.cjs +16 -16
- package/dist/admin.d.cts +15 -2
- package/dist/admin.d.ts +15 -2
- package/dist/admin.js +1 -1
- package/dist/{catalog-error-yTBMAdCv.d.cts → catalog-error-BKN5hNWP.d.cts} +11 -1
- package/dist/{catalog-error-7DCsTyB2.d.ts → catalog-error-BnabMMEy.d.ts} +11 -1
- package/dist/{chunk-JNBKKAMP.js → chunk-3FX2HISB.js} +97 -2
- package/dist/{chunk-B2DYAHNR.cjs → chunk-J2GHGQY6.cjs} +334 -43
- package/dist/{chunk-TDMDOHD3.cjs → chunk-OKWXS3FD.cjs} +110 -15
- package/dist/chunk-PZ3SFYH4.cjs +192 -0
- package/dist/chunk-SN6STYPW.js +192 -0
- package/dist/{chunk-55G4ZTD5.js → chunk-VJHA7J7B.js} +315 -24
- package/dist/{client-Dm6I4nAZ.d.ts → client-B6CsU_v9.d.ts} +1 -1
- package/dist/{client-BrHJCyBP.d.cts → client-terkEl6u.d.cts} +1 -1
- package/dist/{contract-types-BPSzY_Co.d.cts → contract-types-D2-SSPM9.d.cts} +241 -11
- package/dist/{contract-types-BPSzY_Co.d.ts → contract-types-D2-SSPM9.d.ts} +241 -11
- package/dist/index.cjs +34 -2
- package/dist/index.d.cts +56 -7
- package/dist/index.d.ts +56 -7
- package/dist/index.js +35 -3
- package/dist/next.cjs +180 -0
- package/dist/next.d.cts +60 -0
- package/dist/next.d.ts +60 -0
- package/dist/next.js +180 -0
- package/dist/react-extras.cjs +27 -9
- package/dist/react-extras.d.cts +7 -4
- package/dist/react-extras.d.ts +7 -4
- package/dist/react-extras.js +20 -2
- package/dist/react.cjs +130 -54
- package/dist/react.d.cts +52 -11
- package/dist/react.d.ts +52 -11
- package/dist/react.js +112 -36
- package/dist/server.cjs +58 -66
- package/dist/server.d.cts +58 -10
- package/dist/server.d.ts +58 -10
- package/dist/server.js +52 -60
- package/dist/{types-BlYCKzB8.d.ts → types-jNpOwEUw.d.cts} +81 -8
- package/dist/{types-BTrqSprj.d.cts → types-z57bkjjB.d.ts} +81 -8
- package/dist/url.d.cts +2 -1
- package/dist/url.d.ts +2 -1
- package/dist/{use-query-QOEBuYlp.d.ts → use-query-COqRZJnC.d.ts} +1 -1
- package/dist/{use-query-BZgjxGPO.d.cts → use-query-H1xgL3_e.d.cts} +1 -1
- package/package.json +17 -2
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
var
|
|
9
|
+
var _chunkJ2GHGQY6cjs = require('./chunk-J2GHGQY6.cjs');
|
|
10
10
|
|
|
11
11
|
// src/react/provider.tsx
|
|
12
12
|
|
|
@@ -32,7 +32,7 @@ function createStore(client, options = {}) {
|
|
|
32
32
|
let until = 0;
|
|
33
33
|
let cause;
|
|
34
34
|
let pauseTimer;
|
|
35
|
-
const pausedError = () => new (0,
|
|
35
|
+
const pausedError = () => new (0, _chunkJ2GHGQY6cjs.RateLimitedError)({
|
|
36
36
|
code: _nullishCoalesce(_optionalChain([cause, 'optionalAccess', _ => _.code]), () => ( "RATE_LIMITED")),
|
|
37
37
|
message: _nullishCoalesce(_optionalChain([cause, 'optionalAccess', _2 => _2.message]), () => ( "Too many requests.")),
|
|
38
38
|
statusCode: 429,
|
|
@@ -54,7 +54,7 @@ function createStore(client, options = {}) {
|
|
|
54
54
|
retries: 0
|
|
55
55
|
};
|
|
56
56
|
for (const [oldKey, old] of entries) {
|
|
57
|
-
if (entries.size <
|
|
57
|
+
if (entries.size < _chunkJ2GHGQY6cjs.CACHE_MAX_ENTRIES) break;
|
|
58
58
|
if (old.subs.size === 0 && old.flight === void 0) {
|
|
59
59
|
clearTimeout(old.timer);
|
|
60
60
|
entries.delete(oldKey);
|
|
@@ -73,7 +73,7 @@ function createStore(client, options = {}) {
|
|
|
73
73
|
else entry.indexing = false;
|
|
74
74
|
}, ms);
|
|
75
75
|
};
|
|
76
|
-
function fetchKey(key, run, { force = false, staleMs =
|
|
76
|
+
function fetchKey(key, run, { force = false, staleMs = _chunkJ2GHGQY6cjs.STALE_MS } = {}) {
|
|
77
77
|
const entry = touch(key);
|
|
78
78
|
entry.run = run;
|
|
79
79
|
if (entry.promise !== void 0 && !_optionalChain([entry, 'access', _4 => _4.flight, 'optionalAccess', _5 => _5.signal, 'access', _6 => _6.aborted]))
|
|
@@ -125,7 +125,7 @@ function createStore(client, options = {}) {
|
|
|
125
125
|
return;
|
|
126
126
|
}
|
|
127
127
|
if (_optionalChain([result, 'access', _7 => _7.data, 'optionalAccess', _8 => _8.indexing]) === true) {
|
|
128
|
-
if (!entry.indexing) later(key, entry,
|
|
128
|
+
if (!entry.indexing) later(key, entry, _chunkJ2GHGQY6cjs.INDEXING_REVALIDATE_MS);
|
|
129
129
|
} else {
|
|
130
130
|
entry.indexing = false;
|
|
131
131
|
}
|
|
@@ -138,7 +138,7 @@ function createStore(client, options = {}) {
|
|
|
138
138
|
},
|
|
139
139
|
(error) => {
|
|
140
140
|
if (!current()) return;
|
|
141
|
-
const retryMs = (_nullishCoalesce(error.retryAfterSeconds, () => (
|
|
141
|
+
const retryMs = (_nullishCoalesce(error.retryAfterSeconds, () => ( _chunkJ2GHGQY6cjs.RATE_LIMIT_DEFAULT_RETRY_S))) * 1e3;
|
|
142
142
|
if (error.statusCode === 429 && error.code === "RATE_LIMITED")
|
|
143
143
|
pause(now() + retryMs, error);
|
|
144
144
|
else if (error.code === "STOREFRONT_INDEXING") {
|
|
@@ -183,6 +183,21 @@ function createStore(client, options = {}) {
|
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
185
|
}
|
|
186
|
+
function invalidate() {
|
|
187
|
+
for (const [key, entry] of [...entries]) {
|
|
188
|
+
clearTimeout(entry.timer);
|
|
189
|
+
clearTimeout(entry.retry);
|
|
190
|
+
_optionalChain([entry, 'access', _12 => _12.flight, 'optionalAccess', _13 => _13.abort, 'call', _14 => _14()]);
|
|
191
|
+
if (entry.subs.size === 0) {
|
|
192
|
+
entries.delete(key);
|
|
193
|
+
} else {
|
|
194
|
+
entry.etag = entry.flight = entry.promise = void 0;
|
|
195
|
+
entry.indexing = false;
|
|
196
|
+
entry.retries = 0;
|
|
197
|
+
if (entry.run) void fetchKey(key, entry.run, { force: true });
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
186
201
|
return {
|
|
187
202
|
subscribe(key, listener) {
|
|
188
203
|
const entry = touch(key);
|
|
@@ -190,11 +205,11 @@ function createStore(client, options = {}) {
|
|
|
190
205
|
return () => {
|
|
191
206
|
entry.subs.delete(listener);
|
|
192
207
|
void done.then(() => {
|
|
193
|
-
if (entry.subs.size === 0) _optionalChain([entry, 'access',
|
|
208
|
+
if (entry.subs.size === 0) _optionalChain([entry, 'access', _15 => _15.flight, 'optionalAccess', _16 => _16.abort, 'call', _17 => _17()]);
|
|
194
209
|
});
|
|
195
210
|
};
|
|
196
211
|
},
|
|
197
|
-
get: (key, initial, stale) => key === null ? EMPTY : _nullishCoalesce(_optionalChain([(_nullishCoalesce(entries.get(key), () => ( (initial === void 0 ? void 0 : touch(key, initial, stale))))), 'optionalAccess',
|
|
212
|
+
get: (key, initial, stale) => key === null ? EMPTY : _nullishCoalesce(_optionalChain([(_nullishCoalesce(entries.get(key), () => ( (initial === void 0 ? void 0 : touch(key, initial, stale))))), 'optionalAccess', _18 => _18.snap]), () => ( EMPTY)),
|
|
198
213
|
getServer(key, initial, stale) {
|
|
199
214
|
if (key === null || initial === void 0) return EMPTY;
|
|
200
215
|
const entry = _nullishCoalesce(entries.get(key), () => ( touch(key, initial, stale)));
|
|
@@ -202,6 +217,7 @@ function createStore(client, options = {}) {
|
|
|
202
217
|
},
|
|
203
218
|
fetch: fetchKey,
|
|
204
219
|
clear,
|
|
220
|
+
invalidate,
|
|
205
221
|
pause,
|
|
206
222
|
pausedUntil: () => until > now() ? until : 0,
|
|
207
223
|
dispose() {
|
|
@@ -218,6 +234,7 @@ function createStore(client, options = {}) {
|
|
|
218
234
|
var _jsxruntime = require('react/jsx-runtime');
|
|
219
235
|
function createMemoryCartStorage() {
|
|
220
236
|
let id = null;
|
|
237
|
+
const byCurrency = /* @__PURE__ */ new Map();
|
|
221
238
|
return {
|
|
222
239
|
get: () => id,
|
|
223
240
|
set: (value) => {
|
|
@@ -225,6 +242,13 @@ function createMemoryCartStorage() {
|
|
|
225
242
|
},
|
|
226
243
|
remove: () => {
|
|
227
244
|
id = null;
|
|
245
|
+
},
|
|
246
|
+
getFor: (currency) => _nullishCoalesce(byCurrency.get(currency), () => ( null)),
|
|
247
|
+
setFor: (currency, value) => {
|
|
248
|
+
byCurrency.set(currency, value);
|
|
249
|
+
},
|
|
250
|
+
removeFor: (currency) => {
|
|
251
|
+
byCurrency.delete(currency);
|
|
228
252
|
}
|
|
229
253
|
};
|
|
230
254
|
}
|
|
@@ -241,7 +265,7 @@ function CatalogProvider(props) {
|
|
|
241
265
|
const mounted = _react.useRef.call(void 0, null);
|
|
242
266
|
const store = _react.useMemo.call(void 0, () => {
|
|
243
267
|
const next = createStore(client);
|
|
244
|
-
next.pause(_nullishCoalesce(_optionalChain([mounted, 'access',
|
|
268
|
+
next.pause(_nullishCoalesce(_optionalChain([mounted, 'access', _19 => _19.current, 'optionalAccess', _20 => _20.pausedUntil, 'call', _21 => _21()]), () => ( 0)));
|
|
245
269
|
return next;
|
|
246
270
|
}, [client, customerKey]);
|
|
247
271
|
_react.useEffect.call(void 0, () => {
|
|
@@ -273,9 +297,9 @@ function CatalogProvider(props) {
|
|
|
273
297
|
rest.customerCart,
|
|
274
298
|
rest.throttleBaseUrl,
|
|
275
299
|
rest.throttleCheckoutUrl,
|
|
276
|
-
_optionalChain([urls, 'optionalAccess',
|
|
277
|
-
_optionalChain([urls, 'optionalAccess',
|
|
278
|
-
_optionalChain([urls, 'optionalAccess',
|
|
300
|
+
_optionalChain([urls, 'optionalAccess', _22 => _22.returnUrl]),
|
|
301
|
+
_optionalChain([urls, 'optionalAccess', _23 => _23.cancelUrl]),
|
|
302
|
+
_optionalChain([urls, 'optionalAccess', _24 => _24.storefrontUrl])
|
|
279
303
|
]
|
|
280
304
|
);
|
|
281
305
|
cart.context = value;
|
|
@@ -409,9 +433,9 @@ function useDebounced(q, ms) {
|
|
|
409
433
|
return _react.useSyncExternalStore.call(void 0, box.subscribe, box.get, box.get);
|
|
410
434
|
}
|
|
411
435
|
function useSuggest(q, options = {}) {
|
|
412
|
-
const settled = useDebounced(q, _nullishCoalesce(options.debounceMs, () => (
|
|
436
|
+
const settled = useDebounced(q, _nullishCoalesce(options.debounceMs, () => ( _chunkJ2GHGQY6cjs.SUGGEST_DEBOUNCE_MS)));
|
|
413
437
|
const extra = defined({ limit: options.limit });
|
|
414
|
-
const long = (value) => value.trim().length >=
|
|
438
|
+
const long = (value) => value.trim().length >= _chunkJ2GHGQY6cjs.SUGGEST_MIN_CHARS;
|
|
415
439
|
return useQuery(
|
|
416
440
|
"suggest",
|
|
417
441
|
{ q: settled, ...extra },
|
|
@@ -458,6 +482,75 @@ function useConfig(options) {
|
|
|
458
482
|
options
|
|
459
483
|
);
|
|
460
484
|
}
|
|
485
|
+
function useStorefrontSettings(options) {
|
|
486
|
+
return useQuery(
|
|
487
|
+
"settings",
|
|
488
|
+
null,
|
|
489
|
+
(client, call) => client.settings(call),
|
|
490
|
+
options
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
var watches = /* @__PURE__ */ new WeakMap();
|
|
494
|
+
var watchRun = (client, call) => client.config(call);
|
|
495
|
+
var pageDocument = () => Reflect.get(globalThis, "document");
|
|
496
|
+
function watch(store, intervalMs, listener) {
|
|
497
|
+
let w = watches.get(store);
|
|
498
|
+
if (w === void 0) {
|
|
499
|
+
const key = `\0${catalogQueryKey("generation", null)}`;
|
|
500
|
+
const visible = () => pageDocument().visibilityState === "visible";
|
|
501
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
502
|
+
let known;
|
|
503
|
+
let hiddenAt = visible() ? 0 : Date.now();
|
|
504
|
+
const check = async () => {
|
|
505
|
+
if (!visible()) return;
|
|
506
|
+
await store.fetch(key, watchRun, { force: true });
|
|
507
|
+
const data = store.get(key).data;
|
|
508
|
+
if (watches.get(store) !== w || _optionalChain([data, 'optionalAccess', _25 => _25.generation]) === void 0) return;
|
|
509
|
+
const changed = known !== void 0 && data.generation !== known;
|
|
510
|
+
known = data.generation;
|
|
511
|
+
if (changed) {
|
|
512
|
+
store.invalidate();
|
|
513
|
+
for (const { current } of [...listeners]) _optionalChain([current, 'optionalCall', _26 => _26(known)]);
|
|
514
|
+
}
|
|
515
|
+
};
|
|
516
|
+
const onVisibility = () => {
|
|
517
|
+
if (!visible()) hiddenAt = Date.now();
|
|
518
|
+
else {
|
|
519
|
+
if (known === void 0 || Date.now() - hiddenAt >= intervalMs)
|
|
520
|
+
void check();
|
|
521
|
+
hiddenAt = 0;
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
void check();
|
|
525
|
+
const timer = setInterval(() => void check(), intervalMs);
|
|
526
|
+
const doc = pageDocument();
|
|
527
|
+
doc.addEventListener("visibilitychange", onVisibility);
|
|
528
|
+
w = {
|
|
529
|
+
listeners,
|
|
530
|
+
stop() {
|
|
531
|
+
clearInterval(timer);
|
|
532
|
+
doc.removeEventListener("visibilitychange", onVisibility);
|
|
533
|
+
watches.delete(store);
|
|
534
|
+
}
|
|
535
|
+
};
|
|
536
|
+
watches.set(store, w);
|
|
537
|
+
}
|
|
538
|
+
const mine = w;
|
|
539
|
+
mine.listeners.add(listener);
|
|
540
|
+
return () => {
|
|
541
|
+
mine.listeners.delete(listener);
|
|
542
|
+
if (mine.listeners.size === 0) mine.stop();
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
function useGenerationWatch({
|
|
546
|
+
intervalMs = 6e4,
|
|
547
|
+
onChange
|
|
548
|
+
} = {}) {
|
|
549
|
+
const { store } = useCatalogContext();
|
|
550
|
+
const latest = _react.useRef.call(void 0, onChange);
|
|
551
|
+
latest.current = onChange;
|
|
552
|
+
_react.useEffect.call(void 0, () => watch(store, intervalMs, latest), [store, intervalMs]);
|
|
553
|
+
}
|
|
461
554
|
function useFilterValues(key, query = {}, options) {
|
|
462
555
|
return useQuery(
|
|
463
556
|
"filterValues",
|
|
@@ -485,4 +578,6 @@ function useFilterValues(key, query = {}, options) {
|
|
|
485
578
|
|
|
486
579
|
|
|
487
580
|
|
|
488
|
-
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
exports.createMemoryCartStorage = createMemoryCartStorage; exports.useCatalogContext = useCatalogContext; exports.CatalogProvider = CatalogProvider; exports.useCustomerKey = useCustomerKey; exports.useCatalog = useCatalog; exports.catalogQueryKey = catalogQueryKey; exports.useQuery = useQuery; exports.defined = defined; exports.useProducts = useProducts; exports.useProduct = useProduct; exports.useRelated = useRelated; exports.useSuggest = useSuggest; exports.useCategories = useCategories; exports.useCollection = useCollection; exports.useReviews = useReviews; exports.useConfig = useConfig; exports.useStorefrontSettings = useStorefrontSettings; exports.useGenerationWatch = useGenerationWatch; exports.useFilterValues = useFilterValues;
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
var _chunkJ2GHGQY6cjs = require('./chunk-J2GHGQY6.cjs');
|
|
6
|
+
|
|
7
|
+
// src/server/cache-policy.ts
|
|
8
|
+
var UNTIL_CHANGED_REVALIDATE_S = 3600;
|
|
9
|
+
var DEFAULT_CACHE_POLICY = {
|
|
10
|
+
settings: "until-changed",
|
|
11
|
+
navigation: "until-changed",
|
|
12
|
+
pages: "until-changed",
|
|
13
|
+
product: "until-changed",
|
|
14
|
+
listings: "60s",
|
|
15
|
+
facets: "60s",
|
|
16
|
+
related: "60s",
|
|
17
|
+
reviews: "60s",
|
|
18
|
+
search: "60s"
|
|
19
|
+
};
|
|
20
|
+
function decode(segment) {
|
|
21
|
+
try {
|
|
22
|
+
return decodeURIComponent(segment);
|
|
23
|
+
} catch (e) {
|
|
24
|
+
return segment;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function storefrontRoute(path) {
|
|
28
|
+
const bare = _nullishCoalesce(path.split(/[?#]/u, 1)[0], () => ( ""));
|
|
29
|
+
const at = bare.indexOf("/v1/storefront/");
|
|
30
|
+
const parts = (at < 0 ? bare : bare.slice(at + 15)).replace(/^\//u, "");
|
|
31
|
+
const [first, segment, sub, extra] = parts.split("/");
|
|
32
|
+
if (extra !== void 0) return null;
|
|
33
|
+
if (segment === void 0) {
|
|
34
|
+
switch (first) {
|
|
35
|
+
case "config":
|
|
36
|
+
case "products":
|
|
37
|
+
case "pages":
|
|
38
|
+
case "categories":
|
|
39
|
+
case "tags":
|
|
40
|
+
case "collections":
|
|
41
|
+
case "suggest":
|
|
42
|
+
return { route: first };
|
|
43
|
+
default:
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const handle = decode(segment);
|
|
48
|
+
if (handle === "") return null;
|
|
49
|
+
switch (first) {
|
|
50
|
+
case "filters":
|
|
51
|
+
return sub === "values" ? { route: "filters" } : null;
|
|
52
|
+
case "products":
|
|
53
|
+
if (sub === "related" || sub === "reviews") return { route: sub, handle };
|
|
54
|
+
return sub === void 0 ? { route: "product", handle } : null;
|
|
55
|
+
case "pages":
|
|
56
|
+
return sub === void 0 ? { route: "page", handle } : null;
|
|
57
|
+
case "categories":
|
|
58
|
+
return sub === void 0 ? { route: "category", handle } : null;
|
|
59
|
+
case "collections":
|
|
60
|
+
return sub === void 0 ? { route: "collection", handle } : null;
|
|
61
|
+
default:
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
var KIND_OF_ROUTE = {
|
|
66
|
+
config: "settings",
|
|
67
|
+
pages: "pages",
|
|
68
|
+
page: "pages",
|
|
69
|
+
products: "listings",
|
|
70
|
+
product: "product",
|
|
71
|
+
related: "related",
|
|
72
|
+
reviews: "reviews",
|
|
73
|
+
filters: "facets",
|
|
74
|
+
suggest: "search",
|
|
75
|
+
categories: "listings",
|
|
76
|
+
category: "listings",
|
|
77
|
+
collections: "listings",
|
|
78
|
+
collection: "listings",
|
|
79
|
+
tags: "listings"
|
|
80
|
+
};
|
|
81
|
+
function cacheKindForPath(path) {
|
|
82
|
+
const found = storefrontRoute(path);
|
|
83
|
+
return found === null ? null : _nullishCoalesce(KIND_OF_ROUTE[found.route], () => ( null));
|
|
84
|
+
}
|
|
85
|
+
var DURATION = /^(\d+)([sm])$/u;
|
|
86
|
+
function policyToNext(policy) {
|
|
87
|
+
if (policy === "no-store") return "no-store";
|
|
88
|
+
if (policy === "until-changed")
|
|
89
|
+
return { revalidate: UNTIL_CHANGED_REVALIDATE_S };
|
|
90
|
+
const match = typeof policy === "string" ? DURATION.exec(policy) : null;
|
|
91
|
+
if (match === null) {
|
|
92
|
+
throw new (0, _chunkJ2GHGQY6cjs.CatalogError)({
|
|
93
|
+
code: "INVALID_REQUEST",
|
|
94
|
+
message: "A cache policy is 'until-changed', 'no-store' or a duration such as '90s' or '5m'.",
|
|
95
|
+
statusCode: 0,
|
|
96
|
+
source: "client",
|
|
97
|
+
retryable: false
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
const seconds = Number(match[1]) * (match[2] === "m" ? 60 : 1);
|
|
101
|
+
return seconds === 0 ? "no-store" : { revalidate: seconds };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// src/server/min-generation.ts
|
|
105
|
+
var EVERY_STORE = Symbol("every-store");
|
|
106
|
+
var floors = /* @__PURE__ */ new Map();
|
|
107
|
+
function noteMinGeneration(generation, floorKey) {
|
|
108
|
+
if (!Number.isSafeInteger(generation) || generation < 0) return;
|
|
109
|
+
const key = _nullishCoalesce(floorKey, () => ( EVERY_STORE));
|
|
110
|
+
const known = floors.get(key);
|
|
111
|
+
if (known === void 0 || generation > known) floors.set(key, generation);
|
|
112
|
+
}
|
|
113
|
+
function pendingMinGeneration(floorKey) {
|
|
114
|
+
const own = floors.get(floorKey);
|
|
115
|
+
const every = floors.get(EVERY_STORE);
|
|
116
|
+
return own === void 0 || every !== void 0 && every > own ? every : own;
|
|
117
|
+
}
|
|
118
|
+
function observeGeneration(generation, floorKey) {
|
|
119
|
+
if (typeof generation !== "number") return;
|
|
120
|
+
for (const key of [floorKey, EVERY_STORE]) {
|
|
121
|
+
const floor = floors.get(key);
|
|
122
|
+
if (floor !== void 0 && generation >= floor) floors.delete(key);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// src/server/tags.ts
|
|
127
|
+
function familyOf(route) {
|
|
128
|
+
if (route === "config") return "config";
|
|
129
|
+
return route === "pages" || route === "page" ? "pages" : "data";
|
|
130
|
+
}
|
|
131
|
+
function catalogTags(route, handle) {
|
|
132
|
+
const tags = [_chunkJ2GHGQY6cjs.CACHE_TAG, `${_chunkJ2GHGQY6cjs.CACHE_TAG}:${familyOf(route)}`];
|
|
133
|
+
if (route !== familyOf(route)) tags.push(`${_chunkJ2GHGQY6cjs.CACHE_TAG}:${route}`);
|
|
134
|
+
if (handle !== void 0) tags.push(`${_chunkJ2GHGQY6cjs.CACHE_TAG}:${route}:${handle}`);
|
|
135
|
+
return tags.filter((tag) => tag.length <= _chunkJ2GHGQY6cjs.TAG_MAX_CHARS);
|
|
136
|
+
}
|
|
137
|
+
function tagsForUrl(url, storefront) {
|
|
138
|
+
const path = _nullishCoalesce(url.split(/[?#]/u, 1)[0], () => ( ""));
|
|
139
|
+
if (!path.startsWith(storefront)) return null;
|
|
140
|
+
const found = storefrontRoute(path.slice(storefront.length));
|
|
141
|
+
return found === null ? null : catalogTags(found.route, found.handle);
|
|
142
|
+
}
|
|
143
|
+
var family = (name) => `${_chunkJ2GHGQY6cjs.CACHE_TAG}:${name}`;
|
|
144
|
+
function tagsForScope(scope) {
|
|
145
|
+
const colon = scope.indexOf(":");
|
|
146
|
+
const name = colon < 0 ? scope : scope.slice(0, colon);
|
|
147
|
+
const handle = colon < 0 ? "" : scope.slice(colon + 1);
|
|
148
|
+
switch (scope) {
|
|
149
|
+
case "settings":
|
|
150
|
+
case "navigation":
|
|
151
|
+
return [family("config")];
|
|
152
|
+
case "filters":
|
|
153
|
+
return [family("config"), family("data")];
|
|
154
|
+
case "pages":
|
|
155
|
+
return [family("pages")];
|
|
156
|
+
case "taxonomy":
|
|
157
|
+
case "catalog":
|
|
158
|
+
return [family("data")];
|
|
159
|
+
}
|
|
160
|
+
if (handle !== "") {
|
|
161
|
+
if (name === "product" || name === "collection" || name === "category")
|
|
162
|
+
return [`${family(name)}:${handle}`, family("data")];
|
|
163
|
+
if (name === "reviews")
|
|
164
|
+
return [
|
|
165
|
+
`${family("reviews")}:${handle}`,
|
|
166
|
+
`${family("product")}:${handle}`
|
|
167
|
+
];
|
|
168
|
+
}
|
|
169
|
+
return [family("data")];
|
|
170
|
+
}
|
|
171
|
+
function scopesToTags(scopes) {
|
|
172
|
+
const out = /* @__PURE__ */ new Set();
|
|
173
|
+
for (const scope of scopes) {
|
|
174
|
+
for (const tag of tagsForScope(scope)) {
|
|
175
|
+
if (tag.length <= _chunkJ2GHGQY6cjs.TAG_MAX_CHARS) out.add(tag);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return [...out];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
exports.DEFAULT_CACHE_POLICY = DEFAULT_CACHE_POLICY; exports.storefrontRoute = storefrontRoute; exports.cacheKindForPath = cacheKindForPath; exports.policyToNext = policyToNext; exports.noteMinGeneration = noteMinGeneration; exports.pendingMinGeneration = pendingMinGeneration; exports.observeGeneration = observeGeneration; exports.catalogTags = catalogTags; exports.tagsForUrl = tagsForUrl; exports.scopesToTags = scopesToTags;
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CACHE_TAG,
|
|
3
|
+
CatalogError,
|
|
4
|
+
TAG_MAX_CHARS
|
|
5
|
+
} from "./chunk-VJHA7J7B.js";
|
|
6
|
+
|
|
7
|
+
// src/server/cache-policy.ts
|
|
8
|
+
var UNTIL_CHANGED_REVALIDATE_S = 3600;
|
|
9
|
+
var DEFAULT_CACHE_POLICY = {
|
|
10
|
+
settings: "until-changed",
|
|
11
|
+
navigation: "until-changed",
|
|
12
|
+
pages: "until-changed",
|
|
13
|
+
product: "until-changed",
|
|
14
|
+
listings: "60s",
|
|
15
|
+
facets: "60s",
|
|
16
|
+
related: "60s",
|
|
17
|
+
reviews: "60s",
|
|
18
|
+
search: "60s"
|
|
19
|
+
};
|
|
20
|
+
function decode(segment) {
|
|
21
|
+
try {
|
|
22
|
+
return decodeURIComponent(segment);
|
|
23
|
+
} catch {
|
|
24
|
+
return segment;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function storefrontRoute(path) {
|
|
28
|
+
const bare = path.split(/[?#]/u, 1)[0] ?? "";
|
|
29
|
+
const at = bare.indexOf("/v1/storefront/");
|
|
30
|
+
const parts = (at < 0 ? bare : bare.slice(at + 15)).replace(/^\//u, "");
|
|
31
|
+
const [first, segment, sub, extra] = parts.split("/");
|
|
32
|
+
if (extra !== void 0) return null;
|
|
33
|
+
if (segment === void 0) {
|
|
34
|
+
switch (first) {
|
|
35
|
+
case "config":
|
|
36
|
+
case "products":
|
|
37
|
+
case "pages":
|
|
38
|
+
case "categories":
|
|
39
|
+
case "tags":
|
|
40
|
+
case "collections":
|
|
41
|
+
case "suggest":
|
|
42
|
+
return { route: first };
|
|
43
|
+
default:
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const handle = decode(segment);
|
|
48
|
+
if (handle === "") return null;
|
|
49
|
+
switch (first) {
|
|
50
|
+
case "filters":
|
|
51
|
+
return sub === "values" ? { route: "filters" } : null;
|
|
52
|
+
case "products":
|
|
53
|
+
if (sub === "related" || sub === "reviews") return { route: sub, handle };
|
|
54
|
+
return sub === void 0 ? { route: "product", handle } : null;
|
|
55
|
+
case "pages":
|
|
56
|
+
return sub === void 0 ? { route: "page", handle } : null;
|
|
57
|
+
case "categories":
|
|
58
|
+
return sub === void 0 ? { route: "category", handle } : null;
|
|
59
|
+
case "collections":
|
|
60
|
+
return sub === void 0 ? { route: "collection", handle } : null;
|
|
61
|
+
default:
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
var KIND_OF_ROUTE = {
|
|
66
|
+
config: "settings",
|
|
67
|
+
pages: "pages",
|
|
68
|
+
page: "pages",
|
|
69
|
+
products: "listings",
|
|
70
|
+
product: "product",
|
|
71
|
+
related: "related",
|
|
72
|
+
reviews: "reviews",
|
|
73
|
+
filters: "facets",
|
|
74
|
+
suggest: "search",
|
|
75
|
+
categories: "listings",
|
|
76
|
+
category: "listings",
|
|
77
|
+
collections: "listings",
|
|
78
|
+
collection: "listings",
|
|
79
|
+
tags: "listings"
|
|
80
|
+
};
|
|
81
|
+
function cacheKindForPath(path) {
|
|
82
|
+
const found = storefrontRoute(path);
|
|
83
|
+
return found === null ? null : KIND_OF_ROUTE[found.route] ?? null;
|
|
84
|
+
}
|
|
85
|
+
var DURATION = /^(\d+)([sm])$/u;
|
|
86
|
+
function policyToNext(policy) {
|
|
87
|
+
if (policy === "no-store") return "no-store";
|
|
88
|
+
if (policy === "until-changed")
|
|
89
|
+
return { revalidate: UNTIL_CHANGED_REVALIDATE_S };
|
|
90
|
+
const match = typeof policy === "string" ? DURATION.exec(policy) : null;
|
|
91
|
+
if (match === null) {
|
|
92
|
+
throw new CatalogError({
|
|
93
|
+
code: "INVALID_REQUEST",
|
|
94
|
+
message: "A cache policy is 'until-changed', 'no-store' or a duration such as '90s' or '5m'.",
|
|
95
|
+
statusCode: 0,
|
|
96
|
+
source: "client",
|
|
97
|
+
retryable: false
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
const seconds = Number(match[1]) * (match[2] === "m" ? 60 : 1);
|
|
101
|
+
return seconds === 0 ? "no-store" : { revalidate: seconds };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// src/server/min-generation.ts
|
|
105
|
+
var EVERY_STORE = Symbol("every-store");
|
|
106
|
+
var floors = /* @__PURE__ */ new Map();
|
|
107
|
+
function noteMinGeneration(generation, floorKey) {
|
|
108
|
+
if (!Number.isSafeInteger(generation) || generation < 0) return;
|
|
109
|
+
const key = floorKey ?? EVERY_STORE;
|
|
110
|
+
const known = floors.get(key);
|
|
111
|
+
if (known === void 0 || generation > known) floors.set(key, generation);
|
|
112
|
+
}
|
|
113
|
+
function pendingMinGeneration(floorKey) {
|
|
114
|
+
const own = floors.get(floorKey);
|
|
115
|
+
const every = floors.get(EVERY_STORE);
|
|
116
|
+
return own === void 0 || every !== void 0 && every > own ? every : own;
|
|
117
|
+
}
|
|
118
|
+
function observeGeneration(generation, floorKey) {
|
|
119
|
+
if (typeof generation !== "number") return;
|
|
120
|
+
for (const key of [floorKey, EVERY_STORE]) {
|
|
121
|
+
const floor = floors.get(key);
|
|
122
|
+
if (floor !== void 0 && generation >= floor) floors.delete(key);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// src/server/tags.ts
|
|
127
|
+
function familyOf(route) {
|
|
128
|
+
if (route === "config") return "config";
|
|
129
|
+
return route === "pages" || route === "page" ? "pages" : "data";
|
|
130
|
+
}
|
|
131
|
+
function catalogTags(route, handle) {
|
|
132
|
+
const tags = [CACHE_TAG, `${CACHE_TAG}:${familyOf(route)}`];
|
|
133
|
+
if (route !== familyOf(route)) tags.push(`${CACHE_TAG}:${route}`);
|
|
134
|
+
if (handle !== void 0) tags.push(`${CACHE_TAG}:${route}:${handle}`);
|
|
135
|
+
return tags.filter((tag) => tag.length <= TAG_MAX_CHARS);
|
|
136
|
+
}
|
|
137
|
+
function tagsForUrl(url, storefront) {
|
|
138
|
+
const path = url.split(/[?#]/u, 1)[0] ?? "";
|
|
139
|
+
if (!path.startsWith(storefront)) return null;
|
|
140
|
+
const found = storefrontRoute(path.slice(storefront.length));
|
|
141
|
+
return found === null ? null : catalogTags(found.route, found.handle);
|
|
142
|
+
}
|
|
143
|
+
var family = (name) => `${CACHE_TAG}:${name}`;
|
|
144
|
+
function tagsForScope(scope) {
|
|
145
|
+
const colon = scope.indexOf(":");
|
|
146
|
+
const name = colon < 0 ? scope : scope.slice(0, colon);
|
|
147
|
+
const handle = colon < 0 ? "" : scope.slice(colon + 1);
|
|
148
|
+
switch (scope) {
|
|
149
|
+
case "settings":
|
|
150
|
+
case "navigation":
|
|
151
|
+
return [family("config")];
|
|
152
|
+
case "filters":
|
|
153
|
+
return [family("config"), family("data")];
|
|
154
|
+
case "pages":
|
|
155
|
+
return [family("pages")];
|
|
156
|
+
case "taxonomy":
|
|
157
|
+
case "catalog":
|
|
158
|
+
return [family("data")];
|
|
159
|
+
}
|
|
160
|
+
if (handle !== "") {
|
|
161
|
+
if (name === "product" || name === "collection" || name === "category")
|
|
162
|
+
return [`${family(name)}:${handle}`, family("data")];
|
|
163
|
+
if (name === "reviews")
|
|
164
|
+
return [
|
|
165
|
+
`${family("reviews")}:${handle}`,
|
|
166
|
+
`${family("product")}:${handle}`
|
|
167
|
+
];
|
|
168
|
+
}
|
|
169
|
+
return [family("data")];
|
|
170
|
+
}
|
|
171
|
+
function scopesToTags(scopes) {
|
|
172
|
+
const out = /* @__PURE__ */ new Set();
|
|
173
|
+
for (const scope of scopes) {
|
|
174
|
+
for (const tag of tagsForScope(scope)) {
|
|
175
|
+
if (tag.length <= TAG_MAX_CHARS) out.add(tag);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return [...out];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export {
|
|
182
|
+
DEFAULT_CACHE_POLICY,
|
|
183
|
+
storefrontRoute,
|
|
184
|
+
cacheKindForPath,
|
|
185
|
+
policyToNext,
|
|
186
|
+
noteMinGeneration,
|
|
187
|
+
pendingMinGeneration,
|
|
188
|
+
observeGeneration,
|
|
189
|
+
catalogTags,
|
|
190
|
+
tagsForUrl,
|
|
191
|
+
scopesToTags
|
|
192
|
+
};
|