@solvapay/react 2.0.0 → 2.0.1-preview-fab746232bff615a7302c55ee7293205ac645de4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # @solvapay/react changelog
2
2
 
3
+ ## 2.0.1-preview-fab746232bff615a7302c55ee7293205ac645de4
4
+
5
+ ### Patch Changes
6
+
7
+ - a47adff: Free plans with an included allowance now count usage and label the meter correctly.
8
+
9
+ `@solvapay/core` adds `countsUsage` (per-unit charge, tier, or limit) and `meterName`
10
+ (per-unit charge's meter, else the first limit's meter). A free tier with a bare
11
+ limit is not priced per unit, but it still needs a usage counter and a meter noun —
12
+ `isMetered` on the wire was the wrong question for both.
13
+
14
+ `planMeterName` uses the new reader, so a recurring allowance no longer renders the
15
+ literal "units". `useAutoActivateFreePlan` no longer requires deprecated `freeUnits`
16
+ on the plan row. Usage surfaces (`useUsage`, `getUsageCore`, plan cards) derive
17
+ from `options[]` instead of trusting `planSnapshot.isMetered` alone.
18
+
19
+ - 30f7021: PAYG embedded checkout now activates first, then shows the credit top-up picker only when the wallet is empty.
20
+
21
+ A funded wallet skips the amount and payment steps. `ActivationFlow` follows the same contract: API `activated` at zero credits opens the amount picker instead of firing `onSuccess`. Once the customer is on the amount or payment step, a later zero-credit balance refetch no longer rewinds them back to the picker.
22
+
23
+ - Updated dependencies [a47adff]
24
+ - @solvapay/core@1.5.0-preview-fab746232bff615a7302c55ee7293205ac645de4
25
+ - @solvapay/mcp-core@0.3.2-preview-fab746232bff615a7302c55ee7293205ac645de4
26
+
3
27
  ## 2.0.0
4
28
 
5
29
  ### Major Changes
@@ -14,7 +14,7 @@ import {
14
14
  usePurchaseStatus,
15
15
  useSolvaPay,
16
16
  useTransport
17
- } from "./chunk-6ABOJOEV.js";
17
+ } from "./chunk-GMZU5M6R.js";
18
18
 
19
19
  // src/components/CancelledPlanNotice.tsx
20
20
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -362,6 +362,7 @@ var UpdatePaymentMethodButton = forwardRef2(function UpdatePaymentMethodButton2(
362
362
  });
363
363
 
364
364
  // src/components/CurrentPlanCard.tsx
365
+ import { countsUsage } from "@solvapay/core";
365
366
  import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
366
367
  function PlanTypeLine({
367
368
  purchase,
@@ -369,7 +370,7 @@ function PlanTypeLine({
369
370
  className
370
371
  }) {
371
372
  const copy = useCopy();
372
- const isMetered = purchase.planSnapshot?.isMetered === true;
373
+ const isMetered = countsUsage(purchase.planSnapshot) || purchase.planSnapshot?.isMetered === true;
373
374
  if (purchase.isRecurring) {
374
375
  const date2 = formatDate(purchase.nextBillingDate);
375
376
  if (!date2) return null;
@@ -429,7 +430,7 @@ var CurrentPlanCard = ({
429
430
  const { formatDate, shouldShowCancelledNotice } = usePurchaseStatus();
430
431
  const { paymentMethod } = usePaymentMethod();
431
432
  if (!activePurchase) return null;
432
- const isUsageBased = activePurchase.planSnapshot?.isMetered === true;
433
+ const isUsageBased = countsUsage(activePurchase.planSnapshot) || activePurchase.planSnapshot?.isMetered === true;
433
434
  const planType = activePurchase.isRecurring ? "recurring" : isUsageBased ? "usage-based" : "one-time";
434
435
  const amount = activePurchase.originalAmount ?? activePurchase.amount ?? 0;
435
436
  const currency = activePurchase.currency ?? "usd";
@@ -303,10 +303,10 @@ function createHttpTransport(config) {
303
303
  onErrorContext: "getUsage",
304
304
  errorPrefix: "Failed to load usage"
305
305
  }),
306
- getLimits: async ({ productRef, meterName }) => {
306
+ getLimits: async ({ productRef, meterName: meterName2 }) => {
307
307
  const base = routeFor(config, "getLimits");
308
308
  const params = new URLSearchParams({ productRef });
309
- if (meterName) params.set("meterName", meterName);
309
+ if (meterName2) params.set("meterName", meterName2);
310
310
  const url = `${base}?${params.toString()}`;
311
311
  const data = await request(config, url, {
312
312
  method: "GET",
@@ -483,7 +483,7 @@ var enCopy = {
483
483
  activateButton: "Activate",
484
484
  activatingLabel: "Activating...",
485
485
  topupHeading: "Add credits",
486
- topupSubheading: "Top up your credits to activate this plan.",
486
+ topupSubheading: "Top up your credits to start using this plan.",
487
487
  continueToPayment: "Continue to payment",
488
488
  changeAmountButton: "Change amount",
489
489
  retryingHeading: "Activating your plan...",
@@ -816,7 +816,7 @@ var SolvaPayProvider = ({ config, children }) => {
816
816
  setHasAttachBusinessDetails(!!transportRef.current.attachBusinessDetails);
817
817
  }, [config]);
818
818
  const fetchBalanceImpl = useCallback(async () => {
819
- if (optimisticUntilRef.current > Date.now()) return;
819
+ if (optimisticUntilRef.current > Date.now()) return creditsValueRef.current;
820
820
  if (!isAuthenticated && !internalCustomerRef) {
821
821
  creditsValueRef.current = null;
822
822
  setCreditsValue(null);
@@ -826,18 +826,16 @@ var SolvaPayProvider = ({ config, children }) => {
826
826
  setDisplayBlockValue(null);
827
827
  setBalanceLoading(false);
828
828
  balanceLoadedRef.current = false;
829
- return;
829
+ return null;
830
830
  }
831
- if (balanceInFlightRef.current) return;
831
+ if (balanceInFlightRef.current) return creditsValueRef.current;
832
832
  balanceInFlightRef.current = true;
833
833
  if (!balanceLoadedRef.current) {
834
834
  setBalanceLoading(true);
835
835
  }
836
836
  try {
837
837
  if (!transportRef.current.getBalance) {
838
- setBalanceLoading(false);
839
- balanceInFlightRef.current = false;
840
- return;
838
+ return creditsValueRef.current;
841
839
  }
842
840
  const data = await transportRef.current.getBalance();
843
841
  creditsValueRef.current = data.credits ?? null;
@@ -847,8 +845,10 @@ var SolvaPayProvider = ({ config, children }) => {
847
845
  setDisplayExchangeRateValue(data.displayExchangeRate ?? null);
848
846
  setDisplayBlockValue(data.display ?? null);
849
847
  balanceLoadedRef.current = true;
848
+ return creditsValueRef.current;
850
849
  } catch (error) {
851
850
  console.error("[SolvaPayProvider] Failed to fetch balance:", error);
851
+ return creditsValueRef.current;
852
852
  } finally {
853
853
  setBalanceLoading(false);
854
854
  balanceInFlightRef.current = false;
@@ -3010,7 +3010,8 @@ function normalizeOneTimePurchase(input) {
3010
3010
  planSnapshot: {
3011
3011
  price: input.amount,
3012
3012
  currency: input.currency,
3013
- isMetered: false
3013
+ isMetered: false,
3014
+ options: []
3014
3015
  }
3015
3016
  };
3016
3017
  }
@@ -5796,12 +5797,13 @@ function usePurchaseActions() {
5796
5797
  }
5797
5798
 
5798
5799
  // src/primitives/CancelPlanButton.tsx
5800
+ import { countsUsage } from "@solvapay/core";
5799
5801
  import { forwardRef as forwardRef10, useCallback as useCallback16, useContext as useContext13 } from "react";
5800
5802
  import { Fragment as Fragment9, jsx as jsx17 } from "react/jsx-runtime";
5801
5803
  function resolveConfirmText(confirm, purchase, defaults) {
5802
5804
  if (confirm === false) return null;
5803
5805
  if (typeof confirm === "string") return confirm;
5804
- const isUsageBased = purchase?.planSnapshot?.isMetered === true && purchase.isRecurring !== true;
5806
+ const isUsageBased = (countsUsage(purchase?.planSnapshot) || purchase?.planSnapshot?.isMetered === true) && purchase?.isRecurring !== true;
5805
5807
  if (isUsageBased) return defaults.usageBased;
5806
5808
  return defaults.recurring;
5807
5809
  }
@@ -6098,19 +6100,19 @@ import { useCallback as useCallback19, useEffect as useEffect12, useRef as useRe
6098
6100
  var CACHE_TTL_MS = 1e4;
6099
6101
  var OPTIMISTIC_GRACE_MS = 8e3;
6100
6102
  var limitsCache = /* @__PURE__ */ new Map();
6101
- function cacheKey(customerRef, productRef, meterName) {
6102
- return `${customerRef ?? "anonymous"}:${productRef}:${meterName}`;
6103
+ function cacheKey(customerRef, productRef, meterName2) {
6104
+ return `${customerRef ?? "anonymous"}:${productRef}:${meterName2}`;
6103
6105
  }
6104
6106
  function isUnlimited(remaining) {
6105
6107
  return remaining < 0;
6106
6108
  }
6107
6109
  function useLimits(options) {
6108
6110
  const { productRef, meterName: rawMeterName, enabled = true } = options;
6109
- const meterName = rawMeterName || "requests";
6111
+ const meterName2 = rawMeterName || "requests";
6110
6112
  const transport = useTransport();
6111
6113
  const { customerRef } = useCustomer();
6112
6114
  const { purchase } = useSolvaPay();
6113
- const currentKey = !productRef || !enabled ? null : cacheKey(customerRef, productRef, meterName);
6115
+ const currentKey = !productRef || !enabled ? null : cacheKey(customerRef, productRef, meterName2);
6114
6116
  const [data, setData] = useState15(() => {
6115
6117
  if (!currentKey) return null;
6116
6118
  const cached = limitsCache.get(currentKey);
@@ -6165,7 +6167,7 @@ function useLimits(options) {
6165
6167
  setLoading(false);
6166
6168
  return;
6167
6169
  }
6168
- const key = cacheKey(customerRef, productRef, meterName);
6170
+ const key = cacheKey(customerRef, productRef, meterName2);
6169
6171
  const cached = limitsCache.get(key);
6170
6172
  const now = Date.now();
6171
6173
  if (cached?.promise) {
@@ -6178,7 +6180,7 @@ function useLimits(options) {
6178
6180
  setError(null);
6179
6181
  return;
6180
6182
  }
6181
- const promise = transport.getLimits({ productRef, meterName });
6183
+ const promise = transport.getLimits({ productRef, meterName: meterName2 });
6182
6184
  limitsCache.set(key, { data: cached?.data ?? null, timestamp: now, promise });
6183
6185
  const fresh = await attachToFetch(promise);
6184
6186
  if (fresh !== null) {
@@ -6187,7 +6189,7 @@ function useLimits(options) {
6187
6189
  limitsCache.delete(key);
6188
6190
  }
6189
6191
  },
6190
- [transport, customerRef, productRef, meterName, enabled, attachToFetch]
6192
+ [transport, customerRef, productRef, meterName2, enabled, attachToFetch]
6191
6193
  );
6192
6194
  useEffect12(() => {
6193
6195
  fetchLimits(false);
@@ -6205,7 +6207,7 @@ function useLimits(options) {
6205
6207
  (delta) => {
6206
6208
  if (!productRef || !enabled) return;
6207
6209
  if (unlimitedRef.current) return;
6208
- const key = cacheKey(customerRef, productRef, meterName);
6210
+ const key = cacheKey(customerRef, productRef, meterName2);
6209
6211
  setData((prev) => {
6210
6212
  const cached = limitsCache.get(key);
6211
6213
  const baseline = prev ?? cached?.data ?? null;
@@ -6232,7 +6234,7 @@ function useLimits(options) {
6232
6234
  });
6233
6235
  }, OPTIMISTIC_GRACE_MS);
6234
6236
  },
6235
- [customerRef, productRef, meterName, enabled, fetchLimits]
6237
+ [customerRef, productRef, meterName2, enabled, fetchLimits]
6236
6238
  );
6237
6239
  return {
6238
6240
  remaining: data?.remaining ?? null,
@@ -6248,11 +6250,14 @@ function useLimits(options) {
6248
6250
  }
6249
6251
 
6250
6252
  // src/hooks/useUsage.ts
6253
+ import { countsUsage as countsUsage2 } from "@solvapay/core";
6251
6254
  import { useCallback as useCallback20, useEffect as useEffect13, useMemo as useMemo14, useState as useState16 } from "react";
6252
6255
  function deriveUsage(purchase, limits) {
6253
6256
  if (!purchase) return null;
6254
6257
  const usage = purchase.usage;
6255
- if (purchase.planSnapshot?.isMetered !== true && !usage) return null;
6258
+ if (!countsUsage2(purchase.planSnapshot) && purchase.planSnapshot?.isMetered !== true && !usage) {
6259
+ return null;
6260
+ }
6256
6261
  const used = typeof usage?.used === "number" ? usage.used : 0;
6257
6262
  const hasFiniteCap = limits.unlimited === false && limits.remaining !== null;
6258
6263
  const remaining = hasFiniteCap ? limits.remaining : null;
@@ -6275,18 +6280,18 @@ function useUsage() {
6275
6280
  const [override, setOverride] = useState16(null);
6276
6281
  const [error, setError] = useState16(null);
6277
6282
  const [transportLoading, setTransportLoading] = useState16(false);
6278
- const isMetered = activePurchase?.planSnapshot?.isMetered === true;
6283
+ const usageCounted = countsUsage2(activePurchase?.planSnapshot) || activePurchase?.planSnapshot?.isMetered === true;
6279
6284
  const {
6280
6285
  remaining: limitRemaining,
6281
6286
  unlimited,
6282
- meterName
6287
+ meterName: meterName2
6283
6288
  } = useLimits({
6284
6289
  productRef: activePurchase?.productRef,
6285
- enabled: isMetered
6290
+ enabled: usageCounted
6286
6291
  });
6287
6292
  const derived = useMemo14(
6288
- () => deriveUsage(activePurchase ?? null, { remaining: limitRemaining, unlimited, meterName }),
6289
- [activePurchase, limitRemaining, unlimited, meterName]
6293
+ () => deriveUsage(activePurchase ?? null, { remaining: limitRemaining, unlimited, meterName: meterName2 }),
6294
+ [activePurchase, limitRemaining, unlimited, meterName2]
6290
6295
  );
6291
6296
  const activePurchaseRef = activePurchase?.reference ?? null;
6292
6297
  useEffect13(() => {
@@ -6547,6 +6552,7 @@ import {
6547
6552
  billingCycle as readBillingCycle,
6548
6553
  creditsPerUnitFromBalance,
6549
6554
  includedUnits,
6555
+ meterName,
6550
6556
  perUnitCharge
6551
6557
  } from "@solvapay/core";
6552
6558
  function isPayg(plan) {
@@ -6607,7 +6613,7 @@ function inferIncludedUnits(plan) {
6607
6613
  return cap != null && cap > 0 ? cap : null;
6608
6614
  }
6609
6615
  function planMeterName(plan) {
6610
- return perUnitCharge(plan)?.meter ?? null;
6616
+ return meterName(plan);
6611
6617
  }
6612
6618
  function shortCycle(cycle) {
6613
6619
  if (!cycle) return "mo";
@@ -6692,8 +6698,23 @@ function useCheckoutFlow(opts) {
6692
6698
  setStatus("activating");
6693
6699
  try {
6694
6700
  await transport.activatePlan({ productRef, planRef: selectedPlanRef });
6701
+ const credits = await balance.refetch() ?? balance.credits;
6702
+ if (credits == null) {
6703
+ throw new Error("Credit balance is unavailable");
6704
+ }
6695
6705
  setStatus("idle");
6696
- setStep("amount");
6706
+ if (credits === 0) {
6707
+ setStep("amount");
6708
+ } else {
6709
+ const meta = {
6710
+ branch: "payg",
6711
+ plan: selectedPlanShape,
6712
+ rateLabel: formatPaygRate(selectedPlanShape, locale, balance)
6713
+ };
6714
+ setSuccessMeta(meta);
6715
+ setStep("success");
6716
+ onPurchaseSuccessRef.current?.(meta);
6717
+ }
6697
6718
  return true;
6698
6719
  } catch (err) {
6699
6720
  const wrapped = err instanceof Error ? err : new Error("Activation failed");
@@ -6702,13 +6723,37 @@ function useCheckoutFlow(opts) {
6702
6723
  onErrorRef.current?.(wrapped, "activate");
6703
6724
  return false;
6704
6725
  }
6705
- }, [productRef, selectedPlanRef, selectedPlanShape, transport]);
6726
+ }, [balance, locale, productRef, selectedPlanRef, selectedPlanShape, transport]);
6706
6727
  const advanceFromPlan = useCallback21(async () => {
6707
6728
  if (!selectedPlanShape || !selectedPlanRef) return;
6708
6729
  if (branch === "payg") {
6709
6730
  if (planCtx.currentPlanRef === selectedPlanRef) {
6710
6731
  setError(null);
6711
- setStep("amount");
6732
+ setStatus("activating");
6733
+ try {
6734
+ const credits = await balance.refetch() ?? balance.credits;
6735
+ if (credits == null) {
6736
+ throw new Error("Credit balance is unavailable");
6737
+ }
6738
+ setStatus("idle");
6739
+ if (credits === 0) {
6740
+ setStep("amount");
6741
+ } else {
6742
+ const meta = {
6743
+ branch: "payg",
6744
+ plan: selectedPlanShape,
6745
+ rateLabel: formatPaygRate(selectedPlanShape, locale, balance)
6746
+ };
6747
+ setSuccessMeta(meta);
6748
+ setStep("success");
6749
+ onPurchaseSuccessRef.current?.(meta);
6750
+ }
6751
+ } catch (err) {
6752
+ const wrapped = err instanceof Error ? err : new Error("Activation failed");
6753
+ setError(wrapped.message);
6754
+ setStatus("error");
6755
+ onErrorRef.current?.(wrapped, "activate");
6756
+ }
6712
6757
  return;
6713
6758
  }
6714
6759
  await runActivate();
@@ -6716,7 +6761,7 @@ function useCheckoutFlow(opts) {
6716
6761
  }
6717
6762
  setError(null);
6718
6763
  setStep("payment");
6719
- }, [branch, planCtx.currentPlanRef, runActivate, selectedPlanRef, selectedPlanShape]);
6764
+ }, [balance, branch, locale, planCtx.currentPlanRef, runActivate, selectedPlanRef, selectedPlanShape]);
6720
6765
  const recordPaygSuccess = useCallback21(
6721
6766
  (creditsAddedFromBackend) => {
6722
6767
  if (!selectedPlanShape || selectedAmountMinor == null) return;
@@ -40,7 +40,7 @@ import {
40
40
  useTopupAmountSelector,
41
41
  withPaymentElementDefaults,
42
42
  writeAutoRechargeCache
43
- } from "./chunk-6ABOJOEV.js";
43
+ } from "./chunk-GMZU5M6R.js";
44
44
 
45
45
  // src/TopupForm.tsx
46
46
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -216,12 +216,29 @@ var Root2 = forwardRef3(function ActivationFlowRoot({
216
216
  const { activate, state, error, result, reset } = useActivation();
217
217
  const currency = plan?.currency ?? "USD";
218
218
  const amountSelector = useTopupAmountSelector({ currency });
219
- const { adjustBalance, creditsPerMinorUnit, displayExchangeRate } = useBalance();
219
+ const {
220
+ credits,
221
+ adjustBalance,
222
+ creditsPerMinorUnit,
223
+ displayExchangeRate,
224
+ refetch,
225
+ loading: balanceLoading
226
+ } = useBalance();
220
227
  const [step, setStep] = useState2("summary");
221
228
  const calledSuccessRef = useRef(false);
222
229
  const retryTimeoutRef = useRef(null);
223
230
  useEffect2(() => {
224
- if (state === "activated" && !calledSuccessRef.current) {
231
+ if (state !== "activated") return;
232
+ if (step === "selectAmount" || step === "topupPayment") return;
233
+ const isUsagePlan = plan?.type === "usage-based";
234
+ if (isUsagePlan && (credits === null || balanceLoading)) {
235
+ return;
236
+ }
237
+ if (isUsagePlan && credits === 0) {
238
+ setStep("selectAmount");
239
+ return;
240
+ }
241
+ if (!calledSuccessRef.current) {
225
242
  calledSuccessRef.current = true;
226
243
  setStep("activated");
227
244
  if (result) {
@@ -229,7 +246,7 @@ var Root2 = forwardRef3(function ActivationFlowRoot({
229
246
  onSuccess?.(activationResult);
230
247
  }
231
248
  }
232
- }, [state, result, onSuccess]);
249
+ }, [state, result, onSuccess, credits, plan, balanceLoading, step]);
233
250
  useEffect2(() => {
234
251
  if (state === "topup_required" && (step === "summary" || step === "activating")) {
235
252
  setStep("selectAmount");
@@ -245,7 +262,8 @@ var Root2 = forwardRef3(function ActivationFlowRoot({
245
262
  if (!resolvedPlanRef) return;
246
263
  setStep("activating");
247
264
  await activate({ productRef, planRef: resolvedPlanRef });
248
- }, [activate, productRef, resolvedPlanRef]);
265
+ await refetch();
266
+ }, [activate, productRef, resolvedPlanRef, refetch]);
249
267
  const goToTopupPayment = useCallback(() => {
250
268
  if (amountSelector.validate()) setStep("topupPayment");
251
269
  }, [amountSelector]);
@@ -336,16 +354,7 @@ var Root2 = forwardRef3(function ActivationFlowRoot({
336
354
  ]
337
355
  );
338
356
  const Comp = asChild ? Slot : "div";
339
- return /* @__PURE__ */ jsx4(ActivationFlowContext.Provider, { value: ctx, children: /* @__PURE__ */ jsx4(
340
- Comp,
341
- {
342
- ref: forwardedRef,
343
- "data-solvapay-activation-flow": "",
344
- "data-state": step,
345
- ...rest,
346
- children
347
- }
348
- ) });
357
+ return /* @__PURE__ */ jsx4(ActivationFlowContext.Provider, { value: ctx, children: /* @__PURE__ */ jsx4(Comp, { ref: forwardedRef, "data-solvapay-activation-flow": "", "data-state": step, ...rest, children }) });
349
358
  });
350
359
  function matchStep(step, allowed) {
351
360
  return allowed.includes(step);
@@ -435,16 +444,7 @@ var ErrorSlot2 = forwardRef3(function ActivationFlowError({ asChild, children, .
435
444
  const ctx = useFlowCtx("Error");
436
445
  if (ctx.step !== "error") return null;
437
446
  const Comp = asChild ? Slot : "div";
438
- return /* @__PURE__ */ jsx4(
439
- Comp,
440
- {
441
- ref: forwardedRef,
442
- role: "alert",
443
- "data-solvapay-activation-flow-error": "",
444
- ...rest,
445
- children: children ?? ctx.error
446
- }
447
- );
447
+ return /* @__PURE__ */ jsx4(Comp, { ref: forwardedRef, role: "alert", "data-solvapay-activation-flow-error": "", ...rest, children: children ?? ctx.error });
448
448
  });
449
449
  var ActivationFlowRoot2 = Root2;
450
450
  var ActivationFlowSummary2 = Summary;
@@ -2885,22 +2885,27 @@ function Success({ className, children }) {
2885
2885
  }
2886
2886
  const meta = flow.successMeta;
2887
2887
  if (meta.branch === "payg") {
2888
+ const chargedAmount = meta.amountMinor;
2889
+ const chargedCurrency = meta.currency;
2890
+ const charged = chargedAmount != null && chargedCurrency != null;
2888
2891
  return /* @__PURE__ */ jsxs3("div", { className: className ?? "solvapay-checkout-success", "data-branch": "payg", children: [
2889
2892
  /* @__PURE__ */ jsx7("div", { className: "solvapay-checkout-success-check", "aria-hidden": "true", children: "\u2713" }),
2890
- /* @__PURE__ */ jsx7("h2", { className: "solvapay-checkout-success-heading", children: "Credits added" }),
2893
+ /* @__PURE__ */ jsx7("h2", { className: "solvapay-checkout-success-heading", children: charged ? "Credits added" : "Plan activated" }),
2891
2894
  /* @__PURE__ */ jsx7("p", { className: "solvapay-checkout-success-subheading", children: "Pay as you go plan is active." }),
2892
2895
  /* @__PURE__ */ jsxs3("dl", { className: "solvapay-checkout-receipt", "data-variant": "payg", children: [
2893
- /* @__PURE__ */ jsxs3("div", { className: "solvapay-checkout-receipt-row", children: [
2894
- /* @__PURE__ */ jsx7("dt", { children: "Amount" }),
2895
- /* @__PURE__ */ jsx7("dd", { children: formatPrice(meta.amountMinor, meta.currency, { locale }) })
2896
- ] }),
2897
- /* @__PURE__ */ jsxs3("div", { className: "solvapay-checkout-receipt-row", children: [
2898
- /* @__PURE__ */ jsx7("dt", { children: "Credits" }),
2899
- /* @__PURE__ */ jsxs3("dd", { children: [
2900
- "+",
2901
- meta.creditsAdded.toLocaleString(locale)
2896
+ charged ? /* @__PURE__ */ jsxs3(Fragment4, { children: [
2897
+ /* @__PURE__ */ jsxs3("div", { className: "solvapay-checkout-receipt-row", children: [
2898
+ /* @__PURE__ */ jsx7("dt", { children: "Amount" }),
2899
+ /* @__PURE__ */ jsx7("dd", { children: formatPrice(chargedAmount, chargedCurrency, { locale }) })
2900
+ ] }),
2901
+ /* @__PURE__ */ jsxs3("div", { className: "solvapay-checkout-receipt-row", children: [
2902
+ /* @__PURE__ */ jsx7("dt", { children: "Credits" }),
2903
+ /* @__PURE__ */ jsxs3("dd", { children: [
2904
+ "+",
2905
+ (meta.creditsAdded ?? 0).toLocaleString(locale)
2906
+ ] })
2902
2907
  ] })
2903
- ] }),
2908
+ ] }) : null,
2904
2909
  /* @__PURE__ */ jsxs3("div", { className: "solvapay-checkout-receipt-row", children: [
2905
2910
  /* @__PURE__ */ jsx7("dt", { children: "Plan" }),
2906
2911
  /* @__PURE__ */ jsx7("dd", { children: meta.plan.name ?? "Pay as you go" })
@@ -1,4 +1,4 @@
1
- import { $ as components, b as Plan, P as PaymentFormProps, a as PrefillCustomer, A as ActivationResult, r as UseTopupAmountSelectorReturn, a0 as AutoRechargeInput, t as AutoRechargeConfig, a1 as AutoRechargeDisplayBlock, E as CheckoutStep, O as SuccessMeta } from './shared-CAxz5wWs.js';
1
+ import { $ as components, b as Plan, P as PaymentFormProps, a as PrefillCustomer, A as ActivationResult, r as UseTopupAmountSelectorReturn, a0 as AutoRechargeInput, t as AutoRechargeConfig, a1 as AutoRechargeDisplayBlock, E as CheckoutStep, O as SuccessMeta } from './shared-BI78qUom.js';
2
2
  import React from 'react';
3
3
  import { PaymentElement, CardElement } from '@stripe/react-stripe-js';
4
4
  import { TaxBreakdown } from '@solvapay/core';
@@ -411,8 +411,11 @@ declare const BalanceBadge: React.ForwardRefExoticComponent<React.HTMLAttributes
411
411
  * ActivationFlow compound primitive.
412
412
  *
413
413
  * Drives the usage-based plan activation state machine:
414
- * summary → activating → (topup_required → selectAmount → topupPayment →
415
- * retrying) → activated | error.
414
+ * summary → activating → (activated + empty wallet → selectAmount →
415
+ * topupPayment → retrying) → activated | error.
416
+ *
417
+ * `topup_required` remains a tolerated legacy activate status that also
418
+ * opens the amount picker.
416
419
  *
417
420
  * `Root` exposes `data-state` set to the current step and publishes the
418
421
  * shared context consumed by leaves. Leaves render only during their
@@ -527,15 +530,6 @@ declare const ActivationFlow: {
527
530
  };
528
531
  declare function useActivationFlow(): ActivationFlowContextValue;
529
532
 
530
- /**
531
- * CancelPlanButton leaf primitive.
532
- *
533
- * Cancels the active (or specified) purchase via `usePurchaseActions`.
534
- * Emits `data-state=idle|cancelling` and auto-derives the confirm dialog
535
- * copy from the plan type (`recurring` vs. `usage-based`) unless overridden
536
- * via the `confirm` prop (`false` to skip, string to replace).
537
- */
538
-
539
533
  declare const CancelPlanButton: React.ForwardRefExoticComponent<React.ButtonHTMLAttributes<HTMLButtonElement> & {
540
534
  asChild?: boolean;
541
535
  /** Defaults to the active purchase from `usePurchase()`. */
@@ -1,4 +1,4 @@
1
- import { $ as components, b as Plan, P as PaymentFormProps, a as PrefillCustomer, A as ActivationResult, r as UseTopupAmountSelectorReturn, a0 as AutoRechargeInput, t as AutoRechargeConfig, a1 as AutoRechargeDisplayBlock, E as CheckoutStep, O as SuccessMeta } from './shared-A_Sg-fJE.cjs';
1
+ import { $ as components, b as Plan, P as PaymentFormProps, a as PrefillCustomer, A as ActivationResult, r as UseTopupAmountSelectorReturn, a0 as AutoRechargeInput, t as AutoRechargeConfig, a1 as AutoRechargeDisplayBlock, E as CheckoutStep, O as SuccessMeta } from './shared-BgyNW-D3.cjs';
2
2
  import React from 'react';
3
3
  import { PaymentElement, CardElement } from '@stripe/react-stripe-js';
4
4
  import { TaxBreakdown } from '@solvapay/core';
@@ -411,8 +411,11 @@ declare const BalanceBadge: React.ForwardRefExoticComponent<React.HTMLAttributes
411
411
  * ActivationFlow compound primitive.
412
412
  *
413
413
  * Drives the usage-based plan activation state machine:
414
- * summary → activating → (topup_required → selectAmount → topupPayment →
415
- * retrying) → activated | error.
414
+ * summary → activating → (activated + empty wallet → selectAmount →
415
+ * topupPayment → retrying) → activated | error.
416
+ *
417
+ * `topup_required` remains a tolerated legacy activate status that also
418
+ * opens the amount picker.
416
419
  *
417
420
  * `Root` exposes `data-state` set to the current step and publishes the
418
421
  * shared context consumed by leaves. Leaves render only during their
@@ -527,15 +530,6 @@ declare const ActivationFlow: {
527
530
  };
528
531
  declare function useActivationFlow(): ActivationFlowContextValue;
529
532
 
530
- /**
531
- * CancelPlanButton leaf primitive.
532
- *
533
- * Cancels the active (or specified) purchase via `usePurchaseActions`.
534
- * Emits `data-state=idle|cancelling` and auto-derives the confirm dialog
535
- * copy from the plan type (`recurring` vs. `usage-based`) unless overridden
536
- * via the `confirm` prop (`false` to skip, string to replace).
537
- */
538
-
539
533
  declare const CancelPlanButton: React.ForwardRefExoticComponent<React.ButtonHTMLAttributes<HTMLButtonElement> & {
540
534
  asChild?: boolean;
541
535
  /** Defaults to the active purchase from `usePurchase()`. */