import { STORAGE_VERSION } from "../config"; export type StoreValue = { value: undefined | object; v?: string; exp?: number; }; export type Store = StoreValue & { key?: string; toJSON: () => StoreValue; write: (value: undefined | object, exp: number) => void; read: () => Store; or: (callBack: () => Object | Promise, exp: number) => Promise; assign: (obj: Store) => Store; }; function isPromise(p: any) { return typeof p === "object" && typeof p.then === "function"; } // default storage limit is set to 3 minutes const DEFAULT_EXP_TIME = 1000 * 60 * 3; const storeValue: Store = { value: undefined, toJSON: function (): StoreValue { return { value: this.value, v: this.v, ...(!!this.exp ? { exp: this.exp } : {}), }; }, // @ts-ignore write: function (value, exp) { if (!this.key) return undefined; this.value = value; this.v = STORAGE_VERSION; if (!exp || (isFinite(exp) && exp >= 0)) this.exp = Date.now() + (exp || DEFAULT_EXP_TIME); localStorage.setItem(this.key, JSON.stringify(this)); }, read: function () { if (!this.key) { return this; } const strData = localStorage.getItem(this.key); try { if (!!strData) { const data = JSON.parse(strData); if ( !data.v || data.v !== STORAGE_VERSION || (!!data.exp && data.exp < Date.now()) ) return this; return this.assign(data); } } catch (e) { // eslint-disable-next-line no-console console.error(`STORAGE: parsing ${this.key} error!!`); } return this; }, or: async function (callBack, exp) { if (!!this.value && (!this.exp || Date.now() < this.exp)) { return this; } if (!!callBack && !!callBack.constructor) { const callBackResult = callBack(); const data = callBack.constructor.name === "AsyncFunction" || isPromise(callBackResult) ? await callBackResult : callBackResult; if (!!data && !!this.key) { this.write(data, exp); } } return this; }, assign: function (obj) { for (const key in obj) { // @ts-ignore this[key] = obj[key]; } return this; }, }; const storage = { createStore: function (key: string) { const store = Object.create(storeValue); store.key = key; return store; }, get: function (key: string) { return storage.createStore(key).read(); }, set: function (key: string, value: object, exp: number) { return storage.createStore(key).write(value, exp); }, remove: function (key: string) { localStorage.removeItem(key); }, }; export default storage;