UNPKG

bucket-storage

Version:

Bucket-storage is an easy storage. It supports rich functions

358 lines (348 loc) 13.1 kB
// src/utls/log.ts function logError(errorType, err) { console.error(`bucket-storage ${errorType} error: ` + err); } // src/utls/is.ts function is(val, type) { return toString.call(val) === `[object ${type}]`; } function isDef(val) { return typeof val !== "undefined"; } function isUnDef(val) { return !isDef(val); } function isNull(val) { return val === null; } function isNullOrUnDef(val) { return isUnDef(val) || isNull(val); } function isObject(val) { return !isNullOrUnDef(val) && is(val, "Object"); } function isArray(val) { return !isNullOrUnDef(val) && is(val, "Array"); } function isValueType(val) { return !isArray(val) && !isObject(val); } function isDate(val) { return is(val, "Date"); } // src/storage/memory.ts var memoryData = new Map(); var memoryStorage = { key(_) { return null; }, setItem: (key, value) => { memoryData.set(key, value); }, get length() { return memoryData.size; }, getItem: (key) => { const value = memoryData.get(key); return isDef(value) ? value : null; }, removeItem: (key) => { memoryData.delete(key); }, clear: () => { memoryData.clear(); } }; // src/storage/storage.ts var storages = { local: window.localStorage, session: window.sessionStorage, memory: memoryStorage }; function isStorageType(storageType) { return !isNullOrUnDef(storageType) && Object.keys(storages).includes(storageType.toString()); } // src/utls/const.ts var DEFAULT_BUCKET_NAME = "__BUCKET-STORAGE__"; var DEFAULT_ENCRYPTION_KEY = "_BUCKET-STORAGE_"; var ENCRYPT_TEXT_SYMBOL = "@BUCKET-STORAGE"; var BUCKET_STORAGE_KEY = "__BUCKET_STORAGE_KEYS__"; // src/manager/base.ts var BucketStorageBaseManager = class { constructor(storageType, bucketName) { this.bucketName = bucketName; this.storageType = storageType; this.manager = new Map(); } getBucketName(bucketName) { return !isNullOrUnDef(bucketName) && isValueType(bucketName) ? bucketName.toString() : this.bucketName; } getStorageType(storageType) { return !isNullOrUnDef(storageType) && isStorageType(storageType) ? storageType : this.storageType; } getStorage(storageType) { return storages[this.getStorageType(storageType)]; } getCurrentStorageTypeManager(storageType) { var _a; return ((_a = this.manager) == null ? void 0 : _a.get(this.getStorageType(storageType))) || null; } getCurrentBucket(bucketName, storageType) { var _a; return ((_a = this.getCurrentStorageTypeManager(storageType)) == null ? void 0 : _a[this.getBucketName(bucketName)]) || null; } }; // src/utls/cipher.ts import { encrypt, decrypt } from "crypto-js/aes"; import ECB from "crypto-js/mode-ecb"; import UTF8 from "crypto-js/enc-utf8"; import Pkcs7 from "crypto-js/pad-pkcs7"; import Base64 from "crypto-js/enc-base64"; import { parse } from "crypto-js/enc-utf8"; var AesEncryption = class { constructor(opt = {}) { this.key = ""; const { key, iv } = opt; this.key = parse(key || DEFAULT_ENCRYPTION_KEY); this.iv = parse(iv || DEFAULT_ENCRYPTION_KEY); } get getOptions() { return { mode: ECB, padding: Pkcs7, iv: this.iv }; } encrypt(text) { return encrypt(text, this.key, this.getOptions).toString(); } decrypt(ciphertext) { return decrypt(ciphertext, this.key, this.getOptions).toString(UTF8); } }; function encryptByBase64(text) { return UTF8.parse(text).toString(Base64); } function decodeByBase64(ciphertext) { return Base64.parse(ciphertext).toString(UTF8); } // src/manager/key.ts var BucketStorageKeyManager = class extends BucketStorageBaseManager { constructor(storageType, bucketName) { super(storageType, bucketName); this.init(); } init() { const fn = (storageType) => { const storage = this.getStorage(storageType); const keysStr = storage.getItem(BUCKET_STORAGE_KEY); if (!keysStr) return; try { const keysData = JSON.parse(decodeByBase64(keysStr)); this.manager.set(storageType, keysData); } catch (err) { this.manager.delete(storageType); logError(`init ${storageType} keys`, err); } }; Object.keys(storages).forEach((type) => { fn(type); }); } exist(value, options) { var _a; return ((_a = this.getCurrentBucket(options == null ? void 0 : options.bucketName, options == null ? void 0 : options.storageType)) == null ? void 0 : _a.includes(value)) || false; } add(value, options) { if (this.exist(value, options)) return; const storageType = this.getStorageType(options == null ? void 0 : options.storageType); !this.manager.has(storageType) && this.manager.set(storageType, {}); const currentStorageTypeManager = this.getCurrentStorageTypeManager(storageType); const bucketName = this.getBucketName(options == null ? void 0 : options.bucketName); !currentStorageTypeManager[bucketName] && (currentStorageTypeManager[bucketName] = []); currentStorageTypeManager[bucketName].push(value); this.durable(options == null ? void 0 : options.storageType); } remove(value, options) { if (!this.exist(value, options)) return; const currentBucket = this.getCurrentBucket(options == null ? void 0 : options.bucketName, options == null ? void 0 : options.storageType); currentBucket.splice(currentBucket.indexOf(value), 1); this.durable(options == null ? void 0 : options.storageType); } clear(bucketName, storageType) { const currentBucket = this.getCurrentBucket(bucketName, storageType); if (!(currentBucket == null ? void 0 : currentBucket.length)) return; currentBucket.splice(0, currentBucket.length); this.durable(storageType); } durable(storageType) { storageType = this.getStorageType(storageType); const currentStorageKeys = this.getCurrentStorageTypeManager(storageType); if (isNullOrUnDef(currentStorageKeys)) return; const currentStorageKeysStr = encryptByBase64(JSON.stringify(currentStorageKeys)); this.getStorage(storageType).setItem(BUCKET_STORAGE_KEY, currentStorageKeysStr); } }; // src/manager/watch.ts var BucketStorageWatchManager = class extends BucketStorageBaseManager { constructor(storageType, bucketName) { super(storageType, bucketName); } exist(key, value, options) { var _a, _b; return ((_b = (_a = this.getCurrentBucket(options == null ? void 0 : options.bucketName, options == null ? void 0 : options.storageType)) == null ? void 0 : _a[key]) == null ? void 0 : _b.includes(value)) || false; } add(key, value, options) { if (this.exist(key, value, options)) return; const storageType = this.getStorageType(options == null ? void 0 : options.storageType); !this.manager.has(storageType) && this.manager.set(storageType, {}); const currentStorageTypeManager = this.getCurrentStorageTypeManager(storageType); const bucketName = this.getBucketName(options == null ? void 0 : options.bucketName); !currentStorageTypeManager[bucketName] && (currentStorageTypeManager[bucketName] = {}); !currentStorageTypeManager[bucketName][key] && (currentStorageTypeManager[bucketName][key] = []); currentStorageTypeManager[bucketName][key].push(value); } get(key, options) { var _a; return ((_a = this.getCurrentBucket(options == null ? void 0 : options.bucketName, options == null ? void 0 : options.storageType)) == null ? void 0 : _a[key]) || []; } remove(key, value, options) { if (!this.exist(key, value, options)) return; const currentBucket = this.getCurrentBucket(options == null ? void 0 : options.bucketName, options == null ? void 0 : options.storageType); currentBucket[key].splice(currentBucket[key].indexOf(value), 1); } clear(key, options) { var _a; const currentBucket = this.getCurrentBucket(options == null ? void 0 : options.bucketName, options == null ? void 0 : options.storageType); if (isNull(currentBucket) || !((_a = currentBucket[key]) == null ? void 0 : _a.length)) return; currentBucket[key].splice(0, currentBucket[key].length); } }; // src/index.ts var BucketStorage = class { constructor(opt) { this.encrypt = true; this.bucketName = DEFAULT_BUCKET_NAME; this.expire = null; this.storageType = "session"; const { encrypt: encrypt2, bucketName, expire, storageType, encryptOption } = opt || {}; this.bucketName = !isNullOrUnDef(bucketName) && isValueType(bucketName) ? bucketName == null ? void 0 : bucketName.toString() : DEFAULT_BUCKET_NAME; this.expire = !Number(expire) ? null : isDate(expire) ? expire : Number(expire); this.storageType = !isNullOrUnDef(storageType) && isStorageType(storageType) ? storageType : "session"; this.encrypt = (encrypt2 == null ? void 0 : encrypt2.toString()) !== "false"; this.encryption = new AesEncryption(isObject(encryptOption) ? encryptOption : { iv: DEFAULT_ENCRYPTION_KEY, key: DEFAULT_ENCRYPTION_KEY }); this.keyManager = new BucketStorageKeyManager(this.storageType, this.bucketName); this.watchManager = new BucketStorageWatchManager(this.storageType, this.bucketName); } set(key, value, options) { let oldData = void 0; this.keyManager.exist(key, options) && (oldData = this.get(key, options)); const stringData = JSON.stringify({ value: isDef(value) ? value : null, time: Date.now(), expire: this.getExpire(options == null ? void 0 : options.expire) }); const stringifyValue = this.encryptStr(stringData, options == null ? void 0 : options.encrypt); this.getStorage(options == null ? void 0 : options.storageType).setItem(this.getKey(key, options == null ? void 0 : options.bucketName), stringifyValue); isDef(oldData) && this.watchManager.get(key, options).forEach((callback) => { callback(value, oldData); }); this.keyManager.add(key, options); } get(key, options) { if (!this.keyManager.exist(key, options)) return null; const stringifyValue = this.getStorage(options == null ? void 0 : options.storageType).getItem(this.getKey(key, options == null ? void 0 : options.bucketName)); if (isNull(stringifyValue)) { return null; } try { const stringData = this.decryptStr(stringifyValue); const data = JSON.parse(stringData); const { value, expire } = data; if (isNullOrUnDef(expire) || expire >= Date.now()) { return value; } this.remove(key); return null; } catch (err) { logError(`get ${key} value`, err); return null; } } remove(key, options) { if (!this.keyManager.exist(key, options)) return; const storage = this.getStorage(options == null ? void 0 : options.storageType); const watches = this.watchManager.get(key, options); key = this.getKey(key, options == null ? void 0 : options.bucketName); const stringifyValue = (watches == null ? void 0 : watches.length) ? storage.getItem(key) : void 0; storage.removeItem(key); if (!isNullOrUnDef(stringifyValue)) { const stringData = this.decryptStr(stringifyValue); const data = JSON.parse(stringData); const { value } = data; watches.forEach((callback) => { callback(null, value); }); } this.keyManager.remove(key, options); } clear(bucketName, options) { var _a; const bucketKeys = (_a = this.keyManager) == null ? void 0 : _a.getCurrentBucket(bucketName, options == null ? void 0 : options.storageType); if (!(bucketKeys == null ? void 0 : bucketKeys.length)) return; const storage = this.getStorage(options == null ? void 0 : options.storageType); bucketKeys.forEach((key) => { storage.removeItem(this.getKey(key, bucketName)); }); this.keyManager.clear(bucketName, options == null ? void 0 : options.storageType); } watch(key, callback, options) { this.watchManager.add(key, callback, options); } unWatch(key, callback, options) { this.watchManager.remove(key, callback, options); } getStorageType(storageType) { return !isNullOrUnDef(storageType) && isStorageType(storageType) ? storageType : this.storageType; } getStorage(type) { return storages[this.getStorageType(type)]; } getBucketName(bucketName) { return !isNullOrUnDef(bucketName) && isValueType(bucketName) ? bucketName.toString() : this.bucketName; } getKey(key, bucketName) { bucketName = this.getBucketName(bucketName); return `${bucketName}__${key}`; } getExpire(expire) { const fn = (e) => { return !Number(e) ? null : isDate(e) ? e.getTime() : new Date().getTime() + Number(e); }; return isDef(expire) ? fn(expire) : fn(this.expire); } encryptStr(value, encrypt2) { encrypt2 = isDef(encrypt2) ? encrypt2.toString() !== "false" : this.encrypt; return encrypt2 ? this.encryption.encrypt(value) + ENCRYPT_TEXT_SYMBOL : value; } decryptStr(value) { return value.endsWith(ENCRYPT_TEXT_SYMBOL) ? this.encryption.decrypt(value.substr(0, value.lastIndexOf(ENCRYPT_TEXT_SYMBOL))) : value; } }; export { BucketStorage as default };