UNPKG

@ort-fe/storage-cache-kit

Version:

Unified client-side cache and storage manager with expiration control

1 lines 52.2 kB
{"version":3,"file":"index.mjs","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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"}