@lukoweb/apitogo-plugin-dev-portal-billing 0.2.54 → 0.2.56
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/{AccountPlansPage-0PYGy1aV.mjs → AccountPlansPage-BuM7fe82.mjs} +12 -6
- package/dist/{CheckoutPage-Bpa128i2.mjs → CheckoutPage-BSiADcI6.mjs} +7 -2
- package/dist/{ContactSalesPage-BslD3Yk4.mjs → ContactSalesPage-BqqDmorF.mjs} +2 -2
- package/dist/{CredentialsPage-C4qpBVrh.mjs → CredentialsPage-DjNvBBLb.mjs} +4 -4
- package/dist/{PricingCard-YJIEwydG.mjs → PricingCard-DFuQEw7Y.mjs} +9 -3
- package/dist/{PricingPage-DIhoFOd9.mjs → PricingPage-SpL81vpd.mjs} +14 -13
- package/dist/{SubscriptionsPage-D7hsYtTB.mjs → SubscriptionsPage-CwsBtNld.mjs} +16 -10
- package/dist/{UsagePage-Di9kQ_3Z.mjs → UsagePage-Dw5Uepg3.mjs} +4 -4
- package/dist/{account-links-9h91uCGj.mjs → account-links-Drofs-f-.mjs} +1 -1
- package/dist/{billing-state-Dgcc3_pT.mjs → billing-state-DBQR2tad.mjs} +1 -1
- package/dist/index.d.mts +3 -2
- package/dist/index.mjs +21 -19
- package/dist/pending-checkout-DpVaNnTu.mjs +45 -0
- package/dist/{useApiKeys-CEwMzqju.mjs → useApiKeys-BOY3vIOr.mjs} +1 -1
- package/dist/{useDevPortalApiBaseUrl-BstWzITX.mjs → useDevPortalApiBaseUrl-BiI2jFjU.mjs} +14 -14
- package/dist/{useMySubscriptions-DuVq2tXL.mjs → useMySubscriptions-BYVIIWbe.mjs} +1 -1
- package/dist/{usePlans-BF7Hy2qJ.mjs → usePlans-HyhIIuJZ.mjs} +1 -1
- package/dist/{useUsage-CJ9VIBc7.mjs → useUsage-B5x9YuKa.mjs} +1 -1
- package/package.json +3 -3
- /package/dist/{page-state-BB-72pbw.mjs → page-state-BLL2JJBc.mjs} +0 -0
- /package/dist/{pricing-config-C44AIqql.mjs → pricing-config-Bc6eWFUO.mjs} +0 -0
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { f as parseManifestPlans, n as useDevPortalPreviewMode, r as useIsDemoSession, s as isActiveSubscription, t as useDevPortalApiBaseUrl } from "./useDevPortalApiBaseUrl-
|
|
2
|
-
import { t as PricingCard } from "./PricingCard-
|
|
1
|
+
import { f as parseManifestPlans, n as useDevPortalPreviewMode, r as useIsDemoSession, s as isActiveSubscription, t as useDevPortalApiBaseUrl } from "./useDevPortalApiBaseUrl-BiI2jFjU.mjs";
|
|
2
|
+
import { t as PricingCard } from "./PricingCard-DFuQEw7Y.mjs";
|
|
3
3
|
import { n as useDevPortalBillingConfig } from "./DevPortalBillingContext-CR83s4LO.mjs";
|
|
4
4
|
import { n as readProblemDetail } from "./problem-details-n20-dy3w.mjs";
|
|
5
|
-
import { t as useMySubscriptions } from "./useMySubscriptions-
|
|
6
|
-
import { t as usePlans } from "./usePlans-
|
|
5
|
+
import { t as useMySubscriptions } from "./useMySubscriptions-BYVIIWbe.mjs";
|
|
6
|
+
import { t as usePlans } from "./usePlans-HyhIIuJZ.mjs";
|
|
7
|
+
import { n as readPendingCheckout, t as clearPendingCheckout } from "./pending-checkout-DpVaNnTu.mjs";
|
|
7
8
|
import { Head } from "@lukoweb/apitogo/components";
|
|
8
9
|
import { CreditCardIcon } from "@lukoweb/apitogo/icons";
|
|
9
10
|
import { useSearchParams } from "@lukoweb/apitogo/router";
|
|
10
|
-
import { useState } from "react";
|
|
11
|
+
import { useEffect, useState } from "react";
|
|
11
12
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
13
|
import { useMutation, useQueryClient } from "@lukoweb/apitogo/react-query";
|
|
13
14
|
|
|
@@ -70,6 +71,10 @@ const AccountPlansPage = () => {
|
|
|
70
71
|
const cancelMutation = useCancelSubscription();
|
|
71
72
|
const [cancelingSku, setCancelingSku] = useState(null);
|
|
72
73
|
const subscriptionBySku = new Map((me?.subscriptions ?? []).map((sub) => [sub.planSku, sub]));
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
if (checkoutCancelled) clearPendingCheckout();
|
|
76
|
+
}, [checkoutCancelled]);
|
|
77
|
+
const pendingSku = checkoutCancelled ? void 0 : readPendingCheckout();
|
|
73
78
|
const handleUnsubscribe = async (planSku) => {
|
|
74
79
|
setCancelingSku(planSku);
|
|
75
80
|
try {
|
|
@@ -133,7 +138,8 @@ const AccountPlansPage = () => {
|
|
|
133
138
|
isSubscribed,
|
|
134
139
|
onUnsubscribe: isPreview || isDemoSession ? void 0 : handleUnsubscribe,
|
|
135
140
|
isCanceling: cancelingSku === plan.sku,
|
|
136
|
-
cancelDisabled: isPreview || isDemoSession
|
|
141
|
+
cancelDisabled: isPreview || isDemoSession,
|
|
142
|
+
isConfirming: !isSubscribed && pendingSku === plan.sku
|
|
137
143
|
}, plan.sku);
|
|
138
144
|
})
|
|
139
145
|
}) : !isLoading && !isError ? /* @__PURE__ */ jsx("div", {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { n as ALREADY_SUBSCRIBED_PARAM, s as PRICING_PATH, t as ACCOUNT_PLANS_PATH } from "./paths-DaVyTIDJ.mjs";
|
|
2
|
-
import { n as useDevPortalPreviewMode, r as useIsDemoSession, t as useDevPortalApiBaseUrl } from "./useDevPortalApiBaseUrl-
|
|
2
|
+
import { n as useDevPortalPreviewMode, r as useIsDemoSession, t as useDevPortalApiBaseUrl } from "./useDevPortalApiBaseUrl-BiI2jFjU.mjs";
|
|
3
3
|
import { n as readProblemDetail, t as isAlreadySubscribedMessage } from "./problem-details-n20-dy3w.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { r as rememberPendingCheckout } from "./pending-checkout-DpVaNnTu.mjs";
|
|
5
|
+
import { t as FREE_CHECKOUT_MARKER } from "./billing-state-DBQR2tad.mjs";
|
|
5
6
|
import { ShieldIcon } from "@lukoweb/apitogo/icons";
|
|
6
7
|
import { Link, useNavigate, useSearchParams } from "@lukoweb/apitogo/router";
|
|
7
8
|
import { useEffect } from "react";
|
|
@@ -87,6 +88,10 @@ const CheckoutPage = () => {
|
|
|
87
88
|
}
|
|
88
89
|
});
|
|
89
90
|
const freeProvisioned = checkoutQuery.data?.checkoutUrl == null && checkoutQuery.data?.entitlementProvisioned === true;
|
|
91
|
+
const checkoutUrl = checkoutQuery.data?.checkoutUrl;
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
if (checkoutUrl) rememberPendingCheckout(planSku);
|
|
94
|
+
}, [checkoutUrl, planSku]);
|
|
90
95
|
const alreadySubscribed = checkoutQuery.isError && isAlreadySubscribedMessage(checkoutQuery.error.message);
|
|
91
96
|
useEffect(() => {
|
|
92
97
|
if (alreadySubscribed) navigate(`/account/subscriptions?${ALREADY_SUBSCRIBED_PARAM}=${encodeURIComponent(planSku)}`, { replace: true });
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { s as PRICING_PATH } from "./paths-DaVyTIDJ.mjs";
|
|
2
|
-
import { l as isPlanCustomPriced, n as useDevPortalPreviewMode, r as useIsDemoSession, t as useDevPortalApiBaseUrl } from "./useDevPortalApiBaseUrl-
|
|
2
|
+
import { l as isPlanCustomPriced, n as useDevPortalPreviewMode, r as useIsDemoSession, t as useDevPortalApiBaseUrl } from "./useDevPortalApiBaseUrl-BiI2jFjU.mjs";
|
|
3
3
|
import "./DevPortalBillingContext-CR83s4LO.mjs";
|
|
4
4
|
import { n as readProblemDetail } from "./problem-details-n20-dy3w.mjs";
|
|
5
|
-
import { t as usePlans } from "./usePlans-
|
|
5
|
+
import { t as usePlans } from "./usePlans-HyhIIuJZ.mjs";
|
|
6
6
|
import { Link, useSearchParams } from "@lukoweb/apitogo/router";
|
|
7
7
|
import { useState } from "react";
|
|
8
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { t as ACCOUNT_PLANS_PATH } from "./paths-DaVyTIDJ.mjs";
|
|
2
|
-
import { n as useDevPortalPreviewMode, r as useIsDemoSession, t as useDevPortalApiBaseUrl } from "./useDevPortalApiBaseUrl-
|
|
2
|
+
import { n as useDevPortalPreviewMode, r as useIsDemoSession, t as useDevPortalApiBaseUrl } from "./useDevPortalApiBaseUrl-BiI2jFjU.mjs";
|
|
3
3
|
import { n as useDevPortalBillingConfig } from "./DevPortalBillingContext-CR83s4LO.mjs";
|
|
4
4
|
import { r as createDemoCredentials, t as DEMO_GATEWAY_KEY_HEADER } from "./demo-session-yK9qEqV-.mjs";
|
|
5
|
-
import { n as useApiKeys } from "./useApiKeys-
|
|
6
|
-
import { n as apiReferencePath, r as ApiKeysPanel } from "./account-links-
|
|
7
|
-
import { i as ChoosePlanNotice, r as keyPlanNote, t as apiKeysPageState } from "./page-state-
|
|
5
|
+
import { n as useApiKeys } from "./useApiKeys-BOY3vIOr.mjs";
|
|
6
|
+
import { n as apiReferencePath, r as ApiKeysPanel } from "./account-links-Drofs-f-.mjs";
|
|
7
|
+
import { i as ChoosePlanNotice, r as keyPlanNote, t as apiKeysPageState } from "./page-state-BLL2JJBc.mjs";
|
|
8
8
|
import { Head } from "@lukoweb/apitogo/components";
|
|
9
9
|
import { KeyRoundIcon } from "@lukoweb/apitogo/icons";
|
|
10
10
|
import { Link as Link$1 } from "@lukoweb/apitogo/router";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { i as CONTACT_SALES_PATH, r as CHECKOUT_PATH } from "./paths-DaVyTIDJ.mjs";
|
|
2
|
-
import { d as listPlanFeatureLines, i as formatPlanDisplayPrice, l as isPlanCustomPriced, o as formatPlanPriceUnit, s as isActiveSubscription, u as isPlanFree } from "./useDevPortalApiBaseUrl-
|
|
2
|
+
import { d as listPlanFeatureLines, i as formatPlanDisplayPrice, l as isPlanCustomPriced, o as formatPlanPriceUnit, s as isActiveSubscription, u as isPlanFree } from "./useDevPortalApiBaseUrl-BiI2jFjU.mjs";
|
|
3
3
|
import { Button } from "@lukoweb/apitogo/components";
|
|
4
4
|
import { Link as Link$1 } from "@lukoweb/apitogo/router";
|
|
5
5
|
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@lukoweb/apitogo/ui/AlertDialog.js";
|
|
@@ -18,7 +18,7 @@ const accountCtaLabel = (plan) => {
|
|
|
18
18
|
};
|
|
19
19
|
/** Custom-priced plans skip checkout and open the contact-sales form. */
|
|
20
20
|
const planCtaPath = (plan) => `${isPlanCustomPriced(plan) ? CONTACT_SALES_PATH : CHECKOUT_PATH}?planSku=${encodeURIComponent(plan.sku)}`;
|
|
21
|
-
const PricingCard = ({ plan, mode = "public", subscriptionStatus, isSubscribed = false, onUnsubscribe, onSwitch, isSwitching = false, isCanceling = false, cancelDisabled = false, featured = false }) => {
|
|
21
|
+
const PricingCard = ({ plan, mode = "public", subscriptionStatus, isSubscribed = false, onUnsubscribe, onSwitch, isSwitching = false, isCanceling = false, cancelDisabled = false, featured = false, isConfirming = false }) => {
|
|
22
22
|
const isActive = isSubscribed || isActiveSubscription(subscriptionStatus ?? "");
|
|
23
23
|
const features = listPlanFeatureLines(plan);
|
|
24
24
|
const displayPrice = formatPlanDisplayPrice(plan);
|
|
@@ -83,7 +83,13 @@ const PricingCard = ({ plan, mode = "public", subscriptionStatus, isSubscribed =
|
|
|
83
83
|
className: "text-center text-xs text-muted-foreground",
|
|
84
84
|
children: "Unsubscribe is available after the portal is published."
|
|
85
85
|
}) : null
|
|
86
|
-
] }) :
|
|
86
|
+
] }) : isConfirming ? /* @__PURE__ */ jsx(Button, {
|
|
87
|
+
variant: "secondary",
|
|
88
|
+
className: "w-full",
|
|
89
|
+
disabled: true,
|
|
90
|
+
"data-testid": `confirming-${plan.sku}`,
|
|
91
|
+
children: "Confirming payment…"
|
|
92
|
+
}) : onSwitch && !isPlanCustomPriced(plan) ? /* @__PURE__ */ jsxs(AlertDialog, { children: [/* @__PURE__ */ jsx(AlertDialogTrigger, {
|
|
87
93
|
asChild: true,
|
|
88
94
|
children: /* @__PURE__ */ jsx(Button, {
|
|
89
95
|
variant: featured ? "default" : "outline",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { f as parseManifestPlans, h as pickFeaturedPlanSku, n as useDevPortalPreviewMode } from "./useDevPortalApiBaseUrl-
|
|
2
|
-
import { t as PricingCard } from "./PricingCard-
|
|
1
|
+
import { f as parseManifestPlans, h as pickFeaturedPlanSku, n as useDevPortalPreviewMode } from "./useDevPortalApiBaseUrl-BiI2jFjU.mjs";
|
|
2
|
+
import { t as PricingCard } from "./PricingCard-DFuQEw7Y.mjs";
|
|
3
3
|
import { n as useDevPortalBillingConfig } from "./DevPortalBillingContext-CR83s4LO.mjs";
|
|
4
|
-
import { t as usePlans } from "./usePlans-
|
|
5
|
-
import { t as isPreviewPricingEnabled } from "./pricing-config-
|
|
6
|
-
import { a as isPricingLoading, n as buildCompareRows } from "./billing-state-
|
|
4
|
+
import { t as usePlans } from "./usePlans-HyhIIuJZ.mjs";
|
|
5
|
+
import { t as isPreviewPricingEnabled } from "./pricing-config-Bc6eWFUO.mjs";
|
|
6
|
+
import { a as isPricingLoading, n as buildCompareRows } from "./billing-state-DBQR2tad.mjs";
|
|
7
7
|
import { Head, Heading } from "@lukoweb/apitogo/components";
|
|
8
8
|
import { Navigate } from "@lukoweb/apitogo/router";
|
|
9
9
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -66,15 +66,16 @@ const DEFAULT_COMPARE_ROWS = [
|
|
|
66
66
|
]
|
|
67
67
|
}
|
|
68
68
|
];
|
|
69
|
+
/** Only what the platform itself does, so the defaults never promise anything for the tenant (API-124). */
|
|
69
70
|
const DEFAULT_FAQS = [{
|
|
70
|
-
question: "What happens if I
|
|
71
|
-
answer: "
|
|
71
|
+
question: "What happens if I go over my plan's limits?",
|
|
72
|
+
answer: "Calls over the rate limit or the quota are refused with a 429 response, and its Retry-After header says when to try again."
|
|
72
73
|
}, {
|
|
73
|
-
question: "Can I
|
|
74
|
-
answer: "Yes
|
|
74
|
+
question: "Can I have more than one plan?",
|
|
75
|
+
answer: "Yes. Each plan has its own API keys and limits: create a key for a plan on the API keys page and use it in your app."
|
|
75
76
|
}];
|
|
76
77
|
const PricingPage = () => {
|
|
77
|
-
const { pricing, previewPlans } = useDevPortalBillingConfig();
|
|
78
|
+
const { pricing, previewPlans, featuredPlanSku } = useDevPortalBillingConfig();
|
|
78
79
|
const isPreview = useDevPortalPreviewMode();
|
|
79
80
|
const pricingEnabled = isPreviewPricingEnabled() || isPreview;
|
|
80
81
|
const livePlans = usePlans();
|
|
@@ -92,10 +93,10 @@ const PricingPage = () => {
|
|
|
92
93
|
to: "/",
|
|
93
94
|
replace: true
|
|
94
95
|
});
|
|
95
|
-
const title = pricing?.title ?? "
|
|
96
|
-
const subtitle = pricing?.subtitle ?? "
|
|
96
|
+
const title = pricing?.title ?? "Plans and pricing";
|
|
97
|
+
const subtitle = pricing?.subtitle ?? "Choose the plan that fits how you use the API. Each plan lists its limits and what it includes.";
|
|
97
98
|
const plans = catalog?.plans ?? [];
|
|
98
|
-
const featuredSku = pickFeaturedPlanSku(plans);
|
|
99
|
+
const featuredSku = pickFeaturedPlanSku(plans, featuredPlanSku);
|
|
99
100
|
const compareRows = buildCompareRows({
|
|
100
101
|
plans,
|
|
101
102
|
configuredRows: pricing?.compareRows,
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { a as CREDENTIALS_PATH, n as ALREADY_SUBSCRIBED_PARAM, t as ACCOUNT_PLANS_PATH } from "./paths-DaVyTIDJ.mjs";
|
|
2
|
-
import { a as formatPlanPrice, p as parseMonthlyQuotaCalls, s as isActiveSubscription, t as useDevPortalApiBaseUrl } from "./useDevPortalApiBaseUrl-
|
|
2
|
+
import { a as formatPlanPrice, p as parseMonthlyQuotaCalls, s as isActiveSubscription, t as useDevPortalApiBaseUrl } from "./useDevPortalApiBaseUrl-BiI2jFjU.mjs";
|
|
3
3
|
import { n as useDevPortalBillingConfig } from "./DevPortalBillingContext-CR83s4LO.mjs";
|
|
4
|
-
import { t as useMySubscriptions } from "./useMySubscriptions-
|
|
5
|
-
import { t as usePlans } from "./usePlans-
|
|
6
|
-
import { n as
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { i as
|
|
4
|
+
import { t as useMySubscriptions } from "./useMySubscriptions-BYVIIWbe.mjs";
|
|
5
|
+
import { t as usePlans } from "./usePlans-HyhIIuJZ.mjs";
|
|
6
|
+
import { n as readPendingCheckout, t as clearPendingCheckout } from "./pending-checkout-DpVaNnTu.mjs";
|
|
7
|
+
import { n as useApiKeys } from "./useApiKeys-BOY3vIOr.mjs";
|
|
8
|
+
import { t as useUsage } from "./useUsage-B5x9YuKa.mjs";
|
|
9
|
+
import { i as hasPaymentProvider, r as checkoutConfirmingText } from "./billing-state-DBQR2tad.mjs";
|
|
10
|
+
import { i as ChoosePlanNotice, n as billingPageState, r as keyPlanNote } from "./page-state-BLL2JJBc.mjs";
|
|
10
11
|
import { Head, Spinner } from "@lukoweb/apitogo/components";
|
|
11
12
|
import { Link as Link$1, useSearchParams } from "@lukoweb/apitogo/router";
|
|
12
13
|
import { useEffect } from "react";
|
|
@@ -71,7 +72,12 @@ const SubscriptionsPage = () => {
|
|
|
71
72
|
const earlierSubscriptions = subscriptions.filter((sub) => !isActiveSubscription(sub.status));
|
|
72
73
|
const hasActivePlan = activeSubscriptions.length > 0;
|
|
73
74
|
const singlePlan = activeSubscriptions.length === 1 ? planBySku.get(activeSubscriptions[0].planSku) : void 0;
|
|
74
|
-
const
|
|
75
|
+
const pendingSku = checkoutSuccess ? readPendingCheckout() : void 0;
|
|
76
|
+
const pendingActive = pendingSku !== void 0 && activeSubscriptions.some((sub) => sub.planSku === pendingSku);
|
|
77
|
+
const confirmingPayment = checkoutSuccess && !isLoading && (pendingSku !== void 0 ? !pendingActive : !hasActivePlan);
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
if (pendingActive) clearPendingCheckout();
|
|
80
|
+
}, [pendingActive]);
|
|
75
81
|
useEffect(() => {
|
|
76
82
|
if (!confirmingPayment) return;
|
|
77
83
|
let attempts = 0;
|
|
@@ -120,7 +126,7 @@ const SubscriptionsPage = () => {
|
|
|
120
126
|
className: "mb-6 rounded-xl border border-border bg-card p-4 text-sm",
|
|
121
127
|
children: checkoutConfirmingText(checkoutPaid)
|
|
122
128
|
}) : null,
|
|
123
|
-
checkoutSuccess && hasActivePlan ? /* @__PURE__ */ jsx("div", {
|
|
129
|
+
checkoutSuccess && hasActivePlan && !confirmingPayment ? /* @__PURE__ */ jsx("div", {
|
|
124
130
|
className: "mb-6 rounded-xl border border-green-500/30 bg-green-500/10 p-4 text-sm",
|
|
125
131
|
children: planNote ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
126
132
|
planNote.text,
|
|
@@ -207,7 +213,7 @@ const SubscriptionsPage = () => {
|
|
|
207
213
|
})
|
|
208
214
|
})]
|
|
209
215
|
}) : null,
|
|
210
|
-
billingState === "empty" ? /* @__PURE__ */ jsx(ChoosePlanNotice, {
|
|
216
|
+
billingState === "empty" && !confirmingPayment ? /* @__PURE__ */ jsx(ChoosePlanNotice, {
|
|
211
217
|
className: "mb-8 rounded-xl border border-dashed p-8 text-center",
|
|
212
218
|
body: "You do not have a plan yet. Choose one to start using the API; your billing details appear here afterwards."
|
|
213
219
|
}) : null,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { m as parseQuotaPeriodDays, p as parseMonthlyQuotaCalls, s as isActiveSubscription } from "./useDevPortalApiBaseUrl-
|
|
1
|
+
import { m as parseQuotaPeriodDays, p as parseMonthlyQuotaCalls, s as isActiveSubscription } from "./useDevPortalApiBaseUrl-BiI2jFjU.mjs";
|
|
2
2
|
import "./DevPortalBillingContext-CR83s4LO.mjs";
|
|
3
|
-
import { t as useMySubscriptions } from "./useMySubscriptions-
|
|
4
|
-
import { t as usePlans } from "./usePlans-
|
|
5
|
-
import { n as useUsageRecent, t as useUsage } from "./useUsage-
|
|
3
|
+
import { t as useMySubscriptions } from "./useMySubscriptions-BYVIIWbe.mjs";
|
|
4
|
+
import { t as usePlans } from "./usePlans-HyhIIuJZ.mjs";
|
|
5
|
+
import { n as useUsageRecent, t as useUsage } from "./useUsage-B5x9YuKa.mjs";
|
|
6
6
|
import { Head } from "@lukoweb/apitogo/components";
|
|
7
7
|
import { Link as Link$1 } from "@lukoweb/apitogo/router";
|
|
8
8
|
import { useState } from "react";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as useRevokeApiKey, r as useCreateApiKey, t as API_KEY_CAP_REACHED } from "./useApiKeys-
|
|
1
|
+
import { i as useRevokeApiKey, r as useCreateApiKey, t as API_KEY_CAP_REACHED } from "./useApiKeys-BOY3vIOr.mjs";
|
|
2
2
|
import { Spinner } from "@lukoweb/apitogo/components";
|
|
3
3
|
import { KeyRoundIcon, TrashIcon } from "@lukoweb/apitogo/icons";
|
|
4
4
|
import { useState } from "react";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as rateLimitCell, g as quotaCell } from "./useDevPortalApiBaseUrl-
|
|
1
|
+
import { _ as rateLimitCell, g as quotaCell } from "./useDevPortalApiBaseUrl-BiI2jFjU.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/utils/billing-state.ts
|
|
4
4
|
/** Whether the pricing page has no plans to show yet because the answer is still on its way. */
|
package/dist/index.d.mts
CHANGED
|
@@ -58,7 +58,8 @@ type DevPortalBillingConfig = {
|
|
|
58
58
|
* The header API users send their key in, as the portal build knows it from the gateway config. Wins over the plans
|
|
59
59
|
* backend's answer, which only knows the platform default.
|
|
60
60
|
*/
|
|
61
|
-
keyHeader?: string; /**
|
|
61
|
+
keyHeader?: string; /** The plan shown as "Popular"; none unless the tenant marked one (API-124). */
|
|
62
|
+
featuredPlanSku?: string; /** Local preview plan catalog (from `apitogo.config.json` `plans`). */
|
|
62
63
|
previewPlans?: Array<{
|
|
63
64
|
sku: string;
|
|
64
65
|
displayName: string;
|
|
@@ -266,7 +267,7 @@ type PlansPreviewItem = {
|
|
|
266
267
|
featured?: boolean;
|
|
267
268
|
};
|
|
268
269
|
/** Maps plans to landing `PlansPreviewSection` cards, highlighting the same plan as /pricing. */
|
|
269
|
-
declare const toPlansPreviewItems: (plans: DevPortalPlan[]) => PlansPreviewItem[];
|
|
270
|
+
declare const toPlansPreviewItems: (plans: DevPortalPlan[], featuredPlanSku?: string) => PlansPreviewItem[];
|
|
270
271
|
/**
|
|
271
272
|
* Plan cards for the landing `PlansPreviewSection`, sourced like the /pricing page: the dev
|
|
272
273
|
* portal backend when live, `modules.userPanel.plans.items` from `apitogo.config.json` in
|
package/dist/index.mjs
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { t as AccountPlansPage } from "./AccountPlansPage-
|
|
1
|
+
import { t as AccountPlansPage } from "./AccountPlansPage-BuM7fe82.mjs";
|
|
2
2
|
import { a as CREDENTIALS_PATH, c as SUBSCRIPTIONS_PATH, i as CONTACT_SALES_PATH, l as USAGE_PATH, o as LOGIN_NAV_PATH, r as CHECKOUT_PATH, s as PRICING_PATH, t as ACCOUNT_PLANS_PATH } from "./paths-DaVyTIDJ.mjs";
|
|
3
|
-
import { d as listPlanFeatureLines, f as parseManifestPlans, h as pickFeaturedPlanSku, i as formatPlanDisplayPrice, o as formatPlanPriceUnit, s as isActiveSubscription, v as resolveDevPortalApiBaseUrl } from "./useDevPortalApiBaseUrl-
|
|
4
|
-
import "./PricingCard-
|
|
3
|
+
import { d as listPlanFeatureLines, f as parseManifestPlans, h as pickFeaturedPlanSku, i as formatPlanDisplayPrice, o as formatPlanPriceUnit, s as isActiveSubscription, v as resolveDevPortalApiBaseUrl } from "./useDevPortalApiBaseUrl-BiI2jFjU.mjs";
|
|
4
|
+
import "./PricingCard-DFuQEw7Y.mjs";
|
|
5
5
|
import { n as useDevPortalBillingConfig, t as DevPortalBillingProvider } from "./DevPortalBillingContext-CR83s4LO.mjs";
|
|
6
6
|
import { t as DEMO_GATEWAY_KEY_HEADER } from "./demo-session-yK9qEqV-.mjs";
|
|
7
|
-
import { t as useMySubscriptions } from "./useMySubscriptions-
|
|
8
|
-
import { n as startPlansPrefetch, t as usePlans } from "./usePlans-
|
|
9
|
-
import
|
|
10
|
-
import { n as
|
|
11
|
-
import {
|
|
12
|
-
import { t as
|
|
7
|
+
import { t as useMySubscriptions } from "./useMySubscriptions-BYVIIWbe.mjs";
|
|
8
|
+
import { n as startPlansPrefetch, t as usePlans } from "./usePlans-HyhIIuJZ.mjs";
|
|
9
|
+
import "./pending-checkout-DpVaNnTu.mjs";
|
|
10
|
+
import { a as playgroundKeyIdentities, i as useRevokeApiKey, n as useApiKeys, r as useCreateApiKey, t as API_KEY_CAP_REACHED } from "./useApiKeys-BOY3vIOr.mjs";
|
|
11
|
+
import { n as useUsageRecent, t as useUsage } from "./useUsage-B5x9YuKa.mjs";
|
|
12
|
+
import { r as ApiKeysPanel, t as accountLayoutProps } from "./account-links-Drofs-f-.mjs";
|
|
13
|
+
import { t as isPreviewPricingEnabled } from "./pricing-config-Bc6eWFUO.mjs";
|
|
13
14
|
import { Head, Link } from "@lukoweb/apitogo/components";
|
|
14
15
|
import { ArrowRightIcon, KeyRoundIcon, StarsIcon } from "@lukoweb/apitogo/icons";
|
|
15
16
|
import { Outlet } from "@lukoweb/apitogo/router";
|
|
@@ -366,13 +367,13 @@ async function getSignedInIdentities(apiBaseUrl, fetchImpl = fetch) {
|
|
|
366
367
|
|
|
367
368
|
//#endregion
|
|
368
369
|
//#region src/DevPortalBillingPlugin.tsx
|
|
369
|
-
const AccountPlansPage$1 = lazy(() => import("./AccountPlansPage-
|
|
370
|
-
const CheckoutPage = lazy(() => import("./CheckoutPage-
|
|
371
|
-
const ContactSalesPage = lazy(() => import("./ContactSalesPage-
|
|
372
|
-
const CredentialsPage = lazy(() => import("./CredentialsPage-
|
|
373
|
-
const PricingPage = lazy(() => import("./PricingPage-
|
|
374
|
-
const SubscriptionsPage = lazy(() => import("./SubscriptionsPage-
|
|
375
|
-
const UsagePage = lazy(() => import("./UsagePage-
|
|
370
|
+
const AccountPlansPage$1 = lazy(() => import("./AccountPlansPage-BuM7fe82.mjs").then((n) => n.n));
|
|
371
|
+
const CheckoutPage = lazy(() => import("./CheckoutPage-BSiADcI6.mjs"));
|
|
372
|
+
const ContactSalesPage = lazy(() => import("./ContactSalesPage-BqqDmorF.mjs"));
|
|
373
|
+
const CredentialsPage = lazy(() => import("./CredentialsPage-DjNvBBLb.mjs"));
|
|
374
|
+
const PricingPage = lazy(() => import("./PricingPage-SpL81vpd.mjs"));
|
|
375
|
+
const SubscriptionsPage = lazy(() => import("./SubscriptionsPage-CwsBtNld.mjs"));
|
|
376
|
+
const UsagePage = lazy(() => import("./UsagePage-Dw5Uepg3.mjs"));
|
|
376
377
|
function resolvePricingEnabled(config) {
|
|
377
378
|
if (config.__meta?.pricingEnabled !== void 0) return config.__meta.pricingEnabled;
|
|
378
379
|
return isPreviewPricingEnabled();
|
|
@@ -495,8 +496,8 @@ function useGatewayCall() {
|
|
|
495
496
|
//#endregion
|
|
496
497
|
//#region src/hooks/usePlansPreview.ts
|
|
497
498
|
/** Maps plans to landing `PlansPreviewSection` cards, highlighting the same plan as /pricing. */
|
|
498
|
-
const toPlansPreviewItems = (plans) => {
|
|
499
|
-
const featuredSku = pickFeaturedPlanSku(plans);
|
|
499
|
+
const toPlansPreviewItems = (plans, featuredPlanSku) => {
|
|
500
|
+
const featuredSku = pickFeaturedPlanSku(plans, featuredPlanSku);
|
|
500
501
|
return plans.map((plan) => ({
|
|
501
502
|
name: plan.displayName,
|
|
502
503
|
price: formatPlanDisplayPrice(plan),
|
|
@@ -513,7 +514,8 @@ const toPlansPreviewItems = (plans) => {
|
|
|
513
514
|
*/
|
|
514
515
|
const usePlansPreview = () => {
|
|
515
516
|
const { data } = usePlans();
|
|
516
|
-
|
|
517
|
+
const { featuredPlanSku } = useDevPortalBillingConfig();
|
|
518
|
+
return toPlansPreviewItems(data?.plans ?? parseManifestPlans().plans, featuredPlanSku);
|
|
517
519
|
};
|
|
518
520
|
|
|
519
521
|
//#endregion
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
//#region src/utils/pending-checkout.ts
|
|
2
|
+
const STORAGE_KEY = "apitogo-pending-checkout";
|
|
3
|
+
/** How long a checkout counts as waiting for its payment to be confirmed. Stripe usually confirms within seconds. */
|
|
4
|
+
const PENDING_FOR_MS = 600 * 1e3;
|
|
5
|
+
const storage = () => {
|
|
6
|
+
try {
|
|
7
|
+
return typeof sessionStorage === "undefined" ? void 0 : sessionStorage;
|
|
8
|
+
} catch {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Remembers the plan the customer is about to pay for, as checkout sends them to Stripe. Back in the portal the payment
|
|
14
|
+
* is confirmed a few seconds later; until then the pages must not offer that plan again (API-128), even when the
|
|
15
|
+
* customer already holds another plan. Only this browser tab knows it.
|
|
16
|
+
*/
|
|
17
|
+
function rememberPendingCheckout(sku, now = Date.now()) {
|
|
18
|
+
try {
|
|
19
|
+
storage()?.setItem(STORAGE_KEY, JSON.stringify({
|
|
20
|
+
sku,
|
|
21
|
+
at: now
|
|
22
|
+
}));
|
|
23
|
+
} catch {}
|
|
24
|
+
}
|
|
25
|
+
/** The plan still waiting for its payment to be confirmed, or undefined when none is (or it is too old). */
|
|
26
|
+
function readPendingCheckout(now = Date.now()) {
|
|
27
|
+
try {
|
|
28
|
+
const raw = storage()?.getItem(STORAGE_KEY);
|
|
29
|
+
if (!raw) return void 0;
|
|
30
|
+
const pending = JSON.parse(raw);
|
|
31
|
+
if (typeof pending.sku !== "string" || typeof pending.at !== "number") return void 0;
|
|
32
|
+
return now - pending.at <= PENDING_FOR_MS ? pending.sku : void 0;
|
|
33
|
+
} catch {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** The payment was confirmed (the plan is active) or given up on. */
|
|
38
|
+
function clearPendingCheckout() {
|
|
39
|
+
try {
|
|
40
|
+
storage()?.removeItem(STORAGE_KEY);
|
|
41
|
+
} catch {}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
//#endregion
|
|
45
|
+
export { readPendingCheckout as n, rememberPendingCheckout as r, clearPendingCheckout as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as useDevPortalPreviewMode, r as useIsDemoSession, t as useDevPortalApiBaseUrl } from "./useDevPortalApiBaseUrl-
|
|
1
|
+
import { n as useDevPortalPreviewMode, r as useIsDemoSession, t as useDevPortalApiBaseUrl } from "./useDevPortalApiBaseUrl-BiI2jFjU.mjs";
|
|
2
2
|
import { n as useDevPortalBillingConfig } from "./DevPortalBillingContext-CR83s4LO.mjs";
|
|
3
3
|
import { n as readProblemDetail } from "./problem-details-n20-dy3w.mjs";
|
|
4
4
|
import { n as createDemoApiKeys, t as DEMO_GATEWAY_KEY_HEADER } from "./demo-session-yK9qEqV-.mjs";
|
|
@@ -115,9 +115,14 @@ function formatPlanDisplayPrice(plan) {
|
|
|
115
115
|
function formatPlanPriceUnit(plan) {
|
|
116
116
|
return isPlanCustomPriced(plan) ? "talk to us" : formatBillingPeriod(plan.billingPeriod);
|
|
117
117
|
}
|
|
118
|
-
/**
|
|
119
|
-
|
|
120
|
-
|
|
118
|
+
/**
|
|
119
|
+
* SKU of the plan to highlight: the one the tenant marked `featured`, when the catalog has it. It used to be guessed
|
|
120
|
+
* (a plan called "developer", or the first cheap paid one), which put "Popular" on a plan the tenant never chose
|
|
121
|
+
* (API-124).
|
|
122
|
+
*/
|
|
123
|
+
function pickFeaturedPlanSku(plans, featuredPlanSku) {
|
|
124
|
+
const wanted = featuredPlanSku?.trim().toLowerCase();
|
|
125
|
+
return wanted ? plans.find((p) => p.sku.toLowerCase() === wanted)?.sku : void 0;
|
|
121
126
|
}
|
|
122
127
|
function formatRateLimit(rate) {
|
|
123
128
|
if (!rate || typeof rate !== "object") return null;
|
|
@@ -172,17 +177,12 @@ function parseLimits(limitsJson) {
|
|
|
172
177
|
}
|
|
173
178
|
}
|
|
174
179
|
/** Marketing bullets keyed by common sample SKUs when limitsJson is sparse. */
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
"Custom rate limits",
|
|
182
|
-
"SSO & audit logs",
|
|
183
|
-
"Dedicated SLA"
|
|
184
|
-
]
|
|
185
|
-
};
|
|
180
|
+
/**
|
|
181
|
+
* Lines a plan gets from its name alone. Empty on purpose: "SSO & audit logs" or "Dedicated SLA" under a plan called
|
|
182
|
+
* Enterprise were promises the tenant never made (API-124). A plan shows its limits, its endpoints and what the
|
|
183
|
+
* tenant wrote.
|
|
184
|
+
*/
|
|
185
|
+
const SAMPLE_PLAN_FEATURE_EXTRAS = {};
|
|
186
186
|
function listPlanFeatureLines(plan) {
|
|
187
187
|
if (plan.features && plan.features.length > 0) return plan.features;
|
|
188
188
|
const lines = [];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as useDevPortalPreviewMode, r as useIsDemoSession, t as useDevPortalApiBaseUrl } from "./useDevPortalApiBaseUrl-
|
|
1
|
+
import { n as useDevPortalPreviewMode, r as useIsDemoSession, t as useDevPortalApiBaseUrl } from "./useDevPortalApiBaseUrl-BiI2jFjU.mjs";
|
|
2
2
|
import { n as useDevPortalBillingConfig } from "./DevPortalBillingContext-CR83s4LO.mjs";
|
|
3
3
|
import { i as createDemoMeResponse } from "./demo-session-yK9qEqV-.mjs";
|
|
4
4
|
import { useQuery } from "@lukoweb/apitogo/react-query";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as isPlaceholderDevPortalApiUrl, f as parseManifestPlans, n as useDevPortalPreviewMode, r as useIsDemoSession, t as useDevPortalApiBaseUrl } from "./useDevPortalApiBaseUrl-
|
|
1
|
+
import { c as isPlaceholderDevPortalApiUrl, f as parseManifestPlans, n as useDevPortalPreviewMode, r as useIsDemoSession, t as useDevPortalApiBaseUrl } from "./useDevPortalApiBaseUrl-BiI2jFjU.mjs";
|
|
2
2
|
import { n as useDevPortalBillingConfig } from "./DevPortalBillingContext-CR83s4LO.mjs";
|
|
3
3
|
import { useQuery } from "@lukoweb/apitogo/react-query";
|
|
4
4
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as useDevPortalPreviewMode, r as useIsDemoSession, t as useDevPortalApiBaseUrl } from "./useDevPortalApiBaseUrl-
|
|
1
|
+
import { n as useDevPortalPreviewMode, r as useIsDemoSession, t as useDevPortalApiBaseUrl } from "./useDevPortalApiBaseUrl-BiI2jFjU.mjs";
|
|
2
2
|
import { useQuery } from "@lukoweb/apitogo/react-query";
|
|
3
3
|
import { useAuth } from "@lukoweb/apitogo/hooks";
|
|
4
4
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lukoweb/apitogo-plugin-dev-portal-billing",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.56",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/zuplo/zudoku",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"react": "19.2.4",
|
|
47
47
|
"react-dom": "19.2.4",
|
|
48
48
|
"tsdown": "0.20.3",
|
|
49
|
-
"@lukoweb/apitogo": "0.2.
|
|
50
|
-
"@lukoweb/apitogo-module-user-panel": "0.2.
|
|
49
|
+
"@lukoweb/apitogo": "0.2.56",
|
|
50
|
+
"@lukoweb/apitogo-module-user-panel": "0.2.56"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
53
|
"react": ">=19.2.0",
|
|
File without changes
|
|
File without changes
|