Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/openstatusHQ/openstatus. ๐ซ Status page with uptime monitoring & API monitoring as code ๐ซ openstatus.dev
bun drizzle-orm monitoring monitoring-as-code nextjs observability on-call open-source shadcn-ui status-page statuspage synthetic-monitoring tinybird turso uptime uptime-checker uptime-monitor
Something went wrong. Try again.
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361// Shamelessly stolen from dub.co
import type { WorkspacePlan } from "@openstatus/db/src/schema";import { allPlans } from "@openstatus/db/src/schema/plan/config";import type { Addons, BillingInterval, Limits,} from "@openstatus/db/src/schema/plan/schema";import { getAddonMaxQuantity, getAddonPackSize, getLimits, updateAddonInLimits,} from "@openstatus/db/src/schema/plan/utils";import type Stripe from "stripe";
type PriceIds = { priceIds: { test: string; production: string } };
/** * Rebuild a workspace's limits from the full set of subscription line items. * The plan item sets the baseline; each addon item then re-applies its flag or * quantity on top, so purchased addons survive subscription updates instead of * being reset to the plan default. Returns null when no plan item is present. * Throws on a line item whose price is neither a known plan nor a known addon, * so misconfigured prices surface instead of silently drifting from billing. */export function buildLimitsFromSubscription( subscription: Stripe.Subscription,): { plan: WorkspacePlan; limits: Limits } | null { const detectedPlan = subscription.items.data .map((item) => getPlanFromPriceId(item.price.id)) .find((plan) => plan !== undefined);
if (!detectedPlan) return null;
let limits: Limits = getLimits(detectedPlan.plan);
for (const item of subscription.items.data) { if (getPlanFromPriceId(item.price.id)) continue; const feature = getFeatureFromPriceId(item.price.id); if (!feature) { throw new Error( `Unsupported Stripe price on subscription: ${item.price.id}`, ); } // Accumulate onto the running value so repeated addon items add up; boolean // addons just flip on. One unit of a pack addon grants `packSize` units. const current = limits[feature.feature]; const value = typeof current === "number" ? current + (item.quantity ?? 1) * getAddonPackSize(feature.feature) : true; limits = updateAddonInLimits(limits, feature.feature, value); }
return { plan: detectedPlan.plan, limits };}
/** * Resolve a requested pack count into the Stripe subscription quantity and the * workspace limit it produces. Throws when the request is not a whole number of * packs or exceeds the self-serve ceiling. */export function resolveAddonQuantity(args: { addon: keyof Addons; plan: WorkspacePlan; packs: number;}): { quantity: number; newLimit: number; packSize: number; maxPacks: number | null;} { const { addon, plan, packs } = args; const packSize = getAddonPackSize(addon); const maxPacks = getAddonMaxQuantity(addon);
if (!Number.isInteger(packs) || packs < 0) { throw new Error( `Quantity must be a whole number of packs, received ${packs}`, ); }
if (maxPacks !== null && packs > maxPacks) { throw new Error( `You can add up to ${maxPacks * packSize} with this add-on. Contact us for more.`, ); }
const planDefault = allPlans[plan].limits[addon]; if (typeof planDefault !== "number") { throw new Error(`${addon} is not a quantity add-on`); }
return { quantity: packs, newLimit: planDefault + packs * packSize, packSize, maxPacks, };}
export const getPlanFromPriceId = (priceId: string) => { const env = process.env.NEXT_PUBLIC_VERCEL_ENV === "production" ? "production" : "test"; return PLANS.find( (plan) => plan.price.monthly.priceIds[env] === priceId || plan.price.yearly.priceIds[env] === priceId, );};
export const getFeatureFromPriceId = (priceId: string) => { const env = process.env.NEXT_PUBLIC_VERCEL_ENV === "production" ? "production" : "test"; return FEATURES.find((feature) => Object.values(feature.price).some((p) => p.priceIds[env] === priceId), );};
export const getPriceIdForPlan = ( plan: WorkspacePlan, interval: BillingInterval = "monthly",) => { const env = process.env.NEXT_PUBLIC_VERCEL_ENV === "production" ? "production" : "test"; return PLANS.find((p) => p.plan === plan)?.price[interval].priceIds[env];};
export const getPriceIdForFeature = ( feature: keyof Addons, interval: BillingInterval = "monthly",) => { const env = process.env.NEXT_PUBLIC_VERCEL_ENV === "production" ? "production" : "test"; return FEATURES.find((f) => f.feature === feature)?.price[interval].priceIds[ env ];};
/** * The item list for a plan or interval change. Every item already on the * subscription is listed by id so Stripe re-prices it in place instead of * dropping it: the plan item takes the new plan price, and each addon moves to * its price for the target interval with its quantity kept โ Stripe rejects * mixed intervals on one subscription, so a yearly plan takes yearly addons. * Throws on an addon item whose price is unknown rather than dropping it. */export function buildPlanChangeItems(args: { subscription: Stripe.Subscription; planItemId: string; planPriceId: string; interval: BillingInterval;}): Stripe.SubscriptionUpdateParams.Item[] { const { subscription, planItemId, planPriceId, interval } = args; return subscription.items.data.map((item) => { if (item.id === planItemId) return { id: item.id, price: planPriceId }; const feature = getFeatureFromPriceId(item.price.id); const price = feature ? getPriceIdForFeature(feature.feature, interval) : undefined; if (!price) { throw new Error( `Unsupported Stripe price on subscription: ${item.price.id}`, ); } return { id: item.id, price, quantity: item.quantity ?? 1 }; });}
export const PLANS = [ { plan: "team", price: { monthly: { priceIds: { test: "price_1UJ8dWBXJcTfzsyJYUgMY5Z5", production: "price_1RxsLNBXJcTfzsyJ7La5Jn5y", }, }, yearly: { priceIds: { test: "price_1UJ8dcBXJcTfzsyJYKursvVr", production: "price_1TDlHxBXJcTfzsyJygJw92nU", }, }, }, }, { plan: "starter", price: { monthly: { priceIds: { test: "price_1UJ8dVBXJcTfzsyJcZsQ2AuH", production: "price_1RxsJzBXJcTfzsyJBOztaKlR", }, }, yearly: { priceIds: { test: "price_1UJ8daBXJcTfzsyJXf50tUL5", production: "price_1TDlGSBXJcTfzsyJMsDV4DRQ", }, }, }, }, { plan: "scale", price: { monthly: { priceIds: { test: "price_1UJ8deBXJcTfzsyJauf9uGPO", production: "price_1Te9BLBXJcTfzsyJlXLsuyFP", }, }, yearly: { priceIds: { test: "price_1UJ8dfBXJcTfzsyJy8Hm8aha", production: "price_1Te9BLBXJcTfzsyJliabl2ou", }, }, }, },] satisfies Array<{ plan: WorkspacePlan; price: { monthly: { priceIds: { test: string; production: string } }; yearly: { priceIds: { test: string; production: string } }; };}>;
export const FEATURES = [ { feature: "email-domain-protection", price: { monthly: { priceIds: { test: "price_1UJ8dXBXJcTfzsyJdd7OVDe7", production: "price_1Sl6oqBXJcTfzsyJCxtzDIx5", }, }, yearly: { priceIds: { test: "price_1UJ8dsBXJcTfzsyJSnyEZXOi", production: "price_1UJ7bhBXJcTfzsyJhHuuQjr2", }, }, }, }, { feature: "ip-restriction", price: { monthly: { priceIds: { test: "price_1UJ8ddBXJcTfzsyJNffp8pmE", production: "price_1TMpxlBXJcTfzsyJ1woQtafW", }, }, yearly: { priceIds: { test: "price_1UJ8drBXJcTfzsyJED62IVFg", production: "price_1UJ7akBXJcTfzsyJzDrC8hdK", }, }, }, }, { feature: "white-label", price: { monthly: { priceIds: { test: "price_1UJ8dYBXJcTfzsyJXQx2FMhh", production: "price_1SlbSdBXJcTfzsyJahJiFE8D", }, }, yearly: { priceIds: { test: "price_1UJ8dmBXJcTfzsyJdmH60moK", production: "price_1UJ74MBXJcTfzsyJ17ksU7wm", }, }, }, }, { feature: "custom-theme", price: { monthly: { priceIds: { test: "price_1UJ8dhBXJcTfzsyJcw93020n", production: "price_1Tvv0zBXJcTfzsyJseLIjNnz", }, }, yearly: { priceIds: { test: "price_1UJ8dnBXJcTfzsyJmLIOAGEa", production: "price_1UJ76GBXJcTfzsyJ6BGJ3ZJd", }, }, }, }, { feature: "status-pages", price: { monthly: { priceIds: { test: "price_1UJ8dZBXJcTfzsyJYZ1An6s1", production: "price_1SlrkHBXJcTfzsyJIxHeKUYe", }, }, yearly: { priceIds: { test: "price_1UJ8dlBXJcTfzsyJ386lE7yh", production: "price_1UJ70tBXJcTfzsyJRDDnbXcP", }, }, }, }, { feature: "monitors", price: { monthly: { priceIds: { test: "price_1UJ8dkBXJcTfzsyJEZUYk2ji", production: "price_1UChsCBXJcTfzsyJgomhUtYY", }, }, yearly: { priceIds: { test: "price_1UJ8doBXJcTfzsyJLyp84Hof", production: "price_1UJ7YkBXJcTfzsyJdklvON8r", }, }, }, }, { feature: "sso", price: { monthly: { priceIds: { test: "price_1UJ8djBXJcTfzsyJ8I9r51Nz", production: "price_1TySGYBXJcTfzsyJQFVFJi6N", }, }, yearly: { priceIds: { test: "price_1UJ8dqBXJcTfzsyJFfAEZuZk", production: "price_1UJ7ZcBXJcTfzsyJ78fA9RFp", }, }, }, },] satisfies Array<{ feature: keyof Addons; // Stripe rejects mixed intervals on one subscription, so every addon needs a // price on each interval a plan is sold on. price: { monthly: PriceIds; yearly: PriceIds; };}>;