UNPKG

@neuroequality/neuroadapt-core

Version:

Core sensory, cognitive, and preference management for NeuroAdapt SDK

209 lines (208 loc) 6.33 kB
import { EventEmitter } from "eventemitter3"; import { ZodError } from "zod"; import { PreferencesUpdateSchema, PreferencesSchema, SCHEMA_VERSION } from "./schemas.js"; import { LocalStoragePreferenceStorage } from "./storage.js"; import { defaultMigrationRegistry } from "./migration.js"; class PreferenceStore extends EventEmitter { constructor(config = {}) { super(); this.isInitialized = false; this.storage = config.storage || new LocalStoragePreferenceStorage(); this.migrationRegistry = config.migrationRegistry || defaultMigrationRegistry; this.autoSave = config.autoSave ?? true; this.storageKey = config.storageKey || "default"; this.preferences = this.getDefaultPreferences(); } /** * Initialize the store by loading preferences from storage */ async initialize() { try { const stored = await this.storage.get(this.storageKey); if (stored) { this.preferences = await this.migrationRegistry.migrate(stored); this.emit("loaded", this.preferences); } this.isInitialized = true; } catch (error) { const errorObj = error instanceof Error ? error : new Error(String(error)); this.emit("error", errorObj); this.isInitialized = true; } } /** * Get current preferences */ getPreferences() { return structuredClone(this.preferences); } /** * Update preferences with validation */ async updatePreferences(updates) { if (!this.isInitialized) { await this.initialize(); } try { const validatedUpdate = PreferencesUpdateSchema.parse(updates); const previousState = structuredClone(this.preferences); const newPreferences = this.mergePreferences(this.preferences, validatedUpdate); const validatedPreferences = PreferencesSchema.parse(newPreferences); validatedPreferences.lastModified = (/* @__PURE__ */ new Date()).toISOString(); this.preferences = validatedPreferences; this.emit("change", updates, previousState); if (this.autoSave) { await this.save(); } } catch (error) { if (error instanceof ZodError) { const validationErrors = error.errors.map((err) => ({ path: err.path.map(String), message: err.message, code: err.code })); this.emit("invalid", validationErrors); throw new Error(`Validation failed: ${validationErrors.map((e) => e.message).join(", ")}`); } throw error; } } /** * Save preferences to storage */ async save() { try { await this.storage.set(this.storageKey, this.preferences); this.emit("saved", this.preferences); } catch (error) { const errorObj = error instanceof Error ? error : new Error(String(error)); this.emit("error", errorObj); throw errorObj; } } /** * Reset preferences to defaults */ async reset() { const previousState = structuredClone(this.preferences); this.preferences = this.getDefaultPreferences(); this.emit("change", this.preferences, previousState); if (this.autoSave) { await this.save(); } } /** * Export preferences as JSON */ export() { return JSON.stringify(this.preferences, null, 2); } /** * Import preferences from JSON */ async import(json) { try { const imported = JSON.parse(json); const migrated = await this.migrationRegistry.migrate(imported); const validated = PreferencesSchema.parse(migrated); const previousState = structuredClone(this.preferences); this.preferences = validated; this.emit("change", validated, previousState); if (this.autoSave) { await this.save(); } } catch (error) { if (error instanceof SyntaxError) { throw new Error("Invalid JSON format"); } if (error instanceof ZodError) { const validationErrors = error.errors.map((err) => ({ path: err.path.map(String), message: err.message, code: err.code })); this.emit("invalid", validationErrors); throw new Error(`Invalid preferences format: ${validationErrors.map((e) => e.message).join(", ")}`); } throw error; } } /** * Get specific preference section */ getSensoryPreferences() { return structuredClone(this.preferences.sensory); } getCognitivePreferences() { return structuredClone(this.preferences.cognitive); } getAIPreferences() { return structuredClone(this.preferences.ai); } getVRPreferences() { return structuredClone(this.preferences.vr); } /** * Check if store is initialized */ isReady() { return this.isInitialized; } /** * Deep merge preferences with updates */ mergePreferences(current, updates) { return { ...current, ...updates, sensory: updates.sensory ? { ...current.sensory, ...updates.sensory } : current.sensory, cognitive: updates.cognitive ? { ...current.cognitive, ...updates.cognitive } : current.cognitive, ai: updates.ai ? { ...current.ai, ...updates.ai } : current.ai, vr: updates.vr ? { ...current.vr, ...updates.vr } : current.vr, metadata: updates.metadata ? { ...current.metadata, ...updates.metadata } : current.metadata }; } /** * Get default preferences */ getDefaultPreferences() { return { schemaVersion: SCHEMA_VERSION, lastModified: (/* @__PURE__ */ new Date()).toISOString(), sensory: { motionReduction: false, highContrast: false, colorVisionFilter: "none", fontSize: 1, reducedFlashing: false, darkMode: false }, cognitive: { readingSpeed: "medium", explanationLevel: "detailed", processingPace: "standard", chunkSize: 5, allowInterruptions: true, preferVisualCues: false }, ai: { tone: "neutral", responseLength: "standard", consistencyLevel: "moderate", useAnalogies: true, allowUndo: true }, vr: { comfortRadius: 1.5, safeSpaceEnabled: true, locomotionType: "comfort", personalSpace: 1, panicButtonEnabled: true } }; } } export { PreferenceStore }; //# sourceMappingURL=store.js.map