gaoluyang
2026-06-24 c0cb161bb52ce0fbdce5c66ec391d107c75e2452
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
//#region src/cache/indexeddb-driver.ts
/**
* IndexedDB 驱动
* 采用懒初始化模式,首次操作时自动打开数据库
*/
var IndexedDBDriver = class {
    dbName;
    dbPromise = null;
    dbVersion;
    storeName;
    constructor({ dbName = "vben-storage", dbVersion = 1, storeName = "kv-store" } = {}) {
        this.dbName = dbName;
        this.dbVersion = dbVersion;
        this.storeName = storeName;
    }
    async clear() {
        const db = await this.getDB();
        return new Promise((resolve, reject) => {
            const tx = db.transaction(this.storeName, "readwrite");
            tx.objectStore(this.storeName).clear();
            tx.addEventListener("complete", () => resolve());
            tx.addEventListener("error", () => reject(tx.error));
            tx.addEventListener("abort", () => reject(tx.error ?? /* @__PURE__ */ new Error("Transaction aborted")));
        });
    }
    async getItem(key) {
        const db = await this.getDB();
        return new Promise((resolve, reject) => {
            const request = db.transaction(this.storeName, "readonly").objectStore(this.storeName).get(key);
            request.addEventListener("success", () => resolve(request.result ?? null));
            request.addEventListener("error", () => reject(request.error));
        });
    }
    async keys() {
        const db = await this.getDB();
        return new Promise((resolve, reject) => {
            const request = db.transaction(this.storeName, "readonly").objectStore(this.storeName).getAllKeys();
            request.addEventListener("success", () => resolve(request.result.map(String)));
            request.addEventListener("error", () => reject(request.error));
        });
    }
    async removeItem(key) {
        const db = await this.getDB();
        return new Promise((resolve, reject) => {
            const tx = db.transaction(this.storeName, "readwrite");
            tx.objectStore(this.storeName).delete(key);
            tx.addEventListener("complete", () => resolve());
            tx.addEventListener("error", () => reject(tx.error));
            tx.addEventListener("abort", () => reject(tx.error ?? /* @__PURE__ */ new Error("Transaction aborted")));
        });
    }
    async setItem(key, value) {
        const db = await this.getDB();
        return new Promise((resolve, reject) => {
            const tx = db.transaction(this.storeName, "readwrite");
            tx.objectStore(this.storeName).put(value, key);
            tx.addEventListener("complete", () => resolve());
            tx.addEventListener("error", () => reject(tx.error));
            tx.addEventListener("abort", () => reject(tx.error ?? /* @__PURE__ */ new Error("Transaction aborted")));
        });
    }
    /**
    * 懒初始化:首次调用时打开数据库,后续复用同一个 Promise
    */
    getDB() {
        if (!this.dbPromise) this.dbPromise = this.openDB().catch((error) => {
            this.dbPromise = null;
            throw error;
        });
        return this.dbPromise;
    }
    openDB() {
        return new Promise((resolve, reject) => {
            const request = indexedDB.open(this.dbName, this.dbVersion);
            request.addEventListener("upgradeneeded", () => {
                const db = request.result;
                if (!db.objectStoreNames.contains(this.storeName)) db.createObjectStore(this.storeName);
            });
            request.addEventListener("success", () => resolve(request.result));
            request.addEventListener("error", () => reject(request.error));
        });
    }
};
//#endregion
//#region src/cache/local-storage-driver.ts
/**
* LocalStorage / SessionStorage 驱动
* 用 async 包装同步 API,保持接口统一
*/
var LocalStorageDriver = class {
    storage;
    constructor({ storageType = "localStorage" } = {}) {
        if (typeof window === "undefined") throw new TypeError("LocalStorageDriver is not available in non-browser environments. Use MemoryStorageDriver instead.");
        this.storage = storageType === "localStorage" ? window.localStorage : window.sessionStorage;
    }
    async clear() {
        this.storage.clear();
    }
    async getItem(key) {
        const raw = this.storage.getItem(key);
        if (raw === null) return null;
        try {
            return JSON.parse(raw);
        } catch {
            this.storage.removeItem(key);
            return null;
        }
    }
    async keys() {
        const result = [];
        for (let i = 0; i < this.storage.length; i++) {
            const key = this.storage.key(i);
            if (key !== null) result.push(key);
        }
        return result;
    }
    async removeItem(key) {
        this.storage.removeItem(key);
    }
    async setItem(key, value) {
        this.storage.setItem(key, JSON.stringify(value));
    }
};
//#endregion
//#region src/cache/memory-storage-driver.ts
/**
* 内存存储驱动
* 适用于测试环境和 SSR 场景,数据不持久化
*/
var MemoryStorageDriver = class {
    store = /* @__PURE__ */ new Map();
    async clear() {
        this.store.clear();
    }
    async getItem(key) {
        return this.store.get(key) ?? null;
    }
    async keys() {
        return [...this.store.keys()];
    }
    async removeItem(key) {
        this.store.delete(key);
    }
    async setItem(key, value) {
        this.store.set(key, value);
    }
};
//#endregion
//#region src/cache/storage-manager.ts
/**
* 存储管理器(策略模式)
* - prefix(命名空间隔离)在此层处理
* - TTL(过期机制)在此层处理
* - Driver 只负责纯粹的 KV 存取
*/
var StorageManager = class {
    driver;
    prefix;
    constructor({ driver, prefix = "" } = {}) {
        this.driver = driver || this.createDefaultDriver();
        this.prefix = prefix;
        if (!this.prefix && this.driver instanceof LocalStorageDriver) console.warn("[StorageManager] empty prefix combined with LocalStorageDriver — clear()/keys() will affect every localStorage entry.");
    }
    /**
    * 清除所有带前缀的存储项
    */
    async clear() {
        const allKeys = await this.driver.keys();
        const fullPrefix = this.prefix ? `${this.prefix}-` : "";
        const prefixedKeys = allKeys.filter((key) => key.startsWith(fullPrefix));
        await Promise.all(prefixedKeys.map((key) => this.driver.removeItem(key)));
    }
    /**
    * 清除所有过期的存储项
    */
    async clearExpiredItems() {
        const allKeys = await this.driver.keys();
        const fullPrefix = this.prefix ? `${this.prefix}-` : "";
        const prefixedKeys = allKeys.filter((key) => key.startsWith(fullPrefix));
        for (const fullKey of prefixedKeys) {
            const raw = await this.driver.getItem(fullKey);
            if (raw && raw.expiry && Date.now() > raw.expiry) await this.driver.removeItem(fullKey);
        }
    }
    /**
    * 获取存储项
    * @param key 键
    * @param defaultValue 当项不存在或已过期时返回的默认值
    * @returns 值,如果项已过期则返回默认值
    */
    async getItem(key, defaultValue = null) {
        const fullKey = this.getFullKey(key);
        const raw = await this.driver.getItem(fullKey);
        if (!raw) return defaultValue;
        if (raw.expiry && Date.now() > raw.expiry) {
            await this.driver.removeItem(fullKey);
            return defaultValue;
        }
        return raw.value;
    }
    /**
    * 获取当前前缀下的所有存储键(已去除前缀部分)
    */
    async keys() {
        const allKeys = await this.driver.keys();
        const fullPrefix = this.prefix ? `${this.prefix}-` : "";
        if (!fullPrefix) return allKeys;
        return allKeys.filter((key) => key.startsWith(fullPrefix)).map((key) => key.slice(fullPrefix.length));
    }
    /**
    * 移除存储项
    * @param key 键
    */
    async removeItem(key) {
        const fullKey = this.getFullKey(key);
        await this.driver.removeItem(fullKey);
    }
    /**
    * 设置存储项
    * @param key 键
    * @param value 值
    * @param ttl 存活时间(毫秒)
    */
    async setItem(key, value, ttl) {
        const fullKey = this.getFullKey(key);
        const item = {
            expiry: ttl ? Date.now() + ttl : void 0,
            value
        };
        await this.driver.setItem(fullKey, item);
    }
    /**
    * 根据运行环境创建默认驱动:
    * - 浏览器环境(window.localStorage 可用)→ LocalStorageDriver
    * - SSR / Node 环境 → MemoryStorageDriver
    */
    createDefaultDriver() {
        try {
            if (typeof window !== "undefined" && window.localStorage) return new LocalStorageDriver();
        } catch (error) {
            console.warn("localStorage is not accessible, falling back to MemoryStorageDriver:", error);
        }
        return new MemoryStorageDriver();
    }
    /**
    * 获取完整的存储键(带前缀)
    * @param key 原始键
    * @returns 带前缀的完整键
    */
    getFullKey(key) {
        return this.prefix ? `${this.prefix}-${key}` : key;
    }
};
//#endregion
export { IndexedDBDriver, LocalStorageDriver, MemoryStorageDriver, StorageManager };