@lukoweb/apitogo-plugin-dev-portal-billing 0.1.47 → 0.1.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.mjs +157 -20
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -12,6 +12,8 @@ import { Alert, AlertAction, AlertDescription } from "@lukoweb/apitogo/ui/Alert"
|
|
|
12
12
|
import { Button as Button$1 } from "@lukoweb/apitogo/ui/Button";
|
|
13
13
|
import { Secret } from "@lukoweb/apitogo/ui/Secret.js";
|
|
14
14
|
import { Value } from "@lukoweb/apitogo/ui/Value.js";
|
|
15
|
+
import { access, readFile } from "node:fs/promises";
|
|
16
|
+
import path from "node:path";
|
|
15
17
|
|
|
16
18
|
//#region src/utils/dev-portal-api.ts
|
|
17
19
|
const DEV_PORTAL_PLACEHOLDER_API_URL = "https://dp-example.azurecontainerapps.io";
|
|
@@ -322,11 +324,19 @@ const AccountPlansPage = () => {
|
|
|
322
324
|
children: [
|
|
323
325
|
"Local preview uses plans from",
|
|
324
326
|
" ",
|
|
327
|
+
/* @__PURE__ */ jsx("code", {
|
|
328
|
+
className: "rounded bg-muted px-1.5 py-0.5",
|
|
329
|
+
children: "apitogo.json"
|
|
330
|
+
}),
|
|
331
|
+
` `,
|
|
332
|
+
"(with optional",
|
|
333
|
+
" ",
|
|
325
334
|
/* @__PURE__ */ jsx("code", {
|
|
326
335
|
className: "rounded bg-muted px-1.5 py-0.5",
|
|
327
336
|
children: "apitogo.local.json"
|
|
328
337
|
}),
|
|
329
|
-
"
|
|
338
|
+
" ",
|
|
339
|
+
"overrides). Subscribe and unsubscribe activate after the portal is published."
|
|
330
340
|
]
|
|
331
341
|
}) : null,
|
|
332
342
|
cancelMutation.isError ? /* @__PURE__ */ jsx("div", {
|
|
@@ -705,14 +715,25 @@ const CredentialsPage = () => {
|
|
|
705
715
|
});
|
|
706
716
|
};
|
|
707
717
|
|
|
718
|
+
//#endregion
|
|
719
|
+
//#region src/utils/pricing-config.ts
|
|
720
|
+
function isPreviewPricingEnabled() {
|
|
721
|
+
return manifestCatalog?.pricingEnabled === true;
|
|
722
|
+
}
|
|
723
|
+
|
|
708
724
|
//#endregion
|
|
709
725
|
//#region src/pages/PricingPage.tsx
|
|
710
726
|
const PricingPage = () => {
|
|
711
727
|
const { pricing } = useDevPortalBillingConfig();
|
|
712
728
|
const auth = useAuth();
|
|
713
729
|
const isPreview = useDevPortalPreviewMode();
|
|
730
|
+
const pricingEnabled = isPreviewPricingEnabled();
|
|
714
731
|
const { data: catalog, isLoading, isError } = usePlans();
|
|
715
732
|
const { data: me } = useMySubscriptions();
|
|
733
|
+
if (!pricingEnabled) return /* @__PURE__ */ jsx(Navigate, {
|
|
734
|
+
to: "/",
|
|
735
|
+
replace: true
|
|
736
|
+
});
|
|
716
737
|
if (auth.isAuthenticated) return /* @__PURE__ */ jsx(Navigate, {
|
|
717
738
|
to: "/account/plans",
|
|
718
739
|
replace: true
|
|
@@ -744,11 +765,19 @@ const PricingPage = () => {
|
|
|
744
765
|
children: [
|
|
745
766
|
"Local preview uses plans from",
|
|
746
767
|
" ",
|
|
768
|
+
/* @__PURE__ */ jsx("code", {
|
|
769
|
+
className: "rounded bg-muted px-1.5 py-0.5",
|
|
770
|
+
children: "apitogo.json"
|
|
771
|
+
}),
|
|
772
|
+
` `,
|
|
773
|
+
"(with optional",
|
|
774
|
+
" ",
|
|
747
775
|
/* @__PURE__ */ jsx("code", {
|
|
748
776
|
className: "rounded bg-muted px-1.5 py-0.5",
|
|
749
777
|
children: "apitogo.local.json"
|
|
750
778
|
}),
|
|
751
|
-
"
|
|
779
|
+
" ",
|
|
780
|
+
"overrides). Checkout activates after the portal is published."
|
|
752
781
|
]
|
|
753
782
|
}) : null,
|
|
754
783
|
isLoading ? /* @__PURE__ */ jsx("p", {
|
|
@@ -766,9 +795,25 @@ const PricingPage = () => {
|
|
|
766
795
|
mode: "public",
|
|
767
796
|
isSubscribed: activeSkus.has(plan.sku)
|
|
768
797
|
}, plan.sku))
|
|
769
|
-
}) : !isLoading && !isError ? /* @__PURE__ */
|
|
798
|
+
}) : !isLoading && !isError ? /* @__PURE__ */ jsxs("div", {
|
|
770
799
|
className: "mx-auto max-w-lg rounded-xl border border-dashed p-8 text-center text-sm text-muted-foreground",
|
|
771
|
-
children:
|
|
800
|
+
children: [
|
|
801
|
+
"No plans are configured yet. Add plans in",
|
|
802
|
+
" ",
|
|
803
|
+
/* @__PURE__ */ jsx("code", {
|
|
804
|
+
className: "rounded bg-muted px-1.5 py-0.5",
|
|
805
|
+
children: "apitogo.json"
|
|
806
|
+
}),
|
|
807
|
+
" ",
|
|
808
|
+
"and set",
|
|
809
|
+
" ",
|
|
810
|
+
/* @__PURE__ */ jsx("code", {
|
|
811
|
+
className: "rounded bg-muted px-1.5 py-0.5",
|
|
812
|
+
children: "pricing.enabled"
|
|
813
|
+
}),
|
|
814
|
+
" ",
|
|
815
|
+
"to true."
|
|
816
|
+
]
|
|
772
817
|
}) : null
|
|
773
818
|
]
|
|
774
819
|
});
|
|
@@ -896,14 +941,103 @@ const SubscriptionsPage = () => {
|
|
|
896
941
|
});
|
|
897
942
|
};
|
|
898
943
|
|
|
944
|
+
//#endregion
|
|
945
|
+
//#region src/utils/manifest-pricing.ts
|
|
946
|
+
const APITOGO_MANIFEST_BASE_FILENAME = "apitogo.json";
|
|
947
|
+
const APITOGO_MANIFEST_ENV_FILES = {
|
|
948
|
+
development: "apitogo.local.json",
|
|
949
|
+
production: "apitogo.prod.json"
|
|
950
|
+
};
|
|
951
|
+
async function fileExists(filePath) {
|
|
952
|
+
try {
|
|
953
|
+
await access(filePath);
|
|
954
|
+
return true;
|
|
955
|
+
} catch {
|
|
956
|
+
return false;
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
async function readManifestFile(filePath) {
|
|
960
|
+
try {
|
|
961
|
+
const raw = await readFile(filePath, "utf8");
|
|
962
|
+
return JSON.parse(raw);
|
|
963
|
+
} catch {
|
|
964
|
+
return null;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
function mergeManifest(base, override) {
|
|
968
|
+
if (!base) return override;
|
|
969
|
+
if (!override) return base;
|
|
970
|
+
return {
|
|
971
|
+
...base,
|
|
972
|
+
...override,
|
|
973
|
+
pricing: {
|
|
974
|
+
...base.pricing,
|
|
975
|
+
...override.pricing
|
|
976
|
+
}
|
|
977
|
+
};
|
|
978
|
+
}
|
|
979
|
+
async function readEffectiveManifest(rootDir, mode) {
|
|
980
|
+
const resolvedRoot = path.resolve(rootDir);
|
|
981
|
+
const env = mode === "production" ? "production" : "development";
|
|
982
|
+
const basePath = path.join(resolvedRoot, APITOGO_MANIFEST_BASE_FILENAME);
|
|
983
|
+
const overridePath = path.join(resolvedRoot, APITOGO_MANIFEST_ENV_FILES[env]);
|
|
984
|
+
const hasBase = await fileExists(basePath);
|
|
985
|
+
const hasOverride = await fileExists(overridePath);
|
|
986
|
+
if (!hasBase) {
|
|
987
|
+
const legacy = await readManifestFile(path.join(resolvedRoot, APITOGO_MANIFEST_ENV_FILES.development));
|
|
988
|
+
if (legacy) return legacy;
|
|
989
|
+
if (hasOverride) return readManifestFile(overridePath);
|
|
990
|
+
return null;
|
|
991
|
+
}
|
|
992
|
+
const base = await readManifestFile(basePath);
|
|
993
|
+
if (!hasOverride) return base;
|
|
994
|
+
return mergeManifest(base, await readManifestFile(overridePath));
|
|
995
|
+
}
|
|
996
|
+
async function manifestPricingEnabled(rootDir, mode = "development") {
|
|
997
|
+
return (await readEffectiveManifest(rootDir, mode))?.pricing?.enabled === true;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
//#endregion
|
|
1001
|
+
//#region src/utils/navigation-plans.ts
|
|
1002
|
+
function withoutPricingNavigation(items) {
|
|
1003
|
+
if (!items?.length) return [];
|
|
1004
|
+
return items.map((item) => {
|
|
1005
|
+
if (typeof item === "string") return item;
|
|
1006
|
+
if (item.type === "link" && item.to === PRICING_PATH) return null;
|
|
1007
|
+
if (item.items?.length) {
|
|
1008
|
+
const filteredItems = withoutPricingNavigation(item.items);
|
|
1009
|
+
return {
|
|
1010
|
+
...item,
|
|
1011
|
+
items: filteredItems
|
|
1012
|
+
};
|
|
1013
|
+
}
|
|
1014
|
+
return item;
|
|
1015
|
+
}).filter((item) => item !== null);
|
|
1016
|
+
}
|
|
1017
|
+
|
|
899
1018
|
//#endregion
|
|
900
1019
|
//#region src/DevPortalBillingPlugin.tsx
|
|
1020
|
+
async function resolvePricingEnabled(config) {
|
|
1021
|
+
const meta = config;
|
|
1022
|
+
const rootDir = meta.__meta?.rootDir;
|
|
1023
|
+
if (rootDir) return manifestPricingEnabled(rootDir, meta.__meta?.mode);
|
|
1024
|
+
return isPreviewPricingEnabled();
|
|
1025
|
+
}
|
|
901
1026
|
const devPortalBillingPlugin = createPlugin((options = {}) => ({
|
|
902
|
-
transformConfig: ({ config, merge }) =>
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
1027
|
+
transformConfig: async ({ config, merge }) => {
|
|
1028
|
+
if (!await resolvePricingEnabled(config)) return merge({
|
|
1029
|
+
navigation: withoutPricingNavigation(config.navigation),
|
|
1030
|
+
header: {
|
|
1031
|
+
...config.header,
|
|
1032
|
+
navigation: withoutPricingNavigation(config.header?.navigation)
|
|
1033
|
+
}
|
|
1034
|
+
});
|
|
1035
|
+
return merge({ header: { navigation: [...config.header?.navigation ?? [], {
|
|
1036
|
+
label: "Pricing",
|
|
1037
|
+
to: PRICING_PATH,
|
|
1038
|
+
display: "anon"
|
|
1039
|
+
}] } });
|
|
1040
|
+
},
|
|
907
1041
|
getProfileMenuItems: () => [{
|
|
908
1042
|
label: "My Subscriptions",
|
|
909
1043
|
path: SUBSCRIPTIONS_PATH,
|
|
@@ -917,15 +1051,8 @@ const devPortalBillingPlugin = createPlugin((options = {}) => ({
|
|
|
917
1051
|
category: "middle",
|
|
918
1052
|
weight: 26
|
|
919
1053
|
}],
|
|
920
|
-
getRoutes: () =>
|
|
921
|
-
|
|
922
|
-
handle: { layout: "none" },
|
|
923
|
-
children: [
|
|
924
|
-
{
|
|
925
|
-
path: PRICING_PATH,
|
|
926
|
-
handle: { layout: "default" },
|
|
927
|
-
element: /* @__PURE__ */ jsx(PricingPage, {})
|
|
928
|
-
},
|
|
1054
|
+
getRoutes: () => {
|
|
1055
|
+
const children = [
|
|
929
1056
|
{
|
|
930
1057
|
path: CHECKOUT_PATH,
|
|
931
1058
|
handle: { layout: "default" },
|
|
@@ -941,8 +1068,18 @@ const devPortalBillingPlugin = createPlugin((options = {}) => ({
|
|
|
941
1068
|
handle: { layout: "default" },
|
|
942
1069
|
element: /* @__PURE__ */ jsx(CredentialsPage, {})
|
|
943
1070
|
}
|
|
944
|
-
]
|
|
945
|
-
|
|
1071
|
+
];
|
|
1072
|
+
if (isPreviewPricingEnabled()) children.unshift({
|
|
1073
|
+
path: PRICING_PATH,
|
|
1074
|
+
handle: { layout: "default" },
|
|
1075
|
+
element: /* @__PURE__ */ jsx(PricingPage, {})
|
|
1076
|
+
});
|
|
1077
|
+
return [{
|
|
1078
|
+
element: /* @__PURE__ */ jsx(DevPortalBillingWrapper, { options }),
|
|
1079
|
+
handle: { layout: "none" },
|
|
1080
|
+
children
|
|
1081
|
+
}];
|
|
1082
|
+
},
|
|
946
1083
|
getProtectedRoutes: () => [
|
|
947
1084
|
CHECKOUT_PATH,
|
|
948
1085
|
SUBSCRIPTIONS_PATH,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lukoweb/apitogo-plugin-dev-portal-billing",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.49",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/zuplo/zudoku",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"react": "19.2.4",
|
|
47
47
|
"react-dom": "19.2.4",
|
|
48
48
|
"tsdown": "0.20.3",
|
|
49
|
-
"@lukoweb/apitogo": "0.1.
|
|
49
|
+
"@lukoweb/apitogo": "0.1.49"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
52
|
"react": ">=19.2.0",
|