@ort-fe/storage-cache-kit
Version:
Unified client-side cache and storage manager with expiration control
1 lines • 50 kB
Source Map (JSON)
{"version":3,"file":"index.cjs","sources":["../src/utils/crypto.ts","../src/utils/environment.ts","../src/utils/index.ts","../src/adapters/localStorage.ts","../src/adapters/sessionStorage.ts","../src/adapters/memoryStorage.ts","../src/adapters/cookieStorage.ts","../src/adapters/index.ts","../src/core/StorageManager.ts","../src/core/SimpleStore.ts","../src/index.ts"],"sourcesContent":["/**\r\n * 简单的加密工具\r\n * 注意:这只是基本的加密,不适用于高安全性要求\r\n */\r\n\r\n/**\r\n * 简单加密字符串\r\n * @param value 要加密的字符串\r\n * @returns 加密后的字符串\r\n */\r\nexport function encrypt(value: string): string {\r\n try {\r\n // 使用 Base64 编码作为简单加密\r\n return btoa(encodeURIComponent(value));\r\n } catch (error) {\r\n console.error('Encryption failed:', error);\r\n return value;\r\n }\r\n}\r\n\r\n/**\r\n * 解密字符串\r\n * @param encryptedValue 加密的字符串\r\n * @returns 解密后的字符串\r\n */\r\nexport function decrypt(encryptedValue: string): string {\r\n try {\r\n // 解码 Base64 字符串\r\n return decodeURIComponent(atob(encryptedValue));\r\n } catch (error) {\r\n console.error('Decryption failed:', error);\r\n return encryptedValue;\r\n }\r\n} ","/**\r\n * 检测当前是否为Node.js环境\r\n * @returns 是否为Node环境\r\n */\r\nexport function isNodeEnvironment(): boolean {\r\n return (\r\n typeof process !== 'undefined' &&\r\n process.versions != null &&\r\n process.versions.node != null\r\n );\r\n}\r\n\r\n/**\r\n * 检测当前是否为浏览器环境\r\n * @returns 是否为浏览器环境\r\n */\r\nexport function isBrowserEnvironment(): boolean {\r\n // 如果window和document存在,则认为是浏览器环境\r\n // 这也会包括测试环境中模拟的浏览器环境\r\n return (\r\n typeof window !== 'undefined' &&\r\n typeof document !== 'undefined'\r\n );\r\n}\r\n\r\n/**\r\n * 检测当前是否为测试环境\r\n * @returns 是否为测试环境\r\n */\r\nexport function isTestEnvironment(): boolean {\r\n return (\r\n // Vitest环境检测\r\n typeof process !== 'undefined' &&\r\n process.env &&\r\n (process.env.NODE_ENV === 'test' || \r\n process.env.VITEST !== undefined)\r\n );\r\n}\r\n\r\n/**\r\n * 全局警告跟踪对象\r\n * 用于防止重复显示同一警告\r\n */\r\nexport const warnOnce = (() => {\r\n // 保存已经显示过的警告\r\n const warnings: Record<string, boolean> = {};\r\n \r\n /**\r\n * 确保每个警告只显示一次\r\n * @param message 警告消息\r\n */\r\n return function(message: string): void {\r\n if (!warnings[message]) {\r\n console.warn(message);\r\n warnings[message] = true;\r\n }\r\n };\r\n})(); ","import type { StorageItem } from '../types';\r\nimport { encrypt, decrypt } from './crypto';\r\nimport { isNodeEnvironment, isBrowserEnvironment, isTestEnvironment } from './environment';\r\n\r\n/**\r\n * 检查存储项是否过期\r\n * @param item 存储项\r\n * @returns 是否过期\r\n */\r\nexport function isExpired(item: StorageItem): boolean {\r\n if (!item.expires) return false;\r\n const now = Date.now();\r\n return now - item.timestamp > item.expires;\r\n}\r\n\r\n/**\r\n * 序列化存储项\r\n * @param item 存储项\r\n * @param shouldEncrypt 是否加密\r\n * @returns 序列化后的字符串\r\n */\r\nexport function serializeItem<T>(item: StorageItem<T>, shouldEncrypt: boolean = false): string {\r\n const serialized = JSON.stringify(item);\r\n return shouldEncrypt ? encrypt(serialized) : serialized;\r\n}\r\n\r\n/**\r\n * 反序列化存储项\r\n * @param data 序列化的字符串\r\n * @param isEncrypted 是否为加密数据\r\n * @returns 存储项对象\r\n */\r\nexport function deserializeItem<T>(data: string, isEncrypted: boolean = false): StorageItem<T> {\r\n try {\r\n const decryptedData = isEncrypted ? decrypt(data) : data;\r\n return JSON.parse(decryptedData) as StorageItem<T>;\r\n } catch (error) {\r\n console.error('Failed to deserialize item:', error);\r\n throw new Error('Invalid storage item format');\r\n }\r\n}\r\n\r\n/**\r\n * 解析存储项,兼容非标准格式\r\n * @param data 存储的数据字符串\r\n * @param isEncrypted 是否为加密数据\r\n * @returns 标准格式的存储项或undefined\r\n */\r\nexport function parseStorageItem<T>(data: string, isEncrypted: boolean = false): StorageItem<T> | undefined {\r\n if (!data) return undefined;\r\n \r\n // 首先尝试按照标准格式解析\r\n try {\r\n const parsedItem = deserializeItem<T>(data, isEncrypted);\r\n // 验证是否符合标准格式\r\n if (\r\n parsedItem && \r\n typeof parsedItem === 'object' && \r\n 'value' in parsedItem && \r\n 'timestamp' in parsedItem\r\n ) {\r\n return parsedItem;\r\n }\r\n } catch (e) {\r\n // 解析标准格式失败,继续处理\r\n // 在调试模式下可以记录详细信息\r\n if (process.env.NODE_ENV === 'development') {\r\n console.debug('Item not in standard format, trying alternative parsing:', e);\r\n }\r\n }\r\n \r\n // 尝试解析为 JSON\r\n let value: T;\r\n try {\r\n value = JSON.parse(data) as T;\r\n if (process.env.NODE_ENV === 'development') {\r\n console.debug('Successfully parsed as JSON:', value);\r\n }\r\n } catch (e) {\r\n // 如果 JSON 解析失败,则使用原始字符串\r\n value = data as unknown as T;\r\n if (process.env.NODE_ENV === 'development') {\r\n console.debug('Using raw string as value:', data);\r\n }\r\n }\r\n \r\n // 返回兼容的 StorageItem\r\n return {\r\n value,\r\n timestamp: Date.now(),\r\n expires: undefined\r\n };\r\n}\r\n\r\n/**\r\n * 生成带命名空间的键名\r\n * @param key 原始键名\r\n * @param namespace 命名空间\r\n * @returns 带命名空间的键名\r\n */\r\nexport function namespaceKey(key: string, namespace?: string): string {\r\n return namespace ? `${namespace}:${key}` : key;\r\n}\r\n\r\nexport { isNodeEnvironment, isBrowserEnvironment, isTestEnvironment }; ","import type { StorageAdapter, StorageItem } from '../types';\r\nimport { serializeItem, parseStorageItem } from '../utils';\r\nimport { warnOnce } from '../utils/environment';\r\n\r\n// 检查 localStorage 是否可用\r\nfunction isLocalStorageAvailable(): boolean {\r\n try {\r\n if (typeof localStorage === 'undefined') return false;\r\n \r\n // 测试 localStorage 是否可写\r\n const testKey = '__test_localStorage__';\r\n localStorage.setItem(testKey, 'test');\r\n localStorage.removeItem(testKey);\r\n return true;\r\n } catch (e) {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * localStorage 存储适配器\r\n */\r\nexport class LocalStorageAdapter implements StorageAdapter {\r\n private readonly encrypt: boolean;\r\n private readonly available: boolean;\r\n\r\n /**\r\n * 创建 localStorage 适配器\r\n * @param encrypt 是否加密数据\r\n */\r\n constructor(encrypt: boolean = false) {\r\n this.encrypt = encrypt;\r\n this.available = isLocalStorageAvailable();\r\n \r\n if (!this.available) {\r\n warnOnce('localStorage is not available in this environment.');\r\n }\r\n }\r\n\r\n /**\r\n * 设置存储项\r\n * @param key 键名\r\n * @param item 存储项\r\n */\r\n async setItem<T>(key: string, item: StorageItem<T>): Promise<void> {\r\n if (!this.available) {\r\n throw new Error('localStorage is not available in this environment');\r\n }\r\n \r\n try {\r\n const serialized = serializeItem(item, this.encrypt);\r\n localStorage.setItem(key, serialized);\r\n } catch (error) {\r\n console.error(`Failed to set item '${key}':`, error);\r\n throw new Error(`Failed to set item '${key}'`);\r\n }\r\n }\r\n\r\n /**\r\n * 获取存储项\r\n * @param key 键名\r\n * @returns 存储项或undefined(如果不存在)\r\n */\r\n async getItem<T>(key: string): Promise<StorageItem<T> | undefined> {\r\n if (!this.available) {\r\n throw new Error('localStorage is not available in this environment');\r\n }\r\n \r\n try {\r\n const data = localStorage.getItem(key);\r\n if (!data) return undefined;\r\n \r\n // 使用通用函数处理标准和非标准格式\r\n return parseStorageItem<T>(data, this.encrypt);\r\n } catch (error) {\r\n console.error(`Failed to get item '${key}':`, error);\r\n return undefined;\r\n }\r\n }\r\n\r\n /**\r\n * 移除存储项\r\n * @param key 键名\r\n */\r\n async removeItem(key: string): Promise<void> {\r\n if (!this.available) {\r\n throw new Error('localStorage is not available in this environment');\r\n }\r\n \r\n localStorage.removeItem(key);\r\n }\r\n\r\n /**\r\n * 清空所有存储\r\n */\r\n async clear(): Promise<void> {\r\n if (!this.available) {\r\n throw new Error('localStorage is not available in this environment');\r\n }\r\n \r\n localStorage.clear();\r\n }\r\n\r\n /**\r\n * 获取所有键名\r\n * @returns 键名数组\r\n */\r\n async keys(): Promise<string[]> {\r\n if (!this.available) {\r\n throw new Error('localStorage is not available in this environment');\r\n }\r\n \r\n const keys: string[] = [];\r\n for (let i = 0; i < localStorage.length; i++) {\r\n const key = localStorage.key(i);\r\n if (key) {\r\n keys.push(key);\r\n }\r\n }\r\n return keys;\r\n }\r\n} ","import type { StorageAdapter, StorageItem } from '../types';\r\nimport { serializeItem, parseStorageItem } from '../utils';\r\nimport { warnOnce } from '../utils/environment';\r\n\r\n// 检查 sessionStorage 是否可用\r\nfunction isSessionStorageAvailable(): boolean {\r\n try {\r\n if (typeof sessionStorage === 'undefined') return false;\r\n \r\n // 测试 sessionStorage 是否可写\r\n const testKey = '__test_sessionStorage__';\r\n sessionStorage.setItem(testKey, 'test');\r\n sessionStorage.removeItem(testKey);\r\n return true;\r\n } catch (e) {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * sessionStorage 存储适配器\r\n */\r\nexport class SessionStorageAdapter implements StorageAdapter {\r\n private readonly encrypt: boolean;\r\n private readonly available: boolean;\r\n\r\n /**\r\n * 创建 sessionStorage 适配器\r\n * @param encrypt 是否加密数据\r\n */\r\n constructor(encrypt: boolean = false) {\r\n this.encrypt = encrypt;\r\n this.available = isSessionStorageAvailable();\r\n \r\n if (!this.available) {\r\n warnOnce('sessionStorage is not available in this environment.');\r\n }\r\n }\r\n\r\n /**\r\n * 设置存储项\r\n * @param key 键名\r\n * @param item 存储项\r\n */\r\n async setItem<T>(key: string, item: StorageItem<T>): Promise<void> {\r\n if (!this.available) {\r\n throw new Error('sessionStorage is not available in this environment');\r\n }\r\n \r\n try {\r\n const serialized = serializeItem(item, this.encrypt);\r\n sessionStorage.setItem(key, serialized);\r\n } catch (error) {\r\n console.error(`Failed to set item '${key}':`, error);\r\n throw new Error(`Failed to set item '${key}'`);\r\n }\r\n }\r\n\r\n /**\r\n * 获取存储项\r\n * @param key 键名\r\n * @returns 存储项或undefined(如果不存在)\r\n */\r\n async getItem<T>(key: string): Promise<StorageItem<T> | undefined> {\r\n if (!this.available) {\r\n throw new Error('sessionStorage is not available in this environment');\r\n }\r\n \r\n try {\r\n const data = sessionStorage.getItem(key);\r\n if (!data) return undefined;\r\n\r\n // 使用通用函数处理标准和非标准格式\r\n return parseStorageItem<T>(data, this.encrypt);\r\n } catch (error) {\r\n console.error(`Failed to get item '${key}':`, error);\r\n return undefined;\r\n }\r\n }\r\n\r\n /**\r\n * 移除存储项\r\n * @param key 键名\r\n */\r\n async removeItem(key: string): Promise<void> {\r\n if (!this.available) {\r\n throw new Error('sessionStorage is not available in this environment');\r\n }\r\n \r\n sessionStorage.removeItem(key);\r\n }\r\n\r\n /**\r\n * 清空所有存储\r\n */\r\n async clear(): Promise<void> {\r\n if (!this.available) {\r\n throw new Error('sessionStorage is not available in this environment');\r\n }\r\n \r\n sessionStorage.clear();\r\n }\r\n\r\n /**\r\n * 获取所有键名\r\n * @returns 键名数组\r\n */\r\n async keys(): Promise<string[]> {\r\n if (!this.available) {\r\n throw new Error('sessionStorage is not available in this environment');\r\n }\r\n \r\n const keys: string[] = [];\r\n for (let i = 0; i < sessionStorage.length; i++) {\r\n const key = sessionStorage.key(i);\r\n if (key) {\r\n keys.push(key);\r\n }\r\n }\r\n return keys;\r\n }\r\n} ","import type { StorageAdapter, StorageItem } from '../types';\r\nimport { serializeItem, parseStorageItem } from '../utils';\r\n\r\n/**\r\n * 内存存储适配器\r\n * 用于在内存中临时存储数据,页面刷新后数据会丢失\r\n */\r\nexport class MemoryStorageAdapter implements StorageAdapter {\r\n private storage: Map<string, string> = new Map();\r\n private readonly encrypt: boolean;\r\n\r\n /**\r\n * 创建内存存储适配器\r\n * @param encrypt 是否加密数据\r\n */\r\n constructor(encrypt: boolean = false) {\r\n this.encrypt = encrypt;\r\n }\r\n\r\n /**\r\n * 设置存储项\r\n * @param key 键名\r\n * @param item 存储项\r\n */\r\n async setItem<T>(key: string, item: StorageItem<T>): Promise<void> {\r\n try {\r\n const serialized = serializeItem(item, this.encrypt);\r\n this.storage.set(key, serialized);\r\n } catch (error) {\r\n console.error(`Failed to set item '${key}':`, error);\r\n throw new Error(`Failed to set item '${key}'`);\r\n }\r\n }\r\n\r\n /**\r\n * 获取存储项\r\n * @param key 键名\r\n * @returns 存储项或undefined(如果不存在)\r\n */\r\n async getItem<T>(key: string): Promise<StorageItem<T> | undefined> {\r\n try {\r\n const data = this.storage.get(key);\r\n if (!data) return undefined;\r\n \r\n // 使用通用函数处理标准和非标准格式\r\n return parseStorageItem<T>(data, this.encrypt);\r\n } catch (error) {\r\n console.error(`Failed to get item '${key}':`, error);\r\n return undefined;\r\n }\r\n }\r\n\r\n /**\r\n * 移除存储项\r\n * @param key 键名\r\n */\r\n async removeItem(key: string): Promise<void> {\r\n this.storage.delete(key);\r\n }\r\n\r\n /**\r\n * 清空所有存储\r\n */\r\n async clear(): Promise<void> {\r\n this.storage.clear();\r\n }\r\n\r\n /**\r\n * 获取所有键名\r\n * @returns 键名数组\r\n */\r\n async keys(): Promise<string[]> {\r\n return Array.from(this.storage.keys());\r\n }\r\n} ","import type { StorageAdapter, StorageItem } from '../types';\r\nimport { serializeItem, parseStorageItem } from '../utils';\r\nimport { warnOnce } from '../utils/environment';\r\n\r\n// 检查 cookie 是否可用\r\nfunction isCookieAvailable(): boolean {\r\n try {\r\n if (typeof document === 'undefined' || typeof document.cookie === 'undefined') {\r\n return false;\r\n }\r\n \r\n // 测试 cookie 是否可写\r\n const testKey = '__test_cookie__';\r\n const testValue = 'test';\r\n const now = new Date();\r\n now.setTime(now.getTime() + 1000); // 1秒后过期\r\n \r\n document.cookie = `${testKey}=${testValue}; expires=${now.toUTCString()}; path=/`;\r\n const success = document.cookie.indexOf(testKey) !== -1;\r\n \r\n // 立即删除测试 cookie\r\n document.cookie = `${testKey}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;\r\n \r\n return success;\r\n } catch (e) {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Cookie存储适配器\r\n */\r\nexport class CookieStorageAdapter implements StorageAdapter {\r\n private readonly encrypt: boolean;\r\n private readonly defaultDays: number;\r\n private readonly path: string;\r\n private readonly domain?: string;\r\n private readonly secure: boolean;\r\n private readonly sameSite: 'strict' | 'lax' | 'none';\r\n private readonly available: boolean;\r\n\r\n /**\r\n * 创建Cookie存储适配器\r\n * @param options Cookie配置选项\r\n */\r\n constructor(options: {\r\n encrypt?: boolean;\r\n defaultDays?: number;\r\n path?: string;\r\n domain?: string;\r\n secure?: boolean;\r\n sameSite?: 'strict' | 'lax' | 'none';\r\n } = {}) {\r\n this.encrypt = options.encrypt || false;\r\n this.defaultDays = options.defaultDays || 7; // 默认7天\r\n this.path = options.path || '/';\r\n this.domain = options.domain;\r\n this.secure = options.secure || false;\r\n this.sameSite = options.sameSite || 'lax';\r\n this.available = isCookieAvailable();\r\n \r\n if (!this.available) {\r\n warnOnce('Cookie is not available in this environment.');\r\n }\r\n }\r\n\r\n /**\r\n * 设置存储项\r\n * @param key 键名\r\n * @param item 存储项\r\n */\r\n async setItem<T>(key: string, item: StorageItem<T>): Promise<void> {\r\n if (!this.available) {\r\n throw new Error('Cookie is not available in this environment');\r\n }\r\n \r\n try {\r\n const serialized = serializeItem(item, this.encrypt);\r\n \r\n // 计算过期时间\r\n const days = item.expires ? Math.ceil(item.expires / (24 * 60 * 60 * 1000)) : this.defaultDays;\r\n const expiresDate = new Date();\r\n expiresDate.setTime(expiresDate.getTime() + days * 24 * 60 * 60 * 1000);\r\n \r\n // 构建cookie字符串\r\n let cookieStr = `${encodeURIComponent(key)}=${encodeURIComponent(serialized)}; expires=${expiresDate.toUTCString()}; path=${this.path}`;\r\n \r\n if (this.domain) {\r\n cookieStr += `; domain=${this.domain}`;\r\n }\r\n \r\n if (this.secure) {\r\n cookieStr += '; secure';\r\n }\r\n \r\n cookieStr += `; samesite=${this.sameSite}`;\r\n \r\n // 设置cookie\r\n document.cookie = cookieStr;\r\n } catch (error) {\r\n console.error(`Failed to set cookie '${key}':`, error);\r\n throw new Error(`Failed to set cookie '${key}'`);\r\n }\r\n }\r\n\r\n /**\r\n * 获取存储项\r\n * @param key 键名\r\n * @returns 存储项或undefined(如果不存在)\r\n */\r\n async getItem<T>(key: string): Promise<StorageItem<T> | undefined> {\r\n if (!this.available) {\r\n throw new Error('Cookie is not available in this environment');\r\n }\r\n \r\n try {\r\n const cookies = document.cookie.split(';');\r\n const encodedKey = encodeURIComponent(key);\r\n \r\n for (const cookie of cookies) {\r\n const [cookieKey, cookieValue] = cookie.trim().split('=');\r\n \r\n if (cookieKey === encodedKey && cookieValue) {\r\n const decodedValue = decodeURIComponent(cookieValue);\r\n \r\n // 使用通用函数处理标准和非标准格式\r\n return parseStorageItem<T>(decodedValue, this.encrypt);\r\n }\r\n }\r\n \r\n return undefined;\r\n } catch (error) {\r\n console.error(`Failed to get cookie '${key}':`, error);\r\n return undefined;\r\n }\r\n }\r\n\r\n /**\r\n * 移除存储项\r\n * @param key 键名\r\n */\r\n async removeItem(key: string): Promise<void> {\r\n if (!this.available) {\r\n throw new Error('Cookie is not available in this environment');\r\n }\r\n \r\n // 设置过期时间为过去,即删除cookie\r\n document.cookie = `${encodeURIComponent(key)}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=${this.path}`;\r\n \r\n if (this.domain) {\r\n document.cookie = `${encodeURIComponent(key)}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=${this.path}; domain=${this.domain}`;\r\n }\r\n }\r\n\r\n /**\r\n * 清空所有存储\r\n * 注意:只能清除当前域下的cookie,且受路径限制\r\n */\r\n async clear(): Promise<void> {\r\n if (!this.available) {\r\n throw new Error('Cookie is not available in this environment');\r\n }\r\n \r\n const cookies = document.cookie.split(';');\r\n \r\n for (const cookie of cookies) {\r\n const cookieKey = cookie.split('=')[0].trim();\r\n await this.removeItem(cookieKey);\r\n }\r\n }\r\n\r\n /**\r\n * 获取所有键名\r\n * @returns 键名数组\r\n */\r\n async keys(): Promise<string[]> {\r\n if (!this.available) {\r\n throw new Error('Cookie is not available in this environment');\r\n }\r\n \r\n const cookies = document.cookie.split(';');\r\n const keys: string[] = [];\r\n \r\n for (const cookie of cookies) {\r\n if (cookie.trim()) {\r\n const cookieKey = cookie.split('=')[0].trim();\r\n keys.push(decodeURIComponent(cookieKey));\r\n }\r\n }\r\n \r\n return keys;\r\n }\r\n} ","import { LocalStorageAdapter } from './localStorage';\r\nimport { SessionStorageAdapter } from './sessionStorage';\r\nimport { MemoryStorageAdapter } from './memoryStorage';\r\nimport { CookieStorageAdapter } from './cookieStorage';\r\n\r\nexport {\r\n LocalStorageAdapter,\r\n SessionStorageAdapter,\r\n MemoryStorageAdapter,\r\n CookieStorageAdapter\r\n};\r\n\r\n// 适配器类型常量\r\nexport const ADAPTER_TYPES = {\r\n LOCAL_STORAGE: 'localStorage',\r\n SESSION_STORAGE: 'sessionStorage',\r\n MEMORY: 'memory',\r\n COOKIE: 'cookie'\r\n} as const;\r\n\r\n// 适配器类型\r\nexport type AdapterType = typeof ADAPTER_TYPES[keyof typeof ADAPTER_TYPES]; ","import type {\r\n StorageAdapter,\r\n StorageItem,\r\n StorageItemOptions,\r\n StorageManagerOptions\r\n} from '../types'\r\nimport {\r\n isExpired,\r\n namespaceKey,\r\n isNodeEnvironment,\r\n isBrowserEnvironment,\r\n isTestEnvironment\r\n} from '../utils'\r\nimport {\r\n LocalStorageAdapter,\r\n SessionStorageAdapter,\r\n MemoryStorageAdapter,\r\n CookieStorageAdapter,\r\n ADAPTER_TYPES\r\n} from '../adapters'\r\nimport type { AdapterType } from '../adapters'\r\nimport { warnOnce } from '../utils/environment'\r\n\r\n/**\r\n * 扩展的存储项选项\r\n */\r\ninterface ExtendedStorageItemOptions extends StorageItemOptions {\r\n adapter?: AdapterType | string\r\n}\r\n\r\n/**\r\n * 安全地检查是否为开发环境\r\n * 同时兼容Node.js和浏览器环境\r\n */\r\nfunction isDevelopment(): boolean {\r\n try {\r\n // Node.js 环境\r\n if (typeof process !== 'undefined' && process.env) {\r\n return process.env.NODE_ENV === 'development';\r\n }\r\n // 浏览器环境\r\n return false; // 在浏览器中默认不开启调试日志\r\n } catch (e) {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * 安全地输出调试日志\r\n * 同时兼容Node.js和浏览器环境\r\n */\r\nfunction debugLog(...args: any[]): void {\r\n if (isDevelopment()) {\r\n console.debug(...args);\r\n }\r\n}\r\n\r\n/**\r\n * 存储管理器\r\n * 用于统一管理各种类型的客户端存储\r\n */\r\nexport class StorageManager {\r\n private adapters: Map<string, StorageAdapter> = new Map()\r\n private options: Required<StorageManagerOptions> & {\r\n defaultAdapter: AdapterType\r\n }\r\n\r\n /**\r\n * 创建存储管理器\r\n * @param options 配置选项\r\n */\r\n constructor(options: StorageManagerOptions = {}) {\r\n // 检测环境\r\n const isNode = isNodeEnvironment()\r\n const isTest = isTestEnvironment()\r\n const isBrowser = isBrowserEnvironment() || isTest // 在测试环境中也当作浏览器环境处理\r\n\r\n // 确定默认适配器\r\n let defaultAdapter: string;\r\n \r\n if (typeof options.defaultAdapter === 'string') {\r\n defaultAdapter = this.mapAdapterString(options.defaultAdapter);\r\n } else {\r\n defaultAdapter = !isBrowser || isNode\r\n ? ADAPTER_TYPES.MEMORY\r\n : options.defaultAdapter || ADAPTER_TYPES.LOCAL_STORAGE;\r\n }\r\n\r\n // 创建选项对象,处理默认值\r\n const optionsCopy = { ...options };\r\n \r\n // 避免重复设置 defaultAdapter\r\n delete optionsCopy.defaultAdapter;\r\n \r\n this.options = {\r\n defaultAdapter: defaultAdapter as AdapterType,\r\n defaultExpires: 0, // 默认不过期\r\n defaultEncrypt: false,\r\n namespace: '',\r\n ...optionsCopy\r\n } as Required<StorageManagerOptions> & { defaultAdapter: AdapterType }\r\n\r\n // 注册所有适配器,让适配器自己决定是否可用\r\n this.registerAdapters();\r\n\r\n // 调试日志\r\n debugLog('Registered adapters:', Array.from(this.adapters.keys()));\r\n \r\n // 验证默认适配器是否可用\r\n if (!this.adapters.has(this.options.defaultAdapter.toLowerCase())) {\r\n // 默认适配器不可用,切换到内存适配器\r\n warnOnce(`Default adapter '${this.options.defaultAdapter}' is not available, falling back to memory adapter.`);\r\n this.options.defaultAdapter = ADAPTER_TYPES.MEMORY;\r\n }\r\n }\r\n \r\n /**\r\n * 注册所有适配器\r\n * @private\r\n */\r\n private registerAdapters(): void {\r\n // 注册内存存储适配器(这个应该总是可用的)\r\n const memoryAdapter = new MemoryStorageAdapter(this.options.defaultEncrypt);\r\n this.registerAdapterWithAliases(ADAPTER_TYPES.MEMORY, memoryAdapter, ['memory', 'mem']);\r\n \r\n // 尝试注册 localStorage 适配器\r\n try {\r\n const localStorageAdapter = new LocalStorageAdapter(this.options.defaultEncrypt);\r\n this.registerAdapterWithAliases(\r\n ADAPTER_TYPES.LOCAL_STORAGE, \r\n localStorageAdapter, \r\n ['localStorage', 'local', 'localstorage']\r\n );\r\n } catch (error: unknown) {\r\n debugLog('localStorage adapter registration failed:', error instanceof Error ? error.message : String(error));\r\n }\r\n \r\n // 尝试注册 sessionStorage 适配器\r\n try {\r\n const sessionStorageAdapter = new SessionStorageAdapter(this.options.defaultEncrypt);\r\n this.registerAdapterWithAliases(\r\n ADAPTER_TYPES.SESSION_STORAGE, \r\n sessionStorageAdapter, \r\n ['sessionStorage', 'session', 'sessionstorage']\r\n );\r\n } catch (error: unknown) {\r\n debugLog('sessionStorage adapter registration failed:', error instanceof Error ? error.message : String(error));\r\n }\r\n \r\n // 尝试注册 cookie 适配器\r\n try {\r\n const cookieAdapter = new CookieStorageAdapter({ encrypt: this.options.defaultEncrypt });\r\n this.registerAdapterWithAliases(\r\n ADAPTER_TYPES.COOKIE, \r\n cookieAdapter, \r\n ['cookie', 'cookies']\r\n );\r\n } catch (error: unknown) {\r\n debugLog('cookie adapter registration failed:', error instanceof Error ? error.message : String(error));\r\n }\r\n }\r\n\r\n /**\r\n * 注册适配器及其别名\r\n * @private\r\n * @param primaryName 主要名称\r\n * @param adapter 适配器实例\r\n * @param aliases 别名数组\r\n */\r\n private registerAdapterWithAliases(primaryName: string, adapter: StorageAdapter, aliases: string[]): void {\r\n // 注册主要名称(确保使用小写)\r\n const lowerPrimaryName = primaryName.toLowerCase();\r\n this.adapters.set(lowerPrimaryName, adapter);\r\n \r\n // 注册所有别名(使用小写以确保大小写不敏感)\r\n for (const alias of aliases) {\r\n const lowerAlias = alias.toLowerCase();\r\n if (lowerAlias !== lowerPrimaryName) { // 避免重复注册\r\n this.adapters.set(lowerAlias, adapter);\r\n }\r\n }\r\n \r\n // 调试日志\r\n debugLog(`Registered adapter '${primaryName}' with aliases:`, aliases);\r\n }\r\n\r\n /**\r\n * 映射适配器字符串到适配器类型\r\n * @private\r\n */\r\n private mapAdapterString(adapter: string): string {\r\n if (!adapter) return ADAPTER_TYPES.MEMORY;\r\n \r\n // 确保大小写不敏感的映射\r\n const lowerAdapter = adapter.toLowerCase();\r\n const adapterMap: Record<string, string> = {\r\n 'localstorage': ADAPTER_TYPES.LOCAL_STORAGE,\r\n 'local': ADAPTER_TYPES.LOCAL_STORAGE,\r\n 'sessionstorage': ADAPTER_TYPES.SESSION_STORAGE,\r\n 'session': ADAPTER_TYPES.SESSION_STORAGE,\r\n 'cookie': ADAPTER_TYPES.COOKIE,\r\n 'cookies': ADAPTER_TYPES.COOKIE,\r\n 'memory': ADAPTER_TYPES.MEMORY,\r\n 'mem': ADAPTER_TYPES.MEMORY,\r\n };\r\n \r\n return adapterMap[lowerAdapter] || adapter;\r\n }\r\n\r\n /**\r\n * 注册存储适配器\r\n * @param name 适配器名称\r\n * @param adapter 适配器实例\r\n */\r\n registerAdapter(name: string, adapter: StorageAdapter): void {\r\n // 始终使用小写存储适配器名称,确保大小写不敏感\r\n this.adapters.set(name.toLowerCase(), adapter)\r\n }\r\n\r\n /**\r\n * 获取存储适配器\r\n * @param name 适配器名称\r\n * @returns 适配器实例\r\n */\r\n getAdapter(name: string = this.options.defaultAdapter): StorageAdapter {\r\n if (!name) {\r\n name = this.options.defaultAdapter;\r\n }\r\n \r\n // 映射字符串名称\r\n const mappedName = this.mapAdapterString(name);\r\n const lowerMappedName = mappedName.toLowerCase();\r\n \r\n // 使用小写名称查找适配器,确保大小写不敏感\r\n const adapter = this.adapters.get(lowerMappedName);\r\n if (!adapter) {\r\n // 调试信息:输出所有已注册的适配器名称\r\n debugLog('Available adapters:', Array.from(this.adapters.keys()));\r\n debugLog('Requested adapter:', name, 'Mapped to:', lowerMappedName);\r\n throw new Error(`Adapter '${name}' not found`);\r\n }\r\n return adapter;\r\n }\r\n\r\n /**\r\n * 设置存储项\r\n * @param key 键名\r\n * @param value 值\r\n * @param options 选项\r\n * @returns Promise\r\n */\r\n async set<T>(\r\n key: string,\r\n value: T,\r\n options: ExtendedStorageItemOptions = {}\r\n ): Promise<void> {\r\n const { expires = this.options.defaultExpires } = options\r\n \r\n // 处理适配器名称\r\n let adapterName: string;\r\n if (options.adapter) {\r\n adapterName = this.mapAdapterString(options.adapter as string);\r\n } else {\r\n adapterName = this.options.defaultAdapter;\r\n }\r\n \r\n const adapter = this.getAdapter(adapterName)\r\n const namespacedKey = namespaceKey(key, this.options.namespace)\r\n\r\n const item: StorageItem<T> = {\r\n value,\r\n timestamp: Date.now(),\r\n expires\r\n }\r\n\r\n await adapter.setItem(namespacedKey, item)\r\n }\r\n\r\n /**\r\n * 获取存储项\r\n * @param key 键名\r\n * @param options 选项\r\n * @returns 存储值或undefined(如果不存在或已过期)\r\n */\r\n async get<T>(\r\n key: string,\r\n options: Partial<ExtendedStorageItemOptions> = {}\r\n ): Promise<T | undefined> {\r\n // 处理适配器名称\r\n let adapterName: string;\r\n if (options.adapter) {\r\n adapterName = this.mapAdapterString(options.adapter as string);\r\n } else {\r\n adapterName = this.options.defaultAdapter;\r\n }\r\n \r\n const adapter = this.getAdapter(adapterName)\r\n const namespacedKey = namespaceKey(key, this.options.namespace)\r\n\r\n const item = await adapter.getItem<T>(namespacedKey)\r\n if (!item) return undefined\r\n \r\n // 检查是否过期\r\n if (isExpired(item)) {\r\n await this.remove(key, { adapter: adapterName })\r\n return undefined\r\n }\r\n\r\n return item.value\r\n }\r\n\r\n /**\r\n * 移除存储项\r\n * @param key 键名\r\n * @param options 选项\r\n * @returns Promise\r\n */\r\n async remove(\r\n key: string,\r\n options: { adapter?: AdapterType | string } = {}\r\n ): Promise<void> {\r\n // 处理适配器名称\r\n let adapterName: string;\r\n if (options.adapter) {\r\n adapterName = this.mapAdapterString(options.adapter as string);\r\n } else {\r\n adapterName = this.options.defaultAdapter;\r\n }\r\n \r\n const adapter = this.getAdapter(adapterName)\r\n const namespacedKey = namespaceKey(key, this.options.namespace)\r\n await adapter.removeItem(namespacedKey)\r\n }\r\n\r\n /**\r\n * 清空指定适配器的所有存储\r\n * @param options 选项\r\n * @returns Promise\r\n */\r\n async clear(options: { adapter?: AdapterType | string } = {}): Promise<void> {\r\n // 处理适配器名称\r\n let adapterName: string;\r\n if (options.adapter) {\r\n adapterName = this.mapAdapterString(options.adapter as string);\r\n } else {\r\n adapterName = this.options.defaultAdapter;\r\n }\r\n \r\n const adapter = this.getAdapter(adapterName)\r\n await adapter.clear()\r\n }\r\n\r\n /**\r\n * 获取指定适配器的所有键名\r\n * @param options 选项\r\n * @returns 键名数组\r\n */\r\n async keys(options: { adapter?: AdapterType | string } = {}): Promise<string[]> {\r\n // 处理适配器名称\r\n let adapterName: string;\r\n if (options.adapter) {\r\n adapterName = this.mapAdapterString(options.adapter as string);\r\n } else {\r\n adapterName = this.options.defaultAdapter;\r\n }\r\n \r\n const adapter = this.getAdapter(adapterName)\r\n const keys = await adapter.keys()\r\n\r\n // 过滤命名空间\r\n if (this.options.namespace) {\r\n const prefix = `${this.options.namespace}:`\r\n return keys\r\n .filter((key) => key.startsWith(prefix))\r\n .map((key) => key.slice(prefix.length))\r\n }\r\n\r\n return keys\r\n }\r\n\r\n /**\r\n * 检查键是否存在\r\n * @param key 键名\r\n * @param options 选项\r\n * @returns 是否存在\r\n */\r\n async has(\r\n key: string,\r\n options: { adapter?: AdapterType | string } = {}\r\n ): Promise<boolean> {\r\n const value = await this.get(key, options)\r\n return value !== undefined\r\n }\r\n}\r\n","import { StorageManager } from './StorageManager';\r\nimport type { StorageManagerOptions } from '../types';\r\nimport type { AdapterType } from '../adapters';\r\n\r\n/**\r\n * 简化的存储API接口\r\n * 使用更短的方法名,提供更简洁的使用体验\r\n */\r\nexport class SimpleStore {\r\n private manager: StorageManager;\r\n\r\n /**\r\n * 创建简化存储接口\r\n * @param options 配置选项\r\n */\r\n constructor(options?: StorageManagerOptions) {\r\n this.manager = new StorageManager(options);\r\n }\r\n\r\n /**\r\n * 设置存储项\r\n * @param key 键名\r\n * @param value 值\r\n * @param options 选项\r\n */\r\n async put<T>(key: string, value: T, options?: { expires?: number; adapter?: AdapterType | string }): Promise<void> {\r\n return this.manager.set(key, value, options);\r\n }\r\n\r\n /**\r\n * 获取存储项\r\n * @param key 键名\r\n * @param options 选项\r\n */\r\n async get<T>(key: string, options?: { adapter?: AdapterType | string }): Promise<T | undefined> {\r\n return this.manager.get(key, options);\r\n }\r\n\r\n /**\r\n * 删除存储项\r\n * @param key 键名\r\n * @param options 选项\r\n */\r\n async del(key: string, options?: { adapter?: AdapterType | string }): Promise<void> {\r\n return this.manager.remove(key, options);\r\n }\r\n\r\n /**\r\n * 检查键是否存在\r\n * @param key 键名\r\n * @param options 选项\r\n */\r\n async has(key: string, options?: { adapter?: AdapterType | string }): Promise<boolean> {\r\n return this.manager.has(key, options);\r\n }\r\n\r\n /**\r\n * 获取所有键名\r\n * @param options 选项\r\n */\r\n async keys(options?: { adapter?: AdapterType | string }): Promise<string[]> {\r\n return this.manager.keys(options);\r\n }\r\n\r\n /**\r\n * 清空存储\r\n * @param options 选项\r\n */\r\n async clear(options?: { adapter?: AdapterType | string }): Promise<void> {\r\n return this.manager.clear(options);\r\n }\r\n\r\n /**\r\n * 获取原始存储管理器实例\r\n * 用于访问高级功能\r\n */\r\n getManager(): StorageManager {\r\n return this.manager;\r\n }\r\n\r\n /**\r\n * 调试方法:获取所有已注册的适配器\r\n * 仅在开发环境中使用\r\n */\r\n getRegisteredAdapters(): string[] {\r\n return Array.from(this.manager[\"adapters\"].keys());\r\n }\r\n} ","// 导出核心模块\r\nexport * from './core';\r\n\r\n// 导出适配器\r\nexport * from './adapters';\r\n\r\n// 导出类型\r\nexport * from './types';\r\n\r\n\r\n// 创建默认存储管理器实例\r\nimport { SimpleStore } from './core';\r\n\r\n\r\n// 创建并导出简化API单例实例\r\nexport const store = new SimpleStore();"],"names":["encrypt","value","error","decrypt","encryptedValue","isNodeEnvironment","isBrowserEnvironment","isTestEnvironment","warnOnce","warnings","message","isExpired","item","serializeItem","shouldEncrypt","serialized","deserializeItem","data","isEncrypted","decryptedData","parseStorageItem","parsedItem","e","namespaceKey","key","namespace","isLocalStorageAvailable","testKey","LocalStorageAdapter","__publicField","keys","i","isSessionStorageAvailable","SessionStorageAdapter","MemoryStorageAdapter","isCookieAvailable","testValue","now","success","CookieStorageAdapter","options","days","expiresDate","cookieStr","cookies","encodedKey","cookie","cookieKey","cookieValue","decodedValue","ADAPTER_TYPES","isDevelopment","debugLog","args","StorageManager","isNode","isTest","isBrowser","defaultAdapter","optionsCopy","memoryAdapter","localStorageAdapter","sessionStorageAdapter","cookieAdapter","primaryName","adapter","aliases","lowerPrimaryName","alias","lowerAlias","lowerAdapter","name","lowerMappedName","expires","adapterName","namespacedKey","prefix","SimpleStore","store"],"mappings":"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"}