@akira-io/billing-js 0.1.0
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/LICENSE +21 -0
- package/README.md +274 -0
- package/dist/checkout.cjs +10 -0
- package/dist/checkout.cjs.map +1 -0
- package/dist/checkout.d.cts +3 -0
- package/dist/checkout.d.ts +3 -0
- package/dist/checkout.js +8 -0
- package/dist/checkout.js.map +1 -0
- package/dist/client-DpOXhuxx.d.cts +141 -0
- package/dist/client-DpOXhuxx.d.ts +141 -0
- package/dist/client.cjs +179 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +1 -0
- package/dist/client.d.ts +1 -0
- package/dist/client.js +176 -0
- package/dist/client.js.map +1 -0
- package/dist/downloads.cjs +51 -0
- package/dist/downloads.cjs.map +1 -0
- package/dist/downloads.d.cts +34 -0
- package/dist/downloads.d.ts +34 -0
- package/dist/downloads.js +46 -0
- package/dist/downloads.js.map +1 -0
- package/dist/helpers.cjs +116 -0
- package/dist/helpers.cjs.map +1 -0
- package/dist/helpers.d.cts +55 -0
- package/dist/helpers.d.ts +55 -0
- package/dist/helpers.js +109 -0
- package/dist/helpers.js.map +1 -0
- package/dist/index.cjs +439 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +16 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +416 -0
- package/dist/index.js.map +1 -0
- package/dist/pricing.cjs +104 -0
- package/dist/pricing.cjs.map +1 -0
- package/dist/pricing.d.cts +15 -0
- package/dist/pricing.d.ts +15 -0
- package/dist/pricing.js +101 -0
- package/dist/pricing.js.map +1 -0
- package/dist/react.cjs +219 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +39 -0
- package/dist/react.d.ts +39 -0
- package/dist/react.js +215 -0
- package/dist/react.js.map +1 -0
- package/dist/types-CH4Vkivj.d.cts +59 -0
- package/dist/types-CH4Vkivj.d.ts +59 -0
- package/dist/vue.cjs +218 -0
- package/dist/vue.cjs.map +1 -0
- package/dist/vue.d.cts +32 -0
- package/dist/vue.d.ts +32 -0
- package/dist/vue.js +214 -0
- package/dist/vue.js.map +1 -0
- package/package.json +113 -0
package/dist/pricing.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// src/pricing.ts
|
|
2
|
+
var INTERVAL_SUFFIXES = ["_monthly", "_yearly", "_month", "_year", "_one_time"];
|
|
3
|
+
function tierKeyFromPlanKey(planKey) {
|
|
4
|
+
for (const suf of INTERVAL_SUFFIXES) {
|
|
5
|
+
if (planKey.endsWith(suf)) {
|
|
6
|
+
return planKey.slice(0, -suf.length);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
return planKey;
|
|
10
|
+
}
|
|
11
|
+
function titleCase(s) {
|
|
12
|
+
return s.replace(/[_-]+/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
13
|
+
}
|
|
14
|
+
function emptyPayload(productKey) {
|
|
15
|
+
return { product: productKey, betaActive: false, tiers: [] };
|
|
16
|
+
}
|
|
17
|
+
function shapeFromApi(payload, config) {
|
|
18
|
+
const meta = config.tierMeta ?? {};
|
|
19
|
+
const monthsFree = config.yearlyMonthsFree ?? 2;
|
|
20
|
+
const tiersMap = /* @__PURE__ */ new Map();
|
|
21
|
+
for (const plan of payload.plans) {
|
|
22
|
+
const tierKey = tierKeyFromPlanKey(plan.key);
|
|
23
|
+
const m = meta[tierKey];
|
|
24
|
+
if (!tiersMap.has(tierKey)) {
|
|
25
|
+
tiersMap.set(tierKey, {
|
|
26
|
+
key: tierKey,
|
|
27
|
+
name: m?.label ?? titleCase(tierKey),
|
|
28
|
+
tagline: m?.tagline ?? plan.description ?? "",
|
|
29
|
+
highlighted: m?.highlighted ?? false,
|
|
30
|
+
monthly: null,
|
|
31
|
+
yearly: null,
|
|
32
|
+
oneTime: null,
|
|
33
|
+
isComingSoon: false,
|
|
34
|
+
features: plan.features.map(
|
|
35
|
+
(f) => ({ key: f.key, name: f.name, description: f.description })
|
|
36
|
+
)
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
const tier = tiersMap.get(tierKey);
|
|
40
|
+
if (plan.is_coming_soon === true) {
|
|
41
|
+
tier.isComingSoon = true;
|
|
42
|
+
}
|
|
43
|
+
if (tier.features.length === 0 && plan.features.length > 0) {
|
|
44
|
+
tier.features = plan.features.map((f) => ({ key: f.key, name: f.name, description: f.description }));
|
|
45
|
+
}
|
|
46
|
+
if (plan.billing_interval === "month" && plan.amount !== null && plan.currency !== null) {
|
|
47
|
+
tier.monthly = { amount: plan.amount, currency: plan.currency, planKey: plan.key };
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (plan.billing_interval === "year" && plan.amount !== null && plan.currency !== null) {
|
|
51
|
+
tier.yearly = { amount: plan.amount, currency: plan.currency, monthsFree, planKey: plan.key };
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (plan.billing_interval === null) {
|
|
55
|
+
const amount = plan.amount ?? 0;
|
|
56
|
+
const currency = plan.currency ?? "eur";
|
|
57
|
+
if (amount === 0) {
|
|
58
|
+
tier.monthly = { amount: 0, currency, planKey: plan.key };
|
|
59
|
+
} else {
|
|
60
|
+
tier.oneTime = { amount, currency, planKey: plan.key };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const tiers = Array.from(tiersMap.values()).sort((a, b) => {
|
|
65
|
+
const oa = meta[a.key]?.order ?? 999;
|
|
66
|
+
const ob = meta[b.key]?.order ?? 999;
|
|
67
|
+
return oa - ob;
|
|
68
|
+
});
|
|
69
|
+
return {
|
|
70
|
+
product: payload.product,
|
|
71
|
+
betaActive: payload.beta_active,
|
|
72
|
+
tiers
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
async function fetchPricing(config) {
|
|
76
|
+
const base = config.baseUrl?.replace(/\/$/, "");
|
|
77
|
+
if (!base) return emptyPayload(config.productKey);
|
|
78
|
+
const f = config.fetcher ?? globalThis.fetch;
|
|
79
|
+
if (!f) {
|
|
80
|
+
throw new Error("No fetch implementation available. Pass a fetcher in config or use Node 18+.");
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const res = await f(`${base}/api/v1/products/${config.productKey}/plans`, {
|
|
84
|
+
headers: { Accept: "application/json" }
|
|
85
|
+
});
|
|
86
|
+
if (!res.ok) return emptyPayload(config.productKey);
|
|
87
|
+
const data = await res.json();
|
|
88
|
+
return shapeFromApi(data, config);
|
|
89
|
+
} catch {
|
|
90
|
+
return emptyPayload(config.productKey);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function formatPrice(amountInCents, currency) {
|
|
94
|
+
const symbol = currency.toLowerCase() === "eur" ? "\u20AC" : currency.toUpperCase() + " ";
|
|
95
|
+
const major = (amountInCents / 100).toFixed(amountInCents % 100 === 0 ? 0 : 2);
|
|
96
|
+
return `${symbol}${major}`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export { fetchPricing, formatPrice };
|
|
100
|
+
//# sourceMappingURL=pricing.js.map
|
|
101
|
+
//# sourceMappingURL=pricing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/pricing.ts"],"names":[],"mappings":"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","file":"pricing.js","sourcesContent":["import type {\n BillingInterval,\n PricingFeature,\n PricingPayload,\n PricingTier,\n TierMeta,\n} from './types';\n\nexport type FetchPricingConfig = {\n baseUrl: string;\n productKey: string;\n tierMeta?: Record<string, TierMeta>;\n yearlyMonthsFree?: number;\n /** Override the global fetch (e.g. Node 18+ or custom retry). */\n fetcher?: typeof fetch;\n};\n\ntype ApiFeature = {\n key: string;\n name: string;\n description: string | null;\n};\n\ntype ApiPlan = {\n key: string;\n name: string;\n description: string | null;\n amount: number | null;\n currency: string | null;\n billing_interval: BillingInterval | null;\n trial_period_days: number;\n is_coming_soon?: boolean;\n features: ApiFeature[];\n};\n\ntype ApiPayload = {\n product: string;\n name: string;\n description: string | null;\n beta_active: boolean;\n plans: ApiPlan[];\n};\n\nconst INTERVAL_SUFFIXES = ['_monthly', '_yearly', '_month', '_year', '_one_time'];\n\nfunction tierKeyFromPlanKey(planKey: string): string {\n for (const suf of INTERVAL_SUFFIXES) {\n if (planKey.endsWith(suf)) {\n return planKey.slice(0, -suf.length);\n }\n }\n return planKey;\n}\n\nfunction titleCase(s: string): string {\n return s.replace(/[_-]+/g, ' ').replace(/\\b\\w/g, (c) => c.toUpperCase());\n}\n\nfunction emptyPayload(productKey: string): PricingPayload {\n return { product: productKey, betaActive: false, tiers: [] };\n}\n\nfunction shapeFromApi(payload: ApiPayload, config: FetchPricingConfig): PricingPayload {\n const meta = config.tierMeta ?? {};\n const monthsFree = config.yearlyMonthsFree ?? 2;\n const tiersMap = new Map<string, PricingTier>();\n\n for (const plan of payload.plans) {\n const tierKey = tierKeyFromPlanKey(plan.key);\n const m = meta[tierKey];\n\n if (!tiersMap.has(tierKey)) {\n tiersMap.set(tierKey, {\n key: tierKey,\n name: m?.label ?? titleCase(tierKey),\n tagline: m?.tagline ?? plan.description ?? '',\n highlighted: m?.highlighted ?? false,\n monthly: null,\n yearly: null,\n oneTime: null,\n isComingSoon: false,\n features: plan.features.map(\n (f): PricingFeature => ({ key: f.key, name: f.name, description: f.description }),\n ),\n });\n }\n\n const tier = tiersMap.get(tierKey)!;\n\n if (plan.is_coming_soon === true) {\n tier.isComingSoon = true;\n }\n\n if (tier.features.length === 0 && plan.features.length > 0) {\n tier.features = plan.features.map((f) => ({ key: f.key, name: f.name, description: f.description }));\n }\n\n if (plan.billing_interval === 'month' && plan.amount !== null && plan.currency !== null) {\n tier.monthly = { amount: plan.amount, currency: plan.currency, planKey: plan.key };\n continue;\n }\n\n if (plan.billing_interval === 'year' && plan.amount !== null && plan.currency !== null) {\n tier.yearly = { amount: plan.amount, currency: plan.currency, monthsFree, planKey: plan.key };\n continue;\n }\n\n if (plan.billing_interval === null) {\n const amount = plan.amount ?? 0;\n const currency = plan.currency ?? 'eur';\n if (amount === 0) {\n tier.monthly = { amount: 0, currency, planKey: plan.key };\n } else {\n tier.oneTime = { amount, currency, planKey: plan.key };\n }\n }\n }\n\n const tiers = Array.from(tiersMap.values()).sort((a, b) => {\n const oa = meta[a.key]?.order ?? 999;\n const ob = meta[b.key]?.order ?? 999;\n return oa - ob;\n });\n\n return {\n product: payload.product,\n betaActive: payload.beta_active,\n tiers,\n };\n}\n\nexport async function fetchPricing(config: FetchPricingConfig): Promise<PricingPayload> {\n const base = config.baseUrl?.replace(/\\/$/, '');\n if (!base) return emptyPayload(config.productKey);\n\n const f = config.fetcher ?? globalThis.fetch;\n if (!f) {\n throw new Error('No fetch implementation available. Pass a fetcher in config or use Node 18+.');\n }\n\n try {\n const res = await f(`${base}/api/v1/products/${config.productKey}/plans`, {\n headers: { Accept: 'application/json' },\n });\n if (!res.ok) return emptyPayload(config.productKey);\n const data = (await res.json()) as ApiPayload;\n return shapeFromApi(data, config);\n } catch {\n return emptyPayload(config.productKey);\n }\n}\n\nexport function formatPrice(amountInCents: number, currency: string): string {\n const symbol = currency.toLowerCase() === 'eur' ? '€' : currency.toUpperCase() + ' ';\n const major = (amountInCents / 100).toFixed(amountInCents % 100 === 0 ? 0 : 2);\n return `${symbol}${major}`;\n}\n\nexport type { PricingFeature, PricingPayload, PricingTier, TierMeta };\n"]}
|
package/dist/react.cjs
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
|
|
5
|
+
// src/react.ts
|
|
6
|
+
|
|
7
|
+
// src/pricing.ts
|
|
8
|
+
var INTERVAL_SUFFIXES = ["_monthly", "_yearly", "_month", "_year", "_one_time"];
|
|
9
|
+
function tierKeyFromPlanKey(planKey) {
|
|
10
|
+
for (const suf of INTERVAL_SUFFIXES) {
|
|
11
|
+
if (planKey.endsWith(suf)) {
|
|
12
|
+
return planKey.slice(0, -suf.length);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return planKey;
|
|
16
|
+
}
|
|
17
|
+
function titleCase(s) {
|
|
18
|
+
return s.replace(/[_-]+/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
19
|
+
}
|
|
20
|
+
function emptyPayload(productKey) {
|
|
21
|
+
return { product: productKey, betaActive: false, tiers: [] };
|
|
22
|
+
}
|
|
23
|
+
function shapeFromApi(payload, config) {
|
|
24
|
+
const meta = config.tierMeta ?? {};
|
|
25
|
+
const monthsFree = config.yearlyMonthsFree ?? 2;
|
|
26
|
+
const tiersMap = /* @__PURE__ */ new Map();
|
|
27
|
+
for (const plan of payload.plans) {
|
|
28
|
+
const tierKey = tierKeyFromPlanKey(plan.key);
|
|
29
|
+
const m = meta[tierKey];
|
|
30
|
+
if (!tiersMap.has(tierKey)) {
|
|
31
|
+
tiersMap.set(tierKey, {
|
|
32
|
+
key: tierKey,
|
|
33
|
+
name: m?.label ?? titleCase(tierKey),
|
|
34
|
+
tagline: m?.tagline ?? plan.description ?? "",
|
|
35
|
+
highlighted: m?.highlighted ?? false,
|
|
36
|
+
monthly: null,
|
|
37
|
+
yearly: null,
|
|
38
|
+
oneTime: null,
|
|
39
|
+
isComingSoon: false,
|
|
40
|
+
features: plan.features.map(
|
|
41
|
+
(f) => ({ key: f.key, name: f.name, description: f.description })
|
|
42
|
+
)
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
const tier = tiersMap.get(tierKey);
|
|
46
|
+
if (plan.is_coming_soon === true) {
|
|
47
|
+
tier.isComingSoon = true;
|
|
48
|
+
}
|
|
49
|
+
if (tier.features.length === 0 && plan.features.length > 0) {
|
|
50
|
+
tier.features = plan.features.map((f) => ({ key: f.key, name: f.name, description: f.description }));
|
|
51
|
+
}
|
|
52
|
+
if (plan.billing_interval === "month" && plan.amount !== null && plan.currency !== null) {
|
|
53
|
+
tier.monthly = { amount: plan.amount, currency: plan.currency, planKey: plan.key };
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (plan.billing_interval === "year" && plan.amount !== null && plan.currency !== null) {
|
|
57
|
+
tier.yearly = { amount: plan.amount, currency: plan.currency, monthsFree, planKey: plan.key };
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (plan.billing_interval === null) {
|
|
61
|
+
const amount = plan.amount ?? 0;
|
|
62
|
+
const currency = plan.currency ?? "eur";
|
|
63
|
+
if (amount === 0) {
|
|
64
|
+
tier.monthly = { amount: 0, currency, planKey: plan.key };
|
|
65
|
+
} else {
|
|
66
|
+
tier.oneTime = { amount, currency, planKey: plan.key };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const tiers = Array.from(tiersMap.values()).sort((a, b) => {
|
|
71
|
+
const oa = meta[a.key]?.order ?? 999;
|
|
72
|
+
const ob = meta[b.key]?.order ?? 999;
|
|
73
|
+
return oa - ob;
|
|
74
|
+
});
|
|
75
|
+
return {
|
|
76
|
+
product: payload.product,
|
|
77
|
+
betaActive: payload.beta_active,
|
|
78
|
+
tiers
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
async function fetchPricing(config) {
|
|
82
|
+
const base = config.baseUrl?.replace(/\/$/, "");
|
|
83
|
+
if (!base) return emptyPayload(config.productKey);
|
|
84
|
+
const f = config.fetcher ?? globalThis.fetch;
|
|
85
|
+
if (!f) {
|
|
86
|
+
throw new Error("No fetch implementation available. Pass a fetcher in config or use Node 18+.");
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const res = await f(`${base}/api/v1/products/${config.productKey}/plans`, {
|
|
90
|
+
headers: { Accept: "application/json" }
|
|
91
|
+
});
|
|
92
|
+
if (!res.ok) return emptyPayload(config.productKey);
|
|
93
|
+
const data = await res.json();
|
|
94
|
+
return shapeFromApi(data, config);
|
|
95
|
+
} catch {
|
|
96
|
+
return emptyPayload(config.productKey);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// src/downloads.ts
|
|
101
|
+
function downloadUrl(config) {
|
|
102
|
+
const base = config.baseUrl.replace(/\/$/, "");
|
|
103
|
+
const path = `/api/v1/downloads/${config.product}/${config.channel}/${config.platform}`;
|
|
104
|
+
const params = new URLSearchParams();
|
|
105
|
+
for (const [k, v] of Object.entries(config.query ?? {})) {
|
|
106
|
+
if (v !== void 0 && v !== "") params.set(k, v);
|
|
107
|
+
}
|
|
108
|
+
const qs = params.toString();
|
|
109
|
+
return qs ? `${base}${path}?${qs}` : `${base}${path}`;
|
|
110
|
+
}
|
|
111
|
+
async function issueDownload(config) {
|
|
112
|
+
const f = config.fetcher ?? globalThis.fetch;
|
|
113
|
+
if (!f) {
|
|
114
|
+
throw new Error("No fetch implementation available. Pass a fetcher in config or use Node 18+.");
|
|
115
|
+
}
|
|
116
|
+
const url = downloadUrl(config);
|
|
117
|
+
const res = await f(url, { headers: { Accept: "application/json" } });
|
|
118
|
+
if (!res.ok) {
|
|
119
|
+
throw new Error(`download issue failed: HTTP ${res.status}`);
|
|
120
|
+
}
|
|
121
|
+
return await res.json();
|
|
122
|
+
}
|
|
123
|
+
function sendCompletionBeacon(beaconUrl) {
|
|
124
|
+
if (typeof navigator !== "undefined" && typeof navigator.sendBeacon === "function") {
|
|
125
|
+
navigator.sendBeacon(beaconUrl);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (typeof fetch !== "undefined") {
|
|
129
|
+
void fetch(beaconUrl, { method: "POST", keepalive: true }).catch(() => {
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
async function triggerDownload(config) {
|
|
134
|
+
const issued = await issueDownload(config);
|
|
135
|
+
const delay = config.beaconDelayMs ?? 1500;
|
|
136
|
+
if (typeof window !== "undefined") {
|
|
137
|
+
window.location.href = issued.signedUrl;
|
|
138
|
+
setTimeout(() => sendCompletionBeacon(issued.beaconUrl), delay);
|
|
139
|
+
}
|
|
140
|
+
return issued;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// src/helpers.ts
|
|
144
|
+
function hasYearly(tier) {
|
|
145
|
+
return tier.yearly !== null && tier.monthly !== null;
|
|
146
|
+
}
|
|
147
|
+
function defaultInterval(tiers) {
|
|
148
|
+
if (tiers.some(hasYearly)) return "monthly";
|
|
149
|
+
if (tiers.every((t) => t.monthly === null && t.oneTime !== null)) return "oneTime";
|
|
150
|
+
return "monthly";
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// src/react.ts
|
|
154
|
+
function usePricing(config) {
|
|
155
|
+
const [data, setData] = react.useState(null);
|
|
156
|
+
const [error, setError] = react.useState(null);
|
|
157
|
+
const [isLoading, setIsLoading] = react.useState(true);
|
|
158
|
+
const [tick, setTick] = react.useState(0);
|
|
159
|
+
react.useEffect(() => {
|
|
160
|
+
let alive = true;
|
|
161
|
+
setIsLoading(true);
|
|
162
|
+
setError(null);
|
|
163
|
+
fetchPricing(config).then((p) => {
|
|
164
|
+
if (alive) setData(p);
|
|
165
|
+
}).catch((e) => {
|
|
166
|
+
if (alive) setError(e instanceof Error ? e : new Error(String(e)));
|
|
167
|
+
}).finally(() => {
|
|
168
|
+
if (alive) setIsLoading(false);
|
|
169
|
+
});
|
|
170
|
+
return () => {
|
|
171
|
+
alive = false;
|
|
172
|
+
};
|
|
173
|
+
}, [config.baseUrl, config.productKey, config.yearlyMonthsFree, tick]);
|
|
174
|
+
const refresh = react.useCallback(() => setTick((t) => t + 1), []);
|
|
175
|
+
return { data, error, isLoading, refresh };
|
|
176
|
+
}
|
|
177
|
+
function useBillingInterval(tiers) {
|
|
178
|
+
const initial = react.useMemo(() => defaultInterval(tiers ?? []), [tiers]);
|
|
179
|
+
const [interval, setInterval] = react.useState(initial);
|
|
180
|
+
react.useEffect(() => {
|
|
181
|
+
setInterval(initial);
|
|
182
|
+
}, [initial]);
|
|
183
|
+
const toggle = react.useCallback(
|
|
184
|
+
() => setInterval((cur) => cur === "monthly" ? "yearly" : "monthly"),
|
|
185
|
+
[]
|
|
186
|
+
);
|
|
187
|
+
return { interval, setInterval, toggle };
|
|
188
|
+
}
|
|
189
|
+
function useDownload(config) {
|
|
190
|
+
const [isPending, setIsPending] = react.useState(false);
|
|
191
|
+
const [error, setError] = react.useState(null);
|
|
192
|
+
const [lastIssued, setLastIssued] = react.useState(null);
|
|
193
|
+
const trigger = react.useCallback(async () => {
|
|
194
|
+
setIsPending(true);
|
|
195
|
+
setError(null);
|
|
196
|
+
try {
|
|
197
|
+
const issued = await triggerDownload(config);
|
|
198
|
+
setLastIssued(issued);
|
|
199
|
+
} catch (e) {
|
|
200
|
+
setError(e instanceof Error ? e : new Error(String(e)));
|
|
201
|
+
} finally {
|
|
202
|
+
setIsPending(false);
|
|
203
|
+
}
|
|
204
|
+
}, [
|
|
205
|
+
config.baseUrl,
|
|
206
|
+
config.product,
|
|
207
|
+
config.channel,
|
|
208
|
+
config.platform,
|
|
209
|
+
config.beaconDelayMs,
|
|
210
|
+
JSON.stringify(config.query ?? {})
|
|
211
|
+
]);
|
|
212
|
+
return { trigger, isPending, error, lastIssued };
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
exports.useBillingInterval = useBillingInterval;
|
|
216
|
+
exports.useDownload = useDownload;
|
|
217
|
+
exports.usePricing = usePricing;
|
|
218
|
+
//# sourceMappingURL=react.cjs.map
|
|
219
|
+
//# sourceMappingURL=react.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/pricing.ts","../src/downloads.ts","../src/helpers.ts","../src/react.ts"],"names":["useState","useEffect","useCallback","useMemo"],"mappings":"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","file":"react.cjs","sourcesContent":["import type {\n BillingInterval,\n PricingFeature,\n PricingPayload,\n PricingTier,\n TierMeta,\n} from './types';\n\nexport type FetchPricingConfig = {\n baseUrl: string;\n productKey: string;\n tierMeta?: Record<string, TierMeta>;\n yearlyMonthsFree?: number;\n /** Override the global fetch (e.g. Node 18+ or custom retry). */\n fetcher?: typeof fetch;\n};\n\ntype ApiFeature = {\n key: string;\n name: string;\n description: string | null;\n};\n\ntype ApiPlan = {\n key: string;\n name: string;\n description: string | null;\n amount: number | null;\n currency: string | null;\n billing_interval: BillingInterval | null;\n trial_period_days: number;\n is_coming_soon?: boolean;\n features: ApiFeature[];\n};\n\ntype ApiPayload = {\n product: string;\n name: string;\n description: string | null;\n beta_active: boolean;\n plans: ApiPlan[];\n};\n\nconst INTERVAL_SUFFIXES = ['_monthly', '_yearly', '_month', '_year', '_one_time'];\n\nfunction tierKeyFromPlanKey(planKey: string): string {\n for (const suf of INTERVAL_SUFFIXES) {\n if (planKey.endsWith(suf)) {\n return planKey.slice(0, -suf.length);\n }\n }\n return planKey;\n}\n\nfunction titleCase(s: string): string {\n return s.replace(/[_-]+/g, ' ').replace(/\\b\\w/g, (c) => c.toUpperCase());\n}\n\nfunction emptyPayload(productKey: string): PricingPayload {\n return { product: productKey, betaActive: false, tiers: [] };\n}\n\nfunction shapeFromApi(payload: ApiPayload, config: FetchPricingConfig): PricingPayload {\n const meta = config.tierMeta ?? {};\n const monthsFree = config.yearlyMonthsFree ?? 2;\n const tiersMap = new Map<string, PricingTier>();\n\n for (const plan of payload.plans) {\n const tierKey = tierKeyFromPlanKey(plan.key);\n const m = meta[tierKey];\n\n if (!tiersMap.has(tierKey)) {\n tiersMap.set(tierKey, {\n key: tierKey,\n name: m?.label ?? titleCase(tierKey),\n tagline: m?.tagline ?? plan.description ?? '',\n highlighted: m?.highlighted ?? false,\n monthly: null,\n yearly: null,\n oneTime: null,\n isComingSoon: false,\n features: plan.features.map(\n (f): PricingFeature => ({ key: f.key, name: f.name, description: f.description }),\n ),\n });\n }\n\n const tier = tiersMap.get(tierKey)!;\n\n if (plan.is_coming_soon === true) {\n tier.isComingSoon = true;\n }\n\n if (tier.features.length === 0 && plan.features.length > 0) {\n tier.features = plan.features.map((f) => ({ key: f.key, name: f.name, description: f.description }));\n }\n\n if (plan.billing_interval === 'month' && plan.amount !== null && plan.currency !== null) {\n tier.monthly = { amount: plan.amount, currency: plan.currency, planKey: plan.key };\n continue;\n }\n\n if (plan.billing_interval === 'year' && plan.amount !== null && plan.currency !== null) {\n tier.yearly = { amount: plan.amount, currency: plan.currency, monthsFree, planKey: plan.key };\n continue;\n }\n\n if (plan.billing_interval === null) {\n const amount = plan.amount ?? 0;\n const currency = plan.currency ?? 'eur';\n if (amount === 0) {\n tier.monthly = { amount: 0, currency, planKey: plan.key };\n } else {\n tier.oneTime = { amount, currency, planKey: plan.key };\n }\n }\n }\n\n const tiers = Array.from(tiersMap.values()).sort((a, b) => {\n const oa = meta[a.key]?.order ?? 999;\n const ob = meta[b.key]?.order ?? 999;\n return oa - ob;\n });\n\n return {\n product: payload.product,\n betaActive: payload.beta_active,\n tiers,\n };\n}\n\nexport async function fetchPricing(config: FetchPricingConfig): Promise<PricingPayload> {\n const base = config.baseUrl?.replace(/\\/$/, '');\n if (!base) return emptyPayload(config.productKey);\n\n const f = config.fetcher ?? globalThis.fetch;\n if (!f) {\n throw new Error('No fetch implementation available. Pass a fetcher in config or use Node 18+.');\n }\n\n try {\n const res = await f(`${base}/api/v1/products/${config.productKey}/plans`, {\n headers: { Accept: 'application/json' },\n });\n if (!res.ok) return emptyPayload(config.productKey);\n const data = (await res.json()) as ApiPayload;\n return shapeFromApi(data, config);\n } catch {\n return emptyPayload(config.productKey);\n }\n}\n\nexport function formatPrice(amountInCents: number, currency: string): string {\n const symbol = currency.toLowerCase() === 'eur' ? '€' : currency.toUpperCase() + ' ';\n const major = (amountInCents / 100).toFixed(amountInCents % 100 === 0 ? 0 : 2);\n return `${symbol}${major}`;\n}\n\nexport type { PricingFeature, PricingPayload, PricingTier, TierMeta };\n","import type { AssetPlatform, IssuedDownload, ReleaseChannel } from './types';\n\nexport type DownloadConfig = {\n baseUrl: string;\n product: string;\n channel: ReleaseChannel;\n platform: AssetPlatform;\n /** Optional UTM + landing tracking. */\n query?: Record<string, string | undefined>;\n /** Delay before firing the completion beacon, ms. Default 1500. */\n beaconDelayMs?: number;\n fetcher?: typeof fetch;\n};\n\nexport function downloadUrl(config: Pick<DownloadConfig, 'baseUrl' | 'product' | 'channel' | 'platform' | 'query'>): string {\n const base = config.baseUrl.replace(/\\/$/, '');\n const path = `/api/v1/downloads/${config.product}/${config.channel}/${config.platform}`;\n const params = new URLSearchParams();\n for (const [k, v] of Object.entries(config.query ?? {})) {\n if (v !== undefined && v !== '') params.set(k, v);\n }\n const qs = params.toString();\n return qs ? `${base}${path}?${qs}` : `${base}${path}`;\n}\n\n/**\n * Issues a download via the billing API and returns the signed asset URL +\n * beacon URL without redirecting. Useful when you want full control of the\n * UX (e.g. fetch then trigger your own `<a download>` flow).\n */\nexport async function issueDownload(config: DownloadConfig): Promise<IssuedDownload> {\n const f = config.fetcher ?? globalThis.fetch;\n if (!f) {\n throw new Error('No fetch implementation available. Pass a fetcher in config or use Node 18+.');\n }\n\n const url = downloadUrl(config);\n const res = await f(url, { headers: { Accept: 'application/json' } });\n\n if (!res.ok) {\n throw new Error(`download issue failed: HTTP ${res.status}`);\n }\n\n return (await res.json()) as IssuedDownload;\n}\n\n/**\n * Fires the completion beacon for an issued download. Uses\n * `navigator.sendBeacon` when available (survives page navigation), falls\n * back to `fetch` with `keepalive: true`. Safe to call at unload time.\n */\nexport function sendCompletionBeacon(beaconUrl: string): void {\n if (typeof navigator !== 'undefined' && typeof navigator.sendBeacon === 'function') {\n navigator.sendBeacon(beaconUrl);\n return;\n }\n\n if (typeof fetch !== 'undefined') {\n void fetch(beaconUrl, { method: 'POST', keepalive: true }).catch(() => {});\n }\n}\n\n/**\n * One-shot helper for landing-page download CTAs: fetches a signed URL,\n * navigates the current tab to the asset, then schedules the completion\n * beacon. The function resolves once the navigation has been triggered.\n */\nexport async function triggerDownload(config: DownloadConfig): Promise<IssuedDownload> {\n const issued = await issueDownload(config);\n const delay = config.beaconDelayMs ?? 1500;\n\n if (typeof window !== 'undefined') {\n window.location.href = issued.signedUrl;\n setTimeout(() => sendCompletionBeacon(issued.beaconUrl), delay);\n }\n\n return issued;\n}\n","import { checkoutUrl } from './checkout';\nimport { formatPrice } from './pricing';\nimport type { PricingTier, TierMeta } from './types';\n\nexport type IntervalKey = 'monthly' | 'yearly' | 'oneTime';\n\nexport type CtaProps = {\n label: string;\n href: string | null;\n disabled: boolean;\n monthlyHref: string | null;\n yearlyHref: string | null;\n oneTimeHref: string | null;\n};\n\nexport type CtaOptions = {\n billingBaseUrl: string;\n productKey: string;\n tierMeta?: TierMeta;\n interval?: IntervalKey;\n freeLabel?: string;\n subscribeLabel?: string;\n buyLabel?: string;\n comingSoonLabel?: string;\n};\n\nexport function isFreeTier(tier: PricingTier): boolean {\n return tier.monthly?.amount === 0 && tier.yearly === null && tier.oneTime === null;\n}\n\nexport function isOneTimeTier(tier: PricingTier): boolean {\n return tier.oneTime !== null && tier.monthly === null;\n}\n\nexport function hasYearly(tier: PricingTier): boolean {\n return tier.yearly !== null && tier.monthly !== null;\n}\n\n/**\n * Resolves all CTA fields for a tier — label, primary href, per-interval\n * hrefs (so a UI toggle can hot-swap without re-deriving), and disabled\n * state for coming-soon plans. Replaces hand-rolled if/else trees in\n * landing pages.\n */\nexport function getCtaProps(tier: PricingTier, opts: CtaOptions): CtaProps {\n const meta = opts.tierMeta;\n const monthlyHref = tier.monthly\n ? checkoutUrl(opts.billingBaseUrl, opts.productKey, tier.monthly.planKey)\n : null;\n const yearlyHref = tier.yearly\n ? checkoutUrl(opts.billingBaseUrl, opts.productKey, tier.yearly.planKey)\n : null;\n const oneTimeHref = tier.oneTime\n ? checkoutUrl(opts.billingBaseUrl, opts.productKey, tier.oneTime.planKey)\n : null;\n\n if (tier.isComingSoon) {\n return {\n label: opts.comingSoonLabel ?? 'Coming soon',\n href: null,\n disabled: true,\n monthlyHref,\n yearlyHref,\n oneTimeHref,\n };\n }\n\n if (meta?.ctaHref) {\n return {\n label: meta.ctaLabel ?? 'Get started',\n href: meta.ctaHref,\n disabled: false,\n monthlyHref,\n yearlyHref,\n oneTimeHref,\n };\n }\n\n let primary: string | null;\n let defaultLabel: string;\n\n if (isFreeTier(tier)) {\n primary = null;\n defaultLabel = opts.freeLabel ?? 'Get started';\n } else if (isOneTimeTier(tier)) {\n primary = oneTimeHref;\n defaultLabel = opts.buyLabel ?? 'Buy';\n } else {\n primary = opts.interval === 'yearly' ? yearlyHref ?? monthlyHref : monthlyHref;\n defaultLabel = opts.subscribeLabel ?? 'Subscribe';\n }\n\n return {\n label: meta?.ctaLabel ?? defaultLabel,\n href: primary,\n disabled: false,\n monthlyHref,\n yearlyHref,\n oneTimeHref,\n };\n}\n\nexport type FormattedPrice = {\n amount: string;\n suffix: string;\n raw: { amount: number; currency: string } | null;\n note?: string;\n};\n\n/**\n * Returns the price + suffix to render for a tier given the active\n * interval. Falls back gracefully: a tier with only monthly always\n * shows monthly; a free tier shows €0; a one-time tier shows the amount\n * with a 'one-time' suffix.\n */\nexport function getActivePrice(tier: PricingTier, interval: IntervalKey): FormattedPrice {\n if (interval === 'yearly' && tier.yearly) {\n return {\n amount: formatPrice(tier.yearly.amount, tier.yearly.currency),\n suffix: '/year',\n raw: { amount: tier.yearly.amount, currency: tier.yearly.currency },\n note: tier.yearly.monthsFree > 0 ? `${tier.yearly.monthsFree} months free` : undefined,\n };\n }\n\n if (interval === 'oneTime' && tier.oneTime) {\n return {\n amount: formatPrice(tier.oneTime.amount, tier.oneTime.currency),\n suffix: ' one-time',\n raw: { amount: tier.oneTime.amount, currency: tier.oneTime.currency },\n };\n }\n\n if (tier.monthly) {\n return {\n amount: formatPrice(tier.monthly.amount, tier.monthly.currency),\n suffix: '/month',\n raw: { amount: tier.monthly.amount, currency: tier.monthly.currency },\n };\n }\n\n if (tier.oneTime) {\n return {\n amount: formatPrice(tier.oneTime.amount, tier.oneTime.currency),\n suffix: ' one-time',\n raw: { amount: tier.oneTime.amount, currency: tier.oneTime.currency },\n };\n }\n\n return { amount: '—', suffix: '', raw: null };\n}\n\n/**\n * Picks the natural default interval for a list of tiers: 'yearly' if\n * any tier has a yearly option, else 'monthly'. Useful as the initial\n * state for a billing-interval toggle.\n */\nexport function defaultInterval(tiers: PricingTier[]): IntervalKey {\n if (tiers.some(hasYearly)) return 'monthly';\n if (tiers.every((t) => t.monthly === null && t.oneTime !== null)) return 'oneTime';\n return 'monthly';\n}\n","import { useCallback, useEffect, useMemo, useState } from 'react';\nimport { fetchPricing, type FetchPricingConfig } from './pricing';\nimport { triggerDownload, type DownloadConfig } from './downloads';\nimport { defaultInterval, type IntervalKey } from './helpers';\nimport type { IssuedDownload, PricingPayload, PricingTier } from './types';\n\nexport type UsePricingResult = {\n data: PricingPayload | null;\n error: Error | null;\n isLoading: boolean;\n refresh: () => void;\n};\n\n/**\n * Fetches pricing for a product on mount (and whenever productKey/baseUrl\n * changes). Returns loading + error state plus a manual refresh callback.\n */\nexport function usePricing(config: FetchPricingConfig): UsePricingResult {\n const [data, setData] = useState<PricingPayload | null>(null);\n const [error, setError] = useState<Error | null>(null);\n const [isLoading, setIsLoading] = useState<boolean>(true);\n const [tick, setTick] = useState(0);\n\n useEffect(() => {\n let alive = true;\n setIsLoading(true);\n setError(null);\n\n fetchPricing(config)\n .then((p) => {\n if (alive) setData(p);\n })\n .catch((e: unknown) => {\n if (alive) setError(e instanceof Error ? e : new Error(String(e)));\n })\n .finally(() => {\n if (alive) setIsLoading(false);\n });\n\n return () => {\n alive = false;\n };\n }, [config.baseUrl, config.productKey, config.yearlyMonthsFree, tick]);\n\n const refresh = useCallback(() => setTick((t) => t + 1), []);\n\n return { data, error, isLoading, refresh };\n}\n\nexport type UseBillingIntervalResult = {\n interval: IntervalKey;\n setInterval: (next: IntervalKey) => void;\n toggle: () => void;\n};\n\n/**\n * Local state for a monthly/yearly billing toggle. Default is derived\n * from the tier list (yearly when any tier has one, else monthly).\n */\nexport function useBillingInterval(tiers: PricingTier[] | null | undefined): UseBillingIntervalResult {\n const initial = useMemo(() => defaultInterval(tiers ?? []), [tiers]);\n const [interval, setInterval] = useState<IntervalKey>(initial);\n\n useEffect(() => {\n setInterval(initial);\n }, [initial]);\n\n const toggle = useCallback(\n () => setInterval((cur) => (cur === 'monthly' ? 'yearly' : 'monthly')),\n [],\n );\n\n return { interval, setInterval, toggle };\n}\n\nexport type UseDownloadResult = {\n trigger: () => Promise<void>;\n isPending: boolean;\n error: Error | null;\n lastIssued: IssuedDownload | null;\n};\n\n/**\n * Returns a memoized download trigger plus pending/error state for the\n * click handler. Wraps triggerDownload() under the hood.\n */\nexport function useDownload(config: DownloadConfig): UseDownloadResult {\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [lastIssued, setLastIssued] = useState<IssuedDownload | null>(null);\n\n const trigger = useCallback(async () => {\n setIsPending(true);\n setError(null);\n try {\n const issued = await triggerDownload(config);\n setLastIssued(issued);\n } catch (e: unknown) {\n setError(e instanceof Error ? e : new Error(String(e)));\n } finally {\n setIsPending(false);\n }\n }, [\n config.baseUrl,\n config.product,\n config.channel,\n config.platform,\n config.beaconDelayMs,\n JSON.stringify(config.query ?? {}),\n ]);\n\n return { trigger, isPending, error, lastIssued };\n}\n"]}
|
package/dist/react.d.cts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { FetchPricingConfig } from './pricing.cjs';
|
|
2
|
+
import { DownloadConfig } from './downloads.cjs';
|
|
3
|
+
import { IntervalKey } from './helpers.cjs';
|
|
4
|
+
import { I as IssuedDownload, a as PricingPayload, b as PricingTier } from './types-CH4Vkivj.cjs';
|
|
5
|
+
|
|
6
|
+
type UsePricingResult = {
|
|
7
|
+
data: PricingPayload | null;
|
|
8
|
+
error: Error | null;
|
|
9
|
+
isLoading: boolean;
|
|
10
|
+
refresh: () => void;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Fetches pricing for a product on mount (and whenever productKey/baseUrl
|
|
14
|
+
* changes). Returns loading + error state plus a manual refresh callback.
|
|
15
|
+
*/
|
|
16
|
+
declare function usePricing(config: FetchPricingConfig): UsePricingResult;
|
|
17
|
+
type UseBillingIntervalResult = {
|
|
18
|
+
interval: IntervalKey;
|
|
19
|
+
setInterval: (next: IntervalKey) => void;
|
|
20
|
+
toggle: () => void;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Local state for a monthly/yearly billing toggle. Default is derived
|
|
24
|
+
* from the tier list (yearly when any tier has one, else monthly).
|
|
25
|
+
*/
|
|
26
|
+
declare function useBillingInterval(tiers: PricingTier[] | null | undefined): UseBillingIntervalResult;
|
|
27
|
+
type UseDownloadResult = {
|
|
28
|
+
trigger: () => Promise<void>;
|
|
29
|
+
isPending: boolean;
|
|
30
|
+
error: Error | null;
|
|
31
|
+
lastIssued: IssuedDownload | null;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Returns a memoized download trigger plus pending/error state for the
|
|
35
|
+
* click handler. Wraps triggerDownload() under the hood.
|
|
36
|
+
*/
|
|
37
|
+
declare function useDownload(config: DownloadConfig): UseDownloadResult;
|
|
38
|
+
|
|
39
|
+
export { type UseBillingIntervalResult, type UseDownloadResult, type UsePricingResult, useBillingInterval, useDownload, usePricing };
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { FetchPricingConfig } from './pricing.js';
|
|
2
|
+
import { DownloadConfig } from './downloads.js';
|
|
3
|
+
import { IntervalKey } from './helpers.js';
|
|
4
|
+
import { I as IssuedDownload, a as PricingPayload, b as PricingTier } from './types-CH4Vkivj.js';
|
|
5
|
+
|
|
6
|
+
type UsePricingResult = {
|
|
7
|
+
data: PricingPayload | null;
|
|
8
|
+
error: Error | null;
|
|
9
|
+
isLoading: boolean;
|
|
10
|
+
refresh: () => void;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Fetches pricing for a product on mount (and whenever productKey/baseUrl
|
|
14
|
+
* changes). Returns loading + error state plus a manual refresh callback.
|
|
15
|
+
*/
|
|
16
|
+
declare function usePricing(config: FetchPricingConfig): UsePricingResult;
|
|
17
|
+
type UseBillingIntervalResult = {
|
|
18
|
+
interval: IntervalKey;
|
|
19
|
+
setInterval: (next: IntervalKey) => void;
|
|
20
|
+
toggle: () => void;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Local state for a monthly/yearly billing toggle. Default is derived
|
|
24
|
+
* from the tier list (yearly when any tier has one, else monthly).
|
|
25
|
+
*/
|
|
26
|
+
declare function useBillingInterval(tiers: PricingTier[] | null | undefined): UseBillingIntervalResult;
|
|
27
|
+
type UseDownloadResult = {
|
|
28
|
+
trigger: () => Promise<void>;
|
|
29
|
+
isPending: boolean;
|
|
30
|
+
error: Error | null;
|
|
31
|
+
lastIssued: IssuedDownload | null;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Returns a memoized download trigger plus pending/error state for the
|
|
35
|
+
* click handler. Wraps triggerDownload() under the hood.
|
|
36
|
+
*/
|
|
37
|
+
declare function useDownload(config: DownloadConfig): UseDownloadResult;
|
|
38
|
+
|
|
39
|
+
export { type UseBillingIntervalResult, type UseDownloadResult, type UsePricingResult, useBillingInterval, useDownload, usePricing };
|