@better-auth-ui/core
Version:
Authentication components and data utilities for [Better Auth](https://better-auth.com), available for React and Solid.
548 lines (547 loc) • 15.8 kB
JavaScript
import { t as e } from "../../create-auth-plugin-BXWyolC8.js";
import { skipToken as t } from "@tanstack/query-core";
//#region src/plugins/billing/billing-adapter.ts
var n = (e) => e.type === "user" ? `user:${e.userId}` : `organization:${e.organizationId}:${e.organizationSlug}`;
function r(e) {
if (!(!e.url || typeof window > "u")) try {
let t = new URL(e.url, window.location.href);
(t.protocol === "http:" || t.protocol === "https:") && window.location.assign(t.href);
} catch {}
}
//#endregion
//#region src/plugins/billing/billing-localization.ts
var i = {
billing: "Billing",
billingDescription: "Manage plans, subscription details, seats, and usage.",
plans: "Plans",
currentPlan: "Current plan",
choosePlan: "Choose plan",
changePlan: "Change plan",
perMonth: "per month",
perYear: "per year",
oneTime: "one time",
popular: "Popular",
subscription: "Subscription",
noSubscription: "No active subscription",
noSubscriptionDescription: "Choose a plan to start a subscription.",
manageBilling: "Manage billing",
renewsOn: "Renews on {{date}}",
endsOn: "Ends on {{date}}",
cancelSubscription: "Cancel subscription",
cancelSubscriptionTitle: "Cancel subscription?",
cancelSubscriptionDescription: "Your access remains available until the end of the current billing period.",
restoreSubscription: "Restore subscription",
restoreSubscriptionTitle: "Restore subscription?",
restoreSubscriptionDescription: "Your subscription will continue renewing on its current plan.",
confirm: "Confirm",
cancel: "Cancel",
seats: "Seats",
updateSeats: "Update seats",
usage: "Usage",
unlimited: "Unlimited",
used: "{{used}} used",
loadingBilling: "Loading billing information"
}, a = {
all: ["auth", "billing"],
scope: (e) => [...a.all, n(e)],
plans: (e) => [...a.scope(e), "plans"],
state: (e) => [...a.scope(e), "state"]
}, o = (e, n) => ({
queryKey: n ? a.plans(n) : [
...a.all,
null,
"plans"
],
queryFn: n ? ({ signal: t }) => e.listPlans(n, t) : t
}), s = (e, n) => ({
queryKey: n ? a.state(n) : [
...a.all,
null,
"state"
],
queryFn: n ? ({ signal: t }) => e.getState(n, t) : t
}), c = {
all: ["auth", "billing"],
checkout: (e) => [
...c.all,
n(e),
"checkout"
],
portal: (e) => [
...c.all,
n(e),
"portal"
],
cancel: (e) => [
...c.all,
n(e),
"cancel"
],
restore: (e) => [
...c.all,
n(e),
"restore"
],
seats: (e) => [
...c.all,
n(e),
"seats"
]
}, l = (e) => ({ awaits: [a.state(e)] }), u = (e, t) => ({
mutationKey: c.checkout(t),
mutationFn: (n) => e.checkout(t, n),
meta: l(t)
}), d = (e, t) => ({
mutationKey: c.portal(t),
mutationFn: () => e.openPortal(t)
}), f = (e, t) => ({
mutationKey: c.cancel(t),
mutationFn: (n) => e.cancel(t, n),
meta: l(t)
}), p = (e, t) => ({
mutationKey: c.restore(t),
mutationFn: (n) => e.restore(t, n),
meta: l(t)
}), m = (e, t) => ({
mutationKey: c.seats(t),
mutationFn: ({ subscriptionId: n, seats: r }) => e.updateSeats(t, n, r),
meta: l(t)
}), h = e("billing", (e) => {
let t = e.user ?? !0, n = e.organization ?? !1;
if (t && e.adapter.scopes?.user === !1) throw Error(`${e.adapter.id} does not support user billing.`);
if (n && e.adapter.scopes?.organization === !1) throw Error(`${e.adapter.id} does not support explicit organization billing.`);
return {
adapter: e.adapter,
localization: {
...i,
...e.localization
},
user: t,
organization: n,
viewPaths: { settings: { billing: e.path ?? "billing" } }
};
}), g = (e) => e && typeof e == "object" ? e : void 0, _ = (e) => {
let t = g(e), n = t?.error;
if (n) {
let e = g(n);
throw Error(String(e?.message ?? n));
}
return t && "data" in t ? t.data : e;
}, v = (e) => {
let t = _(e);
if (Array.isArray(t)) return t;
let n = g(t), r = n?.items ?? g(n?.result)?.items;
return Array.isArray(r) ? r : [];
}, y = (e) => typeof e == "string" ? e : void 0, b = (e) => typeof e == "number" && Number.isFinite(e) ? e : void 0, x = (e) => {
if (!e) return;
let t = new Date(e);
return Number.isNaN(t.getTime()) ? void 0 : t;
}, S = (e) => {
let t = y(e);
return t === "cancelled" ? "canceled" : t === "scheduled_cancel" ? "active" : t === "active" || t === "trialing" || t === "past_due" || t === "paused" || t === "canceled" || t === "incomplete" ? t : "unknown";
}, C = (e) => {
let t = y(e);
if (t === "month" || t === "monthly") return "month";
if (t === "year" || t === "yearly" || t === "annual") return "year";
if (t === "one-time" || t === "one_time") return "one-time";
}, w = (e) => {
let t = g(e), n = y(t?.id) ?? y(t?.subscriptionId) ?? y(t?.subscription_id) ?? y(t?.creemSubscriptionId);
if (!t || !n) return;
let r = g(t.product), i = g(t.plan), a = g(t.price) ?? g(i?.price), o = g(t.currentPeriod), s = t.canceledAt ?? t.canceled_at ?? t.cancelledAt ?? t.cancelled_at;
return {
id: n,
planId: y(t.planId) ?? y(t.plan) ?? y(t.productId) ?? y(t.product_id) ?? y(r?.id) ?? y(i?.id) ?? "unknown",
planName: y(t.planName) ?? y(r?.name) ?? y(i?.name) ?? y(t.name),
priceId: y(t.priceId) ?? y(t.price_id) ?? y(a?.id),
interval: C(t.interval ?? t.billingInterval ?? t.recurringInterval ?? t.recurring_interval ?? a?.interval) ?? (typeof t.annual == "boolean" ? t.annual ? "year" : "month" : void 0),
status: S(t.status),
currentPeriodEnd: x(t.currentPeriodEnd ?? t.current_period_end ?? t.currentPeriodEndDate ?? t.current_period_end_date ?? t.periodEnd ?? t.period_end ?? t.nextBillingDate ?? t.next_billing_date ?? o?.end),
cancelAtPeriodEnd: !!(t.cancelAtPeriodEnd ?? t.cancel_at_period_end ?? t.cancelAtNextBillingDate ?? t.cancel_at_next_billing_date ?? t.status === "scheduled_cancel"),
canceledAt: x(s),
seats: b(t.seats) ?? b(t.quantity) ?? b(t.units)
};
}, T = (e) => {
let t = g(e), n = g(t?.meter), r = y(t?.id) ?? y(n?.id);
if (!t || !r) return;
let i = b(t.consumedUnits) ?? b(t.consumed_units) ?? b(t.used) ?? 0, a = b(t.creditedUnits) ?? b(t.credited_units) ?? b(t.limit);
return {
id: r,
label: y(t.label) ?? y(n?.name) ?? y(n?.slug) ?? r,
used: i,
limit: a,
unit: y(t.unit) ?? y(n?.unit)
};
}, E = (e) => {
let t = g(_(e));
return { url: y(t?.url ?? t?.paymentUrl ?? t?.redirectUrl ?? t?.redirect_url ?? t?.customerPortalUrl) };
}, D = (e, t) => {
if (e.type === "organization") throw Error(`${t} does not accept an explicit organization ID in its Better Auth client API.`);
}, O = (e, t) => Object.entries(t ?? {}).find(([, t]) => t === e)?.[0] ?? e, k = (e) => Object.entries(g(e.balances) ?? {}).map(([e, t]) => {
let n = g(t), r = g(n?.feature), i = n?.unlimited === !0;
return {
id: e,
label: y(r?.name) ?? e,
used: b(n?.usage) ?? 0,
limit: i ? void 0 : b(n?.granted),
unit: y(r?.displayName) ?? y(r?.name)
};
}), A = (e) => {
let t = g(e), n = g(t?.consumption), r = y(t?.code), i = b(n?.unitsUsed);
if (!(!r || i === void 0)) return {
id: r,
label: y(t?.name) ?? r,
used: i,
limit: n?.unlimited === !0 ? void 0 : b(n?.includedUnits),
unit: y(t?.unitName)
};
}, j = (e) => ({
referenceId: e.type === "organization" ? e.organizationId : e.userId,
customerType: e.type
});
function M(e, t) {
let n = (e) => t.plans.find((t) => t.id === e), r = async (r, i, a) => {
let o = n(i.planId)?.prices.find((e) => e.id === i.priceId);
return E(await e.subscription.upgrade({
plan: i.planId,
annual: o?.interval === "year",
...j(r),
...a ? { subscriptionId: a } : {},
...i.seats ? { seats: i.seats } : {},
successUrl: t.successUrl,
cancelUrl: t.cancelUrl,
returnUrl: t.returnUrl,
disableRedirect: !0
}));
}, i = async (t, n) => ({
subscription: v(await e.subscription.list({
query: j(t),
fetchOptions: {
signal: n,
throw: !0
}
})).map(w).filter((e) => !!e)[0],
usage: []
});
return {
id: "stripe",
supports: {
cancel: !0,
restore: !0,
seats: !0
},
async listPlans() {
return t.plans;
},
getState: i,
checkout: (e, t) => r(e, t),
async openPortal(n) {
return E(await e.subscription.billingPortal({
...j(n),
returnUrl: t.returnUrl,
disableRedirect: !0
}));
},
async cancel(n, r) {
return E(await e.subscription.cancel({
...j(n),
subscriptionId: r,
returnUrl: t.returnUrl,
disableRedirect: !0
}));
},
async restore(t, n) {
return E(await e.subscription.restore({
...j(t),
subscriptionId: n
}));
},
async updateSeats(e, t, a) {
let o = (await i(e)).subscription, s = o?.planId, c = s ? n(s) : void 0, l = o?.priceId ? c?.prices.find((e) => e.id === o.priceId) : o?.interval ? c?.prices.find((e) => e.interval === o.interval) : c?.prices.length === 1 ? c.prices[0] : void 0;
if (!c || !l) throw Error("The current billing price is unavailable.");
return r(e, {
planId: c.id,
priceId: l.id,
seats: a
}, t);
}
};
}
function N(e, t) {
let n = (e) => Object.entries(t.products ?? {}).find(([, t]) => t.value === e)?.[0] ?? e, r = async (t) => E(await e.customer.portal({ fetchOptions: { throw: !0 } }));
return {
id: "polar",
supports: {
cancel: !1,
restore: !1,
seats: !1
},
async listPlans() {
return t.plans;
},
async getState(t, r) {
let i = {
page: 1,
limit: 100,
active: !0,
...t.type === "organization" ? { referenceId: t.organizationId } : {}
}, [a, o] = await Promise.all([e.customer.subscriptions.list({
query: i,
fetchOptions: {
signal: r,
throw: !0
}
}), e.usage.meters.list({
query: {
page: 1,
limit: 100
},
fetchOptions: {
signal: r,
throw: !0
}
})]), s = v(a).map(w).find(Boolean);
return {
subscription: s ? {
...s,
planId: n(s.planId)
} : void 0,
usage: v(o).map(T).filter((e) => !!e)
};
},
async checkout(n, r) {
let i = t.products?.[r.planId];
return E(await e.checkout({
...i?.type === "product" ? { products: [i.value] } : { slug: i?.value ?? r.planId },
...n.type === "organization" ? { referenceId: n.organizationId } : {},
...r.seats ? { seats: r.seats } : {},
successUrl: t.successUrl,
redirect: !1
}));
},
openPortal: r,
async cancel(e) {
return r(e);
},
async restore(e) {
return r(e);
},
async updateSeats(e) {
return r(e);
}
};
}
function P(e, t) {
let n = async (t, n) => {
D(t, "Autumn");
let r = g(await e.getOrCreateCustomer({ expand: ["subscriptions.plan", "balances.feature"] }));
return {
subscription: (Array.isArray(r?.subscriptions) ? r.subscriptions : []).map(w).find(Boolean),
usage: r ? k(r) : []
};
}, r = async (t, n) => (D(t, "Autumn"), E(await e.updateSubscription(n)));
return {
id: "autumn",
scopes: {
user: !0,
organization: !1
},
supports: {
cancel: !0,
restore: !0,
seats: !!t.seatLicensePlans
},
async listPlans(e) {
return D(e, "Autumn"), t.plans;
},
getState: n,
async checkout(n, r) {
D(n, "Autumn");
let i = t.seatLicensePlans?.[r.planId];
return E(await e.attach({
planId: r.planId,
successUrl: t.successUrl,
redirectMode: "always",
...i && r.seats ? { licenseQuantities: [{
licensePlanId: i,
quantity: r.seats
}] } : {}
}));
},
async openPortal(n) {
return D(n, "Autumn"), E(await e.openCustomerPortal({ returnUrl: t.returnUrl }));
},
cancel: (e, t) => r(e, {
subscriptionId: t,
cancelAction: "cancel_end_of_cycle"
}),
restore: (e, t) => r(e, {
subscriptionId: t,
cancelAction: "uncancel"
}),
async updateSeats(e, i, a) {
let o = (await n(e)).subscription?.planId, s = o ? t.seatLicensePlans?.[o] : void 0;
if (!s) throw Error("The Autumn seat license plan is unavailable.");
return r(e, {
subscriptionId: i,
licenseQuantities: [{
licensePlanId: s,
quantity: a
}]
});
}
};
}
function F(e, t) {
let n = async (t) => (D(t, "Creem"), E(await e.creem.createPortal()));
return {
id: "creem",
scopes: {
user: !0,
organization: !1
},
supports: {
cancel: !0,
restore: !1,
seats: !1
},
async listPlans(e) {
return D(e, "Creem"), t.plans;
},
async getState(n) {
D(n, "Creem");
let r = w(g(_(await e.creem.hasAccessGranted()))?.subscription);
return {
subscription: r ? {
...r,
planId: O(r.planId, t.products)
} : void 0,
usage: []
};
},
async checkout(n, r) {
return D(n, "Creem"), E(await e.creem.createCheckout({
productId: t.products?.[r.planId] ?? r.planId,
...r.seats ? { units: r.seats } : {},
successUrl: t.successUrl
}));
},
openPortal: n,
async cancel(t, n) {
return D(t, "Creem"), E(await e.creem.cancelSubscription({ id: n }));
},
restore: n,
updateSeats: n
};
}
function I(e, t) {
let n = async (t) => (D(t, "Dodo Payments"), E(await e.dodopayments.customer.portal()));
return {
id: "dodo-payments",
scopes: {
user: !0,
organization: !1
},
supports: {
cancel: !1,
restore: !1,
seats: !1
},
async listPlans(e) {
return D(e, "Dodo Payments"), t.plans;
},
async getState(n, r) {
D(n, "Dodo Payments");
let i = v(await e.dodopayments.customer.subscriptions.list({
query: {
limit: 100,
page: 1
},
fetchOptions: {
signal: r,
throw: !0
}
})).map(w).find(Boolean);
if (!i) return { usage: [] };
let a = i.planId, o = Object.entries(t.products ?? {}).find(([, e]) => e.value === a)?.[0] ?? a;
return {
subscription: {
...i,
planId: o
},
usage: []
};
},
async checkout(n, r) {
D(n, "Dodo Payments");
let i = t.products?.[r.planId];
return E(await e.dodopayments.checkoutSession({
...i?.type === "product" ? { product_cart: [{
product_id: i.value,
quantity: r.seats ?? 1
}] } : { slug: i?.value ?? r.planId },
referenceId: n.type === "user" ? n.userId : n.organizationId
}));
},
openPortal: n,
cancel: n,
restore: n,
updateSeats: n
};
}
function L(e, t) {
let n = async (t) => (D(t, "Commet"), E(await e.customer.portal()));
return {
id: "commet",
scopes: {
user: !0,
organization: !1
},
supports: {
cancel: !0,
restore: !1,
seats: !!t.seatFeatureCode
},
async listPlans(e) {
return D(e, "Commet"), t.plans;
},
async getState(n, r) {
D(n, "Commet");
let [i, a, o] = await Promise.all([
e.subscription.get({
signal: r,
throw: !0
}),
t.usage ? e.features.list({
signal: r,
throw: !0
}) : void 0,
t.seatFeatureCode ? e.seats.list({
signal: r,
throw: !0
}) : void 0
]), s = w(_(i)), c = t.seatFeatureCode ? g(g(_(o))?.[t.seatFeatureCode]) : void 0;
return {
subscription: s ? {
...s,
planId: O(s.planId, t.planIds),
seats: b(c?.current) ?? s.seats
} : void 0,
usage: t.usage ? v(a).map(A).filter((e) => !!e) : []
};
},
checkout: n,
openPortal: n,
async cancel(t) {
return D(t, "Commet"), E(await e.subscription.cancel({ immediate: !1 }, { throw: !0 }));
},
restore: n,
async updateSeats(r, i, a) {
return D(r, "Commet"), t.seatFeatureCode ? E(await e.seats.set({
featureCode: t.seatFeatureCode,
count: a
}, { throw: !0 })) : n(r);
}
};
}
//#endregion
export { u as billingCheckoutOptions, i as billingLocalization, c as billingMutationKeys, o as billingPlansOptions, h as billingPlugin, d as billingPortalOptions, a as billingQueryKeys, n as billingScopeKey, s as billingStateOptions, f as cancelBillingSubscriptionOptions, P as createAutumnBillingAdapter, L as createCommetBillingAdapter, F as createCreemBillingAdapter, I as createDodoPaymentsBillingAdapter, N as createPolarBillingAdapter, M as createStripeBillingAdapter, r as followBillingAction, p as restoreBillingSubscriptionOptions, m as updateBillingSeatsOptions };