UNPKG

@frank-auth/react

Version:

Flexible and customizable React UI components for Frank Authentication

1 lines 36.5 kB
{"version":3,"file":"organization.cjs","sources":["../../../src/config/organization.ts"],"sourcesContent":["/**\n * @frank-auth/react - Organization Configuration\n *\n * Organization-specific configuration management with support for\n * multi-tenant settings, branding, and feature customization.\n */\n\nimport type {\n AppearanceConfig,\n FrankAuthUIConfig,\n LocalizationConfig,\n OrganizationConfig,\n Theme,\n UserType,\n} from './types';\n\nimport {DEFAULT_ORGANIZATION_CONFIG} from './defaults';\nimport {ThemeManager} from './theme';\nimport {AppearanceManager} from './appearance';\n\n// ============================================================================\n// Organization-Specific Types\n// ============================================================================\n\n/**\n * Organization feature flags with granular control\n */\nexport interface OrganizationFeatureFlags {\n // Authentication features\n authentication: {\n signUp: boolean;\n signIn: boolean;\n passwordReset: boolean;\n emailVerification: boolean;\n phoneVerification: boolean;\n socialAuth: boolean;\n magicLink: boolean;\n passkeys: boolean;\n };\n\n // Security features\n security: {\n mfa: boolean;\n mfaRequired: boolean;\n sso: boolean;\n sessionManagement: boolean;\n auditLogs: boolean;\n ipWhitelist: boolean;\n deviceTrust: boolean;\n riskAssessment: boolean;\n };\n\n // User management\n userManagement: {\n userProfiles: boolean;\n userRoles: boolean;\n userPermissions: boolean;\n userInvitations: boolean;\n userSuspension: boolean;\n userDeletion: boolean;\n bulkUserOperations: boolean;\n };\n\n // Organization features\n organization: {\n memberManagement: boolean;\n roleManagement: boolean;\n invitations: boolean;\n customBranding: boolean;\n customDomain: boolean;\n webhooks: boolean;\n apiAccess: boolean;\n analytics: boolean;\n };\n\n // UI features\n ui: {\n darkMode: boolean;\n customThemes: boolean;\n localization: boolean;\n customCSS: boolean;\n logoUpload: boolean;\n colorCustomization: boolean;\n layoutCustomization: boolean;\n };\n\n // Integration features\n integrations: {\n saml: boolean;\n oidc: boolean;\n ldap: boolean;\n scim: boolean;\n slack: boolean;\n microsoft: boolean;\n google: boolean;\n github: boolean;\n };\n}\n\n/**\n * Organization limits and quotas\n */\nexport interface OrganizationLimits {\n users: {\n maxUsers: number;\n maxEndUsers: number;\n maxExternalUsers: number;\n maxInternalUsers: number;\n };\n\n sessions: {\n maxSessionsPerUser: number;\n maxConcurrentSessions: number;\n sessionTimeout: number;\n maxSessionDuration: number;\n };\n\n api: {\n monthlyRequestLimit: number;\n rateLimit: number;\n burstLimit: number;\n maxWebhooks: number;\n };\n\n storage: {\n maxLogoSize: number;\n maxCustomCSSSize: number;\n auditLogRetention: number;\n maxCustomFields: number;\n };\n\n features: {\n maxRoles: number;\n maxPermissions: number;\n maxIntegrations: number;\n maxDomains: number;\n };\n}\n\n/**\n * Organization compliance settings\n */\nexport interface OrganizationCompliance {\n dataRetention: {\n userDataRetention: number; // days\n auditLogRetention: number; // days\n sessionLogRetention: number; // days\n automaticDeletion: boolean;\n };\n\n privacy: {\n gdprCompliant: boolean;\n ccpaCompliant: boolean;\n hipaaCompliant: boolean;\n soc2Compliant: boolean;\n dataProcessingAgreement: boolean;\n };\n\n security: {\n encryptionAtRest: boolean;\n encryptionInTransit: boolean;\n keyRotation: boolean;\n backupEncryption: boolean;\n accessLogging: boolean;\n };\n\n reporting: {\n complianceReports: boolean;\n auditReports: boolean;\n securityReports: boolean;\n dataExport: boolean;\n rightToBeForgotten: boolean;\n };\n}\n\n/**\n * Extended organization configuration\n */\nexport interface ExtendedOrganizationConfig extends OrganizationConfig {\n features: OrganizationFeatureFlags;\n limits: OrganizationLimits;\n compliance: OrganizationCompliance;\n\n // Computed properties\n tier: 'free' | 'starter' | 'professional' | 'enterprise';\n isActive: boolean;\n trialEndsAt?: Date;\n subscriptionStatus: 'active' | 'trialing' | 'past_due' | 'canceled' | 'unpaid';\n\n // Usage statistics\n usage: {\n currentUsers: number;\n currentEndUsers: number;\n monthlyApiRequests: number;\n storageUsed: number;\n lastActivityAt: Date;\n };\n}\n\n// ============================================================================\n// Organization Configuration Manager\n// ============================================================================\n\nexport class OrganizationConfigManager {\n private config: ExtendedOrganizationConfig;\n private themeManager: ThemeManager;\n private appearanceManager: AppearanceManager;\n private listeners: Set<(config: ExtendedOrganizationConfig) => void> = new Set();\n\n constructor(\n organizationConfig: Partial<ExtendedOrganizationConfig>,\n themeManager?: ThemeManager,\n appearanceManager?: AppearanceManager\n ) {\n this.config = this.mergeWithDefaults(organizationConfig);\n this.themeManager = themeManager || new ThemeManager();\n this.appearanceManager = appearanceManager || new AppearanceManager();\n\n // Apply organization branding\n this.applyOrganizationBranding();\n }\n\n /**\n * Get current organization configuration\n */\n getConfig(): ExtendedOrganizationConfig {\n return { ...this.config };\n }\n\n /**\n * Update organization configuration\n */\n updateConfig(updates: Partial<ExtendedOrganizationConfig>): void {\n this.config = {\n ...this.config,\n ...updates,\n settings: { ...this.config.settings, ...updates.settings },\n features: { ...this.config.features, ...updates.features },\n limits: { ...this.config.limits, ...updates.limits },\n compliance: { ...this.config.compliance, ...updates.compliance },\n usage: { ...this.config.usage, ...updates.usage },\n };\n\n // Re-apply branding if branding settings changed\n if (updates.settings?.branding) {\n this.applyOrganizationBranding();\n }\n\n this.notifyListeners();\n }\n\n /**\n * Check if a feature is enabled\n */\n isFeatureEnabled(featurePath: string): boolean {\n const keys = featurePath.split('.');\n let current: any = this.config.features;\n\n for (const key of keys) {\n if (current?.[key] === undefined) {\n return false;\n }\n current = current[key];\n }\n\n return Boolean(current);\n }\n\n /**\n * Check if a user type is allowed\n */\n isUserTypeAllowed(userType: UserType): boolean {\n switch (userType) {\n case 'internal':\n return this.config.tier === 'enterprise';\n case 'external':\n return this.isFeatureEnabled('userManagement.userProfiles');\n case 'end_user':\n return true; // Always allowed\n default:\n return false;\n }\n }\n\n /**\n * Get user limits for a specific user type\n */\n getUserLimits(userType: UserType): number {\n switch (userType) {\n case 'internal':\n return this.config.limits.users.maxInternalUsers;\n case 'external':\n return this.config.limits.users.maxExternalUsers;\n case 'end_user':\n return this.config.limits.users.maxEndUsers;\n default:\n return 0;\n }\n }\n\n /**\n * Check if organization is within limits\n */\n checkLimits(): {\n withinLimits: boolean;\n violations: Array<{ type: string; current: number; limit: number }>;\n } {\n const violations: Array<{ type: string; current: number; limit: number }> = [];\n\n // Check user limits\n if (this.config.usage.currentUsers > this.config.limits.users.maxUsers) {\n violations.push({\n type: 'users',\n current: this.config.usage.currentUsers,\n limit: this.config.limits.users.maxUsers,\n });\n }\n\n if (this.config.usage.currentEndUsers > this.config.limits.users.maxEndUsers) {\n violations.push({\n type: 'endUsers',\n current: this.config.usage.currentEndUsers,\n limit: this.config.limits.users.maxEndUsers,\n });\n }\n\n // Check API limits\n if (this.config.usage.monthlyApiRequests > this.config.limits.api.monthlyRequestLimit) {\n violations.push({\n type: 'apiRequests',\n current: this.config.usage.monthlyApiRequests,\n limit: this.config.limits.api.monthlyRequestLimit,\n });\n }\n\n return {\n withinLimits: violations.length === 0,\n violations,\n };\n }\n\n /**\n * Get organization tier configuration\n */\n getTierConfig(): {\n name: string;\n features: string[];\n limits: Record<string, number>;\n price?: string;\n } {\n const tierConfigs = {\n free: {\n name: 'Free',\n features: [\n 'Basic authentication',\n 'Up to 100 users',\n 'Email support',\n ],\n limits: {\n users: 100,\n apiRequests: 1000,\n sessions: 5,\n },\n },\n starter: {\n name: 'Starter',\n price: '$29/month',\n features: [\n 'Everything in Free',\n 'Up to 1,000 users',\n 'MFA support',\n 'Basic branding',\n 'Priority support',\n ],\n limits: {\n users: 1000,\n apiRequests: 10000,\n sessions: 10,\n },\n },\n professional: {\n name: 'Professional',\n price: '$99/month',\n features: [\n 'Everything in Starter',\n 'Up to 10,000 users',\n 'SSO integration',\n 'Advanced branding',\n 'API access',\n 'Webhooks',\n 'Audit logs',\n ],\n limits: {\n users: 10000,\n apiRequests: 100000,\n sessions: 25,\n },\n },\n enterprise: {\n name: 'Enterprise',\n price: 'Custom',\n features: [\n 'Everything in Professional',\n 'Unlimited users',\n 'SAML/LDAP integration',\n 'Custom domain',\n 'Advanced security',\n 'Compliance features',\n 'Dedicated support',\n ],\n limits: {\n users: -1, // Unlimited\n apiRequests: -1, // Unlimited\n sessions: -1, // Unlimited\n },\n },\n };\n\n return tierConfigs[this.config.tier];\n }\n\n /**\n * Generate UI configuration based on organization settings\n */\n generateUIConfig(): Partial<FrankAuthUIConfig> {\n const baseConfig: Partial<FrankAuthUIConfig> = {\n projectId: this.config.id,\n organization: this.config,\n features: {\n signUp: this.isFeatureEnabled('authentication.signUp'),\n signIn: this.isFeatureEnabled('authentication.signIn'),\n passwordReset: this.isFeatureEnabled('authentication.passwordReset'),\n mfa: this.isFeatureEnabled('security.mfa'),\n sso: this.isFeatureEnabled('security.sso'),\n organizationManagement: this.isFeatureEnabled('organization.memberManagement'),\n userProfile: this.isFeatureEnabled('userManagement.userProfiles'),\n sessionManagement: this.isFeatureEnabled('security.sessionManagement'),\n },\n };\n\n // Apply theme customization if enabled\n if (this.isFeatureEnabled('ui.customThemes')) {\n baseConfig.theme = this.generateCustomTheme();\n }\n\n // Apply appearance customization if enabled\n if (this.isFeatureEnabled('ui.customThemes')) {\n baseConfig.appearance = this.generateCustomAppearance();\n }\n\n // Apply localization if enabled\n if (this.isFeatureEnabled('ui.localization')) {\n baseConfig.localization = this.generateLocalizationConfig();\n }\n\n return baseConfig;\n }\n\n /**\n * Subscribe to configuration changes\n */\n subscribe(callback: (config: ExtendedOrganizationConfig) => void): () => void {\n this.listeners.add(callback);\n return () => {\n this.listeners.delete(callback);\n };\n }\n\n /**\n * Validate organization configuration\n */\n validateConfig(): {\n isValid: boolean;\n errors: string[];\n warnings: string[];\n } {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n // Validate required fields\n if (!this.config.id) {\n errors.push('Organization ID is required');\n }\n\n if (!this.config.name) {\n errors.push('Organization name is required');\n }\n\n // Validate limits\n const { withinLimits, violations } = this.checkLimits();\n if (!withinLimits) {\n violations.forEach(violation => {\n warnings.push(`${violation.type} limit exceeded: ${violation.current}/${violation.limit}`);\n });\n }\n\n // Validate branding\n if (this.config.settings.branding?.logo && !this.isValidUrl(this.config.settings.branding.logo)) {\n errors.push('Invalid logo URL');\n }\n\n // Validate feature consistency\n if (this.isFeatureEnabled('security.mfaRequired') && !this.isFeatureEnabled('security.mfa')) {\n errors.push('MFA must be enabled if MFA is required');\n }\n\n if (this.isFeatureEnabled('organization.customDomain') && this.config.tier === 'free') {\n warnings.push('Custom domain requires paid plan');\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings,\n };\n }\n\n // Private methods\n\n private mergeWithDefaults(config: Partial<ExtendedOrganizationConfig>): ExtendedOrganizationConfig {\n const defaultFeatures: OrganizationFeatureFlags = {\n authentication: {\n signUp: true,\n signIn: true,\n passwordReset: true,\n emailVerification: true,\n phoneVerification: false,\n socialAuth: false,\n magicLink: false,\n passkeys: false,\n },\n security: {\n mfa: false,\n mfaRequired: false,\n sso: false,\n sessionManagement: true,\n auditLogs: false,\n ipWhitelist: false,\n deviceTrust: false,\n riskAssessment: false,\n },\n userManagement: {\n userProfiles: true,\n userRoles: false,\n userPermissions: false,\n userInvitations: true,\n userSuspension: false,\n userDeletion: false,\n bulkUserOperations: false,\n },\n organization: {\n memberManagement: true,\n roleManagement: false,\n invitations: true,\n customBranding: false,\n customDomain: false,\n webhooks: false,\n apiAccess: false,\n analytics: false,\n },\n ui: {\n darkMode: true,\n customThemes: false,\n localization: true,\n customCSS: false,\n logoUpload: false,\n colorCustomization: false,\n layoutCustomization: false,\n },\n integrations: {\n saml: false,\n oidc: false,\n ldap: false,\n scim: false,\n slack: false,\n microsoft: false,\n google: false,\n github: false,\n },\n };\n\n const defaultLimits: OrganizationLimits = {\n users: {\n maxUsers: 100,\n maxEndUsers: 1000,\n maxExternalUsers: 50,\n maxInternalUsers: 5,\n },\n sessions: {\n maxSessionsPerUser: 5,\n maxConcurrentSessions: 100,\n sessionTimeout: 1800, // 30 minutes\n maxSessionDuration: 86400, // 24 hours\n },\n api: {\n monthlyRequestLimit: 1000,\n rateLimit: 100, // per minute\n burstLimit: 200,\n maxWebhooks: 3,\n },\n storage: {\n maxLogoSize: 1024 * 1024, // 1MB\n maxCustomCSSSize: 50 * 1024, // 50KB\n auditLogRetention: 90, // days\n maxCustomFields: 10,\n },\n features: {\n maxRoles: 10,\n maxPermissions: 50,\n maxIntegrations: 5,\n maxDomains: 1,\n },\n };\n\n const defaultCompliance: OrganizationCompliance = {\n dataRetention: {\n userDataRetention: 365,\n auditLogRetention: 90,\n sessionLogRetention: 30,\n automaticDeletion: false,\n },\n privacy: {\n gdprCompliant: false,\n ccpaCompliant: false,\n hipaaCompliant: false,\n soc2Compliant: false,\n dataProcessingAgreement: false,\n },\n security: {\n encryptionAtRest: true,\n encryptionInTransit: true,\n keyRotation: false,\n backupEncryption: false,\n accessLogging: true,\n },\n reporting: {\n complianceReports: false,\n auditReports: false,\n securityReports: false,\n dataExport: false,\n rightToBeForgotten: false,\n },\n };\n\n return {\n ...DEFAULT_ORGANIZATION_CONFIG,\n ...config,\n features: { ...defaultFeatures, ...config.features },\n limits: { ...defaultLimits, ...config.limits },\n compliance: { ...defaultCompliance, ...config.compliance },\n tier: config.tier || 'free',\n isActive: config.isActive ?? true,\n subscriptionStatus: config.subscriptionStatus || 'active',\n usage: {\n currentUsers: 0,\n currentEndUsers: 0,\n monthlyApiRequests: 0,\n storageUsed: 0,\n lastActivityAt: new Date(),\n ...config.usage,\n },\n } as ExtendedOrganizationConfig;\n }\n\n private applyOrganizationBranding(): void {\n if (this.config.settings.branding) {\n // Apply to theme manager\n this.themeManager.applyBranding({\n logo: {\n url: this.config.settings.branding.logo,\n alt: this.config.name,\n },\n colors: {\n primary: this.config.settings.branding.primaryColor || '#3b82f6',\n secondary: this.config.settings.branding.secondaryColor || '#64748b',\n },\n fonts: {\n primary: 'Inter, ui-sans-serif, system-ui, sans-serif',\n },\n customCSS: this.config.settings.branding.customCSS,\n });\n\n // Apply to appearance manager\n this.appearanceManager.applyOrganizationBranding(this.config);\n }\n }\n\n private generateCustomTheme(): Partial<Theme> {\n if (!this.isFeatureEnabled('ui.customThemes')) return {};\n\n return this.themeManager.getTheme();\n }\n\n private generateCustomAppearance(): Partial<AppearanceConfig> {\n if (!this.isFeatureEnabled('ui.customThemes')) return {};\n\n return this.appearanceManager.getConfig();\n }\n\n private generateLocalizationConfig(): Partial<LocalizationConfig> {\n if (!this.isFeatureEnabled('ui.localization')) return {};\n\n // Return basic localization config\n // In a real implementation, this might be customizable per organization\n return {\n defaultLocale: 'en',\n supportedLocales: ['en', 'es', 'fr'],\n };\n }\n\n private isValidUrl(url: string): boolean {\n try {\n new URL(url);\n return true;\n } catch {\n return false;\n }\n }\n\n private notifyListeners(): void {\n this.listeners.forEach(callback => callback(this.config));\n }\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Create organization configuration manager\n */\nexport function createOrganizationConfigManager(\n config: Partial<ExtendedOrganizationConfig>,\n themeManager?: ThemeManager,\n appearanceManager?: AppearanceManager\n): OrganizationConfigManager {\n return new OrganizationConfigManager(config, themeManager, appearanceManager);\n}\n\n/**\n * Transform organization settings from API to UI config\n */\nexport function transformOrganizationSettings(\n apiSettings: any\n): Partial<ExtendedOrganizationConfig> {\n return {\n id: apiSettings.id,\n name: apiSettings.name,\n slug: apiSettings.slug,\n settings: {\n allowPublicSignup: apiSettings.allowPublicSignup,\n requireEmailVerification: apiSettings.requireEmailVerification,\n requirePhoneVerification: apiSettings.requirePhoneVerification,\n allowedDomains: apiSettings.allowedDomains,\n mfaRequired: apiSettings.mfaSettings?.required,\n allowedMfaMethods: apiSettings.mfaSettings?.allowedMethods || [],\n passwordPolicy: apiSettings.passwordPolicy,\n sessionSettings: apiSettings.sessionSettings,\n branding: apiSettings.branding,\n customFields: apiSettings.customFields,\n },\n features: {\n // Map API features to UI feature flags\n authentication: {\n signUp: apiSettings.allowPublicSignup,\n signIn: true,\n passwordReset: true,\n emailVerification: apiSettings.requireEmailVerification,\n phoneVerification: apiSettings.requirePhoneVerification,\n socialAuth: apiSettings.ssoEnabled,\n magicLink: apiSettings.features?.magicLink || false,\n passkeys: apiSettings.features?.passkeys || false,\n },\n security: {\n mfa: apiSettings.mfaSettings?.enabled || false,\n mfaRequired: apiSettings.mfaSettings?.required || false,\n sso: apiSettings.ssoEnabled || false,\n sessionManagement: true,\n auditLogs: apiSettings.features?.auditLogs || false,\n ipWhitelist: apiSettings.features?.ipWhitelist || false,\n deviceTrust: apiSettings.features?.deviceTrust || false,\n riskAssessment: apiSettings.features?.riskAssessment || false,\n },\n // ... other feature mappings\n } as OrganizationFeatureFlags,\n tier: apiSettings.plan?.tier || 'free',\n isActive: apiSettings.active,\n subscriptionStatus: apiSettings.subscription?.status || 'active',\n usage: {\n currentUsers: apiSettings.stats?.currentUsers || 0,\n currentEndUsers: apiSettings.stats?.currentEndUsers || 0,\n monthlyApiRequests: apiSettings.stats?.monthlyApiRequests || 0,\n storageUsed: apiSettings.stats?.storageUsed || 0,\n lastActivityAt: new Date(apiSettings.stats?.lastActivityAt || Date.now()),\n },\n };\n}\n\n/**\n * Get feature availability by tier\n */\nexport function getFeaturesByTier(tier: 'free' | 'starter' | 'professional' | 'enterprise'): Partial<OrganizationFeatureFlags> {\n const tierFeatures = {\n free: {\n authentication: { signUp: true, signIn: true, passwordReset: true },\n security: { sessionManagement: true },\n userManagement: { userProfiles: true, userInvitations: true },\n organization: { memberManagement: true, invitations: true },\n ui: { darkMode: true, localization: true },\n },\n starter: {\n // All free features plus:\n security: { mfa: true },\n ui: { customThemes: true, logoUpload: true },\n organization: { customBranding: true },\n },\n professional: {\n // All starter features plus:\n security: { sso: true, auditLogs: true },\n organization: { webhooks: true, apiAccess: true, analytics: true },\n integrations: { saml: true, oidc: true },\n ui: { customCSS: true, colorCustomization: true },\n },\n enterprise: {\n // All professional features plus:\n security: { ipWhitelist: true, deviceTrust: true, riskAssessment: true },\n organization: { customDomain: true },\n integrations: { ldap: true, scim: true },\n userManagement: { bulkUserOperations: true },\n ui: { layoutCustomization: true },\n },\n };\n\n // Merge features for the tier and all lower tiers\n const tierOrder = ['free', 'starter', 'professional', 'enterprise'];\n const tierIndex = tierOrder.indexOf(tier);\n\n let features = {};\n for (let i = 0; i <= tierIndex; i++) {\n features = { ...features, ...tierFeatures[tierOrder[i] as keyof typeof tierFeatures] };\n }\n\n return features as Partial<OrganizationFeatureFlags>;\n}\n\n// ============================================================================\n// Export organization utilities\n// ============================================================================\n\nexport {\n DEFAULT_ORGANIZATION_CONFIG,\n};"],"names":["OrganizationConfigManager","organizationConfig","themeManager","appearanceManager","__publicField","ThemeManager","AppearanceManager","updates","featurePath","keys","current","key","userType","violations","baseConfig","callback","errors","warnings","withinLimits","violation","config","defaultFeatures","defaultLimits","defaultCompliance","DEFAULT_ORGANIZATION_CONFIG","url","createOrganizationConfigManager","transformOrganizationSettings","apiSettings","getFeaturesByTier","tier","tierFeatures","tierOrder","tierIndex","features","i"],"mappings":"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"}