shohan
Version:
Production-grade utilities and tools by Shohan - Starting with Smart Cache System for Next.js applications
3 lines • 23.1 kB
JavaScript
/* Shohan Cache - Smart Cache System */
"use strict";var F=Object.create;var I=Object.defineProperty;var P=Object.getOwnPropertyDescriptor;var B=Object.getOwnPropertyNames;var U=Object.getPrototypeOf,k=Object.prototype.hasOwnProperty;var z=(n,e)=>{for(var t in e)I(n,t,{get:e[t],enumerable:!0})},D=(n,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of B(e))!k.call(n,r)&&r!==t&&I(n,r,{get:()=>e[r],enumerable:!(s=P(e,r))||s.enumerable});return n};var A=(n,e,t)=>(t=n!=null?F(U(n)):{},D(e||!n||!n.__esModule?I(t,"default",{value:n,enumerable:!0}):t,n)),G=n=>D(I({},"__esModule",{value:!0}),n);var V={};z(V,{CACHE_CONFIG:()=>i,PerformanceMetrics:()=>T,ProductionEZCache:()=>g,ProductionMemoryCache:()=>C,ProductionTrafficTracker:()=>R,ResilientRedis:()=>E,cache:()=>L,default:()=>K});module.exports=G(V);var v=process.env.NODE_ENV||"production",d=v==="development",h=v==="production",O=v==="test";function x(){try{require.resolve("@upstash/redis");let n=!!process.env.UPSTASH_REDIS_REST_URL,e=!!process.env.UPSTASH_REDIS_REST_TOKEN,t=process.env.CACHE_DISABLE_REDIS==="true";return n&&e&&!t}catch{return!1}}function $(){let n=x();return{enableRedis:n&&process.env.CACHE_ENABLE_REDIS!=="false",redisUrl:process.env.UPSTASH_REDIS_REST_URL||"",redisToken:process.env.UPSTASH_REDIS_REST_TOKEN||"",enableMemory:process.env.CACHE_ENABLE_MEMORY!=="false",memorySize:d?200:h?5e3:1e3,enableLogging:process.env.CACHE_ENABLE_LOGGING==="true"||d,enableMetrics:process.env.CACHE_ENABLE_METRICS!=="false"&&(h||O),enableTrafficDetection:process.env.CACHE_ENABLE_TRAFFIC!=="false",enableCircuitBreaker:process.env.CACHE_ENABLE_CIRCUIT_BREAKER!=="false"&&n,trafficThreshold:d?3:h?100:20,defaultTtl:d?60:h?600:180,cleanupInterval:d?2*60*1e3:h?10*60*1e3:5*60*1e3,cacheStrategy:process.env.CACHE_STRATEGY||(h?"balanced":d?"aggressive":"conservative")}}function q(n){switch(n.cacheStrategy){case"aggressive":return{...n,trafficThreshold:1,defaultTtl:h?900:300,memorySize:n.memorySize*1.5,enableMetrics:!0};case"conservative":return{...n,trafficThreshold:h?200:50,defaultTtl:h?300:60,memorySize:Math.floor(n.memorySize*.7),enableMetrics:h};case"memory-only":return{...n,enableRedis:!1,memorySize:n.memorySize*2,trafficThreshold:5};case"balanced":default:return n}}var Y=$(),c=q(Y),i={ENVIRONMENT:v,IS_DEV:d,IS_PROD:h,IS_TEST:O,ENABLE_MEMORY:c.enableMemory,ENABLE_REDIS:c.enableRedis,REDIS_URL:c.redisUrl,REDIS_TOKEN:c.redisToken,REDIS_TIMEOUT:parseInt(process.env.CACHE_REDIS_TIMEOUT||"5000"),REDIS_RETRY_ATTEMPTS:parseInt(process.env.CACHE_REDIS_RETRIES||"3"),ENABLE_CIRCUIT_BREAKER:c.enableCircuitBreaker,CIRCUIT_FAILURE_THRESHOLD:parseInt(process.env.CACHE_CIRCUIT_THRESHOLD||"3"),CIRCUIT_RESET_TIMEOUT:parseInt(process.env.CACHE_CIRCUIT_RESET||"30000"),MEMORY_SIZE:c.memorySize,MEMORY_TTL_MAX:d?120:h?300:180,TRAFFIC_THRESHOLD:c.trafficThreshold,DEFAULT_TTL:c.defaultTtl,CLEANUP_INTERVAL:c.cleanupInterval,ENABLE_LOGGING:c.enableLogging,ENABLE_METRICS:c.enableMetrics,ENABLE_TRAFFIC_DETECTION:c.enableTrafficDetection,MAX_VALUE_SIZE:parseInt(process.env.CACHE_MAX_VALUE_SIZE||"1048576"),WINDOW_MS:parseInt(process.env.CACHE_WINDOW_MS||"60000"),TRACKER_CLEANUP_MS:parseInt(process.env.CACHE_TRACKER_CLEANUP||"300000"),CACHE_STRATEGY:c.cacheStrategy,CACHE_MODE:c.enableRedis&&c.enableMemory?"HYBRID":c.enableMemory&&!c.enableRedis?"MEMORY_ONLY":!c.enableMemory&&c.enableRedis?"REDIS_ONLY":"DISABLED"},b={isRedisEnabled(){return i.ENABLE_REDIS&&!!i.REDIS_URL},isMemoryEnabled(){return i.ENABLE_MEMORY},getCacheModeDescription(){switch(i.CACHE_MODE){case"HYBRID":return"Full 3-layer caching: Memory \u2192 Redis \u2192 Database";case"MEMORY_ONLY":return"2-layer caching: Memory \u2192 Database (Redis disabled/unavailable)";case"REDIS_ONLY":return"2-layer caching: Redis \u2192 Database (Memory disabled)";case"DISABLED":return"Direct database access (All caching disabled)";default:return"Unknown cache mode"}},getConfigSummary(){return{mode:i.CACHE_MODE,strategy:i.CACHE_STRATEGY,environment:i.ENVIRONMENT,redisEnabled:this.isRedisEnabled(),memoryEnabled:this.isMemoryEnabled(),loggingEnabled:i.ENABLE_LOGGING,metricsEnabled:i.ENABLE_METRICS,trafficDetection:i.ENABLE_TRAFFIC_DETECTION,trafficThreshold:i.TRAFFIC_THRESHOLD,defaultTtl:i.DEFAULT_TTL,memorySize:i.MEMORY_SIZE}}};var C=class{constructor(){this.cache=new Map;this.totalSize=0;this.lastCleanup=Date.now()}set(e,t,s){try{let r=this.estimateSize(t);if(r>i.MAX_VALUE_SIZE)return!1;for(this.cleanupExpired();this.cache.size>=i.MEMORY_SIZE&&this.evictLRU(););let a={data:t,expires:Date.now()+Math.min(s,i.MEMORY_TTL_MAX)*1e3,lastAccess:Date.now(),hitCount:1,size:r,createdAt:Date.now()},o=this.cache.get(e);return o&&(this.totalSize-=o.size),this.cache.set(e,a),this.totalSize+=r,!0}catch{return!1}}get(e){let t=this.cache.get(e);if(!t)return null;let s=Date.now();return s>t.expires?(this.delete(e),null):(t.lastAccess=s,t.hitCount++,t.data)}delete(e){let t=this.cache.get(e);return t?(this.totalSize-=t.size,this.cache.delete(e)):!1}clear(){this.cache.clear(),this.totalSize=0}size(){return this.cache.size}evictLRU(){if(this.cache.size===0)return!1;let e="",t=Number.MAX_SAFE_INTEGER,s=Date.now();for(let[r,a]of this.cache.entries()){let o=s-a.createdAt,l=s-a.lastAccess,p=a.hitCount,m=a.size/1024,f=l/1e3+o/1e4+m-p*100;f<t&&(t=f,e=r)}return e?(this.delete(e),!0):!1}cleanupExpired(){let e=Date.now();if(e-this.lastCleanup<1e4)return;let t=[];for(let[s,r]of this.cache.entries())e>r.expires&&t.push(s);t.forEach(s=>this.delete(s)),this.lastCleanup=e}estimateSize(e){try{return JSON.stringify(e).length*2}catch{return 1024}}getStats(){let e=Date.now(),t=Array.from(this.cache.values());return{size:this.cache.size,maxSize:i.MEMORY_SIZE,totalSizeKB:Math.round(this.totalSize/1024),utilization:Math.round(this.cache.size/i.MEMORY_SIZE*100),expiredItems:t.filter(s=>e>s.expires).length,avgHitCount:t.length>0?Math.round(t.reduce((s,r)=>s+r.hitCount,0)/t.length):0,oldestItem:t.length>0?Math.round((e-Math.min(...t.map(s=>s.createdAt)))/1e3):0}}};var R=class{constructor(){this.requests=new Map;this.lastGlobalCleanup=Date.now()}track(e){let t=Date.now(),s=this.requests.get(e);return s||(s={timestamps:[],lastCleanup:t,totalRequests:0},this.requests.set(e,s)),t-s.lastCleanup>i.TRACKER_CLEANUP_MS&&(this.cleanupEndpoint(e,s),s.lastCleanup=t),t-this.lastGlobalCleanup>i.TRACKER_CLEANUP_MS*2&&(this.globalCleanup(),this.lastGlobalCleanup=t),s.timestamps=s.timestamps.filter(r=>t-r<i.WINDOW_MS),s.timestamps.push(t),s.totalRequests++,s.timestamps.length}isHighTraffic(e,t){let s=this.track(e),r=t||i.TRAFFIC_THRESHOLD;return s>=r}getCurrentCount(e){let t=this.requests.get(e);if(!t)return 0;let s=Date.now();return t.timestamps.filter(a=>s-a<i.WINDOW_MS).length}cleanupEndpoint(e,t){let s=Date.now();t.timestamps=t.timestamps.filter(r=>s-r<i.WINDOW_MS)}globalCleanup(){let e=Date.now(),t=[];for(let[s,r]of this.requests.entries())(r.timestamps.length===0||r.timestamps.length>0&&e-r.timestamps[r.timestamps.length-1]>i.TRACKER_CLEANUP_MS)&&t.push(s);t.forEach(s=>this.requests.delete(s))}getStats(){let e=Date.now(),t={};for(let[s,r]of this.requests.entries()){let a=r.timestamps.filter(o=>e-o<i.WINDOW_MS);t[s]={currentRequests:a.length,totalRequests:r.totalRequests,isHighTraffic:a.length>=i.TRAFFIC_THRESHOLD,lastActivity:r.timestamps.length>0?new Date(r.timestamps[r.timestamps.length-1]).toISOString():null}}return{endpoints:t,trackedEndpoints:this.requests.size,trafficThreshold:i.TRAFFIC_THRESHOLD}}clear(){this.requests.clear(),this.lastGlobalCleanup=Date.now()}getTrackedEndpointsCount(){return this.requests.size}};var E=class{constructor(){this.redis=null;this.isConnected=!1;this.circuitOpen=!1;this.failureCount=0;this.lastFailure=0;this.connectionAttempts=0;this.lastConnectionAttempt=0;this.redisAvailable=!1;this.healthCheckInterval=null;this.reconnectTimeout=null;this.operationMetrics={totalOperations:0,successfulOperations:0,failedOperations:0,avgResponseTime:0,lastOperationTime:0};this.status={available:!1,connected:!1,circuitOpen:!1,failures:0,lastFailure:0,mode:"unavailable"};this.checkRedisAvailability(),this.redisAvailable&&(this.initializeRedis(),this.startHealthMonitoring()),process.on("exit",()=>this.cleanup()),process.on("SIGINT",()=>this.cleanup()),process.on("SIGTERM",()=>this.cleanup())}checkRedisAvailability(){try{if(require.resolve("@upstash/redis"),!i.ENABLE_REDIS){i.ENABLE_LOGGING&&console.log("[REDIS] Disabled in configuration");return}if(!i.REDIS_URL||!i.REDIS_TOKEN){i.ENABLE_LOGGING&&console.log("[REDIS] Credentials not provided - running in memory-only mode");return}this.redisAvailable=!0}catch(e){i.ENABLE_LOGGING&&(console.error("[REDIS] Error checking availability:",e),console.log("[REDIS] Package not installed - graceful fallback to memory-only mode")),this.redisAvailable=!1}}async initializeRedis(){if(this.redisAvailable&&!(this.lastConnectionAttempt&&Date.now()-this.lastConnectionAttempt<5e3)){this.lastConnectionAttempt=Date.now(),this.connectionAttempts++;try{let e=null;try{e=await import("@upstash/redis")}catch{this.log("[REDIS] @upstash/redis package not found - running in memory-only mode"),this.redis=null,this.status.available=!1,this.status.mode="unavailable",this.redisAvailable=!1;return}let{Redis:t}=e;this.redis=new t({url:i.REDIS_URL,token:i.REDIS_TOKEN,retry:{retries:3,backoff:a=>Math.exp(a)*50},automaticDeserialization:!0});let s=this.redis.ping(),r=new Promise((a,o)=>setTimeout(()=>o(new Error("Connection timeout")),i.REDIS_TIMEOUT));await Promise.race([s,r]),this.isConnected=!0,this.resetCircuit(),this.updateStatus(),this.log("[REDIS] Connected successfully")}catch(e){this.redis=null,this.isConnected=!1,this.recordFailure(),this.updateStatus(),this.log(`[REDIS] Connection failed (attempt ${this.connectionAttempts}): ${e instanceof Error?e.message:"Unknown error"}`),this.connectionAttempts<5&&this.scheduleReconnection()}}}async get(e){if(!this.isAvailable())return null;let t=Date.now();this.operationMetrics.totalOperations++;try{let s=await Promise.race([this.redis.get(e),new Promise((r,a)=>setTimeout(()=>a(new Error("Timeout")),i.REDIS_TIMEOUT))]);return this.recordSuccessfulOperation(t),s}catch(s){return this.recordFailedOperation(t),this.recordFailure(),this.log(`[REDIS] Get operation failed for key "${e}": ${s instanceof Error?s.message:"Unknown error"}`),null}}async setex(e,t,s){if(!this.isAvailable())return!1;try{return await Promise.race([this.redis.setex(e,t,s),new Promise((r,a)=>setTimeout(()=>a(new Error("Timeout")),i.REDIS_TIMEOUT))]),this.resetCircuit(),!0}catch{return this.recordFailure(),!1}}async del(e){if(!this.isAvailable())return!1;try{return await this.redis.del(e),this.resetCircuit(),!0}catch{return this.recordFailure(),!1}}isAvailable(){if(!this.redisAvailable||!this.redis)return!1;if(!i.ENABLE_CIRCUIT_BREAKER)return!0;if(this.circuitOpen){if(Date.now()-this.lastFailure<i.CIRCUIT_RESET_TIMEOUT)return!1;this.circuitOpen=!1,this.failureCount=Math.max(0,this.failureCount-1)}return!0}recordFailure(){this.failureCount++,this.lastFailure=Date.now(),this.failureCount>=i.CIRCUIT_FAILURE_THRESHOLD&&(this.circuitOpen=!0,this.isConnected=!1,i.ENABLE_LOGGING&&console.log("[REDIS] Circuit breaker opened - too many failures"))}resetCircuit(){(this.failureCount>0||this.circuitOpen)&&(this.failureCount=0,this.circuitOpen=!1,this.isConnected=!0,i.ENABLE_LOGGING&&console.log("[REDIS] Circuit breaker reset - connection restored"))}getConnectionStatus(){return{available:this.redisAvailable,connected:this.isConnected,circuitOpen:this.circuitOpen,failures:this.failureCount,lastFailure:this.lastFailure,mode:this.redisAvailable?this.circuitOpen?"circuit-open":this.isConnected?"connected":"disconnected":"unavailable"}}async forceReconnect(){return this.redisAvailable?(this.resetCircuit(),await this.initializeRedis(),this.isConnected):!1}async getHealthInfo(){if(!this.isAvailable())return{available:this.redisAvailable,connected:!1,error:this.redisAvailable?"Circuit breaker open":"Redis not available"};try{let e=Date.now();return await this.redis.ping(),{available:!0,connected:!0,latency:Date.now()-e}}catch(e){return{available:this.redisAvailable,connected:!1,error:e instanceof Error?e.message:"Unknown error"}}}log(e){i.ENABLE_LOGGING&&console.log(`[${new Date().toISOString()}] ${e}`)}updateStatus(){this.status={available:this.redisAvailable,connected:this.isConnected,circuitOpen:this.circuitOpen,failures:this.failureCount,lastFailure:this.lastFailure,mode:this.redisAvailable?this.circuitOpen?"circuit-open":this.isConnected?"connected":"disconnected":"unavailable"}}scheduleReconnection(){this.reconnectTimeout&&clearTimeout(this.reconnectTimeout);let e=Math.min(5e3*Math.pow(2,this.connectionAttempts-1),3e4);this.reconnectTimeout=setTimeout(()=>{this.log(`[REDIS] Attempting reconnection (${this.connectionAttempts+1}/5)`),this.initializeRedis()},e)}recordSuccessfulOperation(e){this.operationMetrics.successfulOperations++;let t=Date.now()-e;this.operationMetrics.lastOperationTime=t,this.operationMetrics.avgResponseTime=(this.operationMetrics.avgResponseTime*(this.operationMetrics.successfulOperations-1)+t)/this.operationMetrics.successfulOperations}recordFailedOperation(e){this.operationMetrics.failedOperations++,this.operationMetrics.lastOperationTime=Date.now()-e}startHealthMonitoring(){!this.redisAvailable||this.healthCheckInterval||(this.healthCheckInterval=setInterval(async()=>{if(this.isConnected&&this.redis)try{await Promise.race([this.redis.ping(),new Promise((e,t)=>setTimeout(()=>t(new Error("Health check timeout")),5e3))]),this.isConnected||(this.log("[REDIS] Health check passed - connection restored"),this.isConnected=!0,this.resetCircuit(),this.updateStatus())}catch(e){this.log(`[REDIS] Health check failed: ${e instanceof Error?e.message:"Unknown error"}`),this.isConnected=!1,this.recordFailure(),this.updateStatus()}else!this.isConnected&&this.redisAvailable&&!this.circuitOpen&&(this.log("[REDIS] Health check: attempting reconnection"),this.initializeRedis())},3e4))}cleanup(){this.healthCheckInterval&&(clearInterval(this.healthCheckInterval),this.healthCheckInterval=null),this.reconnectTimeout&&(clearTimeout(this.reconnectTimeout),this.reconnectTimeout=null),this.redis&&this.isConnected&&(this.log("[REDIS] Cleaning up connection"),this.redis=null,this.isConnected=!1)}getMetrics(){let e=this.operationMetrics.totalOperations>0?this.operationMetrics.successfulOperations/this.operationMetrics.totalOperations*100:0;return{...this.operationMetrics,successRate:Math.round(e*100)/100}}async exists(e){if(!this.isAvailable())return!1;try{return await this.redis.exists(e)===1}catch{return this.recordFailure(),!1}}async ttl(e){if(!this.isAvailable())return-1;try{let t=await this.redis.ttl(e);return typeof t=="number"?t:-1}catch{return this.recordFailure(),-1}}async keys(e){if(!this.isAvailable())return[];try{let t=await this.redis.keys(e);return Array.isArray(t)?t:[]}catch{return this.recordFailure(),[]}}},_=null;function Z(){return _||(_=new E),_}var se=Z();var T=class{constructor(){this.metrics={hits:0,misses:0,errors:0,totalRequests:0,avgResponseTime:0,lastReset:Date.now()};this.responseTimes=[]}recordHit(e){i.ENABLE_METRICS&&(this.metrics.hits++,this.metrics.totalRequests++,this.recordResponseTime(e))}recordMiss(e){i.ENABLE_METRICS&&(this.metrics.misses++,this.metrics.totalRequests++,this.recordResponseTime(e))}recordError(){i.ENABLE_METRICS&&(this.metrics.errors++,this.metrics.totalRequests++)}recordResponseTime(e){this.responseTimes.push(e),this.responseTimes.length>1e3&&(this.responseTimes=this.responseTimes.slice(-1e3)),this.metrics.avgResponseTime=this.responseTimes.reduce((t,s)=>t+s,0)/this.responseTimes.length}getStats(){let e=this.metrics.totalRequests>0?Math.round(this.metrics.hits/this.metrics.totalRequests*100):0,t=this.metrics.totalRequests>0?Math.round(this.metrics.errors/this.metrics.totalRequests*100):0;return{...this.metrics,hitRate:e,errorRate:t,avgResponseTime:Math.round(this.metrics.avgResponseTime*100)/100}}getResponseTimeStats(){if(this.responseTimes.length===0)return{min:0,max:0,median:0,p95:0,p99:0};let e=[...this.responseTimes].sort((s,r)=>s-r),t=e.length;return{min:e[0],max:e[t-1],median:e[Math.floor(t/2)],p95:e[Math.floor(t*.95)],p99:e[Math.floor(t*.99)]}}reset(){this.metrics={hits:0,misses:0,errors:0,totalRequests:0,avgResponseTime:0,lastReset:Date.now()},this.responseTimes=[]}getEfficiencyScore(){if(this.metrics.totalRequests===0)return 0;let e=this.metrics.hits/this.metrics.totalRequests*100,t=this.metrics.errors/this.metrics.totalRequests*100,s=Math.max(0,100-this.metrics.avgResponseTime/10);return Math.round(e*.6+(100-t)*.3+s*.1)}isEnabled(){return i.ENABLE_METRICS}};var g=class{constructor(){this.memory=null;this.traffic=null;this.redis=null;this.metrics=null;this.cleanupInterval=null;this.log(`\u{1F680} Production EZ Cache v3 starting (${i.ENVIRONMENT})...`),this.log(`\u{1F4CB} Cache Mode: ${i.CACHE_MODE}`),this.log(`\u{1F3AF} Strategy: ${i.CACHE_STRATEGY}`),this.initializeComponents(),this.setupCleanup(),this.logConfiguration(),this.log(`\u2705 Production EZ Cache ready! ${b.getCacheModeDescription()}`)}initializeComponents(){i.ENABLE_MEMORY&&(this.memory=new C,this.log(`\u{1F9E0} Memory cache initialized (${i.MEMORY_SIZE} items)`)),i.ENABLE_REDIS&&(this.redis=new E,this.log("\u{1F4BE} Redis client initialized")),i.ENABLE_TRAFFIC_DETECTION&&(this.traffic=new R,this.log("\u{1F4CA} Traffic tracking enabled")),i.ENABLE_METRICS&&(this.metrics=new T,this.log("\u{1F4C8} Performance metrics enabled"))}getSmartTrafficThreshold(e){return e<=60?Math.max(3,Math.floor(i.TRAFFIC_THRESHOLD*.1)):e<=600?Math.max(10,Math.floor(i.TRAFFIC_THRESHOLD*.3)):i.TRAFFIC_THRESHOLD}async fetch(e,t,s){var f;let r=Date.now(),a=`ez:${e}`,o;if(typeof s=="number")o={ttl:s,minTrafficCount:this.getSmartTrafficThreshold(s),forceCaching:!1};else if(s&&typeof s=="object"){let u=s.ttl||i.DEFAULT_TTL;o={ttl:u,minTrafficCount:s.minTrafficCount??this.getSmartTrafficThreshold(u),forceCaching:s.forceCaching??!1}}else o={ttl:i.DEFAULT_TTL,minTrafficCount:i.TRAFFIC_THRESHOLD,forceCaching:!1};let l=o.ttl,p=i.ENABLE_REDIS?l*10:l,m=o.minTrafficCount;try{if(i.CACHE_MODE==="DISABLED")return this.log(`\u{1F6AB} Cache disabled - direct database fetch for "${e}"`),await t();let u=o.forceCaching||!0;if(i.ENABLE_TRAFFIC_DETECTION&&this.traffic&&!o.forceCaching&&(u=this.traffic.isHighTraffic(e,m),!u)){this.log(`\u{1F4CA} Low traffic "${e}" (${this.traffic.getCurrentCount(e)}/${m}) - direct database fetch`);let S=await t();return this.metrics&&this.metrics.recordMiss(Date.now()-r),S}return this.log(`\u{1F525} ${u?"High traffic":"Caching"} "${e}" (${((f=this.traffic)==null?void 0:f.getCurrentCount(e))||0}/${m}) - ${i.CACHE_MODE} mode activated`),await this.fetchFromCacheLayers(a,t,l,p,r)}catch(u){return this.log(`\u274C Cache error for "${e}":`,u),this.metrics&&this.metrics.recordError(),await t()}}async fetchFromCacheLayers(e,t,s,r,a){if(this.memory&&i.ENABLE_MEMORY){let l=this.memory.get(e);if(l)return this.log(`\u26A1 Memory cache hit: ${e} (~2ms)`),this.metrics&&this.metrics.recordHit(Date.now()-a),l}if(this.redis&&i.ENABLE_REDIS){let l=await this.redis.get(e);if(l)return this.log(`\u{1F4BE} Redis cache hit: ${e} (~25ms)`),this.memory&&this.memory.set(e,l,Math.min(s,i.MEMORY_TTL_MAX)),this.metrics&&this.metrics.recordHit(Date.now()-a),l}this.log(`\u{1F50D} Cache miss "${e}" - fetching from database (~200ms)`);let o=await t();return await this.storeInCacheLayers(e,o,s,r),this.metrics&&this.metrics.recordMiss(Date.now()-a),o}async storeInCacheLayers(e,t,s,r){let a=[];if(this.memory&&i.ENABLE_MEMORY){let o=this.memory.set(e,t,Math.min(s,i.MEMORY_TTL_MAX));a.push(`Memory=${o}/${s}s`)}if(this.redis&&i.ENABLE_REDIS){let o=await this.redis.setex(e,r,t);a.push(`Redis=${o}/${r}s`)}a.length>0&&this.log(`\u{1F4BE} Cached "${e}": ${a.join(", ")} (Memory: ${s}s, Redis: ${r}s)`)}async clear(e){var a,o;let t=`ez:${e}`,s=((a=this.memory)==null?void 0:a.delete(t))||!1,r=await((o=this.redis)==null?void 0:o.del(t))||!1;this.log(`\u{1F5D1}\uFE0F Cleared cache "${e}": Memory=${s}, Redis=${r}`)}async clearAll(){var e,t;(e=this.memory)==null||e.clear(),(t=this.traffic)==null||t.clear(),this.log("\u{1F9F9} All caches cleared")}async forceRefresh(e,t,s){return await this.clear(e),this.fetch(e,t,s)}getStats(){var a,o,l;let e=((a=this.memory)==null?void 0:a.getStats())||{size:0,maxSize:0,totalSizeKB:0,utilization:0,expiredItems:0,avgHitCount:0,oldestItem:0},t=((o=this.traffic)==null?void 0:o.getStats())||{endpoints:{},trackedEndpoints:0,trafficThreshold:0},s=((l=this.redis)==null?void 0:l.getConnectionStatus())||{available:!1,connected:!1,circuitOpen:!1,failures:0,lastFailure:0,mode:"unavailable"},r=i.ENABLE_METRICS&&this.metrics?this.metrics.getStats():null;return{system:{environment:i.ENVIRONMENT,version:"3.0.0",uptime:Date.now()-((r==null?void 0:r.lastReset)||Date.now()),cacheStrategy:b.getCacheModeDescription()},memory:{...e,enabled:i.ENABLE_MEMORY},redis:{...s,enabled:i.ENABLE_REDIS,circuitBreakerEnabled:i.ENABLE_CIRCUIT_BREAKER},traffic:t,performance:r,config:{trafficThreshold:i.TRAFFIC_THRESHOLD,defaultTtl:i.DEFAULT_TTL,memoryTtlMax:i.MEMORY_TTL_MAX,memorySize:i.MEMORY_SIZE,maxValueSize:i.MAX_VALUE_SIZE}}}getStatus(){let e=this.getStats();return{healthy:e.redis.connected||e.memory.enabled,memoryUtilization:e.memory.utilization,redisConnected:e.redis.connected,trackedEndpoints:e.traffic.trackedEndpoints,efficiencyScore:e.performance&&this.metrics?this.metrics.getEfficiencyScore():void 0}}async test(){var s,r,a,o,l,p,m;let e="ez:test:"+Date.now(),t={test:!0,timestamp:Date.now()};try{let f=((s=this.memory)==null?void 0:s.set(e,t,60))||!1,u=((r=this.memory)==null?void 0:r.get(e))||null,S=f&&!!u,N=await((a=this.redis)==null?void 0:a.setex(e,60,t))||!1,w=await((o=this.redis)==null?void 0:o.get(e))||null,M=N&&!!w,y=(((l=this.traffic)==null?void 0:l.track("test"))||0)>0;(p=this.memory)==null||p.delete(e),await((m=this.redis)==null?void 0:m.del(e));let H=S&&(M||!i.ENABLE_REDIS)&&y;return{memory:S,redis:M,traffic:y,overall:H}}catch{return{memory:!1,redis:!1,traffic:!1,overall:!1}}}setupCleanup(){this.cleanupInterval&&clearInterval(this.cleanupInterval),this.cleanupInterval=setInterval(()=>{this.log("\u{1F9F9} Running periodic cleanup...")},i.CLEANUP_INTERVAL),process.on("exit",()=>{this.cleanupInterval&&clearInterval(this.cleanupInterval)})}logConfiguration(){this.log(`\u{1F4CA} Traffic threshold: ${i.TRAFFIC_THRESHOLD} req/min`),this.log(`\u23F1\uFE0F Default TTL: ${i.DEFAULT_TTL}s`),this.log(`\u{1F9E0} Memory size: ${i.MEMORY_SIZE} items`),this.log(`\u{1F4BE} Redis: ${i.ENABLE_REDIS?"enabled":"disabled"}`),this.log(`\u{1F527} Circuit breaker: ${i.ENABLE_CIRCUIT_BREAKER?"enabled":"disabled"}`),this.log(`\u{1F4C8} Metrics: ${i.ENABLE_METRICS?"enabled":"disabled"}`)}log(e,...t){i.ENABLE_LOGGING&&console.log(`[PROD-EZ-CACHE] ${e}`,...t)}};var L=new g,K=L;0&&(module.exports={CACHE_CONFIG,PerformanceMetrics,ProductionEZCache,ProductionMemoryCache,ProductionTrafficTracker,ResilientRedis,cache});
//# sourceMappingURL=index.js.map