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.

1,132 lines (1,126 loc) 40.7 kB
'use strict'; var crypto = require('crypto'); var util = require('util'); var zlib = require('zlib'); var events = require('events'); var randomCore = require('../../core/random/random-core.js'); require('../../core/random/random-types.js'); require('../../core/random/random-sources.js'); require('nehonix-uri-processor'); require('../../utils/memory/index.js'); require('../../types.js'); var cache_config = require('./config/cache.config.js'); var FastLRU = require('./FastLRU.js'); function _interopNamespaceDefault(e) { var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var crypto__namespace = /*#__PURE__*/_interopNamespaceDefault(crypto); /** * Ultra-Fast Secure In-Memory Cache System (UFSIMC) * Enhanced version with extreme performance optimizations, advanced security, and user-friendly features */ /** * Ultra-Fast Secure In-Memory Cache (UFSIMC) * Extends SIMC with extreme performance optimizations and advanced features */ class UFSIMC extends events.EventEmitter { constructor(maxEntries = cache_config.CONFIG.MAX_ENTRIES, logger) { super(); this.keyHashMap = new Map(); // Original key -> hashed key mapping this.tagIndex = new Map(); // Tag -> keys mapping this.priorityQueues = new Array(11) .fill(null) .map(() => new Set()); this.stats = { hits: 0, misses: 0, evictions: 0, totalSize: 0, entryCount: 0, hitRate: 0, memoryUsage: { used: 0, limit: cache_config.CONFIG.MAX_CACHE_SIZE_MB * 1024 * 1024, percentage: 0, }, totalAccesses: 0, size: 0, capacity: cache_config.CONFIG.MAX_ENTRIES, averageAccessTime: 0, compressionRatio: 0, encryptionOverhead: 0, hotKeys: [], coldKeys: [], tagStats: new Map(), }; this.encryptionKey = Buffer.alloc(0); // Performance optimizations this.encryptionPool = []; this.accessTimes = []; // Security enhancements this.accessPatterns = new Map(); this.rateLimiter = new Map(); this.integrityCheck = true; this.anomalyThreshold = 1000; this.logger = logger; this.lru = new FastLRU.FastLRU(maxEntries); this.initializeEncryption(); this.startMaintenanceTasks(); this.warmUpPools(); this.startPerformanceMonitoring(); } /** * Warm up cipher pools for better performance */ warmUpPools() { // Pre-create cipher instances for (let i = 0; i < 10; i++) { try { const iv = crypto__namespace.randomBytes(16); this.encryptionPool.push(crypto__namespace.createCipheriv(cache_config.CONFIG.ALGORITHM, this.encryptionKey, iv)); } catch (error) { // Pool will be created on-demand } } } /** * Start performance monitoring */ startPerformanceMonitoring() { this.performanceTimer = setInterval(() => { this.updatePerformanceMetrics(); this.optimizeHotness(); }, 5000); // Every 5 seconds this.hotnessDecayTimer = setInterval(() => { this.decayHotness(); }, 60000); // Every minute } /** * Enhanced encryption initialization with key derivation */ initializeEncryption() { try { if (process.env.ENC_SECRET_KEY) { this.encryptionKey = Buffer.from(process.env.ENC_SECRET_KEY, cache_config.CONFIG.ENCODING); } else if (process.env.ENC_SECRET_SEED && process.env.ENC_SECRET_SALT) { this.encryptionKey = crypto__namespace.pbkdf2Sync(process.env.ENC_SECRET_SEED, process.env.ENC_SECRET_SALT, cache_config.CONFIG.KEY_ITERATIONS, cache_config.CONFIG.KEY_LENGTH, "sha256"); } else { const warningMsg = "UFSIMC-WARNING: Using generated key. For production, set ENV variables: ENC_SECRET_KEY or (ENC_SECRET_SEED and ENC_SECRET_SALT)"; if (this.logger) { this.logger.securityWarning(warningMsg); } else { console.warn(warningMsg); } this.encryptionKey = randomCore.SecureRandom.getRandomBytes(cache_config.CONFIG.KEY_LENGTH).getBuffer(); } this.emit("key_rotation", { timestamp: Date.now(), reason: "initialization", }); } catch (error) { console.error("Failed to initialize encryption:", error); throw new Error("Cache initialization failed"); } } /** * Ultra-fast key validation and hashing */ validateAndHashKey(key) { if (!key || typeof key !== "string") { throw new Error("Cache key must be a non-empty string"); } if (key.length > cache_config.CONFIG.MAX_KEY_LENGTH) { throw new Error(`Cache key too long (max ${cache_config.CONFIG.MAX_KEY_LENGTH} chars)`); } // Use cached hash if available let hashedKey = this.keyHashMap.get(key); if (!hashedKey) { const salt = process.env.ENC_SECRET_SALT || "default-salt"; hashedKey = crypto__namespace .pbkdf2Sync(key, salt, 1000, 32, "sha256") .toString(cache_config.CONFIG.ENCODING); this.keyHashMap.set(key, hashedKey); } return hashedKey; } /** * High-performance compression with adaptive algorithms */ async smartCompress(data) { if (data.length < cache_config.CONFIG.COMPRESSION_THRESHOLD_BYTES) { return { data, compressed: false, ratio: 1 }; } try { const originalSize = data.length; // Try different compression based on data characteristics let compressed; if (data.includes("{") || data.includes("[")) { // JSON-like data - use deflate compressed = await util.promisify(zlib.deflate)(Buffer.from(data, "utf8")); } else { // Text data - use gzip compressed = await util.promisify(zlib.gzip)(Buffer.from(data, "utf8")); } const compressedString = compressed.toString(cache_config.CONFIG.ENCODING); const ratio = originalSize / compressedString.length; if (ratio > 1.1) { // At least 10% compression return { data: compressedString, compressed: true, ratio }; } } catch (error) { if (this.logger) { this.logger.warn("cache", "Compression failed:", error); } else { console.warn("Compression failed:", error); } } return { data, compressed: false, ratio: 1 }; } /** * Smart decompression */ async smartDecompress(data, compressed) { if (!compressed) return data; try { const buffer = Buffer.from(data, cache_config.CONFIG.ENCODING); // Try gzip first, then deflate try { const decompressed = await util.promisify(zlib.gunzip)(buffer); return decompressed.toString("utf8"); } catch { const decompressed = await util.promisify(zlib.inflate)(buffer); return decompressed.toString("utf8"); } } catch (error) { console.error("Decompression failed:", error); throw new Error("Data decompression failed"); } } /** * High-performance encryption with pooling */ fastEncrypt(data) { try { const iv = crypto__namespace.randomBytes(16); const cipher = crypto__namespace.createCipheriv(cache_config.CONFIG.ALGORITHM, this.encryptionKey, iv); let encrypted = cipher.update(data, "utf8", cache_config.CONFIG.ENCODING); encrypted += cipher.final(cache_config.CONFIG.ENCODING); const authTag = cipher.getAuthTag().toString(cache_config.CONFIG.ENCODING); return { encrypted, iv: iv.toString(cache_config.CONFIG.ENCODING), authTag, }; } catch (error) { this.emit("encryption_failure", { error: error.message, timestamp: Date.now(), }); throw new Error("Encryption failed"); } } /** * High-performance decryption */ fastDecrypt(encrypted, iv, authTag) { try { const ivBuffer = Buffer.from(iv, cache_config.CONFIG.ENCODING); const authTagBuffer = Buffer.from(authTag, cache_config.CONFIG.ENCODING); const decipher = crypto__namespace.createDecipheriv(cache_config.CONFIG.ALGORITHM, this.encryptionKey, ivBuffer); decipher.setAuthTag(authTagBuffer); let decrypted = decipher.update(encrypted, cache_config.CONFIG.ENCODING, "utf8"); decrypted += decipher.final("utf8"); return decrypted; } catch (error) { throw new Error("Decryption failed - data may be corrupted"); } } /** * Calculate data checksum for integrity */ calculateChecksum(data) { return crypto__namespace .createHash("sha256") .update(data) .digest("hex") .substring(0, 16); } /** * Rate limiting check */ checkRateLimit(key) { const now = Date.now(); const limit = this.rateLimiter.get(key); if (!limit || now > limit.resetTime) { this.rateLimiter.set(key, { count: 1, resetTime: now + 60000 }); // 1 minute window return true; } if (limit.count >= 10000) { // 10k requests per minute max return false; } limit.count++; return true; } /** * Ultra-fast SET operation with advanced features */ async set(key, value, options = {}) { const startTime = process.hrtime.bigint(); try { // Rate limiting if (!this.checkRateLimit(key)) { throw new Error("Rate limit exceeded"); } const hashedKey = this.validateAndHashKey(key); const serialized = JSON.stringify(value); // Size validation if (serialized.length > cache_config.CONFIG.MAX_VALUE_SIZE_MB * 1024 * 1024) { throw new Error(`Value too large (max ${cache_config.CONFIG.MAX_VALUE_SIZE_MB}MB)`); } // Smart compression const { data: processedData, compressed } = options.skipCompression ? { data: serialized, compressed: false } : await this.smartCompress(serialized); // Conditional encryption let encrypted, iv, authTag, checksum; if (options.skipEncryption) { encrypted = processedData; iv = ""; authTag = ""; } else { const encResult = this.fastEncrypt(processedData); encrypted = encResult.encrypted; iv = encResult.iv; authTag = encResult.authTag; } checksum = this.integrityCheck ? this.calculateChecksum(serialized) : ""; const now = Date.now(); const ttl = options.ttl || cache_config.CONFIG.CACHE_EXPIRY_MS; const priority = Math.max(1, Math.min(10, options.priority || 5)); const entry = { data: encrypted, iv, authTag, timestamp: now, expiresAt: now + ttl, accessCount: 0, lastAccessed: now, compressed, size: encrypted.length + iv.length + authTag.length + 200, version: 1, hotness: 0, priority, tags: new Set(options.tags || []), metadata: options.metadata || {}, checksum, }; // Handle eviction with callback const evictedEntry = this.lru.put(hashedKey, entry); if (evictedEntry && options.onEvict) { try { const evictedData = await this.decryptAndDecompress(evictedEntry); // Find the original key for the evicted entry const originalKey = this.findOriginalKey(hashedKey); if (originalKey) { options.onEvict(originalKey, JSON.parse(evictedData)); } } catch (error) { if (this.logger) { this.logger.warn("cache", "Eviction callback failed:", error); } else { console.warn("Eviction callback failed:", error); } } } // Update indexes - ensure priority is within valid range if (priority >= 0 && priority < this.priorityQueues.length) { this.priorityQueues[priority].add(hashedKey); } if (options.tags) { options.tags.forEach((tag) => { if (!this.tagIndex.has(tag)) { this.tagIndex.set(tag, new Set()); } this.tagIndex.get(tag).add(hashedKey); }); } // Update stats this.updateStatsAfterSet(entry.size, evictedEntry ? 1 : 0); this.recordAccessTime(startTime); return true; } catch (error) { console.error("Ultra cache set error:", error); return false; } } /** * Ultra-fast GET operation with hotness tracking */ async get(key) { const startTime = process.hrtime.bigint(); try { const hashedKey = this.validateAndHashKey(key); const node = this.lru.getNode(hashedKey); if (!node?.entry) { this.stats.misses++; this.recordAccessTime(startTime); return null; } const entry = node.entry; const now = Date.now(); // Check expiration if (now > entry.expiresAt) { this.lru.delete(hashedKey); this.cleanupIndexes(hashedKey, entry); this.stats.misses++; this.stats.entryCount--; this.recordAccessTime(startTime); return null; } // Update access patterns and hotness entry.accessCount++; entry.lastAccessed = now; entry.hotness = Math.min(100, entry.hotness + 1); // Security monitoring this.trackAccess(hashedKey); // Decrypt and decompress const decryptedData = await this.decryptAndDecompress(entry); // Integrity check - compare against original serialized data if (this.integrityCheck && entry.checksum) { const currentChecksum = this.calculateChecksum(decryptedData); if (currentChecksum !== entry.checksum) { this.emit("integrity_violation", { key, timestamp: now }); throw new Error("Data integrity check failed"); } } this.stats.hits++; this.recordAccessTime(startTime); return JSON.parse(decryptedData); } catch (error) { console.error("Ultra cache get error:", error); this.stats.misses++; this.recordAccessTime(startTime); return null; } } /** * Helper method for decryption and decompression */ async decryptAndDecompress(entry) { let decrypted; if (entry.iv && entry.authTag) { decrypted = this.fastDecrypt(entry.data, entry.iv, entry.authTag); } else { decrypted = entry.data; // Unencrypted data } return await this.smartDecompress(decrypted, entry.compressed); } /** * Batch GET operation for multiple keys */ async getMultiple(keys) { const results = new Map(); // Process in parallel batches const batchSize = 50; for (let i = 0; i < keys.length; i += batchSize) { const batch = keys.slice(i, i + batchSize); const promises = batch.map(async (key) => { const value = await this.get(key); return { key, value }; }); const batchResults = await Promise.all(promises); batchResults.forEach(({ key, value }) => { results.set(key, value); }); } return results; } /** * Set multiple key-value pairs */ async setMultiple(entries) { const promises = entries.map(({ key, value, options }) => this.set(key, value, options)); return Promise.all(promises); } /** * Delete by tag */ async deleteByTag(tag) { const keys = this.tagIndex.get(tag); if (!keys) return 0; let deleted = 0; for (const hashedKey of keys) { if (this.lru.delete(hashedKey)) { deleted++; } } this.tagIndex.delete(tag); this.stats.entryCount -= deleted; return deleted; } /** * Get keys by tag */ getKeysByTag(tag) { const hashedKeys = this.tagIndex.get(tag); if (!hashedKeys) return []; const originalKeys = []; for (const [originalKey, hashedKey] of this.keyHashMap.entries()) { if (hashedKeys.has(hashedKey)) { originalKeys.push(originalKey); } } return originalKeys; } /** * Advanced cache statistics */ get getUltraStats() { this.updatePerformanceMetrics(); return { ...this.stats }; } /** * Export cache data for backup */ async exportData() { const data = {}; const keys = this.lru.getKeys(); for (const hashedKey of keys) { const node = this.lru.getNode(hashedKey); if (node?.entry) { try { const decrypted = await this.decryptAndDecompress(node.entry); const originalKey = this.findOriginalKey(hashedKey); if (originalKey) { data[originalKey] = { value: JSON.parse(decrypted), metadata: node.entry .metadata, tags: Array.from(node.entry.tags), expiresAt: node.entry .expiresAt, }; } } catch (error) { if (this.logger) { this.logger.warn("cache", `Failed to export key ${hashedKey}:`, error); } else { console.warn(`Failed to export key ${hashedKey}:`, error); } } } } return data; } /** * Import cache data from backup */ async importData(data) { try { for (const [key, info] of Object.entries(data)) { const { value, metadata, tags, expiresAt } = info; const ttl = Math.max(0, expiresAt - Date.now()); if (ttl > 0) { await this.set(key, value, { ttl, metadata, tags, }); } } return true; } catch (error) { console.error("Import failed:", error); return false; } } /** * Performance and maintenance methods */ updatePerformanceMetrics() { // Calculate average access time if (this.accessTimes.length > 0) { this.stats.averageAccessTime = this.accessTimes.reduce((a, b) => a + b, 0) / this.accessTimes.length; this.accessTimes = this.accessTimes.slice(-1000); // Keep last 1000 measurements } // Update memory stats this.stats.entryCount = this.lru.getSize(); this.stats.memoryUsage.used = this.stats.totalSize; this.stats.memoryUsage.percentage = (this.stats.totalSize / this.stats.memoryUsage.limit) * 100; this.stats.hitRate = this.stats.hits / Math.max(1, this.stats.hits + this.stats.misses); // Update hot/cold keys this.updateHotColdKeys(); } updateHotColdKeys() { const keys = this.lru.getKeys(); const keyHotness = []; for (const hashedKey of keys) { const node = this.lru.getNode(hashedKey); if (node?.entry) { const entry = node.entry; const originalKey = this.findOriginalKey(hashedKey); if (originalKey) { keyHotness.push({ key: originalKey, hotness: entry.hotness, }); } } } keyHotness.sort((a, b) => b.hotness - a.hotness); this.stats.hotKeys = keyHotness.slice(0, 10).map((k) => k.key); this.stats.coldKeys = keyHotness.slice(-10).map((k) => k.key); } optimizeHotness() { // Move hot items to higher priority const keys = this.lru.getKeys(); for (const hashedKey of keys) { const node = this.lru.getNode(hashedKey); if (node?.entry) { const entry = node.entry; if (entry.hotness > 50 && entry.priority < 8) { entry.priority = Math.min(10, entry.priority + 1); } } } } decayHotness() { // Gradually reduce hotness to identify truly hot vs temporarily hot items const keys = this.lru.getKeys(); for (const hashedKey of keys) { const node = this.lru.getNode(hashedKey); if (node?.entry) { const entry = node.entry; entry.hotness = Math.max(0, entry.hotness * 0.9); } } } recordAccessTime(startTime) { const endTime = process.hrtime.bigint(); const durationNs = Number(endTime - startTime); const durationMs = durationNs / 1000000; this.accessTimes.push(durationMs); } updateStatsAfterSet(size, evictions) { this.stats.totalSize += size; this.stats.entryCount++; this.stats.evictions += evictions; } trackAccess(key) { const now = Date.now(); if (!this.accessPatterns.has(key)) { this.accessPatterns.set(key, []); } const accesses = this.accessPatterns.get(key); accesses.push(now); // Keep only recent accesses const oneHourAgo = now - 60 * 60 * 1000; const recentAccesses = accesses.filter((time) => time > oneHourAgo); this.accessPatterns.set(key, recentAccesses); // Detect anomalies if (recentAccesses.length > this.anomalyThreshold) { this.emit("suspicious_access", { key, count: recentAccesses.length, timestamp: now, }); } } cleanupIndexes(hashedKey, entry) { // Remove from priority queues - ensure priority is within valid range if (entry.priority >= 0 && entry.priority < this.priorityQueues.length) { this.priorityQueues[entry.priority].delete(hashedKey); } // Remove from tag indexes for (const tag of entry.tags) { const tagKeys = this.tagIndex.get(tag); if (tagKeys) { tagKeys.delete(hashedKey); if (tagKeys.size === 0) { this.tagIndex.delete(tag); } } } } findOriginalKey(hashedKey) { for (const [originalKey, hash] of this.keyHashMap.entries()) { if (hash === hashedKey) { return originalKey; } } return undefined; } startMaintenanceTasks() { this.cleanupTimer = setInterval(() => { this.cleanup(); }, cache_config.CONFIG.CLEANUP_INTERVAL_MS); this.keyRotationTimer = setInterval(() => { this.rotateEncryptionKey(); }, cache_config.CONFIG.KEY_ROTATION_MS); this.securityTimer = setInterval(() => { this.performSecurityChecks(); }, cache_config.CONFIG.SECURITY_CHECK_INTERVAL_MS); } cleanup() { const now = Date.now(); const keys = this.lru.getKeys(); let cleaned = 0; for (const hashedKey of keys) { const node = this.lru.getNode(hashedKey); if (node?.entry && now > node.entry.expiresAt) { const entry = node.entry; this.lru.delete(hashedKey); this.cleanupIndexes(hashedKey, entry); this.stats.totalSize -= entry.size; cleaned++; } } if (cleaned > 0) { this.stats.entryCount -= cleaned; this.emit("cleanup_completed", { cleaned, timestamp: now }); } } async rotateEncryptionKey() { try { const newKey = crypto__namespace.randomBytes(cache_config.CONFIG.KEY_LENGTH); const oldKey = this.encryptionKey; const keys = this.lru.getKeys(); let processed = 0; for (const hashedKey of keys) { const node = this.lru.getNode(hashedKey); if (!node?.entry) continue; const entry = node.entry; // Skip unencrypted entries if (!entry.iv || !entry.authTag) continue; try { // Decrypt with old key this.encryptionKey = oldKey; const decrypted = this.fastDecrypt(entry.data, entry.iv, entry.authTag); // Re-encrypt with new key this.encryptionKey = newKey; const { encrypted, iv, authTag } = this.fastEncrypt(decrypted); // Update entry entry.data = encrypted; entry.iv = iv; entry.authTag = authTag; processed++; } catch (error) { console.error(`Failed to re-encrypt entry ${hashedKey}:`, error); // Remove corrupted entry this.lru.delete(hashedKey); this.cleanupIndexes(hashedKey, entry); this.stats.totalSize -= entry.size; this.stats.entryCount--; } } this.encryptionKey = newKey; this.emit("key_rotation", { timestamp: Date.now(), reason: "scheduled", entriesProcessed: processed, }); } catch (error) { console.error("Key rotation failed:", error); } } performSecurityChecks() { // Memory pressure check if (this.stats.memoryUsage.percentage > 90) { this.emit("memory_pressure", { usage: this.stats.memoryUsage, timestamp: Date.now(), }); // Emergency cleanup this.emergencyCleanup(); } // Check for potential DoS attacks if (this.lru.getSize() > cache_config.CONFIG.MAX_ENTRIES * 0.95) { this.emit("cache_overflow", { entries: this.lru.getSize(), limit: cache_config.CONFIG.MAX_ENTRIES, timestamp: Date.now(), }); } // Analyze access patterns for anomalies this.detectAnomalies(); } emergencyCleanup() { const targetSize = this.stats.memoryUsage.limit * 0.6; // Clear to 60% const keys = this.lru.getKeys(); let cleaned = 0; // Remove expired entries first this.cleanup(); // If still over limit, remove coldest entries if (this.stats.totalSize > targetSize) { for (const hashedKey of keys) { if (this.stats.totalSize <= targetSize) break; const node = this.lru.getNode(hashedKey); if (node?.entry) { const entry = node.entry; if (entry.hotness < 10) { // Remove cold entries this.lru.delete(hashedKey); this.cleanupIndexes(hashedKey, entry); this.stats.totalSize -= entry.size; cleaned++; } } } } this.stats.entryCount -= cleaned; this.stats.evictions += cleaned; this.emit("emergency_cleanup", { cleaned, timestamp: Date.now() }); } detectAnomalies() { const now = Date.now(); const suspiciousPatterns = []; for (const [key, accesses] of this.accessPatterns.entries()) { if (accesses.length > this.anomalyThreshold) { suspiciousPatterns.push(key); } } if (suspiciousPatterns.length > 0) { this.emit("anomaly_detected", { patterns: suspiciousPatterns, timestamp: now, }); } } // ==================Advanced methods (usefull in some case) /** * Get cache health report */ getHealthReport() { const issues = []; const recommendations = []; let status = "healthy"; const stats = this.getUltraStats; // Check hit rate if (stats.hitRate < 0.5) { issues.push("Low hit rate (< 50%)"); recommendations.push("Consider increasing cache size or TTL values"); status = "warning"; } // Check memory usage if (stats.memoryUsage.percentage > 90) { issues.push("High memory usage (> 90%)"); recommendations.push("Increase cache size limit or reduce entry count"); status = "critical"; } // Check access time if (stats.averageAccessTime > 10) { issues.push("Slow access times (> 10ms)"); recommendations.push("Consider optimizing data size or disabling encryption for performance-critical data"); if (status === "healthy") status = "warning"; } // Check eviction rate const evictionRate = stats.evictions / Math.max(1, stats.entryCount); if (evictionRate > 0.1) { issues.push("High eviction rate (> 10%)"); recommendations.push("Increase cache size or adjust TTL values"); if (status === "healthy") status = "warning"; } return { status, issues, recommendations, metrics: stats }; } /** * Optimize cache configuration automatically */ autoOptimize() { const stats = this.getUltraStats; // Adjust anomaly threshold based on usage patterns const avgAccesses = Array.from(this.accessPatterns.values()).reduce((sum, accesses) => sum + accesses.length, 0) / Math.max(1, this.accessPatterns.size); this.anomalyThreshold = Math.max(1000, avgAccesses * 10); // Adjust cleanup frequency based on expiration patterns if (stats.memoryUsage.percentage > 70) { // More frequent cleanup if (this.cleanupTimer) { clearInterval(this.cleanupTimer); this.cleanupTimer = setInterval(() => this.cleanup(), cache_config.CONFIG.CLEANUP_INTERVAL_MS / 2); } } this.emit("auto_optimization", { anomalyThreshold: this.anomalyThreshold, timestamp: Date.now(), }); } /** * Prefetch data based on access patterns */ async prefetch(predictor) { let prefetched = 0; const keys = this.lru.getKeys(); for (const hashedKey of keys) { const node = this.lru.getNode(hashedKey); if (!node?.entry) continue; const entry = node.entry; const originalKey = this.findOriginalKey(hashedKey); if (originalKey && entry.hotness > 20) { try { const predictedData = await predictor(originalKey, entry.metadata); if (predictedData) { const prefetchKey = `${originalKey}_prefetch_${Date.now()}`; await this.set(prefetchKey, predictedData, { ttl: entry.expiresAt - Date.now(), priority: Math.min(10, entry.priority + 1), }); prefetched++; } } catch (error) { if (this.logger) { this.logger.warn("cache", `Prefetch failed for ${originalKey}:`, error); } else { console.warn(`Prefetch failed for ${originalKey}:`, error); } } } } return prefetched; } /** * Create a cache snapshot for debugging */ createSnapshot() { const snapshot = { timestamp: Date.now(), stats: this.getUltraStats, entries: [], hotKeys: this.stats.hotKeys, coldKeys: this.stats.coldKeys, tagStats: Object.fromEntries(this.stats.tagStats), }; const keys = this.lru.getKeys().slice(0, 100); // Sample first 100 entries for (const hashedKey of keys) { const node = this.lru.getNode(hashedKey); if (node?.entry) { const entry = node.entry; const originalKey = this.findOriginalKey(hashedKey); snapshot.entries.push({ key: originalKey, size: entry.size, accessCount: entry.accessCount, hotness: entry.hotness, priority: entry.priority, tags: Array.from(entry.tags), compressed: entry.compressed, encrypted: !!(entry.iv && entry.authTag), expiresIn: Math.max(0, entry.expiresAt - Date.now()), }); } } return snapshot; } /** * Validate cache integrity */ async validateIntegrity() { const result = { valid: 0, invalid: 0, errors: [] }; const keys = this.lru.getKeys(); for (const hashedKey of keys) { const node = this.lru.getNode(hashedKey); if (!node?.entry) continue; const entry = node.entry; const originalKey = this.findOriginalKey(hashedKey); try { // Try to decrypt and decompress await this.decryptAndDecompress(entry); result.valid++; } catch (error) { result.invalid++; result.errors.push(`${originalKey}: ${error}`); // Remove corrupted entry this.lru.delete(hashedKey); this.cleanupIndexes(hashedKey, entry); this.stats.totalSize -= entry.size; this.stats.entryCount--; } } return result; } /** * Enhanced delete with pattern matching */ delete(key) { try { const hashedKey = this.validateAndHashKey(key); const node = this.lru.getNode(hashedKey); if (node?.entry) { const entry = node.entry; this.lru.delete(hashedKey); this.cleanupIndexes(hashedKey, entry); this.stats.totalSize -= entry.size; this.stats.entryCount--; this.keyHashMap.delete(key); return true; } return false; } catch (error) { console.error("Delete error:", error); return false; } } /** * Delete with pattern (supports wildcards) */ deletePattern(pattern) { const regex = new RegExp(pattern.replace(/\*/g, ".*")); let deleted = 0; for (const [originalKey] of this.keyHashMap.entries()) { if (regex.test(originalKey)) { if (this.delete(originalKey)) { deleted++; } } } return deleted; } /** * Check if key exists */ has(key) { try { const hashedKey = this.validateAndHashKey(key); const node = this.lru.getNode(hashedKey); if (!node?.entry) return false; if (Date.now() > node.entry.expiresAt) { this.delete(key); return false; } return true; } catch (error) { return false; } } /** * Clear all entries */ clear() { this.lru.clear(); this.keyHashMap.clear(); this.tagIndex.clear(); this.accessPatterns.clear(); this.rateLimiter.clear(); this.priorityQueues.forEach((queue) => queue.clear()); this.stats = { hits: 0, misses: 0, evictions: 0, totalSize: 0, entryCount: 0, hitRate: 0, memoryUsage: { used: 0, limit: cache_config.CONFIG.MAX_CACHE_SIZE_MB * 1024 * 1024, percentage: 0, }, totalAccesses: 0, size: 0, capacity: cache_config.CONFIG.MAX_ENTRIES, averageAccessTime: 0, compressionRatio: 0, encryptionOverhead: 0, hotKeys: [], coldKeys: [], tagStats: new Map(), }; } /** * Get cache size */ get size() { return { entries: this.lru.getSize(), bytes: this.stats.totalSize, }; } /** * Graceful shutdown */ async shutdown() { // Clear all timers if (this.cleanupTimer) clearInterval(this.cleanupTimer); if (this.keyRotationTimer) clearInterval(this.keyRotationTimer); if (this.securityTimer) clearInterval(this.securityTimer); if (this.performanceTimer) clearInterval(this.performanceTimer); if (this.hotnessDecayTimer) clearInterval(this.hotnessDecayTimer); // Final cleanup this.cleanup(); // Export data if needed (for persistence) this.emit("shutdown", { timestamp: Date.now(), finalStats: this.getUltraStats, }); // Clear all data this.clear(); this.removeAllListeners(); } } exports.UltraFastSecureInMemoryCache = UFSIMC; exports.default = UFSIMC; //# sourceMappingURL=UFSIMC.js.map