@solvapay/react 2.0.0 → 2.0.1-preview-7d806cc7af767dec26b099517bc6ededc85adf9a
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 +20 -0
- package/dist/{chunk-PKZJIV3G.js → chunk-J4VSGFAF.js} +1 -1
- package/dist/{chunk-6ABOJOEV.js → chunk-JN5BJ5MI.js} +26 -20
- package/dist/{chunk-D6TOFFNL.js → chunk-VUGPLAS4.js} +4 -3
- package/dist/{index-D6KKDguz.d.cts → index-BuVbt1j1.d.cts} +0 -9
- package/dist/{index-DomaahLG.d.ts → index-DHK9Op-i.d.ts} +0 -9
- package/dist/index.cjs +43 -33
- package/dist/index.d.cts +2 -22
- package/dist/index.d.ts +2 -22
- package/dist/index.js +9 -7
- package/dist/mcp/index.cjs +57 -50
- package/dist/mcp/index.d.cts +2 -5
- package/dist/mcp/index.d.ts +2 -5
- package/dist/mcp/index.js +4 -6
- package/dist/primitives/index.cjs +32 -27
- package/dist/primitives/index.d.cts +2 -2
- package/dist/primitives/index.d.ts +2 -2
- package/dist/primitives/index.js +2 -2
- package/package.json +5 -5
package/dist/mcp/index.cjs
CHANGED
|
@@ -967,10 +967,10 @@ function createHttpTransport(config) {
|
|
|
967
967
|
onErrorContext: "getUsage",
|
|
968
968
|
errorPrefix: "Failed to load usage"
|
|
969
969
|
}),
|
|
970
|
-
getLimits: async ({ productRef, meterName }) => {
|
|
970
|
+
getLimits: async ({ productRef, meterName: meterName2 }) => {
|
|
971
971
|
const base = routeFor(config, "getLimits");
|
|
972
972
|
const params = new URLSearchParams({ productRef });
|
|
973
|
-
if (
|
|
973
|
+
if (meterName2) params.set("meterName", meterName2);
|
|
974
974
|
const url = `${base}?${params.toString()}`;
|
|
975
975
|
const data = await request(config, url, {
|
|
976
976
|
method: "GET",
|
|
@@ -2447,6 +2447,9 @@ var import_mcp_core3 = require("@solvapay/mcp-core");
|
|
|
2447
2447
|
// src/mcp/McpAppShell.tsx
|
|
2448
2448
|
var import_react51 = require("react");
|
|
2449
2449
|
|
|
2450
|
+
// src/components/CurrentPlanCard.tsx
|
|
2451
|
+
var import_core5 = require("@solvapay/core");
|
|
2452
|
+
|
|
2450
2453
|
// src/hooks/usePurchase.ts
|
|
2451
2454
|
function usePurchase() {
|
|
2452
2455
|
const { purchase, refetchPurchase } = useSolvaPay();
|
|
@@ -2983,12 +2986,13 @@ var BalanceBadge = (0, import_react17.forwardRef)(function BalanceBadge2({ asChi
|
|
|
2983
2986
|
});
|
|
2984
2987
|
|
|
2985
2988
|
// src/primitives/CancelPlanButton.tsx
|
|
2989
|
+
var import_core3 = require("@solvapay/core");
|
|
2986
2990
|
var import_react18 = require("react");
|
|
2987
2991
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
2988
2992
|
function resolveConfirmText(confirm, purchase, defaults) {
|
|
2989
2993
|
if (confirm === false) return null;
|
|
2990
2994
|
if (typeof confirm === "string") return confirm;
|
|
2991
|
-
const isUsageBased = purchase?.planSnapshot?.isMetered === true && purchase
|
|
2995
|
+
const isUsageBased = ((0, import_core3.countsUsage)(purchase?.planSnapshot) || purchase?.planSnapshot?.isMetered === true) && purchase?.isRecurring !== true;
|
|
2992
2996
|
if (isUsageBased) return defaults.usageBased;
|
|
2993
2997
|
return defaults.recurring;
|
|
2994
2998
|
}
|
|
@@ -3291,6 +3295,7 @@ var UpdatePaymentMethodButton = (0, import_react22.forwardRef)(function UpdatePa
|
|
|
3291
3295
|
var import_react25 = require("react");
|
|
3292
3296
|
|
|
3293
3297
|
// src/hooks/useUsage.ts
|
|
3298
|
+
var import_core4 = require("@solvapay/core");
|
|
3294
3299
|
var import_react24 = require("react");
|
|
3295
3300
|
|
|
3296
3301
|
// src/hooks/useLimits.ts
|
|
@@ -3311,19 +3316,19 @@ function useCustomer() {
|
|
|
3311
3316
|
var CACHE_TTL_MS = 1e4;
|
|
3312
3317
|
var OPTIMISTIC_GRACE_MS = 8e3;
|
|
3313
3318
|
var limitsCache = /* @__PURE__ */ new Map();
|
|
3314
|
-
function cacheKey(customerRef, productRef,
|
|
3315
|
-
return `${customerRef ?? "anonymous"}:${productRef}:${
|
|
3319
|
+
function cacheKey(customerRef, productRef, meterName2) {
|
|
3320
|
+
return `${customerRef ?? "anonymous"}:${productRef}:${meterName2}`;
|
|
3316
3321
|
}
|
|
3317
3322
|
function isUnlimited(remaining) {
|
|
3318
3323
|
return remaining < 0;
|
|
3319
3324
|
}
|
|
3320
3325
|
function useLimits(options) {
|
|
3321
3326
|
const { productRef, meterName: rawMeterName, enabled = true } = options;
|
|
3322
|
-
const
|
|
3327
|
+
const meterName2 = rawMeterName || "requests";
|
|
3323
3328
|
const transport = useTransport();
|
|
3324
3329
|
const { customerRef } = useCustomer();
|
|
3325
3330
|
const { purchase } = useSolvaPay();
|
|
3326
|
-
const currentKey = !productRef || !enabled ? null : cacheKey(customerRef, productRef,
|
|
3331
|
+
const currentKey = !productRef || !enabled ? null : cacheKey(customerRef, productRef, meterName2);
|
|
3327
3332
|
const [data, setData] = (0, import_react23.useState)(() => {
|
|
3328
3333
|
if (!currentKey) return null;
|
|
3329
3334
|
const cached = limitsCache.get(currentKey);
|
|
@@ -3378,7 +3383,7 @@ function useLimits(options) {
|
|
|
3378
3383
|
setLoading(false);
|
|
3379
3384
|
return;
|
|
3380
3385
|
}
|
|
3381
|
-
const key = cacheKey(customerRef, productRef,
|
|
3386
|
+
const key = cacheKey(customerRef, productRef, meterName2);
|
|
3382
3387
|
const cached = limitsCache.get(key);
|
|
3383
3388
|
const now = Date.now();
|
|
3384
3389
|
if (cached?.promise) {
|
|
@@ -3391,7 +3396,7 @@ function useLimits(options) {
|
|
|
3391
3396
|
setError(null);
|
|
3392
3397
|
return;
|
|
3393
3398
|
}
|
|
3394
|
-
const promise = transport.getLimits({ productRef, meterName });
|
|
3399
|
+
const promise = transport.getLimits({ productRef, meterName: meterName2 });
|
|
3395
3400
|
limitsCache.set(key, { data: cached?.data ?? null, timestamp: now, promise });
|
|
3396
3401
|
const fresh = await attachToFetch(promise);
|
|
3397
3402
|
if (fresh !== null) {
|
|
@@ -3400,7 +3405,7 @@ function useLimits(options) {
|
|
|
3400
3405
|
limitsCache.delete(key);
|
|
3401
3406
|
}
|
|
3402
3407
|
},
|
|
3403
|
-
[transport, customerRef, productRef,
|
|
3408
|
+
[transport, customerRef, productRef, meterName2, enabled, attachToFetch]
|
|
3404
3409
|
);
|
|
3405
3410
|
(0, import_react23.useEffect)(() => {
|
|
3406
3411
|
fetchLimits(false);
|
|
@@ -3418,7 +3423,7 @@ function useLimits(options) {
|
|
|
3418
3423
|
(delta) => {
|
|
3419
3424
|
if (!productRef || !enabled) return;
|
|
3420
3425
|
if (unlimitedRef.current) return;
|
|
3421
|
-
const key = cacheKey(customerRef, productRef,
|
|
3426
|
+
const key = cacheKey(customerRef, productRef, meterName2);
|
|
3422
3427
|
setData((prev) => {
|
|
3423
3428
|
const cached = limitsCache.get(key);
|
|
3424
3429
|
const baseline = prev ?? cached?.data ?? null;
|
|
@@ -3445,7 +3450,7 @@ function useLimits(options) {
|
|
|
3445
3450
|
});
|
|
3446
3451
|
}, OPTIMISTIC_GRACE_MS);
|
|
3447
3452
|
},
|
|
3448
|
-
[customerRef, productRef,
|
|
3453
|
+
[customerRef, productRef, meterName2, enabled, fetchLimits]
|
|
3449
3454
|
);
|
|
3450
3455
|
return {
|
|
3451
3456
|
remaining: data?.remaining ?? null,
|
|
@@ -3464,7 +3469,9 @@ function useLimits(options) {
|
|
|
3464
3469
|
function deriveUsage(purchase, limits) {
|
|
3465
3470
|
if (!purchase) return null;
|
|
3466
3471
|
const usage = purchase.usage;
|
|
3467
|
-
if (purchase.planSnapshot?.isMetered !== true && !usage)
|
|
3472
|
+
if (!(0, import_core4.countsUsage)(purchase.planSnapshot) && purchase.planSnapshot?.isMetered !== true && !usage) {
|
|
3473
|
+
return null;
|
|
3474
|
+
}
|
|
3468
3475
|
const used = typeof usage?.used === "number" ? usage.used : 0;
|
|
3469
3476
|
const hasFiniteCap = limits.unlimited === false && limits.remaining !== null;
|
|
3470
3477
|
const remaining = hasFiniteCap ? limits.remaining : null;
|
|
@@ -3487,18 +3494,18 @@ function useUsage() {
|
|
|
3487
3494
|
const [override, setOverride] = (0, import_react24.useState)(null);
|
|
3488
3495
|
const [error, setError] = (0, import_react24.useState)(null);
|
|
3489
3496
|
const [transportLoading, setTransportLoading] = (0, import_react24.useState)(false);
|
|
3490
|
-
const
|
|
3497
|
+
const usageCounted = (0, import_core4.countsUsage)(activePurchase?.planSnapshot) || activePurchase?.planSnapshot?.isMetered === true;
|
|
3491
3498
|
const {
|
|
3492
3499
|
remaining: limitRemaining,
|
|
3493
3500
|
unlimited,
|
|
3494
|
-
meterName
|
|
3501
|
+
meterName: meterName2
|
|
3495
3502
|
} = useLimits({
|
|
3496
3503
|
productRef: activePurchase?.productRef,
|
|
3497
|
-
enabled:
|
|
3504
|
+
enabled: usageCounted
|
|
3498
3505
|
});
|
|
3499
3506
|
const derived = (0, import_react24.useMemo)(
|
|
3500
|
-
() => deriveUsage(activePurchase ?? null, { remaining: limitRemaining, unlimited, meterName }),
|
|
3501
|
-
[activePurchase, limitRemaining, unlimited,
|
|
3507
|
+
() => deriveUsage(activePurchase ?? null, { remaining: limitRemaining, unlimited, meterName: meterName2 }),
|
|
3508
|
+
[activePurchase, limitRemaining, unlimited, meterName2]
|
|
3502
3509
|
);
|
|
3503
3510
|
const activePurchaseRef = activePurchase?.reference ?? null;
|
|
3504
3511
|
(0, import_react24.useEffect)(() => {
|
|
@@ -3755,7 +3762,7 @@ function PlanTypeLine({
|
|
|
3755
3762
|
className
|
|
3756
3763
|
}) {
|
|
3757
3764
|
const copy = useCopy();
|
|
3758
|
-
const isMetered = purchase.planSnapshot?.isMetered === true;
|
|
3765
|
+
const isMetered = (0, import_core5.countsUsage)(purchase.planSnapshot) || purchase.planSnapshot?.isMetered === true;
|
|
3759
3766
|
if (purchase.isRecurring) {
|
|
3760
3767
|
const date2 = formatDate(purchase.nextBillingDate);
|
|
3761
3768
|
if (!date2) return null;
|
|
@@ -3815,7 +3822,7 @@ var CurrentPlanCard = ({
|
|
|
3815
3822
|
const { formatDate, shouldShowCancelledNotice } = usePurchaseStatus();
|
|
3816
3823
|
const { paymentMethod } = usePaymentMethod();
|
|
3817
3824
|
if (!activePurchase) return null;
|
|
3818
|
-
const isUsageBased = activePurchase.planSnapshot?.isMetered === true;
|
|
3825
|
+
const isUsageBased = (0, import_core5.countsUsage)(activePurchase.planSnapshot) || activePurchase.planSnapshot?.isMetered === true;
|
|
3819
3826
|
const planType = activePurchase.isRecurring ? "recurring" : isUsageBased ? "usage-based" : "one-time";
|
|
3820
3827
|
const amount = activePurchase.originalAmount ?? activePurchase.amount ?? 0;
|
|
3821
3828
|
const currency = activePurchase.currency ?? "usd";
|
|
@@ -3954,7 +3961,7 @@ var CurrentPlanCard = ({
|
|
|
3954
3961
|
};
|
|
3955
3962
|
|
|
3956
3963
|
// src/mcp/views/detail-cards.tsx
|
|
3957
|
-
var
|
|
3964
|
+
var import_core6 = require("@solvapay/core");
|
|
3958
3965
|
|
|
3959
3966
|
// src/mcp/views/types.ts
|
|
3960
3967
|
var DEFAULT_MCP_CLASS_NAMES = {
|
|
@@ -4036,7 +4043,7 @@ function McpCustomerDetailsCard({
|
|
|
4036
4043
|
}
|
|
4037
4044
|
const displayName = name?.trim() || "Customer";
|
|
4038
4045
|
const showBalance = !hideBalance && typeof credits === "number" && credits > 0;
|
|
4039
|
-
const displayMinor = showBalance && typeof creditsPerMinorUnit === "number" && creditsPerMinorUnit > 0 && displayCurrency ? (0,
|
|
4046
|
+
const displayMinor = showBalance && typeof creditsPerMinorUnit === "number" && creditsPerMinorUnit > 0 && displayCurrency ? (0, import_core6.creditsToDisplayMinorUnits)({
|
|
4040
4047
|
credits: credits ?? 0,
|
|
4041
4048
|
creditsPerMinorUnit,
|
|
4042
4049
|
displayExchangeRate: displayExchangeRate ?? 1,
|
|
@@ -4099,7 +4106,7 @@ function McpSellerDetailsCard({
|
|
|
4099
4106
|
}
|
|
4100
4107
|
const supportEmail = merchant.supportEmail;
|
|
4101
4108
|
const supportUrl = merchant.supportUrl;
|
|
4102
|
-
const sellerIdentity = (0,
|
|
4109
|
+
const sellerIdentity = (0, import_core6.resolveSellerIdentityDisplay)({
|
|
4103
4110
|
country: merchant.country,
|
|
4104
4111
|
vatNumber: merchant.vatNumber,
|
|
4105
4112
|
taxId: merchant.taxId,
|
|
@@ -4252,13 +4259,13 @@ function isPaygPlan(plan) {
|
|
|
4252
4259
|
}
|
|
4253
4260
|
|
|
4254
4261
|
// src/utils/planPricing.ts
|
|
4255
|
-
var
|
|
4262
|
+
var import_core7 = require("@solvapay/core");
|
|
4256
4263
|
function getPlanPricingOptions(plan) {
|
|
4257
4264
|
if (plan.pricingOptions && plan.pricingOptions.length > 0) {
|
|
4258
4265
|
return plan.pricingOptions;
|
|
4259
4266
|
}
|
|
4260
4267
|
const defaultCurrency = (plan.currency ?? "USD").toUpperCase();
|
|
4261
|
-
const charges2 = (0,
|
|
4268
|
+
const charges2 = (0, import_core7.headlineCharges)(plan);
|
|
4262
4269
|
if (charges2.length > 0) {
|
|
4263
4270
|
return charges2.map((charge) => ({
|
|
4264
4271
|
currency: charge.currency,
|
|
@@ -4687,7 +4694,7 @@ function usePlanSelector() {
|
|
|
4687
4694
|
var import_react28 = require("react");
|
|
4688
4695
|
|
|
4689
4696
|
// src/primitives/checkout/shared.ts
|
|
4690
|
-
var
|
|
4697
|
+
var import_core8 = require("@solvapay/core");
|
|
4691
4698
|
function isPayg(plan) {
|
|
4692
4699
|
return isPaygPlan(plan ?? null);
|
|
4693
4700
|
}
|
|
@@ -4718,25 +4725,25 @@ function formatContinueLabel(plan, locale, pricingOption) {
|
|
|
4718
4725
|
return `Continue with ${plan.name ?? "Plan"} \u2014 ${priceLabel}${cycle}`;
|
|
4719
4726
|
}
|
|
4720
4727
|
function planBillingInterval(plan) {
|
|
4721
|
-
return (0,
|
|
4728
|
+
return (0, import_core8.billingCycle)(plan)?.interval ?? null;
|
|
4722
4729
|
}
|
|
4723
4730
|
function formatPaygRate(plan, locale, balance) {
|
|
4724
|
-
const credits = (0,
|
|
4731
|
+
const credits = (0, import_core8.creditsPerUnitFromBalance)(plan, balance);
|
|
4725
4732
|
if (credits != null) {
|
|
4726
4733
|
return `${credits.toLocaleString(locale)} ${credits === 1 ? "credit" : "credits"} / call`;
|
|
4727
4734
|
}
|
|
4728
|
-
const charge = (0,
|
|
4735
|
+
const charge = (0, import_core8.perUnitCharge)(plan);
|
|
4729
4736
|
if (charge && charge.amountMinor > 0) {
|
|
4730
4737
|
return `${formatPrice(charge.amountMinor, charge.currency.toUpperCase(), { locale })} / call`;
|
|
4731
4738
|
}
|
|
4732
4739
|
return null;
|
|
4733
4740
|
}
|
|
4734
4741
|
function inferIncludedUnits(plan) {
|
|
4735
|
-
const cap = (0,
|
|
4742
|
+
const cap = (0, import_core8.includedUnits)(plan);
|
|
4736
4743
|
return cap != null && cap > 0 ? cap : null;
|
|
4737
4744
|
}
|
|
4738
4745
|
function planMeterName(plan) {
|
|
4739
|
-
return (0,
|
|
4746
|
+
return (0, import_core8.meterName)(plan);
|
|
4740
4747
|
}
|
|
4741
4748
|
function shortCycle(cycle) {
|
|
4742
4749
|
if (!cycle) return "mo";
|
|
@@ -5988,14 +5995,14 @@ var Spinner = ({ className, size = "md" }) => {
|
|
|
5988
5995
|
|
|
5989
5996
|
// src/hooks/useBusinessDetailsAttach.ts
|
|
5990
5997
|
var import_react38 = require("react");
|
|
5991
|
-
var
|
|
5998
|
+
var import_core10 = require("@solvapay/core");
|
|
5992
5999
|
|
|
5993
6000
|
// src/components/businessCheckoutParts.tsx
|
|
5994
6001
|
var import_react37 = require("react");
|
|
5995
|
-
var
|
|
6002
|
+
var import_core9 = require("@solvapay/core");
|
|
5996
6003
|
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
5997
6004
|
function mapBusinessFieldErrors(input) {
|
|
5998
|
-
const result = (0,
|
|
6005
|
+
const result = (0, import_core9.validateBusinessDetails)(input);
|
|
5999
6006
|
if (result.success) return {};
|
|
6000
6007
|
const errors = {};
|
|
6001
6008
|
for (const issue of result.error.issues) {
|
|
@@ -6012,25 +6019,25 @@ function isBusinessDetailsKey(key) {
|
|
|
6012
6019
|
function attr(prefix, suffix) {
|
|
6013
6020
|
return `data-solvapay-${prefix}-${suffix}`;
|
|
6014
6021
|
}
|
|
6015
|
-
var SUPPORTED_BUSINESS_COUNTRIES_SET = new Set(
|
|
6022
|
+
var SUPPORTED_BUSINESS_COUNTRIES_SET = new Set(import_core9.SUPPORTED_BUSINESS_COUNTRIES);
|
|
6016
6023
|
function isSupportedBusinessCountry(value) {
|
|
6017
6024
|
return SUPPORTED_BUSINESS_COUNTRIES_SET.has(value);
|
|
6018
6025
|
}
|
|
6019
6026
|
function resolveTaxIdLabel(country) {
|
|
6020
6027
|
if (country && isSupportedBusinessCountry(country)) {
|
|
6021
|
-
return (0,
|
|
6028
|
+
return (0, import_core9.getTaxIdFieldLabel)(country);
|
|
6022
6029
|
}
|
|
6023
6030
|
return "Tax ID";
|
|
6024
6031
|
}
|
|
6025
6032
|
function resolveTaxIdPlaceholder(country) {
|
|
6026
6033
|
if (country && isSupportedBusinessCountry(country)) {
|
|
6027
|
-
return (0,
|
|
6034
|
+
return (0, import_core9.getTaxIdExample)(country);
|
|
6028
6035
|
}
|
|
6029
6036
|
return "Enter tax ID";
|
|
6030
6037
|
}
|
|
6031
6038
|
function resolveTaxIdHelperText(country) {
|
|
6032
6039
|
if (country && isSupportedBusinessCountry(country)) {
|
|
6033
|
-
return (0,
|
|
6040
|
+
return (0, import_core9.getTaxIdHelperText)(country);
|
|
6034
6041
|
}
|
|
6035
6042
|
return "";
|
|
6036
6043
|
}
|
|
@@ -6105,7 +6112,7 @@ function createBusinessDetailsParts(useCtx, prefix) {
|
|
|
6105
6112
|
};
|
|
6106
6113
|
const defaultOptions = /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
|
|
6107
6114
|
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("option", { value: "", children: "Select country" }),
|
|
6108
|
-
|
|
6115
|
+
import_core9.BUSINESS_COUNTRY_OPTIONS.map(({ value, label }) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("option", { value, children: label }, value))
|
|
6109
6116
|
] });
|
|
6110
6117
|
if (asChild) {
|
|
6111
6118
|
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Slot, { ref: forwardedRef, ...commonProps, children: children ?? defaultOptions });
|
|
@@ -6310,7 +6317,7 @@ function useBusinessDetailsAttach(options) {
|
|
|
6310
6317
|
if (!processorPaymentId || !attachBusinessDetails) {
|
|
6311
6318
|
return !attachBusinessDetails;
|
|
6312
6319
|
}
|
|
6313
|
-
const validation = (0,
|
|
6320
|
+
const validation = (0, import_core10.validateBusinessDetails)(input);
|
|
6314
6321
|
if (!validation.success) {
|
|
6315
6322
|
setFieldErrors(mapBusinessFieldErrors(input));
|
|
6316
6323
|
return false;
|
|
@@ -6349,7 +6356,7 @@ function useBusinessDetailsAttach(options) {
|
|
|
6349
6356
|
);
|
|
6350
6357
|
(0, import_react38.useEffect)(() => {
|
|
6351
6358
|
if (!processorPaymentId || !attachBusinessDetails) return;
|
|
6352
|
-
const validation = (0,
|
|
6359
|
+
const validation = (0, import_core10.validateBusinessDetails)(businessDetails);
|
|
6353
6360
|
if (!validation.success) {
|
|
6354
6361
|
setFieldErrors(mapBusinessFieldErrors(businessDetails));
|
|
6355
6362
|
setBusinessDetailsAttached(false);
|
|
@@ -7555,7 +7562,8 @@ function normalizeOneTimePurchase(input) {
|
|
|
7555
7562
|
planSnapshot: {
|
|
7556
7563
|
price: input.amount,
|
|
7557
7564
|
currency: input.currency,
|
|
7558
|
-
isMetered: false
|
|
7565
|
+
isMetered: false,
|
|
7566
|
+
options: []
|
|
7559
7567
|
}
|
|
7560
7568
|
};
|
|
7561
7569
|
}
|
|
@@ -8463,7 +8471,7 @@ var RecurringPaymentStep = (0, import_react46.memo)(function RecurringPaymentSte
|
|
|
8463
8471
|
const amountMinor = pricingOption.price ?? 0;
|
|
8464
8472
|
const cycle = planBillingInterval(plan) ?? "month";
|
|
8465
8473
|
const included = inferIncludedUnits(plan);
|
|
8466
|
-
const
|
|
8474
|
+
const meterName2 = planMeterName(plan) ?? "units";
|
|
8467
8475
|
const planName = plan.name ?? "Plan";
|
|
8468
8476
|
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_jsx_runtime32.Fragment, { children: [
|
|
8469
8477
|
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(BackLink, { label: "Change plan", onClick: onBack }),
|
|
@@ -8480,7 +8488,7 @@ var RecurringPaymentStep = (0, import_react46.memo)(function RecurringPaymentSte
|
|
|
8480
8488
|
included != null ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "solvapay-mcp-checkout-order-summary-row", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("span", { className: cx.muted, children: [
|
|
8481
8489
|
included.toLocaleString(locale),
|
|
8482
8490
|
" ",
|
|
8483
|
-
|
|
8491
|
+
meterName2,
|
|
8484
8492
|
" included"
|
|
8485
8493
|
] }) }) : null
|
|
8486
8494
|
] }),
|
|
@@ -9898,22 +9906,21 @@ function McpApp({
|
|
|
9898
9906
|
}
|
|
9899
9907
|
|
|
9900
9908
|
// src/mcp/plan-actions.ts
|
|
9901
|
-
var
|
|
9909
|
+
var import_core11 = require("@solvapay/core");
|
|
9902
9910
|
function isPaidPlan(plan) {
|
|
9903
9911
|
if (plan.requiresPayment === false) return false;
|
|
9904
|
-
if ((0,
|
|
9912
|
+
if ((0, import_core11.charges)(plan).some((charge) => charge.amountMinor > 0)) return true;
|
|
9905
9913
|
return (plan.price ?? 0) > 0;
|
|
9906
9914
|
}
|
|
9907
9915
|
function isMeteredPlan(plan) {
|
|
9908
|
-
|
|
9909
|
-
return (0, import_core8.perUnitCharge)(plan) != null || (0, import_core8.includedUnits)(plan) != null;
|
|
9916
|
+
return (0, import_core11.countsUsage)(plan);
|
|
9910
9917
|
}
|
|
9911
9918
|
function resolvePlanShape(plan) {
|
|
9912
9919
|
if (!plan) return null;
|
|
9913
|
-
if (((0,
|
|
9920
|
+
if (((0, import_core11.trialDays)(plan) ?? 0) > 0) return "trial";
|
|
9914
9921
|
if (!isPaidPlan(plan)) return "free";
|
|
9915
9922
|
const metered = isMeteredPlan(plan);
|
|
9916
|
-
if ((0,
|
|
9923
|
+
if ((0, import_core11.billingCycle)(plan)) return metered ? "recurring-metered" : "recurring-unlimited";
|
|
9917
9924
|
return metered ? "usage-based" : "recurring-unlimited";
|
|
9918
9925
|
}
|
|
9919
9926
|
function resolveActivationStrategy(plan) {
|
package/dist/mcp/index.d.cts
CHANGED
|
@@ -897,17 +897,14 @@ type PlanShape = 'free' | 'trial' | 'usage-based' | 'recurring-unlimited' | 'rec
|
|
|
897
897
|
type ActivationStrategy = 'activate' | 'topup-first' | 'paid-checkout';
|
|
898
898
|
/**
|
|
899
899
|
* The subset of a plan — or of the plan snapshot frozen onto a purchase
|
|
900
|
-
* — that the shape derivation reads.
|
|
901
|
-
*
|
|
902
|
-
* carries both. Everything else comes out of `options[]`.
|
|
900
|
+
* — that the shape derivation reads. A plan carries `requiresPayment`;
|
|
901
|
+
* a snapshot may not. Usage-counting and the rest come out of `options[]`.
|
|
903
902
|
*/
|
|
904
903
|
interface PlanLike {
|
|
905
904
|
/** Composable pricing options: charges, billing cycle, limit, trial. */
|
|
906
905
|
options?: PricingOptionLike[] | null;
|
|
907
906
|
/** `false` marks a free plan. Only present on a plan, not a snapshot. */
|
|
908
907
|
requiresPayment?: boolean | null;
|
|
909
|
-
/** Set on a frozen purchase snapshot when the plan meters usage. */
|
|
910
|
-
isMetered?: boolean | null;
|
|
911
908
|
/** Derived headline amount; only a fallback for snapshots frozen before `options[]`. */
|
|
912
909
|
price?: number | null;
|
|
913
910
|
currency?: string | null;
|
package/dist/mcp/index.d.ts
CHANGED
|
@@ -897,17 +897,14 @@ type PlanShape = 'free' | 'trial' | 'usage-based' | 'recurring-unlimited' | 'rec
|
|
|
897
897
|
type ActivationStrategy = 'activate' | 'topup-first' | 'paid-checkout';
|
|
898
898
|
/**
|
|
899
899
|
* The subset of a plan — or of the plan snapshot frozen onto a purchase
|
|
900
|
-
* — that the shape derivation reads.
|
|
901
|
-
*
|
|
902
|
-
* carries both. Everything else comes out of `options[]`.
|
|
900
|
+
* — that the shape derivation reads. A plan carries `requiresPayment`;
|
|
901
|
+
* a snapshot may not. Usage-counting and the rest come out of `options[]`.
|
|
903
902
|
*/
|
|
904
903
|
interface PlanLike {
|
|
905
904
|
/** Composable pricing options: charges, billing cycle, limit, trial. */
|
|
906
905
|
options?: PricingOptionLike[] | null;
|
|
907
906
|
/** `false` marks a free plan. Only present on a plan, not a snapshot. */
|
|
908
907
|
requiresPayment?: boolean | null;
|
|
909
|
-
/** Set on a frozen purchase snapshot when the plan meters usage. */
|
|
910
|
-
isMetered?: boolean | null;
|
|
911
908
|
/** Derived headline amount; only a fallback for snapshots frozen before `options[]`. */
|
|
912
909
|
price?: number | null;
|
|
913
910
|
currency?: string | null;
|
package/dist/mcp/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
ExternalLinkGlyph,
|
|
4
4
|
LaunchCustomerPortalButton,
|
|
5
5
|
paymentMethodCache
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-VUGPLAS4.js";
|
|
7
7
|
import {
|
|
8
8
|
AmountPicker,
|
|
9
9
|
BalanceBadge,
|
|
@@ -41,7 +41,7 @@ import {
|
|
|
41
41
|
usePurchaseStatus,
|
|
42
42
|
useTopupAmountSelector,
|
|
43
43
|
useTransport
|
|
44
|
-
} from "../chunk-
|
|
44
|
+
} from "../chunk-JN5BJ5MI.js";
|
|
45
45
|
import "../chunk-UMXOAUW7.js";
|
|
46
46
|
import "../chunk-MLKGABMK.js";
|
|
47
47
|
|
|
@@ -2568,8 +2568,7 @@ function McpApp({
|
|
|
2568
2568
|
import {
|
|
2569
2569
|
billingCycle,
|
|
2570
2570
|
charges,
|
|
2571
|
-
|
|
2572
|
-
perUnitCharge,
|
|
2571
|
+
countsUsage,
|
|
2573
2572
|
trialDays
|
|
2574
2573
|
} from "@solvapay/core";
|
|
2575
2574
|
function isPaidPlan(plan) {
|
|
@@ -2578,8 +2577,7 @@ function isPaidPlan(plan) {
|
|
|
2578
2577
|
return (plan.price ?? 0) > 0;
|
|
2579
2578
|
}
|
|
2580
2579
|
function isMeteredPlan(plan) {
|
|
2581
|
-
|
|
2582
|
-
return perUnitCharge(plan) != null || includedUnits(plan) != null;
|
|
2580
|
+
return countsUsage(plan);
|
|
2583
2581
|
}
|
|
2584
2582
|
function resolvePlanShape(plan) {
|
|
2585
2583
|
if (!plan) return null;
|
|
@@ -665,10 +665,10 @@ function createHttpTransport(config) {
|
|
|
665
665
|
onErrorContext: "getUsage",
|
|
666
666
|
errorPrefix: "Failed to load usage"
|
|
667
667
|
}),
|
|
668
|
-
getLimits: async ({ productRef, meterName }) => {
|
|
668
|
+
getLimits: async ({ productRef, meterName: meterName2 }) => {
|
|
669
669
|
const base = routeFor(config, "getLimits");
|
|
670
670
|
const params = new URLSearchParams({ productRef });
|
|
671
|
-
if (
|
|
671
|
+
if (meterName2) params.set("meterName", meterName2);
|
|
672
672
|
const url = `${base}?${params.toString()}`;
|
|
673
673
|
const data = await request(config, url, {
|
|
674
674
|
method: "GET",
|
|
@@ -2998,7 +2998,8 @@ function normalizeOneTimePurchase(input) {
|
|
|
2998
2998
|
planSnapshot: {
|
|
2999
2999
|
price: input.amount,
|
|
3000
3000
|
currency: input.currency,
|
|
3001
|
-
isMetered: false
|
|
3001
|
+
isMetered: false,
|
|
3002
|
+
options: []
|
|
3002
3003
|
}
|
|
3003
3004
|
};
|
|
3004
3005
|
}
|
|
@@ -4929,6 +4930,7 @@ var BalanceBadge = (0, import_react24.forwardRef)(function BalanceBadge2({ asChi
|
|
|
4929
4930
|
});
|
|
4930
4931
|
|
|
4931
4932
|
// src/primitives/CancelPlanButton.tsx
|
|
4933
|
+
var import_core5 = require("@solvapay/core");
|
|
4932
4934
|
var import_react26 = require("react");
|
|
4933
4935
|
|
|
4934
4936
|
// src/hooks/usePurchaseActions.ts
|
|
@@ -4986,7 +4988,7 @@ var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
|
4986
4988
|
function resolveConfirmText(confirm, purchase, defaults) {
|
|
4987
4989
|
if (confirm === false) return null;
|
|
4988
4990
|
if (typeof confirm === "string") return confirm;
|
|
4989
|
-
const isUsageBased = purchase?.planSnapshot?.isMetered === true && purchase
|
|
4991
|
+
const isUsageBased = ((0, import_core5.countsUsage)(purchase?.planSnapshot) || purchase?.planSnapshot?.isMetered === true) && purchase?.isRecurring !== true;
|
|
4990
4992
|
if (isUsageBased) return defaults.usageBased;
|
|
4991
4993
|
return defaults.recurring;
|
|
4992
4994
|
}
|
|
@@ -6319,7 +6321,7 @@ function stripSetupIntentParams() {
|
|
|
6319
6321
|
}
|
|
6320
6322
|
|
|
6321
6323
|
// src/utils/credit-estimation.ts
|
|
6322
|
-
var
|
|
6324
|
+
var import_core6 = require("@solvapay/core");
|
|
6323
6325
|
function estimateCredits(resolvedAmountMajor, currency, creditsPerMinorUnit, displayExchangeRate) {
|
|
6324
6326
|
if (resolvedAmountMajor == null || resolvedAmountMajor <= 0) return null;
|
|
6325
6327
|
if (creditsPerMinorUnit == null || creditsPerMinorUnit <= 0) return null;
|
|
@@ -6331,7 +6333,7 @@ function estimateCurrencyMajorFromCredits(credits, currency, creditsPerMinorUnit
|
|
|
6331
6333
|
if (credits == null || credits <= 0) return null;
|
|
6332
6334
|
if (creditsPerMinorUnit == null || creditsPerMinorUnit <= 0) return null;
|
|
6333
6335
|
const rate = displayExchangeRate ?? 1;
|
|
6334
|
-
const displayMinor = (0,
|
|
6336
|
+
const displayMinor = (0, import_core6.creditsToDisplayMinorUnits)({
|
|
6335
6337
|
credits,
|
|
6336
6338
|
creditsPerMinorUnit,
|
|
6337
6339
|
displayExchangeRate: rate,
|
|
@@ -7882,7 +7884,7 @@ function useTransport() {
|
|
|
7882
7884
|
}
|
|
7883
7885
|
|
|
7884
7886
|
// src/primitives/checkout/shared.ts
|
|
7885
|
-
var
|
|
7887
|
+
var import_core7 = require("@solvapay/core");
|
|
7886
7888
|
function isPayg(plan) {
|
|
7887
7889
|
return isPaygPlan(plan ?? null);
|
|
7888
7890
|
}
|
|
@@ -7923,25 +7925,25 @@ function formatContinueLabel(plan, locale, pricingOption) {
|
|
|
7923
7925
|
return `Continue with ${plan.name ?? "Plan"} \u2014 ${priceLabel}${cycle}`;
|
|
7924
7926
|
}
|
|
7925
7927
|
function planBillingInterval(plan) {
|
|
7926
|
-
return (0,
|
|
7928
|
+
return (0, import_core7.billingCycle)(plan)?.interval ?? null;
|
|
7927
7929
|
}
|
|
7928
7930
|
function formatPaygRate(plan, locale, balance) {
|
|
7929
|
-
const credits = (0,
|
|
7931
|
+
const credits = (0, import_core7.creditsPerUnitFromBalance)(plan, balance);
|
|
7930
7932
|
if (credits != null) {
|
|
7931
7933
|
return `${credits.toLocaleString(locale)} ${credits === 1 ? "credit" : "credits"} / call`;
|
|
7932
7934
|
}
|
|
7933
|
-
const charge = (0,
|
|
7935
|
+
const charge = (0, import_core7.perUnitCharge)(plan);
|
|
7934
7936
|
if (charge && charge.amountMinor > 0) {
|
|
7935
7937
|
return `${formatPrice(charge.amountMinor, charge.currency.toUpperCase(), { locale })} / call`;
|
|
7936
7938
|
}
|
|
7937
7939
|
return null;
|
|
7938
7940
|
}
|
|
7939
7941
|
function inferIncludedUnits(plan) {
|
|
7940
|
-
const cap = (0,
|
|
7942
|
+
const cap = (0, import_core7.includedUnits)(plan);
|
|
7941
7943
|
return cap != null && cap > 0 ? cap : null;
|
|
7942
7944
|
}
|
|
7943
7945
|
function planMeterName(plan) {
|
|
7944
|
-
return (0,
|
|
7946
|
+
return (0, import_core7.meterName)(plan);
|
|
7945
7947
|
}
|
|
7946
7948
|
function shortCycle(cycle) {
|
|
7947
7949
|
if (!cycle) return "mo";
|
|
@@ -9116,6 +9118,7 @@ function usePaywallNoticeOptional() {
|
|
|
9116
9118
|
var import_react43 = require("react");
|
|
9117
9119
|
|
|
9118
9120
|
// src/hooks/useUsage.ts
|
|
9121
|
+
var import_core8 = require("@solvapay/core");
|
|
9119
9122
|
var import_react42 = require("react");
|
|
9120
9123
|
|
|
9121
9124
|
// src/hooks/useLimits.ts
|
|
@@ -9123,19 +9126,19 @@ var import_react41 = require("react");
|
|
|
9123
9126
|
var CACHE_TTL_MS = 1e4;
|
|
9124
9127
|
var OPTIMISTIC_GRACE_MS = 8e3;
|
|
9125
9128
|
var limitsCache = /* @__PURE__ */ new Map();
|
|
9126
|
-
function cacheKey(customerRef, productRef,
|
|
9127
|
-
return `${customerRef ?? "anonymous"}:${productRef}:${
|
|
9129
|
+
function cacheKey(customerRef, productRef, meterName2) {
|
|
9130
|
+
return `${customerRef ?? "anonymous"}:${productRef}:${meterName2}`;
|
|
9128
9131
|
}
|
|
9129
9132
|
function isUnlimited(remaining) {
|
|
9130
9133
|
return remaining < 0;
|
|
9131
9134
|
}
|
|
9132
9135
|
function useLimits(options) {
|
|
9133
9136
|
const { productRef, meterName: rawMeterName, enabled = true } = options;
|
|
9134
|
-
const
|
|
9137
|
+
const meterName2 = rawMeterName || "requests";
|
|
9135
9138
|
const transport = useTransport();
|
|
9136
9139
|
const { customerRef } = useCustomer();
|
|
9137
9140
|
const { purchase } = useSolvaPay();
|
|
9138
|
-
const currentKey = !productRef || !enabled ? null : cacheKey(customerRef, productRef,
|
|
9141
|
+
const currentKey = !productRef || !enabled ? null : cacheKey(customerRef, productRef, meterName2);
|
|
9139
9142
|
const [data, setData] = (0, import_react41.useState)(() => {
|
|
9140
9143
|
if (!currentKey) return null;
|
|
9141
9144
|
const cached = limitsCache.get(currentKey);
|
|
@@ -9190,7 +9193,7 @@ function useLimits(options) {
|
|
|
9190
9193
|
setLoading(false);
|
|
9191
9194
|
return;
|
|
9192
9195
|
}
|
|
9193
|
-
const key = cacheKey(customerRef, productRef,
|
|
9196
|
+
const key = cacheKey(customerRef, productRef, meterName2);
|
|
9194
9197
|
const cached = limitsCache.get(key);
|
|
9195
9198
|
const now = Date.now();
|
|
9196
9199
|
if (cached?.promise) {
|
|
@@ -9203,7 +9206,7 @@ function useLimits(options) {
|
|
|
9203
9206
|
setError(null);
|
|
9204
9207
|
return;
|
|
9205
9208
|
}
|
|
9206
|
-
const promise = transport.getLimits({ productRef, meterName });
|
|
9209
|
+
const promise = transport.getLimits({ productRef, meterName: meterName2 });
|
|
9207
9210
|
limitsCache.set(key, { data: cached?.data ?? null, timestamp: now, promise });
|
|
9208
9211
|
const fresh = await attachToFetch(promise);
|
|
9209
9212
|
if (fresh !== null) {
|
|
@@ -9212,7 +9215,7 @@ function useLimits(options) {
|
|
|
9212
9215
|
limitsCache.delete(key);
|
|
9213
9216
|
}
|
|
9214
9217
|
},
|
|
9215
|
-
[transport, customerRef, productRef,
|
|
9218
|
+
[transport, customerRef, productRef, meterName2, enabled, attachToFetch]
|
|
9216
9219
|
);
|
|
9217
9220
|
(0, import_react41.useEffect)(() => {
|
|
9218
9221
|
fetchLimits(false);
|
|
@@ -9230,7 +9233,7 @@ function useLimits(options) {
|
|
|
9230
9233
|
(delta) => {
|
|
9231
9234
|
if (!productRef || !enabled) return;
|
|
9232
9235
|
if (unlimitedRef.current) return;
|
|
9233
|
-
const key = cacheKey(customerRef, productRef,
|
|
9236
|
+
const key = cacheKey(customerRef, productRef, meterName2);
|
|
9234
9237
|
setData((prev) => {
|
|
9235
9238
|
const cached = limitsCache.get(key);
|
|
9236
9239
|
const baseline = prev ?? cached?.data ?? null;
|
|
@@ -9257,7 +9260,7 @@ function useLimits(options) {
|
|
|
9257
9260
|
});
|
|
9258
9261
|
}, OPTIMISTIC_GRACE_MS);
|
|
9259
9262
|
},
|
|
9260
|
-
[customerRef, productRef,
|
|
9263
|
+
[customerRef, productRef, meterName2, enabled, fetchLimits]
|
|
9261
9264
|
);
|
|
9262
9265
|
return {
|
|
9263
9266
|
remaining: data?.remaining ?? null,
|
|
@@ -9276,7 +9279,9 @@ function useLimits(options) {
|
|
|
9276
9279
|
function deriveUsage(purchase, limits) {
|
|
9277
9280
|
if (!purchase) return null;
|
|
9278
9281
|
const usage = purchase.usage;
|
|
9279
|
-
if (purchase.planSnapshot?.isMetered !== true && !usage)
|
|
9282
|
+
if (!(0, import_core8.countsUsage)(purchase.planSnapshot) && purchase.planSnapshot?.isMetered !== true && !usage) {
|
|
9283
|
+
return null;
|
|
9284
|
+
}
|
|
9280
9285
|
const used = typeof usage?.used === "number" ? usage.used : 0;
|
|
9281
9286
|
const hasFiniteCap = limits.unlimited === false && limits.remaining !== null;
|
|
9282
9287
|
const remaining = hasFiniteCap ? limits.remaining : null;
|
|
@@ -9299,18 +9304,18 @@ function useUsage() {
|
|
|
9299
9304
|
const [override, setOverride] = (0, import_react42.useState)(null);
|
|
9300
9305
|
const [error, setError] = (0, import_react42.useState)(null);
|
|
9301
9306
|
const [transportLoading, setTransportLoading] = (0, import_react42.useState)(false);
|
|
9302
|
-
const
|
|
9307
|
+
const usageCounted = (0, import_core8.countsUsage)(activePurchase?.planSnapshot) || activePurchase?.planSnapshot?.isMetered === true;
|
|
9303
9308
|
const {
|
|
9304
9309
|
remaining: limitRemaining,
|
|
9305
9310
|
unlimited,
|
|
9306
|
-
meterName
|
|
9311
|
+
meterName: meterName2
|
|
9307
9312
|
} = useLimits({
|
|
9308
9313
|
productRef: activePurchase?.productRef,
|
|
9309
|
-
enabled:
|
|
9314
|
+
enabled: usageCounted
|
|
9310
9315
|
});
|
|
9311
9316
|
const derived = (0, import_react42.useMemo)(
|
|
9312
|
-
() => deriveUsage(activePurchase ?? null, { remaining: limitRemaining, unlimited, meterName }),
|
|
9313
|
-
[activePurchase, limitRemaining, unlimited,
|
|
9317
|
+
() => deriveUsage(activePurchase ?? null, { remaining: limitRemaining, unlimited, meterName: meterName2 }),
|
|
9318
|
+
[activePurchase, limitRemaining, unlimited, meterName2]
|
|
9314
9319
|
);
|
|
9315
9320
|
const activePurchaseRef = activePurchase?.reference ?? null;
|
|
9316
9321
|
(0, import_react42.useEffect)(() => {
|