apple-dev-mcp
Version:
Complete Apple development guidance: Human Interface Guidelines (design) + Technical Documentation for iOS, macOS, watchOS, tvOS, and visionOS
148 lines • 4 kB
JavaScript
/**
* Content caching layer with TTL and graceful degradation
*/
import NodeCache from 'node-cache';
export class HIGCache {
cache;
defaultTTL;
constructor(defaultTTL = 3600) {
this.cache = new NodeCache({
stdTTL: defaultTTL,
checkperiod: 600, // Check for expired keys every 10 minutes
useClones: false
});
this.defaultTTL = defaultTTL;
}
/**
* Set a cache entry with custom TTL
*/
set(key, data, ttl) {
const entry = {
data,
timestamp: new Date(),
ttl: ttl || this.defaultTTL
};
return this.cache.set(key, entry, ttl || this.defaultTTL);
}
/**
* Get a cache entry
*/
get(key) {
const entry = this.cache.get(key);
if (!entry) {
return null;
}
return entry.data;
}
/**
* Get a cache entry with metadata
*/
getWithMetadata(key) {
return this.cache.get(key) || null;
}
/**
* Check if a key exists and is not expired
*/
has(key) {
return this.cache.has(key);
}
/**
* Delete a cache entry
*/
delete(key) {
return this.cache.del(key);
}
/**
* Clear all cache entries
*/
clear() {
this.cache.flushAll();
}
/**
* Get cache statistics
*/
getStats() {
return this.cache.getStats();
}
/**
* Get all keys in cache
*/
getKeys() {
return this.cache.keys();
}
/**
* Check if cached data is stale (expired but available for graceful degradation)
*/
isStale(key) {
const entry = this.cache.get(key);
if (!entry) {
return false;
}
const now = Date.now();
const entryAge = now - entry.timestamp.getTime();
return entryAge > (entry.ttl * 1000);
}
/**
* Get stale data for graceful degradation
* Returns data even if expired, useful when fresh data fetch fails
*/
getStale(key) {
// First try to get non-expired data
const fresh = this.get(key);
if (fresh) {
return fresh;
}
// If no fresh data, try to get from internal cache even if expired
const allData = this.cache.keys().map(k => ({
key: k,
value: this.cache.get(k)
}));
const staleEntry = allData.find(item => item.key === key);
return staleEntry?.value?.data || null;
}
/**
* Set cache entry that persists longer for graceful degradation
*/
setWithGracefulDegradation(key, data, normalTTL, gracefulTTL) {
const ttl = normalTTL || this.defaultTTL;
const graceTTL = gracefulTTL || (ttl * 24); // Keep stale data 24x longer
// Set the normal cache entry
const normalResult = this.set(key, data, ttl);
// Also set a backup entry with longer TTL for graceful degradation
const backupKey = `${key}:backup`;
const backupResult = this.set(backupKey, data, graceTTL);
return normalResult && backupResult;
}
/**
* Get data with graceful degradation fallback
*/
getWithGracefulFallback(key) {
// Try to get fresh data first
const freshData = this.get(key);
if (freshData) {
return { data: freshData, isStale: false };
}
// Try to get backup data if fresh data is not available
const backupKey = `${key}:backup`;
const staleData = this.get(backupKey);
return {
data: staleData,
isStale: staleData !== null
};
}
/**
* Preload cache with critical data
*/
preload(entries) {
entries.forEach(entry => {
this.set(entry.key, entry.data, entry.ttl);
});
}
/**
* Clean up cache resources
*/
destroy() {
this.cache.close();
}
}
//# sourceMappingURL=cache.js.map