Initial commit of Descrybe v2 without local scratch artifacts.
Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* 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<string>; starterOff?: ReadonlySet<string>; legacyAllow?: ReadonlySet<string> }
|
||||
): 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;
|
||||
}
|
||||
Reference in New Issue
Block a user