UNPKG

fortify2-js

Version:

MOST POWERFUL JavaScript Security Library! Military-grade cryptography + 19 enhanced object methods + quantum-resistant algorithms + perfect TypeScript support. More powerful than Lodash with built-in security.

491 lines (487 loc) 16.7 kB
'use strict'; var CachePlugin = require('../core/CachePlugin.js'); var PluginTypes = require('../types/PluginTypes.js'); /** * Smart Cache Plugin * * Intelligent caching plugin with <0.5ms execution overhead * leveraging FortifyJS cache systems for optimal performance. */ /** * Smart Cache Plugin for intelligent request caching */ class SmartCachePlugin extends CachePlugin.CachePlugin { constructor() { super(...arguments); this.id = "nehonix.ftfy.cache"; this.name = "Smart Cache Plugin"; this.version = "1.0.0"; this.priority = PluginTypes.PluginPriority.HIGH; // Cache configuration this.cacheStrategy = "hybrid"; this.compressionEnabled = true; this.encryptionEnabled = true; // Keep encryption for security // Smart caching rules this.cachingRules = new Map(); // Cache analytics this.cacheAnalytics = { totalRequests: 0, cacheableRequests: 0, cacheHits: 0, cacheMisses: 0, cacheSkips: 0, averageHitTime: 0, averageMissTime: 0, compressionSavings: 0, }; // Dynamic TTL adjustment based on request patterns this.requestPatterns = new Map(); } /** * Initialize smart cache plugin */ async initializeCachePlugin(context) { // Setup default caching rules this.setupDefaultCachingRules(); // Configure custom rules from settings if (context.config.customSettings.cachingRules) { this.configureCachingRules(context.config.customSettings.cachingRules); } // Setup cache analytics cleanup this.setupAnalyticsCleanup(); // Setup dynamic TTL adjustment this.setupDynamicTTLAdjustment(); context.logger.info("Smart Cache Plugin initialized with intelligent caching rules"); } /** * Check if request should be cached (plugin-specific logic) */ shouldCacheRequest(context) { const { req } = context; // Apply smart caching rules for (const [ruleName, rule] of this.cachingRules.entries()) { if (rule.enabled && rule.pattern.test(req.path)) { // Check additional conditions if (this.shouldApplyRule(context, rule)) { return true; } } } // Fallback to intelligent heuristics return this.applyIntelligentCaching(context); } /** * Get custom cache key components */ getCustomKeyComponents(context) { const { req } = context; const components = []; // Add user-specific components for personalized content if (context.security.isAuthenticated) { components.push(`user:${context.security.userId}`); // Add role-based caching if (context.security.roles.length > 0) { components.push(`roles:${context.security.roles.sort().join(",")}`); } } // Add device type for responsive caching const userAgent = req.headers["user-agent"]; if (userAgent) { const deviceType = this.detectDeviceType(userAgent); components.push(`device:${deviceType}`); } // Add language for i18n caching const acceptLanguage = req.headers["accept-language"]; if (acceptLanguage) { const primaryLanguage = acceptLanguage.split(",")[0].split("-")[0]; components.push(`lang:${primaryLanguage}`); } // Add API version for versioned APIs const apiVersion = req.headers["api-version"] || req.query.version; if (apiVersion) { components.push(`version:${apiVersion}`); } return components; } /** * Get custom TTL for request */ getCustomTTL(context) { const { req } = context; const route = this.normalizeRoute(req.path); // Check if we have pattern data for dynamic TTL const pattern = this.requestPatterns.get(route); if (pattern) { return this.calculateDynamicTTL(pattern); } // Apply rule-based TTL for (const [ruleName, rule] of this.cachingRules.entries()) { if (rule.enabled && rule.pattern.test(req.path)) { return rule.ttl; } } // Default TTL based on content type return this.getDefaultTTLByContentType(req.path); } /** * Handle custom cache operations */ async handleCustomCacheOperation(context, operation) { switch (operation) { case "analyze": return await this.analyzeCachePerformance(context); case "optimize": return await this.optimizeCacheStrategy(context); case "prefetch": return await this.prefetchRelatedContent(context); default: return { operation, supported: false }; } } /** * Precompile cache operations */ async precompileCacheOperations() { // Pre-warm route normalization this.normalizeRoute("/api/users/123"); // Pre-warm device detection this.detectDeviceType("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"); // Pre-warm TTL calculation this.calculateDynamicTTL({ frequency: 10, lastAccess: Date.now(), averageResponseTime: 100, volatility: 0.1, }); } // ===== SMART CACHING LOGIC ===== /** * Setup default caching rules */ setupDefaultCachingRules() { // Static assets - long TTL this.cachingRules.set("static", { pattern: /\.(css|js|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot)$/, ttl: 86400000, // 24 hours enabled: true, compression: true, tags: ["static"], }); // API responses - medium TTL this.cachingRules.set("api", { pattern: /^\/api\/(?!auth|admin)/, ttl: 300000, // 5 minutes enabled: true, compression: true, tags: ["api"], }); // Public pages - short TTL this.cachingRules.set("public", { pattern: /^\/(?!admin|dashboard|profile)/, ttl: 60000, // 1 minute enabled: true, compression: true, tags: ["public"], }); // User-specific content - very short TTL this.cachingRules.set("user", { pattern: /^\/(profile|dashboard|settings)/, ttl: 30000, // 30 seconds enabled: true, compression: false, tags: ["user"], }); } /** * Configure custom caching rules */ configureCachingRules(rules) { for (const rule of rules) { this.cachingRules.set(rule.name, { pattern: new RegExp(rule.pattern), ttl: rule.ttl || 300000, enabled: rule.enabled !== false, compression: rule.compression !== false, tags: rule.tags || [], }); } } /** * Check if caching rule should be applied */ shouldApplyRule(context, rule) { const { req } = context; // Don't cache authenticated requests for public rules if (rule.tags.includes("public") && context.security.isAuthenticated) { return false; } // Don't cache if request has cache-control: no-cache const cacheControl = req.headers["cache-control"]; if (cacheControl && cacheControl.includes("no-cache")) { return false; } // Don't cache if request has pragma: no-cache const pragma = req.headers.pragma; if (pragma && pragma.includes("no-cache")) { return false; } return true; } /** * Apply intelligent caching heuristics */ applyIntelligentCaching(context) { const { req } = context; // Analyze request characteristics const hasQueryParams = Object.keys(req.query).length > 0; const hasBody = req.body && Object.keys(req.body).length > 0; const isIdempotent = ["GET", "HEAD", "OPTIONS"].includes(req.method); // Don't cache non-idempotent requests if (!isIdempotent) { return false; } // Don't cache requests with complex query parameters if (hasQueryParams && this.hasComplexQueryParams(req.query)) { return false; } // Cache simple GET requests if (req.method === "GET" && !hasBody) { return true; } return false; } /** * Calculate dynamic TTL based on request patterns */ calculateDynamicTTL(pattern) { const baseTime = 300000; // 5 minutes base // Adjust based on frequency (more frequent = longer cache) const frequencyMultiplier = Math.min(pattern.frequency / 10, 2); // Adjust based on volatility (more volatile = shorter cache) const volatilityMultiplier = Math.max(1 - pattern.volatility, 0.1); // Adjust based on response time (slower = longer cache) const responseTimeMultiplier = Math.min(pattern.averageResponseTime / 100, 3); return Math.round(baseTime * frequencyMultiplier * volatilityMultiplier * responseTimeMultiplier); } /** * Get default TTL by content type */ getDefaultTTLByContentType(path) { if (path.match(/\.(css|js)$/)) { return 3600000; // 1 hour for CSS/JS } if (path.match(/\.(png|jpg|jpeg|gif|svg|ico)$/)) { return 86400000; // 24 hours for images } if (path.startsWith("/api/")) { return 300000; // 5 minutes for API } return 60000; // 1 minute default } // ===== ANALYTICS AND OPTIMIZATION ===== /** * Analyze cache performance */ async analyzeCachePerformance(context) { const hitRate = this.cacheAnalytics.totalRequests > 0 ? (this.cacheAnalytics.cacheHits / this.cacheAnalytics.totalRequests) * 100 : 0; const cacheableRate = this.cacheAnalytics.totalRequests > 0 ? (this.cacheAnalytics.cacheableRequests / this.cacheAnalytics.totalRequests) * 100 : 0; return { hitRate: Math.round(hitRate * 100) / 100, cacheableRate: Math.round(cacheableRate * 100) / 100, totalRequests: this.cacheAnalytics.totalRequests, cacheHits: this.cacheAnalytics.cacheHits, cacheMisses: this.cacheAnalytics.cacheMisses, averageHitTime: this.cacheAnalytics.averageHitTime, averageMissTime: this.cacheAnalytics.averageMissTime, compressionSavings: this.cacheAnalytics.compressionSavings, topPatterns: this.getTopRequestPatterns(), }; } /** * Optimize cache strategy */ async optimizeCacheStrategy(context) { const optimizations = []; // Analyze hit rates by rule for (const [ruleName, rule] of this.cachingRules.entries()) { // Suggest optimizations based on performance if (rule.enabled) { optimizations.push(`Rule '${ruleName}' is active`); } } // Suggest TTL adjustments const ttlSuggestions = this.suggestTTLOptimizations(); optimizations.push(...ttlSuggestions); return { optimizations, suggestions: this.generateOptimizationSuggestions(), }; } /** * Prefetch related content */ async prefetchRelatedContent(context) { const { req } = context; const relatedUrls = this.identifyRelatedContent(req.path); // This would typically trigger background prefetching return { prefetched: relatedUrls.length, urls: relatedUrls, }; } // ===== UTILITY METHODS ===== /** * Normalize route for pattern tracking */ normalizeRoute(path) { return path .replace(/\/\d+/g, "/:id") .replace(/\/[a-f0-9-]{36}/g, "/:uuid") .replace(/\?.*$/, ""); } /** * Detect device type from user agent */ detectDeviceType(userAgent) { if (/Mobile|Android|iPhone|iPad/.test(userAgent)) { return "mobile"; } if (/Tablet|iPad/.test(userAgent)) { return "tablet"; } return "desktop"; } /** * Check for complex query parameters */ hasComplexQueryParams(query) { const complexParams = [ "search", "filter", "sort", "timestamp", "random", ]; return complexParams.some((param) => param in query); } /** * Get top request patterns */ getTopRequestPatterns() { const patterns = Array.from(this.requestPatterns.entries()) .sort((a, b) => b[1].frequency - a[1].frequency) .slice(0, 10); return patterns.map(([route, data]) => ({ route, frequency: data.frequency, averageResponseTime: data.averageResponseTime, volatility: data.volatility, })); } /** * Suggest TTL optimizations */ suggestTTLOptimizations() { const suggestions = []; for (const [route, pattern] of this.requestPatterns.entries()) { if (pattern.frequency > 50 && pattern.volatility < 0.1) { suggestions.push(`Increase TTL for high-frequency, stable route: ${route}`); } if (pattern.volatility > 0.8) { suggestions.push(`Decrease TTL for volatile route: ${route}`); } } return suggestions; } /** * Generate optimization suggestions */ generateOptimizationSuggestions() { const suggestions = []; const hitRate = this.cacheAnalytics.totalRequests > 0 ? (this.cacheAnalytics.cacheHits / this.cacheAnalytics.totalRequests) * 100 : 0; if (hitRate < 30) { suggestions.push("Consider increasing TTL values to improve hit rate"); } if (hitRate > 90) { suggestions.push("Excellent cache performance - consider expanding caching rules"); } if (this.cacheAnalytics.averageMissTime > this.cacheAnalytics.averageHitTime * 10) { suggestions.push("High miss penalty - consider cache warming strategies"); } return suggestions; } /** * Identify related content for prefetching */ identifyRelatedContent(path) { const related = []; // Simple related content identification if (path.startsWith("/api/users/")) { related.push("/api/users/profile", "/api/users/preferences"); } if (path.startsWith("/api/products/")) { related.push("/api/products/categories", "/api/products/featured"); } return related; } /** * Setup analytics cleanup */ setupAnalyticsCleanup() { // Reset analytics every hour setInterval(() => { this.resetAnalytics(); }, 3600000); // 1 hour } /** * Setup dynamic TTL adjustment */ setupDynamicTTLAdjustment() { // Analyze patterns every 10 minutes setInterval(() => { this.analyzeRequestPatterns(); }, 600000); // 10 minutes } /** * Reset analytics */ resetAnalytics() { // Keep some historical data, reset counters this.cacheAnalytics.totalRequests = 0; this.cacheAnalytics.cacheableRequests = 0; this.cacheAnalytics.cacheHits = 0; this.cacheAnalytics.cacheMisses = 0; this.cacheAnalytics.cacheSkips = 0; } /** * Analyze request patterns for optimization */ analyzeRequestPatterns() { const now = Date.now(); // Clean up old patterns for (const [route, pattern] of this.requestPatterns.entries()) { if (now - pattern.lastAccess > 3600000) { // 1 hour this.requestPatterns.delete(route); } } } } exports.SmartCachePlugin = SmartCachePlugin; //# sourceMappingURL=SmartCachePlugin.js.map