bucket-storage
Version:
Bucket-storage is an easy storage. It supports rich functions
358 lines (348 loc) • 13.1 kB
JavaScript
// 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
};