UNPKG

strata-storage

Version:

Zero-dependency universal storage plugin providing a unified API for all storage operations across web, Android, and iOS platforms

201 lines (200 loc) 6.38 kB
/** * Storage strategy implementation for automatic adapter selection */ import { StorageStrategy } from '@/types'; import { AdapterRegistry } from "./AdapterRegistry.js"; /** * Strategy manager for selecting appropriate storage adapters */ export class StrategyManager { registry; strategy; constructor(registry, strategy = StorageStrategy.PERFORMANCE_FIRST) { this.registry = registry; this.strategy = strategy; } /** * Get the best adapter based on current strategy */ async getBestAdapter(preferredTypes, requirements) { const available = await this.registry.getAvailable(); // Filter by preferred types if specified let candidates = preferredTypes ? available.filter((adapter) => preferredTypes.includes(adapter.name)) : available; // Filter by requirements if (requirements) { candidates = candidates.filter((adapter) => this.meetsRequirements(adapter.capabilities, requirements)); } // Sort by strategy candidates.sort((a, b) => this.compareAdapters(a, b)); return candidates[0] || null; } /** * Get multiple adapters sorted by preference */ async getAdapterChain(count, preferredTypes, requirements) { const available = await this.registry.getAvailable(); let candidates = preferredTypes ? available.filter((adapter) => preferredTypes.includes(adapter.name)) : available; if (requirements) { candidates = candidates.filter((adapter) => this.meetsRequirements(adapter.capabilities, requirements)); } candidates.sort((a, b) => this.compareAdapters(a, b)); return candidates.slice(0, count); } /** * Check if capabilities meet requirements */ meetsRequirements(capabilities, requirements) { for (const [key, value] of Object.entries(requirements)) { const capKey = key; if (typeof value === 'boolean' && capabilities[capKey] !== value) { return false; } if (capKey === 'maxSize' && typeof value === 'number') { const capSize = capabilities.maxSize; if (capSize !== -1 && capSize < value) { return false; } } } return true; } /** * Compare two adapters based on current strategy */ compareAdapters(a, b) { switch (this.strategy) { case StorageStrategy.PERFORMANCE_FIRST: return this.comparePerformance(a, b); case StorageStrategy.PERSISTENCE_FIRST: return this.comparePersistence(a, b); case StorageStrategy.SECURITY_FIRST: return this.compareSecurity(a, b); case StorageStrategy.CAPACITY_FIRST: return this.compareCapacity(a, b); default: return 0; } } /** * Compare adapters by performance */ comparePerformance(a, b) { // Priority order for performance const performanceOrder = [ 'memory', 'sessionStorage', 'localStorage', 'cache', 'indexedDB', 'preferences', 'sqlite', 'filesystem', 'cookies', 'secure', ]; const aIndex = performanceOrder.indexOf(a.name); const bIndex = performanceOrder.indexOf(b.name); // Prefer synchronous adapters for performance if (a.capabilities.synchronous !== b.capabilities.synchronous) { return a.capabilities.synchronous ? -1 : 1; } return aIndex - bIndex; } /** * Compare adapters by persistence */ comparePersistence(a, b) { // Prefer persistent storage if (a.capabilities.persistent !== b.capabilities.persistent) { return a.capabilities.persistent ? -1 : 1; } // Priority order for persistence const persistenceOrder = [ 'sqlite', 'filesystem', 'secure', 'indexedDB', 'preferences', 'localStorage', 'cache', 'cookies', 'sessionStorage', 'memory', ]; const aIndex = persistenceOrder.indexOf(a.name); const bIndex = persistenceOrder.indexOf(b.name); return aIndex - bIndex; } /** * Compare adapters by security */ compareSecurity(a, b) { // Prefer encrypted storage if (a.capabilities.encrypted !== b.capabilities.encrypted) { return a.capabilities.encrypted ? -1 : 1; } // Priority order for security const securityOrder = [ 'secure', 'preferences', 'sqlite', 'indexedDB', 'filesystem', 'localStorage', 'sessionStorage', 'cache', 'memory', 'cookies', ]; const aIndex = securityOrder.indexOf(a.name); const bIndex = securityOrder.indexOf(b.name); return aIndex - bIndex; } /** * Compare adapters by capacity */ compareCapacity(a, b) { // Compare max sizes (-1 means unlimited) const aSize = a.capabilities.maxSize; const bSize = b.capabilities.maxSize; if (aSize === -1 && bSize !== -1) return -1; if (bSize === -1 && aSize !== -1) return 1; if (aSize !== -1 && bSize !== -1) { return bSize - aSize; // Higher capacity first } // Priority order for capacity const capacityOrder = [ 'filesystem', 'sqlite', 'indexedDB', 'cache', 'preferences', 'secure', 'localStorage', 'memory', 'sessionStorage', 'cookies', ]; const aIndex = capacityOrder.indexOf(a.name); const bIndex = capacityOrder.indexOf(b.name); return aIndex - bIndex; } /** * Update strategy */ setStrategy(strategy) { this.strategy = strategy; } /** * Get current strategy */ getStrategy() { return this.strategy; } }