如何设计一款功能强大的本地存储系统
需求如下:
代码调整后目录结构如下:
textsrc/ ├── core/ # 核心模块 │ ├── interfaces/ # 接口定义 │ │ └── IStore.ts # 存储核心接口 │ ├── Store.ts # 主存储类 │ ├── engine/ # 存储引擎实现 │ │ ├── index.ts # 引擎导出 │ │ ├── MemoryEngine.ts # 内存存储 │ │ ├── LocalStorageEngine.ts # 本地存储 │ │ ├── SessionStorageEngine.ts # 会话存储 │ │ └── IndexedDBEngine.ts # IndexDB存储 │ ├── lock/ # 锁机制 │ │ └── StorageLock.ts │ └── registry/ # 引擎注册 │ └── EngineRegistry.ts ├── plugins/ # 插件系统 │ ├── crypto/ # 加密插件 │ │ ├── index.ts │ │ ├── types.ts │ │ └── DefaultCrypto.ts │ ├── logger/ # 日志插件 │ │ ├── index.ts │ │ ├── types.ts │ │ └── DefaultLogger.ts │ ├── validator/ # 校验插件 │ │ ├── index.ts │ │ ├── types.ts │ │ └── ZodValidator.ts │ └── reactive/ # 响应式插件 │ ├── index.ts │ ├── types.ts │ ├── ReactHook.ts │ └── VueComposable.ts ├── cache/ # LRU缓存 │ ├── LRUCache.ts │ └── types.ts ├── config/ # 配置管理 │ ├── index.ts │ └── StoreConfig.ts ├── namespace/ # 命名空间 │ └── NamespaceManager.ts ├── utils/ # 工具函数 │ ├── index.ts │ ├── batch.ts # 批量操作优化 │ ├── downgrade.ts # 自动降级 │ └── type-guards.ts └── index.ts # 入口文件
ts/**
* 存储引擎信息接口
*/
export interface EngineInfo {
name: string;
version?: string;
isSupported: boolean;
storageLimit?: number; // 存储限制(MB)
persistent: boolean; // 是否持久化
}
/**
* 核心存储接口
*/
export interface IStore {
/**
* 获取单个值
* @param key 存储键
*/
get<T = any>(key: string): Promise<T | null>;
/**
* 设置单个值
* @param key 存储键
* @param value 存储值
* @param expire? 过期时间(毫秒)
*/
set<T = any>(key: string, value: T, expire?: number): Promise<boolean>;
/**
* 删除单个值
* @param key 存储键
*/
delete(key: string): Promise<boolean>;
/**
* 清空所有存储
*/
clear(): Promise<boolean>;
/**
* 获取所有键名
*/
keys(): Promise<string[]>;
/**
* 检查键是否存在
* @param key 存储键
*/
has(key: string): Promise<boolean>;
/**
* 批量获取
* @param keys 键数组
*/
getMany<T = any>(keys: string[]): Promise<Record<string, T | null>>;
/**
* 批量设置
* @param entries 键值对数组
*/
setMany<T = any>(entries: Array<{ key: string; value: T; expire?: number }>): Promise<boolean[]>;
/**
* 清理过期数据
*/
sweep(): Promise<number>; // 返回清理的数量
/**
* 测试存储方案是否支持
*/
testFunctionality(): Promise<boolean>;
/**
* 获取引擎信息
*/
getEngineInfo(): Promise<EngineInfo>;
/**
* 关闭存储连接(适配IndexedDB)
*/
close?(): Promise<void>;
}
/**
* 存储引擎构造函数接口
*/
export interface IStoreEngineConstructor {
new (namespace: string, config?: any): IStore;
}
ts/**
* 存储锁机制 - 防止并发操作冲突
*/
export class StorageLock {
private locks = new Map<string, Promise<void>>();
private resolvers = new Map<string, () => void>();
/**
* 获取锁
* @param key 锁标识
* @param timeout 超时时间(ms)
*/
async acquire(key: string, timeout = 5000): Promise<() => void> {
// 如果已有锁,等待锁释放
while (this.locks.has(key)) {
await Promise.race([
this.locks.get(key),
new Promise((_, reject) =>
setTimeout(() => reject(new Error(`Lock timeout for key: ${key}`)), timeout)
)
]);
}
// 创建新锁
let resolve: () => void;
const lockPromise = new Promise<void>((res) => {
resolve = res;
});
this.locks.set(key, lockPromise);
this.resolvers.set(key, resolve!);
// 返回释放锁的函数
return () => this.release(key);
}
/**
* 释放锁
* @param key 锁标识
*/
private release(key: string): void {
const resolver = this.resolvers.get(key);
if (resolver) {
resolver();
this.resolvers.delete(key);
this.locks.delete(key);
}
}
/**
* 带锁执行操作
* @param key 锁标识
* @param fn 要执行的函数
* @param timeout 超时时间
*/
async withLock<T>(key: string, fn: () => Promise<T>, timeout = 5000): Promise<T> {
const release = await this.acquire(key, timeout);
try {
return await fn();
} finally {
release();
}
}
/**
* 检查锁是否存在
* @param key 锁标识
*/
hasLock(key: string): boolean {
return this.locks.has(key);
}
/**
* 清空所有锁
*/
clear(): void {
this.locks.clear();
this.resolvers.clear();
}
}
// 全局锁实例
export const storageLock = new StorageLock();
MemoryEngine.tsimport type{ IStore, EngineInfo } from "../interfaces/IStore"; import { LRUCache } from "../../cache/LRUCache"; /** * 内存存储引擎 */ export class MemoryEngine implements IStore { private storage = new LRUCache(); private namespace: string; constructor(namespace: string, config?: { cacheSize?: number }) { this.namespace = namespace; if (config?.cacheSize) { this.storage.setMaxSize(config.cacheSize); } } /** * 获取单个值 */ async get<T = any>(key: string): Promise<T | null> { return this.storage.get(key) as T | null; } /** * 设置单个值 */ async set<T = any>(key: string, value: T, expire?: number): Promise<boolean> { try { this.storage.set(key, value, expire || null); return true; } catch (error) { return false; } } /** * 删除单个值 */ async delete(key: string): Promise<boolean> { if (!this.storage.has(key)) { return false; } this.storage.delete(key); return true; } /** * 清空所有存储 */ async clear(): Promise<boolean> { try { this.storage.clear(); return true; } catch (error) { return false; } } /** * 获取所有键名 */ async keys(): Promise<string[]> { return this.storage.keys(); } /** * 检查键是否存在 */ async has(key: string): Promise<boolean> { return this.storage.has(key); } /** * 批量获取 */ async getMany<T = any>(keys: string[]): Promise<Record<string, T | null>> { const result: Record<string, T | null> = {}; for (const key of keys) { result[key] = this.storage.get(key) as T | null; } return result; } /** * 批量设置 */ async setMany<T = any>(entries: Array<{ key: string; value: T; expire?: number }>): Promise<boolean[]> { const results: boolean[] = []; for (const entry of entries) { try { this.storage.set(entry.key, entry.value, entry.expire || null); results.push(true); } catch (error) { results.push(false); } } return results; } /** * 清理过期数据 */ async sweep(): Promise<number> { return this.storage.sweep(); } /** * 测试存储方案是否支持 */ async testFunctionality(): Promise<boolean> { // 内存存储始终支持 return true; } /** * 获取引擎信息 */ async getEngineInfo(): Promise<EngineInfo> { return { name: 'memory', version: '1.0.0', isSupported: true, storageLimit: Number.MAX_SAFE_INTEGER, // 理论上无限制 persistent: false // 页面刷新后丢失 }; } }
LocalStorageEngine.tsimport type{ IStore, EngineInfo } from "../interfaces/IStore"; import { namespaceManager } from "../../namespace/NamespaceManager"; /** * 存储值结构 */ interface StoredValue { data: any; expire: number | null; } /** * localStorage存储引擎 */ export class LocalStorageEngine implements IStore { private namespace: string; constructor(namespace: string) { this.namespace = namespace; } /** * 获取命名空间后的键 */ private getNamespacedKey(key: string): string { return namespaceManager.getNamespacedKey(this.namespace, key); } /** * 获取单个值 */ async get<T = any>(key: string): Promise<T | null> { try { const namespacedKey = this.getNamespacedKey(key); const item = localStorage.getItem(namespacedKey); if (!item) return null; const parsed: StoredValue = JSON.parse(item); // 检查过期时间 if (parsed.expire && Date.now() > parsed.expire) { localStorage.removeItem(namespacedKey); return null; } return parsed.data as T; } catch (error) { return null; } } /** * 设置单个值 */ async set<T = any>(key: string, value: T, expire?: number): Promise<boolean> { try { const namespacedKey = this.getNamespacedKey(key); const storedValue: StoredValue = { data: value, expire: expire ? Date.now() + expire : null }; localStorage.setItem(namespacedKey, JSON.stringify(storedValue)); return true; } catch (error) { return false; } } /** * 删除单个值 */ async delete(key: string): Promise<boolean> { try { const namespacedKey = this.getNamespacedKey(key); if (!localStorage.getItem(namespacedKey)) { return false; } localStorage.removeItem(namespacedKey); return true; } catch (error) { return false; } } /** * 清空所有存储 */ async clear(): Promise<boolean> { try { // 只清空当前命名空间的键 const keys = await this.keys(); for (const key of keys) { localStorage.removeItem(this.getNamespacedKey(key)); } return true; } catch (error) { return false; } } /** * 获取所有键名 */ async keys(): Promise<string[]> { try { const keys: string[] = []; for (let i = 0; i < localStorage.length; i++) { const key = localStorage.key(i); if (key && namespaceManager.isInNamespace(key, this.namespace)) { keys.push(namespaceManager.extractOriginalKey(key, this.namespace)); } } return keys; } catch (error) { return []; } } /** * 检查键是否存在 */ async has(key: string): Promise<boolean> { try { const namespacedKey = this.getNamespacedKey(key); return !!localStorage.getItem(namespacedKey); } catch (error) { return false; } } /** * 批量获取 */ async getMany<T = any>(keys: string[]): Promise<Record<string, T | null>> { const result: Record<string, T | null> = {}; for (const key of keys) { result[key] = await this.get<T>(key); } return result; } /** * 批量设置 */ async setMany<T = any>(entries: Array<{ key: string; value: T; expire?: number }>): Promise<boolean[]> { const results: boolean[] = []; for (const entry of entries) { results.push(await this.set(entry.key, entry.value, entry.expire)); } return results; } /** * 清理过期数据 */ async sweep(): Promise<number> { try { const keys = await this.keys(); let count = 0; for (const key of keys) { const namespacedKey = this.getNamespacedKey(key); const item = localStorage.getItem(namespacedKey); if (item) { const parsed: StoredValue = JSON.parse(item); if (parsed.expire && Date.now() > parsed.expire) { localStorage.removeItem(namespacedKey); count++; } } } return count; } catch (error) { return 0; } } /** * 测试存储方案是否支持 */ async testFunctionality(): Promise<boolean> { try { const testKey = this.getNamespacedKey('__test__'); localStorage.setItem(testKey, 'test'); localStorage.removeItem(testKey); return true; } catch (error) { return false; } } /** * 获取引擎信息 */ async getEngineInfo(): Promise<EngineInfo> { return { name: 'localStorage', version: '1.0.0', isSupported: await this.testFunctionality(), storageLimit: 5, // 通常5MB persistent: true }; } }
SessionStorageEngine.tsimport type{ IStore, EngineInfo } from "../interfaces/IStore"; import { namespaceManager } from "../../namespace/NamespaceManager"; /** * 存储值结构 */ interface StoredValue { data: any; expire: number | null; } /** * sessionStorage存储引擎 */ export class SessionStorageEngine implements IStore { private namespace: string; constructor(namespace: string) { this.namespace = namespace; } /** * 获取命名空间后的键 */ private getNamespacedKey(key: string): string { return namespaceManager.getNamespacedKey(this.namespace, key); } /** * 获取单个值 */ async get<T = any>(key: string): Promise<T | null> { try { const namespacedKey = this.getNamespacedKey(key); const item = sessionStorage.getItem(namespacedKey); if (!item) return null; const parsed: StoredValue = JSON.parse(item); // 检查过期时间 if (parsed.expire && Date.now() > parsed.expire) { sessionStorage.removeItem(namespacedKey); return null; } return parsed.data as T; } catch (error) { return null; } } /** * 设置单个值 */ async set<T = any>(key: string, value: T, expire?: number): Promise<boolean> { try { const namespacedKey = this.getNamespacedKey(key); const storedValue: StoredValue = { data: value, expire: expire ? Date.now() + expire : null }; sessionStorage.setItem(namespacedKey, JSON.stringify(storedValue)); return true; } catch (error) { return false; } } /** * 删除单个值 */ async delete(key: string): Promise<boolean> { try { const namespacedKey = this.getNamespacedKey(key); if (!sessionStorage.getItem(namespacedKey)) { return false; } sessionStorage.removeItem(namespacedKey); return true; } catch (error) { return false; } } /** * 清空所有存储 */ async clear(): Promise<boolean> { try { // 只清空当前命名空间的键 const keys = await this.keys(); for (const key of keys) { sessionStorage.removeItem(this.getNamespacedKey(key)); } return true; } catch (error) { return false; } } /** * 获取所有键名 */ async keys(): Promise<string[]> { try { const keys: string[] = []; for (let i = 0; i < sessionStorage.length; i++) { const key = sessionStorage.key(i); if (key && namespaceManager.isInNamespace(key, this.namespace)) { keys.push(namespaceManager.extractOriginalKey(key, this.namespace)); } } return keys; } catch (error) { return []; } } /** * 检查键是否存在 */ async has(key: string): Promise<boolean> { try { const namespacedKey = this.getNamespacedKey(key); return !!sessionStorage.getItem(namespacedKey); } catch (error) { return false; } } /** * 批量获取 */ async getMany<T = any>(keys: string[]): Promise<Record<string, T | null>> { const result: Record<string, T | null> = {}; for (const key of keys) { result[key] = await this.get<T>(key); } return result; } /** * 批量设置 */ async setMany<T = any>(entries: Array<{ key: string; value: T; expire?: number }>): Promise<boolean[]> { const results: boolean[] = []; for (const entry of entries) { results.push(await this.set(entry.key, entry.value, entry.expire)); } return results; } /** * 清理过期数据 */ async sweep(): Promise<number> { try { const keys = await this.keys(); let count = 0; for (const key of keys) { const namespacedKey = this.getNamespacedKey(key); const item = sessionStorage.getItem(namespacedKey); if (item) { const parsed: StoredValue = JSON.parse(item); if (parsed.expire && Date.now() > parsed.expire) { sessionStorage.removeItem(namespacedKey); count++; } } } return count; } catch (error) { return 0; } } /** * 测试存储方案是否支持 */ async testFunctionality(): Promise<boolean> { try { const testKey = this.getNamespacedKey('__test__'); sessionStorage.setItem(testKey, 'test'); sessionStorage.removeItem(testKey); return true; } catch (error) { return false; } } /** * 获取引擎信息 */ async getEngineInfo(): Promise<EngineInfo> { return { name: 'sessionStorage', version: '1.0.0', isSupported: await this.testFunctionality(), storageLimit: 5, // 通常5MB persistent: false // 会话结束后丢失 }; } }
IndexedDBEngine.tsimport type{ IStore, EngineInfo } from "../interfaces/IStore"; import { namespaceManager } from "../../namespace/NamespaceManager"; import { batchOptimize } from "../../utils/batch"; /** * IndexedDB存储值接口 */ interface DBValue { id: string; // 带命名空间的key data: any; expire: number | null; createdAt: number; updatedAt: number; } /** * IndexedDB存储引擎 */ export class IndexedDBEngine implements IStore { private dbName: string; private storeName: string; private version: number; private namespace: string; private db: IDBDatabase | null = null; constructor(namespace: string, config?: { dbName?: string; storeName?: string; version?: number }) { this.namespace = namespace; this.dbName = config?.dbName || 'enterprise-store'; this.storeName = config?.storeName || 'data'; this.version = config?.version || 1; } /** * 打开数据库连接 */ private async openDB(): Promise<IDBDatabase> { if (this.db) { return this.db; } return new Promise((resolve, reject) => { const request = indexedDB.open(this.dbName, this.version); // 数据库升级 request.onupgradeneeded = (event) => { const db = (event.target as IDBOpenDBRequest).result; // 创建对象存储 if (!db.objectStoreNames.contains(this.storeName)) { const store = db.createObjectStore(this.storeName, { keyPath: 'id' }); // 创建索引 store.createIndex('expire', 'expire', { unique: false }); store.createIndex('namespace', 'namespace', { unique: false }); } }; request.onsuccess = (event) => { this.db = (event.target as IDBOpenDBRequest).result; resolve(this.db); }; request.onerror = (event) => { reject(new Error(`Failed to open IndexedDB: ${(event.target as IDBOpenDBRequest).error?.message}`)); }; request.onblocked = () => { reject(new Error('IndexedDB upgrade blocked')); }; }); } /** * 获取命名空间后的键 */ private getNamespacedKey(key: string): string { return namespaceManager.getNamespacedKey(this.namespace, key); } /** * 执行数据库操作 */ private async execute<T>( mode: IDBTransactionMode, operation: (store: IDBObjectStore) => Promise<T> ): Promise<T> { const db = await this.openDB(); return new Promise((resolve, reject) => { const transaction = db.transaction(this.storeName, mode); const store = transaction.objectStore(this.storeName); operation(store) .then(resolve) .catch(reject); transaction.oncomplete = () => {}; transaction.onerror = (event) => { reject(new Error(`Transaction error: ${(event.target as IDBTransaction).error?.message}`)); }; transaction.onabort = (event) => { reject(new Error(`Transaction aborted: ${(event.target as IDBTransaction).error?.message}`)); }; }); } /** * 获取单个值 */ async get<T = any>(key: string): Promise<T | null> { try { const namespacedKey = this.getNamespacedKey(key); return this.execute('readonly', async (store) => { return new Promise((resolve, reject) => { const request = store.get(namespacedKey); request.onsuccess = (event) => { const result = (event.target as IDBRequest).result as DBValue | undefined; if (!result) { resolve(null); return; } // 检查过期时间 if (result.expire && Date.now() > result.expire) { // 删除过期数据 store.delete(namespacedKey); resolve(null); return; } resolve(result.data as T); }; request.onerror = (event) => { reject(new Error(`Get error: ${(event.target as IDBRequest).error?.message}`)); }; }); }); } catch (error) { return null; } } /** * 设置单个值 */ async set<T = any>(key: string, value: T, expire?: number): Promise<boolean> { try { const namespacedKey = this.getNamespacedKey(key); return this.execute('readwrite', async (store) => { return new Promise((resolve, reject) => { const dbValue: DBValue = { id: namespacedKey, data: value, expire: expire ? Date.now() + expire : null, createdAt: Date.now(), updatedAt: Date.now() }; const request = store.put(dbValue); request.onsuccess = () => { resolve(true); }; request.onerror = (event) => { reject(new Error(`Set error: ${(event.target as IDBRequest).error?.message}`)); }; }); }); } catch (error) { return false; } } /** * 删除单个值 */ async delete(key: string): Promise<boolean> { try { const namespacedKey = this.getNamespacedKey(key); return this.execute('readwrite', async (store) => { return new Promise((resolve, reject) => { // 先检查是否存在 const getRequest = store.get(namespacedKey); getRequest.onsuccess = (event) => { const exists = !!((event.target as IDBRequest).result); if (!exists) { resolve(false); return; } // 执行删除 const deleteRequest = store.delete(namespacedKey); deleteRequest.onsuccess = () => { resolve(true); }; deleteRequest.onerror = (event) => { reject(new Error(`Delete error: ${(event.target as IDBRequest).error?.message}`)); }; }; getRequest.onerror = (event) => { reject(new Error(`Delete check error: ${(event.target as IDBRequest).error?.message}`)); }; }); }); } catch (error) { return false; } } /** * 清空所有存储 */ async clear(): Promise<boolean> { try { return this.execute('readwrite', async (store) => { return new Promise((resolve, reject) => { // 获取当前命名空间的所有键 const keys: string[] = []; const cursorRequest = store.openCursor(); cursorRequest.onsuccess = (event) => { const cursor = (event.target as IDBRequest).result as IDBCursorWithValue; if (cursor) { const dbValue = cursor.value as DBValue; if (namespaceManager.isInNamespace(dbValue.id, this.namespace)) { keys.push(dbValue.id); cursor.delete(); // 直接删除 } cursor.continue(); } else { // 游标遍历完成 resolve(true); } }; cursorRequest.onerror = (event) => { reject(new Error(`Clear error: ${(event.target as IDBRequest).error?.message}`)); }; }); }); } catch (error) { return false; } } /** * 获取所有键名 */ async keys(): Promise<string[]> { try { return this.execute('readonly', async (store) => { return new Promise((resolve, reject) => { const keys: string[] = []; const cursorRequest = store.openCursor(); cursorRequest.onsuccess = (event) => { const cursor = (event.target as IDBRequest).result as IDBCursorWithValue; if (cursor) { const dbValue = cursor.value as DBValue; if (namespaceManager.isInNamespace(dbValue.id, this.namespace)) { keys.push(namespaceManager.extractOriginalKey(dbValue.id, this.namespace)); } cursor.continue(); } else { resolve(keys); } }; cursorRequest.onerror = (event) => { reject(new Error(`Keys error: ${(event.target as IDBRequest).error?.message}`)); }; }); }); } catch (error) { return []; } } /** * 检查键是否存在 */ async has(key: string): Promise<boolean> { try { const namespacedKey = this.getNamespacedKey(key); return this.execute('readonly', async (store) => { return new Promise((resolve, reject) => { const request = store.get(namespacedKey); request.onsuccess = (event) => { resolve(!!((event.target as IDBRequest).result)); }; request.onerror = (event) => { reject(new Error(`Has error: ${(event.target as IDBRequest).error?.message}`)); }; }); }); } catch (error) { return false; } } /** * 批量获取 - 优化版 */ async getMany<T = any>(keys: string[]): Promise<Record<string, T | null>> { try { // 使用批量操作优化 return batchOptimize<Record<string, T | null>>( () => this.execute('readonly', async (store) => { const result: Record<string, T | null> = {}; const namespacedKeys = keys.map(key => this.getNamespacedKey(key)); // 并行获取所有值 await Promise.all(namespacedKeys.map(async (namespacedKey, index) => { const originalKey = keys[index]; try { const value = await new Promise<DBValue | undefined>((resolve) => { const request = store.get(namespacedKey); request.onsuccess = (event) => { resolve((event.target as IDBRequest).result as DBValue | undefined); }; request.onerror = () => resolve(undefined); }); if (!value) { result[originalKey] = null; return; } // 检查过期 if (value.expire && Date.now() > value.expire) { result[originalKey] = null; // 异步删除过期数据(不阻塞当前操作) store.delete(namespacedKey); return; } result[originalKey] = value.data as T; } catch (error) { result[originalKey] = null; } })); return result; }) ); } catch (error) { return keys.reduce((acc, key) => ({ ...acc, [key]: null }), {}); } } /** * 批量设置 - 优化版 */ async setMany<T = any>(entries: Array<{ key: string; value: T; expire?: number }>): Promise<boolean[]> { try { // 使用批量操作优化 return batchOptimize<boolean[]>( () => this.execute('readwrite', async (store) => { const results: boolean[] = []; // 批量插入所有值 await Promise.all(entries.map(async (entry) => { try { const namespacedKey = this.getNamespacedKey(entry.key); const dbValue: DBValue = { id: namespacedKey, data: entry.value, expire: entry.expire ? Date.now() + entry.expire : null, createdAt: Date.now(), updatedAt: Date.now() }; await new Promise<void>((resolve) => { const request = store.put(dbValue); request.onsuccess = () => resolve(); request.onerror = () => resolve(); }); results.push(true); } catch (error) { results.push(false); } })); return results; }) ); } catch (error) { return entries.map(() => false); } } /** * 清理过期数据 */ async sweep(): Promise<number> { try { return this.execute('readwrite', async (store) => { return new Promise((resolve, reject) => { let count = 0; const now = Date.now(); // 使用索引查询过期数据 const index = store.index('expire'); const cursorRequest = index.openCursor(IDBKeyRange.upperBound(now)); cursorRequest.onsuccess = (event) => { const cursor = (event.target as IDBRequest).result as IDBCursorWithValue; if (cursor) { const dbValue = cursor.value as DBValue; // 只清理当前命名空间的过期数据 if (namespaceManager.isInNamespace(dbValue.id, this.namespace)) { cursor.delete(); count++; } cursor.continue(); } else { resolve(count); } }; cursorRequest.onerror = (event) => { reject(new Error(`Sweep error: ${(event.target as IDBRequest).error?.message}`)); }; }); }); } catch (error) { return 0; } } /** * 测试存储方案是否支持 */ async testFunctionality(): Promise<boolean> { if (!('indexedDB' in window)) { return false; } try { const testDbName = `${this.dbName}-test`; const testStoreName = 'test'; return new Promise((resolve) => { const request = indexedDB.open(testDbName, 1); request.onupgradeneeded = (event) => { const db = (event.target as IDBOpenDBRequest).result; if (!db.objectStoreNames.contains(testStoreName)) { db.createObjectStore(testStoreName); } }; request.onsuccess = (event) => { const db = (event.target as IDBOpenDBRequest).result; // 清理测试数据库 indexedDB.deleteDatabase(testDbName); db.close(); resolve(true); }; request.onerror = () => { resolve(false); }; request.onblocked = () => { resolve(false); }; }); } catch (error) { return false; } } /** * 获取引擎信息 */ async getEngineInfo(): Promise<EngineInfo> { const isSupported = await this.testFunctionality(); return { name: 'indexeddb', version: '1.0.0', isSupported, storageLimit: isSupported ? 50 : 0, // 通常50MB+ persistent: true }; } /** * 关闭数据库连接 */ async close(): Promise<void> { if (this.db) { this.db.close(); this.db = null; } } }
tsimport type { IStoreEngineConstructor } from "../interfaces/IStore";
/**
* 存储引擎注册器 - 管理所有可用的存储引擎
*/
export class EngineRegistry {
private static instance: EngineRegistry;
private engines = new Map<string, IStoreEngineConstructor>();
private constructor() {}
/**
* 获取单例实例
*/
public static getInstance(): EngineRegistry {
if (!EngineRegistry.instance) {
EngineRegistry.instance = new EngineRegistry();
}
return EngineRegistry.instance;
}
/**
* 注册存储引擎
* @param name 引擎名称
* @param constructor 引擎构造函数
*/
public registerEngine(name: string, constructor: IStoreEngineConstructor): void {
if (this.engines.has(name)) {
console.warn(`Engine "${name}" is already registered, it will be overwritten`);
}
this.engines.set(name, constructor);
}
/**
* 注销存储引擎
* @param name 引擎名称
*/
public unregisterEngine(name: string): boolean {
return this.engines.delete(name);
}
/**
* 获取存储引擎构造函数
* @param name 引擎名称
*/
public getEngine(name: string): IStoreEngineConstructor | undefined {
return this.engines.get(name);
}
/**
* 获取所有已注册的引擎名称
*/
public getRegisteredEngines(): string[] {
return Array.from(this.engines.keys());
}
/**
* 检查引擎是否已注册
* @param name 引擎名称
*/
public hasEngine(name: string): boolean {
return this.engines.has(name);
}
/**
* 清空所有引擎
*/
public clear(): void {
this.engines.clear();
}
}
// 全局注册器实例
export const engineRegistry = EngineRegistry.getInstance();
主存储模块
import type{ IStore, EngineInfo, IStoreEngineConstructor } from "./interfaces/IStore"; import { engineRegistry } from "./registry/EngineRegistry"; import { configManager } from "../config/StoreConfig"; import type{ StoreConfig, RuntimeConfig } from "../config/StoreConfig"; import { storageLock } from "./lock/StorageLock"; import { namespaceManager } from "../namespace/NamespaceManager"; import { LRUCache } from "../cache/LRUCache"; import type{ CryptoPlugin } from "../plugins/crypto"; import { DefaultCrypto } from "../plugins/crypto/DefaultCrypto"; import type{ LoggerPlugin, LogEntry } from "../plugins/logger"; import { DefaultLogger } from "../plugins/logger/DefaultLogger"; import type{ ValidatorPlugin } from "../plugins/validator"; import { ZodValidator } from "../plugins/validator/ZodValidator"; import { checkEngineSupport, getFallbackEngine } from "../utils/downgrade"; import { assertExists } from "../utils/type-guards"; /** * 企业级存储主类 */ export class EnterpriseStore implements IStore { private engine: IStore; private namespace: string; private config: StoreConfig; private lruCache?: LRUCache; private cryptoPlugin: CryptoPlugin; private loggerPlugin: LoggerPlugin; private validatorPlugin?: ValidatorPlugin; private encryptionKey?: string; /** * 私有构造函数(禁止直接实例化,使用 create 静态方法) */ private constructor(options: { engine: IStore; namespace: string; config: StoreConfig; cryptoPlugin: CryptoPlugin; loggerPlugin: LoggerPlugin; validatorPlugin?: ValidatorPlugin; encryptionKey?: string; }) { this.engine = options.engine; this.namespace = options.namespace; this.config = options.config; this.cryptoPlugin = options.cryptoPlugin; this.loggerPlugin = options.loggerPlugin; this.validatorPlugin = options.validatorPlugin; this.encryptionKey = options.encryptionKey; // 初始化LRU缓存 if (this.config.enableLRUCache) { this.lruCache = new LRUCache(this.config.lruCacheSize); } } /** * 静态创建方法(处理异步初始化) * @param options 配置选项 */ public static async create(options?: { namespace?: string; engine?: string; config?: RuntimeConfig; cryptoPlugin?: CryptoPlugin; loggerPlugin?: LoggerPlugin; validatorPlugin?: ValidatorPlugin; encryptionKey?: string; }): Promise<EnterpriseStore> { // 初始化配置 const globalConfig = configManager.getConfig(); const config: StoreConfig = { ...globalConfig, cryptoPlugin: options?.cryptoPlugin || new DefaultCrypto(), loggerPlugin: options?.loggerPlugin || new DefaultLogger(), validatorPlugin: options?.validatorPlugin || new ZodValidator() }; // 更新运行时配置 if (options?.config) { configManager.updateConfig(options.config); } // 设置命名空间 const namespace = options?.namespace || config.defaultNamespace; // 设置加密插件和密钥 const cryptoPlugin = config.cryptoPlugin!; const encryptionKey = options?.encryptionKey; // 设置日志插件 const loggerPlugin = config.loggerPlugin!; // 设置校验插件 const validatorPlugin = config.enableValidation ? config.validatorPlugin : undefined; // 初始化存储引擎(异步) const engineName = options?.engine || config.defaultEngine; const engine = await EnterpriseStore.initEngine(engineName, namespace, config, loggerPlugin); return new EnterpriseStore({ engine, namespace, config, cryptoPlugin, loggerPlugin, validatorPlugin, encryptionKey }); } /** * 异步初始化存储引擎(支持自动降级) */ private static async initEngine( engineName: string, namespace: string, config: StoreConfig, logger: LoggerPlugin ): Promise<IStore> { // 尝试创建指定引擎 try { const EngineConstructor = engineRegistry.getEngine(engineName); if (!EngineConstructor) { throw new Error(`Engine "${engineName}" is not registered`); } const engine = new EngineConstructor(namespace, config); // 异步测试引擎是否支持 const isSupported = await engine.testFunctionality(); if (!isSupported) { throw new Error(`Engine "${engineName}" is not supported in this environment`); } return engine; } catch (error) { logger.reportError( error as Error, { namespace, engine: engineName, action: 'initEngine' } ); // 自动降级(异步获取降级引擎) if (config.enableAutoDowngrade) { const fallbackEngineName = await getFallbackEngine(engineName); // 关键修复:添加 await if (fallbackEngineName) { await logger.log({ timestamp: Date.now(), level: 'warn', operation: 'test', namespace, engine: engineName, success: false, metadata: { fallbackTo: fallbackEngineName } } as LogEntry); // 递归初始化降级引擎(异步) return this.initEngine(fallbackEngineName, namespace, config, logger); } } throw new Error(`Failed to initialize any storage engine: ${(error as Error).message}`); } } /** * 记录操作日志 */ private async logOperation( operation: LogEntry['operation'], key: string | string[] | undefined, success: boolean, startTime: number, error?: Error, metadata?: Record<string, any> ): Promise<void> { if (!this.config.enableLogger) return; const engineInfo = await this.engine.getEngineInfo(); await this.loggerPlugin.log({ timestamp: Date.now(), level: success ? 'info' : 'error', operation, key, namespace: this.namespace, engine: engineInfo.name, duration: Date.now() - startTime, success, error, metadata } as LogEntry); } /** * 加密数据 */ private async encryptData<T = any>(data: T): Promise<string> { if (!this.config.enableCrypto) { return JSON.stringify(data); } const encrypted = await this.cryptoPlugin.encrypt(data, this.encryptionKey); return typeof encrypted === 'string' ? encrypted : JSON.stringify(encrypted); } /** * 解密数据 */ private async decryptData<T = any>(encryptedData: string): Promise<T> { if (!this.config.enableCrypto) { try { return JSON.parse(encryptedData) as T; } catch (e) { return encryptedData as unknown as T; } } return this.cryptoPlugin.decrypt<T>(encryptedData, this.encryptionKey); } /** * 校验数据 */ private async validateData<T = any>(data: T, schema?: any): Promise<boolean> { if (!this.config.enableValidation || !this.validatorPlugin || !schema) { return true; } const result = await this.validatorPlugin.validate(data, schema); if (!result.valid && result.errors) { throw new Error(`Data validation failed: ${result.errors.join(', ')}`); } return result.valid; } /** * 获取单个值 */ async get<T = any>(key: string, schema?: any): Promise<T | null> { const startTime = Date.now(); const lockKey = `${this.namespace}:${key}`; try { return await storageLock.withLock(lockKey, async () => { // 先从LRU缓存获取 if (this.lruCache?.has(key)) { const cached = this.lruCache.get(key); await this.logOperation('get', key, true, startTime, undefined, { fromCache: true }); return cached as T | null; } // 从存储引擎获取 const encryptedData = await this.engine.get<string>(key); if (encryptedData === null) { await this.logOperation('get', key, true, startTime); return null; } // 确保是字符串类型 const encryptedStr = typeof encryptedData === 'string' ? encryptedData : JSON.stringify(encryptedData); // 解密数据 const data = await this.decryptData<T>(encryptedStr); // 校验数据 if (schema) { await this.validateData(data, schema); } // 更新LRU缓存 this.lruCache?.set(key, data); await this.logOperation('get', key, true, startTime); return data; }); } catch (error) { await this.logOperation('get', key, false, startTime, error as Error); this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, key, operation: 'get' }); return null; } } /** * 设置单个值 */ async set<T = any>(key: string, value: T, expire?: number, schema?: any): Promise<boolean> { const startTime = Date.now(); const lockKey = `${this.namespace}:${key}`; try { return await storageLock.withLock(lockKey, async () => { // 校验数据 if (schema) { await this.validateData(value, schema); } // 加密数据 const encryptedData = await this.encryptData(value); // 存储到引擎 const result = await this.engine.set<string>( key, encryptedData, expire || this.config.defaultExpire ); // 更新LRU缓存 if (result && this.lruCache) { this.lruCache.set(key, value, expire || this.config.defaultExpire); } await this.logOperation('set', key, result, startTime); return result; }); } catch (error) { await this.logOperation('set', key, false, startTime, error as Error); this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, key, operation: 'set' }); return false; } } /** * 删除单个值 */ async delete(key: string): Promise<boolean> { const startTime = Date.now(); const lockKey = `${this.namespace}:${key}`; try { return await storageLock.withLock(lockKey, async () => { const result = await this.engine.delete(key); if (result && this.lruCache) { this.lruCache.delete(key); } await this.logOperation('delete', key, result, startTime); return result; }); } catch (error) { await this.logOperation('delete', key, false, startTime, error as Error); this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, key, operation: 'delete' }); return false; } } /** * 清空所有存储 */ async clear(): Promise<boolean> { const startTime = Date.now(); const lockKey = `${this.namespace}:clear`; try { return await storageLock.withLock(lockKey, async () => { const result = await this.engine.clear(); if (result && this.lruCache) { this.lruCache.clear(); } await this.logOperation('clear', undefined, result, startTime); return result; }); } catch (error) { await this.logOperation('clear', undefined, false, startTime, error as Error); this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, operation: 'clear' }); return false; } } /** * 获取所有键名 */ async keys(): Promise<string[]> { const startTime = Date.now(); try { const keys = await this.engine.keys(); await this.logOperation('keys', undefined, true, startTime); return keys; } catch (error) { await this.logOperation('keys', undefined, false, startTime, error as Error); this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, operation: 'keys' }); return []; } } /** * 检查键是否存在 */ async has(key: string): Promise<boolean> { const startTime = Date.now(); try { if (this.lruCache?.has(key)) { await this.logOperation('has', key, true, startTime, undefined, { fromCache: true }); return true; } const result = await this.engine.has(key); await this.logOperation('has', key, true, startTime); return result; } catch (error) { await this.logOperation('has', key, false, startTime, error as Error); this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, key, operation: 'has' }); return false; } } /** * 批量获取 */ async getMany<T = any>(keys: string[], schemas?: Record<string, any>): Promise<Record<string, T | null>> { const startTime = Date.now(); const lockKey = `${this.namespace}:batch:get`; try { return await storageLock.withLock(lockKey, async () => { const encryptedResults = await this.engine.getMany<string>(keys); const results: Record<string, T | null> = {}; for (const key of keys) { if (encryptedResults[key] === null) { results[key] = null; continue; } try { const encryptedStr = typeof encryptedResults[key] === 'string' ? encryptedResults[key]! : JSON.stringify(encryptedResults[key]); const data = await this.decryptData<T>(encryptedStr); if (schemas?.[key]) { await this.validateData(data, schemas[key]); } this.lruCache?.set(key, data); results[key] = data; } catch (error) { results[key] = null; this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, key, operation: 'getMany' }); } } await this.logOperation('batch', keys, true, startTime); return results; }); } catch (error) { await this.logOperation('batch', keys, false, startTime, error as Error); this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, operation: 'getMany' }); return keys.reduce((acc, key) => ({ ...acc, [key]: null }), {}); } } /** * 批量设置 */ async setMany<T = any>( entries: Array<{ key: string; value: T; expire?: number; schema?: any }> ): Promise<boolean[]> { const startTime = Date.now(); const lockKey = `${this.namespace}:batch:set`; try { return await storageLock.withLock(lockKey, async () => { const encryptedEntries = []; for (const entry of entries) { if (entry.schema) { await this.validateData(entry.value, entry.schema); } const encryptedData = await this.encryptData(entry.value); encryptedEntries.push({ key: entry.key, value: encryptedData, expire: entry.expire || this.config.defaultExpire }); } const results = await this.engine.setMany<string>(encryptedEntries); for (let i = 0; i < entries.length; i++) { if (results[i] && this.lruCache) { this.lruCache.set( entries[i].key, entries[i].value, entries[i].expire || this.config.defaultExpire ); } } await this.logOperation('batch', entries.map(e => e.key), true, startTime); return results; }); } catch (error) { await this.logOperation('batch', entries.map(e => e.key), false, startTime, error as Error); this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, operation: 'setMany' }); return entries.map(() => false); } } /** * 清理过期数据 */ async sweep(): Promise<number> { const startTime = Date.now(); const lockKey = `${this.namespace}:sweep`; try { const count = await storageLock.withLock(lockKey, async () => { const engineCount = await this.engine.sweep(); const cacheCount = this.lruCache?.sweep() || 0; return engineCount + cacheCount; }); await this.logOperation('sweep', undefined, true, startTime, undefined, { count }); return count; } catch (error) { await this.logOperation('sweep', undefined, false, startTime, error as Error); this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, operation: 'sweep' }); return 0; } } /** * 测试存储方案是否支持 */ async testFunctionality(): Promise<boolean> { const startTime = Date.now(); try { const result = await this.engine.testFunctionality(); await this.logOperation('test', undefined, result, startTime); return result; } catch (error) { await this.logOperation('test', undefined, false, startTime, error as Error); this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, operation: 'testFunctionality' }); return false; } } /** * 获取引擎信息 */ async getEngineInfo(): Promise<EngineInfo> { return this.engine.getEngineInfo(); } /** * 关闭存储连接 */ async close(): Promise<void> { if (typeof this.engine.close === 'function') { await this.engine.close(); } this.lruCache?.clear(); storageLock.clear(); } /** * 更新配置 */ updateConfig(newConfig: RuntimeConfig): void { configManager.updateConfig(newConfig); if (newConfig.enableLRUCache !== undefined && !newConfig.enableLRUCache) { this.lruCache?.clear(); } else if (newConfig.lruCacheSize && this.lruCache) { this.lruCache.setMaxSize(newConfig.lruCacheSize); } } /** * 切换存储引擎(异步) */ async switchEngine(engineName: string): Promise<boolean> { try { const newEngine = await EnterpriseStore.initEngine( engineName, this.namespace, this.config, this.loggerPlugin ); this.engine = newEngine; this.lruCache?.clear(); return true; } catch (error) { this.loggerPlugin.reportError(error as Error, { namespace: this.namespace, operation: 'switchEngine', engineName }); return false; } } /** * 获取当前命名空间 */ getNamespace(): string { return this.namespace; } /** * 切换命名空间 */ switchNamespace(namespace: string): void { this.namespace = namespace; this.lruCache?.clear(); } }
ts/**
* 缓存项接口
*/
export interface CacheEntry<T = any> {
/**
* 缓存值
*/
value: T;
/**
* 过期时间戳(ms)
*/
expire: number | null;
/**
* 最后访问时间戳
*/
lastAccessed: number;
/**
* 访问次数
*/
accessCount?: number;
}
/**
* 缓存策略类型
*/
export type CachePolicy = 'LRU' | 'LFU' | 'FIFO';
/**
* 缓存配置接口
*/
export interface CacheConfig {
/**
* 最大缓存大小
*/
maxSize: number;
/**
* 缓存策略
*/
policy: CachePolicy;
/**
* 默认过期时间(ms)
*/
defaultExpire: number | null;
/**
* 是否自动清理过期项
*/
autoSweep: boolean;
/**
* 自动清理间隔(ms)
*/
sweepInterval: number;
}
tsinterface CacheEntry<T = any> {
value: T;
expire: number | null;
lastAccessed: number;
}
/**
* LRU缓存实现 - 优化内存使用
*/
export class LRUCache<T = any> {
private cache = new Map<string, CacheEntry<T>>();
private maxSize: number;
constructor(maxSize = 100) {
this.maxSize = maxSize;
}
/**
* 获取缓存值
* @param key 缓存键
*/
get(key: string): T | null {
const entry = this.cache.get(key);
if (!entry) return null;
// 检查是否过期
if (entry.expire && Date.now() > entry.expire) {
this.cache.delete(key);
return null;
}
// 更新最后访问时间
entry.lastAccessed = Date.now();
this.cache.set(key, entry);
return entry.value;
}
/**
* 设置缓存值
* @param key 缓存键
* @param value 缓存值
* @param expire 过期时间(ms)
*/
set(key: string, value: T, expire: number | null = null): void {
// 如果达到最大容量,移除最久未使用的项
if (this.cache.size >= this.maxSize) {
const oldestKey = Array.from(this.cache.entries())
.sort((a, b) => a[1].lastAccessed - b[1].lastAccessed)[0][0];
this.cache.delete(oldestKey);
}
this.cache.set(key, {
value,
expire: expire ? Date.now() + expire : null,
lastAccessed: Date.now()
});
}
/**
* 删除缓存项
* @param key 缓存键
*/
delete(key: string): void {
this.cache.delete(key);
}
/**
* 检查缓存项是否存在
* @param key 缓存键
*/
has(key: string): boolean {
const entry = this.cache.get(key);
if (!entry) return false;
// 检查是否过期
if (entry.expire && Date.now() > entry.expire) {
this.cache.delete(key);
return false;
}
return true;
}
/**
* 获取所有缓存键
*/
keys(): string[] {
// 清理过期项
this.sweep();
return Array.from(this.cache.keys());
}
/**
* 清理过期项
*/
sweep(): number {
const now = Date.now();
let count = 0;
for (const [key, entry] of this.cache.entries()) {
if (entry.expire && now > entry.expire) {
this.cache.delete(key);
count++;
}
}
return count;
}
/**
* 清空缓存
*/
clear(): void {
this.cache.clear();
}
/**
* 获取缓存大小
*/
get size(): number {
return this.cache.size;
}
/**
* 设置最大缓存大小
* @param size 最大容量
*/
setMaxSize(size: number): void {
this.maxSize = size;
// 如果当前大小超过新限制,移除多余项
while (this.cache.size > this.maxSize) {
const oldestKey = Array.from(this.cache.entries())
.sort((a, b) => a[1].lastAccessed - b[1].lastAccessed)[0][0];
this.cache.delete(oldestKey);
}
}
}
tsimport type{ CryptoPlugin } from "../plugins/crypto";
import type{ LoggerPlugin } from "../plugins/logger";
import type{ ValidatorPlugin } from "../plugins/validator";
/**
* 引擎优先级配置
*/
export type EnginePriority = string[];
/**
* 全局存储配置
*/
export interface StoreGlobalConfig {
// 默认存储引擎
defaultEngine: string;
// 引擎优先级(用于自动降级)
enginePriority: EnginePriority;
// 是否开启自动降级
enableAutoDowngrade: boolean;
// 默认命名空间
defaultNamespace: string;
// 是否开启LRU缓存
enableLRUCache: boolean;
// LRU缓存大小
lruCacheSize: number;
// 是否开启锁机制
enableLock: boolean;
// 锁超时时间(ms)
lockTimeout: number;
// 是否开启日志
enableLogger: boolean;
// 是否开启加密
enableCrypto: boolean;
// 是否开启数据校验
enableValidation: boolean;
// 默认过期时间(ms)
defaultExpire: number | null;
// IndexedDB配置
indexeddb?: {
dbName: string;
storeName: string;
version: number;
};
}
/**
* 运行时可配置的选项
*/
export type RuntimeConfig = Partial<Omit<StoreGlobalConfig, 'indexeddb'>>;
/**
* 完整配置(包含插件)
*/
export interface StoreConfig extends StoreGlobalConfig {
// 加密插件
cryptoPlugin?: CryptoPlugin;
// 日志插件
loggerPlugin?: LoggerPlugin;
// 校验插件
validatorPlugin?: ValidatorPlugin;
}
/**
* 默认全局配置
*/
export const defaultConfig: StoreGlobalConfig = {
defaultEngine: 'localStorage',
enginePriority: ['indexeddb', 'localStorage', 'sessionStorage', 'memory'],
enableAutoDowngrade: true,
defaultNamespace: 'default',
enableLRUCache: true,
lruCacheSize: 100,
enableLock: true,
lockTimeout: 5000,
enableLogger: true,
enableCrypto: false,
enableValidation: false,
defaultExpire: null,
indexeddb: {
dbName: 'enterprise-store',
storeName: 'data',
version: 1,
},
};
/**
* 配置管理器
*/
export class ConfigManager {
private static instance: ConfigManager;
private config: StoreGlobalConfig;
private constructor() {
this.config = { ...defaultConfig };
}
/**
* 获取单例实例
*/
public static getInstance(): ConfigManager {
if (!ConfigManager.instance) {
ConfigManager.instance = new ConfigManager();
}
return ConfigManager.instance;
}
/**
* 获取当前配置
*/
public getConfig(): StoreGlobalConfig {
return { ...this.config };
}
/**
* 更新运行时配置
* @param newConfig 新配置
*/
public updateConfig(newConfig: RuntimeConfig): void {
this.config = { ...this.config, ...newConfig };
}
/**
* 重置配置到默认值
*/
public resetConfig(): void {
this.config = { ...defaultConfig };
}
/**
* 获取指定引擎的优先级
* @param engineName 引擎名称
*/
public getEnginePriority(engineName: string): number {
return this.config.enginePriority.indexOf(engineName);
}
}
// 导出全局配置实例
export const configManager = ConfigManager.getInstance();
ts/**
* 命名空间管理器 - 避免key冲突
*/
export class NamespaceManager {
private readonly separator = '::';
/**
* 生成带命名空间的键
* @param namespace 命名空间
* @param key 原始键
*/
getNamespacedKey(namespace: string, key: string): string {
if (!namespace) return key;
return `${namespace}${this.separator}${key}`;
}
/**
* 从带命名空间的键中提取原始键
* @param namespacedKey 带命名空间的键
* @param namespace 命名空间
*/
extractOriginalKey(namespacedKey: string, namespace: string): string {
if (!namespace) return namespacedKey;
const prefix = `${namespace}${this.separator}`;
return namespacedKey.startsWith(prefix)
? namespacedKey.slice(prefix.length)
: namespacedKey;
}
/**
* 过滤指定命名空间的键
* @param keys 所有键
* @param namespace 命名空间
*/
filterNamespaceKeys(keys: string[], namespace: string): string[] {
if (!namespace) return keys;
const prefix = `${namespace}${this.separator}`;
return keys
.filter(key => key.startsWith(prefix))
.map(key => this.extractOriginalKey(key, namespace));
}
/**
* 检查键是否属于指定命名空间
* @param key 键
* @param namespace 命名空间
*/
isInNamespace(key: string, namespace: string): boolean {
if (!namespace) return true;
return key.startsWith(`${namespace}${this.separator}`);
}
/**
* 获取命名空间
* @param namespacedKey 带命名空间的键
*/
getNamespace(namespacedKey: string): string {
const parts = namespacedKey.split(this.separator);
return parts.length > 1 ? parts[0] : '';
}
}
// 全局实例
export const namespaceManager = new NamespaceManager();
batch.ts/** * 批量操作优化器 * @param operation 要执行的批量操作 * @param batchSize 批次大小 * @returns 操作结果 */ export async function batchOptimize<T>( operation: () => Promise<T>, batchSize: number = 100 ): Promise<T> { // 性能监控 const startTime = performance.now(); try { // 执行操作 const result = await operation(); // 记录性能 const duration = performance.now() - startTime; if (duration > 100) { // 超过100ms的操作记录警告 console.warn(`Batch operation took ${duration.toFixed(2)}ms, consider optimizing batch size`); } return result; } catch (error) { console.error('Batch operation failed:', error); throw error; } } /** * 分割数组为批次 * @param array 原始数组 * @param batchSize 批次大小 * @returns 批次数组 */ export function splitIntoBatches<T>(array: T[], batchSize: number = 100): T[][] { const batches: T[][] = []; for (let i = 0; i < array.length; i += batchSize) { batches.push(array.slice(i, i + batchSize)); } return batches; } /** * 并行执行批次操作 * @param batches 批次数组 * @param handler 批次处理函数 * @returns 合并的结果 */ export async function executeBatches<T, R>( batches: T[][], handler: (batch: T[]) => Promise<R[]> ): Promise<R[]> { const results: R[][] = []; // 并行执行所有批次 const promises = batches.map(batch => handler(batch)); const batchResults = await Promise.allSettled(promises); // 处理结果 for (const result of batchResults) { if (result.status === 'fulfilled') { results.push(result.value); } else { console.error('Batch execution failed:', result.reason); results.push([]); } } // 合并结果 return results.flat(); }
downgrade.tsimport { engineRegistry } from "../core/registry/EngineRegistry"; import { configManager } from "../config/StoreConfig"; /** * 检查引擎是否支持 */ export async function checkEngineSupport(engineName: string): Promise<boolean> { const EngineConstructor = engineRegistry.getEngine(engineName); if (!EngineConstructor) { return false; } try { const engine = new EngineConstructor('__test__'); return await engine.testFunctionality(); } catch (error) { return false; } } /** * 获取降级引擎 */ export async function getFallbackEngine(preferredEngine: string): Promise<string | null> { const priority = configManager.getConfig().enginePriority; const preferredIndex = priority.indexOf(preferredEngine); // 从优先级列表中查找第一个支持的引擎 for (let i = preferredIndex + 1; i < priority.length; i++) { const engineName = priority[i]; if (await checkEngineSupport(engineName)) { return engineName; } } return null; }
类型守卫
type-guards.ts/** * 类型守卫工具类 */ /** * 检查值是否为字符串 * @param value 要检查的值 */ export function isString(value: unknown): value is string { return typeof value === 'string' || value instanceof String; } /** * 检查值是否为数字 * @param value 要检查的值 */ export function isNumber(value: unknown): value is number { return typeof value === 'number' && !isNaN(value); } /** * 检查值是否为布尔值 * @param value 要检查的值 */ export function isBoolean(value: unknown): value is boolean { return typeof value === 'boolean'; } /** * 检查值是否为数组 * @param value 要检查的值 */ export function isArray(value: unknown): value is any[] { return Array.isArray(value); } /** * 检查值是否为对象 * @param value 要检查的值 */ export function isObject(value: unknown): value is Record<string, any> { return typeof value === 'object' && value !== null && !Array.isArray(value); } /** * 检查值是否为函数 * @param value 要检查的值 */ export function isFunction(value: unknown): value is Function { return typeof value === 'function'; } /** * 检查值是否为null * @param value 要检查的值 */ export function isNull(value: unknown): value is null { return value === null; } /** * 检查值是否为undefined * @param value 要检查的值 */ export function isUndefined(value: unknown): value is undefined { return typeof value === 'undefined'; } /** * 检查值是否为Date对象 * @param value 要检查的值 */ export function isDate(value: unknown): value is Date { return value instanceof Date && !isNaN(value.getTime()); } /** * 检查值是否为有效的JSON * @param value 要检查的值 */ export function isJsonString(value: string): boolean { try { JSON.parse(value); return true; } catch { return false; } } /** * 检查值是否为过期时间戳 * @param timestamp 时间戳 */ export function isExpired(timestamp: number | null): boolean { if (timestamp === null) return false; return Date.now() > timestamp; } /** * 类型断言函数 - 确保值不为null/undefined * @param value 要断言的值 * @param message 错误消息 */ export function assertExists<T>(value: T | null | undefined, message = 'Value must exist'): asserts value is T { if (value === null || value === undefined) { throw new Error(message); } }
index.tsexport * from './batch'; export * from './downgrade'; export * from './type-guards'; /** * 通用工具函数 */ /** * 生成唯一ID * @param prefix 前缀 */ export function generateId(prefix = 'store_'): string { return `${prefix}${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } /** * 防抖函数 * @param func 要防抖的函数 * @param wait 等待时间 */ export function debounce<T extends (...args: any[]) => any>( func: T, wait: number ): (...args: Parameters<T>) => void { let timeout: number; return (...args: Parameters<T>) => { clearTimeout(timeout); timeout = setTimeout(() => func(...args), wait); }; } /** * 节流函数 * @param func 要节流的函数 * @param limit 限制时间 */ export function throttle<T extends (...args: any[]) => any>( func: T, limit: number ): (...args: Parameters<T>) => void { let lastCall = 0; return (...args: Parameters<T>) => { const now = Date.now(); if (now - lastCall >= limit) { lastCall = now; func(...args); } }; } /** * 深拷贝 * @param obj 要拷贝的对象 */ export function deepClone<T>(obj: T): T { if (obj === null || typeof obj !== 'object') { return obj; } if (obj instanceof Date) { return new Date(obj.getTime()) as T; } if (obj instanceof Array) { return obj.map(item => deepClone(item)) as T; } if (obj instanceof Object) { const clonedObj = {} as Record<string, any>; for (const key in obj) { if (obj.hasOwnProperty(key)) { clonedObj[key] = deepClone((obj as Record<string, any>)[key]); } } return clonedObj as T; } return obj; }
type.ts/** * 加密插件接口 */ export interface CryptoPlugin { /** * 加密数据 * @param data 原始数据 * @param key 加密密钥(可选) */ encrypt<T = any>(data: T, key?: string): Promise<string>; /** * 解密数据 * @param encryptedData 加密后的数据 * @param key 解密密钥(可选) */ decrypt<T = any>(encryptedData: string, key?: string): Promise<T>; /** * 设置默认密钥 * @param key 密钥 */ setDefaultKey(key: string): void; /** * 获取插件信息 */ getInfo(): { name: string; version: string }; }
DefaultCrypto.ts// src/plugins/crypto/DefaultCrypto.ts import type { CryptoPlugin } from "./types"; /** * 默认加密插件 - 使用AES加密 */ export class DefaultCrypto implements CryptoPlugin { private defaultKey = 'enterprise-store-default-key'; /** * 简单的加密实现(生产环境建议使用更安全的加密方式) */ async encrypt<T = any>(data: T, key?: string): Promise<string> { const secretKey = key || this.defaultKey; const jsonString = JSON.stringify(data); // 简单的XOR加密(仅示例,生产环境请使用Web Crypto API) let encrypted = ''; for (let i = 0; i < jsonString.length; i++) { encrypted += String.fromCharCode( jsonString.charCodeAt(i) ^ secretKey.charCodeAt(i % secretKey.length) ); } return btoa(encrypted); } /** * 解密 */ async decrypt<T = any>(encryptedData: string, key?: string): Promise<T> { const secretKey = key || this.defaultKey; const decoded = atob(encryptedData); // XOR解密 let decrypted = ''; for (let i = 0; i < decoded.length; i++) { decrypted += String.fromCharCode( decoded.charCodeAt(i) ^ secretKey.charCodeAt(i % secretKey.length) ); } return JSON.parse(decrypted); } /** * 设置默认密钥 */ setDefaultKey(key: string): void { this.defaultKey = key; } /** * 获取插件信息 */ getInfo(): { name: string; version: string } { return { name: 'DefaultCrypto', version: '1.0.0' }; } }
type.ts/** * 日志级别 */ export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal'; /** * 日志条目 */ export interface LogEntry { timestamp: number; level: LogLevel; operation: 'get' | 'set' | 'delete' | 'clear' | 'sweep' | 'batch' | 'test' | 'other' | 'keys' | 'has'; key?: string | string[]; namespace: string; engine: string; duration?: number; // 操作耗时(ms) success: boolean; error?: Error; metadata?: Record<string, any>; } /** * 日志插件接口 */ export interface LoggerPlugin { /** * 记录日志 * @param entry 日志条目 */ log(entry: LogEntry): Promise<void>; /** * 设置日志级别 * @param level 日志级别 */ setLogLevel(level: LogLevel): void; /** * 获取日志级别 */ getLogLevel(): LogLevel; /** * 上报错误 * @param error 错误对象 * @param context 上下文信息 */ reportError(error: Error, context?: Record<string, any>): Promise<void>; /** * 获取插件信息 */ getInfo(): { name: string; version: string }; }
DefaultLogger.ts// src/plugins/logger/DefaultLogger.ts import type{ LoggerPlugin, LogEntry, LogLevel } from "./types"; /** * 默认日志插件 */ export class DefaultLogger implements LoggerPlugin { private logLevel: LogLevel = 'info'; private logs: LogEntry[] = []; private maxLogs = 1000; /** * 记录日志 */ async log(entry: LogEntry): Promise<void> { // 根据日志级别过滤 const levels: LogLevel[] = ['debug', 'info', 'warn', 'error', 'fatal']; if (levels.indexOf(entry.level) < levels.indexOf(this.logLevel)) { return; } // 存储日志 this.logs.push(entry); // 限制日志数量 if (this.logs.length > this.maxLogs) { this.logs.shift(); } // 控制台输出 const logMessage = `[${new Date(entry.timestamp).toISOString()}] [${entry.level}] [${entry.engine}] [${entry.operation}] ${entry.success ? 'SUCCESS' : 'FAILED'} ${entry.key ? `(key: ${Array.isArray(entry.key) ? entry.key.join(',') : entry.key})` : ''}`; switch (entry.level) { case 'debug': console.debug(logMessage, entry); break; case 'info': console.info(logMessage, entry); break; case 'warn': console.warn(logMessage, entry); break; case 'error': case 'fatal': console.error(logMessage, entry.error || entry); break; } } /** * 设置日志级别 */ setLogLevel(level: LogLevel): void { this.logLevel = level; } /** * 获取日志级别 */ getLogLevel(): LogLevel { return this.logLevel; } /** * 上报错误 */ async reportError(error: Error, context?: Record<string, any>): Promise<void> { // 这里可以集成错误监控平台,如Sentry、Fundebug等 console.error('Error reported:', error, context); // 记录错误日志 await this.log({ timestamp: Date.now(), level: 'error', operation: 'other', namespace: context?.namespace || 'unknown', engine: context?.engine || 'unknown', success: false, error, metadata: context }); } /** * 获取插件信息 */ getInfo(): { name: string; version: string } { return { name: 'DefaultLogger', version: '1.0.0' }; } /** * 获取日志记录 */ getLogs(): LogEntry[] { return [...this.logs]; } /** * 清空日志 */ clearLogs(): void { this.logs = []; } }
type.ts/** * 校验结果 */ export interface ValidationResult { valid: boolean; errors?: string[]; } /** * 校验插件接口 */ export interface ValidatorPlugin { /** * 校验数据 * @param data 要校验的数据 * @param schema 校验规则 */ validate<T = any>(data: T, schema: any): Promise<ValidationResult>; /** * 获取插件信息 */ getInfo(): { name: string; version: string }; }
ZodValidator.ts// src/plugins/validator/ZodValidator.ts import { z, ZodSchema } from 'zod'; import type{ ValidatorPlugin, ValidationResult } from "./types"; /** * Zod校验插件 */ export class ZodValidator implements ValidatorPlugin { /** * 校验数据 */ async validate<T = any>(data: T, schema: ZodSchema): Promise<ValidationResult> { try { const result = schema.safeParse(data); if (result.success) { return { valid: true }; } else { return { valid: false, errors: result.error.issues.map(issue => `${issue.path.join('.')}: ${issue.message}` ) }; } } catch (error) { return { valid: false, errors: [error instanceof Error ? error.message : 'Unknown validation error'] }; } } /** * 获取插件信息 */ getInfo(): { name: string; version: string } { return { name: 'ZodValidator', version: '1.0.0' }; } }
type.ts/** * 响应式插件通用接口 */ export interface ReactivePlugin { /** * 创建响应式存储 * @param key 存储键 * @param initialValue 初始值 */ createReactiveStorage<T = any>(key: string, initialValue: T): ReactiveStorage<T>; } /** * 响应式存储接口 */ export interface ReactiveStorage<T = any> { /** * 响应式值 */ value: T; /** * 设置值 * @param value 新值 * @param expire 过期时间 */ set(value: T, expire?: number): Promise<boolean>; /** * 删除值 */ remove(): Promise<boolean>; /** * 刷新值 */ refresh(): Promise<void>; /** * 销毁响应式存储 */ destroy(): void; }
React Hooks
tsimport { useState, useEffect, useCallback } from 'react';
import { EnterpriseStore } from '../../core/Store';
/**
* React响应式Hook
*/
export function useStorage<T = any>(
store: EnterpriseStore,
key: string,
initialValue: T,
schema?: any
): [T, (value: T, expire?: number) => Promise<boolean>, () => Promise<boolean>] {
// 初始化状态
const [value, setValue] = useState<T>(initialValue);
// 加载数据
useEffect(() => {
async function loadData() {
const data = await store.get<T>(key, schema);
if (data !== null) {
setValue(data);
}
}
loadData();
// TODO: 可以实现监听存储变化的逻辑
const listener = (e: StorageEvent) => {
if (e.key === key) {
loadData();
}
};
window.addEventListener('storage', listener);
return () => window.removeEventListener('storage', listener);
}, [store, key, schema]);
// 设置值的函数
const setStoredValue = useCallback(async (newValue: T, expire?: number) => {
const success = await store.set(key, newValue, expire, schema);
if (success) {
setValue(newValue);
}
return success;
}, [store, key, schema]);
// 删除值的函数
const removeStoredValue = useCallback(async () => {
const success = await store.delete(key);
if (success) {
setValue(initialValue);
}
return success;
}, [store, key, initialValue]);
return [value, setStoredValue, removeStoredValue];
}
Vue Hooks
tsimport { ref, watch, onMounted } from 'vue';
import type{ Ref } from 'vue';
import { EnterpriseStore } from '../../core/Store';
// 定义返回类型接口
interface UseStorageReturn<T> {
value: Ref<T>;
set: (newValue: T, expire?: number) => Promise<boolean>;
remove: () => Promise<boolean>;
load: () => Promise<void>;
}
/**
* Vue响应式Composable
*/
export function useStorage<T = any>(
store: EnterpriseStore,
key: string,
initialValue: T,
schema?: any
): UseStorageReturn<T> {
const value = ref<T>(initialValue) as Ref<T>;
// 加载数据
const load = async () => {
const data = await store.get<T>(key, schema);
if (data !== null) {
value.value = data;
}
};
// 设置值
const set = async (newValue: T, expire?: number) => {
const success = await store.set(key, newValue, expire, schema);
if (success) {
value.value = newValue;
}
return success;
};
// 删除值
const remove = async () => {
const success = await store.delete(key);
if (success) {
value.value = initialValue;
}
return success;
};
// 初始化加载
onMounted(() => {
load();
// TODO: 实现监听逻辑
window.addEventListener('storage', (e) => {
if (e.key === key) {
load();
}
});
});
// 双向绑定
watch(value, (newValue) => {
store.set(key, newValue, undefined, schema);
}, { deep: true });
return {
value,
set,
remove,
load
};
}
ts// 核心接口
export * from './core/interfaces/IStore';
// 主存储类
export { EnterpriseStore } from './core/Store';
// 配置管理
export * from './config';
// 存储引擎
export { MemoryEngine } from './core/engine/MemoryEngine';
export { LocalStorageEngine } from './core/engine/LocalStorageEngine';
export { SessionStorageEngine } from './core/engine/SessionStorageEngine';
export { IndexedDBEngine } from './core/engine/IndexedDBEngine';
// 引擎注册
export { engineRegistry } from './core/registry/EngineRegistry';
// 插件
export * from './plugins/crypto';
export * from './plugins/logger';
export * from './plugins/validator';
export * from './plugins/reactive';
// 工具函数
export * from './utils';
// 初始化默认引擎
import { engineRegistry } from './core/registry/EngineRegistry';
import { MemoryEngine } from './core/engine/MemoryEngine';
import { LocalStorageEngine } from './core/engine/LocalStorageEngine';
import { SessionStorageEngine } from './core/engine/SessionStorageEngine';
import { IndexedDBEngine } from './core/engine/IndexedDBEngine';
import { EnterpriseStore } from './core/Store';
// 注册默认引擎
engineRegistry.registerEngine('memory', MemoryEngine);
engineRegistry.registerEngine('localStorage', LocalStorageEngine);
engineRegistry.registerEngine('sessionStorage', SessionStorageEngine);
engineRegistry.registerEngine('indexeddb', IndexedDBEngine);
// 默认导出
export default EnterpriseStore;
tsimport { EnterpriseStore, DefaultCrypto, DefaultLogger, ZodValidator } from './index';
import { z } from 'zod';
// 正确的使用方式
async function initStore() {
// 1. 异步创建存储实例(关键修改)
const store = await EnterpriseStore.create({
namespace: 'my-app',
engine: 'indexeddb',
config: {
enableAutoDowngrade: true,
enableLRUCache: true,
lruCacheSize: 200,
enableCrypto: true,
enableValidation: true,
enableLogger: true
},
cryptoPlugin: new DefaultCrypto(),
loggerPlugin: new DefaultLogger(),
validatorPlugin: new ZodValidator(),
encryptionKey: 'my-secret-key-123'
});
// 2. 定义数据校验规则
const userSchema = z.object({
id: z.string().uuid(),
name: z.string().min(2),
age: z.number().int().positive()
});
// 3. 执行存储操作
await store.set(
'user:123',
{ id: '123e4567-e89b-12d3-a456-426614174000', name: '张三', age: 25 },
86400000, // 24小时过期
userSchema
);
const user = await store.get('user:123', userSchema);
console.log(user);
return store;
}
// 初始化并使用存储
initStore().catch(console.error);


本文作者:繁星
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!