@cimplify/sdk 0.8.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.js CHANGED
@@ -1,8 +1,12 @@
1
1
  'use strict';
2
2
 
3
- var react = require('react');
3
+ var React2 = require('react');
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
 
6
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
+
8
+ var React2__default = /*#__PURE__*/_interopDefault(React2);
9
+
6
10
  // src/react/index.tsx
7
11
 
8
12
  // src/types/elements.ts
@@ -16,6 +20,7 @@ var MESSAGE_TYPES = {
16
20
  // Parent → Iframe
17
21
  INIT: "init",
18
22
  SET_TOKEN: "set_token",
23
+ SET_CART: "set_cart",
19
24
  GET_DATA: "get_data",
20
25
  PROCESS_CHECKOUT: "process_checkout",
21
26
  ABORT_CHECKOUT: "abort_checkout",
@@ -33,7 +38,8 @@ var MESSAGE_TYPES = {
33
38
  CONTACT_PROVIDED: "contact_provided",
34
39
  CHECKOUT_STATUS: "checkout_status",
35
40
  CHECKOUT_COMPLETE: "checkout_complete",
36
- ORDER_TYPE_CHANGED: "order_type_changed"
41
+ ORDER_TYPE_CHANGED: "order_type_changed",
42
+ REQUEST_SUBMIT: "request_submit"
37
43
  };
38
44
  var EVENT_TYPES = {
39
45
  READY: "ready",
@@ -41,7 +47,8 @@ var EVENT_TYPES = {
41
47
  REQUIRES_OTP: "requires_otp",
42
48
  ERROR: "error",
43
49
  CHANGE: "change",
44
- ORDER_TYPE_CHANGED: "order_type_changed"
50
+ ORDER_TYPE_CHANGED: "order_type_changed",
51
+ REQUEST_SUBMIT: "request_submit"
45
52
  };
46
53
 
47
54
  // src/ads/identity.ts
@@ -194,7 +201,7 @@ function deriveAdsApiUrl() {
194
201
  }
195
202
  return "https://api.cimplify.io";
196
203
  }
197
- var AdContext = react.createContext({
204
+ var AdContext = React2.createContext({
198
205
  siteId: null,
199
206
  config: null,
200
207
  isLoading: true,
@@ -202,7 +209,7 @@ var AdContext = react.createContext({
202
209
  apiBase: "https://api.cimplify.io"
203
210
  });
204
211
  function useAds() {
205
- return react.useContext(AdContext);
212
+ return React2.useContext(AdContext);
206
213
  }
207
214
  function AdProvider({
208
215
  siteId,
@@ -211,10 +218,10 @@ function AdProvider({
211
218
  children
212
219
  }) {
213
220
  const resolvedApiBase = apiBase || deriveAdsApiUrl();
214
- const [config, setConfig] = react.useState(null);
215
- const [isLoading, setIsLoading] = react.useState(true);
216
- const [identity, setIdentity] = react.useState(null);
217
- react.useEffect(() => {
221
+ const [config, setConfig] = React2.useState(null);
222
+ const [isLoading, setIsLoading] = React2.useState(true);
223
+ const [identity, setIdentity] = React2.useState(null);
224
+ React2.useEffect(() => {
218
225
  const userIdentity = getUserIdentity(authenticatedAccountId);
219
226
  setIdentity(userIdentity);
220
227
  fetch(`${resolvedApiBase}/ads/config/${siteId}`).then((r) => r.json()).then((data) => {
@@ -237,11 +244,11 @@ function Ad({
237
244
  onClick
238
245
  }) {
239
246
  const { siteId, config, isLoading, identity, apiBase } = useAds();
240
- const [ad, setAd] = react.useState(null);
241
- const [error, setError] = react.useState(false);
242
- const impressionTracked = react.useRef(false);
243
- const containerRef = react.useRef(null);
244
- react.useEffect(() => {
247
+ const [ad, setAd] = React2.useState(null);
248
+ const [error, setError] = React2.useState(false);
249
+ const impressionTracked = React2.useRef(false);
250
+ const containerRef = React2.useRef(null);
251
+ React2.useEffect(() => {
245
252
  if (isLoading || !config?.enabled || !siteId || !identity) return;
246
253
  const path = typeof window !== "undefined" ? window.location.pathname : "/";
247
254
  const referrer = typeof document !== "undefined" ? document.referrer : "";
@@ -284,7 +291,7 @@ function Ad({
284
291
  }
285
292
  }).catch(() => setError(true));
286
293
  }, [siteId, config, isLoading, slot, identity, apiBase]);
287
- react.useEffect(() => {
294
+ React2.useEffect(() => {
288
295
  if (!ad || impressionTracked.current || typeof window === "undefined" || !identity) return;
289
296
  const observer = new IntersectionObserver(
290
297
  ([entry]) => {
@@ -343,7 +350,62 @@ function Ad({
343
350
  }
344
351
  );
345
352
  }
346
- var SPACE = { sm: 8, md: 12, lg: 16, xl: 24 };
353
+
354
+ // src/utils/cart-transform.ts
355
+ function getSelections(item) {
356
+ if (item.bundle_resolved?.selections?.length) {
357
+ return item.bundle_resolved.selections.map((s) => ({
358
+ name: s.product_name || s.component_id,
359
+ quantity: s.quantity,
360
+ variant_name: s.variant_name
361
+ }));
362
+ }
363
+ if (item.composite_resolved?.selections?.length) {
364
+ return item.composite_resolved.selections.map((s) => ({
365
+ name: s.component_name || s.component_id,
366
+ quantity: s.quantity
367
+ }));
368
+ }
369
+ return void 0;
370
+ }
371
+ function mapItem(item) {
372
+ const result = {
373
+ name: item.name,
374
+ quantity: item.quantity,
375
+ unit_price: String(item.base_price),
376
+ total_price: String(item.total_price),
377
+ line_type: item.line_type
378
+ };
379
+ if (item.image_url) result.image_url = item.image_url;
380
+ const variantName = item.variant_info?.name || item.variant_name || void 0;
381
+ if (variantName) result.variant_name = variantName;
382
+ if (item.scheduled_start) result.scheduled_start = item.scheduled_start;
383
+ if (item.scheduled_end) result.scheduled_end = item.scheduled_end;
384
+ const selections = getSelections(item);
385
+ if (selections) result.selections = selections;
386
+ if (item.add_on_options?.length) {
387
+ result.add_ons = item.add_on_options.map((opt) => ({
388
+ name: opt.name,
389
+ price: String(opt.price ?? "0")
390
+ }));
391
+ }
392
+ if (item.special_instructions) {
393
+ result.special_instructions = item.special_instructions;
394
+ }
395
+ return result;
396
+ }
397
+ function transformToCheckoutCart(cart) {
398
+ return {
399
+ items: cart.items.map(mapItem),
400
+ subtotal: String(cart.pricing.subtotal),
401
+ tax_amount: String(cart.pricing.tax_amount),
402
+ total_discounts: String(cart.pricing.total_discounts),
403
+ service_charge: String(cart.pricing.service_charge),
404
+ total: String(cart.pricing.total_price),
405
+ currency: cart.pricing.currency
406
+ };
407
+ }
408
+ var SPACE = { sm: 8};
347
409
  function shellColors(isDark, primaryColor) {
348
410
  return {
349
411
  text: isDark ? "#f4f4f5" : "#1a1a1a",
@@ -397,49 +459,48 @@ function CimplifyCheckout({
397
459
  demoMode,
398
460
  className
399
461
  }) {
400
- const resolvedOrderTypes = react.useMemo(
462
+ const resolvedOrderTypes = React2.useMemo(
401
463
  () => orderTypes && orderTypes.length > 0 ? orderTypes : ["pickup", "delivery"],
402
464
  [orderTypes]
403
465
  );
404
- const [orderType, setOrderType] = react.useState(resolvedOrderTypes[0] || "pickup");
405
- const [status, setStatus] = react.useState(null);
406
- const [statusText, setStatusText] = react.useState("");
407
- const [isSubmitting, setIsSubmitting] = react.useState(false);
408
- const [isInitializing, setIsInitializing] = react.useState(false);
409
- const [errorMessage, setErrorMessage] = react.useState(null);
410
- const [resolvedBusinessId, setResolvedBusinessId] = react.useState(businessId ?? null);
411
- const [resolvedCartId, setResolvedCartId] = react.useState(cartId ?? null);
412
- const checkoutMountRef = react.useRef(null);
413
- const elementsRef = react.useRef(null);
414
- const activeCheckoutRef = react.useRef(null);
415
- const initialAppearanceRef = react.useRef(appearance);
416
- const hasWarnedInlineAppearanceRef = react.useRef(false);
417
- const isMountedRef = react.useRef(true);
418
- const demoRunRef = react.useRef(0);
419
- const onCompleteRef = react.useRef(onComplete);
420
- const onErrorRef = react.useRef(onError);
421
- const onStatusChangeRef = react.useRef(onStatusChange);
422
- onCompleteRef.current = onComplete;
423
- onErrorRef.current = onError;
424
- onStatusChangeRef.current = onStatusChange;
466
+ const [orderType, setOrderType] = React2.useState(resolvedOrderTypes[0] || "pickup");
467
+ const [status, setStatus] = React2.useState(null);
468
+ const [statusText, setStatusText] = React2.useState("");
469
+ const [isSubmitting, setIsSubmitting] = React2.useState(false);
470
+ const [isInitializing, setIsInitializing] = React2.useState(false);
471
+ const [errorMessage, setErrorMessage] = React2.useState(null);
472
+ const [resolvedBusinessId, setResolvedBusinessId] = React2.useState(businessId ?? null);
473
+ const [resolvedCartId, setResolvedCartId] = React2.useState(cartId ?? null);
474
+ const [resolvedCart, setResolvedCart] = React2.useState(null);
475
+ const checkoutMountRef = React2.useRef(null);
476
+ const elementsRef = React2.useRef(null);
477
+ const activeCheckoutRef = React2.useRef(null);
478
+ const initialAppearanceRef = React2.useRef(appearance);
479
+ const hasWarnedInlineAppearanceRef = React2.useRef(false);
480
+ const isMountedRef = React2.useRef(true);
481
+ const demoRunRef = React2.useRef(0);
425
482
  const isDemoCheckout = demoMode ?? client.getPublicKey().trim().length === 0;
426
483
  const isTestMode = client.isTestMode();
427
484
  const primaryColor = appearance?.variables?.primaryColor || "#0a2540";
428
485
  const isDark = appearance?.theme === "dark";
429
- const emitStatus = react.useCallback(
486
+ const emitStatus = React2__default.default.useEffectEvent(
430
487
  (nextStatus, context = {}) => {
431
488
  setStatus(nextStatus);
432
489
  setStatusText(context.display_text || "");
433
- onStatusChangeRef.current?.(nextStatus, context);
434
- },
435
- []
490
+ onStatusChange?.(nextStatus, context);
491
+ }
492
+ );
493
+ const fireError = React2__default.default.useEffectEvent(
494
+ (error) => {
495
+ onError?.(error);
496
+ }
436
497
  );
437
- react.useEffect(() => {
498
+ React2.useEffect(() => {
438
499
  if (!resolvedOrderTypes.includes(orderType)) {
439
500
  setOrderType(resolvedOrderTypes[0] || "pickup");
440
501
  }
441
502
  }, [resolvedOrderTypes, orderType]);
442
- react.useEffect(() => {
503
+ React2.useEffect(() => {
443
504
  if (appearance && appearance !== initialAppearanceRef.current && !hasWarnedInlineAppearanceRef.current) {
444
505
  hasWarnedInlineAppearanceRef.current = true;
445
506
  console.warn(
@@ -447,7 +508,7 @@ function CimplifyCheckout({
447
508
  );
448
509
  }
449
510
  }, [appearance]);
450
- react.useEffect(() => {
511
+ React2.useEffect(() => {
451
512
  let cancelled = false;
452
513
  async function bootstrap() {
453
514
  if (isDemoCheckout) {
@@ -468,6 +529,12 @@ function CimplifyCheckout({
468
529
  setIsInitializing(false);
469
530
  setErrorMessage(null);
470
531
  }
532
+ client.cart.get().then((cartResult) => {
533
+ if (!cancelled && cartResult.ok && cartResult.value) {
534
+ setResolvedCart(cartResult.value);
535
+ }
536
+ }).catch(() => {
537
+ });
471
538
  return;
472
539
  }
473
540
  if (!cancelled) {
@@ -485,7 +552,7 @@ function CimplifyCheckout({
485
552
  setResolvedCartId(null);
486
553
  setErrorMessage(message);
487
554
  setIsInitializing(false);
488
- onErrorRef.current?.({ code: "BUSINESS_ID_REQUIRED", message });
555
+ fireError({ code: "BUSINESS_ID_REQUIRED", message });
489
556
  }
490
557
  return;
491
558
  }
@@ -500,11 +567,14 @@ function CimplifyCheckout({
500
567
  setResolvedCartId(null);
501
568
  setErrorMessage(message);
502
569
  setIsInitializing(false);
503
- onErrorRef.current?.({ code: "CART_EMPTY", message });
570
+ fireError({ code: "CART_EMPTY", message });
504
571
  }
505
572
  return;
506
573
  }
507
574
  nextCartId = cartResult.value.id;
575
+ if (!cancelled) {
576
+ setResolvedCart(cartResult.value);
577
+ }
508
578
  }
509
579
  if (!cancelled) {
510
580
  setResolvedBusinessId(nextBusinessId);
@@ -518,7 +588,7 @@ function CimplifyCheckout({
518
588
  cancelled = true;
519
589
  };
520
590
  }, [businessId, cartId, client, isDemoCheckout]);
521
- react.useEffect(() => {
591
+ React2.useEffect(() => {
522
592
  return () => {
523
593
  isMountedRef.current = false;
524
594
  demoRunRef.current += 1;
@@ -526,42 +596,12 @@ function CimplifyCheckout({
526
596
  activeCheckoutRef.current = null;
527
597
  };
528
598
  }, []);
529
- react.useEffect(() => {
530
- if (isDemoCheckout || !resolvedBusinessId) {
531
- elementsRef.current = null;
532
- return;
533
- }
534
- const elements = client.elements(resolvedBusinessId, {
535
- appearance: initialAppearanceRef.current,
536
- linkUrl
537
- });
538
- elementsRef.current = elements;
539
- const checkout = elements.create("checkout", {
540
- orderTypes: resolvedOrderTypes,
541
- defaultOrderType: resolvedOrderTypes[0]
542
- });
543
- if (checkoutMountRef.current) {
544
- checkout.mount(checkoutMountRef.current);
545
- }
546
- checkout.on("order_type_changed", (data) => {
547
- const typed = data;
548
- if (typed.orderType) {
549
- setOrderType(typed.orderType);
550
- }
551
- });
552
- return () => {
553
- activeCheckoutRef.current?.abort();
554
- activeCheckoutRef.current = null;
555
- elements.destroy();
556
- elementsRef.current = null;
557
- };
558
- }, [client, resolvedBusinessId, isDemoCheckout]);
559
- const handleSubmit = react.useCallback(async () => {
599
+ const handleSubmit = React2__default.default.useEffectEvent(async () => {
560
600
  if (isSubmitting || isInitializing || !resolvedCartId) {
561
601
  if (!resolvedCartId && !isInitializing) {
562
602
  const message = "Your cart is empty. Add items before checkout.";
563
603
  setErrorMessage(message);
564
- onErrorRef.current?.({ code: "CART_EMPTY", message });
604
+ fireError({ code: "CART_EMPTY", message });
565
605
  }
566
606
  return;
567
607
  }
@@ -596,7 +636,7 @@ function CimplifyCheckout({
596
636
  order_number: result.order?.order_number,
597
637
  display_text: statusToLabel("success")
598
638
  });
599
- onCompleteRef.current(result);
639
+ onComplete(result);
600
640
  } finally {
601
641
  if (isMountedRef.current && runId === demoRunRef.current) {
602
642
  setIsSubmitting(false);
@@ -607,7 +647,7 @@ function CimplifyCheckout({
607
647
  if (!elementsRef.current) {
608
648
  const message = "Checkout is still initializing. Please try again.";
609
649
  setErrorMessage(message);
610
- onErrorRef.current?.({ code: "CHECKOUT_NOT_READY", message });
650
+ fireError({ code: "CHECKOUT_NOT_READY", message });
611
651
  setIsSubmitting(false);
612
652
  return;
613
653
  }
@@ -622,30 +662,65 @@ function CimplifyCheckout({
622
662
  try {
623
663
  const result = await checkout;
624
664
  if (result.success) {
625
- onCompleteRef.current(result);
665
+ onComplete(result);
626
666
  return;
627
667
  }
628
668
  const code = result.error?.code || "CHECKOUT_FAILED";
629
669
  const message = result.error?.message || "Payment failed.";
630
670
  setErrorMessage(message);
631
- onErrorRef.current?.({ code, message });
671
+ fireError({ code, message });
632
672
  } finally {
633
673
  if (isMountedRef.current) {
634
674
  activeCheckoutRef.current = null;
635
675
  setIsSubmitting(false);
636
676
  }
637
677
  }
638
- }, [
639
- resolvedCartId,
640
- client,
641
- enrollInLink,
642
- emitStatus,
643
- isDemoCheckout,
644
- isInitializing,
645
- isSubmitting,
646
- locationId,
647
- orderType
648
- ]);
678
+ });
679
+ React2.useEffect(() => {
680
+ if (isDemoCheckout || !resolvedBusinessId) {
681
+ elementsRef.current = null;
682
+ return;
683
+ }
684
+ const elements = client.elements(resolvedBusinessId, {
685
+ appearance: initialAppearanceRef.current,
686
+ linkUrl
687
+ });
688
+ elementsRef.current = elements;
689
+ const checkout = elements.create("checkout", {
690
+ orderTypes: resolvedOrderTypes,
691
+ defaultOrderType: resolvedOrderTypes[0]
692
+ });
693
+ if (checkoutMountRef.current) {
694
+ checkout.mount(checkoutMountRef.current);
695
+ }
696
+ checkout.on("ready", () => {
697
+ if (resolvedCart) {
698
+ checkout.setCart(transformToCheckoutCart(resolvedCart));
699
+ }
700
+ });
701
+ checkout.on("order_type_changed", (data) => {
702
+ const typed = data;
703
+ if (typed.orderType) {
704
+ setOrderType(typed.orderType);
705
+ }
706
+ });
707
+ checkout.on("request_submit", () => {
708
+ void handleSubmit();
709
+ });
710
+ return () => {
711
+ activeCheckoutRef.current?.abort();
712
+ activeCheckoutRef.current = null;
713
+ elements.destroy();
714
+ elementsRef.current = null;
715
+ };
716
+ }, [client, resolvedBusinessId, isDemoCheckout]);
717
+ React2.useEffect(() => {
718
+ if (!resolvedCart || !elementsRef.current) return;
719
+ const checkoutElement = elementsRef.current.getElement("checkout");
720
+ if (checkoutElement) {
721
+ checkoutElement.setCart(transformToCheckoutCart(resolvedCart));
722
+ }
723
+ }, [resolvedCart]);
649
724
  const colors = shellColors(isDark ?? false, primaryColor);
650
725
  if (isInitializing) {
651
726
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className, "data-cimplify-checkout": "", children: /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-status": "", style: { fontSize: 13, color: colors.textSecondary }, children: "Preparing checkout..." }) });
@@ -668,28 +743,6 @@ function CimplifyCheckout({
668
743
  }
669
744
  ),
670
745
  /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-section": "checkout", children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: isDemoCheckout ? void 0 : checkoutMountRef }) }),
671
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: SPACE.xl }, children: /* @__PURE__ */ jsxRuntime.jsx(
672
- "button",
673
- {
674
- type: "button",
675
- onClick: handleSubmit,
676
- disabled: isSubmitting,
677
- style: {
678
- width: "100%",
679
- padding: `${SPACE.md}px ${SPACE.lg}px`,
680
- borderRadius: 8,
681
- border: "none",
682
- background: isSubmitting ? colors.textMuted : primaryColor,
683
- color: "#ffffff",
684
- cursor: isSubmitting ? "not-allowed" : "pointer",
685
- fontWeight: 600,
686
- fontSize: 16,
687
- transition: "all 150ms ease",
688
- WebkitTapHighlightColor: "transparent"
689
- },
690
- children: isSubmitting ? "Processing..." : "Complete Order"
691
- }
692
- ) }),
693
746
  status && /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-status": "", style: { marginTop: SPACE.sm, fontSize: 13, color: colors.textSecondary }, children: statusText || statusToLabel(status) }),
694
747
  errorMessage && /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-error": "", style: { marginTop: SPACE.sm, fontSize: 13, color: colors.error }, children: errorMessage })
695
748
  ] });
@@ -1299,6 +1352,13 @@ var CartOperations = class {
1299
1352
  }
1300
1353
  };
1301
1354
 
1355
+ // src/constants.ts
1356
+ var MOBILE_MONEY_PROVIDER = {
1357
+ MTN: "mtn",
1358
+ VODAFONE: "vodafone",
1359
+ AIRTEL: "airtel"
1360
+ };
1361
+
1302
1362
  // src/utils/price.ts
1303
1363
  function parsePrice(value) {
1304
1364
  if (value === void 0 || value === null) {
@@ -1537,6 +1597,10 @@ async function openCardPopup(provider, checkoutResult, email, currency, signal)
1537
1597
  }
1538
1598
  return { success: false, error: "PROVIDER_UNAVAILABLE" };
1539
1599
  }
1600
+ var VALID_MOBILE_MONEY_PROVIDERS = new Set(Object.values(MOBILE_MONEY_PROVIDER));
1601
+ function isValidMobileMoneyProvider(value) {
1602
+ return VALID_MOBILE_MONEY_PROVIDERS.has(value);
1603
+ }
1540
1604
  function normalizeAuthorizationType(value) {
1541
1605
  return value === "otp" || value === "pin" ? value : void 0;
1542
1606
  }
@@ -1769,6 +1833,16 @@ var CheckoutResolver = class {
1769
1833
  }
1770
1834
  await this.wait(this.pollIntervalMs);
1771
1835
  }
1836
+ try {
1837
+ const finalResult = await this.client.checkout.pollPaymentStatus(input.orderId);
1838
+ if (finalResult.ok) {
1839
+ const normalized = normalizeStatusResponse(finalResult.value);
1840
+ if (normalized.paid || isPaymentStatusSuccess(normalized.status)) {
1841
+ return this.finalizeSuccess(latestCheckoutResult);
1842
+ }
1843
+ }
1844
+ } catch {
1845
+ }
1772
1846
  return this.fail(
1773
1847
  "PAYMENT_TIMEOUT",
1774
1848
  "Payment confirmation timed out. Please retry checkout.",
@@ -1899,7 +1973,7 @@ var CheckoutResolver = class {
1899
1973
  };
1900
1974
  }
1901
1975
  getEnrollmentMobileMoney() {
1902
- if (this.paymentData?.type === "mobile_money" && this.paymentData.phone_number && this.paymentData.provider) {
1976
+ if (this.paymentData?.type === "mobile_money" && this.paymentData.phone_number && this.paymentData.provider && isValidMobileMoneyProvider(this.paymentData.provider)) {
1903
1977
  return {
1904
1978
  phone_number: this.paymentData.phone_number,
1905
1979
  provider: this.paymentData.provider,
@@ -2973,8 +3047,10 @@ var CimplifyElements = class {
2973
3047
  false
2974
3048
  );
2975
3049
  }
3050
+ this.checkoutInProgress = true;
2976
3051
  if (!options.cart_id) {
2977
3052
  console.debug("[cimplify:checkout] BLOCKED: no cart_id");
3053
+ this.checkoutInProgress = false;
2978
3054
  return toCheckoutError(
2979
3055
  "INVALID_CART",
2980
3056
  "A valid cart is required before checkout can start.",
@@ -2983,6 +3059,7 @@ var CimplifyElements = class {
2983
3059
  }
2984
3060
  if (!options.order_type) {
2985
3061
  console.debug("[cimplify:checkout] BLOCKED: no order_type");
3062
+ this.checkoutInProgress = false;
2986
3063
  return toCheckoutError(
2987
3064
  "ORDER_TYPE_REQUIRED",
2988
3065
  "Order type is required before checkout can start.",
@@ -2992,6 +3069,7 @@ var CimplifyElements = class {
2992
3069
  const checkoutElement = this.elements.get(ELEMENT_TYPES.CHECKOUT) || this.elements.get(ELEMENT_TYPES.PAYMENT);
2993
3070
  if (!checkoutElement) {
2994
3071
  console.debug("[cimplify:checkout] BLOCKED: no checkout element");
3072
+ this.checkoutInProgress = false;
2995
3073
  return toCheckoutError(
2996
3074
  "NO_PAYMENT_ELEMENT",
2997
3075
  "Checkout element must be mounted before checkout.",
@@ -3000,6 +3078,7 @@ var CimplifyElements = class {
3000
3078
  }
3001
3079
  if (!checkoutElement.isMounted()) {
3002
3080
  console.debug("[cimplify:checkout] BLOCKED: checkout element not mounted");
3081
+ this.checkoutInProgress = false;
3003
3082
  return toCheckoutError(
3004
3083
  "PAYMENT_NOT_MOUNTED",
3005
3084
  "Checkout element must be mounted before checkout.",
@@ -3011,6 +3090,7 @@ var CimplifyElements = class {
3011
3090
  const authElement = this.elements.get(ELEMENT_TYPES.AUTH);
3012
3091
  if (authElement && !this.accessToken) {
3013
3092
  console.debug("[cimplify:checkout] BLOCKED: auth incomplete");
3093
+ this.checkoutInProgress = false;
3014
3094
  return toCheckoutError(
3015
3095
  "AUTH_INCOMPLETE",
3016
3096
  "Authentication must complete before checkout can start.",
@@ -3048,7 +3128,6 @@ var CimplifyElements = class {
3048
3128
  };
3049
3129
  const timeoutMs = options.timeout_ms ?? 18e4;
3050
3130
  const paymentWindow = checkoutElement.getContentWindow();
3051
- this.checkoutInProgress = true;
3052
3131
  return new Promise((resolve) => {
3053
3132
  let settled = false;
3054
3133
  const cleanup = () => {
@@ -3343,6 +3422,9 @@ var CimplifyElement = class {
3343
3422
  this.sendMessage({ type: MESSAGE_TYPES.GET_DATA });
3344
3423
  });
3345
3424
  }
3425
+ setCart(cart) {
3426
+ this.sendMessage({ type: MESSAGE_TYPES.SET_CART, cart });
3427
+ }
3346
3428
  sendMessage(message) {
3347
3429
  if (this.iframe?.contentWindow) {
3348
3430
  this.iframe.contentWindow.postMessage(message, this.linkUrl);
@@ -3398,7 +3480,8 @@ var CimplifyElement = class {
3398
3480
  prefillEmail: this.options.prefillEmail,
3399
3481
  appearance: this.parent.getAppearance(),
3400
3482
  orderTypes: this.options.orderTypes,
3401
- defaultOrderType: this.options.defaultOrderType
3483
+ defaultOrderType: this.options.defaultOrderType,
3484
+ renderSubmitButton: true
3402
3485
  });
3403
3486
  const token = this.parent.getAccessToken();
3404
3487
  if (token && this.type !== ELEMENT_TYPES.AUTH) {
@@ -3465,6 +3548,9 @@ var CimplifyElement = class {
3465
3548
  case MESSAGE_TYPES.ORDER_TYPE_CHANGED:
3466
3549
  this.emit(EVENT_TYPES.ORDER_TYPE_CHANGED, { orderType: message.orderType });
3467
3550
  break;
3551
+ case MESSAGE_TYPES.REQUEST_SUBMIT:
3552
+ this.emit(EVENT_TYPES.REQUEST_SUBMIT, {});
3553
+ break;
3468
3554
  }
3469
3555
  }
3470
3556
  emit(event, data) {
@@ -3487,6 +3573,7 @@ var ACCESS_TOKEN_STORAGE_KEY = "cimplify_access_token";
3487
3573
  var SESSION_TOKEN_STORAGE_KEY = "cimplify_session_token";
3488
3574
  var ORDER_TOKEN_PREFIX = "cimplify_ot_";
3489
3575
  var SESSION_TOKEN_HEADER = "x-session-token";
3576
+ var ORDER_TOKEN_TTL_MS = 24 * 60 * 60 * 1e3;
3490
3577
  var DEFAULT_TIMEOUT_MS = 3e4;
3491
3578
  var DEFAULT_MAX_RETRIES = 3;
3492
3579
  var DEFAULT_RETRY_DELAY_MS = 1e3;
@@ -3636,12 +3723,27 @@ var CimplifyClient = class {
3636
3723
  }
3637
3724
  setOrderToken(orderId, token) {
3638
3725
  if (typeof window !== "undefined" && window.localStorage) {
3639
- localStorage.setItem(`${ORDER_TOKEN_PREFIX}${orderId}`, token);
3726
+ try {
3727
+ const entry = JSON.stringify({ token, storedAt: Date.now() });
3728
+ localStorage.setItem(`${ORDER_TOKEN_PREFIX}${orderId}`, entry);
3729
+ } catch {
3730
+ }
3640
3731
  }
3641
3732
  }
3642
3733
  getOrderToken(orderId) {
3643
3734
  if (typeof window !== "undefined" && window.localStorage) {
3644
- return localStorage.getItem(`${ORDER_TOKEN_PREFIX}${orderId}`);
3735
+ try {
3736
+ const raw = localStorage.getItem(`${ORDER_TOKEN_PREFIX}${orderId}`);
3737
+ if (!raw) return null;
3738
+ const entry = JSON.parse(raw);
3739
+ if (Date.now() - entry.storedAt > ORDER_TOKEN_TTL_MS) {
3740
+ localStorage.removeItem(`${ORDER_TOKEN_PREFIX}${orderId}`);
3741
+ return null;
3742
+ }
3743
+ return entry.token;
3744
+ } catch {
3745
+ return null;
3746
+ }
3645
3747
  }
3646
3748
  return null;
3647
3749
  }
@@ -3717,10 +3819,13 @@ var CimplifyClient = class {
3717
3819
  }
3718
3820
  saveAccessToken(token) {
3719
3821
  if (typeof window !== "undefined" && window.localStorage) {
3720
- if (token) {
3721
- localStorage.setItem(ACCESS_TOKEN_STORAGE_KEY, token);
3722
- } else {
3723
- localStorage.removeItem(ACCESS_TOKEN_STORAGE_KEY);
3822
+ try {
3823
+ if (token) {
3824
+ localStorage.setItem(ACCESS_TOKEN_STORAGE_KEY, token);
3825
+ } else {
3826
+ localStorage.removeItem(ACCESS_TOKEN_STORAGE_KEY);
3827
+ }
3828
+ } catch {
3724
3829
  }
3725
3830
  }
3726
3831
  }
@@ -3793,6 +3898,19 @@ var CimplifyClient = class {
3793
3898
  });
3794
3899
  return response;
3795
3900
  }
3901
+ if (response.status === 429 && attempt < this.maxRetries) {
3902
+ retryCount++;
3903
+ const retryAfter = response.headers.get("Retry-After");
3904
+ const delay = retryAfter ? Math.min(parseInt(retryAfter, 10) * 1e3, 3e4) || this.retryDelay * Math.pow(2, attempt) : this.retryDelay * Math.pow(2, attempt);
3905
+ this.hooks.onRetry?.({
3906
+ ...context,
3907
+ attempt: retryCount,
3908
+ delayMs: delay,
3909
+ error: new Error(`Rate limited: ${response.status}`)
3910
+ });
3911
+ await sleep(delay);
3912
+ continue;
3913
+ }
3796
3914
  if (response.status >= 400 && response.status < 500) {
3797
3915
  this.hooks.onRequestError?.({
3798
3916
  ...context,
@@ -4116,23 +4234,23 @@ function resolveInitialLocation(locations) {
4116
4234
  }
4117
4235
  return locations[0];
4118
4236
  }
4119
- var CimplifyContext = react.createContext(null);
4237
+ var CimplifyContext = React2.createContext(null);
4120
4238
  function CimplifyProvider({
4121
4239
  client,
4122
4240
  children,
4123
4241
  onLocationChange
4124
4242
  }) {
4125
- const resolvedClient = react.useMemo(() => client ?? createDefaultClient(), [client]);
4126
- const onLocationChangeRef = react.useRef(onLocationChange);
4127
- const [business, setBusiness] = react.useState(null);
4128
- const [locations, setLocations] = react.useState([]);
4129
- const [currentLocation, setCurrentLocationState] = react.useState(null);
4130
- const [isReady, setIsReady] = react.useState(false);
4131
- react.useEffect(() => {
4243
+ const resolvedClient = React2.useMemo(() => client ?? createDefaultClient(), [client]);
4244
+ const onLocationChangeRef = React2.useRef(onLocationChange);
4245
+ const [business, setBusiness] = React2.useState(null);
4246
+ const [locations, setLocations] = React2.useState([]);
4247
+ const [currentLocation, setCurrentLocationState] = React2.useState(null);
4248
+ const [isReady, setIsReady] = React2.useState(false);
4249
+ React2.useEffect(() => {
4132
4250
  onLocationChangeRef.current = onLocationChange;
4133
4251
  }, [onLocationChange]);
4134
4252
  const isDemoMode = resolvedClient.getPublicKey().trim().length === 0;
4135
- const setCurrentLocation = react.useCallback(
4253
+ const setCurrentLocation = React2.useCallback(
4136
4254
  (location) => {
4137
4255
  setCurrentLocationState(location);
4138
4256
  resolvedClient.setLocationId(location.id);
@@ -4141,7 +4259,7 @@ function CimplifyProvider({
4141
4259
  },
4142
4260
  [resolvedClient]
4143
4261
  );
4144
- react.useEffect(() => {
4262
+ React2.useEffect(() => {
4145
4263
  let cancelled = false;
4146
4264
  async function bootstrap() {
4147
4265
  setIsReady(false);
@@ -4197,7 +4315,7 @@ function CimplifyProvider({
4197
4315
  cancelled = true;
4198
4316
  };
4199
4317
  }, [resolvedClient, isDemoMode]);
4200
- const contextValue = react.useMemo(
4318
+ const contextValue = React2.useMemo(
4201
4319
  () => ({
4202
4320
  client: resolvedClient,
4203
4321
  business,
@@ -4222,14 +4340,14 @@ function CimplifyProvider({
4222
4340
  return /* @__PURE__ */ jsxRuntime.jsx(CimplifyContext.Provider, { value: contextValue, children });
4223
4341
  }
4224
4342
  function useCimplify() {
4225
- const context = react.useContext(CimplifyContext);
4343
+ const context = React2.useContext(CimplifyContext);
4226
4344
  if (!context) {
4227
4345
  throw new Error("useCimplify must be used within CimplifyProvider");
4228
4346
  }
4229
4347
  return context;
4230
4348
  }
4231
4349
  function useOptionalCimplify() {
4232
- return react.useContext(CimplifyContext);
4350
+ return React2.useContext(CimplifyContext);
4233
4351
  }
4234
4352
  var productsCache = /* @__PURE__ */ new Map();
4235
4353
  var productsInflight = /* @__PURE__ */ new Map();
@@ -4248,9 +4366,9 @@ function useProducts(options = {}) {
4248
4366
  }
4249
4367
  const enabled = options.enabled ?? true;
4250
4368
  const locationId = client.getLocationId();
4251
- const previousLocationIdRef = react.useRef(locationId);
4252
- const requestIdRef = react.useRef(0);
4253
- const queryOptions = react.useMemo(
4369
+ const previousLocationIdRef = React2.useRef(locationId);
4370
+ const requestIdRef = React2.useRef(0);
4371
+ const queryOptions = React2.useMemo(
4254
4372
  () => ({
4255
4373
  category: options.category,
4256
4374
  collection: options.collection,
@@ -4260,25 +4378,25 @@ function useProducts(options = {}) {
4260
4378
  }),
4261
4379
  [options.category, options.collection, options.featured, options.limit, options.search]
4262
4380
  );
4263
- const cacheKey = react.useMemo(
4381
+ const cacheKey = React2.useMemo(
4264
4382
  () => buildProductsCacheKey(client, locationId, queryOptions),
4265
4383
  [client, locationId, queryOptions]
4266
4384
  );
4267
4385
  const cached = productsCache.get(cacheKey);
4268
- const [products, setProducts] = react.useState(cached?.products ?? []);
4269
- const [isComplete, setIsComplete] = react.useState(cached?.is_complete ?? true);
4270
- const [totalAvailable, setTotalAvailable] = react.useState(cached?.total_available);
4271
- const [pagination, setPagination] = react.useState(cached?.pagination);
4272
- const [isLoading, setIsLoading] = react.useState(enabled && !cached);
4273
- const [error, setError] = react.useState(null);
4274
- react.useEffect(() => {
4386
+ const [products, setProducts] = React2.useState(cached?.products ?? []);
4387
+ const [isComplete, setIsComplete] = React2.useState(cached?.is_complete ?? true);
4388
+ const [totalAvailable, setTotalAvailable] = React2.useState(cached?.total_available);
4389
+ const [pagination, setPagination] = React2.useState(cached?.pagination);
4390
+ const [isLoading, setIsLoading] = React2.useState(enabled && !cached);
4391
+ const [error, setError] = React2.useState(null);
4392
+ React2.useEffect(() => {
4275
4393
  if (previousLocationIdRef.current !== locationId) {
4276
4394
  productsCache.clear();
4277
4395
  productsInflight.clear();
4278
4396
  previousLocationIdRef.current = locationId;
4279
4397
  }
4280
4398
  }, [locationId]);
4281
- const load = react.useCallback(
4399
+ const load = React2.useCallback(
4282
4400
  async (force = false) => {
4283
4401
  if (!enabled) {
4284
4402
  setIsLoading(false);
@@ -4341,10 +4459,10 @@ function useProducts(options = {}) {
4341
4459
  },
4342
4460
  [cacheKey, client, enabled, queryOptions]
4343
4461
  );
4344
- react.useEffect(() => {
4462
+ React2.useEffect(() => {
4345
4463
  void load(false);
4346
4464
  }, [load]);
4347
- const refetch = react.useCallback(async () => {
4465
+ const refetch = React2.useCallback(async () => {
4348
4466
  productsCache.delete(cacheKey);
4349
4467
  await load(true);
4350
4468
  }, [cacheKey, load]);
@@ -4378,27 +4496,27 @@ function useProduct(slugOrId, options = {}) {
4378
4496
  }
4379
4497
  const enabled = options.enabled ?? true;
4380
4498
  const locationId = client.getLocationId();
4381
- const previousLocationIdRef = react.useRef(locationId);
4382
- const requestIdRef = react.useRef(0);
4383
- const normalizedSlugOrId = react.useMemo(() => (slugOrId || "").trim(), [slugOrId]);
4384
- const cacheKey = react.useMemo(
4499
+ const previousLocationIdRef = React2.useRef(locationId);
4500
+ const requestIdRef = React2.useRef(0);
4501
+ const normalizedSlugOrId = React2.useMemo(() => (slugOrId || "").trim(), [slugOrId]);
4502
+ const cacheKey = React2.useMemo(
4385
4503
  () => buildProductCacheKey(client, locationId, normalizedSlugOrId),
4386
4504
  [client, locationId, normalizedSlugOrId]
4387
4505
  );
4388
4506
  const cached = productCache.get(cacheKey);
4389
- const [product, setProduct] = react.useState(cached?.product ?? null);
4390
- const [isLoading, setIsLoading] = react.useState(
4507
+ const [product, setProduct] = React2.useState(cached?.product ?? null);
4508
+ const [isLoading, setIsLoading] = React2.useState(
4391
4509
  enabled && normalizedSlugOrId.length > 0 && !cached
4392
4510
  );
4393
- const [error, setError] = react.useState(null);
4394
- react.useEffect(() => {
4511
+ const [error, setError] = React2.useState(null);
4512
+ React2.useEffect(() => {
4395
4513
  if (previousLocationIdRef.current !== locationId) {
4396
4514
  productCache.clear();
4397
4515
  productInflight.clear();
4398
4516
  previousLocationIdRef.current = locationId;
4399
4517
  }
4400
4518
  }, [locationId]);
4401
- const load = react.useCallback(
4519
+ const load = React2.useCallback(
4402
4520
  async (force = false) => {
4403
4521
  if (!enabled || normalizedSlugOrId.length === 0) {
4404
4522
  setProduct(null);
@@ -4451,10 +4569,10 @@ function useProduct(slugOrId, options = {}) {
4451
4569
  },
4452
4570
  [cacheKey, client, enabled, normalizedSlugOrId]
4453
4571
  );
4454
- react.useEffect(() => {
4572
+ React2.useEffect(() => {
4455
4573
  void load(false);
4456
4574
  }, [load]);
4457
- const refetch = react.useCallback(async () => {
4575
+ const refetch = React2.useCallback(async () => {
4458
4576
  productCache.delete(cacheKey);
4459
4577
  await load(true);
4460
4578
  }, [cacheKey, load]);
@@ -4472,12 +4590,12 @@ function useCategories(options = {}) {
4472
4590
  throw new Error("useCategories must be used within CimplifyProvider or passed { client }.");
4473
4591
  }
4474
4592
  const enabled = options.enabled ?? true;
4475
- const cacheKey = react.useMemo(() => buildCategoriesCacheKey(client), [client]);
4593
+ const cacheKey = React2.useMemo(() => buildCategoriesCacheKey(client), [client]);
4476
4594
  const cached = categoriesCache.get(cacheKey);
4477
- const [categories, setCategories] = react.useState(cached ?? []);
4478
- const [isLoading, setIsLoading] = react.useState(enabled && !cached);
4479
- const [error, setError] = react.useState(null);
4480
- const load = react.useCallback(
4595
+ const [categories, setCategories] = React2.useState(cached ?? []);
4596
+ const [isLoading, setIsLoading] = React2.useState(enabled && !cached);
4597
+ const [error, setError] = React2.useState(null);
4598
+ const load = React2.useCallback(
4481
4599
  async (force = false) => {
4482
4600
  if (!enabled) {
4483
4601
  setIsLoading(false);
@@ -4521,10 +4639,10 @@ function useCategories(options = {}) {
4521
4639
  },
4522
4640
  [cacheKey, client, enabled]
4523
4641
  );
4524
- react.useEffect(() => {
4642
+ React2.useEffect(() => {
4525
4643
  void load(false);
4526
4644
  }, [load]);
4527
- const refetch = react.useCallback(async () => {
4645
+ const refetch = React2.useCallback(async () => {
4528
4646
  categoriesCache.delete(cacheKey);
4529
4647
  await load(true);
4530
4648
  }, [cacheKey, load]);
@@ -5045,7 +5163,7 @@ function useCart(options = {}) {
5045
5163
  const locationId = options.locationId ?? client.getLocationId();
5046
5164
  const isDemoMode = options.demoMode ?? context?.isDemoMode ?? client.getPublicKey().trim().length === 0;
5047
5165
  const currency = options.currency ?? context?.currency ?? "USD";
5048
- const store = react.useMemo(
5166
+ const store = React2.useMemo(
5049
5167
  () => getOrCreateStore({
5050
5168
  client,
5051
5169
  locationId,
@@ -5054,43 +5172,43 @@ function useCart(options = {}) {
5054
5172
  }),
5055
5173
  [client, currency, isDemoMode, locationId]
5056
5174
  );
5057
- const snapshot = react.useSyncExternalStore(
5175
+ const snapshot = React2.useSyncExternalStore(
5058
5176
  store.subscribe,
5059
5177
  store.getSnapshot,
5060
5178
  store.getSnapshot
5061
5179
  );
5062
- react.useEffect(() => {
5180
+ React2.useEffect(() => {
5063
5181
  void store.initialize();
5064
5182
  }, [store]);
5065
- const addItem = react.useCallback(
5183
+ const addItem = React2.useCallback(
5066
5184
  async (product, quantity, addOptions) => {
5067
5185
  await store.addItem(product, quantity, addOptions);
5068
5186
  },
5069
5187
  [store]
5070
5188
  );
5071
- const removeItem = react.useCallback(
5189
+ const removeItem = React2.useCallback(
5072
5190
  async (itemId) => {
5073
5191
  await store.removeItem(itemId);
5074
5192
  },
5075
5193
  [store]
5076
5194
  );
5077
- const updateQuantity = react.useCallback(
5195
+ const updateQuantity = React2.useCallback(
5078
5196
  async (itemId, quantity) => {
5079
5197
  await store.updateQuantity(itemId, quantity);
5080
5198
  },
5081
5199
  [store]
5082
5200
  );
5083
- const clearCart = react.useCallback(async () => {
5201
+ const clearCart = React2.useCallback(async () => {
5084
5202
  await store.clearCart();
5085
5203
  }, [store]);
5086
- const sync = react.useCallback(async () => {
5204
+ const sync = React2.useCallback(async () => {
5087
5205
  try {
5088
5206
  await store.sync();
5089
5207
  } catch (syncError) {
5090
5208
  throw syncError;
5091
5209
  }
5092
5210
  }, [store]);
5093
- const itemCount = react.useMemo(
5211
+ const itemCount = React2.useMemo(
5094
5212
  () => snapshot.items.reduce((sum, item) => sum + item.quantity, 0),
5095
5213
  [snapshot.items]
5096
5214
  );
@@ -5121,22 +5239,22 @@ function useOrder(orderId, options = {}) {
5121
5239
  if (!client) {
5122
5240
  throw new Error("useOrder must be used within CimplifyProvider or passed { client }.");
5123
5241
  }
5124
- const normalizedOrderId = react.useMemo(() => (orderId || "").trim(), [orderId]);
5242
+ const normalizedOrderId = React2.useMemo(() => (orderId || "").trim(), [orderId]);
5125
5243
  const enabled = options.enabled ?? true;
5126
5244
  const poll = options.poll ?? false;
5127
5245
  const pollInterval = options.pollInterval ?? 5e3;
5128
- const requestIdRef = react.useRef(0);
5129
- const cacheKey = react.useMemo(
5246
+ const requestIdRef = React2.useRef(0);
5247
+ const cacheKey = React2.useMemo(
5130
5248
  () => buildOrderCacheKey(client, normalizedOrderId),
5131
5249
  [client, normalizedOrderId]
5132
5250
  );
5133
5251
  const cached = orderCache.get(cacheKey);
5134
- const [order, setOrder] = react.useState(cached?.order ?? null);
5135
- const [isLoading, setIsLoading] = react.useState(
5252
+ const [order, setOrder] = React2.useState(cached?.order ?? null);
5253
+ const [isLoading, setIsLoading] = React2.useState(
5136
5254
  enabled && normalizedOrderId.length > 0 && !cached
5137
5255
  );
5138
- const [error, setError] = react.useState(null);
5139
- const load = react.useCallback(
5256
+ const [error, setError] = React2.useState(null);
5257
+ const load = React2.useCallback(
5140
5258
  async (force = false) => {
5141
5259
  if (!enabled || normalizedOrderId.length === 0) {
5142
5260
  setOrder(null);
@@ -5189,10 +5307,10 @@ function useOrder(orderId, options = {}) {
5189
5307
  },
5190
5308
  [cacheKey, client, enabled, normalizedOrderId]
5191
5309
  );
5192
- react.useEffect(() => {
5310
+ React2.useEffect(() => {
5193
5311
  void load(false);
5194
5312
  }, [load]);
5195
- react.useEffect(() => {
5313
+ React2.useEffect(() => {
5196
5314
  if (!poll || !enabled || normalizedOrderId.length === 0) {
5197
5315
  return;
5198
5316
  }
@@ -5203,7 +5321,7 @@ function useOrder(orderId, options = {}) {
5203
5321
  window.clearInterval(timer);
5204
5322
  };
5205
5323
  }, [enabled, load, normalizedOrderId.length, poll, pollInterval]);
5206
- const refetch = react.useCallback(async () => {
5324
+ const refetch = React2.useCallback(async () => {
5207
5325
  orderCache.delete(cacheKey);
5208
5326
  await load(true);
5209
5327
  }, [cacheKey, load]);
@@ -5254,10 +5372,10 @@ function useLocations(options = {}) {
5254
5372
  };
5255
5373
  }
5256
5374
  const client = options.client;
5257
- const [locations, setLocations] = react.useState([]);
5258
- const [currentLocation, setCurrentLocationState] = react.useState(null);
5259
- const [isLoading, setIsLoading] = react.useState(true);
5260
- const setCurrentLocation = react.useCallback(
5375
+ const [locations, setLocations] = React2.useState([]);
5376
+ const [currentLocation, setCurrentLocationState] = React2.useState(null);
5377
+ const [isLoading, setIsLoading] = React2.useState(true);
5378
+ const setCurrentLocation = React2.useCallback(
5261
5379
  (location) => {
5262
5380
  setCurrentLocationState(location);
5263
5381
  if (client) {
@@ -5267,7 +5385,7 @@ function useLocations(options = {}) {
5267
5385
  },
5268
5386
  [client]
5269
5387
  );
5270
- react.useEffect(() => {
5388
+ React2.useEffect(() => {
5271
5389
  if (!client) {
5272
5390
  setLocations([]);
5273
5391
  setCurrentLocationState(null);
@@ -5325,24 +5443,24 @@ function useCollections(options = {}) {
5325
5443
  }
5326
5444
  const enabled = options.enabled ?? true;
5327
5445
  const locationId = client.getLocationId();
5328
- const previousLocationIdRef = react.useRef(locationId);
5329
- const requestIdRef = react.useRef(0);
5330
- const cacheKey = react.useMemo(
5446
+ const previousLocationIdRef = React2.useRef(locationId);
5447
+ const requestIdRef = React2.useRef(0);
5448
+ const cacheKey = React2.useMemo(
5331
5449
  () => buildCollectionsCacheKey(client, locationId),
5332
5450
  [client, locationId]
5333
5451
  );
5334
5452
  const cached = collectionsCache.get(cacheKey);
5335
- const [collections, setCollections] = react.useState(cached?.collections ?? []);
5336
- const [isLoading, setIsLoading] = react.useState(enabled && !cached);
5337
- const [error, setError] = react.useState(null);
5338
- react.useEffect(() => {
5453
+ const [collections, setCollections] = React2.useState(cached?.collections ?? []);
5454
+ const [isLoading, setIsLoading] = React2.useState(enabled && !cached);
5455
+ const [error, setError] = React2.useState(null);
5456
+ React2.useEffect(() => {
5339
5457
  if (previousLocationIdRef.current !== locationId) {
5340
5458
  collectionsCache.clear();
5341
5459
  collectionsInflight.clear();
5342
5460
  previousLocationIdRef.current = locationId;
5343
5461
  }
5344
5462
  }, [locationId]);
5345
- const load = react.useCallback(
5463
+ const load = React2.useCallback(
5346
5464
  async (force = false) => {
5347
5465
  if (!enabled) {
5348
5466
  setIsLoading(false);
@@ -5392,10 +5510,10 @@ function useCollections(options = {}) {
5392
5510
  },
5393
5511
  [cacheKey, client, enabled]
5394
5512
  );
5395
- react.useEffect(() => {
5513
+ React2.useEffect(() => {
5396
5514
  void load(false);
5397
5515
  }, [load]);
5398
- const refetch = react.useCallback(async () => {
5516
+ const refetch = React2.useCallback(async () => {
5399
5517
  collectionsCache.delete(cacheKey);
5400
5518
  await load(true);
5401
5519
  }, [cacheKey, load]);
@@ -5421,28 +5539,28 @@ function useCollection(idOrSlug, options = {}) {
5421
5539
  }
5422
5540
  const enabled = options.enabled ?? true;
5423
5541
  const locationId = client.getLocationId();
5424
- const previousLocationIdRef = react.useRef(locationId);
5425
- const requestIdRef = react.useRef(0);
5426
- const normalizedIdOrSlug = react.useMemo(() => (idOrSlug || "").trim(), [idOrSlug]);
5427
- const cacheKey = react.useMemo(
5542
+ const previousLocationIdRef = React2.useRef(locationId);
5543
+ const requestIdRef = React2.useRef(0);
5544
+ const normalizedIdOrSlug = React2.useMemo(() => (idOrSlug || "").trim(), [idOrSlug]);
5545
+ const cacheKey = React2.useMemo(
5428
5546
  () => buildCollectionCacheKey(client, locationId, normalizedIdOrSlug),
5429
5547
  [client, locationId, normalizedIdOrSlug]
5430
5548
  );
5431
5549
  const cached = collectionCache.get(cacheKey);
5432
- const [collection, setCollection] = react.useState(cached?.collection ?? null);
5433
- const [products, setProducts] = react.useState(cached?.products ?? []);
5434
- const [isLoading, setIsLoading] = react.useState(
5550
+ const [collection, setCollection] = React2.useState(cached?.collection ?? null);
5551
+ const [products, setProducts] = React2.useState(cached?.products ?? []);
5552
+ const [isLoading, setIsLoading] = React2.useState(
5435
5553
  enabled && normalizedIdOrSlug.length > 0 && !cached
5436
5554
  );
5437
- const [error, setError] = react.useState(null);
5438
- react.useEffect(() => {
5555
+ const [error, setError] = React2.useState(null);
5556
+ React2.useEffect(() => {
5439
5557
  if (previousLocationIdRef.current !== locationId) {
5440
5558
  collectionCache.clear();
5441
5559
  collectionInflight.clear();
5442
5560
  previousLocationIdRef.current = locationId;
5443
5561
  }
5444
5562
  }, [locationId]);
5445
- const load = react.useCallback(
5563
+ const load = React2.useCallback(
5446
5564
  async (force = false) => {
5447
5565
  if (!enabled || normalizedIdOrSlug.length === 0) {
5448
5566
  setCollection(null);
@@ -5505,10 +5623,10 @@ function useCollection(idOrSlug, options = {}) {
5505
5623
  },
5506
5624
  [cacheKey, client, enabled, normalizedIdOrSlug]
5507
5625
  );
5508
- react.useEffect(() => {
5626
+ React2.useEffect(() => {
5509
5627
  void load(false);
5510
5628
  }, [load]);
5511
- const refetch = react.useCallback(async () => {
5629
+ const refetch = React2.useCallback(async () => {
5512
5630
  collectionCache.delete(cacheKey);
5513
5631
  await load(true);
5514
5632
  }, [cacheKey, load]);
@@ -5534,27 +5652,27 @@ function useBundle(idOrSlug, options = {}) {
5534
5652
  }
5535
5653
  const enabled = options.enabled ?? true;
5536
5654
  const locationId = client.getLocationId();
5537
- const previousLocationIdRef = react.useRef(locationId);
5538
- const requestIdRef = react.useRef(0);
5539
- const normalizedIdOrSlug = react.useMemo(() => (idOrSlug || "").trim(), [idOrSlug]);
5540
- const cacheKey = react.useMemo(
5655
+ const previousLocationIdRef = React2.useRef(locationId);
5656
+ const requestIdRef = React2.useRef(0);
5657
+ const normalizedIdOrSlug = React2.useMemo(() => (idOrSlug || "").trim(), [idOrSlug]);
5658
+ const cacheKey = React2.useMemo(
5541
5659
  () => buildBundleCacheKey(client, locationId, normalizedIdOrSlug),
5542
5660
  [client, locationId, normalizedIdOrSlug]
5543
5661
  );
5544
5662
  const cached = bundleCache.get(cacheKey);
5545
- const [bundle, setBundle] = react.useState(cached?.bundle ?? null);
5546
- const [isLoading, setIsLoading] = react.useState(
5663
+ const [bundle, setBundle] = React2.useState(cached?.bundle ?? null);
5664
+ const [isLoading, setIsLoading] = React2.useState(
5547
5665
  enabled && normalizedIdOrSlug.length > 0 && !cached
5548
5666
  );
5549
- const [error, setError] = react.useState(null);
5550
- react.useEffect(() => {
5667
+ const [error, setError] = React2.useState(null);
5668
+ React2.useEffect(() => {
5551
5669
  if (previousLocationIdRef.current !== locationId) {
5552
5670
  bundleCache.clear();
5553
5671
  bundleInflight.clear();
5554
5672
  previousLocationIdRef.current = locationId;
5555
5673
  }
5556
5674
  }, [locationId]);
5557
- const load = react.useCallback(
5675
+ const load = React2.useCallback(
5558
5676
  async (force = false) => {
5559
5677
  if (!enabled || normalizedIdOrSlug.length === 0) {
5560
5678
  setBundle(null);
@@ -5605,10 +5723,10 @@ function useBundle(idOrSlug, options = {}) {
5605
5723
  },
5606
5724
  [cacheKey, client, enabled, normalizedIdOrSlug]
5607
5725
  );
5608
- react.useEffect(() => {
5726
+ React2.useEffect(() => {
5609
5727
  void load(false);
5610
5728
  }, [load]);
5611
- const refetch = react.useCallback(async () => {
5729
+ const refetch = React2.useCallback(async () => {
5612
5730
  bundleCache.delete(cacheKey);
5613
5731
  await load(true);
5614
5732
  }, [cacheKey, load]);
@@ -5638,37 +5756,37 @@ function useComposite(idOrProductId, options = {}) {
5638
5756
  }
5639
5757
  const enabled = options.enabled ?? true;
5640
5758
  const locationId = client.getLocationId();
5641
- const previousLocationIdRef = react.useRef(locationId);
5642
- const requestIdRef = react.useRef(0);
5643
- const priceRequestIdRef = react.useRef(0);
5644
- const normalizedIdOrProductId = react.useMemo(
5759
+ const previousLocationIdRef = React2.useRef(locationId);
5760
+ const requestIdRef = React2.useRef(0);
5761
+ const priceRequestIdRef = React2.useRef(0);
5762
+ const normalizedIdOrProductId = React2.useMemo(
5645
5763
  () => (idOrProductId || "").trim(),
5646
5764
  [idOrProductId]
5647
5765
  );
5648
- const byProductId = react.useMemo(
5766
+ const byProductId = React2.useMemo(
5649
5767
  () => shouldFetchByProductId(normalizedIdOrProductId, options.byProductId),
5650
5768
  [normalizedIdOrProductId, options.byProductId]
5651
5769
  );
5652
- const cacheKey = react.useMemo(
5770
+ const cacheKey = React2.useMemo(
5653
5771
  () => buildCompositeCacheKey(client, locationId, normalizedIdOrProductId, byProductId),
5654
5772
  [byProductId, client, locationId, normalizedIdOrProductId]
5655
5773
  );
5656
5774
  const cached = compositeCache.get(cacheKey);
5657
- const [composite, setComposite] = react.useState(cached?.composite ?? null);
5658
- const [isLoading, setIsLoading] = react.useState(
5775
+ const [composite, setComposite] = React2.useState(cached?.composite ?? null);
5776
+ const [isLoading, setIsLoading] = React2.useState(
5659
5777
  enabled && normalizedIdOrProductId.length > 0 && !cached
5660
5778
  );
5661
- const [error, setError] = react.useState(null);
5662
- const [priceResult, setPriceResult] = react.useState(null);
5663
- const [isPriceLoading, setIsPriceLoading] = react.useState(false);
5664
- react.useEffect(() => {
5779
+ const [error, setError] = React2.useState(null);
5780
+ const [priceResult, setPriceResult] = React2.useState(null);
5781
+ const [isPriceLoading, setIsPriceLoading] = React2.useState(false);
5782
+ React2.useEffect(() => {
5665
5783
  if (previousLocationIdRef.current !== locationId) {
5666
5784
  compositeCache.clear();
5667
5785
  compositeInflight.clear();
5668
5786
  previousLocationIdRef.current = locationId;
5669
5787
  }
5670
5788
  }, [locationId]);
5671
- const load = react.useCallback(
5789
+ const load = React2.useCallback(
5672
5790
  async (force = false) => {
5673
5791
  if (!enabled || normalizedIdOrProductId.length === 0) {
5674
5792
  setComposite(null);
@@ -5721,10 +5839,10 @@ function useComposite(idOrProductId, options = {}) {
5721
5839
  },
5722
5840
  [byProductId, cacheKey, client, enabled, normalizedIdOrProductId]
5723
5841
  );
5724
- react.useEffect(() => {
5842
+ React2.useEffect(() => {
5725
5843
  void load(false);
5726
5844
  }, [load]);
5727
- const calculatePrice = react.useCallback(
5845
+ const calculatePrice = React2.useCallback(
5728
5846
  async (selections, overrideLocationId) => {
5729
5847
  if (!composite) {
5730
5848
  return null;
@@ -5758,7 +5876,7 @@ function useComposite(idOrProductId, options = {}) {
5758
5876
  },
5759
5877
  [client, composite]
5760
5878
  );
5761
- const refetch = react.useCallback(async () => {
5879
+ const refetch = React2.useCallback(async () => {
5762
5880
  compositeCache.delete(cacheKey);
5763
5881
  await load(true);
5764
5882
  }, [cacheKey, load]);
@@ -5773,13 +5891,13 @@ function useSearch(options = {}) {
5773
5891
  const minLength = Math.max(0, options.minLength ?? 2);
5774
5892
  const debounceMs = Math.max(0, options.debounceMs ?? 300);
5775
5893
  const limit = Math.max(1, options.limit ?? 20);
5776
- const [query, setQueryState] = react.useState("");
5777
- const [results, setResults] = react.useState([]);
5778
- const [isLoading, setIsLoading] = react.useState(false);
5779
- const [error, setError] = react.useState(null);
5780
- const requestIdRef = react.useRef(0);
5781
- const timerRef = react.useRef(null);
5782
- react.useEffect(() => {
5894
+ const [query, setQueryState] = React2.useState("");
5895
+ const [results, setResults] = React2.useState([]);
5896
+ const [isLoading, setIsLoading] = React2.useState(false);
5897
+ const [error, setError] = React2.useState(null);
5898
+ const requestIdRef = React2.useRef(0);
5899
+ const timerRef = React2.useRef(null);
5900
+ React2.useEffect(() => {
5783
5901
  if (timerRef.current) {
5784
5902
  clearTimeout(timerRef.current);
5785
5903
  timerRef.current = null;
@@ -5826,10 +5944,10 @@ function useSearch(options = {}) {
5826
5944
  }
5827
5945
  };
5828
5946
  }, [client, debounceMs, limit, minLength, options.category, query]);
5829
- const setQuery = react.useCallback((nextQuery) => {
5947
+ const setQuery = React2.useCallback((nextQuery) => {
5830
5948
  setQueryState(nextQuery);
5831
5949
  }, []);
5832
- const clear = react.useCallback(() => {
5950
+ const clear = React2.useCallback(() => {
5833
5951
  requestIdRef.current += 1;
5834
5952
  if (timerRef.current) {
5835
5953
  clearTimeout(timerRef.current);
@@ -5885,28 +6003,28 @@ function useQuote(input, options = {}) {
5885
6003
  const autoRefresh = options.autoRefresh ?? true;
5886
6004
  const refreshBeforeExpiryMs = Math.max(0, options.refreshBeforeExpiryMs ?? 3e4);
5887
6005
  const locationId = client.getLocationId();
5888
- const requestIdRef = react.useRef(0);
5889
- const refreshTimerRef = react.useRef(null);
5890
- const expiryTimerRef = react.useRef(null);
5891
- const inputSignature = react.useMemo(() => JSON.stringify(input ?? null), [input]);
5892
- const normalizedInput = react.useMemo(() => {
6006
+ const requestIdRef = React2.useRef(0);
6007
+ const refreshTimerRef = React2.useRef(null);
6008
+ const expiryTimerRef = React2.useRef(null);
6009
+ const inputSignature = React2.useMemo(() => JSON.stringify(input ?? null), [input]);
6010
+ const normalizedInput = React2.useMemo(() => {
5893
6011
  if (!input) {
5894
6012
  return null;
5895
6013
  }
5896
6014
  const normalized = normalizeInput(input, locationId);
5897
6015
  return normalized.product_id.length > 0 ? normalized : null;
5898
6016
  }, [inputSignature, locationId]);
5899
- const cacheKey = react.useMemo(
6017
+ const cacheKey = React2.useMemo(
5900
6018
  () => buildQuoteCacheKey(client, locationId, inputSignature),
5901
6019
  [client, inputSignature, locationId]
5902
6020
  );
5903
6021
  const cached = quoteCache.get(cacheKey);
5904
- const [quote, setQuote] = react.useState(cached?.quote ?? null);
5905
- const [isLoading, setIsLoading] = react.useState(enabled && normalizedInput !== null && !cached);
5906
- const [error, setError] = react.useState(null);
5907
- const [isExpired, setIsExpired] = react.useState(isQuoteExpired(cached?.quote ?? null));
5908
- const [messages, setMessages] = react.useState(cached?.quote?.ui_messages ?? []);
5909
- const load = react.useCallback(
6022
+ const [quote, setQuote] = React2.useState(cached?.quote ?? null);
6023
+ const [isLoading, setIsLoading] = React2.useState(enabled && normalizedInput !== null && !cached);
6024
+ const [error, setError] = React2.useState(null);
6025
+ const [isExpired, setIsExpired] = React2.useState(isQuoteExpired(cached?.quote ?? null));
6026
+ const [messages, setMessages] = React2.useState(cached?.quote?.ui_messages ?? []);
6027
+ const load = React2.useCallback(
5910
6028
  async (force = false) => {
5911
6029
  if (!enabled || !normalizedInput) {
5912
6030
  setQuote(null);
@@ -5964,10 +6082,10 @@ function useQuote(input, options = {}) {
5964
6082
  },
5965
6083
  [cacheKey, client, enabled, normalizedInput]
5966
6084
  );
5967
- react.useEffect(() => {
6085
+ React2.useEffect(() => {
5968
6086
  void load(false);
5969
6087
  }, [load]);
5970
- const refresh = react.useCallback(async () => {
6088
+ const refresh = React2.useCallback(async () => {
5971
6089
  if (!enabled || !normalizedInput) {
5972
6090
  return;
5973
6091
  }
@@ -6004,7 +6122,7 @@ function useQuote(input, options = {}) {
6004
6122
  }
6005
6123
  }
6006
6124
  }, [cacheKey, client, enabled, load, normalizedInput, quote]);
6007
- react.useEffect(() => {
6125
+ React2.useEffect(() => {
6008
6126
  if (expiryTimerRef.current) {
6009
6127
  clearTimeout(expiryTimerRef.current);
6010
6128
  expiryTimerRef.current = null;
@@ -6028,7 +6146,7 @@ function useQuote(input, options = {}) {
6028
6146
  }
6029
6147
  };
6030
6148
  }, [quote?.expires_at, quote?.quote_id]);
6031
- react.useEffect(() => {
6149
+ React2.useEffect(() => {
6032
6150
  if (refreshTimerRef.current) {
6033
6151
  clearTimeout(refreshTimerRef.current);
6034
6152
  refreshTimerRef.current = null;
@@ -6053,15 +6171,15 @@ function useQuote(input, options = {}) {
6053
6171
  }, [autoRefresh, enabled, quote?.expires_at, quote?.quote_id, refresh, refreshBeforeExpiryMs]);
6054
6172
  return { quote, isLoading, error, refresh, isExpired, messages };
6055
6173
  }
6056
- var ElementsContext = react.createContext({
6174
+ var ElementsContext = React2.createContext({
6057
6175
  elements: null,
6058
6176
  isReady: false
6059
6177
  });
6060
6178
  function useElements() {
6061
- return react.useContext(ElementsContext).elements;
6179
+ return React2.useContext(ElementsContext).elements;
6062
6180
  }
6063
6181
  function useElementsReady() {
6064
- return react.useContext(ElementsContext).isReady;
6182
+ return React2.useContext(ElementsContext).isReady;
6065
6183
  }
6066
6184
  function ElementsProvider({
6067
6185
  client,
@@ -6069,10 +6187,10 @@ function ElementsProvider({
6069
6187
  options,
6070
6188
  children
6071
6189
  }) {
6072
- const [elements, setElements] = react.useState(null);
6073
- const [isReady, setIsReady] = react.useState(false);
6074
- const initialOptionsRef = react.useRef(options);
6075
- react.useEffect(() => {
6190
+ const [elements, setElements] = React2.useState(null);
6191
+ const [isReady, setIsReady] = React2.useState(false);
6192
+ const initialOptionsRef = React2.useRef(options);
6193
+ React2.useEffect(() => {
6076
6194
  let cancelled = false;
6077
6195
  let instance = null;
6078
6196
  setIsReady(false);
@@ -6113,20 +6231,20 @@ function AuthElement({
6113
6231
  onRequiresOtp,
6114
6232
  onError
6115
6233
  }) {
6116
- const containerRef = react.useRef(null);
6117
- const elementRef = react.useRef(null);
6234
+ const containerRef = React2.useRef(null);
6235
+ const elementRef = React2.useRef(null);
6118
6236
  const elements = useElements();
6119
- const onReadyRef = react.useRef(onReady);
6120
- const onAuthenticatedRef = react.useRef(onAuthenticated);
6121
- const onRequiresOtpRef = react.useRef(onRequiresOtp);
6122
- const onErrorRef = react.useRef(onError);
6123
- react.useEffect(() => {
6237
+ const onReadyRef = React2.useRef(onReady);
6238
+ const onAuthenticatedRef = React2.useRef(onAuthenticated);
6239
+ const onRequiresOtpRef = React2.useRef(onRequiresOtp);
6240
+ const onErrorRef = React2.useRef(onError);
6241
+ React2.useEffect(() => {
6124
6242
  onReadyRef.current = onReady;
6125
6243
  onAuthenticatedRef.current = onAuthenticated;
6126
6244
  onRequiresOtpRef.current = onRequiresOtp;
6127
6245
  onErrorRef.current = onError;
6128
6246
  }, [onReady, onAuthenticated, onRequiresOtp, onError]);
6129
- react.useEffect(() => {
6247
+ React2.useEffect(() => {
6130
6248
  if (!elements || !containerRef.current) return;
6131
6249
  const element = elements.create(ELEMENT_TYPES.AUTH, { prefillEmail });
6132
6250
  elementRef.current = element;
@@ -6156,18 +6274,18 @@ function AddressElement({
6156
6274
  onChange,
6157
6275
  onError
6158
6276
  }) {
6159
- const containerRef = react.useRef(null);
6160
- const elementRef = react.useRef(null);
6277
+ const containerRef = React2.useRef(null);
6278
+ const elementRef = React2.useRef(null);
6161
6279
  const elements = useElements();
6162
- const onReadyRef = react.useRef(onReady);
6163
- const onChangeRef = react.useRef(onChange);
6164
- const onErrorRef = react.useRef(onError);
6165
- react.useEffect(() => {
6280
+ const onReadyRef = React2.useRef(onReady);
6281
+ const onChangeRef = React2.useRef(onChange);
6282
+ const onErrorRef = React2.useRef(onError);
6283
+ React2.useEffect(() => {
6166
6284
  onReadyRef.current = onReady;
6167
6285
  onChangeRef.current = onChange;
6168
6286
  onErrorRef.current = onError;
6169
6287
  }, [onReady, onChange, onError]);
6170
- react.useEffect(() => {
6288
+ React2.useEffect(() => {
6171
6289
  if (!elements || !containerRef.current) return;
6172
6290
  const element = elements.create(ELEMENT_TYPES.ADDRESS, { mode });
6173
6291
  elementRef.current = element;
@@ -6194,18 +6312,18 @@ function PaymentElement({
6194
6312
  onChange,
6195
6313
  onError
6196
6314
  }) {
6197
- const containerRef = react.useRef(null);
6198
- const elementRef = react.useRef(null);
6315
+ const containerRef = React2.useRef(null);
6316
+ const elementRef = React2.useRef(null);
6199
6317
  const elements = useElements();
6200
- const onReadyRef = react.useRef(onReady);
6201
- const onChangeRef = react.useRef(onChange);
6202
- const onErrorRef = react.useRef(onError);
6203
- react.useEffect(() => {
6318
+ const onReadyRef = React2.useRef(onReady);
6319
+ const onChangeRef = React2.useRef(onChange);
6320
+ const onErrorRef = React2.useRef(onError);
6321
+ React2.useEffect(() => {
6204
6322
  onReadyRef.current = onReady;
6205
6323
  onChangeRef.current = onChange;
6206
6324
  onErrorRef.current = onError;
6207
6325
  }, [onReady, onChange, onError]);
6208
- react.useEffect(() => {
6326
+ React2.useEffect(() => {
6209
6327
  if (!elements || !containerRef.current) return;
6210
6328
  const element = elements.create(ELEMENT_TYPES.PAYMENT, { amount, currency });
6211
6329
  elementRef.current = element;
@@ -6225,8 +6343,8 @@ function PaymentElement({
6225
6343
  }
6226
6344
  function useCheckout() {
6227
6345
  const elements = useElements();
6228
- const [isLoading, setIsLoading] = react.useState(false);
6229
- const submit = react.useCallback(
6346
+ const [isLoading, setIsLoading] = React2.useState(false);
6347
+ const submit = React2.useCallback(
6230
6348
  async (data) => {
6231
6349
  if (!elements) {
6232
6350
  return { success: false, error: { code: "NO_ELEMENTS", message: "Elements not initialized" } };
@@ -6240,7 +6358,7 @@ function useCheckout() {
6240
6358
  },
6241
6359
  [elements]
6242
6360
  );
6243
- const process = react.useCallback(
6361
+ const process = React2.useCallback(
6244
6362
  async (options) => {
6245
6363
  if (!elements) {
6246
6364
  return {