UNPKG

react-native-healthkit-bridge

Version:

A comprehensive React Native bridge for Apple HealthKit with TypeScript support, advanced authorization, and flexible data queries

160 lines (130 loc) 3.69 kB
import { HEALTHKIT_CONFIG } from '../config/healthkit.config'; export interface CachedData<T = any> { data: T; timestamp: number; ttl: number; key: string; } export interface CacheStats { hits: number; misses: number; size: number; keys: string[]; hitRate: number; } export class HealthKitCache { private static instance: HealthKitCache; private cache = new Map<string, CachedData>(); private stats = { hits: 0, misses: 0 }; private constructor() { this.startCleanupInterval(); } static getInstance(): HealthKitCache { if (!HealthKitCache.instance) { HealthKitCache.instance = new HealthKitCache(); } return HealthKitCache.instance; } set<T>(key: string, data: T, ttl: number = HEALTHKIT_CONFIG.CACHE_TTL): void { if (!HEALTHKIT_CONFIG.CACHE_ENABLED) return; // Check cache size limit if (this.cache.size >= HEALTHKIT_CONFIG.CACHE_MAX_SIZE) { this.evictOldest(); } const cachedData: CachedData<T> = { data, timestamp: Date.now(), ttl, key }; this.cache.set(key, cachedData); } get<T>(key: string): T | null { if (!HEALTHKIT_CONFIG.CACHE_ENABLED) return null; const cachedData = this.cache.get(key) as CachedData<T>; if (!cachedData) { this.stats.misses++; return null; } // Check if expired if (Date.now() - cachedData.timestamp > cachedData.ttl) { this.cache.delete(key); this.stats.misses++; return null; } this.stats.hits++; return cachedData.data; } has(key: string): boolean { if (!HEALTHKIT_CONFIG.CACHE_ENABLED) return false; const cachedData = this.cache.get(key); if (!cachedData) return false; // Check if expired if (Date.now() - cachedData.timestamp > cachedData.ttl) { this.cache.delete(key); return false; } return true; } delete(key: string): boolean { return this.cache.delete(key); } clear(): void { this.cache.clear(); this.stats = { hits: 0, misses: 0 }; } invalidatePattern(pattern: string): void { const regex = new RegExp(pattern); for (const key of this.cache.keys()) { if (regex.test(key)) { this.cache.delete(key); } } } getStats(): CacheStats { const keys = Array.from(this.cache.keys()); const totalRequests = this.stats.hits + this.stats.misses; const hitRate = totalRequests > 0 ? this.stats.hits / totalRequests : 0; return { hits: this.stats.hits, misses: this.stats.misses, size: this.cache.size, keys, hitRate }; } private evictOldest(): void { let oldestKey: string | null = null; let oldestTime = Date.now(); for (const [key, data] of this.cache.entries()) { if (data.timestamp < oldestTime) { oldestTime = data.timestamp; oldestKey = key; } } if (oldestKey) { this.cache.delete(oldestKey); } } private startCleanupInterval(): void { // Clean up expired entries every 5 minutes setInterval(() => { const now = Date.now(); for (const [key, data] of this.cache.entries()) { if (now - data.timestamp > data.ttl) { this.cache.delete(key); } } }, 5 * 60 * 1000); } // Helper methods for common cache keys static createKey(operation: string, ...params: any[]): string { return `${operation}:${params.join(':')}`; } static createAuthKey(types: string[]): string { return `auth:${types.sort().join(',')}`; } static createQueryKey(identifier: string, unit: string, days: number): string { return `query:${identifier}:${unit}:${days}`; } }