{"version":3,"file":"storage.mjs","sources":["../../../src/lib/utils/storage.ts"],"sourcesContent":["/**\n * @file Storage Utilities\n * @description Enterprise-grade storage utilities with TTL, encryption,\n * quota management, and cross-tab synchronization\n */\n\nimport { logger } from './logging';\nimport { globalEventBus } from './eventEmitter';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Storage item with metadata\n */\nexport interface StorageItem<T> {\n  value: T;\n  timestamp: number;\n  ttl?: number;\n  version?: number;\n  encrypted?: boolean;\n}\n\n/**\n * Storage configuration\n */\nexport interface StorageConfig {\n  /** Storage prefix for namespacing */\n  prefix?: string;\n  /** Default TTL in milliseconds */\n  defaultTTL?: number;\n  /** Enable encryption for sensitive data */\n  enableEncryption?: boolean;\n  /** Encryption key (required if encryption enabled) */\n  encryptionKey?: string;\n  /** Storage version for migrations */\n  version?: number;\n  /** Maximum storage quota in bytes */\n  maxQuota?: number;\n  /** Enable cross-tab synchronization */\n  syncAcrossTabs?: boolean;\n}\n\n/**\n * Storage statistics\n */\nexport interface StorageStats {\n  itemCount: number;\n  usedBytes: number;\n  availableBytes: number;\n  expiredCount: number;\n}\n\n/**\n * Migration function type\n */\nexport type MigrationFn<T> = (oldValue: unknown, oldVersion: number) => T;\n\n// ============================================================================\n// Encryption Utilities\n// ============================================================================\n\n/**\n * Simple XOR-based obfuscation (not cryptographically secure)\n * For production, use Web Crypto API with proper encryption\n */\nfunction obfuscate(data: string, key: string): string {\n  let result = '';\n  for (let i = 0; i < data.length; i++) {\n    result += String.fromCharCode(\n      data.charCodeAt(i) ^ key.charCodeAt(i % key.length)\n    );\n  }\n  return btoa(result);\n}\n\nfunction deobfuscate(data: string, key: string): string {\n  const decoded = atob(data);\n  let result = '';\n  for (let i = 0; i < decoded.length; i++) {\n    result += String.fromCharCode(\n      decoded.charCodeAt(i) ^ key.charCodeAt(i % key.length)\n    );\n  }\n  return result;\n}\n\n/**\n * Secure encryption using Web Crypto API\n */\nexport class CryptoStorage {\n  private key: CryptoKey | null = null;\n  private keyPromise: Promise<CryptoKey> | null = null;\n\n  constructor(private passphrase: string) {}\n\n  async encrypt(data: string): Promise<string> {\n    const key = await this.getKey();\n    const encoder = new TextEncoder();\n    const iv = crypto.getRandomValues(new Uint8Array(12));\n\n    const encrypted = await crypto.subtle.encrypt(\n      { name: 'AES-GCM', iv },\n      key,\n      encoder.encode(data)\n    );\n\n    // Combine IV and encrypted data\n    const combined = new Uint8Array(iv.length + encrypted.byteLength);\n    combined.set(iv);\n    combined.set(new Uint8Array(encrypted), iv.length);\n\n    return btoa(String.fromCharCode(...combined));\n  }\n\n  async decrypt(data: string): Promise<string> {\n    const key = await this.getKey();\n    const combined = Uint8Array.from(atob(data), (c) => c.charCodeAt(0));\n\n    const iv = combined.slice(0, 12);\n    const encrypted = combined.slice(12);\n\n    const decrypted = await crypto.subtle.decrypt(\n      { name: 'AES-GCM', iv },\n      key,\n      encrypted\n    );\n\n    return new TextDecoder().decode(decrypted);\n  }\n\n  private async getKey(): Promise<CryptoKey> {\n    if (this.key) return this.key;\n    if (this.keyPromise) return this.keyPromise;\n\n    this.keyPromise = this.deriveKey();\n    this.key = await this.keyPromise;\n    return this.key;\n  }\n\n  private async deriveKey(): Promise<CryptoKey> {\n    const encoder = new TextEncoder();\n    const keyMaterial = await crypto.subtle.importKey(\n      'raw',\n      encoder.encode(this.passphrase),\n      'PBKDF2',\n      false,\n      ['deriveKey']\n    );\n\n    return crypto.subtle.deriveKey(\n      {\n        name: 'PBKDF2',\n        salt: encoder.encode('storage-salt-v1'),\n        iterations: 100000,\n        hash: 'SHA-256',\n      },\n      keyMaterial,\n      { name: 'AES-GCM', length: 256 },\n      false,\n      ['encrypt', 'decrypt']\n    );\n  }\n}\n\n// ============================================================================\n// Storage Manager\n// ============================================================================\n\n/**\n * Enterprise storage manager with TTL, encryption, and quota management\n */\nexport class StorageManager {\n  private storage: Storage;\n  private config: Required<StorageConfig>;\n  private readonly crypto: CryptoStorage | null = null;\n  private migrations = new Map<string, MigrationFn<unknown>>();\n  private broadcastChannel: BroadcastChannel | null = null;\n\n  constructor(\n    storage: Storage,\n    config: StorageConfig = {}\n  ) {\n    this.storage = storage;\n    this.config = {\n      prefix: config.prefix ?? 'app',\n      defaultTTL: config.defaultTTL ?? 0, // 0 = no expiration\n      enableEncryption: config.enableEncryption ?? false,\n      encryptionKey: config.encryptionKey ?? '',\n      version: config.version ?? 1,\n      maxQuota: config.maxQuota ?? 5 * 1024 * 1024, // 5MB default\n      syncAcrossTabs: config.syncAcrossTabs ?? true,\n    };\n\n    if (this.config.enableEncryption && this.config.encryptionKey) {\n      this.crypto = new CryptoStorage(this.config.encryptionKey);\n    }\n\n    if (this.config.syncAcrossTabs && typeof BroadcastChannel !== 'undefined') {\n      this.setupCrossTabSync();\n    }\n\n    // Periodic cleanup of expired items\n    this.scheduleCleanup();\n  }\n\n  /**\n   * Set item in storage\n   */\n  async set<T>(\n    key: string,\n    value: T,\n    options: { ttl?: number; encrypt?: boolean } = {}\n  ): Promise<void> {\n    const fullKey = this.getKey(key);\n    const ttl = options.ttl ?? this.config.defaultTTL;\n    const shouldEncrypt = options.encrypt ?? false;\n\n    const item: StorageItem<T> = {\n      value,\n      timestamp: Date.now(),\n      ttl: ttl > 0 ? ttl : undefined,\n      version: this.config.version,\n      encrypted: shouldEncrypt,\n    };\n\n    let serialized = JSON.stringify(item);\n\n    // Check quota before saving\n    const {size} = new Blob([serialized]);\n    const stats = this.getStats();\n\n    if (stats.usedBytes + size > this.config.maxQuota) {\n      // Try to free space by removing expired items\n      this.cleanup();\n\n      const newStats = this.getStats();\n      if (newStats.usedBytes + size > this.config.maxQuota) {\n        throw new StorageQuotaError(\n          `Storage quota exceeded. Need ${size} bytes, available ${this.config.maxQuota - newStats.usedBytes} bytes.`\n        );\n      }\n    }\n\n    // Encrypt if needed\n    if (shouldEncrypt) {\n      if (this.crypto) {\n        serialized = await this.crypto.encrypt(serialized);\n      } else if (this.config.encryptionKey) {\n        serialized = obfuscate(serialized, this.config.encryptionKey);\n      }\n    }\n\n    try {\n      this.storage.setItem(fullKey, serialized);\n      this.broadcast('set', key);\n      logger.debug('[Storage] Set item', { key, ttl, encrypted: shouldEncrypt });\n    } catch (error) {\n      if (error instanceof Error && error.name === 'QuotaExceededError') {\n        throw new StorageQuotaError('Browser storage quota exceeded');\n      }\n      throw error;\n    }\n  }\n\n  /**\n   * Get item from storage\n   */\n  async get<T>(key: string, defaultValue?: T): Promise<T | undefined> {\n    const fullKey = this.getKey(key);\n\n    try {\n      let serialized = this.storage.getItem(fullKey);\n      if (serialized === null || serialized === '') return defaultValue;\n\n      // Try to decrypt if it looks encrypted (base64)\n      let item: StorageItem<T>;\n\n      try {\n        item = JSON.parse(serialized) as StorageItem<T>;\n      } catch {\n        // Might be encrypted\n        if (this.crypto) {\n          serialized = await this.crypto.decrypt(serialized);\n        } else if (this.config.encryptionKey !== '') {\n          serialized = deobfuscate(serialized, this.config.encryptionKey);\n        }\n        item = JSON.parse(serialized) as StorageItem<T>;\n      }\n\n      // Check expiration\n      if (item.ttl !== undefined && item.ttl > 0 && Date.now() - item.timestamp > item.ttl) {\n        this.storage.removeItem(fullKey);\n        logger.debug('[Storage] Item expired', { key });\n        return defaultValue;\n      }\n\n      // Check version and run migration if needed\n      if (item.version !== this.config.version) {\n        const migration = this.migrations.get(key);\n        if (migration) {\n          const migratedValue = migration(item.value, item.version ?? 1) as T;\n          await this.set(key, migratedValue);\n          return migratedValue;\n        }\n      }\n\n      return item.value;\n    } catch (error) {\n      logger.error('[Storage] Failed to get item', { key, error });\n      return defaultValue;\n    }\n  }\n\n  /**\n   * Get item synchronously (no encryption support)\n   */\n  getSync<T>(key: string, defaultValue?: T): T | undefined {\n    const fullKey = this.getKey(key);\n\n    try {\n      const serialized = this.storage.getItem(fullKey);\n      if (serialized === null || serialized === '') return defaultValue;\n\n      const item: StorageItem<T> = JSON.parse(serialized) as StorageItem<T>;\n\n      // Check expiration\n      if (item.ttl !== undefined && item.ttl > 0 && Date.now() - item.timestamp > item.ttl) {\n        this.storage.removeItem(fullKey);\n        return defaultValue;\n      }\n\n      return item.value;\n    } catch {\n      return defaultValue;\n    }\n  }\n\n  /**\n   * Remove item from storage\n   */\n  remove(key: string): void {\n    const fullKey = this.getKey(key);\n    this.storage.removeItem(fullKey);\n    this.broadcast('remove', key);\n    logger.debug('[Storage] Removed item', { key });\n  }\n\n  /**\n   * Check if key exists and is not expired\n   */\n  async has(key: string): Promise<boolean> {\n    return (await this.get(key)) !== undefined;\n  }\n\n  /**\n   * Clear all items with prefix\n   */\n  clear(): void {\n    const keysToRemove: string[] = [];\n\n    for (let i = 0; i < this.storage.length; i++) {\n      const key = this.storage.key(i);\n      if (key?.startsWith(`${this.config.prefix}:`) === true) {\n        keysToRemove.push(key);\n      }\n    }\n\n    keysToRemove.forEach((key) => this.storage.removeItem(key));\n    this.broadcast('clear');\n    logger.debug('[Storage] Cleared all items', { count: keysToRemove.length });\n  }\n\n  /**\n   * Get all keys with prefix\n   */\n  keys(): string[] {\n    const keys: string[] = [];\n    const prefixLength = `${this.config.prefix}:`.length;\n\n    for (let i = 0; i < this.storage.length; i++) {\n      const key = this.storage.key(i);\n      if (key?.startsWith(`${this.config.prefix}:`) === true) {\n        keys.push(key.substring(prefixLength));\n      }\n    }\n\n    return keys;\n  }\n\n  /**\n   * Cleanup expired items\n   */\n  cleanup(): number {\n    let cleaned = 0;\n\n    for (let i = this.storage.length - 1; i >= 0; i--) {\n      const key = this.storage.key(i);\n      if (!(key?.startsWith(`${this.config.prefix}:`) ?? false)) continue;\n      if (key === null) continue;\n\n      try {\n        const serialized = this.storage.getItem(key);\n        if (serialized === null || serialized === '') continue;\n\n        const item = JSON.parse(serialized) as StorageItem<unknown>;\n\n        if (item.ttl !== undefined && item.ttl > 0 && Date.now() - item.timestamp > item.ttl) {\n          this.storage.removeItem(key);\n          cleaned++;\n        }\n      } catch {\n        // If we can't parse it, it's corrupted - remove it\n        this.storage.removeItem(key);\n        cleaned++;\n      }\n    }\n\n    if (cleaned > 0) {\n      logger.debug('[Storage] Cleaned expired items', { count: cleaned });\n    }\n\n    return cleaned;\n  }\n\n  /**\n   * Get storage statistics\n   */\n  getStats(): StorageStats {\n    let itemCount = 0;\n    let usedBytes = 0;\n    let expiredCount = 0;\n\n    for (let i = 0; i < this.storage.length; i++) {\n      const key = this.storage.key(i);\n      if (!(key?.startsWith(`${this.config.prefix}:`) ?? false)) continue;\n      if (key === null) continue;\n\n      itemCount++;\n      const value = this.storage.getItem(key);\n      if (value !== null && value !== '') {\n        usedBytes += new Blob([key, value]).size;\n\n        try {\n          const item = JSON.parse(value) as StorageItem<unknown>;\n          if (item.ttl !== undefined && item.ttl > 0 && Date.now() - item.timestamp > item.ttl) {\n            expiredCount++;\n          }\n        } catch {\n          // Ignore parse errors\n        }\n      }\n    }\n\n    return {\n      itemCount,\n      usedBytes,\n      availableBytes: this.config.maxQuota - usedBytes,\n      expiredCount,\n    };\n  }\n\n  /**\n   * Register a migration function for a key\n   */\n  registerMigration<T>(key: string, migration: MigrationFn<T>): void {\n    this.migrations.set(key, migration as MigrationFn<unknown>);\n  }\n\n  /**\n   * Dispose resources\n   */\n  dispose(): void {\n    this.broadcastChannel?.close();\n    this.broadcastChannel = null;\n  }\n\n  /**\n   * Get prefixed key\n   */\n  private getKey(key: string): string {\n    return `${this.config.prefix}:${key}`;\n  }\n\n  /**\n   * Setup cross-tab synchronization\n   */\n  private setupCrossTabSync(): void {\n    this.broadcastChannel = new BroadcastChannel(`${this.config.prefix}-storage`);\n\n    this.broadcastChannel.onmessage = (event: MessageEvent<{ type: string; key?: string }>) => {\n      const { type, key } = event.data;\n\n      if (type === 'set' && key !== undefined && key !== '') {\n        globalEventBus.emitSync('data:invalidate', { keys: [key] });\n      } else if (type === 'remove' && key !== undefined && key !== '') {\n        globalEventBus.emitSync('data:invalidate', { keys: [key] });\n      } else if (type === 'clear') {\n        globalEventBus.emitSync('data:invalidate', { keys: ['*'] });\n      }\n    };\n  }\n\n  /**\n   * Broadcast storage change to other tabs\n   */\n  private broadcast(type: 'set' | 'remove' | 'clear', key?: string): void {\n    if (this.broadcastChannel) {\n      this.broadcastChannel.postMessage({ type, key });\n    }\n  }\n\n  /**\n   * Schedule periodic cleanup of expired items\n   */\n  private scheduleCleanup(): void {\n    if (typeof window !== 'undefined') {\n      setInterval(() => this.cleanup(), 60000); // Every minute\n    }\n  }\n}\n\n// ============================================================================\n// Storage Quota Error\n// ============================================================================\n\n/**\n * Error thrown when storage quota is exceeded\n */\nexport class StorageQuotaError extends Error {\n  constructor(message: string) {\n    super(message);\n    this.name = 'StorageQuotaError';\n  }\n}\n\n// ============================================================================\n// Session Storage Manager\n// ============================================================================\n\n/**\n * Session-scoped storage with automatic cleanup\n */\nexport class SessionStorageManager extends StorageManager {\n  constructor(config: Omit<StorageConfig, 'syncAcrossTabs'> = {}) {\n    super(\n      typeof sessionStorage !== 'undefined'\n        ? sessionStorage\n        : createMemoryStorage(),\n      { ...config, syncAcrossTabs: false }\n    );\n  }\n}\n\n// ============================================================================\n// Memory Storage (SSR-safe fallback)\n// ============================================================================\n\n/**\n * In-memory storage implementation for SSR\n */\nexport function createMemoryStorage(): Storage {\n  const store = new Map<string, string>();\n\n  return {\n    get length() {\n      return store.size;\n    },\n    key(index: number): string | null {\n      const keys = Array.from(store.keys());\n      return keys[index] ?? null;\n    },\n    getItem(key: string): string | null {\n      return store.get(key) ?? null;\n    },\n    setItem(key: string, value: string): void {\n      store.set(key, value);\n    },\n    removeItem(key: string): void {\n      store.delete(key);\n    },\n    clear(): void {\n      store.clear();\n    },\n  };\n}\n\n// ============================================================================\n// Default Instances\n// ============================================================================\n\n/**\n * Default localStorage manager\n */\nexport const localStorageManager = new StorageManager(\n  typeof localStorage !== 'undefined' ? localStorage : createMemoryStorage(),\n  {\n    prefix: 'app',\n    syncAcrossTabs: true,\n  }\n);\n\n/**\n * Default sessionStorage manager\n */\nexport const sessionStorageManager = new SessionStorageManager({\n  prefix: 'app-session',\n});\n\n// ============================================================================\n// Convenience Functions\n// ============================================================================\n\n/**\n * Set item in local storage\n */\nexport async function setLocal<T>(\n  key: string,\n  value: T,\n  options?: { ttl?: number; encrypt?: boolean }\n): Promise<void> {\n  return localStorageManager.set(key, value, options);\n}\n\n/**\n * Get item from local storage\n */\nexport async function getLocal<T>(key: string, defaultValue?: T): Promise<T | undefined> {\n  return localStorageManager.get(key, defaultValue);\n}\n\n/**\n * Remove item from local storage\n */\nexport function removeLocal(key: string): void {\n  localStorageManager.remove(key);\n}\n\n/**\n * Set item in session storage\n */\nexport async function setSession<T>(\n  key: string,\n  value: T,\n  options?: { ttl?: number; encrypt?: boolean }\n): Promise<void> {\n  return sessionStorageManager.set(key, value, options);\n}\n\n/**\n * Get item from session storage\n */\nexport async function getSession<T>(key: string, defaultValue?: T): Promise<T | undefined> {\n  return sessionStorageManager.get(key, defaultValue);\n}\n\n/**\n * Remove item from session storage\n */\nexport function removeSession(key: string): void {\n  sessionStorageManager.remove(key);\n}\n"],"names":["obfuscate","data","key","result","i","deobfuscate","decoded","CryptoStorage","passphrase","encoder","iv","encrypted","combined","c","decrypted","keyMaterial","StorageManager","storage","config","value","options","fullKey","ttl","shouldEncrypt","item","serialized","size","newStats","StorageQuotaError","logger","error","defaultValue","migration","migratedValue","keysToRemove","keys","prefixLength","cleaned","itemCount","usedBytes","expiredCount","event","type","globalEventBus","message","SessionStorageManager","createMemoryStorage","store","index","localStorageManager","sessionStorageManager","setLocal","getLocal","removeLocal","setSession","getSession","removeSession"],"mappings":"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"}