@noony-serverless/core
Version:
A Middy base framework compatible with Firebase and GCP Cloud Functions with TypeScript
897 lines • 36.1 kB
JavaScript
;
/**
* Route Guards Facade
*
* Main entry point for the guard system providing a clean, NestJS-inspired API
* for protecting routes with authentication and authorization. This facade
* orchestrates all guard components to provide three distinct protection methods
* optimized for different use cases.
*
* Three Protection Methods:
* 1. `requirePermissions()` - Simple permission list checks (fastest)
* 2. `requireWildcardPermissions()` - Hierarchical wildcard patterns
* 3. `requireComplexPermissions()` - Boolean expression evaluation
*
* Key Features:
* - Automatic resolver selection for optimal performance
* - Intelligent caching strategies per protection method
* - Conservative security approach with automatic cache invalidation
* - Built-in authentication with cached user context loading
* - Comprehensive monitoring and audit trails
* - Framework-agnostic middleware integration
*
* @example
* Complete guard system setup:
* ```typescript
* import { RouteGuards, GuardSetup } from '@noony-serverless/core';
*
* // Define user permission source
* const userPermissionSource = {
* async getUserPermissions(userId: string): Promise<string[]> {
* const user = await getUserFromDatabase(userId);
* return user.permissions;
* }
* };
*
* // Define token validator
* const tokenValidator = {
* async validateToken(token: string) {
* try {
* const decoded = jwt.verify(token, process.env.JWT_SECRET);
* return { valid: true, decoded };
* } catch (error) {
* return { valid: false, error: error.message };
* }
* },
* extractUserId: (decoded: any) => decoded.sub,
* isTokenExpired: (decoded: any) => decoded.exp < Date.now() / 1000
* };
*
* // Configure guard system
* await RouteGuards.configure(
* GuardSetup.production(),
* userPermissionSource,
* tokenValidator,
* {
* tokenHeader: 'authorization',
* tokenPrefix: 'Bearer ',
* requireEmailVerification: true,
* allowInactiveUsers: false
* }
* );
* ```
*
* @example
* Simple permission checks (fastest - ~0.1ms cached):
* ```typescript
* import { Handler, RouteGuards } from '@noony-serverless/core';
*
* const userManagementHandler = new Handler()
* .use(RouteGuards.requirePermissions(['user:read', 'user:update']))
* .handle(async (context) => {
* // User has either 'user:read' OR 'user:update' permission
* const users = await getUsers();
* return { success: true, users };
* });
* ```
*
* @example
* Wildcard permission patterns (hierarchical - ~0.2ms cached):
* ```typescript
* const adminHandler = new Handler()
* .use(RouteGuards.requireWildcardPermissions(['admin.*', 'org.reports.*']))
* .handle(async (context) => {
* // User has any permission starting with 'admin.' OR 'org.reports.'
* const adminData = await getAdminDashboard();
* return { success: true, data: adminData };
* });
* ```
*
* @example
* Complex boolean expressions (~0.5ms cached):
* ```typescript
* const complexAccessHandler = new Handler()
* .use(RouteGuards.requireComplexPermissions({
* or: [
* { permission: 'admin.users' },
* { and: [
* { permission: 'moderator.content' },
* { permission: 'org.reports.view' }
* ]}
* ]
* }))
* .handle(async (context) => {
* // User has 'admin.users' OR ('moderator.content' AND 'org.reports.view')
* return { success: true, accessGranted: true };
* });
* ```
*
* @example
* Authentication-only (no permissions):
* ```typescript
* const profileHandler = new Handler()
* .use(RouteGuards.requireAuth())
* .handle(async (context) => {
* // Only checks if user is authenticated
* const profile = await getUserProfile(context.user.id);
* return { success: true, profile };
* });
* ```
*
* @example
* Cache invalidation for security:
* ```typescript
* // Invalidate specific user when permissions change
* await RouteGuards.invalidateUserPermissions('user-123', 'Permission update');
*
* // System-wide invalidation for major updates
* await RouteGuards.invalidateAllPermissions('System update deployed');
*
* // Emergency invalidation for security incidents
* await RouteGuards.emergencyInvalidation('Security breach detected');
* ```
*
* @example
* Monitoring and health checks:
* ```typescript
* // Get comprehensive system statistics
* const stats = RouteGuards.getSystemStats();
* console.log('Guard system performance:', stats.systemHealth);
*
* // Perform health check
* const health = await RouteGuards.healthCheck();
* console.log('System status:', health.status);
* console.log('Recommendations:', health.details.recommendations);
* ```
*
* @author Noony Framework Team
* @version 1.0.0
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var RouteGuards_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.RouteGuards = void 0;
const typedi_1 = require("typedi");
const GuardConfiguration_1 = require("./config/GuardConfiguration");
const MemoryCacheAdapter_1 = require("./cache/MemoryCacheAdapter");
const NoopCacheAdapter_1 = require("./cache/NoopCacheAdapter");
const FastUserContextService_1 = require("./services/FastUserContextService");
const ConservativeCacheInvalidation_1 = require("./cache/ConservativeCacheInvalidation");
const FastAuthGuard_1 = require("./guards/FastAuthGuard");
const PermissionGuardFactory_1 = require("./guards/PermissionGuardFactory");
const PermissionRegistry_1 = require("./registry/PermissionRegistry");
const CustomTokenVerificationPortAdapter_1 = require("./adapters/CustomTokenVerificationPortAdapter");
/**
* Helper function to check if a token validator is a CustomTokenVerificationPort
*/
function isCustomTokenVerificationPort(validator) {
return (typeof validator === 'object' &&
'verifyToken' in validator &&
!('validateToken' in validator));
}
/**
* Convert any token validator to the TokenValidator interface expected by RouteGuards.
* Automatically wraps CustomTokenVerificationPort implementations with an adapter.
*/
function normalizeTokenValidator(validator) {
if (isCustomTokenVerificationPort(validator)) {
// For CustomTokenVerificationPort, we create a generic adapter
// We use a basic configuration that tries to extract common fields
return new CustomTokenVerificationPortAdapter_1.CustomTokenVerificationPortAdapter(validator, {
userIdExtractor: (user) => {
// Try to extract user ID from common field names
if (user && typeof user === 'object') {
const userObj = user;
return String(userObj.sub ||
userObj.id ||
userObj.userId ||
userObj.user_id ||
'unknown');
}
return 'unknown';
},
expirationExtractor: (user) => {
// Try to extract expiration from common field names
if (user && typeof user === 'object') {
const userObj = user;
const exp = userObj.exp || userObj.expiresAt || userObj.expires_at;
return typeof exp === 'number' ? exp : undefined;
}
return undefined;
},
});
}
// Already a TokenValidator, return as-is
return validator;
}
/**
* Route Guards Facade Implementation
*
* This class provides the main API for the guard system and handles
* the orchestration of all guard components. It follows the facade pattern
* to simplify the complex underlying guard architecture.
*/
let RouteGuards = class RouteGuards {
static { RouteGuards_1 = this; }
static instance = null;
static isConfigured = false;
// @ts-expect-error - Reserved for future functionality
_config;
cache;
userContextService;
cacheInvalidation;
authGuard;
guardFactory;
// @ts-expect-error - Reserved for future functionality
_permissionRegistry;
// System-wide statistics
systemStartTime = Date.now();
totalGuardChecks = 0;
totalErrors = 0;
totalResponseTime = 0;
constructor(config, cache, userContextService, cacheInvalidation, authGuard, guardFactory, permissionRegistry) {
this._config = config;
this.cache = cache;
this.userContextService = userContextService;
this.cacheInvalidation = cacheInvalidation;
this.authGuard = authGuard;
this.guardFactory = guardFactory;
this._permissionRegistry = permissionRegistry;
}
/**
* Configure the guard system with environment-specific settings
*
* This method must be called once before using any guard methods.
* It sets up all guard components with optimal configurations for
* the target environment (development, production, serverless).
*
* @param profile - Environment profile with guard configurations
* @param permissionSource - User permission data source
* @param tokenValidator - Token validation service (supports both TokenValidator and CustomTokenVerificationPort)
* @param authConfig - Authentication guard configuration
* @returns Promise resolving when configuration is complete
*
* @example
* Using with CustomTokenVerificationPort from AuthenticationMiddleware:
* ```typescript
* import { CustomTokenVerificationPort } from '@/middlewares/authenticationMiddleware';
* import { RouteGuards, GuardSetup } from '@/middlewares/guards';
*
* // Same token verifier used across the framework
* const tokenVerifier: CustomTokenVerificationPort<User> = {
* async verifyToken(token: string): Promise<User> {
* const payload = jwt.verify(token, process.env.JWT_SECRET!) as JWTPayload;
* return {
* id: payload.sub,
* email: payload.email,
* roles: payload.roles || [],
* sub: payload.sub,
* exp: payload.exp
* };
* }
* };
*
* // Configure RouteGuards with the same verifier
* await RouteGuards.configure(
* GuardSetup.production(),
* userPermissionSource,
* tokenVerifier, // Automatically wrapped with adapter
* authConfig
* );
* ```
*
* @example
* Traditional usage with TokenValidator (backward compatible):
* ```typescript
* const tokenValidator: TokenValidator = {
* async validateToken(token: string) {
* // Your existing validation logic
* return { valid: true, decoded: userPayload };
* },
* extractUserId: (decoded) => decoded.sub,
* isTokenExpired: (decoded) => decoded.exp < Date.now() / 1000
* };
*
* await RouteGuards.configure(
* GuardSetup.production(),
* userPermissionSource,
* tokenValidator, // Works as before
* authConfig
* );
* ```
*/
static async configure(profile, permissionSource, tokenValidator, authConfig) {
if (RouteGuards_1.isConfigured) {
console.warn('⚠️ RouteGuards already configured, skipping reconfiguration');
return;
}
try {
// Create guard configuration
const config = GuardConfiguration_1.GuardConfiguration.fromEnvironmentProfile(profile);
// Get effective cache type considering environment variable override
// Environment variable NOONY_GUARD_CACHE_ENABLE takes precedence for security
const effectiveCacheType = GuardConfiguration_1.GuardConfiguration.getEffectiveCacheType(profile.cacheType);
// Select cache adapter based on effective cache type
let cache;
if (effectiveCacheType === 'memory') {
cache = new MemoryCacheAdapter_1.MemoryCacheAdapter({
maxSize: config.cache.maxEntries || 1000,
defaultTTL: config.cache.defaultTtlMs || 15 * 60 * 1000,
name: 'guard-memory-cache',
});
}
else if (effectiveCacheType === 'none') {
cache = new NoopCacheAdapter_1.NoopCacheAdapter();
// Log cache status for debugging
if (!GuardConfiguration_1.GuardConfiguration.isCachingEnabled()) {
console.log(`🚫 Guard caching disabled by environment variable NOONY_GUARD_CACHE_ENABLE`);
}
else {
console.log(`🚫 Guard caching disabled by configuration (cacheType: 'none')`);
}
}
else {
// Default to memory cache (redis support would go here)
cache = new MemoryCacheAdapter_1.MemoryCacheAdapter({
maxSize: 1000,
defaultTTL: 15 * 60 * 1000,
name: 'guard-default-cache',
});
}
// Initialize permission registry
const permissionRegistry = new PermissionRegistry_1.DefaultPermissionRegistry();
// Create user context service
const userContextService = new FastUserContextService_1.FastUserContextService(cache, config, permissionSource, permissionRegistry);
// Create cache invalidation service
const cacheInvalidation = new ConservativeCacheInvalidation_1.ConservativeCacheInvalidation(cache);
// Normalize token validator to ensure compatibility
const normalizedTokenValidator = normalizeTokenValidator(tokenValidator);
// Create authentication guard
const authGuard = new FastAuthGuard_1.FastAuthGuard(cache, config, authConfig, userContextService, cacheInvalidation, normalizedTokenValidator);
// Create permission guard factory
const guardFactory = new PermissionGuardFactory_1.PermissionGuardFactory(userContextService, config, cache);
// Register services with TypeDI container
typedi_1.Container.set('GuardConfiguration', config);
typedi_1.Container.set('CacheAdapter', cache);
typedi_1.Container.set('FastUserContextService', userContextService);
typedi_1.Container.set('ConservativeCacheInvalidation', cacheInvalidation);
typedi_1.Container.set('FastAuthGuard', authGuard);
typedi_1.Container.set('PermissionGuardFactory', guardFactory);
typedi_1.Container.set('PermissionRegistry', permissionRegistry);
// Create and register the main RouteGuards instance
const routeGuards = new RouteGuards_1(config, cache, userContextService, cacheInvalidation, authGuard, guardFactory, permissionRegistry);
typedi_1.Container.set('RouteGuards', routeGuards);
RouteGuards_1.instance = routeGuards;
RouteGuards_1.isConfigured = true;
console.log('✅ RouteGuards configured successfully', {
environment: profile.environment,
cacheType: profile.cacheType,
effectiveCacheType: effectiveCacheType,
cachingEnabled: GuardConfiguration_1.GuardConfiguration.isCachingEnabled(),
permissionStrategy: config.security.permissionResolutionStrategy,
timestamp: new Date().toISOString(),
});
}
catch (error) {
console.error('❌ RouteGuards configuration failed', {
error: error instanceof Error ? error.message : 'Unknown error',
profile: profile.environment,
});
throw error;
}
}
/**
* Get the configured RouteGuards instance
*
* @returns Configured RouteGuards instance
* @throws Error if not configured
*/
static getInstance() {
if (!RouteGuards_1.instance || !RouteGuards_1.isConfigured) {
throw new Error('RouteGuards not configured. Call RouteGuards.configure() first.');
}
return RouteGuards_1.instance;
}
/**
* Create middleware for simple permission list checks
*
* This is the fastest protection method using direct O(1) set membership
* checks. Ideal for high-traffic endpoints with straightforward permission
* requirements.
*
* Performance: ~0.1ms cached, ~1-2ms uncached
*
* @param permissions - Array of required permissions (OR logic)
* @param options - Optional guard configuration
* @returns Middleware instance for permission checking
*/
static requirePermissions(permissions, options = {}) {
const instance = RouteGuards_1.getInstance();
return instance.createPlainPermissionGuard(permissions, options);
}
/**
* Create middleware for wildcard permission pattern checks
*
* Supports hierarchical permission patterns with wildcards for flexible
* permission management. Uses configurable pre-expansion or on-demand
* matching strategies.
*
* Performance: ~0.2ms cached (pre-expansion), ~2-5ms cached (on-demand)
*
* @param wildcardPatterns - Array of wildcard patterns
* @param options - Optional guard configuration
* @returns Middleware instance for wildcard permission checking
*/
static requireWildcardPermissions(wildcardPatterns, options = {}) {
const instance = RouteGuards_1.getInstance();
return instance.createWildcardPermissionGuard(wildcardPatterns, options);
}
/**
* Create middleware for complex boolean expression checks
*
* Supports advanced permission logic with AND, OR, and NOT operations.
* Includes expression caching and complexity tracking for performance
* optimization.
*
* Performance: ~0.5ms cached, ~5-15ms uncached (depends on complexity)
*
* @param expression - Permission expression with boolean logic
* @param options - Optional guard configuration
* @returns Middleware instance for expression permission checking
*/
static requireComplexPermissions(expression, options = {}) {
const instance = RouteGuards_1.getInstance();
return instance.createExpressionPermissionGuard(expression, options);
}
/**
* Create middleware with automatic resolver selection
*
* Analyzes permission requirements and automatically selects the optimal
* resolution strategy for best performance. Useful when you want the
* system to choose the best approach.
*
* @param permissions - Any type of permission requirement
* @param options - Optional guard configuration
* @returns Optimally configured middleware instance
*/
static requireAny(permissions, options = {}) {
const instance = RouteGuards_1.getInstance();
return instance.createAutoPermissionGuard(permissions, options);
}
/**
* Get authentication-only middleware
*
* Provides user authentication without permission checking.
* Useful for endpoints that only need to verify user identity.
*
* @param options - Optional guard configuration
* @returns Authentication-only middleware
*/
static requireAuth(_options = {}) {
const instance = RouteGuards_1.getInstance();
return instance.authGuard;
}
/**
* Invalidate user permissions cache
*
* Use when user permissions change to ensure fresh permission checks.
* Implements conservative invalidation strategy for security.
*
* @param userId - User ID to invalidate
* @param reason - Reason for invalidation (for audit)
* @returns Promise resolving when invalidation is complete
*/
static async invalidateUserPermissions(userId, reason) {
const instance = RouteGuards_1.getInstance();
await instance.cacheInvalidation.invalidateUserPermissions(userId, reason);
}
/**
* System-wide cache invalidation
*
* Nuclear option for clearing all permission-related caches.
* Use for major system updates or security incidents.
*
* @param reason - Reason for system-wide invalidation
* @returns Promise resolving when invalidation is complete
*/
static async invalidateAllPermissions(reason) {
const instance = RouteGuards_1.getInstance();
await instance.cacheInvalidation.invalidateSystemWide(reason);
}
/**
* Emergency security invalidation
*
* Immediate cache clearing for security incidents.
* Bypasses backup creation for maximum speed.
*
* @param reason - Security incident description
* @returns Promise resolving when emergency invalidation is complete
*/
static async emergencyInvalidation(reason) {
const instance = RouteGuards_1.getInstance();
await instance.cacheInvalidation.emergencySecurityInvalidation(reason);
}
/**
* Get comprehensive system statistics
*
* @returns Complete guard system performance and health metrics
*/
static getSystemStats() {
const instance = RouteGuards_1.getInstance();
return instance.getSystemStats();
}
/**
* Reset all system statistics
*/
static resetSystemStats() {
const instance = RouteGuards_1.getInstance();
instance.resetSystemStats();
}
/**
* Health check for the guard system
*
* @returns Health status with key metrics
*/
static async healthCheck() {
const instance = RouteGuards_1.getInstance();
return instance.performHealthCheck();
}
/**
* Factory method: Configure RouteGuards with CustomTokenVerificationPort for JWT tokens.
* Provides a streamlined setup for JWT-based authentication with common field extraction.
*
* @example
* Quick JWT setup with CustomTokenVerificationPort:
* ```typescript
* import { CustomTokenVerificationPort } from '@/middlewares/authenticationMiddleware';
*
* interface JWTUser {
* sub: string;
* email: string;
* roles: string[];
* exp: number;
* }
*
* const jwtVerifier: CustomTokenVerificationPort<JWTUser> = {
* async verifyToken(token: string): Promise<JWTUser> {
* const payload = jwt.verify(token, process.env.JWT_SECRET!) as any;
* return {
* sub: payload.sub,
* email: payload.email,
* roles: payload.roles || [],
* exp: payload.exp
* };
* }
* };
*
* // One-line setup for JWT authentication
* await RouteGuards.configureWithJWT(
* GuardSetup.production(),
* userPermissionSource,
* jwtVerifier,
* {
* tokenHeader: 'authorization',
* tokenPrefix: 'Bearer ',
* requireEmailVerification: true
* }
* );
* ```
*/
static async configureWithJWT(profile, permissionSource, jwtVerifier, authConfig) {
// Create a properly typed adapter for JWT tokens
const tokenValidator = CustomTokenVerificationPortAdapter_1.TokenVerificationAdapterFactory.forJWT(jwtVerifier);
await RouteGuards_1.configure(profile, permissionSource, tokenValidator, authConfig);
}
/**
* Factory method: Configure RouteGuards with CustomTokenVerificationPort for API keys.
* Provides setup for API key-based authentication with flexible field mapping.
*
* @example
* API key authentication setup:
* ```typescript
* interface APIKeyUser {
* keyId: string;
* permissions: string[];
* organization: string;
* expiresAt?: number;
* isActive: boolean;
* }
*
* const apiKeyVerifier: CustomTokenVerificationPort<APIKeyUser> = {
* async verifyToken(token: string): Promise<APIKeyUser> {
* const keyData = await validateAPIKeyInDatabase(token);
* if (!keyData || !keyData.isActive) {
* throw new Error('Invalid or inactive API key');
* }
* return keyData;
* }
* };
*
* await RouteGuards.configureWithAPIKey(
* GuardSetup.production(),
* userPermissionSource,
* apiKeyVerifier,
* {
* tokenHeader: 'x-api-key',
* tokenPrefix: '',
* allowInactiveUsers: false
* },
* 'keyId',
* 'expiresAt'
* );
* ```
*/
static async configureWithAPIKey(profile, permissionSource, apiKeyVerifier, authConfig, userIdField, expirationField) {
// Create a properly configured adapter for API keys
const tokenValidator = CustomTokenVerificationPortAdapter_1.TokenVerificationAdapterFactory.forAPIKey(apiKeyVerifier, userIdField, expirationField);
await RouteGuards_1.configure(profile, permissionSource, tokenValidator, authConfig);
}
/**
* Factory method: Configure RouteGuards with CustomTokenVerificationPort for OAuth tokens.
* Provides setup for OAuth-based authentication with scope validation.
*
* @example
* OAuth token authentication with scope requirements:
* ```typescript
* interface OAuthUser {
* sub: string;
* email: string;
* scope: string[];
* exp: number;
* client_id: string;
* }
*
* const oauthVerifier: CustomTokenVerificationPort<OAuthUser> = {
* async verifyToken(token: string): Promise<OAuthUser> {
* const response = await fetch(`${OAUTH_INTROSPECT_URL}`, {
* method: 'POST',
* headers: { 'Authorization': `Bearer ${token}` },
* body: new URLSearchParams({ token })
* });
*
* const tokenInfo = await response.json();
* if (!tokenInfo.active) {
* throw new Error('Token is not active');
* }
*
* return tokenInfo as OAuthUser;
* }
* };
*
* await RouteGuards.configureWithOAuth(
* GuardSetup.production(),
* userPermissionSource,
* oauthVerifier,
* {
* tokenHeader: 'authorization',
* tokenPrefix: 'Bearer ',
* requireEmailVerification: false
* },
* ['read:profile', 'write:data'] // Required OAuth scopes
* );
* ```
*/
static async configureWithOAuth(profile, permissionSource, oauthVerifier, authConfig, requiredScopes) {
// Create a properly configured adapter for OAuth tokens
const tokenValidator = CustomTokenVerificationPortAdapter_1.TokenVerificationAdapterFactory.forOAuth(oauthVerifier, requiredScopes);
await RouteGuards_1.configure(profile, permissionSource, tokenValidator, authConfig);
}
/**
* Factory method: Configure RouteGuards with a custom CustomTokenVerificationPort adapter.
* Provides maximum flexibility for custom token validation scenarios.
*
* @example
* Custom token validation with business-specific logic:
* ```typescript
* interface CustomUser {
* userId: string;
* tenantId: string;
* roles: string[];
* sessionExpiry: number;
* isVerified: boolean;
* }
*
* const customVerifier: CustomTokenVerificationPort<CustomUser> = {
* async verifyToken(token: string): Promise<CustomUser> {
* // Your custom verification logic
* return await verifyCustomToken(token);
* }
* };
*
* await RouteGuards.configureWithCustom(
* GuardSetup.production(),
* userPermissionSource,
* customVerifier,
* {
* tokenHeader: 'x-auth-token',
* tokenPrefix: 'Custom ',
* customValidation: async (token, user) => {
* return user.isVerified && user.tenantId === 'valid-tenant';
* }
* },
* {
* userIdExtractor: (user) => user.userId,
* expirationExtractor: (user) => user.sessionExpiry,
* additionalValidation: (user) => user.isVerified
* }
* );
* ```
*/
static async configureWithCustom(profile, permissionSource, customVerifier, authConfig, adapterConfig) {
// Create a custom configured adapter
const tokenValidator = CustomTokenVerificationPortAdapter_1.TokenVerificationAdapterFactory.custom(customVerifier, adapterConfig);
await RouteGuards_1.configure(profile, permissionSource, tokenValidator, authConfig);
}
// Private implementation methods
createPlainPermissionGuard(permissions, options) {
this.trackGuardCreation();
const guardConfig = {
requireAuth: options.requireAuth !== false,
cacheResults: options.cacheResults !== false,
auditTrail: options.auditTrail === true,
errorMessage: options.errorMessage,
};
const guard = this.guardFactory.createPlainGuard(permissions, guardConfig);
return this.wrapGuardWithStats(guard, 'plain');
}
createWildcardPermissionGuard(wildcardPatterns, options) {
this.trackGuardCreation();
const guardConfig = {
requireAuth: options.requireAuth !== false,
cacheResults: options.cacheResults !== false,
auditTrail: options.auditTrail === true,
errorMessage: options.errorMessage,
};
const guard = this.guardFactory.createWildcardGuard(wildcardPatterns, guardConfig);
return this.wrapGuardWithStats(guard, 'wildcard');
}
createExpressionPermissionGuard(expression, options) {
this.trackGuardCreation();
const guardConfig = {
requireAuth: options.requireAuth !== false,
cacheResults: options.cacheResults !== false,
auditTrail: options.auditTrail === true,
errorMessage: options.errorMessage,
};
const guard = this.guardFactory.createExpressionGuard(expression, guardConfig);
return this.wrapGuardWithStats(guard, 'expression');
}
createAutoPermissionGuard(permissions, options) {
this.trackGuardCreation();
const guardConfig = {
requireAuth: options.requireAuth !== false,
cacheResults: options.cacheResults !== false,
auditTrail: options.auditTrail === true,
errorMessage: options.errorMessage,
};
const guard = this.guardFactory.createAutoGuard(permissions, guardConfig);
return this.wrapGuardWithStats(guard, 'auto');
}
wrapGuardWithStats(guard, _type) {
const originalBefore = guard.before?.bind(guard);
if (!originalBefore) {
return guard;
}
guard.before = async (context) => {
const startTime = Date.now();
this.totalGuardChecks++;
try {
await originalBefore(context);
this.totalResponseTime += Date.now() - startTime;
}
catch (error) {
this.totalErrors++;
this.totalResponseTime += Date.now() - startTime;
throw error;
}
};
return guard;
}
trackGuardCreation() {
// Track guard creation for monitoring
console.log('🛡️ Guard created', {
timestamp: new Date().toISOString(),
});
}
getSystemStats() {
const uptime = Date.now() - this.systemStartTime;
const errorRate = this.totalGuardChecks > 0
? (this.totalErrors / this.totalGuardChecks) * 100
: 0;
const averageResponseTime = this.totalGuardChecks > 0
? this.totalResponseTime / this.totalGuardChecks
: 0;
const cacheStats = this.cache.getName() === 'noop-cache' ? { hitRate: 0 } : { hitRate: 85 }; // Estimate for memory cache
return {
authentication: this.authGuard.getStats(),
userContextService: this.userContextService.getStats(),
permissionGuardFactory: this.guardFactory.getStats(),
cacheInvalidation: this.cacheInvalidation.getStats(),
cacheAdapter: {
name: this.cache.getName(),
stats: cacheStats,
},
systemHealth: {
totalGuardChecks: this.totalGuardChecks,
averageResponseTime,
errorRate,
cacheEfficiency: cacheStats.hitRate,
uptime,
},
};
}
resetSystemStats() {
this.totalGuardChecks = 0;
this.totalErrors = 0;
this.totalResponseTime = 0;
this.systemStartTime = Date.now();
this.authGuard.resetStats();
this.userContextService.resetStats();
this.guardFactory.clearCache();
}
async performHealthCheck() {
const stats = this.getSystemStats();
const errorRate = stats.systemHealth.errorRate;
const averageResponseTime = stats.systemHealth.averageResponseTime;
let status;
if (errorRate < 1 && averageResponseTime < 10) {
status = 'healthy';
}
else if (errorRate < 5 && averageResponseTime < 50) {
status = 'degraded';
}
else {
status = 'unhealthy';
}
return {
status,
details: {
errorRate: `${errorRate.toFixed(2)}%`,
averageResponseTime: `${averageResponseTime.toFixed(2)}ms`,
totalChecks: stats.systemHealth.totalGuardChecks,
uptime: `${Math.round(stats.systemHealth.uptime / 1000)}s`,
cacheEfficiency: `${stats.systemHealth.cacheEfficiency.toFixed(1)}%`,
recommendations: this.getHealthRecommendations(status, stats),
},
timestamp: new Date().toISOString(),
};
}
getHealthRecommendations(status, stats) {
const recommendations = [];
if (status === 'unhealthy') {
recommendations.push('Consider emergency cache invalidation');
recommendations.push('Review error logs for system issues');
recommendations.push('Check user permission source performance');
}
if (stats.systemHealth.errorRate > 2) {
recommendations.push('High error rate detected - investigate failed permission checks');
}
if (stats.systemHealth.averageResponseTime > 20) {
recommendations.push('Slow response times - consider cache optimization');
}
if (stats.systemHealth.cacheEfficiency < 50) {
recommendations.push('Low cache efficiency - review caching strategy');
}
if (recommendations.length === 0) {
recommendations.push('System is operating optimally');
}
return recommendations;
}
};
exports.RouteGuards = RouteGuards;
exports.RouteGuards = RouteGuards = RouteGuards_1 = __decorate([
(0, typedi_1.Service)(),
__metadata("design:paramtypes", [GuardConfiguration_1.GuardConfiguration, Object, FastUserContextService_1.FastUserContextService,
ConservativeCacheInvalidation_1.ConservativeCacheInvalidation,
FastAuthGuard_1.FastAuthGuard,
PermissionGuardFactory_1.PermissionGuardFactory, Object])
], RouteGuards);
//# sourceMappingURL=RouteGuards.js.map