@solvapay/react 2.1.1 → 2.2.0-preview-11dbbe603cd1b9a44cc41b5eee3686bc4000f97f
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 +23 -2
- package/dist/{chunk-HQH6KSXJ.js → chunk-EWB43JVC.js} +5 -2
- package/dist/{chunk-QXNNMNCV.js → chunk-M6O7ZWNP.js} +136 -51
- package/dist/{chunk-LL6AYSTC.js → chunk-WISTNSUH.js} +371 -317
- package/dist/{index-CBWGkBqF.d.ts → index-APG9WYgS.d.cts} +33 -5
- package/dist/{index-SylJb9Rh.d.cts → index-ofZwGvIZ.d.ts} +33 -5
- package/dist/index.cjs +1455 -1319
- package/dist/index.d.cts +82 -17
- package/dist/index.d.ts +82 -17
- package/dist/index.js +9 -3
- package/dist/mcp/index.cjs +1561 -1345
- package/dist/mcp/index.d.cts +176 -129
- package/dist/mcp/index.d.ts +176 -129
- package/dist/mcp/index.js +178 -92
- package/dist/mcp/styles.css +39 -14
- package/dist/primitives/index.cjs +822 -786
- package/dist/primitives/index.d.cts +4 -4
- package/dist/primitives/index.d.ts +4 -4
- package/dist/primitives/index.js +2 -2
- package/dist/{shared-D0hmT1qU.d.cts → shared-BQbMyX5V.d.cts} +14 -1
- package/dist/{shared-CUl6mTC1.d.ts → shared-DJdsOLag.d.ts} +14 -1
- package/dist/styles.css +20 -0
- package/package.json +5 -5
package/dist/mcp/index.js
CHANGED
|
@@ -3,11 +3,12 @@ import {
|
|
|
3
3
|
ExternalLinkGlyph,
|
|
4
4
|
LaunchCustomerPortalButton,
|
|
5
5
|
paymentMethodCache
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-M6O7ZWNP.js";
|
|
7
7
|
import {
|
|
8
8
|
AmountPicker,
|
|
9
9
|
BalanceBadge,
|
|
10
10
|
CancelledPlanNotice,
|
|
11
|
+
ExternalLinkProvider,
|
|
11
12
|
LegalFooter,
|
|
12
13
|
MandateText,
|
|
13
14
|
PaymentForm,
|
|
@@ -34,6 +35,7 @@ import {
|
|
|
34
35
|
useCheckoutFlow,
|
|
35
36
|
useCopy,
|
|
36
37
|
useCustomer,
|
|
38
|
+
useExternalLinkClick,
|
|
37
39
|
useMerchant,
|
|
38
40
|
usePlanSelection,
|
|
39
41
|
usePlanSelector,
|
|
@@ -41,7 +43,7 @@ import {
|
|
|
41
43
|
usePurchaseStatus,
|
|
42
44
|
useTopupAmountSelector,
|
|
43
45
|
useTransport
|
|
44
|
-
} from "../chunk-
|
|
46
|
+
} from "../chunk-WISTNSUH.js";
|
|
45
47
|
import "../chunk-UMXOAUW7.js";
|
|
46
48
|
import "../chunk-MLKGABMK.js";
|
|
47
49
|
|
|
@@ -76,15 +78,30 @@ function pickDefined(input) {
|
|
|
76
78
|
function createMcpAppAdapter(app) {
|
|
77
79
|
const callTool = async (name, args = {}) => unwrap(await app.callServerTool({ name, arguments: args }));
|
|
78
80
|
return {
|
|
79
|
-
createPayment: (params) => callTool(
|
|
81
|
+
createPayment: (params) => callTool(
|
|
82
|
+
MCP_TOOL_NAMES.createPayment,
|
|
83
|
+
pickDefined({ purpose: "plan", ...params })
|
|
84
|
+
),
|
|
80
85
|
processPayment: (params) => callTool(MCP_TOOL_NAMES.processPayment, pickDefined({ ...params })),
|
|
81
|
-
createTopupPayment: (params) => callTool(
|
|
86
|
+
createTopupPayment: (params) => callTool(
|
|
87
|
+
MCP_TOOL_NAMES.createPayment,
|
|
88
|
+
pickDefined({ purpose: "topup", ...params })
|
|
89
|
+
),
|
|
82
90
|
attachBusinessDetails: (params) => callTool(MCP_TOOL_NAMES.attachBusinessDetails, pickDefined({ ...params })),
|
|
83
|
-
cancelRenewal: (params) => callTool(
|
|
84
|
-
|
|
91
|
+
cancelRenewal: (params) => callTool(
|
|
92
|
+
MCP_TOOL_NAMES.setRenewal,
|
|
93
|
+
pickDefined({ enabled: false, ...params })
|
|
94
|
+
),
|
|
95
|
+
reactivateRenewal: (params) => callTool(
|
|
96
|
+
MCP_TOOL_NAMES.setRenewal,
|
|
97
|
+
pickDefined({ enabled: true, ...params })
|
|
98
|
+
),
|
|
85
99
|
activatePlan: (params) => callTool(MCP_TOOL_NAMES.activatePlan, pickDefined({ ...params })),
|
|
86
|
-
createCheckoutSession: (params) => callTool(
|
|
87
|
-
|
|
100
|
+
createCheckoutSession: (params) => callTool(
|
|
101
|
+
MCP_TOOL_NAMES.createHostedSession,
|
|
102
|
+
pickDefined({ kind: "checkout", ...params ?? {} })
|
|
103
|
+
),
|
|
104
|
+
createCustomerSession: () => callTool(MCP_TOOL_NAMES.createHostedSession, { kind: "portal" })
|
|
88
105
|
};
|
|
89
106
|
}
|
|
90
107
|
|
|
@@ -125,6 +142,7 @@ function useStripeProbe(publishableKey) {
|
|
|
125
142
|
}
|
|
126
143
|
};
|
|
127
144
|
const isStripeFrameViolation = (event) => {
|
|
145
|
+
if (event.disposition === "report") return false;
|
|
128
146
|
const directive = event.effectiveDirective || event.violatedDirective || "";
|
|
129
147
|
const blockedURI = event.blockedURI || "";
|
|
130
148
|
const isFrameSrc = directive === "frame-src" || directive.startsWith("frame-src ");
|
|
@@ -133,6 +151,16 @@ function useStripeProbe(publishableKey) {
|
|
|
133
151
|
const onCspViolation = (event) => {
|
|
134
152
|
if (!isStripeFrameViolation(event)) return;
|
|
135
153
|
cspBlockedStripeFrame = true;
|
|
154
|
+
const directive = event.effectiveDirective || event.violatedDirective || "";
|
|
155
|
+
console.warn(
|
|
156
|
+
"[solvapay-mcp] host CSP refused the Stripe iframe; falling back to hosted checkout.",
|
|
157
|
+
{
|
|
158
|
+
blockedURI: event.blockedURI,
|
|
159
|
+
effectiveDirective: directive,
|
|
160
|
+
originalPolicy: event.originalPolicy,
|
|
161
|
+
sourceFile: event.sourceFile
|
|
162
|
+
}
|
|
163
|
+
);
|
|
136
164
|
resolve("blocked");
|
|
137
165
|
};
|
|
138
166
|
document.addEventListener("securitypolicyviolation", onCspViolation);
|
|
@@ -339,7 +367,26 @@ function McpBridgeProvider({ app, messageOnSuccess, children }) {
|
|
|
339
367
|
}
|
|
340
368
|
};
|
|
341
369
|
}, [app, locale, messageOnSuccess]);
|
|
342
|
-
|
|
370
|
+
const opener = useMemo(
|
|
371
|
+
() => ({
|
|
372
|
+
// Capabilities are read at click time, not render time: the
|
|
373
|
+
// bridge can mount before `connect()` has populated them, and a
|
|
374
|
+
// render-time snapshot would go stale.
|
|
375
|
+
canOpen: () => typeof app.openLink === "function" && Boolean(app.getHostCapabilities?.()?.openLinks),
|
|
376
|
+
open: async (url) => {
|
|
377
|
+
if (typeof app.openLink !== "function") return false;
|
|
378
|
+
try {
|
|
379
|
+
const result = await app.openLink({ url });
|
|
380
|
+
return result?.isError !== true;
|
|
381
|
+
} catch (err) {
|
|
382
|
+
console.error("[solvapay] ui/open-link failed:", err);
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}),
|
|
387
|
+
[app]
|
|
388
|
+
);
|
|
389
|
+
return /* @__PURE__ */ jsx(McpBridgeContext.Provider, { value, children: /* @__PURE__ */ jsx(ExternalLinkProvider, { opener, children }) });
|
|
343
390
|
}
|
|
344
391
|
function useMcpBridge() {
|
|
345
392
|
return useContext(McpBridgeContext);
|
|
@@ -558,6 +605,82 @@ import { VIEW_FOR_TOOL as VIEW_FOR_TOOL2 } from "@solvapay/mcp-core";
|
|
|
558
605
|
// src/mcp/McpAppShell.tsx
|
|
559
606
|
import { useState as useState6 } from "react";
|
|
560
607
|
|
|
608
|
+
// src/mcp/plan-actions.ts
|
|
609
|
+
import {
|
|
610
|
+
billingCycle,
|
|
611
|
+
charges,
|
|
612
|
+
countsUsage,
|
|
613
|
+
trialDays
|
|
614
|
+
} from "@solvapay/core";
|
|
615
|
+
function isPaidPlan(plan) {
|
|
616
|
+
if (plan.requiresPayment === false) return false;
|
|
617
|
+
if (charges(plan).some((charge) => charge.amountMinor > 0)) return true;
|
|
618
|
+
return (plan.price ?? 0) > 0;
|
|
619
|
+
}
|
|
620
|
+
function isMeteredPlan(plan) {
|
|
621
|
+
return countsUsage(plan);
|
|
622
|
+
}
|
|
623
|
+
function resolvePlanShape(plan) {
|
|
624
|
+
if (!plan) return null;
|
|
625
|
+
if ((trialDays(plan) ?? 0) > 0) return "trial";
|
|
626
|
+
if (!isPaidPlan(plan)) return "free";
|
|
627
|
+
const metered = isMeteredPlan(plan);
|
|
628
|
+
if (billingCycle(plan)) return metered ? "recurring-metered" : "recurring-unlimited";
|
|
629
|
+
return metered ? "usage-based" : "recurring-unlimited";
|
|
630
|
+
}
|
|
631
|
+
function resolveActivationStrategy(plan) {
|
|
632
|
+
const shape = resolvePlanShape(plan);
|
|
633
|
+
if (shape === "usage-based") return "topup-first";
|
|
634
|
+
if (shape === "free" || shape === "trial") return "activate";
|
|
635
|
+
return "paid-checkout";
|
|
636
|
+
}
|
|
637
|
+
function mergePlanSnapshot(snapshot, catalog) {
|
|
638
|
+
if (!snapshot && !catalog) return null;
|
|
639
|
+
if (!catalog) return snapshot ?? null;
|
|
640
|
+
if (!snapshot) return catalog;
|
|
641
|
+
const snapshotHasOptions = Array.isArray(snapshot.options) && snapshot.options.length > 0;
|
|
642
|
+
return {
|
|
643
|
+
...catalog,
|
|
644
|
+
...snapshot,
|
|
645
|
+
options: snapshotHasOptions ? snapshot.options : catalog.options,
|
|
646
|
+
requiresPayment: snapshot.requiresPayment ?? catalog.requiresPayment,
|
|
647
|
+
isMetered: snapshot.isMetered ?? catalog.isMetered
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
function findCatalogPlan(plans, snapshot, planRef) {
|
|
651
|
+
const ref = snapshot?.reference ?? planRef;
|
|
652
|
+
if (!ref || !plans) return void 0;
|
|
653
|
+
return plans.find((p) => p.reference === ref);
|
|
654
|
+
}
|
|
655
|
+
function resolvePlanActions({
|
|
656
|
+
purchase,
|
|
657
|
+
planCount,
|
|
658
|
+
paidPlanCount
|
|
659
|
+
}) {
|
|
660
|
+
const shape = resolvePlanShape(purchase?.planSnapshot);
|
|
661
|
+
const hasPaymentMethod = Boolean(purchase?.hasPaymentMethod);
|
|
662
|
+
const canOfferChange = planCount > 1;
|
|
663
|
+
const isFree = shape === "free";
|
|
664
|
+
const canUpgrade = isFree && paidPlanCount > 0;
|
|
665
|
+
return {
|
|
666
|
+
topUp: shape === "usage-based",
|
|
667
|
+
cancel: shape === "recurring-unlimited" || shape === "recurring-metered" || shape === "free" || shape === "trial",
|
|
668
|
+
changePlan: canOfferChange && !canUpgrade,
|
|
669
|
+
managePortal: hasPaymentMethod,
|
|
670
|
+
upgrade: canUpgrade
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
function resolveActivityStrip(purchase) {
|
|
674
|
+
const shape = resolvePlanShape(purchase?.planSnapshot);
|
|
675
|
+
if (!shape) return "none";
|
|
676
|
+
if (shape === "usage-based") return "payg-balance";
|
|
677
|
+
if (shape === "recurring-unlimited") return "recurring-unlimited-renew";
|
|
678
|
+
if (shape === "recurring-metered") return "recurring-metered-usage";
|
|
679
|
+
if (shape === "free") return "free-usage";
|
|
680
|
+
if (shape === "trial") return "free-usage";
|
|
681
|
+
return "none";
|
|
682
|
+
}
|
|
683
|
+
|
|
561
684
|
// src/mcp/views/detail-cards.tsx
|
|
562
685
|
import { creditsToDisplayMinorUnits, resolveSellerIdentityDisplay } from "@solvapay/core";
|
|
563
686
|
|
|
@@ -721,17 +844,8 @@ function McpSellerDetailsCard({
|
|
|
721
844
|
/* @__PURE__ */ jsxs("dl", { className: "solvapay-mcp-detail-grid", children: [
|
|
722
845
|
/* @__PURE__ */ jsx2(DetailRow, { value: merchant.displayName, muted: cx.muted }),
|
|
723
846
|
merchant.legalName && merchant.legalName !== merchant.displayName ? /* @__PURE__ */ jsx2(DetailRow, { value: merchant.legalName, muted: cx.muted }) : null,
|
|
724
|
-
supportEmail ? /* @__PURE__ */ jsx2(
|
|
725
|
-
supportUrl ? /* @__PURE__ */ jsx2(
|
|
726
|
-
"a",
|
|
727
|
-
{
|
|
728
|
-
className: "solvapay-mcp-detail-link",
|
|
729
|
-
href: supportUrl,
|
|
730
|
-
target: "_blank",
|
|
731
|
-
rel: "noopener noreferrer",
|
|
732
|
-
children: "Support centre"
|
|
733
|
-
}
|
|
734
|
-
) }) : null,
|
|
847
|
+
supportEmail ? /* @__PURE__ */ jsx2(DetailRow, { value: supportEmail, muted: cx.muted }) : null,
|
|
848
|
+
supportUrl ? /* @__PURE__ */ jsx2(DetailRow, { value: supportUrl, muted: cx.muted }) : null,
|
|
735
849
|
sellerIdentity.companyNumber ? /* @__PURE__ */ jsx2(
|
|
736
850
|
DetailRow,
|
|
737
851
|
{
|
|
@@ -763,6 +877,7 @@ function McpAccountView({
|
|
|
763
877
|
classNames,
|
|
764
878
|
onTopup,
|
|
765
879
|
onChangePlan,
|
|
880
|
+
plans,
|
|
766
881
|
hideDetailCards
|
|
767
882
|
}) {
|
|
768
883
|
const cx = resolveMcpClassNames(classNames);
|
|
@@ -773,14 +888,27 @@ function McpAccountView({
|
|
|
773
888
|
if (loading) {
|
|
774
889
|
return /* @__PURE__ */ jsx3("div", { className: cx.card, children: /* @__PURE__ */ jsx3("p", { children: "Loading account\u2026" }) });
|
|
775
890
|
}
|
|
776
|
-
const hasAnyPlan =
|
|
891
|
+
const hasAnyPlan = Boolean(activePurchase) || shouldShowCancelledNotice;
|
|
777
892
|
const hasCredits = (credits ?? 0) > 0;
|
|
778
893
|
const showPortalCta = Boolean(
|
|
779
894
|
hasPaidPurchase && activePurchase && activePurchase.amount && activePurchase.amount > 0
|
|
780
895
|
);
|
|
896
|
+
const catalogPlan = findCatalogPlan(plans, activePurchase?.planSnapshot, activePurchase?.planRef);
|
|
897
|
+
const planForActions = mergePlanSnapshot(activePurchase?.planSnapshot, catalogPlan);
|
|
898
|
+
const paidPlanCount = (plans ?? []).filter((plan) => resolvePlanShape(plan) !== "free").length;
|
|
899
|
+
const actions = resolvePlanActions({
|
|
900
|
+
purchase: {
|
|
901
|
+
planSnapshot: planForActions,
|
|
902
|
+
hasPaymentMethod: false
|
|
903
|
+
},
|
|
904
|
+
planCount: plans?.length ?? 0,
|
|
905
|
+
paidPlanCount
|
|
906
|
+
});
|
|
907
|
+
const showChangePlanCta = Boolean(onChangePlan && (actions.upgrade || actions.changePlan));
|
|
781
908
|
return /* @__PURE__ */ jsxs2("div", { className: "solvapay-mcp-account", children: [
|
|
782
909
|
/* @__PURE__ */ jsxs2("div", { className: cx.card, children: [
|
|
783
|
-
|
|
910
|
+
activePurchase ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
911
|
+
/* @__PURE__ */ jsx3("h2", { className: cx.heading, children: copy.currentPlan.heading }),
|
|
784
912
|
/* @__PURE__ */ jsx3(
|
|
785
913
|
CurrentPlanCard,
|
|
786
914
|
{
|
|
@@ -789,11 +917,13 @@ function McpAccountView({
|
|
|
789
917
|
hideUpdatePaymentButton: true,
|
|
790
918
|
hideCancelButton: true,
|
|
791
919
|
hideCancelledNotice: true,
|
|
920
|
+
hidePaymentMethod: true,
|
|
792
921
|
showStartDate: true,
|
|
793
|
-
|
|
922
|
+
showFieldLabels: true,
|
|
923
|
+
plans
|
|
794
924
|
}
|
|
795
925
|
),
|
|
796
|
-
|
|
926
|
+
showChangePlanCta ? /* @__PURE__ */ jsx3("button", { type: "button", className: cx.button, onClick: onChangePlan, children: actions.upgrade ? copy.account.upgradeButton : copy.account.changePlanButton }) : null
|
|
797
927
|
] }) : null,
|
|
798
928
|
/* @__PURE__ */ jsxs2(CancelledPlanNotice.Root, { className: cx.notice, children: [
|
|
799
929
|
/* @__PURE__ */ jsx3(CancelledPlanNotice.Heading, {}),
|
|
@@ -814,14 +944,17 @@ function McpAccountView({
|
|
|
814
944
|
/* @__PURE__ */ jsx3("p", { className: cx.muted, children: copy.account.noPlanBody }),
|
|
815
945
|
onChangePlan ? /* @__PURE__ */ jsx3("button", { type: "button", className: cx.button, onClick: onChangePlan, children: copy.account.pickPlanButton }) : null
|
|
816
946
|
] }),
|
|
817
|
-
showPortalCta ? /* @__PURE__ */
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
947
|
+
showPortalCta ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
948
|
+
/* @__PURE__ */ jsx3("p", { className: cx.muted, "data-solvapay-mcp-portal-hint": "", children: copy.currentPlan.portalHint }),
|
|
949
|
+
/* @__PURE__ */ jsx3(
|
|
950
|
+
LaunchCustomerPortalButton,
|
|
951
|
+
{
|
|
952
|
+
className: cx.button,
|
|
953
|
+
loadingClassName: cx.button,
|
|
954
|
+
errorClassName: cx.button
|
|
955
|
+
}
|
|
956
|
+
)
|
|
957
|
+
] }) : null
|
|
825
958
|
] }),
|
|
826
959
|
!hideDetailCards ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
827
960
|
/* @__PURE__ */ jsx3(McpCustomerDetailsCard, { classNames, onTopup }),
|
|
@@ -1536,6 +1669,7 @@ var HostedLinkButton = React8.memo(function HostedLinkButton2({
|
|
|
1536
1669
|
onLaunch,
|
|
1537
1670
|
cx
|
|
1538
1671
|
}) {
|
|
1672
|
+
const handleExternalClick = useExternalLinkClick();
|
|
1539
1673
|
if (state.status === "ready") {
|
|
1540
1674
|
return /* @__PURE__ */ jsx11(
|
|
1541
1675
|
"a",
|
|
@@ -1545,7 +1679,10 @@ var HostedLinkButton = React8.memo(function HostedLinkButton2({
|
|
|
1545
1679
|
target: "_blank",
|
|
1546
1680
|
rel: "noopener noreferrer",
|
|
1547
1681
|
"aria-label": `${readyLabel} (opens in a new tab)`,
|
|
1548
|
-
onClick: () =>
|
|
1682
|
+
onClick: (event) => {
|
|
1683
|
+
onLaunch?.(state.href);
|
|
1684
|
+
handleExternalClick(event);
|
|
1685
|
+
},
|
|
1549
1686
|
children: /* @__PURE__ */ jsxs10("button", { type: "button", className: cx.button, children: [
|
|
1550
1687
|
readyLabel,
|
|
1551
1688
|
/* @__PURE__ */ jsx11(ExternalLinkGlyph, {})
|
|
@@ -1565,6 +1702,7 @@ var AwaitingBody = React8.memo(function AwaitingBody2({
|
|
|
1565
1702
|
onCancel,
|
|
1566
1703
|
cx
|
|
1567
1704
|
}) {
|
|
1705
|
+
const handleExternalClick = useExternalLinkClick();
|
|
1568
1706
|
return /* @__PURE__ */ jsxs10(Fragment8, { children: [
|
|
1569
1707
|
/* @__PURE__ */ jsxs10("div", { className: cx.awaitingHeader, children: [
|
|
1570
1708
|
/* @__PURE__ */ jsx11(Spinner, {}),
|
|
@@ -1579,7 +1717,10 @@ var AwaitingBody = React8.memo(function AwaitingBody2({
|
|
|
1579
1717
|
target: "_blank",
|
|
1580
1718
|
rel: "noopener noreferrer",
|
|
1581
1719
|
"aria-label": "Reopen checkout (opens in a new tab)",
|
|
1582
|
-
onClick: () =>
|
|
1720
|
+
onClick: (event) => {
|
|
1721
|
+
onReopen();
|
|
1722
|
+
handleExternalClick(event);
|
|
1723
|
+
},
|
|
1583
1724
|
children: /* @__PURE__ */ jsxs10("button", { type: "button", className: cx.button, children: [
|
|
1584
1725
|
"Reopen checkout",
|
|
1585
1726
|
/* @__PURE__ */ jsx11(ExternalLinkGlyph, {})
|
|
@@ -2182,6 +2323,7 @@ function McpViewRouter({
|
|
|
2182
2323
|
classNames,
|
|
2183
2324
|
onTopup: goTopup,
|
|
2184
2325
|
onChangePlan: goCheckout,
|
|
2326
|
+
plans: bootstrap.plans,
|
|
2185
2327
|
hideDetailCards: suppressDetailCards
|
|
2186
2328
|
}
|
|
2187
2329
|
);
|
|
@@ -2555,64 +2697,6 @@ function McpApp({
|
|
|
2555
2697
|
) }) })
|
|
2556
2698
|
] }) });
|
|
2557
2699
|
}
|
|
2558
|
-
|
|
2559
|
-
// src/mcp/plan-actions.ts
|
|
2560
|
-
import {
|
|
2561
|
-
billingCycle,
|
|
2562
|
-
charges,
|
|
2563
|
-
countsUsage,
|
|
2564
|
-
trialDays
|
|
2565
|
-
} from "@solvapay/core";
|
|
2566
|
-
function isPaidPlan(plan) {
|
|
2567
|
-
if (plan.requiresPayment === false) return false;
|
|
2568
|
-
if (charges(plan).some((charge) => charge.amountMinor > 0)) return true;
|
|
2569
|
-
return (plan.price ?? 0) > 0;
|
|
2570
|
-
}
|
|
2571
|
-
function isMeteredPlan(plan) {
|
|
2572
|
-
return countsUsage(plan);
|
|
2573
|
-
}
|
|
2574
|
-
function resolvePlanShape(plan) {
|
|
2575
|
-
if (!plan) return null;
|
|
2576
|
-
if ((trialDays(plan) ?? 0) > 0) return "trial";
|
|
2577
|
-
if (!isPaidPlan(plan)) return "free";
|
|
2578
|
-
const metered = isMeteredPlan(plan);
|
|
2579
|
-
if (billingCycle(plan)) return metered ? "recurring-metered" : "recurring-unlimited";
|
|
2580
|
-
return metered ? "usage-based" : "recurring-unlimited";
|
|
2581
|
-
}
|
|
2582
|
-
function resolveActivationStrategy(plan) {
|
|
2583
|
-
const shape = resolvePlanShape(plan);
|
|
2584
|
-
if (shape === "usage-based") return "topup-first";
|
|
2585
|
-
if (shape === "free" || shape === "trial") return "activate";
|
|
2586
|
-
return "paid-checkout";
|
|
2587
|
-
}
|
|
2588
|
-
function resolvePlanActions({
|
|
2589
|
-
purchase,
|
|
2590
|
-
planCount,
|
|
2591
|
-
paidPlanCount
|
|
2592
|
-
}) {
|
|
2593
|
-
const shape = resolvePlanShape(purchase?.planSnapshot);
|
|
2594
|
-
const hasPaymentMethod = Boolean(purchase?.hasPaymentMethod);
|
|
2595
|
-
const canOfferChange = planCount > 1;
|
|
2596
|
-
const isFree = shape === "free";
|
|
2597
|
-
const canUpgrade = isFree && paidPlanCount > 0;
|
|
2598
|
-
return {
|
|
2599
|
-
topUp: shape === "usage-based",
|
|
2600
|
-
cancel: shape === "recurring-unlimited" || shape === "recurring-metered" || shape === "free" || shape === "trial",
|
|
2601
|
-
changePlan: canOfferChange && !canUpgrade,
|
|
2602
|
-
managePortal: hasPaymentMethod,
|
|
2603
|
-
upgrade: canUpgrade
|
|
2604
|
-
};
|
|
2605
|
-
}
|
|
2606
|
-
function resolveActivityStrip(purchase) {
|
|
2607
|
-
const shape = resolvePlanShape(purchase?.planSnapshot);
|
|
2608
|
-
if (!shape) return "none";
|
|
2609
|
-
if (shape === "usage-based") return "payg-balance";
|
|
2610
|
-
if (shape === "recurring-unlimited") return "recurring-unlimited-renew";
|
|
2611
|
-
if (shape === "recurring-metered") return "recurring-metered-usage";
|
|
2612
|
-
if (shape === "free") return "free-usage";
|
|
2613
|
-
if (shape === "trial") return "free-usage";
|
|
2614
|
-
return "none";
|
|
2615
|
-
}
|
|
2616
2700
|
export {
|
|
2617
2701
|
AppHeader,
|
|
2618
2702
|
BackLink,
|
|
@@ -2633,7 +2717,9 @@ export {
|
|
|
2633
2717
|
createMcpAppAdapter,
|
|
2634
2718
|
fetchMcpBootstrap,
|
|
2635
2719
|
fetchMcpBootstrapViaResource,
|
|
2720
|
+
findCatalogPlan,
|
|
2636
2721
|
isTransportToolName,
|
|
2722
|
+
mergePlanSnapshot,
|
|
2637
2723
|
parseBootstrapFromToolResult,
|
|
2638
2724
|
resolveActivationStrategy,
|
|
2639
2725
|
resolveActivityStrip,
|
package/dist/mcp/styles.css
CHANGED
|
@@ -355,6 +355,41 @@ body {
|
|
|
355
355
|
|
|
356
356
|
/* Account view */
|
|
357
357
|
|
|
358
|
+
/* `<CurrentPlanCard>` ships its own card frame for standalone web
|
|
359
|
+
* surfaces. Inside the MCP account view the surrounding
|
|
360
|
+
* `.solvapay-mcp-card` already IS the frame, so the default chrome
|
|
361
|
+
* nested a second bordered box and doubled the inset (16px card
|
|
362
|
+
* padding + 16px card padding). Flatten it: the plan facts then align
|
|
363
|
+
* to the same left edge and 16px gutter as the heading, the CTA, and
|
|
364
|
+
* every other MCP surface (checkout, topup, success). */
|
|
365
|
+
.solvapay-mcp-account [data-solvapay-current-plan-card] {
|
|
366
|
+
padding: 0;
|
|
367
|
+
border: 0;
|
|
368
|
+
background: none;
|
|
369
|
+
border-radius: 0;
|
|
370
|
+
gap: 10px;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/* Type scale inside the flattened plan card, descending from the
|
|
374
|
+
* surface title so each rank is legible at a glance:
|
|
375
|
+
* 18 title → 16 plan name → 14 captioned value → 13 muted date
|
|
376
|
+
* → 11 field label. Left at the sheet defaults the plan name and the
|
|
377
|
+
* price both land near 18px and compete with the title. */
|
|
378
|
+
.solvapay-mcp-account [data-solvapay-current-plan-name] {
|
|
379
|
+
font-size: 16px;
|
|
380
|
+
line-height: 1.3;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.solvapay-mcp-account [data-solvapay-current-plan-price],
|
|
384
|
+
.solvapay-mcp-account [data-solvapay-current-plan-balance-line] {
|
|
385
|
+
font-size: 14px;
|
|
386
|
+
font-weight: 600;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
.solvapay-mcp-account [data-solvapay-current-plan-field-label] {
|
|
390
|
+
color: var(--color-text-secondary, #475569);
|
|
391
|
+
}
|
|
392
|
+
|
|
358
393
|
.solvapay-mcp-account-credit-stack {
|
|
359
394
|
flex: 1;
|
|
360
395
|
}
|
|
@@ -498,9 +533,9 @@ body {
|
|
|
498
533
|
cursor: pointer;
|
|
499
534
|
}
|
|
500
535
|
|
|
501
|
-
.solvapay-mcp-business-details:not(
|
|
502
|
-
:has([data-solvapay-
|
|
503
|
-
)
|
|
536
|
+
.solvapay-mcp-business-details:not(
|
|
537
|
+
:has([data-solvapay-topup-form-business-details-toggle]:checked)
|
|
538
|
+
):not(:has([data-solvapay-payment-form-business-details-toggle]:checked))
|
|
504
539
|
.solvapay-mcp-business-field {
|
|
505
540
|
display: none;
|
|
506
541
|
}
|
|
@@ -829,6 +864,7 @@ body {
|
|
|
829
864
|
.solvapay-mcp-detail-value {
|
|
830
865
|
font-size: 14px;
|
|
831
866
|
color: var(--color-text-primary, #0f172a);
|
|
867
|
+
word-break: break-word;
|
|
832
868
|
}
|
|
833
869
|
|
|
834
870
|
.solvapay-mcp-detail-value-mono {
|
|
@@ -838,17 +874,6 @@ body {
|
|
|
838
874
|
font-size: 12px;
|
|
839
875
|
}
|
|
840
876
|
|
|
841
|
-
.solvapay-mcp-detail-link {
|
|
842
|
-
color: var(--color-text-primary, #0f172a);
|
|
843
|
-
font-size: 14px;
|
|
844
|
-
text-decoration: none;
|
|
845
|
-
word-break: break-word;
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
.solvapay-mcp-detail-link:hover {
|
|
849
|
-
text-decoration: underline;
|
|
850
|
-
}
|
|
851
|
-
|
|
852
877
|
.solvapay-mcp-detail-heading-row {
|
|
853
878
|
display: flex;
|
|
854
879
|
align-items: center;
|