@solvapay/react 2.2.2 → 2.3.0-preview-e77af6c08d8a185342e1a74903c8545b94a9f51d

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.
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  AmountPicker,
3
+ CACHE_DURATION,
3
4
  MandateText,
4
5
  MissingProductRefError,
5
6
  MissingProviderError,
@@ -9,11 +10,14 @@ import {
9
10
  SolvaPayContext,
10
11
  Spinner,
11
12
  TopupForm,
13
+ autoRechargeCache,
14
+ autoRechargeCacheKeyFor,
12
15
  buildDefaultCheckoutPlanFilter,
13
16
  buildSummaryLine,
14
17
  composeEventHandlers,
15
18
  configToForm,
16
19
  createDefaultAutoRechargeForm,
20
+ createHttpTransport,
17
21
  effectiveMonthlySpend,
18
22
  estimateCredits,
19
23
  estimateCurrencyMajorFromCredits,
@@ -28,10 +32,10 @@ import {
28
32
  planBillingCycle,
29
33
  planBillingInterval,
30
34
  planSortByPaygFirstThenAsc,
35
+ subscribeAutoRecharge,
31
36
  useActivation,
32
37
  useAmountPicker,
33
38
  useAmountPickerCopy,
34
- useAutoRecharge,
35
39
  useBalance,
36
40
  useCheckoutFlow,
37
41
  useCopy,
@@ -43,10 +47,12 @@ import {
43
47
  useProduct,
44
48
  usePurchase,
45
49
  usePurchaseActions,
50
+ useSolvaPay,
46
51
  useTopupAmountSelector,
47
52
  validateAutoRechargeForm,
48
- withPaymentElementDefaults
49
- } from "./chunk-GPP4MY3I.js";
53
+ withPaymentElementDefaults,
54
+ writeAutoRechargeCache
55
+ } from "./chunk-JXH36VLL.js";
50
56
 
51
57
  // src/TopupForm.tsx
52
58
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -670,17 +676,194 @@ function useCreditGate() {
670
676
  return useGateCtx2("useCreditGate");
671
677
  }
672
678
 
679
+ // src/hooks/useAutoRecharge.ts
680
+ import { useCallback as useCallback3, useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
681
+ function mergeAutoRechargeConfig(config, display) {
682
+ return display ? { ...config, display } : config;
683
+ }
684
+ async function fetchAutoRecharge(config) {
685
+ const transport = config?.transport ?? createHttpTransport(config);
686
+ if (!transport.getAutoRecharge) return null;
687
+ const response = await transport.getAutoRecharge();
688
+ if (!response.config) return null;
689
+ return mergeAutoRechargeConfig(response.config, response.display);
690
+ }
691
+ function useAutoRecharge() {
692
+ const { _config } = useSolvaPay();
693
+ const key = autoRechargeCacheKeyFor(_config);
694
+ const [config, setConfig] = useState3(
695
+ () => autoRechargeCache.get(key)?.config ?? null
696
+ );
697
+ const [loading, setLoading] = useState3(() => {
698
+ const cached = autoRechargeCache.get(key);
699
+ return !cached || !cached.config && !cached.promise;
700
+ });
701
+ const [saving, setSaving] = useState3(false);
702
+ const [disabling, setDisabling] = useState3(false);
703
+ const [error, setError] = useState3(null);
704
+ const requestSeq = useRef2(0);
705
+ const load = useCallback3(
706
+ async (force = false) => {
707
+ const seq = requestSeq.current;
708
+ const cached = autoRechargeCache.get(key);
709
+ const now = Date.now();
710
+ if (!force && cached?.config && now - cached.timestamp < CACHE_DURATION) {
711
+ if (seq !== requestSeq.current) return;
712
+ setConfig(cached.config);
713
+ setLoading(false);
714
+ setError(null);
715
+ return;
716
+ }
717
+ if (!force && cached?.promise) {
718
+ setLoading(true);
719
+ try {
720
+ const value = await cached.promise;
721
+ if (seq !== requestSeq.current) return;
722
+ setConfig(value);
723
+ setError(null);
724
+ } catch (caught) {
725
+ if (seq !== requestSeq.current) return;
726
+ setError(caught instanceof Error ? caught : new Error(String(caught)));
727
+ } finally {
728
+ if (seq === requestSeq.current) {
729
+ setLoading(false);
730
+ }
731
+ }
732
+ return;
733
+ }
734
+ setLoading(true);
735
+ setError(null);
736
+ const promise = fetchAutoRecharge(_config);
737
+ writeAutoRechargeCache(key, {
738
+ config: cached?.config ?? null,
739
+ promise,
740
+ timestamp: now
741
+ });
742
+ try {
743
+ const value = await promise;
744
+ if (seq !== requestSeq.current) return;
745
+ writeAutoRechargeCache(key, { config: value, promise: null, timestamp: Date.now() });
746
+ setConfig(value);
747
+ } catch (caught) {
748
+ if (seq !== requestSeq.current) return;
749
+ const err = caught instanceof Error ? caught : new Error(String(caught));
750
+ writeAutoRechargeCache(key, {
751
+ config: cached?.config ?? null,
752
+ promise: null,
753
+ timestamp: Date.now()
754
+ });
755
+ setError(err);
756
+ } finally {
757
+ if (seq === requestSeq.current) {
758
+ setLoading(false);
759
+ }
760
+ }
761
+ },
762
+ [_config, key]
763
+ );
764
+ useEffect3(() => {
765
+ void load();
766
+ }, [load]);
767
+ useEffect3(() => {
768
+ return subscribeAutoRecharge(key, () => {
769
+ const cached = autoRechargeCache.get(key);
770
+ if (cached) {
771
+ setConfig(cached.config);
772
+ return;
773
+ }
774
+ void load(true);
775
+ });
776
+ }, [key, load]);
777
+ const refresh = useCallback3(
778
+ async (force = true) => {
779
+ await load(force);
780
+ },
781
+ [load]
782
+ );
783
+ const save = useCallback3(
784
+ async (input) => {
785
+ const transport = _config?.transport ?? createHttpTransport(_config);
786
+ if (!transport.saveAutoRecharge) {
787
+ throw new Error("saveAutoRecharge is not available on this transport");
788
+ }
789
+ setSaving(true);
790
+ setError(null);
791
+ const seq = ++requestSeq.current;
792
+ try {
793
+ const result = await transport.saveAutoRecharge(input);
794
+ if (seq !== requestSeq.current) return result;
795
+ const nextConfig = mergeAutoRechargeConfig(result.config, result.display);
796
+ writeAutoRechargeCache(key, {
797
+ config: nextConfig,
798
+ promise: null,
799
+ timestamp: Date.now()
800
+ });
801
+ setConfig(nextConfig);
802
+ return result;
803
+ } catch (caught) {
804
+ const err = caught instanceof Error ? caught : new Error(String(caught));
805
+ setError(err);
806
+ throw err;
807
+ } finally {
808
+ setSaving(false);
809
+ }
810
+ },
811
+ [_config, key]
812
+ );
813
+ const disable = useCallback3(async () => {
814
+ const transport = _config?.transport ?? createHttpTransport(_config);
815
+ if (!transport.disableAutoRecharge) {
816
+ throw new Error("disableAutoRecharge is not available on this transport");
817
+ }
818
+ setDisabling(true);
819
+ setError(null);
820
+ const seq = ++requestSeq.current;
821
+ try {
822
+ const result = await transport.disableAutoRecharge();
823
+ if (seq === requestSeq.current) {
824
+ setConfig((current) => {
825
+ const disabledConfig = current ? { ...current, enabled: false } : null;
826
+ writeAutoRechargeCache(key, {
827
+ config: disabledConfig,
828
+ promise: null,
829
+ timestamp: Date.now()
830
+ });
831
+ return disabledConfig;
832
+ });
833
+ await refresh(true);
834
+ setConfig((current) => {
835
+ const disabledConfig = current ? { ...current, enabled: false } : null;
836
+ writeAutoRechargeCache(key, {
837
+ config: disabledConfig,
838
+ promise: null,
839
+ timestamp: Date.now()
840
+ });
841
+ return disabledConfig;
842
+ });
843
+ }
844
+ return result;
845
+ } catch (caught) {
846
+ const err = caught instanceof Error ? caught : new Error(String(caught));
847
+ setError(err);
848
+ throw err;
849
+ } finally {
850
+ setDisabling(false);
851
+ }
852
+ }, [_config, key, refresh]);
853
+ return { config, loading, saving, disabling, error, refresh, save, disable };
854
+ }
855
+
673
856
  // src/primitives/AutoRecharge.tsx
674
857
  import {
675
858
  createContext as createContext4,
676
859
  forwardRef as forwardRef6,
677
- useCallback as useCallback3,
860
+ useCallback as useCallback4,
678
861
  useContext as useContext6,
679
- useEffect as useEffect3,
862
+ useEffect as useEffect4,
680
863
  useId,
681
864
  useMemo as useMemo5,
682
- useRef as useRef2,
683
- useState as useState3
865
+ useRef as useRef3,
866
+ useState as useState4
684
867
  } from "react";
685
868
  import { createPortal } from "react-dom";
686
869
  import {
@@ -778,12 +961,12 @@ var Root4 = forwardRef6(function AutoRechargeRoot({
778
961
  const { creditsPerMinorUnit, displayExchangeRate } = useBalance();
779
962
  const copy = useCopy();
780
963
  const titleId = useId();
781
- const triggerRef = useRef2(null);
964
+ const triggerRef = useRef3(null);
782
965
  const defaultTopup = defaultTopupAmountMajor ?? defaultThresholdAmountMajor ?? void 0;
783
- const [uncontrolledOpen, setUncontrolledOpen] = useState3(defaultOpen);
966
+ const [uncontrolledOpen, setUncontrolledOpen] = useState4(defaultOpen);
784
967
  const isControlled = openProp !== void 0;
785
968
  const open = isControlled ? openProp : uncontrolledOpen;
786
- const setOpen = useCallback3(
969
+ const setOpen = useCallback4(
787
970
  (next) => {
788
971
  if (!isControlled) {
789
972
  setUncontrolledOpen(next);
@@ -792,23 +975,23 @@ var Root4 = forwardRef6(function AutoRechargeRoot({
792
975
  },
793
976
  [isControlled, onOpenChange]
794
977
  );
795
- const registerTriggerRef = useCallback3((node) => {
978
+ const registerTriggerRef = useCallback4((node) => {
796
979
  triggerRef.current = node;
797
980
  }, []);
798
- const focusTrigger = useCallback3(() => {
981
+ const focusTrigger = useCallback4(() => {
799
982
  triggerRef.current?.focus();
800
983
  }, []);
801
- const [form, setForm] = useState3(
984
+ const [form, setForm] = useState4(
802
985
  () => autoRecharge.config ? configToForm(autoRecharge.config, currency) : createDefaultAutoRechargeForm(currency, defaultTopup)
803
986
  );
804
- const [validationError, setValidationError] = useState3(null);
805
- const [statusMessage, setStatusMessage] = useState3(null);
806
- const [setup, setSetup] = useState3(null);
807
- const latestConfigRef = useRef2(autoRecharge.config);
808
- useEffect3(() => {
987
+ const [validationError, setValidationError] = useState4(null);
988
+ const [statusMessage, setStatusMessage] = useState4(null);
989
+ const [setup, setSetup] = useState4(null);
990
+ const latestConfigRef = useRef3(autoRecharge.config);
991
+ useEffect4(() => {
809
992
  latestConfigRef.current = autoRecharge.config;
810
993
  }, [autoRecharge.config]);
811
- useEffect3(() => {
994
+ useEffect4(() => {
812
995
  if (autoRecharge.config) {
813
996
  setForm(configToForm(autoRecharge.config, currency));
814
997
  }
@@ -816,7 +999,7 @@ var Root4 = forwardRef6(function AutoRechargeRoot({
816
999
  const canToggleUnits = creditsPerMinorUnit != null && creditsPerMinorUnit > 0;
817
1000
  const rate = displayExchangeRate ?? 1;
818
1001
  const isApproximate = rate !== 1;
819
- const emitValidation = useCallback3(
1002
+ const emitValidation = useCallback4(
820
1003
  (next) => {
821
1004
  const result = validateAutoRechargeForm(
822
1005
  next,
@@ -833,7 +1016,7 @@ var Root4 = forwardRef6(function AutoRechargeRoot({
833
1016
  },
834
1017
  [currency, creditsPerMinorUnit, displayExchangeRate, copy.autoRecharge]
835
1018
  );
836
- const updateForm = useCallback3(
1019
+ const updateForm = useCallback4(
837
1020
  (patch) => {
838
1021
  setForm((prev) => {
839
1022
  const next = { ...prev, ...patch };
@@ -843,7 +1026,7 @@ var Root4 = forwardRef6(function AutoRechargeRoot({
843
1026
  },
844
1027
  [emitValidation]
845
1028
  );
846
- const resetForm = useCallback3(() => {
1029
+ const resetForm = useCallback4(() => {
847
1030
  if (autoRecharge.config) {
848
1031
  setForm(configToForm(autoRecharge.config, currency));
849
1032
  } else {
@@ -851,7 +1034,7 @@ var Root4 = forwardRef6(function AutoRechargeRoot({
851
1034
  }
852
1035
  setValidationError(null);
853
1036
  }, [autoRecharge.config, currency, defaultTopup]);
854
- const flipUnit = useCallback3(
1037
+ const flipUnit = useCallback4(
855
1038
  (valueKey, unitKey, baseValueKey, baseUnitKey, currentUnit) => {
856
1039
  const nextUnit = currentUnit === "currency" ? "credits" : "currency";
857
1040
  setForm((prev) => {
@@ -906,7 +1089,7 @@ var Root4 = forwardRef6(function AutoRechargeRoot({
906
1089
  currency
907
1090
  );
908
1091
  }, [autoRecharge.config, currency]);
909
- const save = useCallback3(async () => {
1092
+ const save = useCallback4(async () => {
910
1093
  const payload = emitValidation(form);
911
1094
  if (!payload) return;
912
1095
  const saveInput = deferCardSetup ? { ...payload, deferSetupIntent: true } : payload;
@@ -937,13 +1120,13 @@ var Root4 = forwardRef6(function AutoRechargeRoot({
937
1120
  onSetupRequired,
938
1121
  setOpen
939
1122
  ]);
940
- const disable = useCallback3(async () => {
1123
+ const disable = useCallback4(async () => {
941
1124
  await autoRecharge.disable();
942
1125
  setStatusMessage(copy.autoRecharge.disabledMessage);
943
1126
  setSetup(null);
944
1127
  await onDisabled?.();
945
1128
  }, [autoRecharge, copy.autoRecharge, onDisabled]);
946
- const completeSetup = useCallback3(async () => {
1129
+ const completeSetup = useCallback4(async () => {
947
1130
  const activated = await waitForAutoRechargeActivation({
948
1131
  refresh: autoRecharge.refresh,
949
1132
  getStatus: () => latestConfigRef.current?.status
@@ -1150,8 +1333,8 @@ var Overlay = forwardRef6(
1150
1333
  );
1151
1334
  var Content = forwardRef6(function AutoRechargeContent({ className, children, ...rest }, forwardedRef) {
1152
1335
  const ctx = useAutoRechargeCtx("Content");
1153
- const panelRef = useRef2(null);
1154
- useEffect3(() => {
1336
+ const panelRef = useRef3(null);
1337
+ useEffect4(() => {
1155
1338
  if (!ctx.open) return;
1156
1339
  const handleKeyDown = (event) => {
1157
1340
  if (event.key === "Escape") {
@@ -1790,9 +1973,9 @@ function CardSetupInner({ onComplete }) {
1790
1973
  const copy = useCopy();
1791
1974
  const stripe = useStripe();
1792
1975
  const elements = useElements();
1793
- const [processing, setProcessing] = useState3(false);
1794
- const [error, setError] = useState3(null);
1795
- useEffect3(() => {
1976
+ const [processing, setProcessing] = useState4(false);
1977
+ const [error, setError] = useState4(null);
1978
+ useEffect4(() => {
1796
1979
  if (!stripe) return;
1797
1980
  const clientSecret = readSetupIntentClientSecret(window.location.search);
1798
1981
  if (!clientSecret) return;
@@ -1970,7 +2153,7 @@ function useAutoRechargeForm() {
1970
2153
  }
1971
2154
 
1972
2155
  // src/hooks/usePaywallResolver.ts
1973
- import { useCallback as useCallback4, useMemo as useMemo6 } from "react";
2156
+ import { useCallback as useCallback5, useMemo as useMemo6 } from "react";
1974
2157
  function balanceCoversNextUnit(balance, credits) {
1975
2158
  if (!balance) return false;
1976
2159
  if (typeof balance.remainingUnits === "number" && balance.remainingUnits > 0) {
@@ -1994,7 +2177,7 @@ function usePaywallResolver(content) {
1994
2177
  if (balanceCoversNextUnit(content.balance, credits)) return true;
1995
2178
  return Boolean(productMatches && activePurchase?.status === "active");
1996
2179
  }, [content, hasPaidPurchase, activePurchase, credits]);
1997
- const refetch = useCallback4(async () => {
2180
+ const refetch = useCallback5(async () => {
1998
2181
  await Promise.all([
1999
2182
  refetchPurchase().catch(() => void 0),
2000
2183
  refetchBalance().catch(() => void 0)
@@ -2007,11 +2190,11 @@ function usePaywallResolver(content) {
2007
2190
  import {
2008
2191
  createContext as createContext6,
2009
2192
  forwardRef as forwardRef8,
2010
- useCallback as useCallback5,
2193
+ useCallback as useCallback6,
2011
2194
  useContext as useContext8,
2012
- useEffect as useEffect4,
2195
+ useEffect as useEffect5,
2013
2196
  useMemo as useMemo8,
2014
- useRef as useRef3
2197
+ useRef as useRef4
2015
2198
  } from "react";
2016
2199
 
2017
2200
  // src/primitives/checkout/index.tsx
@@ -2603,17 +2786,17 @@ function usePaywallNoticeCtx(part) {
2603
2786
  var Root6 = forwardRef8(function PaywallNoticeRoot({ content, onResolved, classNames, asChild, children, ...rest }, forwardedRef) {
2604
2787
  const { resolved, refetch } = usePaywallResolver(content);
2605
2788
  const classNamesResolved = useMemo8(() => classNames ?? {}, [classNames]);
2606
- const onResolvedRef = useRef3(onResolved);
2607
- useEffect4(() => {
2789
+ const onResolvedRef = useRef4(onResolved);
2790
+ useEffect5(() => {
2608
2791
  onResolvedRef.current = onResolved;
2609
2792
  }, [onResolved]);
2610
- const hasResolvedRef = useRef3(false);
2611
- const signalResolved = useCallback5(() => {
2793
+ const hasResolvedRef = useRef4(false);
2794
+ const signalResolved = useCallback6(() => {
2612
2795
  if (hasResolvedRef.current) return;
2613
2796
  hasResolvedRef.current = true;
2614
2797
  onResolvedRef.current?.();
2615
2798
  }, []);
2616
- useEffect4(() => {
2799
+ useEffect5(() => {
2617
2800
  if (resolved) signalResolved();
2618
2801
  }, [resolved, signalResolved]);
2619
2802
  const ctx = useMemo8(
@@ -2905,6 +3088,7 @@ export {
2905
3088
  CreditGateError2 as CreditGateError,
2906
3089
  CreditGate,
2907
3090
  useCreditGate,
3091
+ useAutoRecharge,
2908
3092
  AutoRechargeRoot2 as AutoRechargeRoot,
2909
3093
  AutoRechargeLoading2 as AutoRechargeLoading,
2910
3094
  AutoRechargeCard2 as AutoRechargeCard,
@@ -8,7 +8,7 @@ import {
8
8
  useOpenExternal,
9
9
  useSolvaPay,
10
10
  useTransport
11
- } from "./chunk-GPP4MY3I.js";
11
+ } from "./chunk-JXH36VLL.js";
12
12
 
13
13
  // src/hooks/usePaymentMethod.ts
14
14
  import { useCallback, useEffect, useState } from "react";
@@ -1,4 +1,4 @@
1
- import { a4 as components, b as Plan, P as PaymentFormProps, a as PrefillCustomer, A as ActivationResult, s as UseTopupAmountSelectorReturn, a5 as AutoRechargeInput, u as AutoRechargeConfig, a6 as AutoRechargeDisplayBlock, E as CheckoutStep, O as SuccessMeta } from './useUsage-DSPWQ37m.js';
1
+ import { a4 as components, b as Plan, P as PaymentFormProps, a as PrefillCustomer, A as ActivationResult, s as UseTopupAmountSelectorReturn, a5 as AutoRechargeInput, u as AutoRechargeConfig, a6 as AutoRechargeDisplayBlock, E as CheckoutStep, O as SuccessMeta } from './useUsage-DNXxsmyG.cjs';
2
2
  import React from 'react';
3
3
  import { PaymentElement, CardElement } from '@stripe/react-stripe-js';
4
4
  import { TaxBreakdown } from '@solvapay/core';
@@ -177,6 +177,12 @@ declare function deriveVariant(plan: Plan | null | undefined, mode?: 'topup'): C
177
177
  * i18n template signature untouched while lifting the legal commitment
178
178
  * to the point of charge.
179
179
  *
180
+ * `savesPaymentMethod` marks a confirm that also stores the card for
181
+ * later off-session charges (auto-recharge). The MCP payment surfaces
182
+ * turn Stripe's own `terms` line off, so this component is the only
183
+ * place that discloses the storage — the topup template appends a
184
+ * saved-card sentence when the flag is set.
185
+ *
180
186
  * When the merchant record omits `termsUrl` / `privacyUrl`, we fall back
181
187
  * to SolvaPay's hosted legal pages so the mandate sentence always carries
182
188
  * working links. SolvaPay is the underlying processor on every charge, so
@@ -192,6 +198,11 @@ type MandateTextProps = {
192
198
  mode?: 'topup';
193
199
  amountMinor?: number;
194
200
  currency?: string;
201
+ /**
202
+ * Set when the confirm also stores the card for later off-session
203
+ * charges (auto-recharge), so the mandate discloses the storage.
204
+ */
205
+ savesPaymentMethod?: boolean;
195
206
  asChild?: boolean;
196
207
  } & Omit<React.HTMLAttributes<HTMLParagraphElement>, 'children'> & {
197
208
  children?: React.ReactNode;
@@ -203,6 +214,11 @@ declare const MandateText: React.ForwardRefExoticComponent<{
203
214
  mode?: "topup";
204
215
  amountMinor?: number;
205
216
  currency?: string;
217
+ /**
218
+ * Set when the confirm also stores the card for later off-session
219
+ * charges (auto-recharge), so the mandate discloses the storage.
220
+ */
221
+ savesPaymentMethod?: boolean;
206
222
  asChild?: boolean;
207
223
  } & Omit<React.HTMLAttributes<HTMLParagraphElement>, "children"> & {
208
224
  children?: React.ReactNode;
@@ -1,4 +1,4 @@
1
- import { a4 as components, b as Plan, P as PaymentFormProps, a as PrefillCustomer, A as ActivationResult, s as UseTopupAmountSelectorReturn, a5 as AutoRechargeInput, u as AutoRechargeConfig, a6 as AutoRechargeDisplayBlock, E as CheckoutStep, O as SuccessMeta } from './useUsage-CRd_E6J3.cjs';
1
+ import { a4 as components, b as Plan, P as PaymentFormProps, a as PrefillCustomer, A as ActivationResult, s as UseTopupAmountSelectorReturn, a5 as AutoRechargeInput, u as AutoRechargeConfig, a6 as AutoRechargeDisplayBlock, E as CheckoutStep, O as SuccessMeta } from './useUsage-CwvxnICf.js';
2
2
  import React from 'react';
3
3
  import { PaymentElement, CardElement } from '@stripe/react-stripe-js';
4
4
  import { TaxBreakdown } from '@solvapay/core';
@@ -177,6 +177,12 @@ declare function deriveVariant(plan: Plan | null | undefined, mode?: 'topup'): C
177
177
  * i18n template signature untouched while lifting the legal commitment
178
178
  * to the point of charge.
179
179
  *
180
+ * `savesPaymentMethod` marks a confirm that also stores the card for
181
+ * later off-session charges (auto-recharge). The MCP payment surfaces
182
+ * turn Stripe's own `terms` line off, so this component is the only
183
+ * place that discloses the storage — the topup template appends a
184
+ * saved-card sentence when the flag is set.
185
+ *
180
186
  * When the merchant record omits `termsUrl` / `privacyUrl`, we fall back
181
187
  * to SolvaPay's hosted legal pages so the mandate sentence always carries
182
188
  * working links. SolvaPay is the underlying processor on every charge, so
@@ -192,6 +198,11 @@ type MandateTextProps = {
192
198
  mode?: 'topup';
193
199
  amountMinor?: number;
194
200
  currency?: string;
201
+ /**
202
+ * Set when the confirm also stores the card for later off-session
203
+ * charges (auto-recharge), so the mandate discloses the storage.
204
+ */
205
+ savesPaymentMethod?: boolean;
195
206
  asChild?: boolean;
196
207
  } & Omit<React.HTMLAttributes<HTMLParagraphElement>, 'children'> & {
197
208
  children?: React.ReactNode;
@@ -203,6 +214,11 @@ declare const MandateText: React.ForwardRefExoticComponent<{
203
214
  mode?: "topup";
204
215
  amountMinor?: number;
205
216
  currency?: string;
217
+ /**
218
+ * Set when the confirm also stores the card for later off-session
219
+ * charges (auto-recharge), so the mandate discloses the storage.
220
+ */
221
+ savesPaymentMethod?: boolean;
206
222
  asChild?: boolean;
207
223
  } & Omit<React.HTMLAttributes<HTMLParagraphElement>, "children"> & {
208
224
  children?: React.ReactNode;
package/dist/index.cjs CHANGED
@@ -624,7 +624,8 @@ var enCopy = {
624
624
  },
625
625
  topup: (ctx) => {
626
626
  const product = ctx.product?.name ? ` to add credits to your ${ctx.product.name} balance` : " to add credits to your balance";
627
- return `By confirming, you authorize ${ctx.merchant.legalName} to charge ${ctx.amountFormatted}${product}. Credits are non-refundable once used. Payments are processed by SolvaPay.${termsSentence(ctx)}`;
627
+ const savedCard = ctx.savesPaymentMethod ? ` You also authorize ${ctx.merchant.legalName} to save this card and charge it for future auto-recharges, which you can turn off any time.` : "";
628
+ return `By confirming, you authorize ${ctx.merchant.legalName} to charge ${ctx.amountFormatted}${product}. Credits are non-refundable once used.${savedCard} Payments are processed by SolvaPay.${termsSentence(ctx)}`;
628
629
  },
629
630
  usageMetered: (ctx) => {
630
631
  const measures = ctx.plan?.measures ?? "request";
@@ -863,8 +864,10 @@ var enCopy = {
863
864
  addFunds: "Add funds",
864
865
  autoRechargeOn: "Auto-recharge on",
865
866
  autoRechargeOff: "Auto-recharge off",
866
- turnOn: "Turn on \u2192",
867
- manage: "Manage \u2192",
867
+ autoRechargePending: "Auto-recharge starts once this payment clears",
868
+ turnOn: "Turn on",
869
+ manage: "Manage",
870
+ fixCard: "Fix card",
868
871
  autoRechargeOffCaption: "Calls fail the moment the balance runs out.",
869
872
  autoRechargeOffFixCaption: "Turning it on stops this happening again.",
870
873
  callsFailingCaption: "The plan is active, but calls fail until you add credits.",
@@ -3537,6 +3540,7 @@ var MandateText = (0, import_react18.forwardRef)(
3537
3540
  mode,
3538
3541
  amountMinor,
3539
3542
  currency,
3543
+ savesPaymentMethod,
3540
3544
  asChild,
3541
3545
  children,
3542
3546
  ...rest
@@ -3578,9 +3582,10 @@ var MandateText = (0, import_react18.forwardRef)(
3578
3582
  } : void 0,
3579
3583
  product: product ? { name: product.name } : void 0,
3580
3584
  amountFormatted,
3581
- trialDays: plan?.trialDays
3585
+ trialDays: plan?.trialDays,
3586
+ savesPaymentMethod
3582
3587
  }),
3583
- [merchant, plan, product, amountFormatted]
3588
+ [merchant, plan, product, amountFormatted, savesPaymentMethod]
3584
3589
  );
3585
3590
  const template = copy.mandate[resolvedVariant];
3586
3591
  const text = typeof template === "function" ? template(ctx) : template;
package/dist/index.d.cts CHANGED
@@ -1,8 +1,8 @@
1
1
  import React from 'react';
2
- import { S as SolvaPayProviderProps, P as PaymentFormProps, a as PrefillCustomer, T as TopupFormProps, C as CheckoutResult, b as Plan, A as ActivationResult, B as BootstrapPlanLike, c as SaveAutoRechargeResponse, d as PurchaseStatus, e as SolvaPayContextValue, U as UsePlansOptions, f as UsePlansReturn, g as UsePlanOptions, h as UsePlanReturn, i as UseProductReturn, j as UseMerchantReturn, k as SolvaPayCopy, l as PurchaseStatusReturn, m as CancelResult, R as ReactivateResult, n as ActivatePlanResult, o as UseTopupOptions, p as UseTopupReturn, q as BalanceStatus, r as UseTopupAmountSelectorOptions, s as UseTopupAmountSelectorReturn, t as UsePaymentMethodReturn, u as AutoRechargeConfig, v as SaveAutoRechargeInput, w as SolvaPayTransport, x as PartialSolvaPayCopy, y as PurchaseInfo, z as Product, D as SolvaPayConfig } from './useUsage-CRd_E6J3.cjs';
3
- export { E as CheckoutStep, F as CustomerPurchaseData, M as MandateContext, G as MandateTemplate, H as Merchant, I as PaymentError, J as PaymentIntentResult, K as PaymentMethodInfo, L as PaymentResult, N as PurchaseStatusValue, O as SuccessMeta, Q as TopupPaymentResult, V as TransportBalanceResult, W as TransportCheckoutSessionResult, X as TransportCustomerSessionResult, Y as TransportLimitsResult, Z as UnsupportedTransportMethodError, _ as UsageSnapshot, $ as UseUsageReturn, a0 as useUsage } from './useUsage-CRd_E6J3.cjs';
4
- import { P as PaymentFormSummary, a as PaymentFormCustomerFields, b as PaymentFormPaymentElement, c as PaymentFormCardElement, d as PaymentFormMandateText, e as PaymentFormTermsCheckbox, f as PaymentFormSubmitButton, g as PaymentFormLoading, h as PaymentFormError, i as PaymentFormLegalFooter, j as PaymentFormBusinessDetails, k as PaymentFormTaxSummary, A as AutoRechargeInputPayload, l as PaywallStructuredContent, C as CheckoutVariant } from './index-B5QUesJE.cjs';
5
- export { m as ActivationFlowStep, B as BalanceBadge, n as CancelPlanButton, o as CheckoutErrorPhase, p as CheckoutStatus, q as CheckoutSteps, r as CheckoutSummary, s as CheckoutSummaryProps, M as MandateText, t as MandateTextProps, u as PlanBadge, v as ProductBadge, w as PurchaseGate, U as UseCheckoutFlowOptions, x as UseCheckoutFlowReturn, y as configToAutoRechargeInput, z as deriveVariant, D as useCheckoutFlow, E as useCheckoutStepsContext } from './index-B5QUesJE.cjs';
2
+ import { S as SolvaPayProviderProps, P as PaymentFormProps, a as PrefillCustomer, T as TopupFormProps, C as CheckoutResult, b as Plan, A as ActivationResult, B as BootstrapPlanLike, c as SaveAutoRechargeResponse, d as PurchaseStatus, e as SolvaPayContextValue, U as UsePlansOptions, f as UsePlansReturn, g as UsePlanOptions, h as UsePlanReturn, i as UseProductReturn, j as UseMerchantReturn, k as SolvaPayCopy, l as PurchaseStatusReturn, m as CancelResult, R as ReactivateResult, n as ActivatePlanResult, o as UseTopupOptions, p as UseTopupReturn, q as BalanceStatus, r as UseTopupAmountSelectorOptions, s as UseTopupAmountSelectorReturn, t as UsePaymentMethodReturn, u as AutoRechargeConfig, v as SaveAutoRechargeInput, w as SolvaPayTransport, x as PartialSolvaPayCopy, y as PurchaseInfo, z as Product, D as SolvaPayConfig } from './useUsage-DNXxsmyG.cjs';
3
+ export { E as CheckoutStep, F as CustomerPurchaseData, M as MandateContext, G as MandateTemplate, H as Merchant, I as PaymentError, J as PaymentIntentResult, K as PaymentMethodInfo, L as PaymentResult, N as PurchaseStatusValue, O as SuccessMeta, Q as TopupPaymentResult, V as TransportBalanceResult, W as TransportCheckoutSessionResult, X as TransportCustomerSessionResult, Y as TransportLimitsResult, Z as UnsupportedTransportMethodError, _ as UsageSnapshot, $ as UseUsageReturn, a0 as useUsage } from './useUsage-DNXxsmyG.cjs';
4
+ import { P as PaymentFormSummary, a as PaymentFormCustomerFields, b as PaymentFormPaymentElement, c as PaymentFormCardElement, d as PaymentFormMandateText, e as PaymentFormTermsCheckbox, f as PaymentFormSubmitButton, g as PaymentFormLoading, h as PaymentFormError, i as PaymentFormLegalFooter, j as PaymentFormBusinessDetails, k as PaymentFormTaxSummary, A as AutoRechargeInputPayload, l as PaywallStructuredContent, C as CheckoutVariant } from './index-BadShw3R.cjs';
5
+ export { m as ActivationFlowStep, B as BalanceBadge, n as CancelPlanButton, o as CheckoutErrorPhase, p as CheckoutStatus, q as CheckoutSteps, r as CheckoutSummary, s as CheckoutSummaryProps, M as MandateText, t as MandateTextProps, u as PlanBadge, v as ProductBadge, w as PurchaseGate, U as UseCheckoutFlowOptions, x as UseCheckoutFlowReturn, y as configToAutoRechargeInput, z as deriveVariant, D as useCheckoutFlow, E as useCheckoutStepsContext } from './index-BadShw3R.cjs';
6
6
  import { PaymentIntent, Stripe, StripeElements } from '@stripe/stripe-js';
7
7
  import { BusinessDetailsInput, TaxBreakdown } from '@solvapay/core';
8
8
  import * as react_jsx_runtime from 'react/jsx-runtime';
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import React from 'react';
2
- import { S as SolvaPayProviderProps, P as PaymentFormProps, a as PrefillCustomer, T as TopupFormProps, C as CheckoutResult, b as Plan, A as ActivationResult, B as BootstrapPlanLike, c as SaveAutoRechargeResponse, d as PurchaseStatus, e as SolvaPayContextValue, U as UsePlansOptions, f as UsePlansReturn, g as UsePlanOptions, h as UsePlanReturn, i as UseProductReturn, j as UseMerchantReturn, k as SolvaPayCopy, l as PurchaseStatusReturn, m as CancelResult, R as ReactivateResult, n as ActivatePlanResult, o as UseTopupOptions, p as UseTopupReturn, q as BalanceStatus, r as UseTopupAmountSelectorOptions, s as UseTopupAmountSelectorReturn, t as UsePaymentMethodReturn, u as AutoRechargeConfig, v as SaveAutoRechargeInput, w as SolvaPayTransport, x as PartialSolvaPayCopy, y as PurchaseInfo, z as Product, D as SolvaPayConfig } from './useUsage-DSPWQ37m.js';
3
- export { E as CheckoutStep, F as CustomerPurchaseData, M as MandateContext, G as MandateTemplate, H as Merchant, I as PaymentError, J as PaymentIntentResult, K as PaymentMethodInfo, L as PaymentResult, N as PurchaseStatusValue, O as SuccessMeta, Q as TopupPaymentResult, V as TransportBalanceResult, W as TransportCheckoutSessionResult, X as TransportCustomerSessionResult, Y as TransportLimitsResult, Z as UnsupportedTransportMethodError, _ as UsageSnapshot, $ as UseUsageReturn, a0 as useUsage } from './useUsage-DSPWQ37m.js';
4
- import { P as PaymentFormSummary, a as PaymentFormCustomerFields, b as PaymentFormPaymentElement, c as PaymentFormCardElement, d as PaymentFormMandateText, e as PaymentFormTermsCheckbox, f as PaymentFormSubmitButton, g as PaymentFormLoading, h as PaymentFormError, i as PaymentFormLegalFooter, j as PaymentFormBusinessDetails, k as PaymentFormTaxSummary, A as AutoRechargeInputPayload, l as PaywallStructuredContent, C as CheckoutVariant } from './index-BAYpUp5R.js';
5
- export { m as ActivationFlowStep, B as BalanceBadge, n as CancelPlanButton, o as CheckoutErrorPhase, p as CheckoutStatus, q as CheckoutSteps, r as CheckoutSummary, s as CheckoutSummaryProps, M as MandateText, t as MandateTextProps, u as PlanBadge, v as ProductBadge, w as PurchaseGate, U as UseCheckoutFlowOptions, x as UseCheckoutFlowReturn, y as configToAutoRechargeInput, z as deriveVariant, D as useCheckoutFlow, E as useCheckoutStepsContext } from './index-BAYpUp5R.js';
2
+ import { S as SolvaPayProviderProps, P as PaymentFormProps, a as PrefillCustomer, T as TopupFormProps, C as CheckoutResult, b as Plan, A as ActivationResult, B as BootstrapPlanLike, c as SaveAutoRechargeResponse, d as PurchaseStatus, e as SolvaPayContextValue, U as UsePlansOptions, f as UsePlansReturn, g as UsePlanOptions, h as UsePlanReturn, i as UseProductReturn, j as UseMerchantReturn, k as SolvaPayCopy, l as PurchaseStatusReturn, m as CancelResult, R as ReactivateResult, n as ActivatePlanResult, o as UseTopupOptions, p as UseTopupReturn, q as BalanceStatus, r as UseTopupAmountSelectorOptions, s as UseTopupAmountSelectorReturn, t as UsePaymentMethodReturn, u as AutoRechargeConfig, v as SaveAutoRechargeInput, w as SolvaPayTransport, x as PartialSolvaPayCopy, y as PurchaseInfo, z as Product, D as SolvaPayConfig } from './useUsage-CwvxnICf.js';
3
+ export { E as CheckoutStep, F as CustomerPurchaseData, M as MandateContext, G as MandateTemplate, H as Merchant, I as PaymentError, J as PaymentIntentResult, K as PaymentMethodInfo, L as PaymentResult, N as PurchaseStatusValue, O as SuccessMeta, Q as TopupPaymentResult, V as TransportBalanceResult, W as TransportCheckoutSessionResult, X as TransportCustomerSessionResult, Y as TransportLimitsResult, Z as UnsupportedTransportMethodError, _ as UsageSnapshot, $ as UseUsageReturn, a0 as useUsage } from './useUsage-CwvxnICf.js';
4
+ import { P as PaymentFormSummary, a as PaymentFormCustomerFields, b as PaymentFormPaymentElement, c as PaymentFormCardElement, d as PaymentFormMandateText, e as PaymentFormTermsCheckbox, f as PaymentFormSubmitButton, g as PaymentFormLoading, h as PaymentFormError, i as PaymentFormLegalFooter, j as PaymentFormBusinessDetails, k as PaymentFormTaxSummary, A as AutoRechargeInputPayload, l as PaywallStructuredContent, C as CheckoutVariant } from './index-DN66D54Q.js';
5
+ export { m as ActivationFlowStep, B as BalanceBadge, n as CancelPlanButton, o as CheckoutErrorPhase, p as CheckoutStatus, q as CheckoutSteps, r as CheckoutSummary, s as CheckoutSummaryProps, M as MandateText, t as MandateTextProps, u as PlanBadge, v as ProductBadge, w as PurchaseGate, U as UseCheckoutFlowOptions, x as UseCheckoutFlowReturn, y as configToAutoRechargeInput, z as deriveVariant, D as useCheckoutFlow, E as useCheckoutStepsContext } from './index-DN66D54Q.js';
6
6
  import { PaymentIntent, Stripe, StripeElements } from '@stripe/stripe-js';
7
7
  import { BusinessDetailsInput, TaxBreakdown } from '@solvapay/core';
8
8
  import * as react_jsx_runtime from 'react/jsx-runtime';
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  LaunchCustomerPortalButton,
6
6
  usePaymentMethod
7
- } from "./chunk-4UFQDYG5.js";
7
+ } from "./chunk-QWK3LMGG.js";
8
8
  import {
9
9
  ActivationFlow,
10
10
  AutoRecharge,
@@ -16,10 +16,11 @@ import {
16
16
  PurchaseGate,
17
17
  TopupForm,
18
18
  useActivationFlow,
19
+ useAutoRecharge,
19
20
  useCheckoutSteps,
20
21
  useCreditGate,
21
22
  usePaywallResolver
22
- } from "./chunk-KUH3SNWZ.js";
23
+ } from "./chunk-LXG7QDM3.js";
23
24
  import {
24
25
  AmountPicker,
25
26
  BalanceBadge,
@@ -77,7 +78,6 @@ import {
77
78
  useActivation,
78
79
  useAmountPicker,
79
80
  useAmountPickerCopy,
80
- useAutoRecharge,
81
81
  useBalance,
82
82
  useCheckout,
83
83
  useCheckoutFlow,
@@ -100,7 +100,7 @@ import {
100
100
  useTopupAmountSelector,
101
101
  useTransport,
102
102
  useUsage
103
- } from "./chunk-GPP4MY3I.js";
103
+ } from "./chunk-JXH36VLL.js";
104
104
  import {
105
105
  createAnonymousAuthAdapter,
106
106
  defaultAuthAdapter,