import type { FreeCreditsTier } from './freeCreditsTier.js'; import type { PricingModel } from './pricingModel.js'; export enum BillingPlan { TRIAL = 'TRIAL', /** @deprecated Legacy v1 plan — no longer issued to new organizations. */ FREE = 'FREE', /** @deprecated Legacy v1 plan — no longer issued to new organizations. */ STARTER = 'STARTER', /** @deprecated Legacy v1 plan — no longer issued to new organizations. */ PRO = 'PRO', ENTERPRISE = 'ENTERPRISE', TEAMS = 'TEAMS', POC = 'POC' } const ENTERPRISE_LIKE_PLANS: ReadonlySet = new Set([ BillingPlan.ENTERPRISE, BillingPlan.PRO, BillingPlan.STARTER, BillingPlan.POC ]); const TRIAL_LIKE_PLANS: ReadonlySet = new Set([BillingPlan.TRIAL, BillingPlan.FREE]); /** * Plans entitled to the Policy Gates MVP. The MVP rollout is limited to * enterprise (and POC) orgs, so this is intentionally narrower than * {@link isEnterpriseLikePlan} (which also covers legacy PRO/STARTER). */ const POLICY_GATES_ENTITLED_PLANS: ReadonlySet = new Set([BillingPlan.ENTERPRISE, BillingPlan.POC]); export function isEnterpriseLikePlan(plan: BillingPlan | undefined | null): boolean { return plan != null && ENTERPRISE_LIKE_PLANS.has(plan); } export function isPolicyGatesEntitledPlan(plan: BillingPlan | undefined | null): boolean { return plan != null && POLICY_GATES_ENTITLED_PLANS.has(plan); } export function isTrialLikePlan(plan: BillingPlan | undefined | null): boolean { return plan != null && TRIAL_LIKE_PLANS.has(plan); } export type Billing = { plan: BillingPlan; isExpired: boolean; expiryDate: Date; daysLeft: number; billingInterval?: 'annual' | 'monthly' | null; interval?: 'annual' | 'monthly' | null; cancelAt?: Date | null; stripeSubStatus?: string | null; showCcGateIfTrial?: boolean; /** Set at signup; used for LD targeting (`freeCreditsTier`). */ freeCreditsTier?: FreeCreditsTier; /** Set at signup; `seats` (legacy, default) or `credits` (seatless PLG/GAU pricing). Absent = seat-based. */ pricingModel?: PricingModel; };