web-localstorage-plus
Version:
Enhanced localStorage
631 lines (612 loc) • 16.4 kB
JavaScript
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
// src/helper/const.ts
var pkgName = "web-localstorage-plus";
var defaultRootName = pkgName;
var workerMsg = `${pkgName}-expired`;
var defaultLocalStorage = {
getItem: () => {
},
setItem: () => {
},
removeItem: () => {
},
clearItem: () => {
}
};
var messages = /* @__PURE__ */ new Map([
["DISABLED_LOC", `\u8BF7\u4F7F\u7528${pkgName}\u8FDB\u884C\u5B58\u50A8\u64CD\u4F5C`],
["NOT_FOUND_NAME", (name) => `\u65E0\u6CD5\u901A\u8FC7${name}\u627E\u5230\u5339\u914D\u7684\u5B58\u50A8\u6570\u636E\uFF0C\u8BF7\u6307\u5B9Anamespace\u8FDB\u884C\u5C1D\u8BD5`],
["NOT_FOUND_SPACE", (name) => `\u547D\u540D\u7A7A\u95F4\uFF08${name}\uFF09\u4E0D\u5B58\u5728`]
]);
// src/helper/function.ts
function cloneDeep(o) {
return JSON.parse(JSON.stringify(o));
}
var isObject = (p) => Object.prototype.toString.call(p) === "[object Object]";
function log(messageType, color = "log", rest) {
let msg = messages.get(messageType);
if (typeof msg === "function") {
msg = msg(rest);
}
console[color](`[web-storage]:${msg}`);
}
function setupGlobal(that) {
window.WEB_STORAGE_USE_LOCAL_STORAGE = () => that.localStorage;
window.WEB_STORAGE_EXPIRES = [];
window.WEB_STORAGE_USER_REGISTERED_CALLBACK = {
change: [],
expire: [],
on: []
};
window.WEB_STORAGE_IS_WARNING = true;
}
function useCallback(eventType) {
const [callback] = useGlobal("WEB_STORAGE_USER_REGISTERED_CALLBACK");
const curCb = callback[eventType] || [];
return [
curCb,
(newCb) => {
window.WEB_STORAGE_USER_REGISTERED_CALLBACK[eventType] = newCb;
}
];
}
function useGlobal(type) {
return [
window[type],
(newValue) => {
window[type] = newValue;
}
];
}
// src/core/native-storage.ts
function native_storage_default(rootName) {
const localStorage = window.WEB_STORAGE_USE_LOCAL_STORAGE();
const load = () => JSON.parse(localStorage.getItem(rootName) || "{}");
function _update(storage) {
localStorage.setItem(rootName, JSON.stringify(storage));
}
function _createSpace(storage, namespace) {
if (namespace) {
storage[namespace] = storage[namespace] || {};
return storage[namespace];
}
return storage;
}
return {
load,
methods: {
getItem(params) {
const { key, namespace = "" } = params;
const storage = load();
if (isObject(storage[namespace]))
return storage[namespace][key];
if (storage[key])
return storage[key];
window.WEB_STORAGE_IS_WARNING && log("NOT_FOUND_NAME", "warn", key);
},
setItem(params) {
const { key, value, namespace } = params;
const storage = load();
const space = _createSpace(storage, namespace);
space[key] = value;
_update(storage);
},
removeItem(params) {
const { key, namespace = "" } = params;
const storage = load();
if (isObject(storage[namespace])) {
delete storage[namespace][key];
} else {
delete storage[key];
}
_update(storage);
},
removeSpace(space) {
const storage = load();
delete storage[space];
_update(storage);
},
clear() {
const storage = load();
for (let key in storage) {
delete storage[key];
}
_update(storage);
}
}
};
}
// src/core/api/getItem.ts
function getItem(key, namespace, isFlatten) {
const params = {
key: "",
namespace: getNamespace()
};
let flatten = false;
const queue = [];
if (typeof key === "string") {
params.key = key;
params.namespace = getNamespace(namespace);
queue.push(params);
flatten = true;
} else if (Array.isArray(key)) {
key.forEach((k) => {
const p = __spreadValues({}, params);
if (typeof k === "string") {
p.key = k;
if (namespace) {
if (typeof namespace === "string") {
p.namespace = getNamespace(namespace);
} else {
p.namespace = getNamespace();
flatten = namespace;
}
}
if (isFlatten) {
flatten = isFlatten;
}
} else {
p.key = k.key;
p.namespace = k.namespace;
flatten = !!namespace;
}
queue.push(p);
});
}
let res = queue.map((v) => ({
value: runPlugin(
__spreadProps(__spreadValues({}, v), {
ctx: native,
value: native.methods.getItem(v)
}),
"getItem"
),
namespace: v.namespace
}));
if (flatten) {
res = res.map((v) => v.value);
}
return typeof key === "string" ? res[0] : res;
}
var getItem_default = getItem;
// src/core/api/worker.ts
var workerFile = `
let timer = null;
self.addEventListener("message", (params) => {
clearInterval(timer);
const { data } = params || {};
const { meaasgeType, payload } = data || {};
function run() {
timer = setInterval(() => {
if (meaasgeType && Array.isArray(payload)) {
const legals = payload.filter((v) => Date.now() >= v.expireTime);
if (Array.isArray(legals) && legals.length) {
clearInterval(timer);
postMessage(legals);
run()
}
}
}, 500);
}
run();
});
`;
var workBlob = new Blob([workerFile]);
var workUrl = URL.createObjectURL(workBlob);
var WorkerSpace = class {
static getInstance() {
if (WorkerSpace.instance) {
return WorkerSpace.instance.run();
}
WorkerSpace.instance = new WorkerSpace();
WorkerSpace.instance.run();
}
run() {
if (!this.worker) {
this.worker = new Worker(workUrl);
}
this.worker.postMessage({
meaasgeType: workerMsg,
payload: window.WEB_STORAGE_EXPIRES
});
this.worker.onmessage = (payload) => {
const { data } = payload;
if (Array.isArray(data)) {
data.forEach((v) => window.WEB_STORAGE_APIS.getItem(v.key, v.namespace));
}
};
}
};
var worker_default = WorkerSpace.getInstance;
// src/core/api/setItem.ts
function setExpire({ expireTime, key, namespace }) {
if (typeof expireTime === "number") {
const [expires = [], update] = useGlobal("WEB_STORAGE_EXPIRES");
const params = {
key,
expireTime: Date.now() + expireTime,
namespace
};
const i = expires.findIndex((v) => {
let legal = v.key === key;
if (legal && namespace) {
legal = v.namespace === namespace;
}
return legal;
});
if (i === -1) {
expires.push(params);
} else {
expires[i].expireTime = expireTime;
}
update(expires);
worker_default();
}
}
function setItem(key, value, namespace, expireTime, encrypt) {
const params = {
key: "",
value,
namespace: getNamespace()
};
const queue = [];
if (typeof key === "string") {
params.key = key;
params.value = value;
params.encrypt = encrypt;
params.expireTime = expireTime;
if (typeof namespace === "string") {
params.namespace = namespace;
} else if (typeof namespace === "boolean") {
params.encrypt = namespace;
} else if (typeof namespace === "number") {
params.expireTime = namespace;
}
queue.push(params);
} else {
key.forEach((v) => {
v.namespace = v.namespace || value;
queue.push(v);
});
}
queue.forEach((v) => {
setExpire(v);
v.value = runPlugin(
__spreadProps(__spreadValues({}, v), {
ctx: native
}),
"setItem"
);
native.methods.setItem(v);
});
}
var setItem_default = setItem;
// src/core/api/removeItem.ts
function removeItem(key, namespace) {
const params = {
key: "",
namespace: getNamespace()
};
const queue = [];
if (typeof key === "string") {
params.key = key;
if (typeof namespace === "string") {
params.namespace = namespace;
}
queue.push(params);
} else {
key.forEach((v) => {
const p = __spreadValues({}, params);
if (typeof v === "string") {
p.key = v;
p.namespace = getNamespace(namespace);
} else {
p.key = v.key;
p.namespace = v.namespace || getNamespace(namespace);
}
queue.push(p);
});
}
queue.forEach((v) => {
runPlugin.call(
native,
__spreadProps(__spreadValues({}, v), {
ctx: native
}),
"removeItem"
);
native.methods.removeItem(v);
});
}
var removeItem_default = removeItem;
// src/core/api/clear.ts
function clear(include, reverse) {
let que = Array.isArray(include) ? include : [];
if (!que.length) {
native.methods.clear();
} else {
if (reverse === true) {
que = Object.keys(native.load()).filter((v) => !que.find((q) => v === q));
}
que.forEach((v) => native.methods.removeSpace(v));
}
runPlugin(
{
value: que,
ctx: native
},
"clear"
);
}
var clear_default = clear;
// src/core/api/change.ts
function change(key, callback, namespace) {
const spacename = getNamespace(namespace);
const [change2, setChange] = useCallback("change");
change2.push({
key,
namespace: spacename,
callback
});
setChange(change2);
}
var change_default = change;
// src/core/api/bus.ts
function listen(key, callback, overwrite) {
const [on, setOn] = useCallback("on");
const i = on.findIndex((v) => v.key === key);
const ov = typeof overwrite === "string" ? false : overwrite;
if (ov === true && i > -1) {
on[i].callback = callback;
} else {
on.push({
key,
callback
});
}
setOn(on);
}
function emit(key, payload, mode) {
const [on] = useCallback("on");
const triggers = on.filter((v) => v.key === key);
if (Array.isArray(triggers) && triggers.length) {
triggers.forEach((trigger) => trigger.callback(payload));
}
}
var bus_default = {
on: listen,
emit
};
// src/core/api/expire.ts
function expire(key, callback, namespace) {
const spacename = getNamespace(namespace);
const [expire2, setExpire2] = useCallback("expire");
expire2.push({
key,
namespace: spacename,
callback
});
setExpire2(expire2);
}
var expire_default = expire;
// src/core/api/index.ts
function getNamespace(namespace) {
if (namespace) {
return namespace;
}
return "";
}
function runPlugin(payload, wark) {
let value = payload.value;
const buildIn = native.plugins.filter((v) => v.framework === "buildIn");
const users = native.plugins.filter((v) => v.framework === "customer");
const plugins = [...buildIn, ...users];
for (let i = 0; i < plugins.length; i++) {
const plugin = plugins[i];
value = payload.value = plugin.apis[wark](payload);
}
return value;
}
// src/plugin/encrypt.ts
var encrypts = /* @__PURE__ */ new Map([]);
function encryptPlugin(params) {
const { key, wark, value, namespace, encrypt } = params;
if (wark === "setItem" && encrypt) {
let s = "*";
if (namespace) {
const space = encrypts.get(namespace) || [];
space.push([key, value]);
encrypts.set(namespace, space);
} else {
encrypts.set(key, [key, value]);
}
return s.repeat(String(value).length);
}
if (wark === "getItem") {
let space = namespace ? encrypts.get(namespace) : encrypts.get(key);
if (Array.isArray(space)) {
space = Array.isArray(space[0]) ? space[0] : space;
if (space[0] === key) {
return space[1];
}
}
}
if (wark === "removeItem") {
const delKey = namespace || key;
if (encrypts.has(delKey)) {
encrypts.delete(delKey);
}
}
if (wark === "clear") {
if (Array.isArray(value)) {
value.forEach((v) => {
if (encrypts.has(v)) {
encrypts.delete(v);
}
});
} else {
encrypts.clear();
}
}
return value;
}
// src/plugin/watch.ts
function watchPlugin(params) {
const { key, wark, value, namespace, ctx } = params;
if (["setItem", "removeItem", "clear"].includes(wark)) {
const [changes] = useCallback("change");
if (Array.isArray(changes) && changes.length) {
window.WEB_STORAGE_IS_WARNING = false;
const oldValue = ctx.methods.getItem({
key,
namespace
});
changes.forEach((v) => {
if (v.namespace === namespace && v.key === key) {
v.callback({
newValue: wark === "setItem" ? value : void 0,
oldValue,
key,
namespace
});
}
});
window.WEB_STORAGE_IS_WARNING = true;
}
}
return value;
}
// src/plugin/expire.ts
function watchPlugin2(params) {
const { key, value, namespace, ctx } = params;
const [expires] = useCallback("expire");
const [expireTimes, setExpireTimes] = useGlobal("WEB_STORAGE_EXPIRES");
const expired = [];
for (let i = 0; i < expireTimes.length; i++) {
if (Date.now() >= expireTimes[i].expireTime) {
expired.push(cloneDeep(expireTimes[i]));
expireTimes.splice(i, 1);
i--;
}
}
expired.forEach((v) => {
ctx.methods.removeItem({
key: v.key,
namespace: v.namespace
});
});
setExpireTimes(expireTimes);
if (Array.isArray(expires) && expires.length) {
expires.forEach((v) => {
const item = expired.find(
(e) => e.key === v.key && e.namespace === v.namespace
);
if (item) {
v.callback({
key,
namespace
});
}
});
}
worker_default();
return value;
}
// src/core/api/use.ts
function useBuildInPlugin(methods) {
const buildIn = [watchPlugin2, encryptPlugin, watchPlugin];
buildIn.forEach((v) => {
methods.use(v, "buildIn");
});
}
function setApis(api) {
return {
getItem: (p) => api(__spreadProps(__spreadValues({}, p), {
wark: "getItem"
})),
setItem: (p) => api(__spreadProps(__spreadValues({}, p), {
wark: "setItem"
})),
removeItem: (p) => api(__spreadProps(__spreadValues({}, p), {
wark: "removeItem"
})),
clear: (p) => api(__spreadProps(__spreadValues({}, p), {
wark: "clear"
}))
};
}
function use(userCallback, framework) {
native.plugins.push({
framework: framework || "customer",
apis: setApis(userCallback)
});
}
var use_default = use;
// src/core/web-storage.ts
var native;
function web_storage_default(rootName) {
const storage = native_storage_default(rootName);
native = __spreadProps(__spreadValues({}, storage), {
plugins: []
});
useBuildInPlugin({
use: use_default
});
return {
getItem: getItem_default,
setItem: setItem_default,
removeItem: removeItem_default,
clear: clear_default,
onChange: change_default,
onExpire: expire_default,
postMessage: bus_default.emit,
onMessage: bus_default.on,
use: use_default
};
}
// src/index.ts
function proxyLocalStorage() {
Object.defineProperty(window, "localStorage", {
get() {
log("DISABLED_LOC", "warn");
return defaultLocalStorage;
}
});
}
var init = function(config) {
if (init.created || window.WEB_STORAGE_APIS)
return window.WEB_STORAGE_APIS;
const { rootName, noUseLocalStorage = true } = config || {};
const name = rootName || defaultRootName;
this.localStorage = window.localStorage;
noUseLocalStorage && proxyLocalStorage();
setupGlobal(this);
this.created = true;
return window["WEB_STORAGE_APIS"] = web_storage_default(name);
};
function useStorage() {
return window.WEB_STORAGE_APIS;
}
var src_default = init.bind(init);
export {
src_default as default,
useStorage
};