@devbro/neko-cache 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { Cache, cacheOptions } from './cache.mjs';
2
2
  export { CacheProviderInterface } from './CacheProviderInterface.mjs';
3
- export { RedisCacheProvider } from './providers/RedisCacheProvider.mjs';
3
+ export { RedisCacheProvider, RedisCacheProviderConfig } from './providers/RedisCacheProvider.mjs';
4
4
  export { FileCacheConfig, FileCacheProvider } from './providers/FileCacheProvider.mjs';
5
5
  export { MemoryCacheConfig, MemoryCacheProvider } from './providers/MemoryCacheProvider.mjs';
6
6
  export { MemcacheCacheProvider, MemcachedConfig } from './providers/MemcacheCacheProvider.mjs';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/cache.mts","../src/providers/RedisCacheProvider.mts","../src/providers/FileCacheProvider.mts","../src/providers/MemoryCacheProvider.mts","../src/providers/MemcacheCacheProvider.mts","../src/providers/DisabledCacheProvider.mts"],"sourcesContent":["export * from './cache.mjs';\nexport * from './CacheProviderInterface.mjs';\nexport * from './providers/index.mjs';\n","import { JSONValue } from '@devbro/neko-helper';\nimport { CacheProviderInterface } from './CacheProviderInterface.mjs';\nimport { createHash } from 'crypto';\n\n/**\n * Options for cache operations.\n */\nexport type cacheOptions = {\n /** Time to live in seconds */\n ttl?: number;\n};\n\n/**\n * Cache class providing a unified interface for various cache providers.\n * Handles key generation, serialization, and common cache operations.\n */\nexport class Cache {\n /**\n * Creates a new Cache instance.\n * @param provider - The cache provider implementation to use\n */\n constructor(private provider: CacheProviderInterface) {}\n\n /**\n * Retrieves a value from the cache.\n * @template T - The expected type of the cached value\n * @param key - The cache key (can be string, number, object, or array)\n * @returns The cached value or undefined if not found or expired\n */\n async get<T>(key: JSONValue): Promise<T | undefined> {\n return this.provider.get(this.generateKey(key)) as Promise<T | undefined>;\n }\n\n /**\n * Stores a value in the cache.\n * @param key - The cache key (can be string, number, object, or array)\n * @param value - The value to cache\n * @param ttl - Time to live in seconds (optional)\n */\n async put(key: JSONValue, value: any, ttl?: number): Promise<void> {\n return this.provider.put(this.generateKey(key), value, ttl);\n }\n\n /**\n * Deletes a value from the cache.\n * @param key - The cache key to delete\n */\n async delete(key: JSONValue): Promise<void> {\n return this.provider.delete(this.generateKey(key));\n }\n\n /**\n * Checks if a key exists in the cache.\n * @param key - The cache key to check\n * @returns True if the key exists and has not expired, false otherwise\n */\n async has(key: JSONValue): Promise<boolean> {\n return this.provider.has(this.generateKey(key));\n }\n\n /**\n * Increments a numeric value in the cache atomically.\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The new value after incrementing\n */\n async increment(key: JSONValue, amount: number = 1): Promise<number> {\n return this.provider.increment(this.generateKey(key), amount);\n }\n\n /**\n * Gets a value from cache or executes callback and caches the result.\n * This is useful for caching expensive operations.\n * @template T - The expected type of the value\n * @param key - The cache key\n * @param callback - Function to execute if cache miss occurs\n * @param options - Cache options including TTL (default: 3600 seconds)\n * @returns The cached value or the result of the callback\n */\n async remember<T>(\n key: JSONValue,\n callback: () => Promise<T>,\n options: cacheOptions = {}\n ): Promise<T> {\n options.ttl = options.ttl ?? 3600; // default TTL 1 hour\n\n const cached = await this.get<T>(key);\n if (cached) {\n return cached;\n }\n\n const result = await callback();\n await this.put(key, result, options.ttl);\n return result;\n }\n\n /**\n * Generates a cache key by serializing and hashing complex keys.\n * Simple string keys under 250 characters are returned as-is.\n * Complex keys (objects, arrays, long strings) are MD5 hashed.\n * @param key - The key to generate a cache key from\n * @returns A string suitable for use as a cache key\n */\n generateKey(key: JSONValue): string {\n if (typeof key === 'string' && key.length <= 250) {\n return key;\n }\n return createHash('md5').update(JSON.stringify(key)).digest('hex');\n }\n}\n","import { createClient, RedisClientOptions, RedisClientType } from 'redis';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONValue, JSONObject } from '@devbro/neko-helper';\n\n/**\n * Redis-based cache provider that stores cache entries in a Redis server.\n * Provides distributed caching with automatic expiration support.\n */\nexport class RedisCacheProvider implements CacheProviderInterface {\n private client: RedisClientType;\n private defaultTTL: number = 3600; // default TTL in seconds\n\n /**\n * Creates a new RedisCacheProvider instance.\n * @param config - Redis client configuration options\n */\n constructor(private config: RedisClientOptions) {\n this.client = this.createRedisClient();\n this.client.connect();\n }\n\n /**\n * Creates a Redis client with the provided configuration.\n * @returns A Redis client instance\n */\n private createRedisClient(): any {\n let rc = createClient(this.config);\n return rc;\n }\n\n /**\n * Ensures the Redis client is connected before performing operations.\n */\n private async ensureConnection(): Promise<void> {\n if (!this.client.isOpen) {\n await this.client.connect();\n }\n }\n\n /**\n * Retrieves a value from the cache.\n * @param key - The cache key\n * @returns The cached value or undefined if not found\n */\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n await this.ensureConnection();\n let rc = this.client.get(key);\n return rc.then((value) => {\n if (value === null || value === undefined) {\n return undefined;\n }\n return JSON.parse(value);\n });\n }\n\n /**\n * Stores a value in the cache.\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds (optional)\n */\n async put(key: string, value: JSONValue | JSONObject, ttl?: number): Promise<void> {\n await this.ensureConnection();\n const serializedValue = JSON.stringify(value);\n ttl = ttl ?? this.defaultTTL;\n if (ttl && ttl > 0) {\n await this.client.setEx(key, ttl, serializedValue);\n } else {\n await this.client.set(key, serializedValue);\n }\n }\n\n /**\n * Deletes a value from the cache.\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {\n await this.ensureConnection();\n await this.client.del(key);\n }\n\n /**\n * Checks if a key exists in the cache.\n * @param key - The cache key to check\n * @returns True if the key exists, false otherwise\n */\n async has(key: string): Promise<boolean> {\n await this.ensureConnection();\n const result = await this.client.exists(key);\n return result === 1;\n }\n\n /**\n * Increments a numeric value in the cache atomically using Redis INCRBY.\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The new value after incrementing\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n await this.ensureConnection();\n // Redis INCRBY is atomic\n return await this.client.incrBy(key, amount);\n }\n}\n","import * as fs from 'fs/promises';\nimport * as path from 'path';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONObject, JSONValue } from '@devbro/neko-helper';\n\n/**\n * Configuration options for the file-based cache provider.\n */\nexport interface FileCacheConfig {\n /** Directory where cache files are stored (default: './cache') */\n cacheDirectory?: string;\n /** Default time to live in milliseconds (default: 3600000) */\n defaultTTL?: number;\n /** Interval in milliseconds for cleanup of expired entries (default: 300000) */\n cleanupInterval?: number;\n}\n\n/**\n * Represents a cached item stored in a file.\n */\ninterface CacheItem {\n /** The cached value */\n value: any;\n /** Timestamp when the item expires (milliseconds since epoch) */\n expiresAt?: number;\n /** Timestamp when the item was created (milliseconds since epoch) */\n createdAt: number;\n}\n\n/**\n * File-based cache provider that stores cache entries as JSON files.\n * Provides persistent caching with automatic cleanup of expired entries.\n */\nexport class FileCacheProvider implements CacheProviderInterface {\n private config: FileCacheConfig = {\n cacheDirectory: path.join(process.cwd(), 'cache'),\n defaultTTL: 3600 * 1000,\n cleanupInterval: 300 * 1000,\n };\n\n private cleanupTimer?: NodeJS.Timeout;\n\n /**\n * Creates a new FileCacheProvider instance.\n * @param config - Configuration options for the cache\n */\n constructor(config: FileCacheConfig = {}) {\n this.config = { ...this.config, ...config };\n\n this.ensureCacheDirectory();\n this.startCleanupTimer();\n }\n\n /**\n * Ensures the cache directory exists, creating it if necessary.\n */\n private async ensureCacheDirectory(): Promise<void> {\n try {\n await fs.access(this.config.cacheDirectory!);\n } catch {\n await fs.mkdir(this.config.cacheDirectory!, { recursive: true });\n }\n }\n\n /**\n * Starts the automatic cleanup timer for expired entries.\n */\n private startCleanupTimer(): void {\n if (this.config.cleanupInterval! > 0) {\n this.cleanupTimer = setInterval(() => {\n this.cleanupExpiredEntries().catch(console.error);\n }, this.config.cleanupInterval!);\n }\n }\n\n /**\n * Stops the automatic cleanup timer.\n */\n private stopCleanupTimer(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined;\n }\n }\n\n /**\n * Generates a safe file path for the given cache key.\n * @param key - The cache key\n * @returns The full file path for the cache entry\n */\n private getFilePath(key: string): string {\n // Create a safe filename from the key\n const safeKey = key.replace(/[^a-z0-9]/gi, '_');\n return path.join(this.config.cacheDirectory!, `${safeKey}.json`);\n }\n\n /**\n * Removes all expired cache entries from the cache directory.\n */\n private async cleanupExpiredEntries(): Promise<void> {\n try {\n const files = await fs.readdir(this.config.cacheDirectory!);\n const now = Date.now();\n\n for (const file of files) {\n if (file.endsWith('.json')) {\n const filePath = path.join(this.config.cacheDirectory!, file);\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const item: CacheItem = JSON.parse(content);\n\n if (item.expiresAt && item.expiresAt < now) {\n await fs.unlink(filePath);\n }\n } catch {\n // If file is corrupted, delete it\n await fs.unlink(filePath).catch(() => {});\n }\n }\n }\n } catch (error) {\n // Ignore cleanup errors\n }\n }\n\n /**\n * Retrieves a value from the cache.\n * @param key - The cache key\n * @returns The cached value or undefined if not found or expired\n */\n async get(key: string): Promise<JSONObject | JSONValue | undefined> {\n const filePath = this.getFilePath(key);\n\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const item: CacheItem = JSON.parse(content);\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n await fs.unlink(filePath).catch(() => {});\n return undefined;\n }\n\n return item.value;\n } catch (error) {\n return undefined;\n }\n }\n\n /**\n * Stores a value in the cache.\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds (optional)\n */\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n const filePath = this.getFilePath(key);\n const now = Date.now();\n const effectiveTTL = ttl ?? this.config.defaultTTL!;\n\n const item: CacheItem = {\n value,\n createdAt: now,\n expiresAt: effectiveTTL > 0 ? now + effectiveTTL * 1000 : undefined,\n };\n\n this.ensureCacheDirectory();\n await fs.writeFile(filePath, JSON.stringify(item), 'utf-8');\n }\n\n /**\n * Deletes a value from the cache.\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {\n const filePath = this.getFilePath(key);\n\n try {\n await fs.unlink(filePath);\n } catch {\n // File doesn't exist, that's fine\n }\n }\n\n /**\n * Checks if a key exists in the cache and has not expired.\n * @param key - The cache key to check\n * @returns True if the key exists and is not expired, false otherwise\n */\n async has(key: string): Promise<boolean> {\n const value = await this.get(key);\n return value !== undefined;\n }\n\n /**\n * Increments a numeric value in the cache atomically using file-based locking.\n * If the key doesn't exist or is expired, it starts from 0.\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The new value after incrementing\n * @throws Error if lock cannot be acquired after maximum retries\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n const filePath = this.getFilePath(key);\n\n // Use a lock file to ensure atomicity\n const lockPath = `${filePath}.lock`;\n\n // Simple file-based locking mechanism\n let lockAcquired = false;\n let retries = 0;\n const maxRetries = 50;\n\n while (!lockAcquired && retries < maxRetries) {\n try {\n // Try to create lock file exclusively\n await fs.writeFile(lockPath, '', { flag: 'wx' });\n lockAcquired = true;\n } catch {\n // Lock exists, wait a bit and retry\n await new Promise((resolve) => setTimeout(resolve, 10));\n retries++;\n }\n }\n\n if (!lockAcquired) {\n throw new Error('Failed to acquire lock for increment operation');\n }\n\n try {\n let currentValue = 0;\n let item: CacheItem | undefined;\n\n // Read current value\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const parsedItem = JSON.parse(content);\n\n // Check if item has expired\n if (parsedItem.expiresAt && parsedItem.expiresAt < Date.now()) {\n item = undefined;\n } else {\n item = parsedItem;\n currentValue = typeof parsedItem.value === 'number' ? parsedItem.value : 0;\n }\n } catch {\n // File doesn't exist or is corrupted, start from 0\n }\n\n // Calculate new value\n const newValue = currentValue + amount;\n\n // Write back with same TTL if it existed\n const now = Date.now();\n const newItem: CacheItem = {\n value: newValue,\n createdAt: item?.createdAt ?? now,\n expiresAt: item?.expiresAt,\n };\n\n await fs.writeFile(filePath, JSON.stringify(newItem), 'utf-8');\n\n return newValue;\n } finally {\n // Release lock\n try {\n await fs.unlink(lockPath);\n } catch {\n // Ignore errors when removing lock file\n }\n }\n }\n}\n","import { JSONObject, JSONValue } from '@devbro/neko-helper';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\n\n/**\n * Configuration options for the in-memory cache provider.\n */\nexport interface MemoryCacheConfig {\n /** Maximum number of items to store in cache (default: 1000) */\n maxSize?: number;\n /** Default time to live in seconds (default: 3600) */\n defaultTTL?: number;\n /** Interval in seconds to run cleanup of expired entries (default: 600) */\n cleanupInterval?: number;\n}\n\n/**\n * Represents a cached item with metadata.\n */\ninterface CacheItem {\n /** The cached value */\n value: any;\n /** Timestamp when the item expires (milliseconds since epoch) */\n expiresAt?: number;\n /** Timestamp when the item was created (milliseconds since epoch) */\n createdAt: number;\n /** Timestamp when the item was last accessed (milliseconds since epoch) */\n lastAccessed: number;\n}\n\n/**\n * In-memory cache provider with LRU eviction and automatic cleanup.\n * Stores cache entries in memory with support for TTL and size limits.\n */\nexport class MemoryCacheProvider implements CacheProviderInterface {\n private cache = new Map<string, CacheItem>();\n private config: MemoryCacheConfig = {\n maxSize: 1000,\n defaultTTL: 3600,\n cleanupInterval: 600, // 10 minutes\n };\n\n private cleanupTimer?: NodeJS.Timeout;\n\n /**\n * Creates a new MemoryCacheProvider instance.\n * @param config - Configuration options for the cache\n */\n constructor(config: MemoryCacheConfig = {}) {\n this.config = { ...this.config, ...config };\n\n this.startCleanupTimer();\n }\n\n /**\n * Starts the automatic cleanup timer for expired entries.\n */\n private startCleanupTimer(): void {\n if (this.config.cleanupInterval! > 0) {\n this.cleanupTimer = setInterval(() => {\n this.cleanupExpiredEntries();\n }, this.config.cleanupInterval! * 1000);\n }\n }\n\n /**\n * Stops the automatic cleanup timer.\n */\n private stopCleanupTimer(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined;\n }\n }\n\n /**\n * Removes all expired entries from the cache.\n */\n private cleanupExpiredEntries(): void {\n const now = Date.now();\n\n for (const [key, item] of this.cache.entries()) {\n if (item.expiresAt && item.expiresAt < now) {\n this.cache.delete(key);\n }\n }\n }\n\n /**\n * Evicts the least recently used item if cache size exceeds maximum.\n */\n private evictLRU(): void {\n if (this.cache.size <= this.config.maxSize!) {\n return;\n }\n\n // Find the least recently accessed item\n let oldestKey: string | null = null;\n let oldestTime = Date.now();\n\n for (const [key, item] of this.cache.entries()) {\n if (item.lastAccessed < oldestTime) {\n oldestTime = item.lastAccessed;\n oldestKey = key;\n }\n }\n\n if (oldestKey) {\n this.cache.delete(oldestKey);\n }\n }\n\n /**\n * Retrieves a value from the cache.\n * @param key - The cache key\n * @returns The cached value or undefined if not found or expired\n */\n async get(key: string): Promise<JSONObject | JSONValue | undefined> {\n const item = this.cache.get(key);\n\n if (!item) {\n return undefined;\n }\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n this.cache.delete(key);\n return undefined;\n }\n\n // Update last accessed time for LRU\n item.lastAccessed = Date.now();\n\n return item.value;\n }\n\n /**\n * Stores a value in the cache.\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds (optional)\n */\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n const now = Date.now();\n const effectiveTTL = ttl ?? this.config.defaultTTL!;\n\n const item: CacheItem = {\n value,\n createdAt: now,\n lastAccessed: now,\n expiresAt: effectiveTTL > 0 ? now + effectiveTTL * 1000 : undefined,\n };\n\n this.cache.set(key, item);\n\n // Evict items if we exceed maxSize\n this.evictLRU();\n }\n\n /**\n * Deletes a value from the cache.\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {\n this.cache.delete(key);\n }\n\n /**\n * Checks if a key exists in the cache and has not expired.\n * @param key - The cache key to check\n * @returns True if the key exists and is not expired, false otherwise\n */\n async has(key: string): Promise<boolean> {\n const item = this.cache.get(key);\n\n if (!item) {\n return false;\n }\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n this.cache.delete(key);\n return false;\n }\n\n return true;\n }\n\n /**\n * Increments a numeric value in the cache atomically.\n * If the key doesn't exist or is expired, it starts from 0.\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The new value after incrementing\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n const item = this.cache.get(key);\n const now = Date.now();\n\n let currentValue = 0;\n\n // Check if item exists and is not expired\n if (item) {\n if (item.expiresAt && item.expiresAt < now) {\n this.cache.delete(key);\n } else {\n // Get current value, ensure it's a number\n currentValue = typeof item.value === 'number' ? item.value : 0;\n }\n }\n\n // Calculate new value\n const newValue = currentValue + amount;\n\n // Store the new value with the same TTL if it existed\n const newItem: CacheItem = {\n value: newValue,\n createdAt: item?.createdAt ?? now,\n lastAccessed: now,\n expiresAt: item?.expiresAt,\n };\n\n this.cache.set(key, newItem);\n\n return newValue;\n }\n}\n","import { CacheProviderInterface } from '@/CacheProviderInterface.mjs';\nimport { JSONValue, JSONObject } from '@devbro/neko-helper';\nimport Memcached from 'memcached';\n\n/**\n * Configuration options for the Memcached cache provider.\n */\nexport interface MemcachedConfig {\n /** Memcached server location(s) */\n location?: Memcached.Location;\n /** Additional Memcached options */\n options?: Memcached.options;\n}\n\n/**\n * Memcached-based cache provider that stores cache entries in a Memcached server.\n * Provides distributed caching with automatic serialization and expiration.\n */\nexport class MemcacheCacheProvider implements CacheProviderInterface {\n private client: Memcached;\n private defaultTTL: number = 3600; // default TTL in seconds\n\n /**\n * Creates a new MemcacheCacheProvider instance.\n * @param config - Memcached configuration options\n */\n constructor(private config: MemcachedConfig = {}) {\n this.client = new Memcached(config.location || 'localhost:11211', config.options || {});\n }\n\n /**\n * Retrieves a value from the cache.\n * @param key - The cache key\n * @returns The cached value or undefined if not found\n */\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n return new Promise((resolve, reject) => {\n this.client.get(key, (err: Error | undefined, data: any) => {\n if (err) {\n reject(err);\n return;\n }\n\n if (data === undefined || data === null) {\n resolve(undefined);\n return;\n }\n\n try {\n // Memcached automatically handles JSON serialization/deserialization\n // but we need to ensure we return the correct type\n resolve(typeof data === 'string' ? JSON.parse(data) : data);\n } catch (parseErr) {\n // If parsing fails, return the raw value\n resolve(data);\n }\n });\n });\n }\n\n /**\n * Stores a value in the cache.\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds (optional)\n */\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n return new Promise((resolve, reject) => {\n const serializedValue = JSON.stringify(value);\n const finalTTL = ttl ?? this.defaultTTL;\n\n this.client.set(key, serializedValue, finalTTL, (err: Error | undefined) => {\n if (err) {\n reject(err);\n return;\n }\n resolve();\n });\n });\n }\n\n /**\n * Deletes a value from the cache.\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {\n return new Promise((resolve, reject) => {\n this.client.del(key, (err: Error | undefined) => {\n if (err) {\n reject(err);\n return;\n }\n resolve();\n });\n });\n }\n\n /**\n * Checks if a key exists in the cache.\n * @param key - The cache key to check\n * @returns True if the key exists, false otherwise\n */\n async has(key: string): Promise<boolean> {\n return new Promise((resolve, reject) => {\n this.client.get(key, (err: Error | undefined, data: any) => {\n if (err) {\n reject(err);\n return;\n }\n resolve(data !== undefined && data !== null);\n });\n });\n }\n\n /**\n * Increments a numeric value in the cache atomically using Memcached's native increment.\n * If the key doesn't exist, it is initialized with the increment amount.\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The new value after incrementing\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n return new Promise((resolve, reject) => {\n // Memcached incr are atomic operations\n this.client.incr(key, amount, (err: any, result: number | boolean) => {\n if (err) {\n reject(err);\n return;\n }\n\n // If key doesn't exist, result will be false\n if (result === false) {\n // Initialize the key with the amount value\n this.client.set(key, amount.toString(), this.defaultTTL, (setErr: Error | undefined) => {\n if (setErr) {\n reject(setErr);\n return;\n }\n resolve(amount);\n });\n } else {\n resolve(result as number);\n }\n });\n });\n }\n}\n","import { createClient, RedisClientOptions, RedisClientType } from 'redis';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONValue, JSONObject } from '@devbro/neko-helper';\n\n/**\n * A cache provider that disables caching entirely.\n * All operations are no-ops, useful for testing or disabling cache in certain environments.\n */\nexport class DisabledCacheProvider implements CacheProviderInterface {\n /**\n * Creates a new DisabledCacheProvider instance.\n * @param config - Configuration object (currently unused)\n */\n constructor(private config = {}) {}\n\n /**\n * Always returns undefined (no caching).\n * @param key - The cache key\n * @returns Always undefined\n */\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n return undefined;\n }\n\n /**\n * Does nothing (no caching).\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds\n */\n async put(key: string, value: JSONValue | JSONObject, ttl?: number): Promise<void> {}\n\n /**\n * Does nothing (no caching).\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {}\n\n /**\n * Always returns false (no caching).\n * @param key - The cache key to check\n * @returns Always false\n */\n async has(key: string): Promise<boolean> {\n return false;\n }\n\n /**\n * Returns the increment amount as if starting from 0 (no caching).\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The increment amount\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n // Disabled cache always returns the increment amount as if starting from 0\n return amount;\n }\n}\n"],"mappings":"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","names":["Memcached"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/cache.mts","../src/providers/RedisCacheProvider.mts","../src/providers/FileCacheProvider.mts","../src/providers/MemoryCacheProvider.mts","../src/providers/MemcacheCacheProvider.mts","../src/providers/DisabledCacheProvider.mts"],"sourcesContent":["export * from './cache.mjs';\nexport * from './CacheProviderInterface.mjs';\nexport * from './providers/index.mjs';\n","import { JSONValue } from '@devbro/neko-helper';\nimport { CacheProviderInterface } from './CacheProviderInterface.mjs';\nimport { createHash } from 'crypto';\n\n/**\n * Options for cache operations.\n */\nexport type cacheOptions = {\n /** Time to live in seconds */\n ttl?: number;\n};\n\n/**\n * Cache class providing a unified interface for various cache providers.\n * Handles key generation, serialization, and common cache operations.\n */\nexport class Cache {\n /**\n * Creates a new Cache instance.\n * @param provider - The cache provider implementation to use\n */\n constructor(private provider: CacheProviderInterface) {}\n\n /**\n * Retrieves a value from the cache.\n * @template T - The expected type of the cached value\n * @param key - The cache key (can be string, number, object, or array)\n * @returns The cached value or undefined if not found or expired\n */\n async get<T>(key: JSONValue): Promise<T | undefined> {\n return this.provider.get(this.generateKey(key)) as Promise<T | undefined>;\n }\n\n /**\n * Stores a value in the cache.\n * @param key - The cache key (can be string, number, object, or array)\n * @param value - The value to cache\n * @param ttl - Time to live in seconds (optional)\n */\n async put(key: JSONValue, value: any, ttl?: number): Promise<void> {\n return this.provider.put(this.generateKey(key), value, ttl);\n }\n\n /**\n * Deletes a value from the cache.\n * @param key - The cache key to delete\n */\n async delete(key: JSONValue): Promise<void> {\n return this.provider.delete(this.generateKey(key));\n }\n\n /**\n * Checks if a key exists in the cache.\n * @param key - The cache key to check\n * @returns True if the key exists and has not expired, false otherwise\n */\n async has(key: JSONValue): Promise<boolean> {\n return this.provider.has(this.generateKey(key));\n }\n\n /**\n * Increments a numeric value in the cache atomically.\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The new value after incrementing\n */\n async increment(key: JSONValue, amount: number = 1): Promise<number> {\n return this.provider.increment(this.generateKey(key), amount);\n }\n\n /**\n * Gets a value from cache or executes callback and caches the result.\n * This is useful for caching expensive operations.\n * @template T - The expected type of the value\n * @param key - The cache key\n * @param callback - Function to execute if cache miss occurs\n * @param options - Cache options including TTL (default: 3600 seconds)\n * @returns The cached value or the result of the callback\n */\n async remember<T>(\n key: JSONValue,\n callback: () => Promise<T>,\n options: cacheOptions = {}\n ): Promise<T> {\n options.ttl = options.ttl ?? 3600; // default TTL 1 hour\n\n const cached = await this.get<T>(key);\n if (cached) {\n return cached;\n }\n\n const result = await callback();\n await this.put(key, result, options.ttl);\n return result;\n }\n\n /**\n * Generates a cache key by serializing and hashing complex keys.\n * Simple string keys under 250 characters are returned as-is.\n * Complex keys (objects, arrays, long strings) are MD5 hashed.\n * @param key - The key to generate a cache key from\n * @returns A string suitable for use as a cache key\n */\n generateKey(key: JSONValue): string {\n if (typeof key === 'string' && key.length <= 250) {\n return key;\n }\n return createHash('md5').update(JSON.stringify(key)).digest('hex');\n }\n}\n","import { createClient, RedisClientOptions, RedisClientType } from 'redis';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONValue, JSONObject } from '@devbro/neko-helper';\n\nexport type RedisCacheProviderConfig = RedisClientOptions;\n/**\n * Redis-based cache provider that stores cache entries in a Redis server.\n * Provides distributed caching with automatic expiration support.\n */\nexport class RedisCacheProvider implements CacheProviderInterface {\n private client: RedisClientType;\n private defaultTTL: number = 3600; // default TTL in seconds\n\n /**\n * Creates a new RedisCacheProvider instance.\n * @param config - Redis client configuration options\n */\n constructor(private config: RedisCacheProviderConfig) {\n this.client = this.createRedisClient();\n this.client.connect();\n }\n\n /**\n * Creates a Redis client with the provided configuration.\n * @returns A Redis client instance\n */\n private createRedisClient(): any {\n let rc = createClient(this.config);\n return rc;\n }\n\n /**\n * Ensures the Redis client is connected before performing operations.\n */\n private async ensureConnection(): Promise<void> {\n if (!this.client.isOpen) {\n await this.client.connect();\n }\n }\n\n /**\n * Retrieves a value from the cache.\n * @param key - The cache key\n * @returns The cached value or undefined if not found\n */\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n await this.ensureConnection();\n let rc = this.client.get(key);\n return rc.then((value) => {\n if (value === null || value === undefined) {\n return undefined;\n }\n return JSON.parse(value);\n });\n }\n\n /**\n * Stores a value in the cache.\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds (optional)\n */\n async put(key: string, value: JSONValue | JSONObject, ttl?: number): Promise<void> {\n await this.ensureConnection();\n const serializedValue = JSON.stringify(value);\n ttl = ttl ?? this.defaultTTL;\n if (ttl && ttl > 0) {\n await this.client.setEx(key, ttl, serializedValue);\n } else {\n await this.client.set(key, serializedValue);\n }\n }\n\n /**\n * Deletes a value from the cache.\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {\n await this.ensureConnection();\n await this.client.del(key);\n }\n\n /**\n * Checks if a key exists in the cache.\n * @param key - The cache key to check\n * @returns True if the key exists, false otherwise\n */\n async has(key: string): Promise<boolean> {\n await this.ensureConnection();\n const result = await this.client.exists(key);\n return result === 1;\n }\n\n /**\n * Increments a numeric value in the cache atomically using Redis INCRBY.\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The new value after incrementing\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n await this.ensureConnection();\n // Redis INCRBY is atomic\n return await this.client.incrBy(key, amount);\n }\n}\n","import * as fs from 'fs/promises';\nimport * as path from 'path';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONObject, JSONValue } from '@devbro/neko-helper';\n\n/**\n * Configuration options for the file-based cache provider.\n */\nexport type FileCacheConfig = {\n /** Directory where cache files are stored (default: './cache') */\n cacheDirectory?: string;\n /** Default time to live in milliseconds (default: 3600000) */\n defaultTTL?: number;\n /** Interval in milliseconds for cleanup of expired entries (default: 300000) */\n cleanupInterval?: number;\n};\n\n/**\n * Represents a cached item stored in a file.\n */\ninterface CacheItem {\n /** The cached value */\n value: any;\n /** Timestamp when the item expires (milliseconds since epoch) */\n expiresAt?: number;\n /** Timestamp when the item was created (milliseconds since epoch) */\n createdAt: number;\n}\n\n/**\n * File-based cache provider that stores cache entries as JSON files.\n * Provides persistent caching with automatic cleanup of expired entries.\n */\nexport class FileCacheProvider implements CacheProviderInterface {\n private config: FileCacheConfig = {\n cacheDirectory: path.join(process.cwd(), 'cache'),\n defaultTTL: 3600 * 1000,\n cleanupInterval: 300 * 1000,\n };\n\n private cleanupTimer?: NodeJS.Timeout;\n\n /**\n * Creates a new FileCacheProvider instance.\n * @param config - Configuration options for the cache\n */\n constructor(config: FileCacheConfig = {}) {\n this.config = { ...this.config, ...config };\n\n this.ensureCacheDirectory();\n this.startCleanupTimer();\n }\n\n /**\n * Ensures the cache directory exists, creating it if necessary.\n */\n private async ensureCacheDirectory(): Promise<void> {\n try {\n await fs.access(this.config.cacheDirectory!);\n } catch {\n await fs.mkdir(this.config.cacheDirectory!, { recursive: true });\n }\n }\n\n /**\n * Starts the automatic cleanup timer for expired entries.\n */\n private startCleanupTimer(): void {\n if (this.config.cleanupInterval! > 0) {\n this.cleanupTimer = setInterval(() => {\n this.cleanupExpiredEntries().catch(console.error);\n }, this.config.cleanupInterval!);\n }\n }\n\n /**\n * Stops the automatic cleanup timer.\n */\n private stopCleanupTimer(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined;\n }\n }\n\n /**\n * Generates a safe file path for the given cache key.\n * @param key - The cache key\n * @returns The full file path for the cache entry\n */\n private getFilePath(key: string): string {\n // Create a safe filename from the key\n const safeKey = key.replace(/[^a-z0-9]/gi, '_');\n return path.join(this.config.cacheDirectory!, `${safeKey}.json`);\n }\n\n /**\n * Removes all expired cache entries from the cache directory.\n */\n private async cleanupExpiredEntries(): Promise<void> {\n try {\n const files = await fs.readdir(this.config.cacheDirectory!);\n const now = Date.now();\n\n for (const file of files) {\n if (file.endsWith('.json')) {\n const filePath = path.join(this.config.cacheDirectory!, file);\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const item: CacheItem = JSON.parse(content);\n\n if (item.expiresAt && item.expiresAt < now) {\n await fs.unlink(filePath);\n }\n } catch {\n // If file is corrupted, delete it\n await fs.unlink(filePath).catch(() => {});\n }\n }\n }\n } catch (error) {\n // Ignore cleanup errors\n }\n }\n\n /**\n * Retrieves a value from the cache.\n * @param key - The cache key\n * @returns The cached value or undefined if not found or expired\n */\n async get(key: string): Promise<JSONObject | JSONValue | undefined> {\n const filePath = this.getFilePath(key);\n\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const item: CacheItem = JSON.parse(content);\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n await fs.unlink(filePath).catch(() => {});\n return undefined;\n }\n\n return item.value;\n } catch (error) {\n return undefined;\n }\n }\n\n /**\n * Stores a value in the cache.\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds (optional)\n */\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n const filePath = this.getFilePath(key);\n const now = Date.now();\n const effectiveTTL = ttl ?? this.config.defaultTTL!;\n\n const item: CacheItem = {\n value,\n createdAt: now,\n expiresAt: effectiveTTL > 0 ? now + effectiveTTL * 1000 : undefined,\n };\n\n this.ensureCacheDirectory();\n await fs.writeFile(filePath, JSON.stringify(item), 'utf-8');\n }\n\n /**\n * Deletes a value from the cache.\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {\n const filePath = this.getFilePath(key);\n\n try {\n await fs.unlink(filePath);\n } catch {\n // File doesn't exist, that's fine\n }\n }\n\n /**\n * Checks if a key exists in the cache and has not expired.\n * @param key - The cache key to check\n * @returns True if the key exists and is not expired, false otherwise\n */\n async has(key: string): Promise<boolean> {\n const value = await this.get(key);\n return value !== undefined;\n }\n\n /**\n * Increments a numeric value in the cache atomically using file-based locking.\n * If the key doesn't exist or is expired, it starts from 0.\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The new value after incrementing\n * @throws Error if lock cannot be acquired after maximum retries\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n const filePath = this.getFilePath(key);\n\n // Use a lock file to ensure atomicity\n const lockPath = `${filePath}.lock`;\n\n // Simple file-based locking mechanism\n let lockAcquired = false;\n let retries = 0;\n const maxRetries = 50;\n\n while (!lockAcquired && retries < maxRetries) {\n try {\n // Try to create lock file exclusively\n await fs.writeFile(lockPath, '', { flag: 'wx' });\n lockAcquired = true;\n } catch {\n // Lock exists, wait a bit and retry\n await new Promise((resolve) => setTimeout(resolve, 10));\n retries++;\n }\n }\n\n if (!lockAcquired) {\n throw new Error('Failed to acquire lock for increment operation');\n }\n\n try {\n let currentValue = 0;\n let item: CacheItem | undefined;\n\n // Read current value\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const parsedItem = JSON.parse(content);\n\n // Check if item has expired\n if (parsedItem.expiresAt && parsedItem.expiresAt < Date.now()) {\n item = undefined;\n } else {\n item = parsedItem;\n currentValue = typeof parsedItem.value === 'number' ? parsedItem.value : 0;\n }\n } catch {\n // File doesn't exist or is corrupted, start from 0\n }\n\n // Calculate new value\n const newValue = currentValue + amount;\n\n // Write back with same TTL if it existed\n const now = Date.now();\n const newItem: CacheItem = {\n value: newValue,\n createdAt: item?.createdAt ?? now,\n expiresAt: item?.expiresAt,\n };\n\n await fs.writeFile(filePath, JSON.stringify(newItem), 'utf-8');\n\n return newValue;\n } finally {\n // Release lock\n try {\n await fs.unlink(lockPath);\n } catch {\n // Ignore errors when removing lock file\n }\n }\n }\n}\n","import { JSONObject, JSONValue } from '@devbro/neko-helper';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\n\n/**\n * Configuration options for the in-memory cache provider.\n */\nexport type MemoryCacheConfig = {\n /** Maximum number of items to store in cache (default: 1000) */\n maxSize?: number;\n /** Default time to live in seconds (default: 3600) */\n defaultTTL?: number;\n /** Interval in seconds to run cleanup of expired entries (default: 600) */\n cleanupInterval?: number;\n};\n\n/**\n * Represents a cached item with metadata.\n */\ninterface CacheItem {\n /** The cached value */\n value: any;\n /** Timestamp when the item expires (milliseconds since epoch) */\n expiresAt?: number;\n /** Timestamp when the item was created (milliseconds since epoch) */\n createdAt: number;\n /** Timestamp when the item was last accessed (milliseconds since epoch) */\n lastAccessed: number;\n}\n\n/**\n * In-memory cache provider with LRU eviction and automatic cleanup.\n * Stores cache entries in memory with support for TTL and size limits.\n */\nexport class MemoryCacheProvider implements CacheProviderInterface {\n private cache = new Map<string, CacheItem>();\n private config: MemoryCacheConfig = {\n maxSize: 1000,\n defaultTTL: 3600,\n cleanupInterval: 600, // 10 minutes\n };\n\n private cleanupTimer?: NodeJS.Timeout;\n\n /**\n * Creates a new MemoryCacheProvider instance.\n * @param config - Configuration options for the cache\n */\n constructor(config: MemoryCacheConfig = {}) {\n this.config = { ...this.config, ...config };\n\n this.startCleanupTimer();\n }\n\n /**\n * Starts the automatic cleanup timer for expired entries.\n */\n private startCleanupTimer(): void {\n if (this.config.cleanupInterval! > 0) {\n this.cleanupTimer = setInterval(() => {\n this.cleanupExpiredEntries();\n }, this.config.cleanupInterval! * 1000);\n }\n }\n\n /**\n * Stops the automatic cleanup timer.\n */\n private stopCleanupTimer(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined;\n }\n }\n\n /**\n * Removes all expired entries from the cache.\n */\n private cleanupExpiredEntries(): void {\n const now = Date.now();\n\n for (const [key, item] of this.cache.entries()) {\n if (item.expiresAt && item.expiresAt < now) {\n this.cache.delete(key);\n }\n }\n }\n\n /**\n * Evicts the least recently used item if cache size exceeds maximum.\n */\n private evictLRU(): void {\n if (this.cache.size <= this.config.maxSize!) {\n return;\n }\n\n // Find the least recently accessed item\n let oldestKey: string | null = null;\n let oldestTime = Date.now();\n\n for (const [key, item] of this.cache.entries()) {\n if (item.lastAccessed < oldestTime) {\n oldestTime = item.lastAccessed;\n oldestKey = key;\n }\n }\n\n if (oldestKey) {\n this.cache.delete(oldestKey);\n }\n }\n\n /**\n * Retrieves a value from the cache.\n * @param key - The cache key\n * @returns The cached value or undefined if not found or expired\n */\n async get(key: string): Promise<JSONObject | JSONValue | undefined> {\n const item = this.cache.get(key);\n\n if (!item) {\n return undefined;\n }\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n this.cache.delete(key);\n return undefined;\n }\n\n // Update last accessed time for LRU\n item.lastAccessed = Date.now();\n\n return item.value;\n }\n\n /**\n * Stores a value in the cache.\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds (optional)\n */\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n const now = Date.now();\n const effectiveTTL = ttl ?? this.config.defaultTTL!;\n\n const item: CacheItem = {\n value,\n createdAt: now,\n lastAccessed: now,\n expiresAt: effectiveTTL > 0 ? now + effectiveTTL * 1000 : undefined,\n };\n\n this.cache.set(key, item);\n\n // Evict items if we exceed maxSize\n this.evictLRU();\n }\n\n /**\n * Deletes a value from the cache.\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {\n this.cache.delete(key);\n }\n\n /**\n * Checks if a key exists in the cache and has not expired.\n * @param key - The cache key to check\n * @returns True if the key exists and is not expired, false otherwise\n */\n async has(key: string): Promise<boolean> {\n const item = this.cache.get(key);\n\n if (!item) {\n return false;\n }\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n this.cache.delete(key);\n return false;\n }\n\n return true;\n }\n\n /**\n * Increments a numeric value in the cache atomically.\n * If the key doesn't exist or is expired, it starts from 0.\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The new value after incrementing\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n const item = this.cache.get(key);\n const now = Date.now();\n\n let currentValue = 0;\n\n // Check if item exists and is not expired\n if (item) {\n if (item.expiresAt && item.expiresAt < now) {\n this.cache.delete(key);\n } else {\n // Get current value, ensure it's a number\n currentValue = typeof item.value === 'number' ? item.value : 0;\n }\n }\n\n // Calculate new value\n const newValue = currentValue + amount;\n\n // Store the new value with the same TTL if it existed\n const newItem: CacheItem = {\n value: newValue,\n createdAt: item?.createdAt ?? now,\n lastAccessed: now,\n expiresAt: item?.expiresAt,\n };\n\n this.cache.set(key, newItem);\n\n return newValue;\n }\n}\n","import { CacheProviderInterface } from '@/CacheProviderInterface.mjs';\nimport { JSONValue, JSONObject } from '@devbro/neko-helper';\nimport Memcached from 'memcached';\n\n/**\n * Configuration options for the Memcached cache provider.\n */\nexport type MemcachedConfig = {\n /** Memcached server location(s) */\n location?: Memcached.Location;\n /** Additional Memcached options */\n options?: Memcached.options;\n};\n\n/**\n * Memcached-based cache provider that stores cache entries in a Memcached server.\n * Provides distributed caching with automatic serialization and expiration.\n */\nexport class MemcacheCacheProvider implements CacheProviderInterface {\n private client: Memcached;\n private defaultTTL: number = 3600; // default TTL in seconds\n\n /**\n * Creates a new MemcacheCacheProvider instance.\n * @param config - Memcached configuration options\n */\n constructor(private config: MemcachedConfig = {}) {\n this.client = new Memcached(config.location || 'localhost:11211', config.options || {});\n }\n\n /**\n * Retrieves a value from the cache.\n * @param key - The cache key\n * @returns The cached value or undefined if not found\n */\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n return new Promise((resolve, reject) => {\n this.client.get(key, (err: Error | undefined, data: any) => {\n if (err) {\n reject(err);\n return;\n }\n\n if (data === undefined || data === null) {\n resolve(undefined);\n return;\n }\n\n try {\n // Memcached automatically handles JSON serialization/deserialization\n // but we need to ensure we return the correct type\n resolve(typeof data === 'string' ? JSON.parse(data) : data);\n } catch (parseErr) {\n // If parsing fails, return the raw value\n resolve(data);\n }\n });\n });\n }\n\n /**\n * Stores a value in the cache.\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds (optional)\n */\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n return new Promise((resolve, reject) => {\n const serializedValue = JSON.stringify(value);\n const finalTTL = ttl ?? this.defaultTTL;\n\n this.client.set(key, serializedValue, finalTTL, (err: Error | undefined) => {\n if (err) {\n reject(err);\n return;\n }\n resolve();\n });\n });\n }\n\n /**\n * Deletes a value from the cache.\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {\n return new Promise((resolve, reject) => {\n this.client.del(key, (err: Error | undefined) => {\n if (err) {\n reject(err);\n return;\n }\n resolve();\n });\n });\n }\n\n /**\n * Checks if a key exists in the cache.\n * @param key - The cache key to check\n * @returns True if the key exists, false otherwise\n */\n async has(key: string): Promise<boolean> {\n return new Promise((resolve, reject) => {\n this.client.get(key, (err: Error | undefined, data: any) => {\n if (err) {\n reject(err);\n return;\n }\n resolve(data !== undefined && data !== null);\n });\n });\n }\n\n /**\n * Increments a numeric value in the cache atomically using Memcached's native increment.\n * If the key doesn't exist, it is initialized with the increment amount.\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The new value after incrementing\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n return new Promise((resolve, reject) => {\n // Memcached incr are atomic operations\n this.client.incr(key, amount, (err: any, result: number | boolean) => {\n if (err) {\n reject(err);\n return;\n }\n\n // If key doesn't exist, result will be false\n if (result === false) {\n // Initialize the key with the amount value\n this.client.set(key, amount.toString(), this.defaultTTL, (setErr: Error | undefined) => {\n if (setErr) {\n reject(setErr);\n return;\n }\n resolve(amount);\n });\n } else {\n resolve(result as number);\n }\n });\n });\n }\n}\n","import { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONValue, JSONObject } from '@devbro/neko-helper';\n\n/**\n * A cache provider that disables caching entirely.\n * All operations are no-ops, useful for testing or disabling cache in certain environments.\n */\nexport class DisabledCacheProvider implements CacheProviderInterface {\n /**\n * Creates a new DisabledCacheProvider instance.\n * @param config - Configuration object (currently unused)\n */\n constructor(private config = {}) {}\n\n /**\n * Always returns undefined (no caching).\n * @param key - The cache key\n * @returns Always undefined\n */\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n return undefined;\n }\n\n /**\n * Does nothing (no caching).\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds\n */\n async put(key: string, value: JSONValue | JSONObject, ttl?: number): Promise<void> {}\n\n /**\n * Does nothing (no caching).\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {}\n\n /**\n * Always returns false (no caching).\n * @param key - The cache key to check\n * @returns Always false\n */\n async has(key: string): Promise<boolean> {\n return false;\n }\n\n /**\n * Returns the increment amount as if starting from 0 (no caching).\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The increment amount\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n // Disabled cache always returns the increment amount as if starting from 0\n return amount;\n }\n}\n"],"mappings":"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","names":["Memcached"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/DisabledCacheProvider.mts"],"sourcesContent":["import { createClient, RedisClientOptions, RedisClientType } from 'redis';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONValue, JSONObject } from '@devbro/neko-helper';\n\n/**\n * A cache provider that disables caching entirely.\n * All operations are no-ops, useful for testing or disabling cache in certain environments.\n */\nexport class DisabledCacheProvider implements CacheProviderInterface {\n /**\n * Creates a new DisabledCacheProvider instance.\n * @param config - Configuration object (currently unused)\n */\n constructor(private config = {}) {}\n\n /**\n * Always returns undefined (no caching).\n * @param key - The cache key\n * @returns Always undefined\n */\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n return undefined;\n }\n\n /**\n * Does nothing (no caching).\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds\n */\n async put(key: string, value: JSONValue | JSONObject, ttl?: number): Promise<void> {}\n\n /**\n * Does nothing (no caching).\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {}\n\n /**\n * Always returns false (no caching).\n * @param key - The cache key to check\n * @returns Always false\n */\n async has(key: string): Promise<boolean> {\n return false;\n }\n\n /**\n * Returns the increment amount as if starting from 0 (no caching).\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The increment amount\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n // Disabled cache always returns the increment amount as if starting from 0\n return amount;\n }\n}\n"],"mappings":";;AAQO,MAAM,sBAAwD;AAAA;AAAA;AAAA;AAAA;AAAA,EAKnE,YAAoB,SAAS,CAAC,GAAG;AAAb;AAAA,EAAc;AAAA,EAbpC,OAQqE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYnE,MAAM,IAAI,KAA0D;AAClE,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,IAAI,KAAa,OAA+B,KAA6B;AAAA,EAAC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMpF,MAAM,OAAO,KAA4B;AAAA,EAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO1C,MAAM,IAAI,KAA+B;AACvC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,UAAU,KAAa,SAAiB,GAAoB;AAEhE,WAAO;AAAA,EACT;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/providers/DisabledCacheProvider.mts"],"sourcesContent":["import { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONValue, JSONObject } from '@devbro/neko-helper';\n\n/**\n * A cache provider that disables caching entirely.\n * All operations are no-ops, useful for testing or disabling cache in certain environments.\n */\nexport class DisabledCacheProvider implements CacheProviderInterface {\n /**\n * Creates a new DisabledCacheProvider instance.\n * @param config - Configuration object (currently unused)\n */\n constructor(private config = {}) {}\n\n /**\n * Always returns undefined (no caching).\n * @param key - The cache key\n * @returns Always undefined\n */\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n return undefined;\n }\n\n /**\n * Does nothing (no caching).\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds\n */\n async put(key: string, value: JSONValue | JSONObject, ttl?: number): Promise<void> {}\n\n /**\n * Does nothing (no caching).\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {}\n\n /**\n * Always returns false (no caching).\n * @param key - The cache key to check\n * @returns Always false\n */\n async has(key: string): Promise<boolean> {\n return false;\n }\n\n /**\n * Returns the increment amount as if starting from 0 (no caching).\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The increment amount\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n // Disabled cache always returns the increment amount as if starting from 0\n return amount;\n }\n}\n"],"mappings":";;AAOO,MAAM,sBAAwD;AAAA;AAAA;AAAA;AAAA;AAAA,EAKnE,YAAoB,SAAS,CAAC,GAAG;AAAb;AAAA,EAAc;AAAA,EAZpC,OAOqE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYnE,MAAM,IAAI,KAA0D;AAClE,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,IAAI,KAAa,OAA+B,KAA6B;AAAA,EAAC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMpF,MAAM,OAAO,KAA4B;AAAA,EAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO1C,MAAM,IAAI,KAA+B;AACvC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,UAAU,KAAa,SAAiB,GAAoB;AAEhE,WAAO;AAAA,EACT;AACF;","names":[]}
@@ -4,14 +4,14 @@ import { JSONObject, JSONValue } from '@devbro/neko-helper';
4
4
  /**
5
5
  * Configuration options for the file-based cache provider.
6
6
  */
7
- interface FileCacheConfig {
7
+ type FileCacheConfig = {
8
8
  /** Directory where cache files are stored (default: './cache') */
9
9
  cacheDirectory?: string;
10
10
  /** Default time to live in milliseconds (default: 3600000) */
11
11
  defaultTTL?: number;
12
12
  /** Interval in milliseconds for cleanup of expired entries (default: 300000) */
13
13
  cleanupInterval?: number;
14
- }
14
+ };
15
15
  /**
16
16
  * File-based cache provider that stores cache entries as JSON files.
17
17
  * Provides persistent caching with automatic cleanup of expired entries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/FileCacheProvider.mts"],"sourcesContent":["import * as fs from 'fs/promises';\nimport * as path from 'path';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONObject, JSONValue } from '@devbro/neko-helper';\n\n/**\n * Configuration options for the file-based cache provider.\n */\nexport interface FileCacheConfig {\n /** Directory where cache files are stored (default: './cache') */\n cacheDirectory?: string;\n /** Default time to live in milliseconds (default: 3600000) */\n defaultTTL?: number;\n /** Interval in milliseconds for cleanup of expired entries (default: 300000) */\n cleanupInterval?: number;\n}\n\n/**\n * Represents a cached item stored in a file.\n */\ninterface CacheItem {\n /** The cached value */\n value: any;\n /** Timestamp when the item expires (milliseconds since epoch) */\n expiresAt?: number;\n /** Timestamp when the item was created (milliseconds since epoch) */\n createdAt: number;\n}\n\n/**\n * File-based cache provider that stores cache entries as JSON files.\n * Provides persistent caching with automatic cleanup of expired entries.\n */\nexport class FileCacheProvider implements CacheProviderInterface {\n private config: FileCacheConfig = {\n cacheDirectory: path.join(process.cwd(), 'cache'),\n defaultTTL: 3600 * 1000,\n cleanupInterval: 300 * 1000,\n };\n\n private cleanupTimer?: NodeJS.Timeout;\n\n /**\n * Creates a new FileCacheProvider instance.\n * @param config - Configuration options for the cache\n */\n constructor(config: FileCacheConfig = {}) {\n this.config = { ...this.config, ...config };\n\n this.ensureCacheDirectory();\n this.startCleanupTimer();\n }\n\n /**\n * Ensures the cache directory exists, creating it if necessary.\n */\n private async ensureCacheDirectory(): Promise<void> {\n try {\n await fs.access(this.config.cacheDirectory!);\n } catch {\n await fs.mkdir(this.config.cacheDirectory!, { recursive: true });\n }\n }\n\n /**\n * Starts the automatic cleanup timer for expired entries.\n */\n private startCleanupTimer(): void {\n if (this.config.cleanupInterval! > 0) {\n this.cleanupTimer = setInterval(() => {\n this.cleanupExpiredEntries().catch(console.error);\n }, this.config.cleanupInterval!);\n }\n }\n\n /**\n * Stops the automatic cleanup timer.\n */\n private stopCleanupTimer(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined;\n }\n }\n\n /**\n * Generates a safe file path for the given cache key.\n * @param key - The cache key\n * @returns The full file path for the cache entry\n */\n private getFilePath(key: string): string {\n // Create a safe filename from the key\n const safeKey = key.replace(/[^a-z0-9]/gi, '_');\n return path.join(this.config.cacheDirectory!, `${safeKey}.json`);\n }\n\n /**\n * Removes all expired cache entries from the cache directory.\n */\n private async cleanupExpiredEntries(): Promise<void> {\n try {\n const files = await fs.readdir(this.config.cacheDirectory!);\n const now = Date.now();\n\n for (const file of files) {\n if (file.endsWith('.json')) {\n const filePath = path.join(this.config.cacheDirectory!, file);\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const item: CacheItem = JSON.parse(content);\n\n if (item.expiresAt && item.expiresAt < now) {\n await fs.unlink(filePath);\n }\n } catch {\n // If file is corrupted, delete it\n await fs.unlink(filePath).catch(() => {});\n }\n }\n }\n } catch (error) {\n // Ignore cleanup errors\n }\n }\n\n /**\n * Retrieves a value from the cache.\n * @param key - The cache key\n * @returns The cached value or undefined if not found or expired\n */\n async get(key: string): Promise<JSONObject | JSONValue | undefined> {\n const filePath = this.getFilePath(key);\n\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const item: CacheItem = JSON.parse(content);\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n await fs.unlink(filePath).catch(() => {});\n return undefined;\n }\n\n return item.value;\n } catch (error) {\n return undefined;\n }\n }\n\n /**\n * Stores a value in the cache.\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds (optional)\n */\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n const filePath = this.getFilePath(key);\n const now = Date.now();\n const effectiveTTL = ttl ?? this.config.defaultTTL!;\n\n const item: CacheItem = {\n value,\n createdAt: now,\n expiresAt: effectiveTTL > 0 ? now + effectiveTTL * 1000 : undefined,\n };\n\n this.ensureCacheDirectory();\n await fs.writeFile(filePath, JSON.stringify(item), 'utf-8');\n }\n\n /**\n * Deletes a value from the cache.\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {\n const filePath = this.getFilePath(key);\n\n try {\n await fs.unlink(filePath);\n } catch {\n // File doesn't exist, that's fine\n }\n }\n\n /**\n * Checks if a key exists in the cache and has not expired.\n * @param key - The cache key to check\n * @returns True if the key exists and is not expired, false otherwise\n */\n async has(key: string): Promise<boolean> {\n const value = await this.get(key);\n return value !== undefined;\n }\n\n /**\n * Increments a numeric value in the cache atomically using file-based locking.\n * If the key doesn't exist or is expired, it starts from 0.\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The new value after incrementing\n * @throws Error if lock cannot be acquired after maximum retries\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n const filePath = this.getFilePath(key);\n\n // Use a lock file to ensure atomicity\n const lockPath = `${filePath}.lock`;\n\n // Simple file-based locking mechanism\n let lockAcquired = false;\n let retries = 0;\n const maxRetries = 50;\n\n while (!lockAcquired && retries < maxRetries) {\n try {\n // Try to create lock file exclusively\n await fs.writeFile(lockPath, '', { flag: 'wx' });\n lockAcquired = true;\n } catch {\n // Lock exists, wait a bit and retry\n await new Promise((resolve) => setTimeout(resolve, 10));\n retries++;\n }\n }\n\n if (!lockAcquired) {\n throw new Error('Failed to acquire lock for increment operation');\n }\n\n try {\n let currentValue = 0;\n let item: CacheItem | undefined;\n\n // Read current value\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const parsedItem = JSON.parse(content);\n\n // Check if item has expired\n if (parsedItem.expiresAt && parsedItem.expiresAt < Date.now()) {\n item = undefined;\n } else {\n item = parsedItem;\n currentValue = typeof parsedItem.value === 'number' ? parsedItem.value : 0;\n }\n } catch {\n // File doesn't exist or is corrupted, start from 0\n }\n\n // Calculate new value\n const newValue = currentValue + amount;\n\n // Write back with same TTL if it existed\n const now = Date.now();\n const newItem: CacheItem = {\n value: newValue,\n createdAt: item?.createdAt ?? now,\n expiresAt: item?.expiresAt,\n };\n\n await fs.writeFile(filePath, JSON.stringify(newItem), 'utf-8');\n\n return newValue;\n } finally {\n // Release lock\n try {\n await fs.unlink(lockPath);\n } catch {\n // Ignore errors when removing lock file\n }\n }\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/providers/FileCacheProvider.mts"],"sourcesContent":["import * as fs from 'fs/promises';\nimport * as path from 'path';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONObject, JSONValue } from '@devbro/neko-helper';\n\n/**\n * Configuration options for the file-based cache provider.\n */\nexport type FileCacheConfig = {\n /** Directory where cache files are stored (default: './cache') */\n cacheDirectory?: string;\n /** Default time to live in milliseconds (default: 3600000) */\n defaultTTL?: number;\n /** Interval in milliseconds for cleanup of expired entries (default: 300000) */\n cleanupInterval?: number;\n};\n\n/**\n * Represents a cached item stored in a file.\n */\ninterface CacheItem {\n /** The cached value */\n value: any;\n /** Timestamp when the item expires (milliseconds since epoch) */\n expiresAt?: number;\n /** Timestamp when the item was created (milliseconds since epoch) */\n createdAt: number;\n}\n\n/**\n * File-based cache provider that stores cache entries as JSON files.\n * Provides persistent caching with automatic cleanup of expired entries.\n */\nexport class FileCacheProvider implements CacheProviderInterface {\n private config: FileCacheConfig = {\n cacheDirectory: path.join(process.cwd(), 'cache'),\n defaultTTL: 3600 * 1000,\n cleanupInterval: 300 * 1000,\n };\n\n private cleanupTimer?: NodeJS.Timeout;\n\n /**\n * Creates a new FileCacheProvider instance.\n * @param config - Configuration options for the cache\n */\n constructor(config: FileCacheConfig = {}) {\n this.config = { ...this.config, ...config };\n\n this.ensureCacheDirectory();\n this.startCleanupTimer();\n }\n\n /**\n * Ensures the cache directory exists, creating it if necessary.\n */\n private async ensureCacheDirectory(): Promise<void> {\n try {\n await fs.access(this.config.cacheDirectory!);\n } catch {\n await fs.mkdir(this.config.cacheDirectory!, { recursive: true });\n }\n }\n\n /**\n * Starts the automatic cleanup timer for expired entries.\n */\n private startCleanupTimer(): void {\n if (this.config.cleanupInterval! > 0) {\n this.cleanupTimer = setInterval(() => {\n this.cleanupExpiredEntries().catch(console.error);\n }, this.config.cleanupInterval!);\n }\n }\n\n /**\n * Stops the automatic cleanup timer.\n */\n private stopCleanupTimer(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined;\n }\n }\n\n /**\n * Generates a safe file path for the given cache key.\n * @param key - The cache key\n * @returns The full file path for the cache entry\n */\n private getFilePath(key: string): string {\n // Create a safe filename from the key\n const safeKey = key.replace(/[^a-z0-9]/gi, '_');\n return path.join(this.config.cacheDirectory!, `${safeKey}.json`);\n }\n\n /**\n * Removes all expired cache entries from the cache directory.\n */\n private async cleanupExpiredEntries(): Promise<void> {\n try {\n const files = await fs.readdir(this.config.cacheDirectory!);\n const now = Date.now();\n\n for (const file of files) {\n if (file.endsWith('.json')) {\n const filePath = path.join(this.config.cacheDirectory!, file);\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const item: CacheItem = JSON.parse(content);\n\n if (item.expiresAt && item.expiresAt < now) {\n await fs.unlink(filePath);\n }\n } catch {\n // If file is corrupted, delete it\n await fs.unlink(filePath).catch(() => {});\n }\n }\n }\n } catch (error) {\n // Ignore cleanup errors\n }\n }\n\n /**\n * Retrieves a value from the cache.\n * @param key - The cache key\n * @returns The cached value or undefined if not found or expired\n */\n async get(key: string): Promise<JSONObject | JSONValue | undefined> {\n const filePath = this.getFilePath(key);\n\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const item: CacheItem = JSON.parse(content);\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n await fs.unlink(filePath).catch(() => {});\n return undefined;\n }\n\n return item.value;\n } catch (error) {\n return undefined;\n }\n }\n\n /**\n * Stores a value in the cache.\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds (optional)\n */\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n const filePath = this.getFilePath(key);\n const now = Date.now();\n const effectiveTTL = ttl ?? this.config.defaultTTL!;\n\n const item: CacheItem = {\n value,\n createdAt: now,\n expiresAt: effectiveTTL > 0 ? now + effectiveTTL * 1000 : undefined,\n };\n\n this.ensureCacheDirectory();\n await fs.writeFile(filePath, JSON.stringify(item), 'utf-8');\n }\n\n /**\n * Deletes a value from the cache.\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {\n const filePath = this.getFilePath(key);\n\n try {\n await fs.unlink(filePath);\n } catch {\n // File doesn't exist, that's fine\n }\n }\n\n /**\n * Checks if a key exists in the cache and has not expired.\n * @param key - The cache key to check\n * @returns True if the key exists and is not expired, false otherwise\n */\n async has(key: string): Promise<boolean> {\n const value = await this.get(key);\n return value !== undefined;\n }\n\n /**\n * Increments a numeric value in the cache atomically using file-based locking.\n * If the key doesn't exist or is expired, it starts from 0.\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The new value after incrementing\n * @throws Error if lock cannot be acquired after maximum retries\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n const filePath = this.getFilePath(key);\n\n // Use a lock file to ensure atomicity\n const lockPath = `${filePath}.lock`;\n\n // Simple file-based locking mechanism\n let lockAcquired = false;\n let retries = 0;\n const maxRetries = 50;\n\n while (!lockAcquired && retries < maxRetries) {\n try {\n // Try to create lock file exclusively\n await fs.writeFile(lockPath, '', { flag: 'wx' });\n lockAcquired = true;\n } catch {\n // Lock exists, wait a bit and retry\n await new Promise((resolve) => setTimeout(resolve, 10));\n retries++;\n }\n }\n\n if (!lockAcquired) {\n throw new Error('Failed to acquire lock for increment operation');\n }\n\n try {\n let currentValue = 0;\n let item: CacheItem | undefined;\n\n // Read current value\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const parsedItem = JSON.parse(content);\n\n // Check if item has expired\n if (parsedItem.expiresAt && parsedItem.expiresAt < Date.now()) {\n item = undefined;\n } else {\n item = parsedItem;\n currentValue = typeof parsedItem.value === 'number' ? parsedItem.value : 0;\n }\n } catch {\n // File doesn't exist or is corrupted, start from 0\n }\n\n // Calculate new value\n const newValue = currentValue + amount;\n\n // Write back with same TTL if it existed\n const now = Date.now();\n const newItem: CacheItem = {\n value: newValue,\n createdAt: item?.createdAt ?? now,\n expiresAt: item?.expiresAt,\n };\n\n await fs.writeFile(filePath, JSON.stringify(newItem), 'utf-8');\n\n return newValue;\n } finally {\n // Release lock\n try {\n await fs.unlink(lockPath);\n } catch {\n // Ignore errors when removing lock file\n }\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -5,12 +5,12 @@ import Memcached from 'memcached';
5
5
  /**
6
6
  * Configuration options for the Memcached cache provider.
7
7
  */
8
- interface MemcachedConfig {
8
+ type MemcachedConfig = {
9
9
  /** Memcached server location(s) */
10
10
  location?: Memcached.Location;
11
11
  /** Additional Memcached options */
12
12
  options?: Memcached.options;
13
- }
13
+ };
14
14
  /**
15
15
  * Memcached-based cache provider that stores cache entries in a Memcached server.
16
16
  * Provides distributed caching with automatic serialization and expiration.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/MemcacheCacheProvider.mts"],"sourcesContent":["import { CacheProviderInterface } from '@/CacheProviderInterface.mjs';\nimport { JSONValue, JSONObject } from '@devbro/neko-helper';\nimport Memcached from 'memcached';\n\n/**\n * Configuration options for the Memcached cache provider.\n */\nexport interface MemcachedConfig {\n /** Memcached server location(s) */\n location?: Memcached.Location;\n /** Additional Memcached options */\n options?: Memcached.options;\n}\n\n/**\n * Memcached-based cache provider that stores cache entries in a Memcached server.\n * Provides distributed caching with automatic serialization and expiration.\n */\nexport class MemcacheCacheProvider implements CacheProviderInterface {\n private client: Memcached;\n private defaultTTL: number = 3600; // default TTL in seconds\n\n /**\n * Creates a new MemcacheCacheProvider instance.\n * @param config - Memcached configuration options\n */\n constructor(private config: MemcachedConfig = {}) {\n this.client = new Memcached(config.location || 'localhost:11211', config.options || {});\n }\n\n /**\n * Retrieves a value from the cache.\n * @param key - The cache key\n * @returns The cached value or undefined if not found\n */\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n return new Promise((resolve, reject) => {\n this.client.get(key, (err: Error | undefined, data: any) => {\n if (err) {\n reject(err);\n return;\n }\n\n if (data === undefined || data === null) {\n resolve(undefined);\n return;\n }\n\n try {\n // Memcached automatically handles JSON serialization/deserialization\n // but we need to ensure we return the correct type\n resolve(typeof data === 'string' ? JSON.parse(data) : data);\n } catch (parseErr) {\n // If parsing fails, return the raw value\n resolve(data);\n }\n });\n });\n }\n\n /**\n * Stores a value in the cache.\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds (optional)\n */\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n return new Promise((resolve, reject) => {\n const serializedValue = JSON.stringify(value);\n const finalTTL = ttl ?? this.defaultTTL;\n\n this.client.set(key, serializedValue, finalTTL, (err: Error | undefined) => {\n if (err) {\n reject(err);\n return;\n }\n resolve();\n });\n });\n }\n\n /**\n * Deletes a value from the cache.\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {\n return new Promise((resolve, reject) => {\n this.client.del(key, (err: Error | undefined) => {\n if (err) {\n reject(err);\n return;\n }\n resolve();\n });\n });\n }\n\n /**\n * Checks if a key exists in the cache.\n * @param key - The cache key to check\n * @returns True if the key exists, false otherwise\n */\n async has(key: string): Promise<boolean> {\n return new Promise((resolve, reject) => {\n this.client.get(key, (err: Error | undefined, data: any) => {\n if (err) {\n reject(err);\n return;\n }\n resolve(data !== undefined && data !== null);\n });\n });\n }\n\n /**\n * Increments a numeric value in the cache atomically using Memcached's native increment.\n * If the key doesn't exist, it is initialized with the increment amount.\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The new value after incrementing\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n return new Promise((resolve, reject) => {\n // Memcached incr are atomic operations\n this.client.incr(key, amount, (err: any, result: number | boolean) => {\n if (err) {\n reject(err);\n return;\n }\n\n // If key doesn't exist, result will be false\n if (result === false) {\n // Initialize the key with the amount value\n this.client.set(key, amount.toString(), this.defaultTTL, (setErr: Error | undefined) => {\n if (setErr) {\n reject(setErr);\n return;\n }\n resolve(amount);\n });\n } else {\n resolve(result as number);\n }\n });\n });\n }\n}\n"],"mappings":";;AAEA,OAAO,eAAe;AAgBf,MAAM,sBAAwD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQnE,YAAoB,SAA0B,CAAC,GAAG;AAA9B;AAClB,SAAK,SAAS,IAAI,UAAU,OAAO,YAAY,mBAAmB,OAAO,WAAW,CAAC,CAAC;AAAA,EACxF;AAAA,EA5BF,OAkBqE;AAAA;AAAA;AAAA,EAC3D;AAAA,EACA,aAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAe7B,MAAM,IAAI,KAA0D;AAClE,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,WAAK,OAAO,IAAI,KAAK,CAAC,KAAwB,SAAc;AAC1D,YAAI,KAAK;AACP,iBAAO,GAAG;AACV;AAAA,QACF;AAEA,YAAI,SAAS,UAAa,SAAS,MAAM;AACvC,kBAAQ,MAAS;AACjB;AAAA,QACF;AAEA,YAAI;AAGF,kBAAQ,OAAO,SAAS,WAAW,KAAK,MAAM,IAAI,IAAI,IAAI;AAAA,QAC5D,SAAS,UAAU;AAEjB,kBAAQ,IAAI;AAAA,QACd;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,IAAI,KAAa,OAA+B,KAA6B;AACjF,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,kBAAkB,KAAK,UAAU,KAAK;AAC5C,YAAM,WAAW,OAAO,KAAK;AAE7B,WAAK,OAAO,IAAI,KAAK,iBAAiB,UAAU,CAAC,QAA2B;AAC1E,YAAI,KAAK;AACP,iBAAO,GAAG;AACV;AAAA,QACF;AACA,gBAAQ;AAAA,MACV,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAO,KAA4B;AACvC,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,WAAK,OAAO,IAAI,KAAK,CAAC,QAA2B;AAC/C,YAAI,KAAK;AACP,iBAAO,GAAG;AACV;AAAA,QACF;AACA,gBAAQ;AAAA,MACV,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,IAAI,KAA+B;AACvC,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,WAAK,OAAO,IAAI,KAAK,CAAC,KAAwB,SAAc;AAC1D,YAAI,KAAK;AACP,iBAAO,GAAG;AACV;AAAA,QACF;AACA,gBAAQ,SAAS,UAAa,SAAS,IAAI;AAAA,MAC7C,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,UAAU,KAAa,SAAiB,GAAoB;AAChE,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAEtC,WAAK,OAAO,KAAK,KAAK,QAAQ,CAAC,KAAU,WAA6B;AACpE,YAAI,KAAK;AACP,iBAAO,GAAG;AACV;AAAA,QACF;AAGA,YAAI,WAAW,OAAO;AAEpB,eAAK,OAAO,IAAI,KAAK,OAAO,SAAS,GAAG,KAAK,YAAY,CAAC,WAA8B;AACtF,gBAAI,QAAQ;AACV,qBAAO,MAAM;AACb;AAAA,YACF;AACA,oBAAQ,MAAM;AAAA,UAChB,CAAC;AAAA,QACH,OAAO;AACL,kBAAQ,MAAgB;AAAA,QAC1B;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/providers/MemcacheCacheProvider.mts"],"sourcesContent":["import { CacheProviderInterface } from '@/CacheProviderInterface.mjs';\nimport { JSONValue, JSONObject } from '@devbro/neko-helper';\nimport Memcached from 'memcached';\n\n/**\n * Configuration options for the Memcached cache provider.\n */\nexport type MemcachedConfig = {\n /** Memcached server location(s) */\n location?: Memcached.Location;\n /** Additional Memcached options */\n options?: Memcached.options;\n};\n\n/**\n * Memcached-based cache provider that stores cache entries in a Memcached server.\n * Provides distributed caching with automatic serialization and expiration.\n */\nexport class MemcacheCacheProvider implements CacheProviderInterface {\n private client: Memcached;\n private defaultTTL: number = 3600; // default TTL in seconds\n\n /**\n * Creates a new MemcacheCacheProvider instance.\n * @param config - Memcached configuration options\n */\n constructor(private config: MemcachedConfig = {}) {\n this.client = new Memcached(config.location || 'localhost:11211', config.options || {});\n }\n\n /**\n * Retrieves a value from the cache.\n * @param key - The cache key\n * @returns The cached value or undefined if not found\n */\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n return new Promise((resolve, reject) => {\n this.client.get(key, (err: Error | undefined, data: any) => {\n if (err) {\n reject(err);\n return;\n }\n\n if (data === undefined || data === null) {\n resolve(undefined);\n return;\n }\n\n try {\n // Memcached automatically handles JSON serialization/deserialization\n // but we need to ensure we return the correct type\n resolve(typeof data === 'string' ? JSON.parse(data) : data);\n } catch (parseErr) {\n // If parsing fails, return the raw value\n resolve(data);\n }\n });\n });\n }\n\n /**\n * Stores a value in the cache.\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds (optional)\n */\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n return new Promise((resolve, reject) => {\n const serializedValue = JSON.stringify(value);\n const finalTTL = ttl ?? this.defaultTTL;\n\n this.client.set(key, serializedValue, finalTTL, (err: Error | undefined) => {\n if (err) {\n reject(err);\n return;\n }\n resolve();\n });\n });\n }\n\n /**\n * Deletes a value from the cache.\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {\n return new Promise((resolve, reject) => {\n this.client.del(key, (err: Error | undefined) => {\n if (err) {\n reject(err);\n return;\n }\n resolve();\n });\n });\n }\n\n /**\n * Checks if a key exists in the cache.\n * @param key - The cache key to check\n * @returns True if the key exists, false otherwise\n */\n async has(key: string): Promise<boolean> {\n return new Promise((resolve, reject) => {\n this.client.get(key, (err: Error | undefined, data: any) => {\n if (err) {\n reject(err);\n return;\n }\n resolve(data !== undefined && data !== null);\n });\n });\n }\n\n /**\n * Increments a numeric value in the cache atomically using Memcached's native increment.\n * If the key doesn't exist, it is initialized with the increment amount.\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The new value after incrementing\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n return new Promise((resolve, reject) => {\n // Memcached incr are atomic operations\n this.client.incr(key, amount, (err: any, result: number | boolean) => {\n if (err) {\n reject(err);\n return;\n }\n\n // If key doesn't exist, result will be false\n if (result === false) {\n // Initialize the key with the amount value\n this.client.set(key, amount.toString(), this.defaultTTL, (setErr: Error | undefined) => {\n if (setErr) {\n reject(setErr);\n return;\n }\n resolve(amount);\n });\n } else {\n resolve(result as number);\n }\n });\n });\n }\n}\n"],"mappings":";;AAEA,OAAO,eAAe;AAgBf,MAAM,sBAAwD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQnE,YAAoB,SAA0B,CAAC,GAAG;AAA9B;AAClB,SAAK,SAAS,IAAI,UAAU,OAAO,YAAY,mBAAmB,OAAO,WAAW,CAAC,CAAC;AAAA,EACxF;AAAA,EA5BF,OAkBqE;AAAA;AAAA;AAAA,EAC3D;AAAA,EACA,aAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAe7B,MAAM,IAAI,KAA0D;AAClE,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,WAAK,OAAO,IAAI,KAAK,CAAC,KAAwB,SAAc;AAC1D,YAAI,KAAK;AACP,iBAAO,GAAG;AACV;AAAA,QACF;AAEA,YAAI,SAAS,UAAa,SAAS,MAAM;AACvC,kBAAQ,MAAS;AACjB;AAAA,QACF;AAEA,YAAI;AAGF,kBAAQ,OAAO,SAAS,WAAW,KAAK,MAAM,IAAI,IAAI,IAAI;AAAA,QAC5D,SAAS,UAAU;AAEjB,kBAAQ,IAAI;AAAA,QACd;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,IAAI,KAAa,OAA+B,KAA6B;AACjF,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,kBAAkB,KAAK,UAAU,KAAK;AAC5C,YAAM,WAAW,OAAO,KAAK;AAE7B,WAAK,OAAO,IAAI,KAAK,iBAAiB,UAAU,CAAC,QAA2B;AAC1E,YAAI,KAAK;AACP,iBAAO,GAAG;AACV;AAAA,QACF;AACA,gBAAQ;AAAA,MACV,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAO,KAA4B;AACvC,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,WAAK,OAAO,IAAI,KAAK,CAAC,QAA2B;AAC/C,YAAI,KAAK;AACP,iBAAO,GAAG;AACV;AAAA,QACF;AACA,gBAAQ;AAAA,MACV,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,IAAI,KAA+B;AACvC,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,WAAK,OAAO,IAAI,KAAK,CAAC,KAAwB,SAAc;AAC1D,YAAI,KAAK;AACP,iBAAO,GAAG;AACV;AAAA,QACF;AACA,gBAAQ,SAAS,UAAa,SAAS,IAAI;AAAA,MAC7C,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,UAAU,KAAa,SAAiB,GAAoB;AAChE,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAEtC,WAAK,OAAO,KAAK,KAAK,QAAQ,CAAC,KAAU,WAA6B;AACpE,YAAI,KAAK;AACP,iBAAO,GAAG;AACV;AAAA,QACF;AAGA,YAAI,WAAW,OAAO;AAEpB,eAAK,OAAO,IAAI,KAAK,OAAO,SAAS,GAAG,KAAK,YAAY,CAAC,WAA8B;AACtF,gBAAI,QAAQ;AACV,qBAAO,MAAM;AACb;AAAA,YACF;AACA,oBAAQ,MAAM;AAAA,UAChB,CAAC;AAAA,QACH,OAAO;AACL,kBAAQ,MAAgB;AAAA,QAC1B;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;","names":[]}
@@ -4,14 +4,14 @@ import { CacheProviderInterface } from '../CacheProviderInterface.mjs';
4
4
  /**
5
5
  * Configuration options for the in-memory cache provider.
6
6
  */
7
- interface MemoryCacheConfig {
7
+ type MemoryCacheConfig = {
8
8
  /** Maximum number of items to store in cache (default: 1000) */
9
9
  maxSize?: number;
10
10
  /** Default time to live in seconds (default: 3600) */
11
11
  defaultTTL?: number;
12
12
  /** Interval in seconds to run cleanup of expired entries (default: 600) */
13
13
  cleanupInterval?: number;
14
- }
14
+ };
15
15
  /**
16
16
  * In-memory cache provider with LRU eviction and automatic cleanup.
17
17
  * Stores cache entries in memory with support for TTL and size limits.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/MemoryCacheProvider.mts"],"sourcesContent":["import { JSONObject, JSONValue } from '@devbro/neko-helper';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\n\n/**\n * Configuration options for the in-memory cache provider.\n */\nexport interface MemoryCacheConfig {\n /** Maximum number of items to store in cache (default: 1000) */\n maxSize?: number;\n /** Default time to live in seconds (default: 3600) */\n defaultTTL?: number;\n /** Interval in seconds to run cleanup of expired entries (default: 600) */\n cleanupInterval?: number;\n}\n\n/**\n * Represents a cached item with metadata.\n */\ninterface CacheItem {\n /** The cached value */\n value: any;\n /** Timestamp when the item expires (milliseconds since epoch) */\n expiresAt?: number;\n /** Timestamp when the item was created (milliseconds since epoch) */\n createdAt: number;\n /** Timestamp when the item was last accessed (milliseconds since epoch) */\n lastAccessed: number;\n}\n\n/**\n * In-memory cache provider with LRU eviction and automatic cleanup.\n * Stores cache entries in memory with support for TTL and size limits.\n */\nexport class MemoryCacheProvider implements CacheProviderInterface {\n private cache = new Map<string, CacheItem>();\n private config: MemoryCacheConfig = {\n maxSize: 1000,\n defaultTTL: 3600,\n cleanupInterval: 600, // 10 minutes\n };\n\n private cleanupTimer?: NodeJS.Timeout;\n\n /**\n * Creates a new MemoryCacheProvider instance.\n * @param config - Configuration options for the cache\n */\n constructor(config: MemoryCacheConfig = {}) {\n this.config = { ...this.config, ...config };\n\n this.startCleanupTimer();\n }\n\n /**\n * Starts the automatic cleanup timer for expired entries.\n */\n private startCleanupTimer(): void {\n if (this.config.cleanupInterval! > 0) {\n this.cleanupTimer = setInterval(() => {\n this.cleanupExpiredEntries();\n }, this.config.cleanupInterval! * 1000);\n }\n }\n\n /**\n * Stops the automatic cleanup timer.\n */\n private stopCleanupTimer(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined;\n }\n }\n\n /**\n * Removes all expired entries from the cache.\n */\n private cleanupExpiredEntries(): void {\n const now = Date.now();\n\n for (const [key, item] of this.cache.entries()) {\n if (item.expiresAt && item.expiresAt < now) {\n this.cache.delete(key);\n }\n }\n }\n\n /**\n * Evicts the least recently used item if cache size exceeds maximum.\n */\n private evictLRU(): void {\n if (this.cache.size <= this.config.maxSize!) {\n return;\n }\n\n // Find the least recently accessed item\n let oldestKey: string | null = null;\n let oldestTime = Date.now();\n\n for (const [key, item] of this.cache.entries()) {\n if (item.lastAccessed < oldestTime) {\n oldestTime = item.lastAccessed;\n oldestKey = key;\n }\n }\n\n if (oldestKey) {\n this.cache.delete(oldestKey);\n }\n }\n\n /**\n * Retrieves a value from the cache.\n * @param key - The cache key\n * @returns The cached value or undefined if not found or expired\n */\n async get(key: string): Promise<JSONObject | JSONValue | undefined> {\n const item = this.cache.get(key);\n\n if (!item) {\n return undefined;\n }\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n this.cache.delete(key);\n return undefined;\n }\n\n // Update last accessed time for LRU\n item.lastAccessed = Date.now();\n\n return item.value;\n }\n\n /**\n * Stores a value in the cache.\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds (optional)\n */\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n const now = Date.now();\n const effectiveTTL = ttl ?? this.config.defaultTTL!;\n\n const item: CacheItem = {\n value,\n createdAt: now,\n lastAccessed: now,\n expiresAt: effectiveTTL > 0 ? now + effectiveTTL * 1000 : undefined,\n };\n\n this.cache.set(key, item);\n\n // Evict items if we exceed maxSize\n this.evictLRU();\n }\n\n /**\n * Deletes a value from the cache.\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {\n this.cache.delete(key);\n }\n\n /**\n * Checks if a key exists in the cache and has not expired.\n * @param key - The cache key to check\n * @returns True if the key exists and is not expired, false otherwise\n */\n async has(key: string): Promise<boolean> {\n const item = this.cache.get(key);\n\n if (!item) {\n return false;\n }\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n this.cache.delete(key);\n return false;\n }\n\n return true;\n }\n\n /**\n * Increments a numeric value in the cache atomically.\n * If the key doesn't exist or is expired, it starts from 0.\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The new value after incrementing\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n const item = this.cache.get(key);\n const now = Date.now();\n\n let currentValue = 0;\n\n // Check if item exists and is not expired\n if (item) {\n if (item.expiresAt && item.expiresAt < now) {\n this.cache.delete(key);\n } else {\n // Get current value, ensure it's a number\n currentValue = typeof item.value === 'number' ? item.value : 0;\n }\n }\n\n // Calculate new value\n const newValue = currentValue + amount;\n\n // Store the new value with the same TTL if it existed\n const newItem: CacheItem = {\n value: newValue,\n createdAt: item?.createdAt ?? now,\n lastAccessed: now,\n expiresAt: item?.expiresAt,\n };\n\n this.cache.set(key, newItem);\n\n return newValue;\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/providers/MemoryCacheProvider.mts"],"sourcesContent":["import { JSONObject, JSONValue } from '@devbro/neko-helper';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\n\n/**\n * Configuration options for the in-memory cache provider.\n */\nexport type MemoryCacheConfig = {\n /** Maximum number of items to store in cache (default: 1000) */\n maxSize?: number;\n /** Default time to live in seconds (default: 3600) */\n defaultTTL?: number;\n /** Interval in seconds to run cleanup of expired entries (default: 600) */\n cleanupInterval?: number;\n};\n\n/**\n * Represents a cached item with metadata.\n */\ninterface CacheItem {\n /** The cached value */\n value: any;\n /** Timestamp when the item expires (milliseconds since epoch) */\n expiresAt?: number;\n /** Timestamp when the item was created (milliseconds since epoch) */\n createdAt: number;\n /** Timestamp when the item was last accessed (milliseconds since epoch) */\n lastAccessed: number;\n}\n\n/**\n * In-memory cache provider with LRU eviction and automatic cleanup.\n * Stores cache entries in memory with support for TTL and size limits.\n */\nexport class MemoryCacheProvider implements CacheProviderInterface {\n private cache = new Map<string, CacheItem>();\n private config: MemoryCacheConfig = {\n maxSize: 1000,\n defaultTTL: 3600,\n cleanupInterval: 600, // 10 minutes\n };\n\n private cleanupTimer?: NodeJS.Timeout;\n\n /**\n * Creates a new MemoryCacheProvider instance.\n * @param config - Configuration options for the cache\n */\n constructor(config: MemoryCacheConfig = {}) {\n this.config = { ...this.config, ...config };\n\n this.startCleanupTimer();\n }\n\n /**\n * Starts the automatic cleanup timer for expired entries.\n */\n private startCleanupTimer(): void {\n if (this.config.cleanupInterval! > 0) {\n this.cleanupTimer = setInterval(() => {\n this.cleanupExpiredEntries();\n }, this.config.cleanupInterval! * 1000);\n }\n }\n\n /**\n * Stops the automatic cleanup timer.\n */\n private stopCleanupTimer(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined;\n }\n }\n\n /**\n * Removes all expired entries from the cache.\n */\n private cleanupExpiredEntries(): void {\n const now = Date.now();\n\n for (const [key, item] of this.cache.entries()) {\n if (item.expiresAt && item.expiresAt < now) {\n this.cache.delete(key);\n }\n }\n }\n\n /**\n * Evicts the least recently used item if cache size exceeds maximum.\n */\n private evictLRU(): void {\n if (this.cache.size <= this.config.maxSize!) {\n return;\n }\n\n // Find the least recently accessed item\n let oldestKey: string | null = null;\n let oldestTime = Date.now();\n\n for (const [key, item] of this.cache.entries()) {\n if (item.lastAccessed < oldestTime) {\n oldestTime = item.lastAccessed;\n oldestKey = key;\n }\n }\n\n if (oldestKey) {\n this.cache.delete(oldestKey);\n }\n }\n\n /**\n * Retrieves a value from the cache.\n * @param key - The cache key\n * @returns The cached value or undefined if not found or expired\n */\n async get(key: string): Promise<JSONObject | JSONValue | undefined> {\n const item = this.cache.get(key);\n\n if (!item) {\n return undefined;\n }\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n this.cache.delete(key);\n return undefined;\n }\n\n // Update last accessed time for LRU\n item.lastAccessed = Date.now();\n\n return item.value;\n }\n\n /**\n * Stores a value in the cache.\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds (optional)\n */\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n const now = Date.now();\n const effectiveTTL = ttl ?? this.config.defaultTTL!;\n\n const item: CacheItem = {\n value,\n createdAt: now,\n lastAccessed: now,\n expiresAt: effectiveTTL > 0 ? now + effectiveTTL * 1000 : undefined,\n };\n\n this.cache.set(key, item);\n\n // Evict items if we exceed maxSize\n this.evictLRU();\n }\n\n /**\n * Deletes a value from the cache.\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {\n this.cache.delete(key);\n }\n\n /**\n * Checks if a key exists in the cache and has not expired.\n * @param key - The cache key to check\n * @returns True if the key exists and is not expired, false otherwise\n */\n async has(key: string): Promise<boolean> {\n const item = this.cache.get(key);\n\n if (!item) {\n return false;\n }\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n this.cache.delete(key);\n return false;\n }\n\n return true;\n }\n\n /**\n * Increments a numeric value in the cache atomically.\n * If the key doesn't exist or is expired, it starts from 0.\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The new value after incrementing\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n const item = this.cache.get(key);\n const now = Date.now();\n\n let currentValue = 0;\n\n // Check if item exists and is not expired\n if (item) {\n if (item.expiresAt && item.expiresAt < now) {\n this.cache.delete(key);\n } else {\n // Get current value, ensure it's a number\n currentValue = typeof item.value === 'number' ? item.value : 0;\n }\n }\n\n // Calculate new value\n const newValue = currentValue + amount;\n\n // Store the new value with the same TTL if it existed\n const newItem: CacheItem = {\n value: newValue,\n createdAt: item?.createdAt ?? now,\n lastAccessed: now,\n expiresAt: item?.expiresAt,\n };\n\n this.cache.set(key, newItem);\n\n return newValue;\n }\n}\n"],"mappings":"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","names":[]}
@@ -2,6 +2,7 @@ import { RedisClientOptions } from 'redis';
2
2
  import { CacheProviderInterface } from '../CacheProviderInterface.mjs';
3
3
  import { JSONValue, JSONObject } from '@devbro/neko-helper';
4
4
 
5
+ type RedisCacheProviderConfig = RedisClientOptions;
5
6
  /**
6
7
  * Redis-based cache provider that stores cache entries in a Redis server.
7
8
  * Provides distributed caching with automatic expiration support.
@@ -14,7 +15,7 @@ declare class RedisCacheProvider implements CacheProviderInterface {
14
15
  * Creates a new RedisCacheProvider instance.
15
16
  * @param config - Redis client configuration options
16
17
  */
17
- constructor(config: RedisClientOptions);
18
+ constructor(config: RedisCacheProviderConfig);
18
19
  /**
19
20
  * Creates a Redis client with the provided configuration.
20
21
  * @returns A Redis client instance
@@ -57,4 +58,4 @@ declare class RedisCacheProvider implements CacheProviderInterface {
57
58
  increment(key: string, amount?: number): Promise<number>;
58
59
  }
59
60
 
60
- export { RedisCacheProvider };
61
+ export { RedisCacheProvider, type RedisCacheProviderConfig };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/RedisCacheProvider.mts"],"sourcesContent":["import { createClient, RedisClientOptions, RedisClientType } from 'redis';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONValue, JSONObject } from '@devbro/neko-helper';\n\n/**\n * Redis-based cache provider that stores cache entries in a Redis server.\n * Provides distributed caching with automatic expiration support.\n */\nexport class RedisCacheProvider implements CacheProviderInterface {\n private client: RedisClientType;\n private defaultTTL: number = 3600; // default TTL in seconds\n\n /**\n * Creates a new RedisCacheProvider instance.\n * @param config - Redis client configuration options\n */\n constructor(private config: RedisClientOptions) {\n this.client = this.createRedisClient();\n this.client.connect();\n }\n\n /**\n * Creates a Redis client with the provided configuration.\n * @returns A Redis client instance\n */\n private createRedisClient(): any {\n let rc = createClient(this.config);\n return rc;\n }\n\n /**\n * Ensures the Redis client is connected before performing operations.\n */\n private async ensureConnection(): Promise<void> {\n if (!this.client.isOpen) {\n await this.client.connect();\n }\n }\n\n /**\n * Retrieves a value from the cache.\n * @param key - The cache key\n * @returns The cached value or undefined if not found\n */\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n await this.ensureConnection();\n let rc = this.client.get(key);\n return rc.then((value) => {\n if (value === null || value === undefined) {\n return undefined;\n }\n return JSON.parse(value);\n });\n }\n\n /**\n * Stores a value in the cache.\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds (optional)\n */\n async put(key: string, value: JSONValue | JSONObject, ttl?: number): Promise<void> {\n await this.ensureConnection();\n const serializedValue = JSON.stringify(value);\n ttl = ttl ?? this.defaultTTL;\n if (ttl && ttl > 0) {\n await this.client.setEx(key, ttl, serializedValue);\n } else {\n await this.client.set(key, serializedValue);\n }\n }\n\n /**\n * Deletes a value from the cache.\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {\n await this.ensureConnection();\n await this.client.del(key);\n }\n\n /**\n * Checks if a key exists in the cache.\n * @param key - The cache key to check\n * @returns True if the key exists, false otherwise\n */\n async has(key: string): Promise<boolean> {\n await this.ensureConnection();\n const result = await this.client.exists(key);\n return result === 1;\n }\n\n /**\n * Increments a numeric value in the cache atomically using Redis INCRBY.\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The new value after incrementing\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n await this.ensureConnection();\n // Redis INCRBY is atomic\n return await this.client.incrBy(key, amount);\n }\n}\n"],"mappings":";;AAAA,SAAS,oBAAyD;AAQ3D,MAAM,mBAAqD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQhE,YAAoB,QAA4B;AAA5B;AAClB,SAAK,SAAS,KAAK,kBAAkB;AACrC,SAAK,OAAO,QAAQ;AAAA,EACtB;AAAA,EAnBF,OAQkE;AAAA;AAAA;AAAA,EACxD;AAAA,EACA,aAAqB;AAAA;AAAA;AAAA;AAAA;AAAA,EAerB,oBAAyB;AAC/B,QAAI,KAAK,aAAa,KAAK,MAAM;AACjC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,mBAAkC;AAC9C,QAAI,CAAC,KAAK,OAAO,QAAQ;AACvB,YAAM,KAAK,OAAO,QAAQ;AAAA,IAC5B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,IAAI,KAA0D;AAClE,UAAM,KAAK,iBAAiB;AAC5B,QAAI,KAAK,KAAK,OAAO,IAAI,GAAG;AAC5B,WAAO,GAAG,KAAK,CAAC,UAAU;AACxB,UAAI,UAAU,QAAQ,UAAU,QAAW;AACzC,eAAO;AAAA,MACT;AACA,aAAO,KAAK,MAAM,KAAK;AAAA,IACzB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,IAAI,KAAa,OAA+B,KAA6B;AACjF,UAAM,KAAK,iBAAiB;AAC5B,UAAM,kBAAkB,KAAK,UAAU,KAAK;AAC5C,UAAM,OAAO,KAAK;AAClB,QAAI,OAAO,MAAM,GAAG;AAClB,YAAM,KAAK,OAAO,MAAM,KAAK,KAAK,eAAe;AAAA,IACnD,OAAO;AACL,YAAM,KAAK,OAAO,IAAI,KAAK,eAAe;AAAA,IAC5C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAO,KAA4B;AACvC,UAAM,KAAK,iBAAiB;AAC5B,UAAM,KAAK,OAAO,IAAI,GAAG;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,IAAI,KAA+B;AACvC,UAAM,KAAK,iBAAiB;AAC5B,UAAM,SAAS,MAAM,KAAK,OAAO,OAAO,GAAG;AAC3C,WAAO,WAAW;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,UAAU,KAAa,SAAiB,GAAoB;AAChE,UAAM,KAAK,iBAAiB;AAE5B,WAAO,MAAM,KAAK,OAAO,OAAO,KAAK,MAAM;AAAA,EAC7C;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/providers/RedisCacheProvider.mts"],"sourcesContent":["import { createClient, RedisClientOptions, RedisClientType } from 'redis';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONValue, JSONObject } from '@devbro/neko-helper';\n\nexport type RedisCacheProviderConfig = RedisClientOptions;\n/**\n * Redis-based cache provider that stores cache entries in a Redis server.\n * Provides distributed caching with automatic expiration support.\n */\nexport class RedisCacheProvider implements CacheProviderInterface {\n private client: RedisClientType;\n private defaultTTL: number = 3600; // default TTL in seconds\n\n /**\n * Creates a new RedisCacheProvider instance.\n * @param config - Redis client configuration options\n */\n constructor(private config: RedisCacheProviderConfig) {\n this.client = this.createRedisClient();\n this.client.connect();\n }\n\n /**\n * Creates a Redis client with the provided configuration.\n * @returns A Redis client instance\n */\n private createRedisClient(): any {\n let rc = createClient(this.config);\n return rc;\n }\n\n /**\n * Ensures the Redis client is connected before performing operations.\n */\n private async ensureConnection(): Promise<void> {\n if (!this.client.isOpen) {\n await this.client.connect();\n }\n }\n\n /**\n * Retrieves a value from the cache.\n * @param key - The cache key\n * @returns The cached value or undefined if not found\n */\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n await this.ensureConnection();\n let rc = this.client.get(key);\n return rc.then((value) => {\n if (value === null || value === undefined) {\n return undefined;\n }\n return JSON.parse(value);\n });\n }\n\n /**\n * Stores a value in the cache.\n * @param key - The cache key\n * @param value - The value to cache\n * @param ttl - Time to live in seconds (optional)\n */\n async put(key: string, value: JSONValue | JSONObject, ttl?: number): Promise<void> {\n await this.ensureConnection();\n const serializedValue = JSON.stringify(value);\n ttl = ttl ?? this.defaultTTL;\n if (ttl && ttl > 0) {\n await this.client.setEx(key, ttl, serializedValue);\n } else {\n await this.client.set(key, serializedValue);\n }\n }\n\n /**\n * Deletes a value from the cache.\n * @param key - The cache key to delete\n */\n async delete(key: string): Promise<void> {\n await this.ensureConnection();\n await this.client.del(key);\n }\n\n /**\n * Checks if a key exists in the cache.\n * @param key - The cache key to check\n * @returns True if the key exists, false otherwise\n */\n async has(key: string): Promise<boolean> {\n await this.ensureConnection();\n const result = await this.client.exists(key);\n return result === 1;\n }\n\n /**\n * Increments a numeric value in the cache atomically using Redis INCRBY.\n * @param key - The cache key to increment\n * @param amount - The amount to increment by (default: 1)\n * @returns The new value after incrementing\n */\n async increment(key: string, amount: number = 1): Promise<number> {\n await this.ensureConnection();\n // Redis INCRBY is atomic\n return await this.client.incrBy(key, amount);\n }\n}\n"],"mappings":";;AAAA,SAAS,oBAAyD;AAS3D,MAAM,mBAAqD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQhE,YAAoB,QAAkC;AAAlC;AAClB,SAAK,SAAS,KAAK,kBAAkB;AACrC,SAAK,OAAO,QAAQ;AAAA,EACtB;AAAA,EApBF,OASkE;AAAA;AAAA;AAAA,EACxD;AAAA,EACA,aAAqB;AAAA;AAAA;AAAA;AAAA;AAAA,EAerB,oBAAyB;AAC/B,QAAI,KAAK,aAAa,KAAK,MAAM;AACjC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,mBAAkC;AAC9C,QAAI,CAAC,KAAK,OAAO,QAAQ;AACvB,YAAM,KAAK,OAAO,QAAQ;AAAA,IAC5B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,IAAI,KAA0D;AAClE,UAAM,KAAK,iBAAiB;AAC5B,QAAI,KAAK,KAAK,OAAO,IAAI,GAAG;AAC5B,WAAO,GAAG,KAAK,CAAC,UAAU;AACxB,UAAI,UAAU,QAAQ,UAAU,QAAW;AACzC,eAAO;AAAA,MACT;AACA,aAAO,KAAK,MAAM,KAAK;AAAA,IACzB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,IAAI,KAAa,OAA+B,KAA6B;AACjF,UAAM,KAAK,iBAAiB;AAC5B,UAAM,kBAAkB,KAAK,UAAU,KAAK;AAC5C,UAAM,OAAO,KAAK;AAClB,QAAI,OAAO,MAAM,GAAG;AAClB,YAAM,KAAK,OAAO,MAAM,KAAK,KAAK,eAAe;AAAA,IACnD,OAAO;AACL,YAAM,KAAK,OAAO,IAAI,KAAK,eAAe;AAAA,IAC5C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAO,KAA4B;AACvC,UAAM,KAAK,iBAAiB;AAC5B,UAAM,KAAK,OAAO,IAAI,GAAG;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,IAAI,KAA+B;AACvC,UAAM,KAAK,iBAAiB;AAC5B,UAAM,SAAS,MAAM,KAAK,OAAO,OAAO,GAAG;AAC3C,WAAO,WAAW;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,UAAU,KAAa,SAAiB,GAAoB;AAChE,UAAM,KAAK,iBAAiB;AAE5B,WAAO,MAAM,KAAK,OAAO,OAAO,KAAK,MAAM;AAAA,EAC7C;AACF;","names":[]}
@@ -1,4 +1,4 @@
1
- export { RedisCacheProvider } from './RedisCacheProvider.mjs';
1
+ export { RedisCacheProvider, RedisCacheProviderConfig } from './RedisCacheProvider.mjs';
2
2
  export { FileCacheConfig, FileCacheProvider } from './FileCacheProvider.mjs';
3
3
  export { MemoryCacheConfig, MemoryCacheProvider } from './MemoryCacheProvider.mjs';
4
4
  export { MemcacheCacheProvider, MemcachedConfig } from './MemcacheCacheProvider.mjs';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devbro/neko-cache",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "driver agnostic caching implementation",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",