/** * Pure plan-cohort classifiers (no $lib) — mirrors billing A1 PAYG vs Legacy vs Growth. * Used by admin-plan-permissions and unit tests. */ export function isLegacyPlanNamePure(name: string | null | undefined): boolean { const n = (name ?? "").trim().toLowerCase(); if (!n) return false; if (n === "legacy") return true; if (n.includes("a1 slovenija")) return true; if (n === "a1" || n.startsWith("a1 ") || n.startsWith("a1-") || n.startsWith("a1_")) return true; return false; } export type PlanCohortFlags = { name: string; is_custom?: boolean; is_legacy?: boolean; }; /** Restricted Legacy matrix (processing off). */ export function isRestrictedLegacyPlan(plan: PlanCohortFlags | null | undefined): boolean { if (!plan) return false; if (plan.is_legacy === true) return true; const n = (plan.name ?? "").trim().toLowerCase(); if (n === "legacy") return true; if (plan.is_custom) return false; return isLegacyPlanNamePure(plan.name); } /** A1* PAYG client deal (processing on; stores/marketing/integrations off). */ export function isA1PaygPlanPure(plan: PlanCohortFlags | null | undefined): boolean { if (!plan) return false; if (plan.is_legacy === true) return false; if (!plan.is_custom) return false; const n = (plan.name ?? "").trim().toLowerCase(); if (n === "legacy") return false; return isLegacyPlanNamePure(plan.name); } export function isA1PaygDeniedKey(key: string): boolean { if ( key === "dashboard.etl_gaps" || key === "dashboard.store_reconnect" || key === "dashboard.migrated_checklist" ) { return true; } return key.startsWith("stores.") || key.startsWith("marketing.") || key.startsWith("integrations."); } /** Resolve whether a feature is ON by default for the named cohort. */ export function defaultAllowsFeature( plan: PlanCohortFlags, key: string, opts?: { freeOff?: ReadonlySet; starterOff?: ReadonlySet; legacyAllow?: ReadonlySet } ): boolean { if (isRestrictedLegacyPlan(plan)) { if (opts?.legacyAllow) return opts.legacyAllow.has(key); // Fallback for audit keys when allowlist not provided. if (key === "processing.monitor" || key.startsWith("stores.") || key.startsWith("marketing.") || key.startsWith("integrations.") || key.startsWith("support.")) { return false; } return true; } if (isA1PaygPlanPure(plan)) { return !isA1PaygDeniedKey(key); } const n = (plan.name ?? "").trim().toLowerCase(); if (n === "free" && opts?.freeOff?.has(key)) return false; if ((n === "starter" || n === "plus") && opts?.starterOff?.has(key)) return false; return true; }