| |
| |
| |
| |
|
|
| type FeatureFlagValue = boolean | "rollout" | "experiment"; |
|
|
| interface FeatureFlagConfig { |
| enabled: boolean; |
| rolloutPercentage?: number; |
| users?: string[]; |
| excludeUsers?: string[]; |
| experimentGroup?: "control" | "treatment"; |
| } |
|
|
| const FEATURE_FLAGS: Record<string, FeatureFlagConfig> = { |
| |
| emailNotifications: { |
| enabled: true, |
| }, |
| twoFactorAuth: { |
| enabled: false, |
| rolloutPercentage: 10, |
| }, |
| advancedAnalytics: { |
| enabled: true, |
| rolloutPercentage: 100, |
| }, |
| aiPoweredSuggestions: { |
| enabled: false, |
| rolloutPercentage: 5, |
| }, |
| customWhiteListing: { |
| enabled: true, |
| rolloutPercentage: 100, |
| }, |
|
|
| |
| newDashboardUI: { |
| enabled: false, |
| rolloutPercentage: 20, |
| experimentGroup: "treatment", |
| }, |
| betaWorkflowBuilder: { |
| enabled: false, |
| rolloutPercentage: 15, |
| experimentGroup: "treatment", |
| }, |
|
|
| |
| adminPanel: { |
| enabled: true, |
| users: ["admin@example.com"], |
| }, |
| }; |
|
|
| |
| |
| |
| export function isFeatureEnabled( |
| featureName: string, |
| userId?: string, |
| userEmail?: string |
| ): boolean { |
| const flag = FEATURE_FLAGS[featureName]; |
|
|
| if (!flag || !flag.enabled) { |
| return false; |
| } |
|
|
| |
| if (flag.users && flag.users.length > 0) { |
| const isWhitelisted = flag.users.includes(userEmail || userId || ""); |
| if (!isWhitelisted) { |
| return false; |
| } |
| } |
|
|
| |
| if (flag.excludeUsers && flag.excludeUsers.length > 0) { |
| const isBlacklisted = flag.excludeUsers.includes(userEmail || userId || ""); |
| if (isBlacklisted) { |
| return false; |
| } |
| } |
|
|
| |
| if (flag.rolloutPercentage !== undefined && flag.rolloutPercentage < 100) { |
| const hash = hashUserId(userId || userEmail || ""); |
| return (hash % 100) < flag.rolloutPercentage; |
| } |
|
|
| return true; |
| } |
|
|
| |
| |
| |
| export function getExperimentGroup( |
| featureName: string, |
| userId?: string |
| ): "control" | "treatment" | null { |
| const flag = FEATURE_FLAGS[featureName]; |
|
|
| if (!flag || !flag.experimentGroup) { |
| return null; |
| } |
|
|
| |
| const hash = hashUserId(userId || ""); |
| return hash % 2 === 0 ? "control" : "treatment"; |
| } |
|
|
| |
| |
| |
| export function getEnabledFeatures(userId?: string): string[] { |
| return Object.keys(FEATURE_FLAGS).filter((featureName) => |
| isFeatureEnabled(featureName, userId) |
| ); |
| } |
|
|
| |
| |
| |
| function hashUserId(userId: string): number { |
| let hash = 0; |
| for (let i = 0; i < userId.length; i++) { |
| const char = userId.charCodeAt(i); |
| hash = (hash << 5) - hash + char; |
| hash = hash & hash; |
| } |
| return Math.abs(hash); |
| } |
|
|
| |
| |
| |
| export function updateFeatureFlag( |
| featureName: string, |
| config: Partial<FeatureFlagConfig> |
| ): void { |
| if (FEATURE_FLAGS[featureName]) { |
| FEATURE_FLAGS[featureName] = { |
| ...FEATURE_FLAGS[featureName], |
| ...config, |
| }; |
| } else { |
| FEATURE_FLAGS[featureName] = config as FeatureFlagConfig; |
| } |
| } |
|
|
| |
| |
| |
| export function getAllFeatureFlags(): Record<string, FeatureFlagConfig> { |
| return { ...FEATURE_FLAGS }; |
| } |
|
|
| |
| |
| |
| export function resetFeatureFlags(): void { |
| Object.keys(FEATURE_FLAGS).forEach((key) => { |
| delete FEATURE_FLAGS[key]; |
| }); |
|
|
| |
| Object.assign(FEATURE_FLAGS, { |
| emailNotifications: { enabled: true }, |
| twoFactorAuth: { enabled: false, rolloutPercentage: 10 }, |
| advancedAnalytics: { enabled: true, rolloutPercentage: 100 }, |
| }); |
| } |
|
|