@usethrottle/catalog 1.1.0 → 1.3.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 +28 -0
- package/README.md +135 -24
- package/dist/admin.cjs +16 -16
- package/dist/admin.d.cts +6 -2
- package/dist/admin.d.ts +6 -2
- package/dist/admin.js +1 -1
- package/dist/{catalog-error-s1BINNkt.d.cts → catalog-error-BOaSKgY3.d.cts} +12 -2
- package/dist/{catalog-error-C_zLOtYA.d.ts → catalog-error-CSoPS0-d.d.ts} +12 -2
- package/dist/{chunk-4ORXUW2U.cjs → chunk-2YQNMBDI.cjs} +119 -33
- package/dist/{chunk-JK2UY4CD.js → chunk-3DLH56OX.js} +99 -13
- package/dist/chunk-CADIHOIR.js +496 -0
- package/dist/chunk-GU63WFXI.cjs +496 -0
- package/dist/{client-c2F-eCaL.d.ts → client-6j1Iz-iJ.d.cts} +2 -9
- package/dist/{client-BAoq6jmM.d.cts → client-B3mL2-xJ.d.ts} +2 -9
- package/dist/{contract-types-DhiThMEr.d.cts → contract-types-BRyonOYH.d.cts} +23 -21
- package/dist/{contract-types-DhiThMEr.d.ts → contract-types-BRyonOYH.d.ts} +23 -21
- package/dist/index.cjs +24 -2
- package/dist/index.d.cts +13 -7
- package/dist/index.d.ts +13 -7
- package/dist/index.js +25 -3
- package/dist/react-extras.cjs +42 -0
- package/dist/react-extras.d.cts +23 -0
- package/dist/react-extras.d.ts +23 -0
- package/dist/react-extras.js +42 -0
- package/dist/react.cjs +286 -491
- package/dist/react.d.cts +44 -38
- package/dist/react.d.ts +44 -38
- package/dist/react.js +289 -494
- package/dist/server.cjs +19 -14
- package/dist/server.d.cts +4 -3
- package/dist/server.d.ts +4 -3
- package/dist/server.js +7 -2
- package/dist/{types-DsjoG8ce.d.cts → types-BfveENg1.d.ts} +76 -3
- package/dist/{types-xQLID-4j.d.ts → types-D0PywKnN.d.cts} +76 -3
- package/dist/url.d.cts +2 -1
- package/dist/url.d.ts +2 -1
- package/dist/use-query-CR7r5tam.d.ts +40 -0
- package/dist/use-query-UWf6Pi5g.d.cts +40 -0
- package/dist/version-ev3p03v2.d.cts +8 -0
- package/dist/version-ev3p03v2.d.ts +8 -0
- package/package.json +13 -2
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CACHE_MAX_ENTRIES,
|
|
3
|
+
INDEXING_REVALIDATE_MS,
|
|
4
|
+
RATE_LIMIT_DEFAULT_RETRY_S,
|
|
5
|
+
RateLimitedError,
|
|
6
|
+
STALE_MS,
|
|
7
|
+
SUGGEST_DEBOUNCE_MS,
|
|
8
|
+
SUGGEST_MIN_CHARS
|
|
9
|
+
} from "./chunk-3DLH56OX.js";
|
|
10
|
+
|
|
11
|
+
// src/react/provider.tsx
|
|
12
|
+
import {
|
|
13
|
+
createContext,
|
|
14
|
+
useContext,
|
|
15
|
+
useEffect,
|
|
16
|
+
useMemo,
|
|
17
|
+
useRef
|
|
18
|
+
} from "react";
|
|
19
|
+
|
|
20
|
+
// src/react/store.ts
|
|
21
|
+
var HOOK_CALL = Symbol.for("@usethrottle/catalog.hookCall");
|
|
22
|
+
var EMPTY = {
|
|
23
|
+
data: void 0,
|
|
24
|
+
error: void 0,
|
|
25
|
+
isValidating: false,
|
|
26
|
+
fetchedAt: void 0
|
|
27
|
+
};
|
|
28
|
+
var done = Promise.resolve();
|
|
29
|
+
function createStore(client, options = {}) {
|
|
30
|
+
const now = options.now ?? Date.now;
|
|
31
|
+
const entries = /* @__PURE__ */ new Map();
|
|
32
|
+
let until = 0;
|
|
33
|
+
let cause;
|
|
34
|
+
let pauseTimer;
|
|
35
|
+
const pausedError = () => new RateLimitedError({
|
|
36
|
+
code: cause?.code ?? "RATE_LIMITED",
|
|
37
|
+
message: cause?.message ?? "Too many requests.",
|
|
38
|
+
statusCode: 429,
|
|
39
|
+
source: cause?.source ?? "catalog",
|
|
40
|
+
retryAfterSeconds: Math.ceil((until - now()) / 1e3)
|
|
41
|
+
});
|
|
42
|
+
const update = (entry, patch) => {
|
|
43
|
+
entry.snap = { ...entry.snap, ...patch };
|
|
44
|
+
for (const listener of [...entry.subs]) listener();
|
|
45
|
+
};
|
|
46
|
+
const touch = (key, initial, stale = false) => {
|
|
47
|
+
let entry = entries.get(key);
|
|
48
|
+
if (entry !== void 0) {
|
|
49
|
+
entries.delete(key);
|
|
50
|
+
} else {
|
|
51
|
+
entry = {
|
|
52
|
+
snap: initial === void 0 ? EMPTY : { ...EMPTY, data: initial, fetchedAt: stale ? void 0 : now() },
|
|
53
|
+
subs: /* @__PURE__ */ new Set(),
|
|
54
|
+
retries: 0
|
|
55
|
+
};
|
|
56
|
+
for (const [oldKey, old] of entries) {
|
|
57
|
+
if (entries.size < CACHE_MAX_ENTRIES) break;
|
|
58
|
+
if (old.subs.size === 0 && old.flight === void 0) {
|
|
59
|
+
clearTimeout(old.timer);
|
|
60
|
+
entries.delete(oldKey);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
entries.set(key, entry);
|
|
65
|
+
return entry;
|
|
66
|
+
};
|
|
67
|
+
const later = (key, entry, ms) => {
|
|
68
|
+
entry.indexing = true;
|
|
69
|
+
clearTimeout(entry.timer);
|
|
70
|
+
entry.timer = setTimeout(() => {
|
|
71
|
+
if (entries.get(key) === entry && entry.subs.size > 0 && entry.run)
|
|
72
|
+
void fetchKey(key, entry.run, { force: true });
|
|
73
|
+
else entry.indexing = false;
|
|
74
|
+
}, ms);
|
|
75
|
+
};
|
|
76
|
+
function fetchKey(key, run, { force = false, staleMs = STALE_MS } = {}) {
|
|
77
|
+
const entry = touch(key);
|
|
78
|
+
entry.run = run;
|
|
79
|
+
if (entry.promise !== void 0 && !entry.flight?.signal.aborted)
|
|
80
|
+
return entry.promise;
|
|
81
|
+
if (now() < until) {
|
|
82
|
+
if (entry.snap.data === void 0 && entry.snap.error === void 0)
|
|
83
|
+
update(entry, { error: pausedError() });
|
|
84
|
+
return done;
|
|
85
|
+
}
|
|
86
|
+
const at = entry.snap.fetchedAt;
|
|
87
|
+
if (!force && at !== void 0 && now() - at < staleMs) return done;
|
|
88
|
+
const controller = new AbortController();
|
|
89
|
+
const box = entry.etag === void 0 ? {} : { etag: entry.etag };
|
|
90
|
+
const current = () => {
|
|
91
|
+
if (entry.flight !== controller) return false;
|
|
92
|
+
entry.flight = entry.promise = void 0;
|
|
93
|
+
if (!controller.signal.aborted) return true;
|
|
94
|
+
update(entry, { isValidating: false });
|
|
95
|
+
return false;
|
|
96
|
+
};
|
|
97
|
+
clearTimeout(entry.retry);
|
|
98
|
+
entry.flight = controller;
|
|
99
|
+
update(entry, { isValidating: true });
|
|
100
|
+
let pending;
|
|
101
|
+
try {
|
|
102
|
+
pending = run(client, {
|
|
103
|
+
signal: controller.signal,
|
|
104
|
+
[HOOK_CALL]: box
|
|
105
|
+
});
|
|
106
|
+
} catch (error) {
|
|
107
|
+
pending = Promise.reject(error);
|
|
108
|
+
}
|
|
109
|
+
const promise = pending.then(
|
|
110
|
+
(value) => {
|
|
111
|
+
if (!current()) return;
|
|
112
|
+
const result = box.result ?? {
|
|
113
|
+
notModified: false,
|
|
114
|
+
data: value,
|
|
115
|
+
etag: null
|
|
116
|
+
};
|
|
117
|
+
entry.etag = result.etag ?? void 0;
|
|
118
|
+
entry.retries = 0;
|
|
119
|
+
if (result.notModified) {
|
|
120
|
+
update(entry, {
|
|
121
|
+
error: void 0,
|
|
122
|
+
isValidating: false,
|
|
123
|
+
fetchedAt: now()
|
|
124
|
+
});
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (result.data?.indexing === true) {
|
|
128
|
+
if (!entry.indexing) later(key, entry, INDEXING_REVALIDATE_MS);
|
|
129
|
+
} else {
|
|
130
|
+
entry.indexing = false;
|
|
131
|
+
}
|
|
132
|
+
update(entry, {
|
|
133
|
+
data: result.data,
|
|
134
|
+
error: void 0,
|
|
135
|
+
isValidating: false,
|
|
136
|
+
fetchedAt: now()
|
|
137
|
+
});
|
|
138
|
+
},
|
|
139
|
+
(error) => {
|
|
140
|
+
if (!current()) return;
|
|
141
|
+
const retryMs = (error.retryAfterSeconds ?? RATE_LIMIT_DEFAULT_RETRY_S) * 1e3;
|
|
142
|
+
if (error.statusCode === 429 && error.code === "RATE_LIMITED")
|
|
143
|
+
pause(now() + retryMs, error);
|
|
144
|
+
else if (error.code === "STOREFRONT_INDEXING") {
|
|
145
|
+
if (!entry.indexing) later(key, entry, retryMs);
|
|
146
|
+
} else if (entry.snap.data !== void 0 && (error.retryable && error.statusCode < 429 || error.statusCode >= 500) && entry.retries < 2) {
|
|
147
|
+
const wait = entry.retries++ ? 1e4 : 2e3;
|
|
148
|
+
entry.retry = setTimeout(() => {
|
|
149
|
+
if (entries.get(key) === entry && entry.subs.size > 0 && entry.run)
|
|
150
|
+
void fetchKey(key, entry.run, { force: true });
|
|
151
|
+
}, wait);
|
|
152
|
+
}
|
|
153
|
+
update(entry, { error, isValidating: false });
|
|
154
|
+
}
|
|
155
|
+
);
|
|
156
|
+
entry.promise = promise;
|
|
157
|
+
return promise;
|
|
158
|
+
}
|
|
159
|
+
function pause(untilMs, error) {
|
|
160
|
+
if (untilMs <= Math.max(until, now())) return;
|
|
161
|
+
until = untilMs;
|
|
162
|
+
cause = error;
|
|
163
|
+
clearTimeout(pauseTimer);
|
|
164
|
+
pauseTimer = setTimeout(() => {
|
|
165
|
+
until = 0;
|
|
166
|
+
for (const [key, entry] of [...entries]) {
|
|
167
|
+
if (entry.subs.size > 0 && entry.run)
|
|
168
|
+
void fetchKey(key, entry.run, { force: true });
|
|
169
|
+
}
|
|
170
|
+
}, untilMs - now());
|
|
171
|
+
}
|
|
172
|
+
function clear() {
|
|
173
|
+
for (const [key, entry] of [...entries]) {
|
|
174
|
+
clearTimeout(entry.timer);
|
|
175
|
+
clearTimeout(entry.retry);
|
|
176
|
+
entry.flight?.abort();
|
|
177
|
+
if (entry.subs.size === 0) {
|
|
178
|
+
entries.delete(key);
|
|
179
|
+
} else {
|
|
180
|
+
entry.etag = entry.flight = entry.promise = void 0;
|
|
181
|
+
entry.indexing = false;
|
|
182
|
+
update(entry, EMPTY);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
subscribe(key, listener) {
|
|
188
|
+
const entry = touch(key);
|
|
189
|
+
entry.subs.add(listener);
|
|
190
|
+
return () => {
|
|
191
|
+
entry.subs.delete(listener);
|
|
192
|
+
void done.then(() => {
|
|
193
|
+
if (entry.subs.size === 0) entry.flight?.abort();
|
|
194
|
+
});
|
|
195
|
+
};
|
|
196
|
+
},
|
|
197
|
+
get: (key, initial, stale) => key === null ? EMPTY : (entries.get(key) ?? (initial === void 0 ? void 0 : touch(key, initial, stale)))?.snap ?? EMPTY,
|
|
198
|
+
getServer(key, initial, stale) {
|
|
199
|
+
if (key === null || initial === void 0) return EMPTY;
|
|
200
|
+
const entry = entries.get(key) ?? touch(key, initial, stale);
|
|
201
|
+
return entry.server ?? (entry.server = { ...EMPTY, data: initial });
|
|
202
|
+
},
|
|
203
|
+
fetch: fetchKey,
|
|
204
|
+
clear,
|
|
205
|
+
pause,
|
|
206
|
+
pausedUntil: () => until > now() ? until : 0,
|
|
207
|
+
dispose() {
|
|
208
|
+
clearTimeout(pauseTimer);
|
|
209
|
+
until = 0;
|
|
210
|
+
clear();
|
|
211
|
+
for (const entry of entries.values()) entry.subs.clear();
|
|
212
|
+
entries.clear();
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// src/react/provider.tsx
|
|
218
|
+
import { jsx } from "react/jsx-runtime";
|
|
219
|
+
function createMemoryCartStorage() {
|
|
220
|
+
let id = null;
|
|
221
|
+
const byCurrency = /* @__PURE__ */ new Map();
|
|
222
|
+
return {
|
|
223
|
+
get: () => id,
|
|
224
|
+
set: (value) => {
|
|
225
|
+
id = value;
|
|
226
|
+
},
|
|
227
|
+
remove: () => {
|
|
228
|
+
id = null;
|
|
229
|
+
},
|
|
230
|
+
getFor: (currency) => byCurrency.get(currency) ?? null,
|
|
231
|
+
setFor: (currency, value) => {
|
|
232
|
+
byCurrency.set(currency, value);
|
|
233
|
+
},
|
|
234
|
+
removeFor: (currency) => {
|
|
235
|
+
byCurrency.delete(currency);
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
var CatalogContext = createContext(null);
|
|
240
|
+
function useCatalogContext() {
|
|
241
|
+
const value = useContext(CatalogContext);
|
|
242
|
+
if (value === null)
|
|
243
|
+
throw new Error("Catalog hooks must be used inside a <CatalogProvider>.");
|
|
244
|
+
return value;
|
|
245
|
+
}
|
|
246
|
+
function CatalogProvider(props) {
|
|
247
|
+
const { client, children, ...rest } = props;
|
|
248
|
+
const customerKey = props.customerKey ?? null;
|
|
249
|
+
const mounted = useRef(null);
|
|
250
|
+
const store = useMemo(() => {
|
|
251
|
+
const next = createStore(client);
|
|
252
|
+
next.pause(mounted.current?.pausedUntil() ?? 0);
|
|
253
|
+
return next;
|
|
254
|
+
}, [client, customerKey]);
|
|
255
|
+
useEffect(() => {
|
|
256
|
+
mounted.current = store;
|
|
257
|
+
return () => {
|
|
258
|
+
mounted.current = null;
|
|
259
|
+
void Promise.resolve().then(() => {
|
|
260
|
+
if (mounted.current !== store) store.dispose();
|
|
261
|
+
});
|
|
262
|
+
};
|
|
263
|
+
}, [store]);
|
|
264
|
+
const memory = useMemo(createMemoryCartStorage, []);
|
|
265
|
+
const cartStorage = rest.cartStorage ?? memory;
|
|
266
|
+
const shared = useRef({}).current;
|
|
267
|
+
const cart = useMemo(
|
|
268
|
+
() => ({ shared }),
|
|
269
|
+
[shared, client, rest.throttleBaseUrl]
|
|
270
|
+
);
|
|
271
|
+
const urls = rest.cartUrls;
|
|
272
|
+
const value = useMemo(
|
|
273
|
+
() => ({ ...rest, client, customerKey, store, cartStorage, cart }),
|
|
274
|
+
// `rest` is spread fresh each render; its fields are the dependencies.
|
|
275
|
+
[
|
|
276
|
+
client,
|
|
277
|
+
customerKey,
|
|
278
|
+
store,
|
|
279
|
+
cartStorage,
|
|
280
|
+
cart,
|
|
281
|
+
rest.customerCart,
|
|
282
|
+
rest.throttleBaseUrl,
|
|
283
|
+
rest.throttleCheckoutUrl,
|
|
284
|
+
urls?.returnUrl,
|
|
285
|
+
urls?.cancelUrl,
|
|
286
|
+
urls?.storefrontUrl
|
|
287
|
+
]
|
|
288
|
+
);
|
|
289
|
+
cart.context = value;
|
|
290
|
+
shared.home = cart;
|
|
291
|
+
return /* @__PURE__ */ jsx(CatalogContext.Provider, { value, children });
|
|
292
|
+
}
|
|
293
|
+
function useCustomerKey() {
|
|
294
|
+
return useCatalogContext().customerKey;
|
|
295
|
+
}
|
|
296
|
+
function useCatalog() {
|
|
297
|
+
return useCatalogContext().client;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// src/react/use-query.ts
|
|
301
|
+
import { useCallback, useEffect as useEffect2, useRef as useRef2, useSyncExternalStore } from "react";
|
|
302
|
+
function canonical(value) {
|
|
303
|
+
if (Array.isArray(value)) return value.map(canonical);
|
|
304
|
+
if (value === null || typeof value !== "object") return value;
|
|
305
|
+
const out = {};
|
|
306
|
+
for (const name of Object.keys(value).sort()) {
|
|
307
|
+
const item = value[name];
|
|
308
|
+
if (item !== void 0) out[name] = canonical(item);
|
|
309
|
+
}
|
|
310
|
+
return out;
|
|
311
|
+
}
|
|
312
|
+
function catalogQueryKey(route, params) {
|
|
313
|
+
return `${route}:${JSON.stringify(canonical(params ?? null))}`;
|
|
314
|
+
}
|
|
315
|
+
var noop = () => {
|
|
316
|
+
};
|
|
317
|
+
var unsubscribe = () => noop;
|
|
318
|
+
function useQuery(route, params, run, options = {}) {
|
|
319
|
+
const { store, customerKey } = useCatalogContext();
|
|
320
|
+
const key = run === null || options.enabled === false ? null : `${customerKey ?? ""}\0${catalogQueryKey(route, params)}`;
|
|
321
|
+
const first = useRef2({ store, key });
|
|
322
|
+
const initial = first.current.store === store && first.current.key === key ? options.initialData : void 0;
|
|
323
|
+
const subscribe = useCallback(
|
|
324
|
+
(listener) => key === null ? unsubscribe() : store.subscribe(key, listener),
|
|
325
|
+
[store, key]
|
|
326
|
+
);
|
|
327
|
+
const stale = customerKey !== null;
|
|
328
|
+
const snap = useSyncExternalStore(
|
|
329
|
+
subscribe,
|
|
330
|
+
() => store.get(key, initial, stale),
|
|
331
|
+
() => store.getServer(key, initial, stale)
|
|
332
|
+
);
|
|
333
|
+
const staleMs = options.staleTimeMs;
|
|
334
|
+
useEffect2(() => {
|
|
335
|
+
if (key !== null && run !== null)
|
|
336
|
+
void store.fetch(key, run, staleMs === void 0 ? {} : { staleMs });
|
|
337
|
+
}, [store, key, staleMs]);
|
|
338
|
+
const refetch = useCallback(
|
|
339
|
+
() => key === null || run === null ? Promise.resolve() : store.fetch(key, run, { force: true }),
|
|
340
|
+
[store, key]
|
|
341
|
+
);
|
|
342
|
+
const last = useRef2(void 0);
|
|
343
|
+
const previous = last.current;
|
|
344
|
+
const keep = options.keepPreviousData === true && key !== null && snap.data === void 0 && previous !== void 0 && previous.store === store && previous.key !== key;
|
|
345
|
+
const data = keep ? previous.data : snap.data;
|
|
346
|
+
useEffect2(() => {
|
|
347
|
+
if (snap.data !== void 0)
|
|
348
|
+
last.current = { store, key, data: snap.data, params };
|
|
349
|
+
});
|
|
350
|
+
return {
|
|
351
|
+
data,
|
|
352
|
+
dataFor: keep ? previous.params : params,
|
|
353
|
+
isPreviousData: keep,
|
|
354
|
+
isStale: snap.data !== void 0 && (snap.fetchedAt === void 0 || snap.error !== void 0),
|
|
355
|
+
error: snap.error,
|
|
356
|
+
isLoading: key !== null && data === void 0 && snap.error === void 0,
|
|
357
|
+
isValidating: snap.isValidating,
|
|
358
|
+
refetch
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// src/react/hooks.ts
|
|
363
|
+
import { useEffect as useEffect3, useMemo as useMemo2, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
364
|
+
function defined(options) {
|
|
365
|
+
const out = {};
|
|
366
|
+
for (const name in options) {
|
|
367
|
+
if (options[name] !== void 0) out[name] = options[name];
|
|
368
|
+
}
|
|
369
|
+
return out;
|
|
370
|
+
}
|
|
371
|
+
function useProducts(query = {}, options) {
|
|
372
|
+
return useQuery(
|
|
373
|
+
"products",
|
|
374
|
+
query,
|
|
375
|
+
(client, call) => client.products.list(query, call),
|
|
376
|
+
options
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
function useProduct(handle, options = {}) {
|
|
380
|
+
const extra = defined({ include: options.include });
|
|
381
|
+
return useQuery(
|
|
382
|
+
"product",
|
|
383
|
+
{ handle, ...extra },
|
|
384
|
+
handle === null ? null : (client, call) => client.products.get(handle, { ...call, ...extra }),
|
|
385
|
+
options
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
function useRelated(handle, options = {}) {
|
|
389
|
+
const extra = defined({ limit: options.limit });
|
|
390
|
+
return useQuery(
|
|
391
|
+
"related",
|
|
392
|
+
{ handle, ...extra },
|
|
393
|
+
handle === null ? null : (client, call) => client.products.related(handle, { ...call, ...extra }),
|
|
394
|
+
options
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
function useDebounced(q, ms) {
|
|
398
|
+
const box = useMemo2(() => {
|
|
399
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
400
|
+
let value = q;
|
|
401
|
+
return {
|
|
402
|
+
get: () => value,
|
|
403
|
+
set(next) {
|
|
404
|
+
value = next;
|
|
405
|
+
for (const listener of [...listeners]) listener();
|
|
406
|
+
},
|
|
407
|
+
subscribe(listener) {
|
|
408
|
+
listeners.add(listener);
|
|
409
|
+
return () => listeners.delete(listener);
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
}, []);
|
|
413
|
+
useEffect3(() => {
|
|
414
|
+
const timer = setTimeout(() => box.set(q), ms);
|
|
415
|
+
return () => clearTimeout(timer);
|
|
416
|
+
}, [box, q, ms]);
|
|
417
|
+
return useSyncExternalStore2(box.subscribe, box.get, box.get);
|
|
418
|
+
}
|
|
419
|
+
function useSuggest(q, options = {}) {
|
|
420
|
+
const settled = useDebounced(q, options.debounceMs ?? SUGGEST_DEBOUNCE_MS);
|
|
421
|
+
const extra = defined({ limit: options.limit });
|
|
422
|
+
const long = (value) => value.trim().length >= SUGGEST_MIN_CHARS;
|
|
423
|
+
return useQuery(
|
|
424
|
+
"suggest",
|
|
425
|
+
{ q: settled, ...extra },
|
|
426
|
+
long(q) && long(settled) ? (client, call) => client.suggest(settled, { ...call, ...extra }) : null,
|
|
427
|
+
options
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
function useCategories(options = {}) {
|
|
431
|
+
const extra = defined({ depth: options.depth });
|
|
432
|
+
return useQuery(
|
|
433
|
+
"categories",
|
|
434
|
+
extra,
|
|
435
|
+
(client, call) => client.categories.tree({ ...call, ...extra }),
|
|
436
|
+
options
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
function useCollection(handle, options) {
|
|
440
|
+
return useQuery(
|
|
441
|
+
"collection",
|
|
442
|
+
{ handle },
|
|
443
|
+
handle === null ? null : (client, call) => client.collections.get(handle, call),
|
|
444
|
+
options
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
function useReviews(handle, options = {}) {
|
|
448
|
+
const extra = defined({
|
|
449
|
+
sort: options.sort,
|
|
450
|
+
rating: options.rating,
|
|
451
|
+
limit: options.limit,
|
|
452
|
+
cursor: options.cursor
|
|
453
|
+
});
|
|
454
|
+
return useQuery(
|
|
455
|
+
"reviews",
|
|
456
|
+
{ handle, ...extra },
|
|
457
|
+
handle === null ? null : (client, call) => client.reviews.list(handle, { ...call, ...extra }),
|
|
458
|
+
options
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
function useConfig(options) {
|
|
462
|
+
return useQuery(
|
|
463
|
+
"config",
|
|
464
|
+
null,
|
|
465
|
+
(client, call) => client.config(call),
|
|
466
|
+
options
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
function useFilterValues(key, query = {}, options) {
|
|
470
|
+
return useQuery(
|
|
471
|
+
"filterValues",
|
|
472
|
+
{ key, query },
|
|
473
|
+
key === null ? null : (client, call) => client.filters.values(key, query, call),
|
|
474
|
+
options
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
export {
|
|
479
|
+
createMemoryCartStorage,
|
|
480
|
+
useCatalogContext,
|
|
481
|
+
CatalogProvider,
|
|
482
|
+
useCustomerKey,
|
|
483
|
+
useCatalog,
|
|
484
|
+
catalogQueryKey,
|
|
485
|
+
useQuery,
|
|
486
|
+
defined,
|
|
487
|
+
useProducts,
|
|
488
|
+
useProduct,
|
|
489
|
+
useRelated,
|
|
490
|
+
useSuggest,
|
|
491
|
+
useCategories,
|
|
492
|
+
useCollection,
|
|
493
|
+
useReviews,
|
|
494
|
+
useConfig,
|
|
495
|
+
useFilterValues
|
|
496
|
+
};
|