@noony-serverless/core
Version:
A Middy base framework compatible with Firebase and GCP Cloud Functions with TypeScript
473 lines • 15.5 kB
TypeScript
/**
* Cache Abstraction Layer for High-Performance Guard System
*
* This module provides a pluggable caching interface that allows different
* cache implementations to be injected based on deployment requirements:
* - MemoryCacheAdapter: LRU cache for single-instance deployments
* - RedisCacheAdapter: Distributed cache for multi-instance deployments
* - HybridCacheAdapter: L1 (memory) + L2 (Redis) for maximum performance
* - NoopCacheAdapter: Disabled caching for testing scenarios
*
* The abstraction enables sub-millisecond authentication lookups while
* maintaining flexibility for different environments.
*
* @author Noony Framework Team
* @version 1.0.0
*/
/**
* Cache adapter interface for pluggable caching strategies.
* Provides async operations for storing and retrieving cached data
* with optional TTL support and pattern-based operations.
*
* @example
* Basic usage with any cache adapter:
* ```typescript
* import { CacheAdapter } from '@noony/core';
*
* class MyService {
* constructor(private cache: CacheAdapter) {}
*
* async getUserPermissions(userId: string) {
* const cacheKey = `user:${userId}:permissions`;
*
* // Try cache first
* let permissions = await this.cache.get<string[]>(cacheKey);
* if (permissions) {
* return permissions;
* }
*
* // Load from database and cache
* permissions = await this.loadPermissionsFromDB(userId);
* await this.cache.set(cacheKey, permissions, 600000); // 10 minutes
*
* return permissions;
* }
* }
* ```
*
* @example
* Pattern-based cache invalidation:
* ```typescript
* // Invalidate all user-related cache entries
* await cache.deletePattern('user:123:*');
*
* // Clear all permission caches
* await cache.deletePattern('permissions:*');
*
* // Clear everything (use with caution)
* await cache.clear();
* ```
*/
export interface CacheAdapter {
/**
* Retrieve a cached value by key.
* Returns null if the key doesn't exist or has expired.
*
* @param key - Cache key to retrieve
* @returns Promise resolving to cached value or null if not found
*
* @example
* ```typescript
* // Retrieve user permissions from cache
* const permissions = await cache.get<string[]>('user:123:permissions');
* if (permissions) {
* console.log('Cache hit:', permissions);
* } else {
* console.log('Cache miss - need to load from database');
* }
* ```
*/
get<T>(key: string): Promise<T | null>;
/**
* Store a value in cache with optional TTL.
* If TTL is not provided, uses the cache adapter's default TTL.
*
* @param key - Cache key to store under
* @param value - Value to cache (must be serializable)
* @param ttlMs - Time to live in milliseconds (optional)
*
* @example
* ```typescript
* // Cache user permissions for 10 minutes
* await cache.set('user:123:permissions', ['read', 'write'], 600000);
*
* // Cache with default TTL
* await cache.set('session:abc123', { userId: 123, roles: ['user'] });
*
* // Cache complex objects
* await cache.set('user:123:profile', {
* id: 123,
* name: 'John Doe',
* permissions: ['read', 'write'],
* lastLogin: new Date()
* }, 300000);
* ```
*/
set<T>(key: string, value: T, ttlMs?: number): Promise<void>;
/**
* Delete a specific cache entry.
* Silently succeeds if the key doesn't exist.
*
* @param key - Cache key to delete
*
* @example
* ```typescript
* // Remove specific user permissions from cache
* await cache.delete('user:123:permissions');
*
* // Clean up expired session
* await cache.delete('session:abc123');
* ```
*/
delete(key: string): Promise<void>;
/**
* Delete multiple cache entries matching a pattern.
* Pattern syntax varies by implementation (Redis vs memory cache).
*
* @param pattern - Pattern to match keys (implementation-specific)
*
* @example
* ```typescript
* // Clear all cache entries for a specific user
* await cache.deletePattern('user:123:*');
*
* // Clear all permission caches
* await cache.deletePattern('permissions:*');
*
* // Clear all session data
* await cache.deletePattern('session:*');
*
* // Redis-style patterns (if using Redis cache)
* await cache.deletePattern('auth:token:*'); // All auth tokens
* await cache.deletePattern('user:*:profile'); // All user profiles
* ```
*/
deletePattern(pattern: string): Promise<void>;
/**
* Clear all cache entries (conservative invalidation strategy).
* Used for secure cache invalidation when permissions change globally.
* Use with caution in production as this affects all cached data.
*
* @example
* ```typescript
* // Emergency cache clear after security update
* await cache.flush();
*
* // Clear cache after major permission system changes
* if (permissionSystemUpdated) {
* await cache.flush();
* console.log('Cache cleared due to permission system update');
* }
* ```
*/
flush(): Promise<void>;
/**
* Get cache statistics for monitoring.
* Provides performance metrics for monitoring cache effectiveness.
*
* @returns Cache statistics object with hit/miss ratios and entry counts
*
* @example
* ```typescript
* const stats = await cache.getStats();
* console.log(`Cache hit rate: ${stats.hitRate}%`);
* console.log(`Total entries: ${stats.totalEntries}`);
* console.log(`Memory usage: ${stats.memoryUsage} bytes`);
*
* // Monitor cache performance
* if (stats.hitRate < 70) {
* console.warn('Cache hit rate is low - consider adjusting TTL values');
* }
* ```
*/
getStats(): Promise<CacheStats>;
/**
* Get the name of the cache adapter for debugging.
* Useful for logging and debugging to identify which cache implementation is active.
*
* @returns Cache adapter name (e.g., 'MemoryCache', 'RedisCache', 'NoopCache')
*
* @example
* ```typescript
* console.log(`Using cache adapter: ${cache.getName()}`);
*
* // Environment-specific logging
* if (cache.getName() === 'NoopCache') {
* console.warn('Caching is disabled - performance may be reduced');
* }
* ```
*/
getName(): string;
}
/**
* Cache statistics for performance monitoring.
* Provides comprehensive metrics for analyzing cache performance and effectiveness.
*
* @example
* Using cache statistics for monitoring:
* ```typescript
* const stats = await cache.getStats();
*
* // Performance monitoring
* console.log(`Cache Performance Report:
* Hit Rate: ${stats.hitRate}%
* Total Entries: ${stats.totalEntries}
* Memory Usage: ${(stats.memoryUsage / 1024 / 1024).toFixed(2)} MB
* Average TTL: ${stats.averageTtlMs / 1000}s
* Evictions: ${stats.evictions}`);
*
* // Alert on poor performance
* if (stats.hitRate < 70) {
* console.warn('Low cache hit rate detected');
* }
*
* if (stats.memoryUsage > stats.maxMemoryUsage * 0.9) {
* console.warn('Cache memory usage near limit');
* }
* ```
*
* @example
* Integration with monitoring systems:
* ```typescript
* // Send metrics to monitoring service
* async function reportCacheMetrics() {
* const stats = await cache.getStats();
*
* metrics.gauge('cache.hit_rate', stats.hitRate);
* metrics.gauge('cache.total_entries', stats.totalEntries);
* metrics.gauge('cache.memory_usage', stats.memoryUsage);
* metrics.counter('cache.evictions', stats.evictions);
* }
* ```
*/
export interface CacheStats {
/**
* Total number of cache entries currently stored.
* Includes all cached items regardless of TTL status.
*/
totalEntries: number;
/**
* Number of cache hits since startup.
* Incremented each time a requested key is found in cache.
*/
hits: number;
/**
* Number of cache misses since startup.
* Incremented each time a requested key is not found in cache.
*/
misses: number;
/**
* Cache hit rate as percentage (0-100).
* Calculated as: (hits / (hits + misses)) * 100
*/
hitRate: number;
/**
* Memory usage in bytes (if applicable).
* Available for memory-based cache adapters, optional for others.
*/
memoryUsage?: number;
/**
* Time since cache was created, in milliseconds.
* Useful for calculating rates and monitoring uptime.
*/
uptime: number;
}
/**
* Configuration options for cache adapters.
* Provides standardized configuration interface for all cache implementations.
*
* @example
* Memory cache configuration:
* ```typescript
* const memoryConfig: CacheConfiguration = {
* maxSize: 10000, // Store up to 10k entries
* defaultTTL: 300000, // 5 minutes default TTL
* name: 'UserPermissions' // For debugging and monitoring
* };
*
* const cache = new MemoryCacheAdapter(memoryConfig);
* ```
*
* @example
* Redis cache configuration:
* ```typescript
* const redisConfig: CacheConfiguration = {
* maxSize: 50000, // Higher capacity for distributed cache
* defaultTTL: 600000, // 10 minutes default TTL
* name: 'DistributedAuth' // Identify this cache instance
* };
*
* const cache = new RedisCacheAdapter(redisConfig, redisClient);
* ```
*/
export interface CacheConfiguration {
/**
* Maximum number of entries to store.
* When exceeded, cache will use eviction policy (usually LRU).
*/
maxSize: number;
/**
* Default time to live in milliseconds.
* Applied to cache entries when no specific TTL is provided.
*/
defaultTTL: number;
/**
* Name for debugging/logging purposes.
* Helps identify cache instances in logs and monitoring.
*/
name?: string;
}
/**
* Cache key utilities for consistent key generation.
* Provides standardized key generation methods for different types of cached data
* in the guard system, ensuring consistent naming and avoiding key collisions.
*
* @example
* Basic key generation:
* ```typescript
* // Generate cache keys for different data types
* const userKey = CacheKeyBuilder.userContext('user123');
* // Returns: "noony:guard:user:user123"
*
* const tokenKey = CacheKeyBuilder.authToken('jwt-token-here');
* // Returns: "noony:guard:auth:jwt-toke...ken-here"
*
* const permKey = CacheKeyBuilder.userPermission('user123', 'admin.users.read');
* // Returns: "noony:guard:perm:user123:admin.users.read"
* ```
*
* @example
* Pattern-based cache keys:
* ```typescript
* // Cache wildcard resolution results
* const patterns = ['admin.*', 'user.read'];
* const userPerms = ['admin.users', 'admin.reports', 'user.read'];
* const wildcardKey = CacheKeyBuilder.wildcardPattern(patterns, userPerms);
*
* // Cache expression evaluation results
* const expr = '(admin.users OR admin.reports) AND user.active';
* const exprKey = CacheKeyBuilder.expressionResult(expr, userPerms);
* ```
*
* @example
* Custom key generation:
* ```typescript
* // Generate application-specific keys
* const customKey = CacheKeyBuilder.custom('feature', 'value1', 'value2');
* // Returns: "noony:guard:feature:value1:value2"
* ```
*/
export declare class CacheKeyBuilder {
private static readonly PREFIX;
/**
* Generate a cache key for user context.
* Creates a standardized key for caching user authentication and role data.
*
* @param userId - Unique identifier for the user
* @returns Cache key string for user context
*
* @example
* ```typescript
* const key = CacheKeyBuilder.userContext('user123');
* // Returns: "noony:guard:user:user123"
*
* await cache.set(key, {
* userId: 'user123',
* roles: ['admin', 'user'],
* permissions: ['read', 'write'],
* lastLogin: new Date()
* });
* ```
*/
static userContext(userId: string): string;
/**
* Generate a cache key for authentication token.
* Creates a secure key by using partial token hash to avoid storing full tokens.
*
* @param token - Authentication token (JWT, API key, etc.)
* @returns Cache key string for auth token
*
* @example
* ```typescript
* const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';
* const key = CacheKeyBuilder.authToken(token);
* // Returns: "noony:guard:auth:eyJhbGci...dCI6IkpXVCJ9"
*
* await cache.set(key, {
* valid: true,
* userId: 'user123',
* expires: new Date(Date.now() + 3600000)
* });
* ```
*/
static authToken(token: string): string;
/**
* Generate a cache key for wildcard permission resolution.
* Creates a key for caching the results of wildcard pattern matching
* against user permissions.
*
* @param patterns - Array of wildcard patterns to match
* @param userPermissions - Array of user's actual permissions
* @returns Cache key string for wildcard resolution
*
* @example
* ```typescript
* const patterns = ['admin.*', 'user.read'];
* const userPerms = ['admin.users', 'admin.reports', 'user.read'];
* const key = CacheKeyBuilder.wildcardPattern(patterns, userPerms);
* // Returns: "noony:guard:wildcard:hash1:hash2"
*
* // Cache the expansion result
* await cache.set(key, {
* matched: ['admin.users', 'admin.reports', 'user.read'],
* expandedPatterns: {
* 'admin.*': ['admin.users', 'admin.reports'],
* 'user.read': ['user.read']
* }
* });
* ```
*/
static wildcardPattern(patterns: string[], userPermissions: string[]): string;
/**
* Generate a cache key for expression permission resolution.
* Creates a key for caching the results of boolean expression evaluation
* against user permissions.
*
* @param expression - Boolean expression object to evaluate
* @param userPermissions - Array of user's actual permissions
* @returns Cache key string for expression evaluation
*
* @example
* ```typescript
* const expression = {
* type: 'AND',
* left: { type: 'permission', value: 'admin.users' },
* right: { type: 'permission', value: 'admin.reports' }
* };
* const userPerms = ['admin.users', 'admin.reports', 'user.read'];
* const key = CacheKeyBuilder.expressionResult(expression, userPerms);
* // Returns: "noony:guard:expression:exprHash:permHash"
*
* // Cache the evaluation result
* await cache.set(key, {
* result: true,
* evaluatedAt: new Date(),
* usedPermissions: ['admin.users', 'admin.reports']
* });
* ```
*/
static expressionResult(expression: object, userPermissions: string[]): string;
/**
* Generate a cache key for permission registry data
*/
static permissionRegistry(category?: string): string;
/**
* Simple hash function for arrays (not cryptographically secure)
*/
private static hashArray;
/**
* Simple hash function for objects (not cryptographically secure)
*/
private static hashObject;
}
//# sourceMappingURL=CacheAdapter.d.ts.map