UNPKG

okta-mcp-server

Version:

Model Context Protocol (MCP) server for Okta API operations with support for bulk operations and caching

131 lines 3.67 kB
/** * In-memory cache implementation */ export class MemoryCache { cache = new Map(); tagIndex = new Map(); maxSize; eventBus; constructor(options = {}) { this.maxSize = options.maxSize || 1000; if (options.eventBus) { this.eventBus = options.eventBus; } } async get(key) { const entry = this.cache.get(key); if (!entry) { this.eventBus?.emit('cache:miss', { key }); return undefined; } if (entry.expires < Date.now()) { await this.delete(key); this.eventBus?.emit('cache:miss', { key }); return undefined; } this.eventBus?.emit('cache:hit', { key }); return entry.value; } async set(key, value, options) { // Evict old entries if at capacity if (this.cache.size >= this.maxSize && !this.cache.has(key)) { const oldestKey = this.cache.keys().next().value; if (oldestKey) { await this.delete(oldestKey); } } const ttl = options?.ttl || 300; // Default 5 minutes const expires = Date.now() + ttl * 1000; const entry = { value, expires, ...(options?.tags && { tags: options.tags }), }; this.cache.set(key, entry); // Update tag index if (options?.tags) { for (const tag of options.tags) { if (!this.tagIndex.has(tag)) { this.tagIndex.set(tag, new Set()); } this.tagIndex.get(tag).add(key); } } this.eventBus?.emit('cache:set', { key, ttl }); } async delete(key) { const entry = this.cache.get(key); if (!entry) { return false; } // Remove from tag index if (entry.tags) { for (const tag of entry.tags) { const keys = this.tagIndex.get(tag); if (keys) { keys.delete(key); if (keys.size === 0) { this.tagIndex.delete(tag); } } } } return this.cache.delete(key); } async has(key) { const entry = this.cache.get(key); if (!entry) { return false; } if (entry.expires < Date.now()) { await this.delete(key); return false; } return true; } async clear() { this.cache.clear(); this.tagIndex.clear(); this.eventBus?.emit('cache:clear', {}); } async clearByTag(tag) { const keys = this.tagIndex.get(tag); if (!keys) { return; } for (const key of keys) { await this.delete(key); } this.eventBus?.emit('cache:clear', { pattern: `tag:${tag}` }); } async size() { // Clean up expired entries first const now = Date.now(); const expiredKeys = []; for (const [key, entry] of this.cache) { if (entry.expires < now) { expiredKeys.push(key); } } for (const key of expiredKeys) { await this.delete(key); } return this.cache.size; } /** * Get all keys (for debugging) */ async keys() { return Array.from(this.cache.keys()); } /** * Get cache statistics */ getStats() { return { size: this.cache.size, tags: this.tagIndex.size, }; } } //# sourceMappingURL=memory-cache.js.map