@solvapay/react 1.3.0 → 1.4.0-preview-ecd61384a4e849717e13d47ab2daa086cdcd91c5

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/index.cjs CHANGED
@@ -32,6 +32,7 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  ActivationFlow: () => ActivationFlow2,
34
34
  AmountPicker: () => AmountPicker2,
35
+ AutoRecharge: () => AutoRecharge2,
35
36
  BalanceBadge: () => BalanceBadge,
36
37
  CancelPlanButton: () => CancelPlanButton,
37
38
  CancelledPlanNotice: () => CancelledPlanNotice2,
@@ -58,6 +59,7 @@ __export(index_exports, {
58
59
  TopupForm: () => TopupForm2,
59
60
  UnsupportedTransportMethodError: () => UnsupportedTransportMethodError,
60
61
  UpdatePaymentMethodButton: () => UpdatePaymentMethodButton,
62
+ configToAutoRechargeInput: () => configToAutoRechargeInput,
61
63
  confirmPayment: () => confirmPayment,
62
64
  createAnonymousAuthAdapter: () => createAnonymousAuthAdapter,
63
65
  createHttpTransport: () => createHttpTransport,
@@ -83,6 +85,7 @@ __export(index_exports, {
83
85
  toMajorUnits: () => toMajorUnits,
84
86
  useActivation: () => useActivation,
85
87
  useAutoActivateFreePlan: () => useAutoActivateFreePlan,
88
+ useAutoRecharge: () => useAutoRecharge,
86
89
  useBalance: () => useBalance,
87
90
  useCheckout: () => useCheckout,
88
91
  useCheckoutFlow: () => useCheckoutFlow,
@@ -112,6 +115,29 @@ module.exports = __toCommonJS(index_exports);
112
115
  // src/SolvaPayProvider.tsx
113
116
  var import_react2 = require("react");
114
117
 
118
+ // ../server/src/index.ts
119
+ var import_node_crypto = __toESM(require("crypto"), 1);
120
+ var import_core = require("@solvapay/core");
121
+
122
+ // ../server/src/helpers/balance-poll.ts
123
+ var BALANCE_RECONCILE_DELAYS_MS = [500, 1e3, 2e3, 4e3, 8e3, 16e3];
124
+ async function pollBalanceUntilIncreased(getBalance, baseline, delays = BALANCE_RECONCILE_DELAYS_MS) {
125
+ for (const delay of delays) {
126
+ await new Promise((resolve) => setTimeout(resolve, delay));
127
+ try {
128
+ const post = await getBalance();
129
+ if (post.credits > baseline) {
130
+ return { creditsAdded: post.credits - baseline };
131
+ }
132
+ } catch {
133
+ }
134
+ }
135
+ return null;
136
+ }
137
+
138
+ // src/helpers/auto-recharge-cache.ts
139
+ var BALANCE_RECONCILE_GRACE_MS = BALANCE_RECONCILE_DELAYS_MS.reduce((sum, delay) => sum + delay, 0) + 1e3;
140
+
115
141
  // src/utils/purchases.ts
116
142
  function filterPurchases(purchases) {
117
143
  return purchases.filter((purchase) => purchase.status === "active");
@@ -308,6 +334,7 @@ var DEFAULT_ROUTES = {
308
334
  getProduct: "/api/get-product",
309
335
  listPlans: "/api/list-plans",
310
336
  getPaymentMethod: "/api/payment-method",
337
+ autoRecharge: "/api/auto-recharge",
311
338
  getUsage: "/api/usage",
312
339
  getLimits: "/api/limits"
313
340
  };
@@ -345,7 +372,11 @@ function createHttpTransport(config) {
345
372
  }),
346
373
  createTopupPayment: (params) => request(config, routeFor(config, "createTopupPayment"), {
347
374
  method: "POST",
348
- body: { amount: params.amount, currency: params.currency },
375
+ body: {
376
+ amount: params.amount,
377
+ currency: params.currency,
378
+ ...params.autoRecharge ? { autoRecharge: params.autoRecharge } : {}
379
+ },
349
380
  onErrorContext: "createTopupPayment",
350
381
  errorPrefix: "Failed to create topup payment"
351
382
  }),
@@ -394,16 +425,12 @@ function createHttpTransport(config) {
394
425
  }
395
426
  );
396
427
  },
397
- createCustomerSession: () => request(
398
- config,
399
- routeFor(config, "createCustomerSession"),
400
- {
401
- method: "POST",
402
- body: {},
403
- onErrorContext: "createCustomerSession",
404
- errorPrefix: "Failed to create customer session"
405
- }
406
- ),
428
+ createCustomerSession: () => request(config, routeFor(config, "createCustomerSession"), {
429
+ method: "POST",
430
+ body: {},
431
+ onErrorContext: "createCustomerSession",
432
+ errorPrefix: "Failed to create customer session"
433
+ }),
407
434
  getMerchant: () => request(config, routeFor(config, "getMerchant"), {
408
435
  method: "GET",
409
436
  onErrorContext: "getMerchant",
@@ -433,6 +460,22 @@ function createHttpTransport(config) {
433
460
  onErrorContext: "getPaymentMethod",
434
461
  errorPrefix: "Failed to load payment method"
435
462
  }),
463
+ getAutoRecharge: () => request(config, routeFor(config, "autoRecharge"), {
464
+ method: "GET",
465
+ onErrorContext: "getAutoRecharge",
466
+ errorPrefix: "Failed to load auto-recharge"
467
+ }),
468
+ saveAutoRecharge: (input) => request(config, routeFor(config, "autoRecharge"), {
469
+ method: "PUT",
470
+ body: input,
471
+ onErrorContext: "saveAutoRecharge",
472
+ errorPrefix: "Failed to save auto-recharge"
473
+ }),
474
+ disableAutoRecharge: () => request(config, routeFor(config, "autoRecharge"), {
475
+ method: "DELETE",
476
+ onErrorContext: "disableAutoRecharge",
477
+ errorPrefix: "Failed to disable auto-recharge"
478
+ }),
436
479
  getUsage: () => request(config, routeFor(config, "getUsage"), {
437
480
  method: "GET",
438
481
  onErrorContext: "getUsage",
@@ -571,6 +614,42 @@ var enCopy = {
571
614
  creditEstimateExact: "= {credits} credits",
572
615
  creditEstimateApprox: "~ {credits} credits"
573
616
  },
617
+ autoRecharge: {
618
+ heading: "Auto recharge",
619
+ description: "Automatically top up so you never run out \u2014 recommended for production. You can turn this off anytime.",
620
+ settingsHeading: "Auto recharge settings",
621
+ setupTriggerLabel: "Set up auto-recharge",
622
+ modifyTriggerLabel: "Modify",
623
+ notConfiguredHint: "Automatic top-ups are off. Set up auto-recharge if you want credits added when your balance runs low.",
624
+ enableLabel: "Enable auto-recharge",
625
+ enableQuestion: "Would you like to set up automatic recharge?",
626
+ enableSentence: "Yes, automatically recharge my card when my credit balance falls below a threshold",
627
+ thresholdLabel: "When balance falls below",
628
+ thresholdAriaLabel: "Balance threshold",
629
+ fixedAmountLabel: "Add this amount",
630
+ fixedAmountAriaLabel: "Fixed top-up amount",
631
+ saveButton: "Save settings",
632
+ cancelButton: "Cancel",
633
+ disableButton: "Disable automatic top-up",
634
+ savedMessage: "Automatic top-up settings saved.",
635
+ disabledMessage: "Automatic top-ups disabled.",
636
+ setupRequiredMessage: "Confirm your card to activate automatic top-ups.",
637
+ setupHeading: "Authorize card",
638
+ setupDescription: "Authorize a card for automatic top-ups. You will not be charged now.",
639
+ setupSubmit: "Save card for auto-recharge",
640
+ setupProcessing: "Authorizing...",
641
+ setupAwaitingConfirmation: "Card authorized. Finishing activation \u2014 this can take a moment.",
642
+ setupAuthFailed: "Card authentication failed. Please try a different card.",
643
+ invalidThreshold: "Enter a valid balance threshold.",
644
+ thresholdTooLow: "Balance threshold must be greater than zero.",
645
+ minTopupAmount: "Top-up amount must be at least {amount}.",
646
+ topupBelowThreshold: "Top-up amount must be at least your balance threshold ({amount}).",
647
+ creditsPerRecharge: "\u2248 {credits} credits per recharge",
648
+ creditsPerRechargeApprox: "~ {credits} credits per recharge",
649
+ currencyPerRecharge: "\u2248 {amount} per recharge",
650
+ currencyPerRechargeApprox: "~ {amount} per recharge",
651
+ statusFailed: "Payment failed \u2014 update your card to resume"
652
+ },
574
653
  activationFlow: {
575
654
  heading: "Confirm your plan",
576
655
  activateButton: "Activate",
@@ -798,12 +877,18 @@ var SolvaPayProvider = ({ config, children }) => {
798
877
  const [displayExchangeRateValue, setDisplayExchangeRateValue] = (0, import_react2.useState)(
799
878
  initial?.balance?.displayExchangeRate ?? null
800
879
  );
880
+ const [displayBlockValue, setDisplayBlockValue] = (0, import_react2.useState)(
881
+ initial?.balance?.display ?? null
882
+ );
801
883
  const [balanceLoading, setBalanceLoading] = (0, import_react2.useState)(false);
802
884
  const balanceInFlightRef = (0, import_react2.useRef)(false);
803
885
  const balanceLoadedRef = (0, import_react2.useRef)(!!initial?.balance);
886
+ const creditsValueRef = (0, import_react2.useRef)(initial?.balance?.credits ?? null);
804
887
  const optimisticUntilRef = (0, import_react2.useRef)(0);
805
888
  const optimisticTimerRef = (0, import_react2.useRef)(null);
806
889
  const fetchBalanceRef = (0, import_react2.useRef)(null);
890
+ const reconcileRunningRef = (0, import_react2.useRef)(false);
891
+ const reconcilePollRef = (0, import_react2.useRef)(null);
807
892
  const inFlightRef = (0, import_react2.useRef)(null);
808
893
  const loadedCacheKeysRef = (0, import_react2.useRef)(
809
894
  new Set(initial?.customerRef ? [initial.customerRef] : [])
@@ -821,10 +906,12 @@ var SolvaPayProvider = ({ config, children }) => {
821
906
  const fetchBalanceImpl = (0, import_react2.useCallback)(async () => {
822
907
  if (optimisticUntilRef.current > Date.now()) return;
823
908
  if (!isAuthenticated && !internalCustomerRef) {
909
+ creditsValueRef.current = null;
824
910
  setCreditsValue(null);
825
911
  setDisplayCurrencyValue(null);
826
912
  setCreditsPerMinorUnitValue(null);
827
913
  setDisplayExchangeRateValue(null);
914
+ setDisplayBlockValue(null);
828
915
  setBalanceLoading(false);
829
916
  balanceLoadedRef.current = false;
830
917
  return;
@@ -841,10 +928,12 @@ var SolvaPayProvider = ({ config, children }) => {
841
928
  return;
842
929
  }
843
930
  const data = await transportRef.current.getBalance();
931
+ creditsValueRef.current = data.credits ?? null;
844
932
  setCreditsValue(data.credits ?? null);
845
933
  setDisplayCurrencyValue(data.displayCurrency ?? null);
846
934
  setCreditsPerMinorUnitValue(data.creditsPerMinorUnit ?? null);
847
935
  setDisplayExchangeRateValue(data.displayExchangeRate ?? null);
936
+ setDisplayBlockValue(data.display ?? null);
848
937
  balanceLoadedRef.current = true;
849
938
  } catch (error) {
850
939
  console.error("[SolvaPayProvider] Failed to fetch balance:", error);
@@ -859,18 +948,112 @@ var SolvaPayProvider = ({ config, children }) => {
859
948
  (0, import_react2.useEffect)(() => {
860
949
  return () => {
861
950
  if (optimisticTimerRef.current) clearTimeout(optimisticTimerRef.current);
951
+ reconcilePollRef.current = null;
952
+ reconcileRunningRef.current = false;
862
953
  };
863
954
  }, []);
864
955
  const OPTIMISTIC_GRACE_MS2 = 8e3;
865
- const adjustBalanceImpl = (0, import_react2.useCallback)((credits) => {
866
- setCreditsValue((prev) => (prev ?? 0) + credits);
867
- optimisticUntilRef.current = Date.now() + OPTIMISTIC_GRACE_MS2;
956
+ const DEBIT_GRACE_MS = 2e3;
957
+ const clearOptimisticGrace = (0, import_react2.useCallback)(() => {
958
+ optimisticUntilRef.current = 0;
959
+ if (optimisticTimerRef.current) {
960
+ clearTimeout(optimisticTimerRef.current);
961
+ optimisticTimerRef.current = null;
962
+ }
963
+ }, []);
964
+ const applyBalanceSnapshot = (0, import_react2.useCallback)(
965
+ (data) => {
966
+ creditsValueRef.current = data.credits ?? null;
967
+ setCreditsValue(data.credits ?? null);
968
+ setDisplayCurrencyValue(data.displayCurrency ?? null);
969
+ setCreditsPerMinorUnitValue(data.creditsPerMinorUnit ?? null);
970
+ setDisplayExchangeRateValue(data.displayExchangeRate ?? null);
971
+ setDisplayBlockValue(data.display ?? null);
972
+ balanceLoadedRef.current = true;
973
+ },
974
+ []
975
+ );
976
+ const reconcileBalanceIncreaseImpl = (0, import_react2.useCallback)(async () => {
977
+ if (!transportRef.current.getBalance) return;
978
+ const finishReconcilePoll = () => {
979
+ reconcilePollRef.current = null;
980
+ clearOptimisticGrace();
981
+ };
982
+ reconcileRunningRef.current = true;
983
+ try {
984
+ while (reconcilePollRef.current) {
985
+ const { baseline: activeBaseline, generation: activeGeneration } = reconcilePollRef.current;
986
+ const pollResult = await pollBalanceUntilIncreased(
987
+ async () => {
988
+ const data = await transportRef.current.getBalance();
989
+ return { credits: data.credits ?? 0 };
990
+ },
991
+ activeBaseline,
992
+ BALANCE_RECONCILE_DELAYS_MS
993
+ );
994
+ const pollState = reconcilePollRef.current;
995
+ if (!pollState || pollState.generation !== activeGeneration) {
996
+ continue;
997
+ }
998
+ if (!pollResult) {
999
+ finishReconcilePoll();
1000
+ break;
1001
+ }
1002
+ try {
1003
+ const data = await transportRef.current.getBalance();
1004
+ applyBalanceSnapshot(data);
1005
+ pollState.pending -= 1;
1006
+ if (pollState.pending > 0) {
1007
+ pollState.baseline = data.credits ?? 0;
1008
+ continue;
1009
+ }
1010
+ } catch (error) {
1011
+ console.error("[SolvaPayProvider] Failed to reconcile balance after auto-recharge:", error);
1012
+ }
1013
+ finishReconcilePoll();
1014
+ break;
1015
+ }
1016
+ } finally {
1017
+ reconcileRunningRef.current = false;
1018
+ }
1019
+ }, [applyBalanceSnapshot, clearOptimisticGrace]);
1020
+ const scheduleGraceRefetch = (0, import_react2.useCallback)((graceMs) => {
1021
+ optimisticUntilRef.current = Date.now() + graceMs;
868
1022
  if (optimisticTimerRef.current) clearTimeout(optimisticTimerRef.current);
869
1023
  optimisticTimerRef.current = setTimeout(() => {
870
1024
  optimisticUntilRef.current = 0;
871
1025
  fetchBalanceRef.current?.();
872
- }, OPTIMISTIC_GRACE_MS2);
1026
+ }, graceMs);
873
1027
  }, []);
1028
+ const adjustBalanceImpl = (0, import_react2.useCallback)(
1029
+ (credits) => {
1030
+ const nextCredits = (creditsValueRef.current ?? 0) + credits;
1031
+ creditsValueRef.current = nextCredits;
1032
+ setCreditsValue(nextCredits);
1033
+ if (credits >= 0) {
1034
+ scheduleGraceRefetch(OPTIMISTIC_GRACE_MS2);
1035
+ } else {
1036
+ scheduleGraceRefetch(DEBIT_GRACE_MS);
1037
+ }
1038
+ },
1039
+ [scheduleGraceRefetch]
1040
+ );
1041
+ const reconcileAfterUsageDebitImpl = (0, import_react2.useCallback)(
1042
+ (opts) => {
1043
+ if (opts?.expectIncrease !== true) {
1044
+ return;
1045
+ }
1046
+ const nextCredits = creditsValueRef.current ?? 0;
1047
+ const generation = (reconcilePollRef.current?.generation ?? 0) + 1;
1048
+ const pending = (reconcilePollRef.current?.pending ?? 0) + 1;
1049
+ reconcilePollRef.current = { baseline: nextCredits, generation, pending };
1050
+ scheduleGraceRefetch(BALANCE_RECONCILE_GRACE_MS);
1051
+ if (!reconcileRunningRef.current) {
1052
+ void reconcileBalanceIncreaseImpl();
1053
+ }
1054
+ },
1055
+ [reconcileBalanceIncreaseImpl, scheduleGraceRefetch]
1056
+ );
874
1057
  const createPayment = (0, import_react2.useCallback)(
875
1058
  (params) => transportRef.current.createPayment(params),
876
1059
  []
@@ -1042,6 +1225,7 @@ var SolvaPayProvider = ({ config, children }) => {
1042
1225
  setDisplayCurrencyValue(next.balance?.displayCurrency ?? null);
1043
1226
  setCreditsPerMinorUnitValue(next.balance?.creditsPerMinorUnit ?? null);
1044
1227
  setDisplayExchangeRateValue(next.balance?.displayExchangeRate ?? null);
1228
+ setDisplayBlockValue(next.balance?.display ?? null);
1045
1229
  balanceLoadedRef.current = !!next.balance;
1046
1230
  }, []);
1047
1231
  (0, import_react2.useEffect)(() => {
@@ -1146,8 +1330,10 @@ var SolvaPayProvider = ({ config, children }) => {
1146
1330
  displayCurrency: displayCurrencyValue,
1147
1331
  creditsPerMinorUnit: creditsPerMinorUnitValue,
1148
1332
  displayExchangeRate: displayExchangeRateValue,
1333
+ display: displayBlockValue,
1149
1334
  refetch: fetchBalanceImpl,
1150
- adjustBalance: adjustBalanceImpl
1335
+ adjustBalance: adjustBalanceImpl,
1336
+ reconcileAfterUsageDebit: reconcileAfterUsageDebitImpl
1151
1337
  }),
1152
1338
  [
1153
1339
  balanceLoading,
@@ -1155,8 +1341,10 @@ var SolvaPayProvider = ({ config, children }) => {
1155
1341
  displayCurrencyValue,
1156
1342
  creditsPerMinorUnitValue,
1157
1343
  displayExchangeRateValue,
1344
+ displayBlockValue,
1158
1345
  fetchBalanceImpl,
1159
- adjustBalanceImpl
1346
+ adjustBalanceImpl,
1347
+ reconcileAfterUsageDebitImpl
1160
1348
  ]
1161
1349
  );
1162
1350
  const contextValue = (0, import_react2.useMemo)(
@@ -1401,7 +1589,7 @@ function withPaymentElementDefaults(options) {
1401
1589
 
1402
1590
  // src/utils/errors.ts
1403
1591
  var DOCS_BASE_URL = "https://solvapay.com/docs";
1404
- var SolvaPayError = class extends Error {
1592
+ var SolvaPayError2 = class extends Error {
1405
1593
  code;
1406
1594
  docsUrl;
1407
1595
  constructor(code, message, docsUrl) {
@@ -1411,7 +1599,7 @@ var SolvaPayError = class extends Error {
1411
1599
  this.docsUrl = docsUrl;
1412
1600
  }
1413
1601
  };
1414
- var MissingProviderError = class extends SolvaPayError {
1602
+ var MissingProviderError = class extends SolvaPayError2 {
1415
1603
  constructor(primitiveName) {
1416
1604
  const docsUrl = `${DOCS_BASE_URL}/troubleshooting/missing-provider`;
1417
1605
  super(
@@ -1422,7 +1610,7 @@ var MissingProviderError = class extends SolvaPayError {
1422
1610
  this.name = "MissingProviderError";
1423
1611
  }
1424
1612
  };
1425
- var MissingProductRefError = class extends SolvaPayError {
1613
+ var MissingProductRefError = class extends SolvaPayError2 {
1426
1614
  constructor(primitiveName) {
1427
1615
  const docsUrl = `${DOCS_BASE_URL}/primitives/product-ref`;
1428
1616
  super(
@@ -3674,7 +3862,7 @@ function getStripeCacheKey2(publishableKey, accountId) {
3674
3862
  return accountId ? `${publishableKey}:${accountId}` : publishableKey;
3675
3863
  }
3676
3864
  function useTopup(options) {
3677
- const { amount, currency } = options;
3865
+ const { amount, currency, autoRecharge } = options;
3678
3866
  const { createTopupPayment, customerRef, updateCustomerRef } = useSolvaPay();
3679
3867
  const [loading, setLoading] = (0, import_react20.useState)(false);
3680
3868
  const [error, setError] = (0, import_react20.useState)(null);
@@ -3693,7 +3881,7 @@ function useTopup(options) {
3693
3881
  setLoading(true);
3694
3882
  setError(null);
3695
3883
  try {
3696
- const result = await createTopupPayment({ amount, currency });
3884
+ const result = await createTopupPayment({ amount, currency, autoRecharge });
3697
3885
  if (!result || typeof result !== "object") {
3698
3886
  throw new Error("Invalid topup payment intent response from server");
3699
3887
  }
@@ -3725,7 +3913,7 @@ function useTopup(options) {
3725
3913
  setLoading(false);
3726
3914
  isStartingRef.current = false;
3727
3915
  }
3728
- }, [amount, currency, createTopupPayment, customerRef, updateCustomerRef, loading]);
3916
+ }, [amount, currency, autoRecharge, createTopupPayment, customerRef, updateCustomerRef, loading]);
3729
3917
  const reset = (0, import_react20.useCallback)(() => {
3730
3918
  isStartingRef.current = false;
3731
3919
  setLoading(false);
@@ -3757,6 +3945,7 @@ var Root4 = (0, import_react21.forwardRef)(function TopupFormRoot(props, forward
3757
3945
  const {
3758
3946
  amount,
3759
3947
  currency,
3948
+ autoRecharge,
3760
3949
  onSuccess,
3761
3950
  onError,
3762
3951
  returnUrl,
@@ -3780,7 +3969,8 @@ var Root4 = (0, import_react21.forwardRef)(function TopupFormRoot(props, forward
3780
3969
  stripePromise
3781
3970
  } = useTopup({
3782
3971
  amount,
3783
- currency
3972
+ currency,
3973
+ autoRecharge
3784
3974
  });
3785
3975
  const hasInitializedRef = (0, import_react21.useRef)(false);
3786
3976
  const hasAmount = amount > 0;
@@ -4343,7 +4533,7 @@ var StripePaymentFormWrapper = ({
4343
4533
 
4344
4534
  // src/primitives/BalanceBadge.tsx
4345
4535
  var import_react25 = require("react");
4346
- var import_core = require("@solvapay/core");
4536
+ var import_core2 = require("@solvapay/core");
4347
4537
  var import_jsx_runtime19 = require("react/jsx-runtime");
4348
4538
  var BalanceBadge = (0, import_react25.forwardRef)(function BalanceBadge2({ asChild, numberOnly, lowThreshold = 10, children, ...rest }, forwardedRef) {
4349
4539
  const solva = (0, import_react25.useContext)(SolvaPayContext);
@@ -4372,14 +4562,14 @@ var BalanceBadge = (0, import_react25.forwardRef)(function BalanceBadge2({ asChi
4372
4562
  const formattedCredits = new Intl.NumberFormat(locale).format(credits);
4373
4563
  let currencyEquivalent = "";
4374
4564
  if (!numberOnly && displayCurrency && creditsPerMinorUnit) {
4375
- const displayMinor = (0, import_core.creditsToDisplayMinorUnits)({
4565
+ const displayMinor = (0, import_core2.creditsToDisplayMinorUnits)({
4376
4566
  credits,
4377
4567
  creditsPerMinorUnit,
4378
4568
  displayExchangeRate: displayExchangeRate ?? 1,
4379
4569
  displayCurrency
4380
4570
  });
4381
4571
  if (displayMinor !== null) {
4382
- const minorPerMajor = (0, import_core.minorUnitsPerMajor)(displayCurrency);
4572
+ const minorPerMajor = (0, import_core2.minorUnitsPerMajor)(displayCurrency);
4383
4573
  const formatted = new Intl.NumberFormat(locale, {
4384
4574
  style: "currency",
4385
4575
  currency: displayCurrency,
@@ -6816,177 +7006,1837 @@ var CurrentPlanCard = ({
6816
7006
  );
6817
7007
  };
6818
7008
 
6819
- // src/hooks/useLimits.ts
7009
+ // src/primitives/AutoRecharge.tsx
7010
+ var import_react42 = require("react");
7011
+ var import_react_dom = require("react-dom");
7012
+ var import_react_stripe_js4 = require("@stripe/react-stripe-js");
7013
+ var import_stripe_js3 = require("@stripe/stripe-js");
7014
+
7015
+ // src/hooks/useAutoRecharge.ts
6820
7016
  var import_react41 = require("react");
6821
- var CACHE_TTL_MS = 1e4;
6822
- var OPTIMISTIC_GRACE_MS = 8e3;
6823
- var limitsCache = /* @__PURE__ */ new Map();
6824
- function cacheKey(customerRef, productRef, meterName) {
6825
- return `${customerRef ?? "anonymous"}:${productRef}:${meterName}`;
7017
+
7018
+ // src/hooks/autoRechargeCache.ts
7019
+ var autoRechargeCache = /* @__PURE__ */ new Map();
7020
+ var CACHE_DURATION6 = 5 * 60 * 1e3;
7021
+ function autoRechargeCacheKeyFor(config) {
7022
+ return createTransportCacheKey(config, config?.api?.autoRecharge || "/api/auto-recharge");
6826
7023
  }
6827
- function useLimits(options) {
6828
- const { productRef, meterName: rawMeterName, enabled = true } = options;
6829
- const meterName = rawMeterName || "requests";
6830
- const transport = useTransport();
6831
- const { customerRef } = useCustomer();
6832
- const { purchase } = useSolvaPay();
6833
- const currentKey = !productRef || !enabled ? null : cacheKey(customerRef, productRef, meterName);
6834
- const [data, setData] = (0, import_react41.useState)(() => {
6835
- if (!currentKey) return null;
6836
- const cached = limitsCache.get(currentKey);
6837
- if (!cached || Date.now() - cached.timestamp >= CACHE_TTL_MS) return null;
6838
- return cached.data;
6839
- });
7024
+
7025
+ // src/hooks/useAutoRecharge.ts
7026
+ function mergeAutoRechargeConfig(config, display) {
7027
+ return display ? { ...config, display } : config;
7028
+ }
7029
+ async function fetchAutoRecharge(config) {
7030
+ const transport = config?.transport ?? createHttpTransport(config);
7031
+ if (!transport.getAutoRecharge) return null;
7032
+ const response = await transport.getAutoRecharge();
7033
+ if (!response.config) return null;
7034
+ return mergeAutoRechargeConfig(response.config, response.display);
7035
+ }
7036
+ function useAutoRecharge() {
7037
+ const { _config } = useSolvaPay();
7038
+ const key = autoRechargeCacheKeyFor(_config);
7039
+ const [config, setConfig] = (0, import_react41.useState)(
7040
+ () => autoRechargeCache.get(key)?.config ?? null
7041
+ );
6840
7042
  const [loading, setLoading] = (0, import_react41.useState)(() => {
6841
- if (!currentKey) return false;
6842
- const cached = limitsCache.get(currentKey);
6843
- if (!cached) return true;
6844
- if (cached.promise) return true;
6845
- if (Date.now() - cached.timestamp >= CACHE_TTL_MS) return true;
6846
- return false;
7043
+ const cached = autoRechargeCache.get(key);
7044
+ return !cached || !cached.config && !cached.promise;
6847
7045
  });
7046
+ const [saving, setSaving] = (0, import_react41.useState)(false);
7047
+ const [disabling, setDisabling] = (0, import_react41.useState)(false);
6848
7048
  const [error, setError] = (0, import_react41.useState)(null);
6849
- const [trackedKey, setTrackedKey] = (0, import_react41.useState)(currentKey);
6850
- if (trackedKey !== currentKey) {
6851
- setTrackedKey(currentKey);
6852
- setData(null);
6853
- }
6854
- const optimisticTimerRef = (0, import_react41.useRef)(null);
6855
- (0, import_react41.useEffect)(() => {
6856
- return () => {
6857
- if (optimisticTimerRef.current) clearTimeout(optimisticTimerRef.current);
6858
- };
6859
- }, []);
6860
- const attachToFetch = (0, import_react41.useCallback)(
6861
- async (promise) => {
7049
+ const requestSeq = (0, import_react41.useRef)(0);
7050
+ const load = (0, import_react41.useCallback)(
7051
+ async (force = false) => {
7052
+ const seq = requestSeq.current;
7053
+ const cached = autoRechargeCache.get(key);
7054
+ const now = Date.now();
7055
+ if (!force && cached?.config && now - cached.timestamp < CACHE_DURATION6) {
7056
+ if (seq !== requestSeq.current) return;
7057
+ setConfig(cached.config);
7058
+ setLoading(false);
7059
+ setError(null);
7060
+ return;
7061
+ }
7062
+ if (!force && cached?.promise) {
7063
+ setLoading(true);
7064
+ try {
7065
+ const value = await cached.promise;
7066
+ if (seq !== requestSeq.current) return;
7067
+ setConfig(value);
7068
+ setError(null);
7069
+ } catch (caught) {
7070
+ if (seq !== requestSeq.current) return;
7071
+ setError(caught instanceof Error ? caught : new Error(String(caught)));
7072
+ } finally {
7073
+ if (seq === requestSeq.current) {
7074
+ setLoading(false);
7075
+ }
7076
+ }
7077
+ return;
7078
+ }
6862
7079
  setLoading(true);
7080
+ setError(null);
7081
+ const promise = fetchAutoRecharge(_config);
7082
+ autoRechargeCache.set(key, {
7083
+ config: cached?.config ?? null,
7084
+ promise,
7085
+ timestamp: now
7086
+ });
6863
7087
  try {
6864
- const fresh = await promise;
6865
- setData(fresh);
6866
- setError(null);
6867
- return fresh;
6868
- } catch (err) {
6869
- setError(err instanceof Error ? err : new Error("Failed to fetch limits"));
6870
- return null;
7088
+ const value = await promise;
7089
+ if (seq !== requestSeq.current) return;
7090
+ autoRechargeCache.set(key, { config: value, promise: null, timestamp: Date.now() });
7091
+ setConfig(value);
7092
+ } catch (caught) {
7093
+ if (seq !== requestSeq.current) return;
7094
+ const err = caught instanceof Error ? caught : new Error(String(caught));
7095
+ autoRechargeCache.set(key, { config: null, promise: null, timestamp: Date.now() });
7096
+ setError(err);
6871
7097
  } finally {
6872
- setLoading(false);
7098
+ if (seq === requestSeq.current) {
7099
+ setLoading(false);
7100
+ }
6873
7101
  }
6874
7102
  },
6875
- []
7103
+ [_config, key]
6876
7104
  );
6877
- const fetchLimits = (0, import_react41.useCallback)(
6878
- async (force) => {
6879
- if (!productRef || !enabled || !transport.getLimits) {
6880
- setLoading(false);
6881
- return;
6882
- }
6883
- const key = cacheKey(customerRef, productRef, meterName);
6884
- const cached = limitsCache.get(key);
6885
- const now = Date.now();
6886
- if (cached?.promise) {
6887
- await attachToFetch(cached.promise);
6888
- return;
6889
- }
6890
- if (!force && cached?.data && now - cached.timestamp < CACHE_TTL_MS) {
6891
- setData(cached.data);
6892
- setLoading(false);
6893
- setError(null);
6894
- return;
7105
+ (0, import_react41.useEffect)(() => {
7106
+ void load();
7107
+ }, [load]);
7108
+ const refresh = (0, import_react41.useCallback)(
7109
+ async (force = true) => {
7110
+ await load(force);
7111
+ },
7112
+ [load]
7113
+ );
7114
+ const save = (0, import_react41.useCallback)(
7115
+ async (input) => {
7116
+ const transport = _config?.transport ?? createHttpTransport(_config);
7117
+ if (!transport.saveAutoRecharge) {
7118
+ throw new Error("saveAutoRecharge is not available on this transport");
6895
7119
  }
6896
- const promise = transport.getLimits({ productRef, meterName });
6897
- limitsCache.set(key, { data: cached?.data ?? null, timestamp: now, promise });
6898
- const fresh = await attachToFetch(promise);
6899
- if (fresh !== null) {
6900
- limitsCache.set(key, { data: fresh, timestamp: Date.now(), promise: null });
6901
- } else {
6902
- limitsCache.delete(key);
7120
+ setSaving(true);
7121
+ setError(null);
7122
+ const seq = ++requestSeq.current;
7123
+ try {
7124
+ const result = await transport.saveAutoRecharge(input);
7125
+ if (seq !== requestSeq.current) return result;
7126
+ const nextConfig = mergeAutoRechargeConfig(result.config, result.display);
7127
+ autoRechargeCache.set(key, {
7128
+ config: nextConfig,
7129
+ promise: null,
7130
+ timestamp: Date.now()
7131
+ });
7132
+ setConfig(nextConfig);
7133
+ return result;
7134
+ } catch (caught) {
7135
+ const err = caught instanceof Error ? caught : new Error(String(caught));
7136
+ setError(err);
7137
+ throw err;
7138
+ } finally {
7139
+ setSaving(false);
6903
7140
  }
6904
7141
  },
6905
- [transport, customerRef, productRef, meterName, enabled, attachToFetch]
7142
+ [_config, key]
6906
7143
  );
6907
- (0, import_react41.useEffect)(() => {
6908
- fetchLimits(false);
6909
- }, [fetchLimits]);
6910
- const prevPurchasesRef = (0, import_react41.useRef)(null);
6911
- (0, import_react41.useEffect)(() => {
6912
- if (prevPurchasesRef.current !== null && prevPurchasesRef.current !== purchase.purchases) {
6913
- fetchLimits(true).catch(() => {
6914
- });
7144
+ const disable = (0, import_react41.useCallback)(async () => {
7145
+ const transport = _config?.transport ?? createHttpTransport(_config);
7146
+ if (!transport.disableAutoRecharge) {
7147
+ throw new Error("disableAutoRecharge is not available on this transport");
6915
7148
  }
6916
- prevPurchasesRef.current = purchase.purchases;
6917
- }, [purchase.purchases, fetchLimits]);
6918
- const refetch = (0, import_react41.useCallback)(() => fetchLimits(true), [fetchLimits]);
6919
- const adjustRemaining = (0, import_react41.useCallback)(
6920
- (delta) => {
6921
- if (!productRef || !enabled) return;
6922
- const key = cacheKey(customerRef, productRef, meterName);
6923
- setData((prev) => {
6924
- const cached = limitsCache.get(key);
6925
- const baseline = prev ?? cached?.data ?? null;
6926
- if (!baseline) return prev;
6927
- const next = {
6928
- ...baseline,
6929
- remaining: Math.max(0, baseline.remaining + delta)
6930
- // Don't optimistically flip `withinLimits` — paywall gating
6931
- // can hinge on factors beyond `remaining > 0`
6932
- // (activationRequired, etc.). Let the trailing refetch
6933
- // confirm.
6934
- };
6935
- limitsCache.set(key, {
6936
- data: next,
6937
- timestamp: Date.now(),
6938
- promise: cached?.promise ?? null
7149
+ setDisabling(true);
7150
+ setError(null);
7151
+ const seq = ++requestSeq.current;
7152
+ try {
7153
+ const result = await transport.disableAutoRecharge();
7154
+ if (seq === requestSeq.current) {
7155
+ setConfig((current) => {
7156
+ const disabledConfig = current ? { ...current, enabled: false } : null;
7157
+ autoRechargeCache.set(key, {
7158
+ config: disabledConfig,
7159
+ promise: null,
7160
+ timestamp: Date.now()
7161
+ });
7162
+ return disabledConfig;
6939
7163
  });
6940
- return next;
6941
- });
6942
- if (optimisticTimerRef.current) clearTimeout(optimisticTimerRef.current);
6943
- optimisticTimerRef.current = setTimeout(() => {
6944
- optimisticTimerRef.current = null;
6945
- fetchLimits(true).catch(() => {
7164
+ await refresh(true);
7165
+ setConfig((current) => {
7166
+ const disabledConfig = current ? { ...current, enabled: false } : null;
7167
+ autoRechargeCache.set(key, {
7168
+ config: disabledConfig,
7169
+ promise: null,
7170
+ timestamp: Date.now()
7171
+ });
7172
+ return disabledConfig;
6946
7173
  });
6947
- }, OPTIMISTIC_GRACE_MS);
6948
- },
6949
- [customerRef, productRef, meterName, enabled, fetchLimits]
6950
- );
6951
- return {
6952
- remaining: data?.remaining ?? null,
6953
- withinLimits: data?.withinLimits ?? null,
6954
- meterName: data?.meterName ?? null,
6955
- activationRequired: data?.activationRequired ?? null,
6956
- loading,
6957
- error,
6958
- refetch,
6959
- adjustRemaining
6960
- };
7174
+ }
7175
+ return result;
7176
+ } catch (caught) {
7177
+ const err = caught instanceof Error ? caught : new Error(String(caught));
7178
+ setError(err);
7179
+ throw err;
7180
+ } finally {
7181
+ setDisabling(false);
7182
+ }
7183
+ }, [_config, key, refresh]);
7184
+ return { config, loading, saving, disabling, error, refresh, save, disable };
6961
7185
  }
6962
7186
 
6963
- // src/hooks/useAutoActivateFreePlan.ts
6964
- var import_react42 = require("react");
6965
- function useAutoActivateFreePlan(options) {
6966
- const { productRef, enabled = true, onActivated } = options;
6967
- const { customerRef } = useCustomer();
6968
- const { activationRequired, refetch: refetchLimits } = useLimits({
6969
- productRef,
6970
- enabled
7187
+ // src/primitives/autoRechargeActivation.ts
7188
+ var defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
7189
+ async function waitForAutoRechargeActivation({
7190
+ refresh,
7191
+ getStatus,
7192
+ attempts = 5,
7193
+ delayMs = 800,
7194
+ sleep = defaultSleep
7195
+ }) {
7196
+ for (let attempt = 0; attempt < attempts; attempt++) {
7197
+ await refresh(true);
7198
+ if (getStatus() === "active") return true;
7199
+ if (attempt < attempts - 1) await sleep(delayMs);
7200
+ }
7201
+ return getStatus() === "active";
7202
+ }
7203
+
7204
+ // src/primitives/setupIntentReturn.ts
7205
+ var SETUP_INTENT_PARAMS = ["setup_intent", "setup_intent_client_secret", "redirect_status"];
7206
+ function readSetupIntentClientSecret(search) {
7207
+ return new URLSearchParams(search).get("setup_intent_client_secret");
7208
+ }
7209
+ function stripSetupIntentParams() {
7210
+ if (typeof window === "undefined") return;
7211
+ const url = new URL(window.location.href);
7212
+ let changed = false;
7213
+ for (const param of SETUP_INTENT_PARAMS) {
7214
+ if (url.searchParams.has(param)) {
7215
+ url.searchParams.delete(param);
7216
+ changed = true;
7217
+ }
7218
+ }
7219
+ if (!changed) return;
7220
+ const query = url.searchParams.toString();
7221
+ window.history.replaceState({}, "", `${url.pathname}${query ? `?${query}` : ""}${url.hash}`);
7222
+ }
7223
+
7224
+ // src/utils/credit-estimation.ts
7225
+ var import_core3 = require("@solvapay/core");
7226
+ function estimateCredits(resolvedAmountMajor, currency, creditsPerMinorUnit, displayExchangeRate) {
7227
+ if (resolvedAmountMajor == null || resolvedAmountMajor <= 0) return null;
7228
+ if (creditsPerMinorUnit == null || creditsPerMinorUnit <= 0) return null;
7229
+ const rate = displayExchangeRate ?? 1;
7230
+ const resolvedAmountMinor = Math.round(resolvedAmountMajor * getMinorUnitsPerMajor(currency));
7231
+ return Math.round(resolvedAmountMinor / rate * creditsPerMinorUnit);
7232
+ }
7233
+ function estimateCurrencyMajorFromCredits(credits, currency, creditsPerMinorUnit, displayExchangeRate) {
7234
+ if (credits == null || credits <= 0) return null;
7235
+ if (creditsPerMinorUnit == null || creditsPerMinorUnit <= 0) return null;
7236
+ const rate = displayExchangeRate ?? 1;
7237
+ const displayMinor = (0, import_core3.creditsToDisplayMinorUnits)({
7238
+ credits,
7239
+ creditsPerMinorUnit,
7240
+ displayExchangeRate: rate,
7241
+ displayCurrency: currency
6971
7242
  });
6972
- const { plans } = usePlans({ productRef });
6973
- const { activate, error: activationError } = useActivation();
6974
- const freePlan = (0, import_react42.useMemo)(
6975
- () => plans.find((p) => p.requiresPayment === false && (p.freeUnits ?? 0) > 0),
6976
- [plans]
6977
- );
6978
- const attemptedKeyRef = (0, import_react42.useRef)(null);
6979
- const [activated, setActivated] = (0, import_react42.useState)(false);
6980
- const onActivatedRef = (0, import_react42.useRef)(onActivated);
6981
- (0, import_react42.useEffect)(() => {
6982
- onActivatedRef.current = onActivated;
6983
- }, [onActivated]);
6984
- (0, import_react42.useEffect)(() => {
6985
- attemptedKeyRef.current = null;
6986
- setActivated(false);
6987
- }, [customerRef, productRef]);
6988
- const shouldActivate = enabled && activationRequired === true && Boolean(productRef) && Boolean(freePlan?.reference);
7243
+ if (displayMinor === null) return null;
7244
+ return displayMinor / getMinorUnitsPerMajor(currency);
7245
+ }
7246
+
7247
+ // src/helpers/stripe-minimums.ts
7248
+ var STRIPE_MINIMUM_MINOR = {
7249
+ USD: 50,
7250
+ EUR: 50,
7251
+ GBP: 30,
7252
+ SEK: 300,
7253
+ NOK: 300,
7254
+ DKK: 250,
7255
+ CHF: 50,
7256
+ CAD: 50,
7257
+ AUD: 50,
7258
+ JPY: 50,
7259
+ KRW: 500
7260
+ };
7261
+ var DEFAULT_MINIMUM_MINOR = 50;
7262
+ function getStripeMinimumMinor(currency) {
7263
+ return STRIPE_MINIMUM_MINOR[currency.toUpperCase()] ?? DEFAULT_MINIMUM_MINOR;
7264
+ }
7265
+
7266
+ // src/helpers/auto-recharge-form.ts
7267
+ var DEFAULT_VALIDATION_MESSAGES = {
7268
+ invalidThreshold: "Enter a valid balance threshold.",
7269
+ thresholdTooLow: "Balance threshold must be greater than zero.",
7270
+ minTopupAmount: "Top-up amount must be at least {amount}.",
7271
+ topupBelowThreshold: "Top-up amount must be at least your balance threshold ({amount})."
7272
+ };
7273
+ function amountAnchors(thresholdValue, topupValue, unit = "currency") {
7274
+ return {
7275
+ thresholdBaseValue: thresholdValue,
7276
+ thresholdBaseUnit: unit,
7277
+ topupBaseValue: topupValue,
7278
+ topupBaseUnit: unit
7279
+ };
7280
+ }
7281
+ function createDefaultAutoRechargeForm(currency, defaultTopupMajor, defaultThresholdMajor) {
7282
+ const topup = defaultTopupMajor != null && defaultTopupMajor > 0 ? String(defaultTopupMajor) : "10";
7283
+ const threshold = defaultThresholdMajor != null && defaultThresholdMajor >= 0 ? String(defaultThresholdMajor) : "5";
7284
+ return {
7285
+ enabled: false,
7286
+ thresholdAmountMajor: threshold,
7287
+ thresholdUnit: "currency",
7288
+ topupAmountMajor: topup,
7289
+ topupUnit: "currency",
7290
+ ...amountAnchors(threshold, topup, "currency")
7291
+ };
7292
+ }
7293
+ function parsePositiveNumber(value) {
7294
+ const trimmed = value.trim();
7295
+ if (trimmed.length === 0) return null;
7296
+ const parsed = Number(trimmed);
7297
+ if (!Number.isFinite(parsed) || parsed <= 0) return null;
7298
+ return parsed;
7299
+ }
7300
+ function parseNonNegativeNumber(value) {
7301
+ const trimmed = value.trim();
7302
+ if (trimmed.length === 0) return null;
7303
+ const parsed = Number(trimmed);
7304
+ if (!Number.isFinite(parsed) || parsed < 0) return null;
7305
+ return parsed;
7306
+ }
7307
+ function validateAutoRechargeForm(form, currency, conversion, messages = DEFAULT_VALIDATION_MESSAGES) {
7308
+ if (!form.enabled) {
7309
+ return {
7310
+ ok: true,
7311
+ payload: {
7312
+ enabled: false,
7313
+ triggerType: "balance",
7314
+ currency: currency.toUpperCase()
7315
+ }
7316
+ };
7317
+ }
7318
+ const payload = {
7319
+ enabled: true,
7320
+ triggerType: "balance",
7321
+ currency: currency.toUpperCase()
7322
+ };
7323
+ const minorPerMajor = getMinorUnitsPerMajor(currency);
7324
+ const minMinor = getStripeMinimumMinor(currency);
7325
+ const thresholdRaw = parseNonNegativeNumber(form.thresholdAmountMajor);
7326
+ if (thresholdRaw == null) {
7327
+ return { ok: false, error: messages.invalidThreshold };
7328
+ }
7329
+ if (form.thresholdUnit === "credits") {
7330
+ const major = estimateCurrencyMajorFromCredits(
7331
+ thresholdRaw,
7332
+ currency,
7333
+ conversion?.creditsPerMinorUnit,
7334
+ conversion?.displayExchangeRate
7335
+ );
7336
+ if (major == null) {
7337
+ return { ok: false, error: messages.invalidThreshold };
7338
+ }
7339
+ payload.thresholdAmountMajor = major;
7340
+ } else {
7341
+ payload.thresholdAmountMajor = thresholdRaw;
7342
+ }
7343
+ if (payload.thresholdAmountMajor == null || payload.thresholdAmountMajor <= 0) {
7344
+ return { ok: false, error: messages.thresholdTooLow };
7345
+ }
7346
+ const amountRaw = parsePositiveNumber(form.topupAmountMajor);
7347
+ if (amountRaw == null) {
7348
+ return {
7349
+ ok: false,
7350
+ error: interpolate(messages.minTopupAmount, {
7351
+ amount: formatPrice(minMinor, currency, { free: "" })
7352
+ })
7353
+ };
7354
+ }
7355
+ const amountMajor = form.topupUnit === "credits" ? estimateCurrencyMajorFromCredits(
7356
+ amountRaw,
7357
+ currency,
7358
+ conversion?.creditsPerMinorUnit,
7359
+ conversion?.displayExchangeRate
7360
+ ) : amountRaw;
7361
+ if (amountMajor == null || Math.round(amountMajor * minorPerMajor) < minMinor) {
7362
+ return {
7363
+ ok: false,
7364
+ error: interpolate(messages.minTopupAmount, {
7365
+ amount: formatPrice(minMinor, currency, { free: "" })
7366
+ })
7367
+ };
7368
+ }
7369
+ payload.topupAmountMajor = amountMajor;
7370
+ if (amountMajor < payload.thresholdAmountMajor) {
7371
+ return {
7372
+ ok: false,
7373
+ error: interpolate(messages.topupBelowThreshold, {
7374
+ amount: formatPrice(
7375
+ Math.round(payload.thresholdAmountMajor * minorPerMajor),
7376
+ currency,
7377
+ { free: "" }
7378
+ )
7379
+ })
7380
+ };
7381
+ }
7382
+ return { ok: true, payload };
7383
+ }
7384
+ function triggerAmountMajorFromConfig(config) {
7385
+ const topupCurrency = config.topup.currency.toUpperCase();
7386
+ const minorPerMajor = getMinorUnitsPerMajor(topupCurrency);
7387
+ const { thresholdAmountMinor } = config.trigger;
7388
+ if (!Number.isFinite(thresholdAmountMinor) || thresholdAmountMinor < 0) {
7389
+ return null;
7390
+ }
7391
+ return thresholdAmountMinor / minorPerMajor;
7392
+ }
7393
+ function configToAutoRechargeInput(config, options) {
7394
+ if (!config.enabled) return null;
7395
+ const display = options?.display ?? config.display;
7396
+ const currency = (display?.currency ?? config.topup.currency ?? options?.currency ?? "USD").toUpperCase();
7397
+ if (display?.thresholdAmountMajor != null && display.topupAmountMajor != null) {
7398
+ return {
7399
+ enabled: true,
7400
+ triggerType: "balance",
7401
+ thresholdAmountMajor: display.thresholdAmountMajor,
7402
+ topupAmountMajor: display.topupAmountMajor,
7403
+ currency
7404
+ };
7405
+ }
7406
+ const thresholdMajor = triggerAmountMajorFromConfig(config);
7407
+ const topupAmountMajor = config.topup.amountMinor / getMinorUnitsPerMajor(currency);
7408
+ if (thresholdMajor == null || !Number.isFinite(topupAmountMajor) || topupAmountMajor <= 0) {
7409
+ return null;
7410
+ }
7411
+ return {
7412
+ enabled: true,
7413
+ triggerType: "balance",
7414
+ thresholdAmountMajor: Math.max(0, thresholdMajor),
7415
+ topupAmountMajor,
7416
+ currency
7417
+ };
7418
+ }
7419
+ function configToForm(config, currency) {
7420
+ const base = createDefaultAutoRechargeForm(currency);
7421
+ const display = config.display;
7422
+ if (display?.thresholdAmountMajor != null && display.topupAmountMajor != null) {
7423
+ const thresholdStr2 = String(Math.max(0, display.thresholdAmountMajor));
7424
+ const topupStr2 = String(display.topupAmountMajor);
7425
+ return {
7426
+ ...base,
7427
+ enabled: config.enabled,
7428
+ thresholdAmountMajor: thresholdStr2,
7429
+ topupAmountMajor: topupStr2,
7430
+ ...amountAnchors(thresholdStr2, topupStr2, "currency")
7431
+ };
7432
+ }
7433
+ const thresholdMajor = triggerAmountMajorFromConfig(config);
7434
+ const thresholdStr = thresholdMajor != null ? String(Math.max(0, thresholdMajor)) : "0";
7435
+ const topupStr = String(config.topup.amountMinor / getMinorUnitsPerMajor(currency));
7436
+ return {
7437
+ ...base,
7438
+ enabled: config.enabled,
7439
+ thresholdAmountMajor: thresholdStr,
7440
+ topupAmountMajor: topupStr,
7441
+ ...amountAnchors(thresholdStr, topupStr, "currency")
7442
+ };
7443
+ }
7444
+ function formatAmountWithUnit(value, unit, currency) {
7445
+ const num = Number(value);
7446
+ if (!value || !Number.isFinite(num)) return "\u2014";
7447
+ if (unit === "credits") {
7448
+ return `${new Intl.NumberFormat().format(num)} credits`;
7449
+ }
7450
+ return formatPrice(Math.round(num * getMinorUnitsPerMajor(currency)), currency, { free: "" });
7451
+ }
7452
+ function buildSummaryLine(form, currency) {
7453
+ if (!form.enabled) return null;
7454
+ const thresholdDisplay = formatAmountWithUnit(
7455
+ form.thresholdAmountMajor,
7456
+ form.thresholdUnit,
7457
+ currency
7458
+ );
7459
+ const fixedDisplay = formatAmountWithUnit(form.topupAmountMajor, form.topupUnit, currency);
7460
+ return `When my balance falls below ${thresholdDisplay}, add ${fixedDisplay}.`;
7461
+ }
7462
+ function convertAmountForUnitFlip(value, fromUnit, toUnit, currency, creditsPerMinorUnit, displayExchangeRate) {
7463
+ if (fromUnit === toUnit) return value;
7464
+ const parsed = Number(value);
7465
+ if (!Number.isFinite(parsed) || parsed <= 0) return value;
7466
+ if (fromUnit === "currency" && toUnit === "credits") {
7467
+ const credits = estimateCredits(parsed, currency, creditsPerMinorUnit, displayExchangeRate);
7468
+ return credits != null ? String(credits) : value;
7469
+ }
7470
+ const major = estimateCurrencyMajorFromCredits(
7471
+ parsed,
7472
+ currency,
7473
+ creditsPerMinorUnit,
7474
+ displayExchangeRate
7475
+ );
7476
+ return major != null ? String(major) : value;
7477
+ }
7478
+ function flipUnitValue(anchor, targetUnit, currency, creditsPerMinorUnit, displayExchangeRate) {
7479
+ if (targetUnit === anchor.unit) {
7480
+ return { value: anchor.value, unit: anchor.unit };
7481
+ }
7482
+ const converted = convertAmountForUnitFlip(
7483
+ anchor.value,
7484
+ anchor.unit,
7485
+ targetUnit,
7486
+ currency,
7487
+ creditsPerMinorUnit,
7488
+ displayExchangeRate
7489
+ );
7490
+ return { value: converted, unit: targetUnit };
7491
+ }
7492
+
7493
+ // src/primitives/AutoRecharge.tsx
7494
+ var import_jsx_runtime36 = require("react/jsx-runtime");
7495
+ var AutoRechargeContext = (0, import_react42.createContext)(null);
7496
+ function useAutoRechargeCtx(part) {
7497
+ const ctx = (0, import_react42.useContext)(AutoRechargeContext);
7498
+ if (!ctx) {
7499
+ throw new Error(`AutoRecharge.${part} must be rendered inside <AutoRecharge.Root>.`);
7500
+ }
7501
+ return ctx;
7502
+ }
7503
+ function getCurrencySymbol2(currency) {
7504
+ try {
7505
+ const parts = new Intl.NumberFormat("en", { style: "currency", currency }).formatToParts(0);
7506
+ const sym = parts.find((p) => p.type === "currency");
7507
+ return sym?.value ?? currency.toUpperCase();
7508
+ } catch {
7509
+ return currency.toUpperCase();
7510
+ }
7511
+ }
7512
+ var stripePromiseCache3 = /* @__PURE__ */ new Map();
7513
+ function getStripeCacheKey3(publishableKey, accountId) {
7514
+ return accountId ? `${publishableKey}:${accountId}` : publishableKey;
7515
+ }
7516
+ var Root11 = (0, import_react42.forwardRef)(function AutoRechargeRoot({
7517
+ currency = "USD",
7518
+ defaultThresholdAmountMajor,
7519
+ defaultTopupAmountMajor,
7520
+ open: openProp,
7521
+ defaultOpen = false,
7522
+ onOpenChange,
7523
+ onSetupRequired,
7524
+ onSaved,
7525
+ onDisabled,
7526
+ deferCardSetup = false,
7527
+ onPendingConfig,
7528
+ asChild,
7529
+ children,
7530
+ className,
7531
+ ...rest
7532
+ }, forwardedRef) {
7533
+ const solva = (0, import_react42.useContext)(SolvaPayContext);
7534
+ if (!solva) throw new MissingProviderError("AutoRecharge");
7535
+ const autoRecharge = useAutoRecharge();
7536
+ const { creditsPerMinorUnit, displayExchangeRate } = useBalance();
7537
+ const copy = useCopy();
7538
+ const titleId = (0, import_react42.useId)();
7539
+ const triggerRef = (0, import_react42.useRef)(null);
7540
+ const defaultTopup = defaultTopupAmountMajor ?? defaultThresholdAmountMajor ?? void 0;
7541
+ const [uncontrolledOpen, setUncontrolledOpen] = (0, import_react42.useState)(defaultOpen);
7542
+ const isControlled = openProp !== void 0;
7543
+ const open = isControlled ? openProp : uncontrolledOpen;
7544
+ const setOpen = (0, import_react42.useCallback)(
7545
+ (next) => {
7546
+ if (!isControlled) {
7547
+ setUncontrolledOpen(next);
7548
+ }
7549
+ onOpenChange?.(next);
7550
+ },
7551
+ [isControlled, onOpenChange]
7552
+ );
7553
+ const registerTriggerRef = (0, import_react42.useCallback)((node) => {
7554
+ triggerRef.current = node;
7555
+ }, []);
7556
+ const focusTrigger = (0, import_react42.useCallback)(() => {
7557
+ triggerRef.current?.focus();
7558
+ }, []);
7559
+ const [form, setForm] = (0, import_react42.useState)(
7560
+ () => autoRecharge.config ? configToForm(autoRecharge.config, currency) : createDefaultAutoRechargeForm(currency, defaultTopup)
7561
+ );
7562
+ const [validationError, setValidationError] = (0, import_react42.useState)(null);
7563
+ const [statusMessage, setStatusMessage] = (0, import_react42.useState)(null);
7564
+ const [setup, setSetup] = (0, import_react42.useState)(null);
7565
+ const latestConfigRef = (0, import_react42.useRef)(autoRecharge.config);
7566
+ (0, import_react42.useEffect)(() => {
7567
+ latestConfigRef.current = autoRecharge.config;
7568
+ }, [autoRecharge.config]);
7569
+ (0, import_react42.useEffect)(() => {
7570
+ if (autoRecharge.config) {
7571
+ setForm(configToForm(autoRecharge.config, currency));
7572
+ }
7573
+ }, [autoRecharge.config, currency]);
7574
+ const canToggleUnits = creditsPerMinorUnit != null && creditsPerMinorUnit > 0;
7575
+ const rate = displayExchangeRate ?? 1;
7576
+ const isApproximate = rate !== 1;
7577
+ const emitValidation = (0, import_react42.useCallback)(
7578
+ (next) => {
7579
+ const result = validateAutoRechargeForm(
7580
+ next,
7581
+ currency,
7582
+ { creditsPerMinorUnit, displayExchangeRate },
7583
+ copy.autoRecharge
7584
+ );
7585
+ if (!result.ok) {
7586
+ setValidationError(result.error);
7587
+ return null;
7588
+ }
7589
+ setValidationError(null);
7590
+ return result.payload;
7591
+ },
7592
+ [currency, creditsPerMinorUnit, displayExchangeRate, copy.autoRecharge]
7593
+ );
7594
+ const updateForm = (0, import_react42.useCallback)(
7595
+ (patch) => {
7596
+ setForm((prev) => {
7597
+ const next = { ...prev, ...patch };
7598
+ emitValidation(next);
7599
+ return next;
7600
+ });
7601
+ },
7602
+ [emitValidation]
7603
+ );
7604
+ const resetForm = (0, import_react42.useCallback)(() => {
7605
+ if (autoRecharge.config) {
7606
+ setForm(configToForm(autoRecharge.config, currency));
7607
+ } else {
7608
+ setForm(createDefaultAutoRechargeForm(currency, defaultTopup));
7609
+ }
7610
+ setValidationError(null);
7611
+ }, [autoRecharge.config, currency, defaultTopup]);
7612
+ const flipUnit = (0, import_react42.useCallback)(
7613
+ (valueKey, unitKey, baseValueKey, baseUnitKey, currentUnit) => {
7614
+ const nextUnit = currentUnit === "currency" ? "credits" : "currency";
7615
+ setForm((prev) => {
7616
+ const anchor = { value: prev[baseValueKey], unit: prev[baseUnitKey] };
7617
+ const flipped = flipUnitValue(
7618
+ anchor,
7619
+ nextUnit,
7620
+ currency,
7621
+ creditsPerMinorUnit,
7622
+ displayExchangeRate
7623
+ );
7624
+ const next = {
7625
+ ...prev,
7626
+ [unitKey]: flipped.unit,
7627
+ [valueKey]: flipped.value
7628
+ };
7629
+ emitValidation(next);
7630
+ return next;
7631
+ });
7632
+ },
7633
+ [currency, creditsPerMinorUnit, displayExchangeRate, emitValidation]
7634
+ );
7635
+ const fixedTopupHint = (0, import_react42.useMemo)(() => {
7636
+ const parsed = Number(form.topupAmountMajor);
7637
+ if (!Number.isFinite(parsed) || parsed <= 0) return null;
7638
+ if (form.topupUnit === "currency") {
7639
+ const credits = estimateCredits(parsed, currency, creditsPerMinorUnit, displayExchangeRate);
7640
+ if (credits == null) return null;
7641
+ return { credits, approximate: isApproximate };
7642
+ }
7643
+ const major = estimateCurrencyMajorFromCredits(
7644
+ parsed,
7645
+ currency,
7646
+ creditsPerMinorUnit,
7647
+ displayExchangeRate
7648
+ );
7649
+ if (major == null) return null;
7650
+ return { major, approximate: isApproximate };
7651
+ }, [
7652
+ form.topupAmountMajor,
7653
+ form.topupUnit,
7654
+ currency,
7655
+ creditsPerMinorUnit,
7656
+ displayExchangeRate,
7657
+ isApproximate
7658
+ ]);
7659
+ const summaryLine = (0, import_react42.useMemo)(() => buildSummaryLine(form, currency), [form, currency]);
7660
+ const savedSummaryLine = (0, import_react42.useMemo)(() => {
7661
+ if (!autoRecharge.config?.enabled) return null;
7662
+ return buildSummaryLine(
7663
+ configToForm(autoRecharge.config, currency),
7664
+ currency
7665
+ );
7666
+ }, [autoRecharge.config, currency]);
7667
+ const save = (0, import_react42.useCallback)(async () => {
7668
+ const payload = emitValidation(form);
7669
+ if (!payload) return;
7670
+ const saveInput = deferCardSetup ? { ...payload, deferSetupIntent: true } : payload;
7671
+ const result = await autoRecharge.save(saveInput);
7672
+ if (result.setupClientSecret) {
7673
+ setSetup(result);
7674
+ setStatusMessage(copy.autoRecharge.setupRequiredMessage);
7675
+ await onSetupRequired?.(result);
7676
+ return;
7677
+ }
7678
+ setSetup(null);
7679
+ if (deferCardSetup) {
7680
+ await onPendingConfig?.(payload);
7681
+ }
7682
+ setStatusMessage(
7683
+ payload.enabled ? copy.autoRecharge.savedMessage : copy.autoRecharge.disabledMessage
7684
+ );
7685
+ setOpen(false);
7686
+ await onSaved?.(result);
7687
+ }, [
7688
+ autoRecharge,
7689
+ copy.autoRecharge,
7690
+ deferCardSetup,
7691
+ emitValidation,
7692
+ form,
7693
+ onPendingConfig,
7694
+ onSaved,
7695
+ onSetupRequired,
7696
+ setOpen
7697
+ ]);
7698
+ const disable = (0, import_react42.useCallback)(async () => {
7699
+ await autoRecharge.disable();
7700
+ setStatusMessage(copy.autoRecharge.disabledMessage);
7701
+ setSetup(null);
7702
+ await onDisabled?.();
7703
+ }, [autoRecharge, copy.autoRecharge, onDisabled]);
7704
+ const completeSetup = (0, import_react42.useCallback)(async () => {
7705
+ const activated = await waitForAutoRechargeActivation({
7706
+ refresh: autoRecharge.refresh,
7707
+ getStatus: () => latestConfigRef.current?.status
7708
+ });
7709
+ setSetup(null);
7710
+ if (!form.enabled) return;
7711
+ if (activated) {
7712
+ setStatusMessage(copy.autoRecharge.savedMessage);
7713
+ setOpen(false);
7714
+ } else {
7715
+ setStatusMessage(copy.autoRecharge.setupAwaitingConfirmation);
7716
+ }
7717
+ }, [autoRecharge, copy.autoRecharge, form.enabled, setOpen]);
7718
+ const dataState = setup ? "setup" : autoRecharge.error ? "error" : autoRecharge.loading ? "loading" : autoRecharge.saving ? "saving" : autoRecharge.disabling ? "disabling" : "idle";
7719
+ const ctx = (0, import_react42.useMemo)(
7720
+ () => ({
7721
+ form,
7722
+ updateForm,
7723
+ resetForm,
7724
+ validationError,
7725
+ currency,
7726
+ config: autoRecharge.config,
7727
+ loading: autoRecharge.loading,
7728
+ saving: autoRecharge.saving,
7729
+ disabling: autoRecharge.disabling,
7730
+ error: autoRecharge.error,
7731
+ statusMessage,
7732
+ setup,
7733
+ dataState,
7734
+ creditsPerMinorUnit,
7735
+ displayExchangeRate,
7736
+ canToggleUnits,
7737
+ isApproximate,
7738
+ summaryLine,
7739
+ savedSummaryLine,
7740
+ deferCardSetup,
7741
+ fixedTopupHint: fixedTopupHint && "credits" in fixedTopupHint ? String(fixedTopupHint.credits) : fixedTopupHint && "major" in fixedTopupHint ? formatPrice(
7742
+ Math.round(fixedTopupHint.major * getMinorUnitsPerMajor(currency)),
7743
+ currency,
7744
+ { free: "" }
7745
+ ) : null,
7746
+ open,
7747
+ setOpen,
7748
+ titleId,
7749
+ registerTriggerRef,
7750
+ focusTrigger,
7751
+ save,
7752
+ disable,
7753
+ completeSetup,
7754
+ flipUnit
7755
+ }),
7756
+ [
7757
+ form,
7758
+ updateForm,
7759
+ resetForm,
7760
+ validationError,
7761
+ currency,
7762
+ autoRecharge.config,
7763
+ autoRecharge.loading,
7764
+ autoRecharge.saving,
7765
+ autoRecharge.disabling,
7766
+ autoRecharge.error,
7767
+ statusMessage,
7768
+ setup,
7769
+ dataState,
7770
+ creditsPerMinorUnit,
7771
+ displayExchangeRate,
7772
+ canToggleUnits,
7773
+ isApproximate,
7774
+ summaryLine,
7775
+ savedSummaryLine,
7776
+ deferCardSetup,
7777
+ fixedTopupHint,
7778
+ open,
7779
+ setOpen,
7780
+ titleId,
7781
+ registerTriggerRef,
7782
+ focusTrigger,
7783
+ save,
7784
+ disable,
7785
+ completeSetup,
7786
+ flipUnit
7787
+ ]
7788
+ );
7789
+ const Comp = asChild ? Slot : "section";
7790
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(AutoRechargeContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7791
+ Comp,
7792
+ {
7793
+ ref: forwardedRef,
7794
+ className,
7795
+ "aria-label": "Automatic credit top-up",
7796
+ "data-solvapay-auto-recharge": "",
7797
+ "data-state": dataState,
7798
+ ...rest,
7799
+ children
7800
+ }
7801
+ ) });
7802
+ });
7803
+ var Loading8 = (0, import_react42.forwardRef)(
7804
+ function AutoRechargeLoading({ className, children, ...rest }, forwardedRef) {
7805
+ const ctx = useAutoRechargeCtx("Loading");
7806
+ if (!ctx.loading) return null;
7807
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { ref: forwardedRef, className, "data-solvapay-auto-recharge-loading": "", ...rest, children: children ?? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
7808
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Spinner, { size: "sm" }),
7809
+ " Loading auto-recharge settings\u2026"
7810
+ ] }) });
7811
+ }
7812
+ );
7813
+ var Card2 = (0, import_react42.forwardRef)(function AutoRechargeCard({ className, children, ...rest }, forwardedRef) {
7814
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7815
+ "section",
7816
+ {
7817
+ ref: forwardedRef,
7818
+ className,
7819
+ "data-solvapay-auto-recharge-card": "",
7820
+ ...rest,
7821
+ children
7822
+ }
7823
+ );
7824
+ });
7825
+ var CardHeading = (0, import_react42.forwardRef)(
7826
+ function AutoRechargeCardHeading({ className, children, ...rest }, forwardedRef) {
7827
+ const copy = useCopy();
7828
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7829
+ "h3",
7830
+ {
7831
+ ref: forwardedRef,
7832
+ className,
7833
+ "data-solvapay-auto-recharge-card-heading": "",
7834
+ ...rest,
7835
+ children: children ?? copy.autoRecharge.heading
7836
+ }
7837
+ );
7838
+ }
7839
+ );
7840
+ var CardSummary = (0, import_react42.forwardRef)(
7841
+ function AutoRechargeCardSummary({ className, children, ...rest }, forwardedRef) {
7842
+ const ctx = useAutoRechargeCtx("CardSummary");
7843
+ const copy = useCopy();
7844
+ const text = ctx.savedSummaryLine ?? copy.autoRecharge.notConfiguredHint;
7845
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7846
+ "p",
7847
+ {
7848
+ ref: forwardedRef,
7849
+ className,
7850
+ "data-solvapay-auto-recharge-card-summary": "",
7851
+ ...rest,
7852
+ children: children ?? text
7853
+ }
7854
+ );
7855
+ }
7856
+ );
7857
+ var Trigger = (0, import_react42.forwardRef)(function AutoRechargeTrigger({ asChild, onClick, children, className, ...rest }, forwardedRef) {
7858
+ const ctx = useAutoRechargeCtx("Trigger");
7859
+ const copy = useCopy();
7860
+ const hasExistingConfig = Boolean(ctx.config?.enabled);
7861
+ const label = hasExistingConfig ? copy.autoRecharge.modifyTriggerLabel : copy.autoRecharge.setupTriggerLabel;
7862
+ const setRefs = (node) => {
7863
+ ctx.registerTriggerRef(node);
7864
+ if (typeof forwardedRef === "function") {
7865
+ forwardedRef(node);
7866
+ } else if (forwardedRef) {
7867
+ forwardedRef.current = node;
7868
+ }
7869
+ };
7870
+ const commonProps = {
7871
+ "data-solvapay-auto-recharge-trigger": "",
7872
+ type: "button",
7873
+ "aria-haspopup": "dialog",
7874
+ "aria-expanded": ctx.open,
7875
+ disabled: ctx.loading,
7876
+ onClick: composeEventHandlers(onClick, (event) => {
7877
+ event.preventDefault();
7878
+ ctx.resetForm();
7879
+ ctx.setOpen(true);
7880
+ }),
7881
+ className,
7882
+ ...rest
7883
+ };
7884
+ if (asChild) {
7885
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Slot, { ref: setRefs, ...commonProps, children: children ?? label });
7886
+ }
7887
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("button", { ref: setRefs, ...commonProps, children: children ?? label });
7888
+ });
7889
+ var Overlay = (0, import_react42.forwardRef)(
7890
+ function AutoRechargeOverlay({ onClick, className, ...rest }, forwardedRef) {
7891
+ const ctx = useAutoRechargeCtx("Overlay");
7892
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7893
+ "div",
7894
+ {
7895
+ ref: forwardedRef,
7896
+ className,
7897
+ "data-solvapay-auto-recharge-overlay": "",
7898
+ "aria-hidden": "true",
7899
+ onClick: composeEventHandlers(onClick, () => {
7900
+ ctx.resetForm();
7901
+ ctx.setOpen(false);
7902
+ ctx.focusTrigger();
7903
+ }),
7904
+ ...rest
7905
+ }
7906
+ );
7907
+ }
7908
+ );
7909
+ var Content = (0, import_react42.forwardRef)(function AutoRechargeContent({ className, children, ...rest }, forwardedRef) {
7910
+ const ctx = useAutoRechargeCtx("Content");
7911
+ const panelRef = (0, import_react42.useRef)(null);
7912
+ (0, import_react42.useEffect)(() => {
7913
+ if (!ctx.open) return;
7914
+ const handleKeyDown = (event) => {
7915
+ if (event.key === "Escape") {
7916
+ ctx.resetForm();
7917
+ ctx.setOpen(false);
7918
+ ctx.focusTrigger();
7919
+ }
7920
+ };
7921
+ document.addEventListener("keydown", handleKeyDown);
7922
+ const focusTarget = panelRef.current?.querySelector(
7923
+ 'button:not([disabled]), input:not([disabled]), [href], [tabindex]:not([tabindex="-1"])'
7924
+ );
7925
+ focusTarget?.focus();
7926
+ return () => {
7927
+ document.removeEventListener("keydown", handleKeyDown);
7928
+ };
7929
+ }, [ctx.open, ctx.resetForm, ctx.setOpen, ctx.focusTrigger]);
7930
+ if (!ctx.open || typeof document === "undefined") return null;
7931
+ return (0, import_react_dom.createPortal)(
7932
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { "data-solvapay-auto-recharge-portal": "", children: [
7933
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Overlay, {}),
7934
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7935
+ "div",
7936
+ {
7937
+ ref: (node) => {
7938
+ panelRef.current = node;
7939
+ if (typeof forwardedRef === "function") {
7940
+ forwardedRef(node);
7941
+ } else if (forwardedRef) {
7942
+ forwardedRef.current = node;
7943
+ }
7944
+ },
7945
+ role: "dialog",
7946
+ "aria-modal": "true",
7947
+ "aria-labelledby": ctx.titleId,
7948
+ className,
7949
+ "data-solvapay-auto-recharge-content": "",
7950
+ ...rest,
7951
+ children
7952
+ }
7953
+ )
7954
+ ] }),
7955
+ document.body
7956
+ );
7957
+ });
7958
+ var Title = (0, import_react42.forwardRef)(
7959
+ function AutoRechargeTitle({ className, children, ...rest }, forwardedRef) {
7960
+ const ctx = useAutoRechargeCtx("Title");
7961
+ const copy = useCopy();
7962
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7963
+ "h2",
7964
+ {
7965
+ ref: forwardedRef,
7966
+ id: ctx.titleId,
7967
+ className,
7968
+ "data-solvapay-auto-recharge-title": "",
7969
+ ...rest,
7970
+ children: children ?? copy.autoRecharge.settingsHeading
7971
+ }
7972
+ );
7973
+ }
7974
+ );
7975
+ var EnableQuestion = (0, import_react42.forwardRef)(
7976
+ function AutoRechargeEnableQuestion({ className, children, ...rest }, forwardedRef) {
7977
+ const copy = useCopy();
7978
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { ref: forwardedRef, className, "data-solvapay-auto-recharge-question": "", ...rest, children: children ?? copy.autoRecharge.enableQuestion });
7979
+ }
7980
+ );
7981
+ var EnableSentence = (0, import_react42.forwardRef)(
7982
+ function AutoRechargeEnableSentence({ className, children, ...rest }, forwardedRef) {
7983
+ const copy = useCopy();
7984
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
7985
+ "label",
7986
+ {
7987
+ ref: forwardedRef,
7988
+ className,
7989
+ "data-solvapay-auto-recharge-enable-sentence": "",
7990
+ ...rest,
7991
+ children: children ?? copy.autoRecharge.enableSentence
7992
+ }
7993
+ );
7994
+ }
7995
+ );
7996
+ var EnableRow = (0, import_react42.forwardRef)(
7997
+ function AutoRechargeEnableRow({ className, children, ...rest }, forwardedRef) {
7998
+ const enableId = (0, import_react42.useId)();
7999
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8000
+ "div",
8001
+ {
8002
+ ref: forwardedRef,
8003
+ className,
8004
+ "data-solvapay-auto-recharge-enable-row": "",
8005
+ ...rest,
8006
+ children: children ?? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
8007
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(EnableSwitch, { appearance: "checkbox", id: enableId }),
8008
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(EnableSentence, { htmlFor: enableId })
8009
+ ] })
8010
+ }
8011
+ );
8012
+ }
8013
+ );
8014
+ var CancelButton = (0, import_react42.forwardRef)(
8015
+ function AutoRechargeCancelButton({ asChild, onClick, children, className, ...rest }, forwardedRef) {
8016
+ const ctx = useAutoRechargeCtx("CancelButton");
8017
+ const copy = useCopy();
8018
+ const commonProps = {
8019
+ "data-solvapay-auto-recharge-cancel": "",
8020
+ type: "button",
8021
+ onClick: composeEventHandlers(onClick, (event) => {
8022
+ event.preventDefault();
8023
+ ctx.resetForm();
8024
+ ctx.setOpen(false);
8025
+ ctx.focusTrigger();
8026
+ }),
8027
+ className,
8028
+ ...rest
8029
+ };
8030
+ if (asChild) {
8031
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8032
+ Slot,
8033
+ {
8034
+ ref: forwardedRef,
8035
+ ...commonProps,
8036
+ children: children ?? copy.autoRecharge.cancelButton
8037
+ }
8038
+ );
8039
+ }
8040
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("button", { ref: forwardedRef, ...commonProps, children: children ?? copy.autoRecharge.cancelButton });
8041
+ }
8042
+ );
8043
+ var Header = (0, import_react42.forwardRef)(
8044
+ function AutoRechargeHeader({ className, ...rest }, forwardedRef) {
8045
+ const copy = useCopy();
8046
+ const headingId = (0, import_react42.useId)();
8047
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
8048
+ "header",
8049
+ {
8050
+ ref: forwardedRef,
8051
+ className,
8052
+ "data-solvapay-auto-recharge-header": "",
8053
+ ...rest,
8054
+ children: [
8055
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("section", { "data-solvapay-auto-recharge-heading-group": "", children: [
8056
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("h3", { id: headingId, "data-solvapay-auto-recharge-heading": "", children: copy.autoRecharge.heading }),
8057
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Description, {})
8058
+ ] }),
8059
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(EnableSwitch, { "aria-labelledby": headingId })
8060
+ ]
8061
+ }
8062
+ );
8063
+ }
8064
+ );
8065
+ var Description = (0, import_react42.forwardRef)(
8066
+ function AutoRechargeDescription({ className, children, ...rest }, forwardedRef) {
8067
+ const copy = useCopy();
8068
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8069
+ "p",
8070
+ {
8071
+ ref: forwardedRef,
8072
+ className,
8073
+ "data-solvapay-auto-recharge-description": "",
8074
+ ...rest,
8075
+ children: children ?? copy.autoRecharge.description
8076
+ }
8077
+ );
8078
+ }
8079
+ );
8080
+ var EnableSwitch = (0, import_react42.forwardRef)(
8081
+ function AutoRechargeEnableSwitch({ asChild, appearance = "switch", onChange, className, ...rest }, forwardedRef) {
8082
+ const ctx = useAutoRechargeCtx("EnableSwitch");
8083
+ const copy = useCopy();
8084
+ const commonProps = {
8085
+ "data-solvapay-auto-recharge-enable": "",
8086
+ "data-appearance": appearance,
8087
+ type: "checkbox",
8088
+ ...appearance === "switch" ? { role: "switch", "aria-checked": ctx.form.enabled } : {},
8089
+ checked: ctx.form.enabled,
8090
+ "aria-label": copy.autoRecharge.enableLabel,
8091
+ disabled: ctx.loading || ctx.saving || ctx.disabling || !!ctx.setup,
8092
+ onChange: composeEventHandlers(onChange, (event) => {
8093
+ ctx.updateForm({ enabled: event.currentTarget.checked });
8094
+ }),
8095
+ className,
8096
+ ...rest
8097
+ };
8098
+ if (asChild) {
8099
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8100
+ Slot,
8101
+ {
8102
+ ref: forwardedRef,
8103
+ ...commonProps
8104
+ }
8105
+ );
8106
+ }
8107
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("input", { ref: forwardedRef, ...commonProps });
8108
+ }
8109
+ );
8110
+ var Fields = (0, import_react42.forwardRef)(
8111
+ function AutoRechargeFields({ className, children, ...rest }, forwardedRef) {
8112
+ const ctx = useAutoRechargeCtx("Fields");
8113
+ const copy = useCopy();
8114
+ if (!ctx.form.enabled) return null;
8115
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
8116
+ "fieldset",
8117
+ {
8118
+ ref: forwardedRef,
8119
+ className,
8120
+ disabled: ctx.saving || ctx.disabling,
8121
+ "data-solvapay-auto-recharge-fields": "",
8122
+ "data-solvapay-auto-recharge-body": "",
8123
+ "data-state": "open",
8124
+ ...rest,
8125
+ children: [
8126
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("legend", { className: "sr-only", children: copy.autoRecharge.heading }),
8127
+ children ?? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
8128
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Summary3, {}),
8129
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ThresholdField, {}),
8130
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(TopupField, {}),
8131
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ValidationError, {})
8132
+ ] })
8133
+ ]
8134
+ }
8135
+ );
8136
+ }
8137
+ );
8138
+ var Setup = (0, import_react42.forwardRef)(
8139
+ function AutoRechargeSetup({ className, children, ...rest }, forwardedRef) {
8140
+ const ctx = useAutoRechargeCtx("Setup");
8141
+ if (!ctx.setup?.setupClientSecret) return null;
8142
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8143
+ "div",
8144
+ {
8145
+ ref: forwardedRef,
8146
+ className,
8147
+ "data-solvapay-auto-recharge-setup-panel": "",
8148
+ ...rest,
8149
+ children: children ?? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(CardSetup, { setup: ctx.setup, onComplete: ctx.completeSetup })
8150
+ }
8151
+ );
8152
+ }
8153
+ );
8154
+ var Body = (0, import_react42.forwardRef)(
8155
+ function AutoRechargeBody({ className, children, ...rest }, forwardedRef) {
8156
+ const ctx = useAutoRechargeCtx("Body");
8157
+ if (ctx.setup?.setupClientSecret) {
8158
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Setup, { className });
8159
+ }
8160
+ if (!ctx.form.enabled) return null;
8161
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Fields, { ref: forwardedRef, className, ...rest, children: children ?? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
8162
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Summary3, {}),
8163
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ThresholdField, {}),
8164
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(TopupField, {}),
8165
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ValidationError, {}),
8166
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Actions, {})
8167
+ ] }) });
8168
+ }
8169
+ );
8170
+ var Summary3 = (0, import_react42.forwardRef)(
8171
+ function AutoRechargeSummary({ className, children, ...rest }, forwardedRef) {
8172
+ const ctx = useAutoRechargeCtx("Summary");
8173
+ if (!ctx.summaryLine) return null;
8174
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { ref: forwardedRef, className, "data-solvapay-auto-recharge-summary": "", ...rest, children: children ?? ctx.summaryLine });
8175
+ }
8176
+ );
8177
+ var AmountField = (0, import_react42.forwardRef)(function AutoRechargeAmountField({ field, showLabel = true, asChild, onChange, className, ...rest }, forwardedRef) {
8178
+ const ctx = useAutoRechargeCtx("AmountField");
8179
+ const copy = useCopy();
8180
+ const fieldConfig = {
8181
+ threshold: {
8182
+ label: copy.autoRecharge.thresholdLabel,
8183
+ ariaLabel: copy.autoRecharge.thresholdAriaLabel,
8184
+ unitToggleLabel: "balance threshold",
8185
+ value: ctx.form.thresholdAmountMajor,
8186
+ unit: ctx.form.thresholdUnit,
8187
+ unitKey: "thresholdUnit",
8188
+ valueKey: "thresholdAmountMajor",
8189
+ baseValueKey: "thresholdBaseValue",
8190
+ baseUnitKey: "thresholdBaseUnit",
8191
+ mode: ctx.form.thresholdUnit === "currency" ? "currency" : "number",
8192
+ onValue: (value) => ctx.updateForm({
8193
+ thresholdAmountMajor: value,
8194
+ thresholdBaseValue: value,
8195
+ thresholdBaseUnit: ctx.form.thresholdUnit
8196
+ })
8197
+ },
8198
+ fixed: {
8199
+ label: copy.autoRecharge.fixedAmountLabel,
8200
+ ariaLabel: copy.autoRecharge.fixedAmountAriaLabel,
8201
+ unitToggleLabel: "fixed top-up amount",
8202
+ value: ctx.form.topupAmountMajor,
8203
+ unit: ctx.form.topupUnit,
8204
+ unitKey: "topupUnit",
8205
+ valueKey: "topupAmountMajor",
8206
+ baseValueKey: "topupBaseValue",
8207
+ baseUnitKey: "topupBaseUnit",
8208
+ mode: ctx.form.topupUnit === "currency" ? "currency" : "number",
8209
+ onValue: (value) => ctx.updateForm({
8210
+ topupAmountMajor: value,
8211
+ topupBaseValue: value,
8212
+ topupBaseUnit: ctx.form.topupUnit
8213
+ })
8214
+ }
8215
+ }[field];
8216
+ const inputId = (0, import_react42.useId)();
8217
+ const prefix = fieldConfig.mode === "currency" ? getCurrencySymbol2(ctx.currency) : void 0;
8218
+ const handleChange = (event) => {
8219
+ const raw = event.target.value;
8220
+ const next = fieldConfig.mode === "currency" ? raw.replace(/[^0-9.]/g, "") : raw.replace(/[^0-9]/g, "");
8221
+ fieldConfig.onValue(next);
8222
+ };
8223
+ const inputProps = {
8224
+ id: inputId,
8225
+ "data-solvapay-auto-recharge-amount": "",
8226
+ "data-field": field,
8227
+ type: "text",
8228
+ inputMode: fieldConfig.mode === "currency" ? "decimal" : "numeric",
8229
+ placeholder: fieldConfig.mode === "currency" ? "0.00" : "0",
8230
+ value: fieldConfig.value,
8231
+ "aria-label": fieldConfig.ariaLabel,
8232
+ onChange: composeEventHandlers(onChange, handleChange),
8233
+ className,
8234
+ ...rest
8235
+ };
8236
+ const slotRef = forwardedRef;
8237
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("p", { "data-solvapay-auto-recharge-field": "", "data-field": field, children: [
8238
+ showLabel ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("label", { htmlFor: inputId, children: fieldConfig.label }) : null,
8239
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("span", { "data-solvapay-auto-recharge-amount-row": "", children: [
8240
+ prefix ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { "data-solvapay-auto-recharge-currency-prefix": "", "aria-hidden": "true", children: prefix }) : null,
8241
+ asChild ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Slot, { ref: slotRef, ...inputProps }) : /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("input", { ref: forwardedRef, ...inputProps }),
8242
+ ctx.canToggleUnits ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8243
+ UnitToggle,
8244
+ {
8245
+ unit: fieldConfig.unit,
8246
+ fieldLabel: fieldConfig.unitToggleLabel,
8247
+ onToggle: () => ctx.flipUnit(
8248
+ fieldConfig.valueKey,
8249
+ fieldConfig.unitKey,
8250
+ fieldConfig.baseValueKey,
8251
+ fieldConfig.baseUnitKey,
8252
+ fieldConfig.unit
8253
+ )
8254
+ }
8255
+ ) : null
8256
+ ] })
8257
+ ] });
8258
+ });
8259
+ var ThresholdField = (0, import_react42.forwardRef)(
8260
+ function AutoRechargeThresholdField({ className, ...rest }, ref) {
8261
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("section", { ref, className, ...rest, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(AmountField, { field: "threshold" }) });
8262
+ }
8263
+ );
8264
+ var TopupField = (0, import_react42.forwardRef)(
8265
+ function AutoRechargeTopupField({ className, ...rest }, ref) {
8266
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
8267
+ "section",
8268
+ {
8269
+ ref,
8270
+ className,
8271
+ "data-solvapay-auto-recharge-topup-field": "",
8272
+ ...rest,
8273
+ children: [
8274
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(AmountField, { field: "fixed" }),
8275
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Hint, {})
8276
+ ]
8277
+ }
8278
+ );
8279
+ }
8280
+ );
8281
+ var UnitToggle = (0, import_react42.forwardRef)(function AutoRechargeUnitToggle({ unit, fieldLabel, onToggle, className, ...rest }, forwardedRef) {
8282
+ const ctx = useAutoRechargeCtx("UnitToggle");
8283
+ const targetUnitLabel = unit === "currency" ? "credits" : "currency";
8284
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8285
+ "button",
8286
+ {
8287
+ ref: forwardedRef,
8288
+ type: "button",
8289
+ className,
8290
+ "data-solvapay-auto-recharge-unit-toggle": "",
8291
+ "aria-label": `Switch ${fieldLabel} to ${targetUnitLabel}`,
8292
+ onClick: onToggle,
8293
+ ...rest,
8294
+ children: unit === "currency" ? ctx.currency.toUpperCase() : "credits"
8295
+ }
8296
+ );
8297
+ });
8298
+ var Hint = (0, import_react42.forwardRef)(
8299
+ function AutoRechargeHint({ className, ...rest }, forwardedRef) {
8300
+ const ctx = useAutoRechargeCtx("Hint");
8301
+ const copy = useCopy();
8302
+ const hint = ctx.fixedTopupHint;
8303
+ if (!hint) return null;
8304
+ const isCreditsHint = ctx.form.topupUnit === "currency";
8305
+ const text = isCreditsHint ? interpolate(
8306
+ ctx.isApproximate ? copy.autoRecharge.creditsPerRechargeApprox : copy.autoRecharge.creditsPerRecharge,
8307
+ { credits: new Intl.NumberFormat().format(Number(hint)) }
8308
+ ) : interpolate(
8309
+ ctx.isApproximate ? copy.autoRecharge.currencyPerRechargeApprox : copy.autoRecharge.currencyPerRecharge,
8310
+ { amount: hint }
8311
+ );
8312
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { ref: forwardedRef, className, "data-solvapay-auto-recharge-hint": "", ...rest, children: text });
8313
+ }
8314
+ );
8315
+ var ValidationError = (0, import_react42.forwardRef)(function AutoRechargeValidationError({ className, ...rest }, forwardedRef) {
8316
+ const ctx = useAutoRechargeCtx("ValidationError");
8317
+ if (!ctx.validationError) return null;
8318
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8319
+ "p",
8320
+ {
8321
+ ref: forwardedRef,
8322
+ role: "alert",
8323
+ "aria-live": "polite",
8324
+ className,
8325
+ "data-solvapay-auto-recharge-validation-error": "",
8326
+ ...rest,
8327
+ children: ctx.validationError
8328
+ }
8329
+ );
8330
+ });
8331
+ var Actions = (0, import_react42.forwardRef)(
8332
+ function AutoRechargeActions({ className, children, ...rest }, forwardedRef) {
8333
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8334
+ "menu",
8335
+ {
8336
+ ref: forwardedRef,
8337
+ className,
8338
+ "data-solvapay-auto-recharge-actions": "",
8339
+ ...rest,
8340
+ children: children ?? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
8341
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(CancelButton, {}) }),
8342
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(SaveButton, {}) })
8343
+ ] })
8344
+ }
8345
+ );
8346
+ }
8347
+ );
8348
+ var SaveButton = (0, import_react42.forwardRef)(function AutoRechargeSaveButton({ asChild, onClick, children, className, ...rest }, forwardedRef) {
8349
+ const ctx = useAutoRechargeCtx("SaveButton");
8350
+ const copy = useCopy();
8351
+ const dataState = ctx.saving ? "processing" : ctx.validationError ? "disabled" : "idle";
8352
+ const commonProps = {
8353
+ "data-solvapay-auto-recharge-save": "",
8354
+ "data-state": dataState,
8355
+ type: "button",
8356
+ disabled: ctx.saving || ctx.disabling || !!ctx.validationError,
8357
+ "aria-busy": ctx.saving,
8358
+ onClick: composeEventHandlers(onClick, (event) => {
8359
+ event.preventDefault();
8360
+ void ctx.save();
8361
+ }),
8362
+ className,
8363
+ ...rest
8364
+ };
8365
+ const content = ctx.saving ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
8366
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Spinner, { size: "sm" }),
8367
+ " ",
8368
+ copy.cta.processing
8369
+ ] }) : children ?? copy.autoRecharge.saveButton;
8370
+ if (asChild) {
8371
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8372
+ Slot,
8373
+ {
8374
+ ref: forwardedRef,
8375
+ ...commonProps,
8376
+ children: content
8377
+ }
8378
+ );
8379
+ }
8380
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("button", { ref: forwardedRef, ...commonProps, children: content });
8381
+ });
8382
+ var DisableButton = (0, import_react42.forwardRef)(
8383
+ function AutoRechargeDisableButton({ asChild, onClick, children, className, ...rest }, forwardedRef) {
8384
+ const ctx = useAutoRechargeCtx("DisableButton");
8385
+ const copy = useCopy();
8386
+ if (!ctx.config) return null;
8387
+ const commonProps = {
8388
+ "data-solvapay-auto-recharge-disable": "",
8389
+ type: "button",
8390
+ disabled: ctx.saving || ctx.disabling,
8391
+ "aria-busy": ctx.disabling,
8392
+ onClick: composeEventHandlers(onClick, (event) => {
8393
+ event.preventDefault();
8394
+ void ctx.disable();
8395
+ }),
8396
+ className,
8397
+ ...rest
8398
+ };
8399
+ if (asChild) {
8400
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8401
+ Slot,
8402
+ {
8403
+ ref: forwardedRef,
8404
+ ...commonProps,
8405
+ children: children ?? copy.autoRecharge.disableButton
8406
+ }
8407
+ );
8408
+ }
8409
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("button", { ref: forwardedRef, ...commonProps, children: children ?? copy.autoRecharge.disableButton });
8410
+ }
8411
+ );
8412
+ var ErrorSlot7 = (0, import_react42.forwardRef)(
8413
+ function AutoRechargeError({ className, children, ...rest }, forwardedRef) {
8414
+ const ctx = useAutoRechargeCtx("Error");
8415
+ if (!ctx.error) return null;
8416
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8417
+ "p",
8418
+ {
8419
+ ref: forwardedRef,
8420
+ role: "alert",
8421
+ "aria-live": "polite",
8422
+ className,
8423
+ "data-solvapay-auto-recharge-error": "",
8424
+ ...rest,
8425
+ children: children ?? ctx.error.message
8426
+ }
8427
+ );
8428
+ }
8429
+ );
8430
+ var StatusMessage = (0, import_react42.forwardRef)(
8431
+ function AutoRechargeStatusMessage({ className, children, ...rest }, forwardedRef) {
8432
+ const ctx = useAutoRechargeCtx("StatusMessage");
8433
+ if (!ctx.statusMessage) return null;
8434
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8435
+ "p",
8436
+ {
8437
+ ref: forwardedRef,
8438
+ "aria-live": "polite",
8439
+ className,
8440
+ "data-solvapay-auto-recharge-status-message": "",
8441
+ ...rest,
8442
+ children: children ?? ctx.statusMessage
8443
+ }
8444
+ );
8445
+ }
8446
+ );
8447
+ var Status = (0, import_react42.forwardRef)(
8448
+ function AutoRechargeStatus({ className, ...rest }, forwardedRef) {
8449
+ const ctx = useAutoRechargeCtx("Status");
8450
+ const copy = useCopy();
8451
+ const status = ctx.config?.status;
8452
+ if (!status || status === "active" || status === "disabled" || status === "pending_setup") {
8453
+ return null;
8454
+ }
8455
+ const label = status === "failed" ? copy.autoRecharge.statusFailed : null;
8456
+ if (!label) return null;
8457
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8458
+ "span",
8459
+ {
8460
+ ref: forwardedRef,
8461
+ className,
8462
+ "data-solvapay-auto-recharge-status": "",
8463
+ "data-status": status,
8464
+ ...rest,
8465
+ children: label
8466
+ }
8467
+ );
8468
+ }
8469
+ );
8470
+ function CardSetupInner({ onComplete }) {
8471
+ const copy = useCopy();
8472
+ const stripe = (0, import_react_stripe_js4.useStripe)();
8473
+ const elements = (0, import_react_stripe_js4.useElements)();
8474
+ const [processing, setProcessing] = (0, import_react42.useState)(false);
8475
+ const [error, setError] = (0, import_react42.useState)(null);
6989
8476
  (0, import_react42.useEffect)(() => {
8477
+ if (!stripe) return;
8478
+ const clientSecret = readSetupIntentClientSecret(window.location.search);
8479
+ if (!clientSecret) return;
8480
+ let cancelled = false;
8481
+ void (async () => {
8482
+ setProcessing(true);
8483
+ const { setupIntent, error: retrieveError } = await stripe.retrieveSetupIntent(clientSecret);
8484
+ if (cancelled) return;
8485
+ stripSetupIntentParams();
8486
+ if (retrieveError || !setupIntent) {
8487
+ setError(copy.autoRecharge.setupAuthFailed);
8488
+ setProcessing(false);
8489
+ return;
8490
+ }
8491
+ if (setupIntent.status === "succeeded" || setupIntent.status === "processing") {
8492
+ await onComplete();
8493
+ } else {
8494
+ setError(copy.autoRecharge.setupAuthFailed);
8495
+ }
8496
+ if (!cancelled) setProcessing(false);
8497
+ })();
8498
+ return () => {
8499
+ cancelled = true;
8500
+ };
8501
+ }, [stripe, onComplete, copy.autoRecharge]);
8502
+ const handleSubmit = async (event) => {
8503
+ event.preventDefault();
8504
+ if (!stripe || !elements) {
8505
+ setError("Stripe is still loading. Please wait.");
8506
+ return;
8507
+ }
8508
+ setProcessing(true);
8509
+ setError(null);
8510
+ const { error: submitError } = await elements.submit();
8511
+ if (submitError) {
8512
+ setError(submitError.message ?? "Card authorization failed");
8513
+ setProcessing(false);
8514
+ return;
8515
+ }
8516
+ const { error: confirmError } = await stripe.confirmSetup({
8517
+ elements,
8518
+ confirmParams: {
8519
+ return_url: typeof window !== "undefined" ? window.location.href : "/"
8520
+ },
8521
+ redirect: "if_required"
8522
+ });
8523
+ if (confirmError) {
8524
+ setError(confirmError.message ?? "Card authorization failed");
8525
+ setProcessing(false);
8526
+ return;
8527
+ }
8528
+ await onComplete();
8529
+ setProcessing(false);
8530
+ };
8531
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("form", { onSubmit: handleSubmit, "data-solvapay-auto-recharge-setup": "", children: [
8532
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("h4", { children: copy.autoRecharge.setupHeading }),
8533
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { children: copy.autoRecharge.setupDescription }),
8534
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_react_stripe_js4.PaymentElement, { options: withPaymentElementDefaults() }),
8535
+ error ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { role: "alert", "aria-live": "polite", "data-solvapay-auto-recharge-setup-error": "", children: error }) : null,
8536
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8537
+ "button",
8538
+ {
8539
+ type: "submit",
8540
+ disabled: processing || !stripe,
8541
+ "data-solvapay-auto-recharge-setup-submit": "",
8542
+ children: processing ? copy.autoRecharge.setupProcessing : copy.autoRecharge.setupSubmit
8543
+ }
8544
+ )
8545
+ ] });
8546
+ }
8547
+ function CardSetup({ setup, onComplete }) {
8548
+ const stripePromise = (0, import_react42.useMemo)(() => {
8549
+ if (!setup.publishableKey || !setup.setupClientSecret) return null;
8550
+ const options = {
8551
+ ...setup.stripeAccountId ? { stripeAccount: setup.stripeAccountId } : {},
8552
+ developerTools: { assistant: { enabled: false } }
8553
+ };
8554
+ const cacheKey2 = getStripeCacheKey3(setup.publishableKey, setup.stripeAccountId);
8555
+ const cached = stripePromiseCache3.get(cacheKey2);
8556
+ if (cached) return cached;
8557
+ const promise = (0, import_stripe_js3.loadStripe)(setup.publishableKey, options);
8558
+ stripePromiseCache3.set(cacheKey2, promise);
8559
+ return promise;
8560
+ }, [setup.publishableKey, setup.setupClientSecret, setup.stripeAccountId]);
8561
+ if (!stripePromise || !setup.setupClientSecret) {
8562
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("p", { "data-solvapay-auto-recharge-setup-loading": "", children: [
8563
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Spinner, { size: "sm" }),
8564
+ " Loading card form\u2026"
8565
+ ] });
8566
+ }
8567
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8568
+ import_react_stripe_js4.Elements,
8569
+ {
8570
+ stripe: stripePromise,
8571
+ options: { clientSecret: setup.setupClientSecret },
8572
+ children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(CardSetupInner, { onComplete })
8573
+ },
8574
+ setup.setupClientSecret
8575
+ );
8576
+ }
8577
+ var AutoRecharge = {
8578
+ Root: Root11,
8579
+ Loading: Loading8,
8580
+ Card: Card2,
8581
+ CardHeading,
8582
+ CardSummary,
8583
+ Trigger,
8584
+ Overlay,
8585
+ Content,
8586
+ Title,
8587
+ EnableQuestion,
8588
+ EnableSentence,
8589
+ EnableRow,
8590
+ CancelButton,
8591
+ Header,
8592
+ Description,
8593
+ EnableSwitch,
8594
+ Fields,
8595
+ Setup,
8596
+ Body,
8597
+ Summary: Summary3,
8598
+ ThresholdField,
8599
+ TopupField,
8600
+ AmountField,
8601
+ UnitToggle,
8602
+ Hint,
8603
+ ValidationError,
8604
+ Actions,
8605
+ SaveButton,
8606
+ DisableButton,
8607
+ Error: ErrorSlot7,
8608
+ StatusMessage,
8609
+ Status,
8610
+ CardSetup
8611
+ };
8612
+
8613
+ // src/components/AutoRecharge.tsx
8614
+ var import_jsx_runtime37 = require("react/jsx-runtime");
8615
+ function AutoRecharge2({
8616
+ currency = "USD",
8617
+ defaultThresholdAmountMajor,
8618
+ defaultTopupAmountMajor,
8619
+ onSetupRequired,
8620
+ onSaved,
8621
+ onDisabled,
8622
+ deferCardSetup,
8623
+ onPendingConfig,
8624
+ className
8625
+ }) {
8626
+ const rootClass = ["solvapay-auto-recharge", className].filter(Boolean).join(" ");
8627
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
8628
+ AutoRecharge.Root,
8629
+ {
8630
+ currency,
8631
+ defaultThresholdAmountMajor,
8632
+ defaultTopupAmountMajor,
8633
+ onSetupRequired,
8634
+ onSaved,
8635
+ onDisabled,
8636
+ deferCardSetup,
8637
+ onPendingConfig,
8638
+ className: rootClass,
8639
+ children: [
8640
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(AutoRecharge.Loading, { className: "solvapay-auto-recharge-loading" }),
8641
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(AutoRecharge.Card, { className: "solvapay-auto-recharge-card", children: [
8642
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(AutoRecharge.CardHeading, { className: "solvapay-auto-recharge-card-heading" }),
8643
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(AutoRecharge.CardSummary, { className: "solvapay-auto-recharge-card-summary" }),
8644
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(AutoRecharge.StatusMessage, { className: "solvapay-auto-recharge-status-message" }),
8645
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(AutoRecharge.Status, { className: "solvapay-auto-recharge-status" }),
8646
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(AutoRecharge.Trigger, { className: "solvapay-auto-recharge-trigger" })
8647
+ ] }),
8648
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(AutoRecharge.Error, { className: "solvapay-auto-recharge-error" }),
8649
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(AutoRecharge.Content, { className: "solvapay-auto-recharge-content", children: [
8650
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(AutoRecharge.Title, { className: "solvapay-auto-recharge-title" }),
8651
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(AutoRecharge.EnableQuestion, { className: "solvapay-auto-recharge-question" }),
8652
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(AutoRecharge.EnableRow, { className: "solvapay-auto-recharge-enable-row" }),
8653
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(AutoRecharge.Fields, { className: "solvapay-auto-recharge-fields", children: [
8654
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(AutoRecharge.ThresholdField, {}),
8655
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(AutoRecharge.TopupField, { className: "solvapay-auto-recharge-topup-field" }),
8656
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(AutoRecharge.ValidationError, { className: "solvapay-auto-recharge-validation-error" })
8657
+ ] }),
8658
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(AutoRecharge.Setup, {}),
8659
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(AutoRecharge.Actions, { className: "solvapay-auto-recharge-actions", children: [
8660
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(AutoRecharge.CancelButton, { className: "solvapay-auto-recharge-cancel" }),
8661
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(AutoRecharge.SaveButton, { className: "solvapay-auto-recharge-save" })
8662
+ ] })
8663
+ ] })
8664
+ ]
8665
+ }
8666
+ );
8667
+ }
8668
+
8669
+ // src/hooks/useLimits.ts
8670
+ var import_react43 = require("react");
8671
+ var CACHE_TTL_MS = 1e4;
8672
+ var OPTIMISTIC_GRACE_MS = 8e3;
8673
+ var limitsCache = /* @__PURE__ */ new Map();
8674
+ function cacheKey(customerRef, productRef, meterName) {
8675
+ return `${customerRef ?? "anonymous"}:${productRef}:${meterName}`;
8676
+ }
8677
+ function useLimits(options) {
8678
+ const { productRef, meterName: rawMeterName, enabled = true } = options;
8679
+ const meterName = rawMeterName || "requests";
8680
+ const transport = useTransport();
8681
+ const { customerRef } = useCustomer();
8682
+ const { purchase } = useSolvaPay();
8683
+ const currentKey = !productRef || !enabled ? null : cacheKey(customerRef, productRef, meterName);
8684
+ const [data, setData] = (0, import_react43.useState)(() => {
8685
+ if (!currentKey) return null;
8686
+ const cached = limitsCache.get(currentKey);
8687
+ if (!cached || Date.now() - cached.timestamp >= CACHE_TTL_MS) return null;
8688
+ return cached.data;
8689
+ });
8690
+ const [loading, setLoading] = (0, import_react43.useState)(() => {
8691
+ if (!currentKey) return false;
8692
+ const cached = limitsCache.get(currentKey);
8693
+ if (!cached) return true;
8694
+ if (cached.promise) return true;
8695
+ if (Date.now() - cached.timestamp >= CACHE_TTL_MS) return true;
8696
+ return false;
8697
+ });
8698
+ const [error, setError] = (0, import_react43.useState)(null);
8699
+ const [trackedKey, setTrackedKey] = (0, import_react43.useState)(currentKey);
8700
+ if (trackedKey !== currentKey) {
8701
+ setTrackedKey(currentKey);
8702
+ setData(null);
8703
+ }
8704
+ const optimisticTimerRef = (0, import_react43.useRef)(null);
8705
+ (0, import_react43.useEffect)(() => {
8706
+ return () => {
8707
+ if (optimisticTimerRef.current) clearTimeout(optimisticTimerRef.current);
8708
+ };
8709
+ }, []);
8710
+ const attachToFetch = (0, import_react43.useCallback)(
8711
+ async (promise) => {
8712
+ setLoading(true);
8713
+ try {
8714
+ const fresh = await promise;
8715
+ setData(fresh);
8716
+ setError(null);
8717
+ return fresh;
8718
+ } catch (err) {
8719
+ setError(err instanceof Error ? err : new Error("Failed to fetch limits"));
8720
+ return null;
8721
+ } finally {
8722
+ setLoading(false);
8723
+ }
8724
+ },
8725
+ []
8726
+ );
8727
+ const fetchLimits = (0, import_react43.useCallback)(
8728
+ async (force) => {
8729
+ if (!productRef || !enabled || !transport.getLimits) {
8730
+ setLoading(false);
8731
+ return;
8732
+ }
8733
+ const key = cacheKey(customerRef, productRef, meterName);
8734
+ const cached = limitsCache.get(key);
8735
+ const now = Date.now();
8736
+ if (cached?.promise) {
8737
+ await attachToFetch(cached.promise);
8738
+ return;
8739
+ }
8740
+ if (!force && cached?.data && now - cached.timestamp < CACHE_TTL_MS) {
8741
+ setData(cached.data);
8742
+ setLoading(false);
8743
+ setError(null);
8744
+ return;
8745
+ }
8746
+ const promise = transport.getLimits({ productRef, meterName });
8747
+ limitsCache.set(key, { data: cached?.data ?? null, timestamp: now, promise });
8748
+ const fresh = await attachToFetch(promise);
8749
+ if (fresh !== null) {
8750
+ limitsCache.set(key, { data: fresh, timestamp: Date.now(), promise: null });
8751
+ } else {
8752
+ limitsCache.delete(key);
8753
+ }
8754
+ },
8755
+ [transport, customerRef, productRef, meterName, enabled, attachToFetch]
8756
+ );
8757
+ (0, import_react43.useEffect)(() => {
8758
+ fetchLimits(false);
8759
+ }, [fetchLimits]);
8760
+ const prevPurchasesRef = (0, import_react43.useRef)(null);
8761
+ (0, import_react43.useEffect)(() => {
8762
+ if (prevPurchasesRef.current !== null && prevPurchasesRef.current !== purchase.purchases) {
8763
+ fetchLimits(true).catch(() => {
8764
+ });
8765
+ }
8766
+ prevPurchasesRef.current = purchase.purchases;
8767
+ }, [purchase.purchases, fetchLimits]);
8768
+ const refetch = (0, import_react43.useCallback)(() => fetchLimits(true), [fetchLimits]);
8769
+ const adjustRemaining = (0, import_react43.useCallback)(
8770
+ (delta) => {
8771
+ if (!productRef || !enabled) return;
8772
+ const key = cacheKey(customerRef, productRef, meterName);
8773
+ setData((prev) => {
8774
+ const cached = limitsCache.get(key);
8775
+ const baseline = prev ?? cached?.data ?? null;
8776
+ if (!baseline) return prev;
8777
+ const next = {
8778
+ ...baseline,
8779
+ remaining: Math.max(0, baseline.remaining + delta)
8780
+ // Don't optimistically flip `withinLimits` — paywall gating
8781
+ // can hinge on factors beyond `remaining > 0`
8782
+ // (activationRequired, etc.). Let the trailing refetch
8783
+ // confirm.
8784
+ };
8785
+ limitsCache.set(key, {
8786
+ data: next,
8787
+ timestamp: Date.now(),
8788
+ promise: cached?.promise ?? null
8789
+ });
8790
+ return next;
8791
+ });
8792
+ if (optimisticTimerRef.current) clearTimeout(optimisticTimerRef.current);
8793
+ optimisticTimerRef.current = setTimeout(() => {
8794
+ optimisticTimerRef.current = null;
8795
+ fetchLimits(true).catch(() => {
8796
+ });
8797
+ }, OPTIMISTIC_GRACE_MS);
8798
+ },
8799
+ [customerRef, productRef, meterName, enabled, fetchLimits]
8800
+ );
8801
+ return {
8802
+ remaining: data?.remaining ?? null,
8803
+ withinLimits: data?.withinLimits ?? null,
8804
+ meterName: data?.meterName ?? null,
8805
+ activationRequired: data?.activationRequired ?? null,
8806
+ loading,
8807
+ error,
8808
+ refetch,
8809
+ adjustRemaining
8810
+ };
8811
+ }
8812
+
8813
+ // src/hooks/useAutoActivateFreePlan.ts
8814
+ var import_react44 = require("react");
8815
+ function useAutoActivateFreePlan(options) {
8816
+ const { productRef, enabled = true, onActivated } = options;
8817
+ const { customerRef } = useCustomer();
8818
+ const { activationRequired, refetch: refetchLimits } = useLimits({
8819
+ productRef,
8820
+ enabled
8821
+ });
8822
+ const { plans } = usePlans({ productRef });
8823
+ const { activate, error: activationError } = useActivation();
8824
+ const freePlan = (0, import_react44.useMemo)(
8825
+ () => plans.find((p) => p.requiresPayment === false && (p.freeUnits ?? 0) > 0),
8826
+ [plans]
8827
+ );
8828
+ const attemptedKeyRef = (0, import_react44.useRef)(null);
8829
+ const [activated, setActivated] = (0, import_react44.useState)(false);
8830
+ const onActivatedRef = (0, import_react44.useRef)(onActivated);
8831
+ (0, import_react44.useEffect)(() => {
8832
+ onActivatedRef.current = onActivated;
8833
+ }, [onActivated]);
8834
+ (0, import_react44.useEffect)(() => {
8835
+ attemptedKeyRef.current = null;
8836
+ setActivated(false);
8837
+ }, [customerRef, productRef]);
8838
+ const shouldActivate = enabled && activationRequired === true && Boolean(productRef) && Boolean(freePlan?.reference);
8839
+ (0, import_react44.useEffect)(() => {
6990
8840
  if (!shouldActivate || !productRef || !freePlan?.reference) return;
6991
8841
  const key = `${customerRef ?? "anonymous"}:${productRef}`;
6992
8842
  if (attemptedKeyRef.current === key) return;
@@ -7011,7 +8861,7 @@ function useAutoActivateFreePlan(options) {
7011
8861
  }
7012
8862
 
7013
8863
  // src/hooks/usePaywallResolver.ts
7014
- var import_react43 = require("react");
8864
+ var import_react45 = require("react");
7015
8865
  function balanceCoversNextUnit(balance, credits) {
7016
8866
  if (!balance) return false;
7017
8867
  if (typeof balance.remainingUnits === "number" && balance.remainingUnits > 0) {
@@ -7025,7 +8875,7 @@ function balanceCoversNextUnit(balance, credits) {
7025
8875
  function usePaywallResolver(content) {
7026
8876
  const { activePurchase, hasPaidPurchase, refetch: refetchPurchase } = usePurchase();
7027
8877
  const { credits, refetch: refetchBalance } = useBalance();
7028
- const resolved = (0, import_react43.useMemo)(() => {
8878
+ const resolved = (0, import_react45.useMemo)(() => {
7029
8879
  if (!content) return false;
7030
8880
  const productMatches = !content.product || activePurchase?.productRef === content.product || activePurchase?.productName === content.product;
7031
8881
  if (content.kind === "payment_required") {
@@ -7035,7 +8885,7 @@ function usePaywallResolver(content) {
7035
8885
  if (balanceCoversNextUnit(content.balance, credits)) return true;
7036
8886
  return Boolean(productMatches && activePurchase?.status === "active");
7037
8887
  }, [content, hasPaidPurchase, activePurchase, credits]);
7038
- const refetch = (0, import_react43.useCallback)(async () => {
8888
+ const refetch = (0, import_react45.useCallback)(async () => {
7039
8889
  await Promise.all([
7040
8890
  refetchPurchase().catch(() => void 0),
7041
8891
  refetchBalance().catch(() => void 0)
@@ -7045,7 +8895,7 @@ function usePaywallResolver(content) {
7045
8895
  }
7046
8896
 
7047
8897
  // src/hooks/useCheckoutFlow.ts
7048
- var import_react44 = require("react");
8898
+ var import_react46 = require("react");
7049
8899
 
7050
8900
  // src/primitives/checkout/shared.ts
7051
8901
  function isPayg(plan) {
@@ -7108,10 +8958,10 @@ function useCheckoutFlow(opts) {
7108
8958
  initialStep = "plan",
7109
8959
  initialAmountMinor = null
7110
8960
  } = opts;
7111
- const onPlanSelectRef = (0, import_react44.useRef)(opts.onPlanSelect);
7112
- const onAmountSelectRef = (0, import_react44.useRef)(opts.onAmountSelect);
7113
- const onPurchaseSuccessRef = (0, import_react44.useRef)(opts.onPurchaseSuccess);
7114
- const onErrorRef = (0, import_react44.useRef)(opts.onError);
8961
+ const onPlanSelectRef = (0, import_react46.useRef)(opts.onPlanSelect);
8962
+ const onAmountSelectRef = (0, import_react46.useRef)(opts.onAmountSelect);
8963
+ const onPurchaseSuccessRef = (0, import_react46.useRef)(opts.onPurchaseSuccess);
8964
+ const onErrorRef = (0, import_react46.useRef)(opts.onError);
7115
8965
  onPlanSelectRef.current = opts.onPlanSelect;
7116
8966
  onAmountSelectRef.current = opts.onAmountSelect;
7117
8967
  onPurchaseSuccessRef.current = opts.onPurchaseSuccess;
@@ -7124,8 +8974,8 @@ function useCheckoutFlow(opts) {
7124
8974
  const { creditsPerMinorUnit, displayExchangeRate, adjustBalance } = balance;
7125
8975
  const { refetchPurchase } = useSolvaPay();
7126
8976
  const { merchant } = useMerchant();
7127
- const [topupCurrencyOverride, setTopupCurrencyOverride] = (0, import_react44.useState)(null);
7128
- const topupCurrencies = (0, import_react44.useMemo)(() => {
8977
+ const [topupCurrencyOverride, setTopupCurrencyOverride] = (0, import_react46.useState)(null);
8978
+ const topupCurrencies = (0, import_react46.useMemo)(() => {
7129
8979
  const fromMerchant = (merchant?.supportedTopupCurrencies ?? []).map((code) => code.toUpperCase()).filter(Boolean);
7130
8980
  const fallback = opts.topupCurrency?.toUpperCase() ?? merchant?.defaultCurrency?.toUpperCase() ?? null;
7131
8981
  const list = fromMerchant.length > 0 ? fromMerchant : fallback ? [fallback] : [];
@@ -7135,25 +8985,25 @@ function useCheckoutFlow(opts) {
7135
8985
  const planPickerCurrency = planCtx.preferredCurrency?.toUpperCase() ?? null;
7136
8986
  const topupCurrency = (topupCurrencyOverride && topupCurrencies.includes(topupCurrencyOverride) ? topupCurrencyOverride : null) ?? (planPickerCurrency && topupCurrencies.includes(planPickerCurrency) ? planPickerCurrency : null) ?? resolvedDefaultTopupCurrency;
7137
8987
  const topupCurrencyReady = topupCurrency != null;
7138
- const setTopupCurrency = (0, import_react44.useCallback)(
8988
+ const setTopupCurrency = (0, import_react46.useCallback)(
7139
8989
  (code) => {
7140
8990
  const normalized = code.toUpperCase();
7141
8991
  setTopupCurrencyOverride(normalized);
7142
8992
  },
7143
8993
  []
7144
8994
  );
7145
- const [step, setStep] = (0, import_react44.useState)(initialStep);
7146
- const [status, setStatus] = (0, import_react44.useState)("idle");
7147
- const [selectedAmountMinor, setSelectedAmountMinor] = (0, import_react44.useState)(initialAmountMinor);
7148
- const [successMeta, setSuccessMeta] = (0, import_react44.useState)(null);
7149
- const [error, setError] = (0, import_react44.useState)(null);
7150
- const selectedAmountMinorRef = (0, import_react44.useRef)(initialAmountMinor);
8995
+ const [step, setStep] = (0, import_react46.useState)(initialStep);
8996
+ const [status, setStatus] = (0, import_react46.useState)("idle");
8997
+ const [selectedAmountMinor, setSelectedAmountMinor] = (0, import_react46.useState)(initialAmountMinor);
8998
+ const [successMeta, setSuccessMeta] = (0, import_react46.useState)(null);
8999
+ const [error, setError] = (0, import_react46.useState)(null);
9000
+ const selectedAmountMinorRef = (0, import_react46.useRef)(initialAmountMinor);
7151
9001
  const selectedPlan = planCtx.selectedPlan;
7152
9002
  const selectedPlanRef = planCtx.selectedPlanRef;
7153
9003
  const selectedPlanShape = selectedPlan;
7154
9004
  const branch = selectedPlanShape ? isPayg(selectedPlanShape) ? "payg" : "recurring" : null;
7155
9005
  const canGoBack = step === "amount" || step === "payment";
7156
- const selectPlan = (0, import_react44.useCallback)(
9006
+ const selectPlan = (0, import_react46.useCallback)(
7157
9007
  (ref) => {
7158
9008
  planCtx.select(ref);
7159
9009
  const plan = planCtx.plans.find((p) => p.reference === ref) ?? null;
@@ -7163,7 +9013,7 @@ function useCheckoutFlow(opts) {
7163
9013
  },
7164
9014
  [planCtx]
7165
9015
  );
7166
- const selectAmount = (0, import_react44.useCallback)(
9016
+ const selectAmount = (0, import_react46.useCallback)(
7167
9017
  (amountMinor) => {
7168
9018
  selectedAmountMinorRef.current = amountMinor;
7169
9019
  setSelectedAmountMinor(amountMinor);
@@ -7172,7 +9022,7 @@ function useCheckoutFlow(opts) {
7172
9022
  },
7173
9023
  [topupCurrency]
7174
9024
  );
7175
- const runActivate = (0, import_react44.useCallback)(async () => {
9025
+ const runActivate = (0, import_react46.useCallback)(async () => {
7176
9026
  if (!selectedPlanShape || !selectedPlanRef) return false;
7177
9027
  setError(null);
7178
9028
  setStatus("activating");
@@ -7189,7 +9039,7 @@ function useCheckoutFlow(opts) {
7189
9039
  return false;
7190
9040
  }
7191
9041
  }, [productRef, selectedPlanRef, selectedPlanShape, transport]);
7192
- const advanceFromPlan = (0, import_react44.useCallback)(async () => {
9042
+ const advanceFromPlan = (0, import_react46.useCallback)(async () => {
7193
9043
  if (!selectedPlanShape || !selectedPlanRef) return;
7194
9044
  if (branch === "payg") {
7195
9045
  if (planCtx.currentPlanRef === selectedPlanRef) {
@@ -7203,7 +9053,7 @@ function useCheckoutFlow(opts) {
7203
9053
  setError(null);
7204
9054
  setStep("payment");
7205
9055
  }, [branch, planCtx.currentPlanRef, runActivate, selectedPlanRef, selectedPlanShape]);
7206
- const recordPaygSuccess = (0, import_react44.useCallback)(
9056
+ const recordPaygSuccess = (0, import_react46.useCallback)(
7207
9057
  (creditsAddedFromBackend) => {
7208
9058
  if (!selectedPlanShape || selectedAmountMinor == null) return;
7209
9059
  const currency = topupCurrency ?? "USD";
@@ -7237,7 +9087,7 @@ function useCheckoutFlow(opts) {
7237
9087
  topupCurrency
7238
9088
  ]
7239
9089
  );
7240
- const recordRecurringSuccess = (0, import_react44.useCallback)(() => {
9090
+ const recordRecurringSuccess = (0, import_react46.useCallback)(() => {
7241
9091
  if (!selectedPlanShape) return;
7242
9092
  const pricingOption = selectedPlan ? resolvePlanPricingOption(selectedPlan, planSelection?.selectedCurrency) : {
7243
9093
  currency: selectedPlanShape.currency ?? "USD",
@@ -7256,7 +9106,7 @@ function useCheckoutFlow(opts) {
7256
9106
  setStep("success");
7257
9107
  onPurchaseSuccessRef.current?.(meta);
7258
9108
  }, [selectedPlanShape, selectedPlan, planSelection?.selectedCurrency]);
7259
- const advance = (0, import_react44.useCallback)(async () => {
9109
+ const advance = (0, import_react46.useCallback)(async () => {
7260
9110
  if (step === "plan") {
7261
9111
  await advanceFromPlan();
7262
9112
  return;
@@ -7283,7 +9133,7 @@ function useCheckoutFlow(opts) {
7283
9133
  selectedAmountMinor,
7284
9134
  step
7285
9135
  ]);
7286
- const back = (0, import_react44.useCallback)(() => {
9136
+ const back = (0, import_react46.useCallback)(() => {
7287
9137
  setError(null);
7288
9138
  if (step === "amount") {
7289
9139
  setStep("plan");
@@ -7294,7 +9144,7 @@ function useCheckoutFlow(opts) {
7294
9144
  return;
7295
9145
  }
7296
9146
  }, [branch, step]);
7297
- const reset = (0, import_react44.useCallback)(() => {
9147
+ const reset = (0, import_react46.useCallback)(() => {
7298
9148
  setStep("plan");
7299
9149
  selectedAmountMinorRef.current = null;
7300
9150
  setSelectedAmountMinor(null);
@@ -7303,13 +9153,13 @@ function useCheckoutFlow(opts) {
7303
9153
  setStatus("idle");
7304
9154
  setTopupCurrencyOverride(null);
7305
9155
  }, []);
7306
- const retry = (0, import_react44.useCallback)(async () => {
9156
+ const retry = (0, import_react46.useCallback)(async () => {
7307
9157
  if (status !== "error") return;
7308
9158
  if (step === "plan" && branch === "payg") {
7309
9159
  await runActivate();
7310
9160
  }
7311
9161
  }, [branch, runActivate, status, step]);
7312
- const notifyPaymentSuccess = (0, import_react44.useCallback)(
9162
+ const notifyPaymentSuccess = (0, import_react46.useCallback)(
7313
9163
  (_intent, extras) => {
7314
9164
  if (branch === "payg") {
7315
9165
  recordPaygSuccess(extras?.creditsAdded);
@@ -7319,7 +9169,7 @@ function useCheckoutFlow(opts) {
7319
9169
  },
7320
9170
  [branch, recordPaygSuccess, recordRecurringSuccess]
7321
9171
  );
7322
- return (0, import_react44.useMemo)(
9172
+ return (0, import_react46.useMemo)(
7323
9173
  () => ({
7324
9174
  step,
7325
9175
  status,
@@ -7368,36 +9218,36 @@ function useCheckoutFlow(opts) {
7368
9218
  }
7369
9219
 
7370
9220
  // src/primitives/checkout/index.tsx
7371
- var import_react46 = require("react");
9221
+ var import_react48 = require("react");
7372
9222
 
7373
9223
  // src/primitives/PaywallNotice.tsx
7374
- var import_react45 = require("react");
7375
- var import_jsx_runtime36 = require("react/jsx-runtime");
7376
- var PaywallNoticeContext = (0, import_react45.createContext)(null);
9224
+ var import_react47 = require("react");
9225
+ var import_jsx_runtime38 = require("react/jsx-runtime");
9226
+ var PaywallNoticeContext = (0, import_react47.createContext)(null);
7377
9227
  function usePaywallNoticeCtx(part) {
7378
- const ctx = (0, import_react45.useContext)(PaywallNoticeContext);
9228
+ const ctx = (0, import_react47.useContext)(PaywallNoticeContext);
7379
9229
  if (!ctx) {
7380
9230
  throw new Error(`PaywallNotice.${part} must be rendered inside <PaywallNotice.Root>.`);
7381
9231
  }
7382
9232
  return ctx;
7383
9233
  }
7384
- var Root11 = (0, import_react45.forwardRef)(function PaywallNoticeRoot({ content, onResolved, classNames, asChild, children, ...rest }, forwardedRef) {
9234
+ var Root12 = (0, import_react47.forwardRef)(function PaywallNoticeRoot({ content, onResolved, classNames, asChild, children, ...rest }, forwardedRef) {
7385
9235
  const { resolved, refetch } = usePaywallResolver(content);
7386
- const classNamesResolved = (0, import_react45.useMemo)(() => classNames ?? {}, [classNames]);
7387
- const onResolvedRef = (0, import_react45.useRef)(onResolved);
7388
- (0, import_react45.useEffect)(() => {
9236
+ const classNamesResolved = (0, import_react47.useMemo)(() => classNames ?? {}, [classNames]);
9237
+ const onResolvedRef = (0, import_react47.useRef)(onResolved);
9238
+ (0, import_react47.useEffect)(() => {
7389
9239
  onResolvedRef.current = onResolved;
7390
9240
  }, [onResolved]);
7391
- const hasResolvedRef = (0, import_react45.useRef)(false);
7392
- const signalResolved = (0, import_react45.useCallback)(() => {
9241
+ const hasResolvedRef = (0, import_react47.useRef)(false);
9242
+ const signalResolved = (0, import_react47.useCallback)(() => {
7393
9243
  if (hasResolvedRef.current) return;
7394
9244
  hasResolvedRef.current = true;
7395
9245
  onResolvedRef.current?.();
7396
9246
  }, []);
7397
- (0, import_react45.useEffect)(() => {
9247
+ (0, import_react47.useEffect)(() => {
7398
9248
  if (resolved) signalResolved();
7399
9249
  }, [resolved, signalResolved]);
7400
- const ctx = (0, import_react45.useMemo)(
9250
+ const ctx = (0, import_react47.useMemo)(
7401
9251
  () => ({
7402
9252
  content,
7403
9253
  resolved,
@@ -7408,7 +9258,7 @@ var Root11 = (0, import_react45.forwardRef)(function PaywallNoticeRoot({ content
7408
9258
  [content, resolved, refetch, signalResolved, classNamesResolved]
7409
9259
  );
7410
9260
  const Comp = asChild ? Slot : "div";
7411
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(PaywallNoticeContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
9261
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(PaywallNoticeContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
7412
9262
  Comp,
7413
9263
  {
7414
9264
  ref: forwardedRef,
@@ -7421,12 +9271,12 @@ var Root11 = (0, import_react45.forwardRef)(function PaywallNoticeRoot({ content
7421
9271
  }
7422
9272
  ) });
7423
9273
  });
7424
- var Heading4 = (0, import_react45.forwardRef)(function PaywallNoticeHeading({ asChild, children, className, ...rest }, forwardedRef) {
9274
+ var Heading4 = (0, import_react47.forwardRef)(function PaywallNoticeHeading({ asChild, children, className, ...rest }, forwardedRef) {
7425
9275
  const ctx = usePaywallNoticeCtx("Heading");
7426
9276
  const copy = useCopy();
7427
9277
  const defaultText = ctx.resolved ? copy.paywall.resolvedHeading : ctx.content.kind === "payment_required" ? copy.paywall.paymentRequiredHeading : isTopupGate(ctx.content) ? copy.paywall.topupRequiredHeading : copy.paywall.activationRequiredHeading;
7428
9278
  const Comp = asChild ? Slot : "h2";
7429
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
9279
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
7430
9280
  Comp,
7431
9281
  {
7432
9282
  ref: forwardedRef,
@@ -7437,12 +9287,12 @@ var Heading4 = (0, import_react45.forwardRef)(function PaywallNoticeHeading({ as
7437
9287
  }
7438
9288
  );
7439
9289
  });
7440
- var Message = (0, import_react45.forwardRef)(function PaywallNoticeMessage({ asChild, children, className, ...rest }, forwardedRef) {
9290
+ var Message = (0, import_react47.forwardRef)(function PaywallNoticeMessage({ asChild, children, className, ...rest }, forwardedRef) {
7441
9291
  const ctx = usePaywallNoticeCtx("Message");
7442
9292
  const copy = useCopy();
7443
9293
  const Comp = asChild ? Slot : "p";
7444
9294
  const defaultText = resolvePaywallMessage(ctx.content, copy.paywall);
7445
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
9295
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
7446
9296
  Comp,
7447
9297
  {
7448
9298
  ref: forwardedRef,
@@ -7485,14 +9335,14 @@ function resolvePaywallMessage(content, paywallCopy) {
7485
9335
  }
7486
9336
  return content.message ?? "";
7487
9337
  }
7488
- var ProductContext = (0, import_react45.forwardRef)(function PaywallNoticeProductContext({ asChild, children, className, ...rest }, forwardedRef) {
9338
+ var ProductContext = (0, import_react47.forwardRef)(function PaywallNoticeProductContext({ asChild, children, className, ...rest }, forwardedRef) {
7489
9339
  const ctx = usePaywallNoticeCtx("ProductContext");
7490
9340
  const copy = useCopy();
7491
9341
  const product = ctx.content.kind === "activation_required" ? ctx.content.productDetails : void 0;
7492
9342
  if (!product?.name) return null;
7493
9343
  const label = interpolate(copy.paywall.productContext, { product: product.name });
7494
9344
  const Comp = asChild ? Slot : "div";
7495
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
9345
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
7496
9346
  Comp,
7497
9347
  {
7498
9348
  ref: forwardedRef,
@@ -7503,7 +9353,7 @@ var ProductContext = (0, import_react45.forwardRef)(function PaywallNoticeProduc
7503
9353
  }
7504
9354
  );
7505
9355
  });
7506
- var Balance = (0, import_react45.forwardRef)(function PaywallNoticeBalance({ asChild, children, className, ...rest }, forwardedRef) {
9356
+ var Balance = (0, import_react47.forwardRef)(function PaywallNoticeBalance({ asChild, children, className, ...rest }, forwardedRef) {
7507
9357
  const ctx = usePaywallNoticeCtx("Balance");
7508
9358
  const copy = useCopy();
7509
9359
  const balance = ctx.content.balance;
@@ -7513,7 +9363,7 @@ var Balance = (0, import_react45.forwardRef)(function PaywallNoticeBalance({ asC
7513
9363
  required: String(balance.creditsPerUnit ?? 1)
7514
9364
  });
7515
9365
  const Comp = asChild ? Slot : "div";
7516
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
9366
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
7517
9367
  Comp,
7518
9368
  {
7519
9369
  ref: forwardedRef,
@@ -7529,27 +9379,27 @@ function Plans({ className, children }) {
7529
9379
  if (ctx.content.kind !== "activation_required") return null;
7530
9380
  if (!ctx.content.product) return null;
7531
9381
  const defaultClass = className ?? ctx.classNames.plans ?? "solvapay-paywall-plans";
7532
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { "data-solvapay-paywall-plans": "", className: defaultClass, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(PlanSelector.Root, { productRef: ctx.content.product, filter: hidesFreePlan, children: children ?? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
7533
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(PlanSelector.Grid, { children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(PlanSelector.Card, { children: [
7534
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(PlanSelector.CardBadge, {}),
7535
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(PlanSelector.CardName, {}),
7536
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(PlanSelector.CardPrice, {}),
7537
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(PlanSelector.CardInterval, {})
9382
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { "data-solvapay-paywall-plans": "", className: defaultClass, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(PlanSelector.Root, { productRef: ctx.content.product, filter: hidesFreePlan, children: children ?? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_jsx_runtime38.Fragment, { children: [
9383
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(PlanSelector.Grid, { children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(PlanSelector.Card, { children: [
9384
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(PlanSelector.CardBadge, {}),
9385
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(PlanSelector.CardName, {}),
9386
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(PlanSelector.CardPrice, {}),
9387
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(PlanSelector.CardInterval, {})
7538
9388
  ] }) }),
7539
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(PlanSelector.Loading, {}),
7540
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(PlanSelector.Error, {})
9389
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(PlanSelector.Loading, {}),
9390
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(PlanSelector.Error, {})
7541
9391
  ] }) }) });
7542
9392
  }
7543
9393
  function hidesFreePlan(plan) {
7544
9394
  return plan.requiresPayment !== false;
7545
9395
  }
7546
- var HostedCheckoutLink = (0, import_react45.forwardRef)(function PaywallNoticeHostedCheckoutLink({ asChild, children, className, ...rest }, forwardedRef) {
9396
+ var HostedCheckoutLink = (0, import_react47.forwardRef)(function PaywallNoticeHostedCheckoutLink({ asChild, children, className, ...rest }, forwardedRef) {
7547
9397
  const ctx = usePaywallNoticeCtx("HostedCheckoutLink");
7548
9398
  const copy = useCopy();
7549
9399
  const href = ctx.content.checkoutUrl;
7550
9400
  if (!href) return null;
7551
9401
  const Comp = asChild ? Slot : "a";
7552
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
9402
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
7553
9403
  Comp,
7554
9404
  {
7555
9405
  ref: forwardedRef,
@@ -7567,12 +9417,12 @@ function EmbeddedCheckout({ returnUrl, topupCurrency, className }) {
7567
9417
  const ctx = usePaywallNoticeCtx("EmbeddedCheckout");
7568
9418
  const productRef = ctx.content.product;
7569
9419
  const { plans } = usePlans({ productRef: productRef ?? void 0 });
7570
- const filter = (0, import_react45.useMemo)(() => buildDefaultCheckoutPlanFilter(plans), [plans]);
9420
+ const filter = (0, import_react47.useMemo)(() => buildDefaultCheckoutPlanFilter(plans), [plans]);
7571
9421
  if (!productRef) return null;
7572
9422
  const resolvedClassName = className ?? ctx.classNames.embeddedCheckout ?? "solvapay-paywall-embedded-checkout";
7573
9423
  const headingClassName = ctx.classNames.heading ?? "solvapay-paywall-step-heading";
7574
9424
  const messageClassName = ctx.classNames.message ?? "solvapay-paywall-step-message";
7575
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
9425
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
7576
9426
  CheckoutSteps.Root,
7577
9427
  {
7578
9428
  productRef,
@@ -7585,33 +9435,33 @@ function EmbeddedCheckout({ returnUrl, topupCurrency, className }) {
7585
9435
  },
7586
9436
  className: resolvedClassName,
7587
9437
  children: [
7588
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(CheckoutSteps.StepHeading, { className: headingClassName }),
7589
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(CheckoutSteps.StepMessage, { className: messageClassName }),
7590
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(CheckoutSteps.IfStep, { step: "plan", children: [
7591
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(CheckoutSteps.PlanGrid, {}),
7592
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(PlanSelector.Loading, {}),
7593
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(PlanSelector.Error, {}),
7594
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(CheckoutSteps.PlanContinueButton, {})
9438
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(CheckoutSteps.StepHeading, { className: headingClassName }),
9439
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(CheckoutSteps.StepMessage, { className: messageClassName }),
9440
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(CheckoutSteps.IfStep, { step: "plan", children: [
9441
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(CheckoutSteps.PlanGrid, {}),
9442
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(PlanSelector.Loading, {}),
9443
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(PlanSelector.Error, {}),
9444
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(CheckoutSteps.PlanContinueButton, {})
7595
9445
  ] }),
7596
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(CheckoutSteps.IfStep, { step: "amount", children: [
7597
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(CheckoutSteps.BackLink, {}),
7598
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(CheckoutSteps.AmountPicker, {}),
7599
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(CheckoutSteps.AmountContinueButton, {})
9446
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(CheckoutSteps.IfStep, { step: "amount", children: [
9447
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(CheckoutSteps.BackLink, {}),
9448
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(CheckoutSteps.AmountPicker, {}),
9449
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(CheckoutSteps.AmountContinueButton, {})
7600
9450
  ] }),
7601
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(CheckoutSteps.IfStep, { step: "payment", children: [
7602
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(CheckoutSteps.BackLink, {}),
7603
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(CheckoutSteps.Payment, {})
9451
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(CheckoutSteps.IfStep, { step: "payment", children: [
9452
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(CheckoutSteps.BackLink, {}),
9453
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(CheckoutSteps.Payment, {})
7604
9454
  ] }),
7605
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(CheckoutSteps.IfStep, { step: "success", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(CheckoutSteps.Success, {}) })
9455
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(CheckoutSteps.IfStep, { step: "success", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(CheckoutSteps.Success, {}) })
7606
9456
  ]
7607
9457
  }
7608
9458
  );
7609
9459
  }
7610
- var Retry = (0, import_react45.forwardRef)(function PaywallNoticeRetry({ asChild, children, className, onClick, ...rest }, forwardedRef) {
9460
+ var Retry = (0, import_react47.forwardRef)(function PaywallNoticeRetry({ asChild, children, className, onClick, ...rest }, forwardedRef) {
7611
9461
  const ctx = usePaywallNoticeCtx("Retry");
7612
9462
  const copy = useCopy();
7613
9463
  const Comp = asChild ? Slot : "button";
7614
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
9464
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
7615
9465
  Comp,
7616
9466
  {
7617
9467
  ref: forwardedRef,
@@ -7629,8 +9479,8 @@ var Retry = (0, import_react45.forwardRef)(function PaywallNoticeRetry({ asChild
7629
9479
  }
7630
9480
  );
7631
9481
  });
7632
- var PaywallNotice = Object.assign(Root11, {
7633
- Root: Root11,
9482
+ var PaywallNotice = Object.assign(Root12, {
9483
+ Root: Root12,
7634
9484
  Heading: Heading4,
7635
9485
  Message,
7636
9486
  ProductContext,
@@ -7641,14 +9491,14 @@ var PaywallNotice = Object.assign(Root11, {
7641
9491
  Retry
7642
9492
  });
7643
9493
  function usePaywallNoticeOptional() {
7644
- return (0, import_react45.useContext)(PaywallNoticeContext);
9494
+ return (0, import_react47.useContext)(PaywallNoticeContext);
7645
9495
  }
7646
9496
 
7647
9497
  // src/primitives/checkout/index.tsx
7648
- var import_jsx_runtime37 = require("react/jsx-runtime");
7649
- var CheckoutContext = (0, import_react46.createContext)(null);
9498
+ var import_jsx_runtime39 = require("react/jsx-runtime");
9499
+ var CheckoutContext = (0, import_react48.createContext)(null);
7650
9500
  function useCheckoutContext(part) {
7651
- const ctx = (0, import_react46.useContext)(CheckoutContext);
9501
+ const ctx = (0, import_react48.useContext)(CheckoutContext);
7652
9502
  if (!ctx) {
7653
9503
  throw new Error(`CheckoutSteps.${part} must be rendered inside <CheckoutSteps.Root>.`);
7654
9504
  }
@@ -7657,7 +9507,7 @@ function useCheckoutContext(part) {
7657
9507
  function useCheckoutSteps() {
7658
9508
  return useCheckoutContext("useCheckoutSteps");
7659
9509
  }
7660
- var Root12 = (0, import_react46.forwardRef)(function CheckoutStepsRoot(props, forwardedRef) {
9510
+ var Root13 = (0, import_react48.forwardRef)(function CheckoutStepsRoot(props, forwardedRef) {
7661
9511
  const {
7662
9512
  productRef,
7663
9513
  returnUrl: _returnUrl,
@@ -7679,9 +9529,9 @@ var Root12 = (0, import_react46.forwardRef)(function CheckoutStepsRoot(props, fo
7679
9529
  children
7680
9530
  } = props;
7681
9531
  if (externalFlow) {
7682
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { ref: forwardedRef, "data-solvapay-checkout": "", className, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(CheckoutContext.Provider, { value: externalFlow, children }) });
9532
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { ref: forwardedRef, "data-solvapay-checkout": "", className, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(CheckoutContext.Provider, { value: externalFlow, children }) });
7683
9533
  }
7684
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
9534
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
7685
9535
  RootWithPlanSelector,
7686
9536
  {
7687
9537
  productRef,
@@ -7724,11 +9574,11 @@ function RootWithPlanSelector({
7724
9574
  children
7725
9575
  }) {
7726
9576
  const { plans } = usePlans({ productRef });
7727
- const resolvedFilter = (0, import_react46.useMemo)(
9577
+ const resolvedFilter = (0, import_react48.useMemo)(
7728
9578
  () => filter ?? buildDefaultCheckoutPlanFilter(plans),
7729
9579
  [filter, plans]
7730
9580
  );
7731
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
9581
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
7732
9582
  PlanSelector.Root,
7733
9583
  {
7734
9584
  productRef,
@@ -7738,7 +9588,7 @@ function RootWithPlanSelector({
7738
9588
  currentPlanRef,
7739
9589
  autoSelectFirstPaid,
7740
9590
  initialPlanRef,
7741
- children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
9591
+ children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
7742
9592
  FlowProvider,
7743
9593
  {
7744
9594
  productRef,
@@ -7780,22 +9630,22 @@ function FlowProvider({
7780
9630
  onPurchaseSuccess,
7781
9631
  onError
7782
9632
  });
7783
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { ref: forwardedRef, "data-solvapay-checkout": "", "data-step": flow.step, className, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(CheckoutContext.Provider, { value: flow, children }) });
9633
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { ref: forwardedRef, "data-solvapay-checkout": "", "data-step": flow.step, className, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(CheckoutContext.Provider, { value: flow, children }) });
7784
9634
  }
7785
9635
  function IfStep({ step, children }) {
7786
9636
  const flow = useCheckoutContext("IfStep");
7787
9637
  const matches = Array.isArray(step) ? step.includes(flow.step) : flow.step === step;
7788
9638
  if (!matches) return null;
7789
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_jsx_runtime37.Fragment, { children });
9639
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_jsx_runtime39.Fragment, { children });
7790
9640
  }
7791
- var StepHeading = (0, import_react46.forwardRef)(function CheckoutStepsStepHeading({ asChild, children, className, ...rest }, forwardedRef) {
9641
+ var StepHeading = (0, import_react48.forwardRef)(function CheckoutStepsStepHeading({ asChild, children, className, ...rest }, forwardedRef) {
7792
9642
  const flow = useCheckoutContext("StepHeading");
7793
9643
  const copy = useCopy();
7794
9644
  const paywallCtx = usePaywallNoticeOptional();
7795
9645
  if (flow.step === "success") return null;
7796
9646
  const defaultText = resolveStepHeading(flow.step, copy, paywallCtx?.content ?? null);
7797
9647
  const Comp = asChild ? Slot : "h3";
7798
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
9648
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
7799
9649
  Comp,
7800
9650
  {
7801
9651
  ref: forwardedRef,
@@ -7807,7 +9657,7 @@ var StepHeading = (0, import_react46.forwardRef)(function CheckoutStepsStepHeadi
7807
9657
  }
7808
9658
  );
7809
9659
  });
7810
- var StepMessage = (0, import_react46.forwardRef)(function CheckoutStepsStepMessage({ asChild, children, className, ...rest }, forwardedRef) {
9660
+ var StepMessage = (0, import_react48.forwardRef)(function CheckoutStepsStepMessage({ asChild, children, className, ...rest }, forwardedRef) {
7811
9661
  const flow = useCheckoutContext("StepMessage");
7812
9662
  const copy = useCopy();
7813
9663
  const paywallCtx = usePaywallNoticeOptional();
@@ -7815,7 +9665,7 @@ var StepMessage = (0, import_react46.forwardRef)(function CheckoutStepsStepMessa
7815
9665
  const defaultText = resolveStepMessage(flow, copy, paywallCtx?.content ?? null);
7816
9666
  if (!defaultText && children == null) return null;
7817
9667
  const Comp = asChild ? Slot : "p";
7818
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
9668
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
7819
9669
  Comp,
7820
9670
  {
7821
9671
  ref: forwardedRef,
@@ -7862,21 +9712,21 @@ function resolveStepMessage(flow, copy, content) {
7862
9712
  return "";
7863
9713
  }
7864
9714
  function PlanGrid({ className, children }) {
7865
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(PlanSelector.Grid, { className: className ?? "solvapay-checkout-plan-grid", children: children ?? /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(PlanSelector.Card, { className: "solvapay-checkout-plan-card", children: [
7866
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(PlanSelector.CardBadge, { className: "solvapay-checkout-plan-card-badge" }),
7867
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(PlanSelector.CardName, { className: "solvapay-checkout-plan-card-name" }),
7868
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(PlanSelector.CardPrice, { className: "solvapay-checkout-plan-card-price" }),
7869
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(PlanSelector.CardInterval, { className: "solvapay-checkout-plan-card-interval" })
9715
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(PlanSelector.Grid, { className: className ?? "solvapay-checkout-plan-grid", children: children ?? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(PlanSelector.Card, { className: "solvapay-checkout-plan-card", children: [
9716
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(PlanSelector.CardBadge, { className: "solvapay-checkout-plan-card-badge" }),
9717
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(PlanSelector.CardName, { className: "solvapay-checkout-plan-card-name" }),
9718
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(PlanSelector.CardPrice, { className: "solvapay-checkout-plan-card-price" }),
9719
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(PlanSelector.CardInterval, { className: "solvapay-checkout-plan-card-interval" })
7870
9720
  ] }) });
7871
9721
  }
7872
- var PlanContinueButton = (0, import_react46.forwardRef)(
9722
+ var PlanContinueButton = (0, import_react48.forwardRef)(
7873
9723
  function PlanContinueButton2({ className, children, onClick, disabled, ...rest }, ref) {
7874
9724
  const flow = useCheckoutContext("PlanContinueButton");
7875
9725
  const locale = useLocale();
7876
9726
  const selectedPlanShape = flow.selectedPlan;
7877
9727
  const isDisabled = disabled || !flow.selectedPlanRef || flow.status === "activating";
7878
9728
  const label = children ?? formatContinueLabel(selectedPlanShape, locale);
7879
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
9729
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
7880
9730
  "button",
7881
9731
  {
7882
9732
  ref,
@@ -7899,13 +9749,13 @@ var PlanContinueButton = (0, import_react46.forwardRef)(
7899
9749
  function AmountPicker3({ className, children }) {
7900
9750
  const flow = useCheckoutContext("AmountPicker");
7901
9751
  if (!flow.topupCurrencyReady || flow.topupCurrency == null) {
7902
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
9752
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
7903
9753
  "div",
7904
9754
  {
7905
9755
  className: className ?? "solvapay-amount-picker",
7906
9756
  "data-state": "loading",
7907
9757
  "aria-busy": "true",
7908
- children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "solvapay-amount-picker-pills", children: [0, 1, 2, 3].map((i) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
9758
+ children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "solvapay-amount-picker-pills", children: [0, 1, 2, 3].map((i) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
7909
9759
  "span",
7910
9760
  {
7911
9761
  className: "solvapay-amount-picker-pill",
@@ -7917,7 +9767,7 @@ function AmountPicker3({ className, children }) {
7917
9767
  }
7918
9768
  );
7919
9769
  }
7920
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
9770
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
7921
9771
  AmountPicker.Root,
7922
9772
  {
7923
9773
  currency: flow.topupCurrency,
@@ -7928,16 +9778,16 @@ function AmountPicker3({ className, children }) {
7928
9778
  flow.selectAmount(value);
7929
9779
  }
7930
9780
  },
7931
- children: children ?? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(DefaultAmountTree, {})
9781
+ children: children ?? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(DefaultAmountTree, {})
7932
9782
  }
7933
9783
  );
7934
9784
  }
7935
9785
  function DefaultAmountTree() {
7936
9786
  const ctx = useAmountPicker();
7937
9787
  const { selectAmountLabel, customAmountLabel, creditEstimate } = useAmountPickerCopy();
7938
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_jsx_runtime37.Fragment, { children: [
7939
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "solvapay-amount-picker-label", children: selectAmountLabel }),
7940
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "solvapay-amount-picker-pills", children: ctx.quickAmounts.map((amount) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
9788
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_jsx_runtime39.Fragment, { children: [
9789
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { className: "solvapay-amount-picker-label", children: selectAmountLabel }),
9790
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "solvapay-amount-picker-pills", children: ctx.quickAmounts.map((amount) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
7941
9791
  AmountPicker.Option,
7942
9792
  {
7943
9793
  amount,
@@ -7945,11 +9795,11 @@ function DefaultAmountTree() {
7945
9795
  },
7946
9796
  amount
7947
9797
  )) }),
7948
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "solvapay-amount-picker-custom-wrapper", children: [
7949
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "solvapay-amount-picker-custom-label", children: customAmountLabel }),
7950
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "solvapay-amount-picker-custom-row", children: [
7951
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "solvapay-amount-picker-currency-symbol", children: ctx.currencySymbol }),
7952
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
9798
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "solvapay-amount-picker-custom-wrapper", children: [
9799
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { className: "solvapay-amount-picker-custom-label", children: customAmountLabel }),
9800
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "solvapay-amount-picker-custom-row", children: [
9801
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "solvapay-amount-picker-currency-symbol", children: ctx.currencySymbol }),
9802
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
7953
9803
  AmountPicker.Custom,
7954
9804
  {
7955
9805
  className: "solvapay-amount-picker-custom-input",
@@ -7958,7 +9808,7 @@ function DefaultAmountTree() {
7958
9808
  )
7959
9809
  ] })
7960
9810
  ] }),
7961
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
9811
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
7962
9812
  "p",
7963
9813
  {
7964
9814
  className: "solvapay-amount-picker-credit-estimate",
@@ -7968,7 +9818,7 @@ function DefaultAmountTree() {
7968
9818
  )
7969
9819
  ] });
7970
9820
  }
7971
- var AmountContinueButton = (0, import_react46.forwardRef)(
9821
+ var AmountContinueButton = (0, import_react48.forwardRef)(
7972
9822
  function AmountContinueButton2({ className, children, onClick, disabled, ...rest }, ref) {
7973
9823
  const flow = useCheckoutContext("AmountContinueButton");
7974
9824
  const locale = useLocale();
@@ -7977,7 +9827,7 @@ var AmountContinueButton = (0, import_react46.forwardRef)(
7977
9827
  const ready = flow.topupCurrencyReady && currency != null;
7978
9828
  const isDisabled = disabled || !ready || amountMinor == null;
7979
9829
  const label = children ?? (ready && currency != null && amountMinor != null ? `Continue \u2014 ${formatPrice(amountMinor, currency, { locale })}` : "Continue");
7980
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
9830
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
7981
9831
  "button",
7982
9832
  {
7983
9833
  ref,
@@ -8000,10 +9850,10 @@ var AmountContinueButton = (0, import_react46.forwardRef)(
8000
9850
  function Payment({ className }) {
8001
9851
  const flow = useCheckoutContext("Payment");
8002
9852
  if (flow.branch === "payg") {
8003
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(PaygPayment, { className });
9853
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(PaygPayment, { className });
8004
9854
  }
8005
9855
  if (flow.branch === "recurring") {
8006
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(RecurringPayment, { className });
9856
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(RecurringPayment, { className });
8007
9857
  }
8008
9858
  return null;
8009
9859
  }
@@ -8017,12 +9867,12 @@ function PaygPayment({ className }) {
8017
9867
  const currency = flow.topupCurrency;
8018
9868
  if (!selectedPlanShape || amountMinor == null || currency == null) return null;
8019
9869
  const creditsAdded = creditsPerMinorUnit != null && creditsPerMinorUnit > 0 ? Math.floor(amountMinor / (displayExchangeRate ?? 1) * creditsPerMinorUnit) : null;
8020
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: className ?? "solvapay-checkout-payment", "data-branch": "payg", children: [
8021
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "solvapay-checkout-order-summary", "data-variant": "payg", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "solvapay-checkout-order-summary-row", children: [
8022
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { children: creditsAdded != null ? `${creditsAdded.toLocaleString(locale)} credits` : formatPrice(amountMinor, currency, { locale }) }),
8023
- creditsAdded != null ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { children: formatPrice(amountMinor, currency, { locale }) }) : null
9870
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: className ?? "solvapay-checkout-payment", "data-branch": "payg", children: [
9871
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "solvapay-checkout-order-summary", "data-variant": "payg", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "solvapay-checkout-order-summary-row", children: [
9872
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { children: creditsAdded != null ? `${creditsAdded.toLocaleString(locale)} credits` : formatPrice(amountMinor, currency, { locale }) }),
9873
+ creditsAdded != null ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { children: formatPrice(amountMinor, currency, { locale }) }) : null
8024
9874
  ] }) }),
8025
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
9875
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
8026
9876
  TopupForm.Root,
8027
9877
  {
8028
9878
  amount: amountMinor,
@@ -8031,11 +9881,11 @@ function PaygPayment({ className }) {
8031
9881
  className: "solvapay-checkout-topup-form",
8032
9882
  onSuccess: (intent, extras) => flow.notifyPaymentSuccess(intent, extras),
8033
9883
  children: [
8034
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(TopupForm.Loading, {}),
8035
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(TopupForm.PaymentElement, {}),
8036
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(TopupForm.Error, { className: "solvapay-checkout-error" }),
8037
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(MandateText, { mode: "topup", amountMinor, currency }),
8038
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(TopupForm.SubmitButton, { className: "solvapay-checkout-pay-button", children: [
9884
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(TopupForm.Loading, {}),
9885
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(TopupForm.PaymentElement, {}),
9886
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(TopupForm.Error, { className: "solvapay-checkout-error" }),
9887
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(MandateText, { mode: "topup", amountMinor, currency }),
9888
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(TopupForm.SubmitButton, { className: "solvapay-checkout-pay-button", children: [
8039
9889
  "Pay ",
8040
9890
  formatPrice(amountMinor, currency, { locale })
8041
9891
  ] })
@@ -8058,12 +9908,12 @@ function RecurringPayment({ className }) {
8058
9908
  const isRecurring = !!cycle;
8059
9909
  const formattedAmount = formatPrice(amountMinor, currency, { locale });
8060
9910
  const priceLine = isRecurring ? `${formattedAmount}/${shortCycle(cycle)}` : formattedAmount;
8061
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: className ?? "solvapay-checkout-payment", "data-branch": "recurring", children: [
8062
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "solvapay-checkout-order-summary", "data-variant": "recurring", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "solvapay-checkout-order-summary-row", children: [
8063
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { children: planName }),
8064
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { children: priceLine })
9911
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: className ?? "solvapay-checkout-payment", "data-branch": "recurring", children: [
9912
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "solvapay-checkout-order-summary", "data-variant": "recurring", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "solvapay-checkout-order-summary-row", children: [
9913
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { children: planName }),
9914
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { children: priceLine })
8065
9915
  ] }) }),
8066
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
9916
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
8067
9917
  PaymentForm.Root,
8068
9918
  {
8069
9919
  planRef: flow.selectedPlanRef,
@@ -8072,28 +9922,28 @@ function RecurringPayment({ className }) {
8072
9922
  requireTermsAcceptance: false,
8073
9923
  onSuccess: (intent) => flow.notifyPaymentSuccess(intent),
8074
9924
  children: [
8075
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(PaymentForm.Loading, {}),
8076
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(PaymentForm.PaymentElement, {}),
8077
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(PaymentForm.Error, { className: "solvapay-checkout-error" }),
8078
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(PaymentForm.MandateText, {}),
8079
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(PaymentForm.SubmitButton, { className: "solvapay-checkout-pay-button", children: isRecurring ? `Subscribe \u2014 ${priceLine}` : `Pay ${formattedAmount}` })
9925
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(PaymentForm.Loading, {}),
9926
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(PaymentForm.PaymentElement, {}),
9927
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(PaymentForm.Error, { className: "solvapay-checkout-error" }),
9928
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(PaymentForm.MandateText, {}),
9929
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(PaymentForm.SubmitButton, { className: "solvapay-checkout-pay-button", children: isRecurring ? `Subscribe \u2014 ${priceLine}` : `Pay ${formattedAmount}` })
8080
9930
  ]
8081
9931
  }
8082
9932
  )
8083
9933
  ] });
8084
9934
  }
8085
- var CheckoutEnvContext = (0, import_react46.createContext)(null);
9935
+ var CheckoutEnvContext = (0, import_react48.createContext)(null);
8086
9936
  function useReturnUrl() {
8087
- return (0, import_react46.useContext)(CheckoutEnvContext)?.returnUrl ?? "";
9937
+ return (0, import_react48.useContext)(CheckoutEnvContext)?.returnUrl ?? "";
8088
9938
  }
8089
9939
  function useProductRef() {
8090
- return (0, import_react46.useContext)(CheckoutEnvContext)?.productRef ?? "";
9940
+ return (0, import_react48.useContext)(CheckoutEnvContext)?.productRef ?? "";
8091
9941
  }
8092
- var BackLink = (0, import_react46.forwardRef)(function CheckoutStepsBackLink({ label, glyph = "\u2190", className, onClick, ...rest }, ref) {
9942
+ var BackLink = (0, import_react48.forwardRef)(function CheckoutStepsBackLink({ label, glyph = "\u2190", className, onClick, ...rest }, ref) {
8093
9943
  const flow = useCheckoutContext("BackLink");
8094
9944
  if (!flow.canGoBack) return null;
8095
9945
  const resolvedLabel = label ?? (flow.step === "payment" && flow.branch === "payg" ? "Change amount" : flow.step === "payment" && flow.branch === "recurring" ? "Change plan" : "Back");
8096
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
9946
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
8097
9947
  "button",
8098
9948
  {
8099
9949
  ref,
@@ -8107,8 +9957,8 @@ var BackLink = (0, import_react46.forwardRef)(function CheckoutStepsBackLink({ l
8107
9957
  },
8108
9958
  ...rest,
8109
9959
  children: [
8110
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "solvapay-checkout-back-link-glyph", "aria-hidden": "true", children: glyph }),
8111
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "solvapay-checkout-back-link-label", children: resolvedLabel })
9960
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "solvapay-checkout-back-link-glyph", "aria-hidden": "true", children: glyph }),
9961
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "solvapay-checkout-back-link-label", children: resolvedLabel })
8112
9962
  ]
8113
9963
  }
8114
9964
  );
@@ -8118,74 +9968,74 @@ function Success({ className, children }) {
8118
9968
  const locale = useLocale();
8119
9969
  if (flow.step !== "success" || !flow.successMeta) return null;
8120
9970
  if (children) {
8121
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: className ?? "solvapay-checkout-success", children });
9971
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: className ?? "solvapay-checkout-success", children });
8122
9972
  }
8123
9973
  const meta = flow.successMeta;
8124
9974
  if (meta.branch === "payg") {
8125
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: className ?? "solvapay-checkout-success", "data-branch": "payg", children: [
8126
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "solvapay-checkout-success-check", "aria-hidden": "true", children: "\u2713" }),
8127
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("h2", { className: "solvapay-checkout-success-heading", children: "Credits added" }),
8128
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "solvapay-checkout-success-subheading", children: "Pay as you go plan is active." }),
8129
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("dl", { className: "solvapay-checkout-receipt", "data-variant": "payg", children: [
8130
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "solvapay-checkout-receipt-row", children: [
8131
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("dt", { children: "Amount" }),
8132
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("dd", { children: formatPrice(meta.amountMinor, meta.currency, { locale }) })
9975
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: className ?? "solvapay-checkout-success", "data-branch": "payg", children: [
9976
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "solvapay-checkout-success-check", "aria-hidden": "true", children: "\u2713" }),
9977
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("h2", { className: "solvapay-checkout-success-heading", children: "Credits added" }),
9978
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { className: "solvapay-checkout-success-subheading", children: "Pay as you go plan is active." }),
9979
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("dl", { className: "solvapay-checkout-receipt", "data-variant": "payg", children: [
9980
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "solvapay-checkout-receipt-row", children: [
9981
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("dt", { children: "Amount" }),
9982
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("dd", { children: formatPrice(meta.amountMinor, meta.currency, { locale }) })
8133
9983
  ] }),
8134
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "solvapay-checkout-receipt-row", children: [
8135
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("dt", { children: "Credits" }),
8136
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("dd", { children: [
9984
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "solvapay-checkout-receipt-row", children: [
9985
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("dt", { children: "Credits" }),
9986
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("dd", { children: [
8137
9987
  "+",
8138
9988
  meta.creditsAdded.toLocaleString(locale)
8139
9989
  ] })
8140
9990
  ] }),
8141
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "solvapay-checkout-receipt-row", children: [
8142
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("dt", { children: "Plan" }),
8143
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("dd", { children: meta.plan.name ?? "Pay as you go" })
9991
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "solvapay-checkout-receipt-row", children: [
9992
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("dt", { children: "Plan" }),
9993
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("dd", { children: meta.plan.name ?? "Pay as you go" })
8144
9994
  ] }),
8145
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "solvapay-checkout-receipt-row", children: [
8146
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("dt", { children: "Rate" }),
8147
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("dd", { children: meta.rateLabel })
9995
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "solvapay-checkout-receipt-row", children: [
9996
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("dt", { children: "Rate" }),
9997
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("dd", { children: meta.rateLabel })
8148
9998
  ] })
8149
9999
  ] })
8150
10000
  ] });
8151
10001
  }
8152
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: className ?? "solvapay-checkout-success", "data-branch": "recurring", children: [
8153
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "solvapay-checkout-success-check", "aria-hidden": "true", children: "\u2713" }),
8154
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("h2", { className: "solvapay-checkout-success-heading", children: [
10002
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: className ?? "solvapay-checkout-success", "data-branch": "recurring", children: [
10003
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "solvapay-checkout-success-check", "aria-hidden": "true", children: "\u2713" }),
10004
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("h2", { className: "solvapay-checkout-success-heading", children: [
8155
10005
  meta.plan.name ?? "Plan",
8156
10006
  " active"
8157
10007
  ] }),
8158
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "solvapay-checkout-success-subheading", children: "Subscription is live and credits are ready." }),
8159
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("dl", { className: "solvapay-checkout-receipt", "data-variant": "recurring", children: [
8160
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "solvapay-checkout-receipt-row", children: [
8161
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("dt", { children: "Plan" }),
8162
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("dd", { children: meta.plan.name ?? "Plan" })
10008
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { className: "solvapay-checkout-success-subheading", children: "Subscription is live and credits are ready." }),
10009
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("dl", { className: "solvapay-checkout-receipt", "data-variant": "recurring", children: [
10010
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "solvapay-checkout-receipt-row", children: [
10011
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("dt", { children: "Plan" }),
10012
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("dd", { children: meta.plan.name ?? "Plan" })
8163
10013
  ] }),
8164
- meta.creditsIncluded > 0 ? /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "solvapay-checkout-receipt-row", children: [
8165
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("dt", { children: "Credits" }),
8166
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("dd", { children: [
10014
+ meta.creditsIncluded > 0 ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "solvapay-checkout-receipt-row", children: [
10015
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("dt", { children: "Credits" }),
10016
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("dd", { children: [
8167
10017
  "+",
8168
10018
  meta.creditsIncluded.toLocaleString(locale)
8169
10019
  ] })
8170
10020
  ] }) : null,
8171
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "solvapay-checkout-receipt-row", children: [
8172
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("dt", { children: "Charged today" }),
8173
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("dd", { children: formatPrice(meta.chargedTodayMinor, meta.currency, { locale }) })
10021
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "solvapay-checkout-receipt-row", children: [
10022
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("dt", { children: "Charged today" }),
10023
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("dd", { children: formatPrice(meta.chargedTodayMinor, meta.currency, { locale }) })
8174
10024
  ] }),
8175
- meta.nextRenewalLabel ? /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "solvapay-checkout-receipt-row", children: [
8176
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("dt", { children: "Next renewal" }),
8177
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("dd", { children: meta.nextRenewalLabel })
10025
+ meta.nextRenewalLabel ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "solvapay-checkout-receipt-row", children: [
10026
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("dt", { children: "Next renewal" }),
10027
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("dd", { children: meta.nextRenewalLabel })
8178
10028
  ] }) : null
8179
10029
  ] })
8180
10030
  ] });
8181
10031
  }
8182
- var RootWithEnv = (0, import_react46.forwardRef)(
10032
+ var RootWithEnv = (0, import_react48.forwardRef)(
8183
10033
  function CheckoutStepsRootWithEnv(props, forwardedRef) {
8184
- const env = (0, import_react46.useMemo)(
10034
+ const env = (0, import_react48.useMemo)(
8185
10035
  () => ({ returnUrl: props.returnUrl, productRef: props.productRef }),
8186
10036
  [props.returnUrl, props.productRef]
8187
10037
  );
8188
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(CheckoutEnvContext.Provider, { value: env, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Root12, { ...props, ref: forwardedRef }) });
10038
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(CheckoutEnvContext.Provider, { value: env, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Root13, { ...props, ref: forwardedRef }) });
8189
10039
  }
8190
10040
  );
8191
10041
  var CheckoutSteps = {
@@ -8237,6 +10087,7 @@ var UnsupportedTransportMethodError = class extends Error {
8237
10087
  0 && (module.exports = {
8238
10088
  ActivationFlow,
8239
10089
  AmountPicker,
10090
+ AutoRecharge,
8240
10091
  BalanceBadge,
8241
10092
  CancelPlanButton,
8242
10093
  CancelledPlanNotice,
@@ -8263,6 +10114,7 @@ var UnsupportedTransportMethodError = class extends Error {
8263
10114
  TopupForm,
8264
10115
  UnsupportedTransportMethodError,
8265
10116
  UpdatePaymentMethodButton,
10117
+ configToAutoRechargeInput,
8266
10118
  confirmPayment,
8267
10119
  createAnonymousAuthAdapter,
8268
10120
  createHttpTransport,
@@ -8288,6 +10140,7 @@ var UnsupportedTransportMethodError = class extends Error {
8288
10140
  toMajorUnits,
8289
10141
  useActivation,
8290
10142
  useAutoActivateFreePlan,
10143
+ useAutoRecharge,
8291
10144
  useBalance,
8292
10145
  useCheckout,
8293
10146
  useCheckoutFlow,