{"version":3,"file":"feature-flag-integration.mjs","sources":["../../../src/lib/feature/feature-flag-integration.ts"],"sourcesContent":["/**\n * @file Feature Flag Integration\n * @description Deep integration between features and feature flags\n */\n\nimport { useMemo, useCallback } from 'react';\nimport type { FeatureRegistryEntry, FeatureTab } from './types';\nimport { getAllFeatures, getFeature } from './registry';\nimport { useFeatureFlagsStatus } from '../flags/useFeatureFlag';\nimport { useAuth } from '../auth/useAuth';\nimport { hasFeatureAccess } from './types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Feature visibility state\n */\nexport interface FeatureVisibility {\n  featureId: string;\n  isVisible: boolean;\n  isAccessible: boolean;\n  reason?: 'flag_disabled' | 'insufficient_permissions' | 'not_authenticated' | undefined;\n  tabs: TabVisibility[];\n}\n\n/**\n * Tab visibility state\n */\nexport interface TabVisibility {\n  tabId: string;\n  isVisible: boolean;\n  isAccessible: boolean;\n  reason?: 'flag_disabled' | 'insufficient_permissions' | undefined;\n}\n\n/**\n * Feature flag manifest entry\n */\nexport interface FeatureFlagManifestEntry {\n  flag: string;\n  featureId: string;\n  tabId?: string;\n  description?: string;\n}\n\n// ============================================================================\n// Flag Extraction\n// ============================================================================\n\n/**\n * Extract all feature flags from registered features\n * Returns a unique list of all flags used across features\n */\nexport function extractFeatureFlags(): string[] {\n  const features = getAllFeatures();\n  const flags = new Set<string>();\n\n  for (const feature of features) {\n    const { access, tabs } = feature.config;\n\n    // Main feature flag\n    if (\n      access.featureFlag !== undefined &&\n      access.featureFlag !== null &&\n      access.featureFlag !== ''\n    ) {\n      flags.add(access.featureFlag);\n    }\n\n    // Required flags\n    access.requiredFlags?.forEach((flag) => flags.add(flag));\n\n    // Tab-level flags\n    tabs?.forEach((tab) => {\n      if (tab.access?.featureFlag != null && tab.access.featureFlag.length > 0) {\n        flags.add(tab.access.featureFlag);\n      }\n      tab.access?.requiredFlags?.forEach((flag) => flags.add(flag));\n    });\n  }\n\n  return Array.from(flags).sort();\n}\n\n/**\n * Generate a manifest of all feature flags with their associations\n * Useful for documentation and flag management\n */\nexport function generateFeatureFlagManifest(): FeatureFlagManifestEntry[] {\n  const features = getAllFeatures();\n  const manifest: FeatureFlagManifestEntry[] = [];\n\n  for (const feature of features) {\n    const { metadata, access, tabs } = feature.config;\n\n    // Main feature flag\n    if (access.featureFlag != null && access.featureFlag.length > 0) {\n      manifest.push({\n        flag: access.featureFlag,\n        featureId: metadata.id,\n        description: `Enables the ${metadata.name} feature`,\n      });\n    }\n\n    // Required flags at feature level\n    access.requiredFlags?.forEach((flag) => {\n      manifest.push({\n        flag,\n        featureId: metadata.id,\n        description: `Required for ${metadata.name}`,\n      });\n    });\n\n    // Tab-level flags\n    tabs?.forEach((tab) => {\n      if (tab.access?.featureFlag != null && tab.access.featureFlag.length > 0) {\n        manifest.push({\n          flag: tab.access.featureFlag,\n          featureId: metadata.id,\n          tabId: tab.id,\n          description: `Enables the ${tab.label} tab in ${metadata.name}`,\n        });\n      }\n      tab.access?.requiredFlags?.forEach((flag) => {\n        manifest.push({\n          flag,\n          featureId: metadata.id,\n          tabId: tab.id,\n          description: `Required for ${tab.label} tab in ${metadata.name}`,\n        });\n      });\n    });\n  }\n\n  return manifest;\n}\n\n/**\n * Generate flag keys constant from features\n * Useful for type-safe flag key generation\n */\nexport function generateFeatureFlagKeys(): Record<string, string> {\n  const flags = extractFeatureFlags();\n  const keys: Record<string, string> = {};\n\n  for (const flag of flags) {\n    // Convert flag name to constant key: \"reports_enabled\" -> \"REPORTS_ENABLED\"\n    const key = flag.toUpperCase().replace(/-/g, '_');\n    keys[key] = flag;\n  }\n\n  return keys;\n}\n\n// ============================================================================\n// Visibility Hooks\n// ============================================================================\n\n/**\n * Hook to get visibility status for all features\n */\nexport function useFeatureVisibility(): FeatureVisibility[] {\n  const features = getAllFeatures();\n  const allFlags = extractFeatureFlags();\n  const flagStatus = useFeatureFlagsStatus(allFlags);\n  const { roles, isAuthenticated } = useAuth();\n\n  return useMemo(() => {\n    const enabledFlags = Object.entries(flagStatus)\n      .filter(([, enabled]) => enabled)\n      .map(([flag]) => flag);\n\n    return features.map((feature) => {\n      const { config } = feature;\n      const { access, tabs } = config;\n\n      // Check authentication\n      if (access.requireAuth === true && !isAuthenticated) {\n        return {\n          featureId: config.metadata.id,\n          isVisible: false,\n          isAccessible: false,\n          reason: 'not_authenticated' as const,\n          tabs: [],\n        };\n      }\n\n      // Check main feature visibility (flag enabled)\n      const isVisible =\n        access.featureFlag == null || access.featureFlag === '' || flagStatus[access.featureFlag] === true;\n\n      // Check main feature access (roles/permissions)\n      const isAccessible = hasFeatureAccess(access, roles, enabledFlags);\n\n      // Determine reason for inaccessibility\n      let reason: FeatureVisibility['reason'];\n      if (!isVisible) {\n        reason = 'flag_disabled';\n      } else if (!isAccessible) {\n        reason = 'insufficient_permissions';\n      }\n\n      // Check tab access\n      const tabVisibility: TabVisibility[] = (tabs ?? []).map((tab) => {\n        const tabVisible =\n          tab.access?.featureFlag == null ||\n          tab.access?.featureFlag === '' ||\n          flagStatus[tab.access.featureFlag] === true;\n\n        const tabAccessible = tab.access\n          ? hasFeatureAccess(tab.access, roles, enabledFlags)\n          : isAccessible;\n\n        let tabReason: TabVisibility['reason'];\n        if (!tabVisible) {\n          tabReason = 'flag_disabled';\n        } else if (!tabAccessible) {\n          tabReason = 'insufficient_permissions';\n        }\n\n        return {\n          tabId: tab.id,\n          isVisible: tabVisible,\n          isAccessible: tabAccessible,\n          reason: tabReason,\n        };\n      });\n\n      return {\n        featureId: config.metadata.id,\n        isVisible,\n        isAccessible,\n        reason,\n        tabs: tabVisibility,\n      };\n    });\n  }, [features, flagStatus, roles, isAuthenticated]);\n}\n\n/**\n * Hook to get only accessible features (visible AND accessible)\n */\nexport function useAccessibleFeatures(): FeatureRegistryEntry[] {\n  const features = getAllFeatures();\n  const visibility = useFeatureVisibility();\n\n  return useMemo(() => {\n    const accessibleIds = new Set(\n      visibility.filter((v) => v.isVisible && v.isAccessible).map((v) => v.featureId)\n    );\n\n    return features.filter((f) => accessibleIds.has(f.config.metadata.id));\n  }, [features, visibility]);\n}\n\n/**\n * Hook to get only visible features (flag enabled, regardless of permissions)\n */\nexport function useVisibleFeatures(): FeatureRegistryEntry[] {\n  const features = getAllFeatures();\n  const visibility = useFeatureVisibility();\n\n  return useMemo(() => {\n    const visibleIds = new Set(visibility.filter((v) => v.isVisible).map((v) => v.featureId));\n\n    return features.filter((f) => visibleIds.has(f.config.metadata.id));\n  }, [features, visibility]);\n}\n\n/**\n * Hook to check if a specific feature is accessible\n */\nexport function useIsFeatureAccessible(featureId: string): {\n  isAccessible: boolean;\n  isVisible: boolean;\n  reason?: FeatureVisibility['reason'];\n} {\n  const visibility = useFeatureVisibility();\n\n  return useMemo(() => {\n    const feature = visibility.find((v) => v.featureId === featureId);\n    return {\n      isAccessible: feature?.isAccessible ?? false,\n      isVisible: feature?.isVisible ?? false,\n      reason: feature?.reason,\n    };\n  }, [visibility, featureId]);\n}\n\n/**\n * Hook to check if a specific tab is accessible within a feature\n */\nexport function useIsTabAccessible(\n  featureId: string,\n  tabId: string\n): {\n  isAccessible: boolean;\n  isVisible: boolean;\n  reason?: TabVisibility['reason'];\n} {\n  const visibility = useFeatureVisibility();\n\n  return useMemo(() => {\n    const feature = visibility.find((v) => v.featureId === featureId);\n    const tab = feature?.tabs.find((t) => t.tabId === tabId);\n\n    return {\n      isAccessible: tab?.isAccessible ?? false,\n      isVisible: tab?.isVisible ?? false,\n      reason: tab?.reason,\n    };\n  }, [visibility, featureId, tabId]);\n}\n\n/**\n * Hook to get accessible tabs for a feature\n */\nexport function useAccessibleTabs(featureId: string): FeatureTab[] {\n  const feature = getFeature(featureId);\n  const visibility = useFeatureVisibility();\n\n  return useMemo(() => {\n    if (!feature?.config.tabs) return [];\n\n    const featureVisibility = visibility.find((v) => v.featureId === featureId);\n    if (!featureVisibility) return [];\n\n    const accessibleTabIds = new Set(\n      featureVisibility.tabs.filter((t) => t.isVisible && t.isAccessible).map((t) => t.tabId)\n    );\n\n    return feature.config.tabs.filter((tab) => accessibleTabIds.has(tab.id));\n  }, [feature, visibility, featureId]);\n}\n\n// ============================================================================\n// Utility Hooks\n// ============================================================================\n\n/**\n * Hook to get a callback for checking feature accessibility\n * Useful for programmatic checks without re-renders\n */\nexport function useFeatureAccessChecker(): (featureId: string) => boolean {\n  const visibility = useFeatureVisibility();\n\n  return useCallback(\n    (featureId: string) => {\n      const feature = visibility.find((v) => v.featureId === featureId);\n      return feature?.isVisible === true && feature?.isAccessible === true;\n    },\n    [visibility]\n  );\n}\n\n/**\n * Hook to get all disabled features with reasons\n * Useful for debugging and admin dashboards\n */\nexport function useDisabledFeatures(): Array<{\n  featureId: string;\n  featureName: string;\n  reason: FeatureVisibility['reason'];\n}> {\n  const features = getAllFeatures();\n  const visibility = useFeatureVisibility();\n\n  return useMemo(() => {\n    return visibility\n      .filter((v) => !v.isVisible || !v.isAccessible)\n      .map((v) => {\n        const feature = features.find((f) => f.config.metadata.id === v.featureId);\n        return {\n          featureId: v.featureId,\n          featureName: feature?.config.metadata.name ?? v.featureId,\n          reason: v.reason,\n        };\n      });\n  }, [features, visibility]);\n}\n"],"names":["extractFeatureFlags","features","getAllFeatures","flags","feature","access","tabs","flag","tab","generateFeatureFlagManifest","manifest","metadata","generateFeatureFlagKeys","keys","key","useFeatureVisibility","allFlags","flagStatus","useFeatureFlagsStatus","roles","isAuthenticated","useAuth","useMemo","enabledFlags","enabled","config","isVisible","isAccessible","hasFeatureAccess","reason","tabVisibility","tabVisible","tabAccessible","tabReason","useAccessibleFeatures","visibility","accessibleIds","v","f","useVisibleFeatures","visibleIds","useIsFeatureAccessible","featureId","useIsTabAccessible","tabId","t","useAccessibleTabs","getFeature","featureVisibility","accessibleTabIds","useFeatureAccessChecker","useCallback","useDisabledFeatures"],"mappings":"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"}