@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.
Files changed (41) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +135 -24
  3. package/dist/admin.cjs +16 -16
  4. package/dist/admin.d.cts +6 -2
  5. package/dist/admin.d.ts +6 -2
  6. package/dist/admin.js +1 -1
  7. package/dist/{catalog-error-s1BINNkt.d.cts → catalog-error-BOaSKgY3.d.cts} +12 -2
  8. package/dist/{catalog-error-C_zLOtYA.d.ts → catalog-error-CSoPS0-d.d.ts} +12 -2
  9. package/dist/{chunk-4ORXUW2U.cjs → chunk-2YQNMBDI.cjs} +119 -33
  10. package/dist/{chunk-JK2UY4CD.js → chunk-3DLH56OX.js} +99 -13
  11. package/dist/chunk-CADIHOIR.js +496 -0
  12. package/dist/chunk-GU63WFXI.cjs +496 -0
  13. package/dist/{client-c2F-eCaL.d.ts → client-6j1Iz-iJ.d.cts} +2 -9
  14. package/dist/{client-BAoq6jmM.d.cts → client-B3mL2-xJ.d.ts} +2 -9
  15. package/dist/{contract-types-DhiThMEr.d.cts → contract-types-BRyonOYH.d.cts} +23 -21
  16. package/dist/{contract-types-DhiThMEr.d.ts → contract-types-BRyonOYH.d.ts} +23 -21
  17. package/dist/index.cjs +24 -2
  18. package/dist/index.d.cts +13 -7
  19. package/dist/index.d.ts +13 -7
  20. package/dist/index.js +25 -3
  21. package/dist/react-extras.cjs +42 -0
  22. package/dist/react-extras.d.cts +23 -0
  23. package/dist/react-extras.d.ts +23 -0
  24. package/dist/react-extras.js +42 -0
  25. package/dist/react.cjs +286 -491
  26. package/dist/react.d.cts +44 -38
  27. package/dist/react.d.ts +44 -38
  28. package/dist/react.js +289 -494
  29. package/dist/server.cjs +19 -14
  30. package/dist/server.d.cts +4 -3
  31. package/dist/server.d.ts +4 -3
  32. package/dist/server.js +7 -2
  33. package/dist/{types-DsjoG8ce.d.cts → types-BfveENg1.d.ts} +76 -3
  34. package/dist/{types-xQLID-4j.d.ts → types-D0PywKnN.d.cts} +76 -3
  35. package/dist/url.d.cts +2 -1
  36. package/dist/url.d.ts +2 -1
  37. package/dist/use-query-CR7r5tam.d.ts +40 -0
  38. package/dist/use-query-UWf6Pi5g.d.cts +40 -0
  39. package/dist/version-ev3p03v2.d.cts +8 -0
  40. package/dist/version-ev3p03v2.d.ts +8 -0
  41. package/package.json +13 -2
package/dist/react.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
3
3
 
4
4
 
5
5
 
@@ -11,449 +11,28 @@
11
11
 
12
12
 
13
13
 
14
- var _chunk4ORXUW2Ucjs = require('./chunk-4ORXUW2U.cjs');
15
- require('./chunk-ETV4XYOV.cjs');
16
14
 
17
- // src/react/provider.tsx
18
15
 
19
16
 
20
17
 
18
+ var _chunkGU63WFXIcjs = require('./chunk-GU63WFXI.cjs');
21
19
 
22
20
 
23
21
 
24
- var _react = require('react');
25
22
 
26
- // src/react/store.ts
27
- var HOOK_CALL = Symbol.for("@usethrottle/catalog.hookCall");
28
- var EMPTY = {
29
- data: void 0,
30
- error: void 0,
31
- isValidating: false,
32
- fetchedAt: void 0
33
- };
34
- var done = Promise.resolve();
35
- function createStore(client, options = {}) {
36
- const now = _nullishCoalesce(options.now, () => ( Date.now));
37
- const entries = /* @__PURE__ */ new Map();
38
- let until = 0;
39
- let cause;
40
- let pauseTimer;
41
- const pausedError = () => new (0, _chunk4ORXUW2Ucjs.RateLimitedError)({
42
- code: _nullishCoalesce(_optionalChain([cause, 'optionalAccess', _ => _.code]), () => ( "RATE_LIMITED")),
43
- message: _nullishCoalesce(_optionalChain([cause, 'optionalAccess', _2 => _2.message]), () => ( "Too many requests.")),
44
- statusCode: 429,
45
- source: _nullishCoalesce(_optionalChain([cause, 'optionalAccess', _3 => _3.source]), () => ( "catalog")),
46
- retryAfterSeconds: Math.ceil((until - now()) / 1e3)
47
- });
48
- const update = (entry, patch) => {
49
- entry.snap = { ...entry.snap, ...patch };
50
- for (const listener of [...entry.subs]) listener();
51
- };
52
- const touch = (key, initial, stale = false) => {
53
- let entry = entries.get(key);
54
- if (entry !== void 0) {
55
- entries.delete(key);
56
- } else {
57
- entry = {
58
- snap: initial === void 0 ? EMPTY : { ...EMPTY, data: initial, fetchedAt: stale ? void 0 : now() },
59
- subs: /* @__PURE__ */ new Set()
60
- };
61
- for (const [oldKey, old] of entries) {
62
- if (entries.size < _chunk4ORXUW2Ucjs.CACHE_MAX_ENTRIES) break;
63
- if (old.subs.size === 0 && old.flight === void 0) {
64
- clearTimeout(old.timer);
65
- entries.delete(oldKey);
66
- }
67
- }
68
- }
69
- entries.set(key, entry);
70
- return entry;
71
- };
72
- const later = (key, entry, ms) => {
73
- entry.indexing = true;
74
- clearTimeout(entry.timer);
75
- entry.timer = setTimeout(() => {
76
- if (entries.get(key) === entry && entry.subs.size > 0 && entry.run)
77
- void fetchKey(key, entry.run, { force: true });
78
- else entry.indexing = false;
79
- }, ms);
80
- };
81
- function fetchKey(key, run, { force = false, staleMs = _chunk4ORXUW2Ucjs.STALE_MS } = {}) {
82
- const entry = touch(key);
83
- entry.run = run;
84
- if (entry.promise !== void 0 && !_optionalChain([entry, 'access', _4 => _4.flight, 'optionalAccess', _5 => _5.signal, 'access', _6 => _6.aborted]))
85
- return entry.promise;
86
- if (now() < until) {
87
- if (entry.snap.data === void 0 && entry.snap.error === void 0)
88
- update(entry, { error: pausedError() });
89
- return done;
90
- }
91
- const at = entry.snap.fetchedAt;
92
- if (!force && at !== void 0 && now() - at < staleMs) return done;
93
- const controller = new AbortController();
94
- const box = entry.etag === void 0 ? {} : { etag: entry.etag };
95
- const current = () => {
96
- if (entry.flight !== controller) return false;
97
- entry.flight = entry.promise = void 0;
98
- if (!controller.signal.aborted) return true;
99
- update(entry, { isValidating: false });
100
- return false;
101
- };
102
- entry.flight = controller;
103
- update(entry, { isValidating: true });
104
- let pending;
105
- try {
106
- pending = run(client, {
107
- signal: controller.signal,
108
- [HOOK_CALL]: box
109
- });
110
- } catch (error) {
111
- pending = Promise.reject(error);
112
- }
113
- const promise = pending.then(
114
- (value) => {
115
- if (!current()) return;
116
- const result = _nullishCoalesce(box.result, () => ( {
117
- notModified: false,
118
- data: value,
119
- etag: null
120
- }));
121
- entry.etag = _nullishCoalesce(result.etag, () => ( void 0));
122
- if (result.notModified) {
123
- update(entry, {
124
- error: void 0,
125
- isValidating: false,
126
- fetchedAt: now()
127
- });
128
- return;
129
- }
130
- if (_optionalChain([result, 'access', _7 => _7.data, 'optionalAccess', _8 => _8.indexing]) === true) {
131
- if (!entry.indexing) later(key, entry, _chunk4ORXUW2Ucjs.INDEXING_REVALIDATE_MS);
132
- } else {
133
- entry.indexing = false;
134
- }
135
- update(entry, {
136
- data: result.data,
137
- error: void 0,
138
- isValidating: false,
139
- fetchedAt: now()
140
- });
141
- },
142
- (error) => {
143
- if (!current()) return;
144
- const retryMs = (_nullishCoalesce(error.retryAfterSeconds, () => ( _chunk4ORXUW2Ucjs.RATE_LIMIT_DEFAULT_RETRY_S))) * 1e3;
145
- if (error.statusCode === 429 && error.code === "RATE_LIMITED")
146
- pause(now() + retryMs, error);
147
- else if (error.code === "STOREFRONT_INDEXING" && !entry.indexing)
148
- later(key, entry, retryMs);
149
- update(entry, { error, isValidating: false });
150
- }
151
- );
152
- entry.promise = promise;
153
- return promise;
154
- }
155
- function pause(untilMs, error) {
156
- if (untilMs <= Math.max(until, now())) return;
157
- until = untilMs;
158
- cause = error;
159
- clearTimeout(pauseTimer);
160
- pauseTimer = setTimeout(() => {
161
- until = 0;
162
- for (const [key, entry] of [...entries]) {
163
- if (entry.subs.size > 0 && entry.run)
164
- void fetchKey(key, entry.run, { force: true });
165
- }
166
- }, untilMs - now());
167
- }
168
- function clear() {
169
- for (const [key, entry] of [...entries]) {
170
- clearTimeout(entry.timer);
171
- _optionalChain([entry, 'access', _9 => _9.flight, 'optionalAccess', _10 => _10.abort, 'call', _11 => _11()]);
172
- if (entry.subs.size === 0) {
173
- entries.delete(key);
174
- } else {
175
- entry.etag = entry.flight = entry.promise = void 0;
176
- entry.indexing = false;
177
- update(entry, EMPTY);
178
- }
179
- }
180
- }
181
- return {
182
- subscribe(key, listener) {
183
- const entry = touch(key);
184
- entry.subs.add(listener);
185
- return () => {
186
- entry.subs.delete(listener);
187
- void done.then(() => {
188
- if (entry.subs.size === 0) _optionalChain([entry, 'access', _12 => _12.flight, 'optionalAccess', _13 => _13.abort, 'call', _14 => _14()]);
189
- });
190
- };
191
- },
192
- get: (key, initial, stale) => key === null ? EMPTY : _nullishCoalesce(_optionalChain([(_nullishCoalesce(entries.get(key), () => ( (initial === void 0 ? void 0 : touch(key, initial, stale))))), 'optionalAccess', _15 => _15.snap]), () => ( EMPTY)),
193
- getServer(key, initial, stale) {
194
- if (key === null || initial === void 0) return EMPTY;
195
- const entry = _nullishCoalesce(entries.get(key), () => ( touch(key, initial, stale)));
196
- return _nullishCoalesce(entry.server, () => ( (entry.server = { ...EMPTY, data: initial })));
197
- },
198
- fetch: fetchKey,
199
- clear,
200
- pause,
201
- pausedUntil: () => until > now() ? until : 0,
202
- dispose() {
203
- clearTimeout(pauseTimer);
204
- until = 0;
205
- clear();
206
- for (const entry of entries.values()) entry.subs.clear();
207
- entries.clear();
208
- }
209
- };
210
- }
211
23
 
212
- // src/react/provider.tsx
213
- var _jsxruntime = require('react/jsx-runtime');
214
- function createMemoryCartStorage() {
215
- let id = null;
216
- return {
217
- get: () => id,
218
- set: (value) => {
219
- id = value;
220
- },
221
- remove: () => {
222
- id = null;
223
- }
224
- };
225
- }
226
- var CatalogContext = _react.createContext.call(void 0, null);
227
- function useCatalogContext() {
228
- const value = _react.useContext.call(void 0, CatalogContext);
229
- if (value === null)
230
- throw new Error("Catalog hooks must be used inside a <CatalogProvider>.");
231
- return value;
232
- }
233
- function CatalogProvider(props) {
234
- const { client, children, ...rest } = props;
235
- const customerKey = _nullishCoalesce(props.customerKey, () => ( null));
236
- const mounted = _react.useRef.call(void 0, null);
237
- const store = _react.useMemo.call(void 0, () => {
238
- const next = createStore(client);
239
- next.pause(_nullishCoalesce(_optionalChain([mounted, 'access', _16 => _16.current, 'optionalAccess', _17 => _17.pausedUntil, 'call', _18 => _18()]), () => ( 0)));
240
- return next;
241
- }, [client, customerKey]);
242
- _react.useEffect.call(void 0, () => {
243
- mounted.current = store;
244
- return () => {
245
- mounted.current = null;
246
- void Promise.resolve().then(() => {
247
- if (mounted.current !== store) store.dispose();
248
- });
249
- };
250
- }, [store]);
251
- const memory = _react.useMemo.call(void 0, createMemoryCartStorage, []);
252
- const cartStorage = _nullishCoalesce(rest.cartStorage, () => ( memory));
253
- const shared = _react.useRef.call(void 0, {}).current;
254
- const cart = _react.useMemo.call(void 0,
255
- () => ({ shared }),
256
- [shared, client, rest.throttleBaseUrl]
257
- );
258
- const urls = rest.cartUrls;
259
- const value = _react.useMemo.call(void 0,
260
- () => ({ ...rest, client, customerKey, store, cartStorage, cart }),
261
- // `rest` is spread fresh each render; its fields are the dependencies.
262
- [
263
- client,
264
- customerKey,
265
- store,
266
- cartStorage,
267
- cart,
268
- rest.throttleBaseUrl,
269
- rest.throttleCheckoutUrl,
270
- _optionalChain([urls, 'optionalAccess', _19 => _19.returnUrl]),
271
- _optionalChain([urls, 'optionalAccess', _20 => _20.cancelUrl]),
272
- _optionalChain([urls, 'optionalAccess', _21 => _21.storefrontUrl])
273
- ]
274
- );
275
- cart.context = value;
276
- shared.home = cart;
277
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CatalogContext.Provider, { value, children });
278
- }
279
- function useCatalog() {
280
- return useCatalogContext().client;
281
- }
282
-
283
- // src/react/use-query.ts
284
-
285
- function canonical(value) {
286
- if (Array.isArray(value)) return value.map(canonical);
287
- if (value === null || typeof value !== "object") return value;
288
- const out = {};
289
- for (const name of Object.keys(value).sort()) {
290
- const item = value[name];
291
- if (item !== void 0) out[name] = canonical(item);
292
- }
293
- return out;
294
- }
295
- function catalogQueryKey(route, params) {
296
- return `${route}:${JSON.stringify(canonical(_nullishCoalesce(params, () => ( null))))}`;
297
- }
298
- var noop = () => {
299
- };
300
- var unsubscribe = () => noop;
301
- function useQuery(route, params, run, options = {}) {
302
- const { store, customerKey } = useCatalogContext();
303
- const key = run === null || options.enabled === false ? null : `${_nullishCoalesce(customerKey, () => ( ""))}\0${catalogQueryKey(route, params)}`;
304
- const first = _react.useRef.call(void 0, { store, key });
305
- const initial = first.current.store === store && first.current.key === key ? options.initialData : void 0;
306
- const subscribe = _react.useCallback.call(void 0,
307
- (listener) => key === null ? unsubscribe() : store.subscribe(key, listener),
308
- [store, key]
309
- );
310
- const stale = customerKey !== null;
311
- const snap = _react.useSyncExternalStore.call(void 0,
312
- subscribe,
313
- () => store.get(key, initial, stale),
314
- () => store.getServer(key, initial, stale)
315
- );
316
- const staleMs = options.staleTimeMs;
317
- _react.useEffect.call(void 0, () => {
318
- if (key !== null && run !== null)
319
- void store.fetch(key, run, staleMs === void 0 ? {} : { staleMs });
320
- }, [store, key, staleMs]);
321
- const refetch = _react.useCallback.call(void 0,
322
- () => key === null || run === null ? Promise.resolve() : store.fetch(key, run, { force: true }),
323
- [store, key]
324
- );
325
- return {
326
- data: snap.data,
327
- error: snap.error,
328
- isLoading: key !== null && snap.data === void 0 && snap.error === void 0,
329
- isValidating: snap.isValidating,
330
- refetch
331
- };
332
- }
333
24
 
334
- // src/react/hooks.ts
335
25
 
336
- function defined(options) {
337
- const out = {};
338
- for (const name in options) {
339
- if (options[name] !== void 0) out[name] = options[name];
340
- }
341
- return out;
342
- }
343
- function useProducts(query = {}, options) {
344
- return useQuery(
345
- "products",
346
- query,
347
- (client, call) => client.products.list(query, call),
348
- options
349
- );
350
- }
351
- function useProduct(handle, options = {}) {
352
- const extra = defined({ include: options.include });
353
- return useQuery(
354
- "product",
355
- { handle, ...extra },
356
- handle === null ? null : (client, call) => client.products.get(handle, { ...call, ...extra }),
357
- options
358
- );
359
- }
360
- function useRelated(handle, options = {}) {
361
- const extra = defined({ limit: options.limit });
362
- return useQuery(
363
- "related",
364
- { handle, ...extra },
365
- handle === null ? null : (client, call) => client.products.related(handle, { ...call, ...extra }),
366
- options
367
- );
368
- }
369
- function useDebounced(q, ms) {
370
- const box = _react.useMemo.call(void 0, () => {
371
- const listeners = /* @__PURE__ */ new Set();
372
- let value = q;
373
- return {
374
- get: () => value,
375
- set(next) {
376
- value = next;
377
- for (const listener of [...listeners]) listener();
378
- },
379
- subscribe(listener) {
380
- listeners.add(listener);
381
- return () => listeners.delete(listener);
382
- }
383
- };
384
- }, []);
385
- _react.useEffect.call(void 0, () => {
386
- const timer = setTimeout(() => box.set(q), ms);
387
- return () => clearTimeout(timer);
388
- }, [box, q, ms]);
389
- return _react.useSyncExternalStore.call(void 0, box.subscribe, box.get, box.get);
390
- }
391
- function useSuggest(q, options = {}) {
392
- const settled = useDebounced(q, _nullishCoalesce(options.debounceMs, () => ( _chunk4ORXUW2Ucjs.SUGGEST_DEBOUNCE_MS)));
393
- const extra = defined({ limit: options.limit });
394
- const long = (value) => value.trim().length >= _chunk4ORXUW2Ucjs.SUGGEST_MIN_CHARS;
395
- return useQuery(
396
- "suggest",
397
- { q: settled, ...extra },
398
- long(q) && long(settled) ? (client, call) => client.suggest(settled, { ...call, ...extra }) : null,
399
- options
400
- );
401
- }
402
- function useCategories(options = {}) {
403
- const extra = defined({ depth: options.depth });
404
- return useQuery(
405
- "categories",
406
- extra,
407
- (client, call) => client.categories.tree({ ...call, ...extra }),
408
- options
409
- );
410
- }
411
- function useCollection(handle, options) {
412
- return useQuery(
413
- "collection",
414
- { handle },
415
- handle === null ? null : (client, call) => client.collections.get(handle, call),
416
- options
417
- );
418
- }
419
- function useReviews(handle, options = {}) {
420
- const extra = defined({
421
- sort: options.sort,
422
- rating: options.rating,
423
- limit: options.limit,
424
- cursor: options.cursor
425
- });
426
- return useQuery(
427
- "reviews",
428
- { handle, ...extra },
429
- handle === null ? null : (client, call) => client.reviews.list(handle, { ...call, ...extra }),
430
- options
431
- );
432
- }
433
- function useConfig(options) {
434
- return useQuery(
435
- "config",
436
- null,
437
- (client, call) => client.config(call),
438
- options
439
- );
440
- }
441
- function useFilterValues(key, query = {}, options) {
442
- return useQuery(
443
- "filterValues",
444
- { key, query },
445
- key === null ? null : (client, call) => client.filters.values(key, query, call),
446
- options
447
- );
448
- }
26
+ var _chunk2YQNMBDIcjs = require('./chunk-2YQNMBDI.cjs');
27
+ require('./chunk-ETV4XYOV.cjs');
449
28
 
450
29
  // src/react/use-cart.ts
451
-
30
+ var _react = require('react');
452
31
 
453
32
  // src/react/mutation.ts
454
33
  function newKey() {
455
34
  const webCrypto = globalThis.crypto;
456
- if (typeof _optionalChain([webCrypto, 'optionalAccess', _22 => _22.randomUUID]) === "function")
35
+ if (typeof _optionalChain([webCrypto, 'optionalAccess', _ => _.randomUUID]) === "function")
457
36
  return webCrypto.randomUUID();
458
37
  let out = "";
459
38
  for (let i = 0; i < 32; i += 1)
@@ -461,7 +40,7 @@ function newKey() {
461
40
  return out;
462
41
  }
463
42
  function refuse(message, path) {
464
- return new (0, _chunk4ORXUW2Ucjs.CatalogError)({
43
+ return new (0, _chunk2YQNMBDIcjs.CatalogError)({
465
44
  code: "INVALID_REQUEST",
466
45
  message,
467
46
  statusCode: 0,
@@ -474,7 +53,7 @@ var UNSAFE = /[\x00-\x20\x7f]/u;
474
53
  function isHttpUrl(value) {
475
54
  return typeof value === "string" && /^https?:\/\/[^/?#\\]/iu.test(value) && !UNSAFE.test(value);
476
55
  }
477
- var wrap = (error) => _chunk4ORXUW2Ucjs.isCatalogError.call(void 0, error) ? error : new (0, _chunk4ORXUW2Ucjs.CatalogError)({
56
+ var wrap = (error) => _chunk2YQNMBDIcjs.isCatalogError.call(void 0, error) ? error : new (0, _chunk2YQNMBDIcjs.CatalogError)({
478
57
  code: "CLIENT_ERROR",
479
58
  message: "The action failed.",
480
59
  statusCode: 0,
@@ -485,7 +64,7 @@ var wrap = (error) => _chunk4ORXUW2Ucjs.isCatalogError.call(void 0, error) ? err
485
64
  function checkPause(store) {
486
65
  const until = store.pausedUntil();
487
66
  if (until > 0) {
488
- throw new (0, _chunk4ORXUW2Ucjs.RateLimitedError)({
67
+ throw new (0, _chunk2YQNMBDIcjs.RateLimitedError)({
489
68
  code: "RATE_LIMITED",
490
69
  message: "Too many requests.",
491
70
  statusCode: 429,
@@ -495,7 +74,7 @@ function checkPause(store) {
495
74
  }
496
75
  }
497
76
  function notePause(store, error) {
498
- if (error instanceof _chunk4ORXUW2Ucjs.RateLimitedError && error.source === "catalog" && error.code === "RATE_LIMITED")
77
+ if (error instanceof _chunk2YQNMBDIcjs.RateLimitedError && error.source === "catalog" && error.code === "RATE_LIMITED")
499
78
  store.pause(Date.now() + error.retryAfterSeconds * 1e3, error);
500
79
  }
501
80
  function createBox(initial) {
@@ -515,13 +94,14 @@ function createBox(initial) {
515
94
  }
516
95
 
517
96
  // src/react/use-cart.ts
518
- var EMPTY2 = {
97
+ var EMPTY = {
519
98
  cart: null,
520
99
  sessionId: null,
521
100
  cartUrl: null,
522
101
  status: "idle",
523
102
  error: void 0,
524
- pending: false
103
+ pending: false,
104
+ warnings: []
525
105
  };
526
106
  var ENDED = /* @__PURE__ */ new Set([
527
107
  "cart_session_expired",
@@ -529,11 +109,11 @@ var ENDED = /* @__PURE__ */ new Set([
529
109
  "cart_not_open",
530
110
  "cart_not_found"
531
111
  ]);
532
- var ended = (error) => _chunk4ORXUW2Ucjs.isCatalogError.call(void 0, error) && ENDED.has(error.code);
533
- var converted = (error) => _optionalChain([error, 'access', _23 => _23.details, 'optionalAccess', _24 => _24.reason]) === "converted";
112
+ var ended = (error) => _chunk2YQNMBDIcjs.isCatalogError.call(void 0, error) && ENDED.has(error.code);
113
+ var converted = (error) => _optionalChain([error, 'access', _2 => _2.details, 'optionalAccess', _3 => _3.reason]) === "converted";
534
114
  function itemsOf(cart) {
535
115
  const items = /* @__PURE__ */ new Map();
536
- for (const line of _nullishCoalesce(_optionalChain([cart, 'optionalAccess', _25 => _25.lineItems]), () => ( []))) {
116
+ for (const line of _nullishCoalesce(_optionalChain([cart, 'optionalAccess', _4 => _4.lineItems]), () => ( []))) {
537
117
  if (line.referenceId !== null)
538
118
  items.set(
539
119
  line.referenceId,
@@ -542,7 +122,9 @@ function itemsOf(cart) {
542
122
  }
543
123
  return items;
544
124
  }
545
- var skuOf = (cart, lineId) => _nullishCoalesce(_optionalChain([cart, 'optionalAccess', _26 => _26.lineItems, 'optionalAccess', _27 => _27.find, 'call', _28 => _28((line) => line.id === lineId), 'optionalAccess', _29 => _29.referenceId]), () => ( null));
125
+ var skuOf = (cart, lineId) => _nullishCoalesce(_optionalChain([cart, 'optionalAccess', _5 => _5.lineItems, 'optionalAccess', _6 => _6.find, 'call', _7 => _7((line) => line.id === lineId), 'optionalAccess', _8 => _8.referenceId]), () => ( null));
126
+ var CART_REREAD_MS = 3e4;
127
+ var TRANSPORT = Symbol.for("@usethrottle/catalog.transport");
546
128
  function createController(home) {
547
129
  var _a;
548
130
  const ctx = () => home.context;
@@ -551,16 +133,19 @@ function createController(home) {
551
133
  seen: void 0,
552
134
  moving: void 0,
553
135
  unremoved: false,
136
+ reads: /* @__PURE__ */ new Map(),
137
+ slots: /* @__PURE__ */ new Set(),
554
138
  abort: new AbortController(),
555
139
  writing: Promise.resolve(),
556
140
  tail: Promise.resolve()
557
141
  })));
558
142
  const retired = () => home.shared.home !== home;
559
- const box = createBox(EMPTY2);
143
+ const box = createBox(EMPTY);
560
144
  let queued = 0;
561
145
  let loaded = false;
562
146
  let currency;
563
- const reset = () => box.set({ ...EMPTY2, pending: queued > 0 });
147
+ let hinted;
148
+ const reset = () => box.set({ ...EMPTY, pending: queued > 0 });
564
149
  const session = (id) => {
565
150
  const { client, throttleBaseUrl } = ctx();
566
151
  return client.carts.session(
@@ -568,18 +153,112 @@ function createController(home) {
568
153
  throttleBaseUrl === void 0 ? void 0 : { throttleBaseUrl }
569
154
  );
570
155
  };
571
- const fallbackUrl = (id) => `${(_nullishCoalesce(ctx().throttleCheckoutUrl, () => ( _chunk4ORXUW2Ucjs.THROTTLE_CHECKOUT_URL))).replace(/\/+$/u, "")}/cart/${encodeURIComponent(id)}`;
156
+ const fallbackUrl = (id) => `${(_nullishCoalesce(ctx().throttleCheckoutUrl, () => ( _chunk2YQNMBDIcjs.THROTTLE_CHECKOUT_URL))).replace(/\/+$/u, "")}/cart/${encodeURIComponent(id)}`;
572
157
  const live = async (signal, value) => {
573
158
  const out = await value;
574
159
  if (signal.aborted) throw signal.reason;
575
160
  return out;
576
161
  };
162
+ const resuming = () => ctx().customerCart !== void 0 && ctx().customerKey !== null;
163
+ const wanted = (options) => {
164
+ const transport = ctx().client[TRANSPORT];
165
+ return _optionalChain([(_nullishCoalesce(_nullishCoalesce(_nullishCoalesce(currency, () => ( _optionalChain([options, 'optionalAccess', _9 => _9.currency]))), () => ( hinted)), () => ( _optionalChain([transport, 'optionalAccess', _10 => _10.context, 'optionalCall', _11 => _11(), 'access', _12 => _12.currency])))), 'optionalAccess', _13 => _13.toUpperCase, 'call', _14 => _14()]);
166
+ };
167
+ async function soft(signal, step) {
168
+ try {
169
+ await step();
170
+ } catch (error) {
171
+ if (signal.aborted) throw error;
172
+ }
173
+ }
174
+ async function find(signal, wantedCurrency, strict = false) {
175
+ const source = ctx().customerCart;
176
+ if (source === void 0 || wantedCurrency === void 0) return null;
177
+ const asked = wantedCurrency.toUpperCase();
178
+ try {
179
+ const found = await live(signal, source.getOpenCart({ currency: asked }));
180
+ return found !== null && found.currency.toUpperCase() === asked ? found : null;
181
+ } catch (error) {
182
+ if (signal.aborted || strict) throw error;
183
+ return null;
184
+ }
185
+ }
186
+ async function findTarget(signal, code, storage) {
187
+ if (resuming()) {
188
+ const found = await find(signal, code, true);
189
+ return found === null ? null : { id: found.sessionId, cartUrl: fallbackUrl(found.sessionId) };
190
+ }
191
+ if (ctx().customerKey !== null || storage.getFor === void 0) return null;
192
+ const id = await live(signal, storage.getFor(code));
193
+ if (id === null || id === "") return null;
194
+ try {
195
+ const answer = await live(signal, session(id).get({ signal }));
196
+ if (answer.cart.status !== "open" || answer.cart.currency.toUpperCase() !== code)
197
+ return null;
198
+ } catch (error) {
199
+ if (signal.aborted || !ended(error)) throw error;
200
+ return null;
201
+ }
202
+ return { id, cartUrl: fallbackUrl(id) };
203
+ }
204
+ async function findOnce(signal, storage) {
205
+ var _a2;
206
+ if (!resuming()) return;
207
+ const looked = _nullishCoalesce((_a2 = home.shared).looked, () => ( (_a2.looked = /* @__PURE__ */ new Set())));
208
+ const asked = wanted();
209
+ if (asked === void 0) return;
210
+ const key = `${ctx().customerKey}\0${asked}`;
211
+ if (looked.has(key)) return;
212
+ looked.add(key);
213
+ let found = null;
214
+ try {
215
+ found = await find(signal, asked);
216
+ } finally {
217
+ if (found === null) looked.delete(key);
218
+ }
219
+ if (found !== null) await soft(signal, () => adopt(signal, found, storage));
220
+ }
221
+ async function forgetSlots(storage, codes) {
222
+ for (const code of codes)
223
+ if (storage.removeFor !== void 0) await storage.removeFor(code);
224
+ else await _optionalChain([storage, 'access', _15 => _15.setFor, 'optionalCall', _16 => _16(code, "")]);
225
+ }
226
+ async function save(signal, storage, id) {
227
+ const write = storage.set(id);
228
+ me.writing = Promise.resolve(write).catch(() => void 0);
229
+ await live(signal, write);
230
+ }
231
+ async function adopt(signal, found, storage) {
232
+ const id = found.sessionId;
233
+ const answer = await live(signal, session(id).get({ signal }));
234
+ me.reads.set(id, Date.now());
235
+ await save(signal, storage, id);
236
+ box.set({
237
+ sessionId: id,
238
+ cartUrl: fallbackUrl(id),
239
+ cart: answer.cart,
240
+ status: "ready",
241
+ error: void 0
242
+ });
243
+ }
244
+ async function supersede(signal, answer, storage) {
245
+ if (answer.cart.status !== "abandoned" || !resuming()) return;
246
+ const found = await find(signal, answer.cart.currency);
247
+ if (found !== null && found.cartId !== answer.cart.cartId)
248
+ await adopt(signal, found, storage);
249
+ }
250
+ async function read(signal, id) {
251
+ const answer = await live(signal, session(id).get({ signal }));
252
+ me.reads.set(id, Date.now());
253
+ box.set({ cart: answer.cart, status: "ready", error: void 0 });
254
+ return answer;
255
+ }
577
256
  async function endSession(signal, error, storage) {
578
257
  await live(signal, storage.remove());
579
258
  if (converted(error)) reset();
580
259
  else box.set({ sessionId: null, cartUrl: null });
581
260
  }
582
- async function create(signal, options, items, whole = false) {
261
+ async function start(signal, options, items) {
583
262
  const context = ctx();
584
263
  const body = {
585
264
  items: [...items].map(([sku, quantity]) => ({ sku, quantity }))
@@ -588,9 +267,9 @@ function createController(home) {
588
267
  if (chosen !== void 0) body.currency = chosen;
589
268
  if (options.locale !== void 0) body.locale = options.locale;
590
269
  const urls = context.cartUrls;
591
- if (_optionalChain([urls, 'optionalAccess', _30 => _30.returnUrl]) !== void 0) body.returnUrl = urls.returnUrl;
592
- if (_optionalChain([urls, 'optionalAccess', _31 => _31.cancelUrl]) !== void 0) body.cancelUrl = urls.cancelUrl;
593
- if (_optionalChain([urls, 'optionalAccess', _32 => _32.storefrontUrl]) !== void 0)
270
+ if (_optionalChain([urls, 'optionalAccess', _17 => _17.returnUrl]) !== void 0) body.returnUrl = urls.returnUrl;
271
+ if (_optionalChain([urls, 'optionalAccess', _18 => _18.cancelUrl]) !== void 0) body.cancelUrl = urls.cancelUrl;
272
+ if (_optionalChain([urls, 'optionalAccess', _19 => _19.storefrontUrl]) !== void 0)
594
273
  body.storefrontUrl = urls.storefrontUrl;
595
274
  let answer;
596
275
  try {
@@ -603,33 +282,25 @@ function createController(home) {
603
282
  throw error;
604
283
  }
605
284
  const id = answer.sessionId;
606
- const cartUrl = isHttpUrl(answer.cartUrl) ? answer.cartUrl : fallbackUrl(id);
607
- if (whole) {
608
- const snapshot = await live(signal, session(id).get({ signal }));
609
- const write = context.cartStorage.set(id);
610
- me.writing = Promise.resolve(write).catch(() => void 0);
611
- await live(signal, write);
612
- box.set({
613
- sessionId: id,
614
- cartUrl,
615
- cart: snapshot.cart,
616
- status: "ready",
617
- error: void 0
618
- });
619
- return;
620
- }
285
+ return {
286
+ id,
287
+ cartUrl: isHttpUrl(answer.cartUrl) ? answer.cartUrl : fallbackUrl(id)
288
+ };
289
+ }
290
+ async function create(signal, options, items) {
291
+ const storage = ctx().cartStorage;
292
+ const { id, cartUrl } = await start(signal, options, items);
621
293
  box.set({ sessionId: id, cartUrl });
622
294
  let unsaved;
623
295
  try {
624
- const write = context.cartStorage.set(id);
625
- me.writing = Promise.resolve(write).catch(() => void 0);
626
- await live(signal, write);
296
+ await save(signal, storage, id);
627
297
  } catch (error) {
628
298
  if (signal.aborted) throw error;
629
299
  unsaved = error;
630
300
  }
631
301
  try {
632
302
  const snapshot = await live(signal, session(id).get({ signal }));
303
+ me.reads.set(id, Date.now());
633
304
  box.set({ cart: snapshot.cart, status: "ready", error: void 0 });
634
305
  } catch (error) {
635
306
  if (!signal.aborted) box.set({ status: "error" });
@@ -640,18 +311,52 @@ function createController(home) {
640
311
  async function mutate(signal, options, call, apply) {
641
312
  checkPause(ctx().store);
642
313
  const storage = ctx().cartStorage;
643
- const id = box.get().sessionId;
644
314
  let met;
645
- if (id !== null) {
315
+ const attempt = async (id2) => {
646
316
  try {
647
- const answer = await live(signal, call(session(id), signal));
317
+ const answer = await live(signal, call(session(id2), signal));
648
318
  if (answer !== null)
649
319
  box.set({ cart: answer.cart, status: "ready", error: void 0 });
650
- return void 0;
320
+ return true;
651
321
  } catch (error) {
652
322
  if (signal.aborted || !ended(error)) throw error;
653
323
  await endSession(signal, error, storage);
654
324
  met = error;
325
+ return false;
326
+ }
327
+ };
328
+ const stale = box.get().sessionId;
329
+ if (stale !== null && resuming() && Date.now() - (_nullishCoalesce(me.reads.get(stale), () => ( 0))) > CART_REREAD_MS) {
330
+ let answer;
331
+ try {
332
+ answer = await read(signal, stale);
333
+ } catch (error) {
334
+ if (signal.aborted) throw error;
335
+ if (ended(error)) {
336
+ await endSession(signal, error, storage);
337
+ met = error;
338
+ }
339
+ }
340
+ if (answer !== void 0) {
341
+ const seen = answer;
342
+ await soft(signal, () => supersede(signal, seen, storage));
343
+ }
344
+ }
345
+ const id = box.get().sessionId;
346
+ if (id !== null && await attempt(id)) return void 0;
347
+ if (resuming()) {
348
+ const found = await find(signal, wanted(options));
349
+ if (found !== null) {
350
+ let adopted = true;
351
+ await soft(signal, async () => {
352
+ try {
353
+ await adopt(signal, found, storage);
354
+ } catch (error) {
355
+ adopted = false;
356
+ throw error;
357
+ }
358
+ });
359
+ if (adopted && await attempt(found.sessionId)) return void 0;
655
360
  }
656
361
  }
657
362
  const cart = box.get().cart;
@@ -687,13 +392,16 @@ function createController(home) {
687
392
  me.tail = result.catch(() => void 0);
688
393
  return result;
689
394
  }
690
- async function restore(signal, storage = ctx().cartStorage) {
395
+ async function restore(signal, storage = ctx().cartStorage, look = true) {
691
396
  const id = await live(signal, storage.get());
692
- if (id === null || id === "") return;
397
+ if (id === null || id === "") {
398
+ if (look) await findOnce(signal, storage);
399
+ return;
400
+ }
693
401
  box.set({ sessionId: id, cartUrl: fallbackUrl(id), status: "loading" });
402
+ let answer;
694
403
  try {
695
- const answer = await live(signal, session(id).get({ signal }));
696
- box.set({ cart: answer.cart, status: "ready", error: void 0 });
404
+ answer = await read(signal, id);
697
405
  } catch (error) {
698
406
  if (signal.aborted) return;
699
407
  if (!ended(error)) {
@@ -707,7 +415,10 @@ function createController(home) {
707
415
  return;
708
416
  }
709
417
  reset();
418
+ if (look) await findOnce(signal, storage);
419
+ return;
710
420
  }
421
+ if (look) await soft(signal, () => supersede(signal, answer, storage));
711
422
  }
712
423
  function load() {
713
424
  if (loaded) return;
@@ -716,6 +427,17 @@ function createController(home) {
716
427
  const signal = me.abort.signal;
717
428
  me.tail = me.tail.then(() => me.unremoved ? void 0 : restore(signal)).catch(() => void 0);
718
429
  }
430
+ async function claimSettled(signal) {
431
+ const source = ctx().customerCart;
432
+ if (source === void 0) return false;
433
+ try {
434
+ await live(signal, source.whenClaimSettled());
435
+ return true;
436
+ } catch (error) {
437
+ if (signal.aborted) throw error;
438
+ return false;
439
+ }
440
+ }
719
441
  function follow(guest, fresh) {
720
442
  const signal = me.abort.signal;
721
443
  me.moving = guest;
@@ -727,18 +449,32 @@ function createController(home) {
727
449
  me.tail = me.tail.then(async () => {
728
450
  await me.writing;
729
451
  if (signal.aborted) return;
730
- if (fresh && !me.unremoved) await restore(signal, guest);
452
+ if (fresh && !me.unremoved) await restore(signal, guest, false);
731
453
  if (signal.aborted) return;
454
+ const codes = new Set(me.slots);
455
+ const shown = _optionalChain([box, 'access', _20 => _20.get, 'call', _21 => _21(), 'access', _22 => _22.cart, 'optionalAccess', _23 => _23.currency]);
456
+ if (shown !== void 0) codes.add(shown.toUpperCase());
457
+ await live(signal, forgetSlots(guest, codes));
458
+ me.slots.clear();
732
459
  const id = box.get().sessionId;
733
460
  if (id === null) {
734
- if (box.get().cart === null && !me.unremoved) return restore(signal);
461
+ if (box.get().cart === null && !me.unremoved) {
462
+ await claimSettled(signal);
463
+ return restore(signal);
464
+ }
735
465
  return;
736
466
  }
737
467
  const next = ctx().cartStorage;
738
468
  await write(next, id);
739
- if (guest === next) return;
740
- await live(signal, guest.remove());
741
- if (await live(signal, next.get()) !== id) await write(next, id);
469
+ if (guest !== next) {
470
+ await live(signal, guest.remove());
471
+ if (await live(signal, next.get()) !== id) await write(next, id);
472
+ }
473
+ if (resuming() && await claimSettled(signal))
474
+ await soft(
475
+ signal,
476
+ async () => supersede(signal, await read(signal, id), next)
477
+ );
742
478
  }).catch((error) => {
743
479
  if (!signal.aborted) box.set({ error: wrap(error) });
744
480
  }).finally(() => {
@@ -758,6 +494,9 @@ function createController(home) {
758
494
  if (was === void 0 || was === null || was === key) return;
759
495
  me.abort.abort();
760
496
  me.abort = new AbortController();
497
+ me.reads.clear();
498
+ for (const key2 of _nullishCoalesce(home.shared.looked, () => ( [])))
499
+ if (key2.startsWith(`${was}\0`)) _optionalChain([home, 'access', _24 => _24.shared, 'access', _25 => _25.looked, 'optionalAccess', _26 => _26.delete, 'call', _27 => _27(key2)]);
761
500
  currency = void 0;
762
501
  loaded = true;
763
502
  reset();
@@ -765,9 +504,15 @@ function createController(home) {
765
504
  const outgoing = _nullishCoalesce(prior, () => ( me.seen));
766
505
  const left = me.moving;
767
506
  me.moving = void 0;
507
+ const slots = [...me.slots];
508
+ me.slots.clear();
768
509
  const remove = async () => {
769
510
  await outgoing.remove();
770
- if (left !== void 0 && left !== outgoing) await left.remove();
511
+ await forgetSlots(outgoing, slots);
512
+ if (left !== void 0 && left !== outgoing) {
513
+ await left.remove();
514
+ await forgetSlots(left, slots);
515
+ }
771
516
  };
772
517
  me.tail = me.writing.then(remove).catch(remove).then(
773
518
  () => {
@@ -784,12 +529,16 @@ function createController(home) {
784
529
  box,
785
530
  /** The customer the cart belongs to (`undefined` before the first look). */
786
531
  owner: () => me.owner,
532
+ hint: (next) => {
533
+ hinted = next;
534
+ },
787
535
  identify,
788
536
  load,
789
537
  run,
790
538
  mutate,
791
539
  create,
792
540
  session,
541
+ wanted,
793
542
  async switchCurrency(signal, options, next) {
794
543
  checkPause(ctx().store);
795
544
  const storage = ctx().cartStorage;
@@ -806,28 +555,67 @@ function createController(home) {
806
555
  }
807
556
  const before = currency;
808
557
  currency = next;
809
- const items = itemsOf(box.get().cart);
810
- if (items.size === 0) {
811
- if (box.get().sessionId !== null) await live(signal, storage.remove());
812
- reset();
558
+ const code = next.toUpperCase();
559
+ const from = box.get().sessionId;
560
+ const cart = box.get().cart;
561
+ const items = itemsOf(cart);
562
+ if (from === null || items.size === 0) {
563
+ if (from !== null) await live(signal, storage.remove());
564
+ if (items.size === 0) reset();
813
565
  return;
814
566
  }
567
+ if (_optionalChain([cart, 'optionalAccess', _28 => _28.currency, 'access', _29 => _29.toUpperCase, 'call', _30 => _30()]) === code) return;
568
+ let target;
569
+ let moved;
815
570
  try {
816
- await create(signal, options, items, true);
571
+ target = await _asyncNullishCoalesce(await findTarget(signal, code, storage), async () => ( await start(signal, options, /* @__PURE__ */ new Map())));
572
+ moved = await live(signal, session(target.id).absorb(from, { signal }));
817
573
  } catch (error) {
818
574
  if (!signal.aborted) currency = before;
819
575
  throw error;
820
576
  }
577
+ me.reads.set(target.id, Date.now());
578
+ box.set({
579
+ sessionId: target.id,
580
+ cartUrl: target.cartUrl,
581
+ cart: moved.cart,
582
+ status: "ready",
583
+ error: void 0,
584
+ warnings: moved.warnings.filter(
585
+ (warning) => warning.code !== "lines_stale"
586
+ )
587
+ });
588
+ let unsaved;
589
+ try {
590
+ await save(signal, storage, target.id);
591
+ } catch (error) {
592
+ if (signal.aborted) throw error;
593
+ unsaved = error;
594
+ try {
595
+ await live(signal, storage.remove());
596
+ } catch (failure) {
597
+ if (signal.aborted) throw failure;
598
+ }
599
+ }
600
+ if (ctx().customerKey === null && storage.setFor !== void 0) {
601
+ me.slots.add(code);
602
+ await live(signal, storage.setFor(code, target.id));
603
+ }
604
+ if (unsaved !== void 0) throw unsaved;
821
605
  },
822
606
  async clear(signal) {
823
- await live(signal, ctx().cartStorage.remove());
607
+ const storage = ctx().cartStorage;
608
+ const shown = _optionalChain([box, 'access', _31 => _31.get, 'call', _32 => _32(), 'access', _33 => _33.cart, 'optionalAccess', _34 => _34.currency]);
609
+ await live(signal, storage.remove());
610
+ if (shown !== void 0)
611
+ await live(signal, _optionalChain([storage, 'access', _35 => _35.removeFor, 'optionalCall', _36 => _36(shown.toUpperCase())]));
824
612
  currency = void 0;
825
613
  reset();
826
614
  }
827
615
  };
828
616
  }
829
617
  function useCart(options = {}) {
830
- const context = useCatalogContext();
618
+ const context = _chunkGU63WFXIcjs.useCatalogContext.call(void 0, );
831
619
  const home = context.cart;
832
620
  const controller = _nullishCoalesce(home.current, () => ( (home.current = createController(home))));
833
621
  const state = _react.useSyncExternalStore.call(void 0,
@@ -836,6 +624,10 @@ function useCart(options = {}) {
836
624
  controller.box.get
837
625
  );
838
626
  const { customerKey } = context;
627
+ const hooked = options.currency;
628
+ _react.useEffect.call(void 0, () => {
629
+ controller.hint(hooked);
630
+ }, [controller, hooked]);
839
631
  _react.useEffect.call(void 0, () => {
840
632
  controller.identify(customerKey);
841
633
  controller.load();
@@ -873,8 +665,8 @@ function useCart(options = {}) {
873
665
  ),
874
666
  checkout: (input) => controller.run(async (signal) => {
875
667
  const { cartUrls } = home.context;
876
- const returnUrl = _nullishCoalesce(_optionalChain([input, 'optionalAccess', _33 => _33.returnUrl]), () => ( _optionalChain([cartUrls, 'optionalAccess', _34 => _34.returnUrl])));
877
- const cancelUrl = _nullishCoalesce(_optionalChain([input, 'optionalAccess', _35 => _35.cancelUrl]), () => ( _optionalChain([cartUrls, 'optionalAccess', _36 => _36.cancelUrl])));
668
+ const returnUrl = _nullishCoalesce(_optionalChain([input, 'optionalAccess', _37 => _37.returnUrl]), () => ( _optionalChain([cartUrls, 'optionalAccess', _38 => _38.returnUrl])));
669
+ const cancelUrl = _nullishCoalesce(_optionalChain([input, 'optionalAccess', _39 => _39.cancelUrl]), () => ( _optionalChain([cartUrls, 'optionalAccess', _40 => _40.cancelUrl])));
878
670
  if (returnUrl === void 0 || cancelUrl === void 0)
879
671
  throw refuse(
880
672
  "checkout() needs returnUrl and cancelUrl, given or from the provider cartUrls."
@@ -897,7 +689,7 @@ function useCart(options = {}) {
897
689
  { signal: callSignal }
898
690
  );
899
691
  } catch (error) {
900
- const repriced = _chunk4ORXUW2Ucjs.isCatalogError.call(void 0, error) && error.code === "cart_prices_changed" ? _optionalChain([error, 'access', _37 => _37.details, 'optionalAccess', _38 => _38.cart]) : void 0;
692
+ const repriced = _chunk2YQNMBDIcjs.isCatalogError.call(void 0, error) && error.code === "cart_prices_changed" ? _optionalChain([error, 'access', _41 => _41.details, 'optionalAccess', _42 => _42.cart]) : void 0;
901
693
  if (!callSignal.aborted && typeof repriced === "object" && repriced !== null)
902
694
  controller.box.set({ cart: repriced });
903
695
  throw error;
@@ -917,7 +709,7 @@ function useCart(options = {}) {
917
709
  if (out === void 0)
918
710
  throw _nullishCoalesce(met, () => ( refuse("There is no cart to check out.")));
919
711
  if (!isHttpUrl(out.checkoutUrl))
920
- throw new (0, _chunk4ORXUW2Ucjs.CatalogError)({
712
+ throw new (0, _chunk2YQNMBDIcjs.CatalogError)({
921
713
  code: "INVALID_RESPONSE",
922
714
  message: "Throttle answered a checkout URL that is not http or https.",
923
715
  statusCode: 200,
@@ -933,8 +725,10 @@ function useCart(options = {}) {
933
725
  };
934
726
  }, [controller, home, currency, locale]);
935
727
  const owner = controller.owner();
936
- const view = owner !== void 0 && owner !== null && owner !== customerKey ? { ...EMPTY2, pending: state.pending } : state;
937
- return { ...view, ...actions };
728
+ const view = owner !== void 0 && owner !== null && owner !== customerKey ? { ...EMPTY, pending: state.pending } : state;
729
+ const shownCurrency = _nullishCoalesce(_nullishCoalesce(_optionalChain([view, 'access', _43 => _43.cart, 'optionalAccess', _44 => _44.currency]), () => ( controller.wanted(options))), () => ( ""));
730
+ const format = (minor) => _chunk2YQNMBDIcjs.formatMoney.call(void 0, minor, shownCurrency);
731
+ return { ...view, ...actions, format };
938
732
  }
939
733
 
940
734
  // src/react/use-submit-review.ts
@@ -945,7 +739,7 @@ var IDLE = {
945
739
  result: void 0
946
740
  };
947
741
  function useSubmitReview(handle) {
948
- const { client, store, customerKey } = useCatalogContext();
742
+ const { client, store, customerKey } = _chunkGU63WFXIcjs.useCatalogContext.call(void 0, );
949
743
  const scope = _react.useMemo.call(void 0,
950
744
  () => ({
951
745
  box: createBox(IDLE),
@@ -1015,4 +809,5 @@ function useSubmitReview(handle) {
1015
809
 
1016
810
 
1017
811
 
1018
- exports.CatalogProvider = CatalogProvider; exports.SDK_VERSION = _chunk4ORXUW2Ucjs.SDK_VERSION; exports.catalogQueryKey = catalogQueryKey; exports.createMemoryCartStorage = createMemoryCartStorage; exports.useCart = useCart; exports.useCatalog = useCatalog; exports.useCategories = useCategories; exports.useCollection = useCollection; exports.useConfig = useConfig; exports.useFilterValues = useFilterValues; exports.useProduct = useProduct; exports.useProducts = useProducts; exports.useRelated = useRelated; exports.useReviews = useReviews; exports.useSubmitReview = useSubmitReview; exports.useSuggest = useSuggest;
812
+
813
+ exports.CatalogProvider = _chunkGU63WFXIcjs.CatalogProvider; exports.SDK_VERSION = _chunk2YQNMBDIcjs.SDK_VERSION; exports.catalogQueryKey = _chunkGU63WFXIcjs.catalogQueryKey; exports.createMemoryCartStorage = _chunkGU63WFXIcjs.createMemoryCartStorage; exports.useCart = useCart; exports.useCatalog = _chunkGU63WFXIcjs.useCatalog; exports.useCategories = _chunkGU63WFXIcjs.useCategories; exports.useCollection = _chunkGU63WFXIcjs.useCollection; exports.useConfig = _chunkGU63WFXIcjs.useConfig; exports.useCustomerKey = _chunkGU63WFXIcjs.useCustomerKey; exports.useFilterValues = _chunkGU63WFXIcjs.useFilterValues; exports.useProduct = _chunkGU63WFXIcjs.useProduct; exports.useProducts = _chunkGU63WFXIcjs.useProducts; exports.useRelated = _chunkGU63WFXIcjs.useRelated; exports.useReviews = _chunkGU63WFXIcjs.useReviews; exports.useSubmitReview = useSubmitReview; exports.useSuggest = _chunkGU63WFXIcjs.useSuggest;