@amitkhare/indexed-storage
Version:
A modern, localStorage-like API for IndexedDB with instance-based and static APIs, multi-store support, configurable databases, and enhanced capabilities
2 lines (1 loc) • 14.3 kB
JavaScript
;Object.defineProperty(exports,"__esModule",{value:!0});class t{constructor(t={}){this.config={dbName:t.dbName||"IndexedStorage",version:t.version||1,storeName:t.storeName||"data",storeConfig:t.storeConfig||{keyPath:null,autoIncrement:!1},additionalStores:t.additionalStores||[],storeConfigs:t.storeConfigs||{},logging:t.logging||!1},this.db=null,this.isInitialized=!1,(t.dbName||t.version||t.storeName)&&this._initializeAsync()}async _initializeAsync(){try{await this.init()}catch(t){this.config.logging&&console.error("IndexedStorage auto-initialization failed:",t)}}async init(){return this.isInitialized&&this.db?this.db:new Promise(((t,e)=>{const o=indexedDB.open(this.config.dbName,this.config.version);o.onerror=()=>{const t=new Error(`Failed to open database: ${this.config.dbName}`);this.config.logging&&console.error("IndexedStorage init error:",t),e(t)},o.onsuccess=e=>{this.db=e.target.result,this.isInitialized=!0,this.config.logging&&console.log(`IndexedStorage initialized: ${this.config.dbName}`),t(this.db)},o.onupgradeneeded=t=>{const e=t.target.result;e.objectStoreNames.contains(this.config.storeName)||(e.createObjectStore(this.config.storeName,this.config.storeConfig),this.config.logging&&console.log(`Created store: ${this.config.storeName}`));for(const t of this.config.additionalStores)if(!e.objectStoreNames.contains(t)){const o=this.config.storeConfigs[t]||{keyPath:null,autoIncrement:!1};e.createObjectStore(t,o),this.config.logging&&console.log(`Created additional store: ${t}`)}}}))}async getItem(t,e=this.config.storeName){return await this.init(),new Promise(((o,r)=>{const n=this.db.transaction([e],"readonly").objectStore(e).get(t);n.onsuccess=()=>{const r=n.result;this.config.logging&&console.log(`Retrieved item: ${t} from ${e}`,r),o(r)},n.onerror=()=>{const e=new Error(`Failed to get item: ${t}`);this.config.logging&&console.error("getItem error:",e),r(e)}}))}async setItem(t,e,o=this.config.storeName){return await this.init(),new Promise(((r,n)=>{const s=this.db.transaction([o],"readwrite").objectStore(o).put(e,t);s.onsuccess=()=>{this.config.logging&&console.log(`Stored item: ${t} in ${o}`,e),r()},s.onerror=()=>{const e=new Error(`Failed to set item: ${t}`);this.config.logging&&console.error("setItem error:",e),n(e)}}))}async removeItem(t,e=this.config.storeName){return await this.init(),new Promise(((o,r)=>{const n=this.db.transaction([e],"readwrite").objectStore(e).delete(t);n.onsuccess=()=>{this.config.logging&&console.log(`Removed item: ${t} from ${e}`),o()},n.onerror=()=>{const e=new Error(`Failed to remove item: ${t}`);this.config.logging&&console.error("removeItem error:",e),r(e)}}))}async clear(t=this.config.storeName){return await this.init(),new Promise(((e,o)=>{const r=this.db.transaction([t],"readwrite").objectStore(t).clear();r.onsuccess=()=>{this.config.logging&&console.log(`Cleared store: ${t}`),e()},r.onerror=()=>{const e=new Error(`Failed to clear store: ${t}`);this.config.logging&&console.error("clear error:",e),o(e)}}))}async getAllKeys(t=this.config.storeName){return await this.init(),new Promise(((e,o)=>{const r=this.db.transaction([t],"readonly").objectStore(t).getAllKeys();r.onsuccess=()=>{const o=r.result;this.config.logging&&console.log(`Retrieved keys from ${t}:`,o),e(o)},r.onerror=()=>{const e=new Error(`Failed to get keys from store: ${t}`);this.config.logging&&console.error("getAllKeys error:",e),o(e)}}))}async getAllValues(t=this.config.storeName){return await this.init(),new Promise(((e,o)=>{const r=this.db.transaction([t],"readonly").objectStore(t).getAll();r.onsuccess=()=>{const o=r.result;this.config.logging&&console.log(`Retrieved values from ${t}:`,o),e(o)},r.onerror=()=>{const e=new Error(`Failed to get values from store: ${t}`);this.config.logging&&console.error("getAllValues error:",e),o(e)}}))}async createStore(t,e={keyPath:null,autoIncrement:!1}){return new Promise(((o,r)=>{this.db&&this.db.close();const n=this.config.version+1,s=indexedDB.open(this.config.dbName,n);s.onerror=()=>{const e=new Error(`Failed to create store: ${t}`);this.config.logging&&console.error("createStore error:",e),r(e)},s.onsuccess=e=>{this.db=e.target.result,this.config.version=n,this.config.logging&&console.log(`Store created: ${t}`),o()},s.onupgradeneeded=o=>{const r=o.target.result;r.objectStoreNames.contains(t)||r.createObjectStore(t,e)}}))}async deleteStore(t){return new Promise(((e,o)=>{this.db&&this.db.close();const r=this.config.version+1,n=indexedDB.open(this.config.dbName,r);n.onerror=()=>{const e=new Error(`Failed to delete store: ${t}`);this.config.logging&&console.error("deleteStore error:",e),o(e)},n.onsuccess=o=>{this.db=o.target.result,this.config.version=r,this.config.logging&&console.log(`Store deleted: ${t}`),e()},n.onupgradeneeded=e=>{const o=e.target.result;o.objectStoreNames.contains(t)&&o.deleteObjectStore(t)}}))}async getStoreInfo(t=this.config.storeName){await this.init();if(!this.db.objectStoreNames.contains(t))throw new Error(`Store '${t}' does not exist`);const e=this.db.transaction([t],"readonly").objectStore(t),o={name:t,keyPath:e.keyPath,autoIncrement:e.autoIncrement,indexNames:Array.from(e.indexNames)};return new Promise(((r,n)=>{const s=e.count();s.onsuccess=()=>{o.count=s.result,r(o)},s.onerror=()=>n(new Error(`Failed to get store info: ${t}`))}))}async listStores(){return await this.init(),Array.from(this.db.objectStoreNames)}close(){this.db&&(this.db.close(),this.db=null,this.isInitialized=!1,this.config.logging&&console.log(`Closed database: ${this.config.dbName}`))}getStore(t){const e=this;return{setItem:(o,r)=>e.setItem(o,r,t),getItem:o=>e.getItem(o,t),removeItem:o=>e.removeItem(o,t),clear:()=>e.clear(t),getAllKeys:()=>e.getAllKeys(t),getAllValues:()=>e.getAllValues(t),getInfo:()=>e.getStoreInfo(t)}}async getAllStoresData(){await this.init();const t=await this.listStores(),e={};for(const o of t)try{const t=await this.getAllValues(o),r=await this.getAllKeys(o);e[o]={};for(let n=0;n<r.length;n++)e[o][r[n]]=t[n]}catch(t){this.config.logging&&console.warn(`Failed to get data from store ${o}:`,t),e[o]=null}return e}async clearAllStores(){await this.init();const t=await this.listStores();for(const e of t)try{await this.clear(e),this.config.logging&&console.log(`Cleared store: ${e}`)}catch(t){this.config.logging&&console.error(`Failed to clear store ${e}:`,t)}}async getAvailableStores(){return this.listStores()}async setMultipleStores(t){await this.init();for(const[e,o]of Object.entries(t))for(const[t,r]of Object.entries(o))await this.setItem(t,r,e)}async getMultipleStores(t){await this.init();const e={};for(const[o,r]of Object.entries(t)){e[o]={};for(const t of r)e[o][t]=await this.getItem(t,o)}return e}static _defaultInstance=null;static _getDefaultInstance(){return t._defaultInstance||(t._defaultInstance=new t({dbName:"IndexedStorage",version:1,storeName:"data",logging:!1})),t._defaultInstance}static async getItem(e,o){return t._getDefaultInstance().getItem(e,o)}static async setItem(e,o,r){return t._getDefaultInstance().setItem(e,o,r)}static async removeItem(e,o){return t._getDefaultInstance().removeItem(e,o)}static async clear(e){return t._getDefaultInstance().clear(e)}static async getAllKeys(e){return t._getDefaultInstance().getAllKeys(e)}static async getAllValues(e){return t._getDefaultInstance().getAllValues(e)}static async createStore(e,o){return t._getDefaultInstance().createStore(e,o)}static async deleteStore(e){return t._getDefaultInstance().deleteStore(e)}static async getStoreInfo(e){return t._getDefaultInstance().getStoreInfo(e)}static async listStores(){return t._getDefaultInstance().listStores()}static async init(){return t._getDefaultInstance().init()}static close(){t._defaultInstance&&(t._defaultInstance.close(),t._defaultInstance=null)}static getStore(e){return t._getDefaultInstance().getStore(e)}static async getAllStoresData(){return t._getDefaultInstance().getAllStoresData()}static async clearAllStores(){return t._getDefaultInstance().clearAllStores()}static async getAvailableStores(){return t._getDefaultInstance().getAvailableStores()}static async setMultipleStores(e){return t._getDefaultInstance().setMultipleStores(e)}static async getMultipleStores(e){return t._getDefaultInstance().getMultipleStores(e)}}function e(t={}){const e=t.dbName||"LocalStorageDB",o=t.dbVersion||1,r=t.storeName||"localStates",n=t.additionalStores||[],s=[r,...n];function a(){return new Promise(((t,r)=>{const n=indexedDB.open(e,o);n.onerror=()=>{n.error,r(n.error)},n.onsuccess=()=>{t(n.result)},n.onupgradeneeded=t=>{const e=t.target.result;s.forEach((t=>{if(!e.objectStoreNames.contains(t)){const o=e.createObjectStore(t,{keyPath:"id"});o.createIndex("timestamp","timestamp",{unique:!1}),o.createIndex("version","version",{unique:!1})}}))}}))}async function i(t,e=r){try{const o=(await a()).transaction([e],"readonly"),r=o.objectStore(e).get(t);return new Promise(((t,e)=>{r.onsuccess=()=>{const e=r.result;t(e||null)},r.onerror=()=>e(r.error)}))}catch(t){return null}}async function c(t,e,o=r){try{const r=await a(),n=r.transaction([o],"readwrite").objectStore(o),s={id:t,...e,timestamp:e.timestamp||(new Date).toISOString(),version:e.version||"1.0"},i=n.put(s);return new Promise(((t,e)=>{i.onsuccess=()=>t(),i.onerror=()=>e(i.error)}))}catch(t){throw t}}async function l(t,e=r){try{const o=(await a()).transaction([e],"readwrite"),r=o.objectStore(e).delete(t);return new Promise(((t,e)=>{r.onsuccess=()=>t(),r.onerror=()=>e(r.error)}))}catch(t){throw t}}async function g(t=r){try{const e=(await a()).transaction([t],"readonly"),o=e.objectStore(t).getAll();return new Promise(((t,e)=>{o.onsuccess=()=>t(o.result||[]),o.onerror=()=>e(o.error)}))}catch(t){return[]}}async function u(t,e=r){try{return null!==await i(t,e)}catch(t){return!1}}async function d(t=r){try{const e=(await a()).transaction([t],"readwrite"),o=e.objectStore(t).clear();return new Promise(((t,e)=>{o.onsuccess=()=>{t()},o.onerror=()=>e(o.error)}))}catch(t){throw t}}async function m(t=r){try{const e=await g(t);let o=0;const r={};return e.forEach((t=>{const e=new Blob([JSON.stringify(t)]).size;o+=e,r[t.id]=e})),{totalSize:o,items:r}}catch(t){return{totalSize:0,items:{}}}}return{get:i,save:c,remove:l,getAll:g,exists:u,clear:d,openDB:a,calculateUsage:m,testAvailability:async function(){try{const t="indexeddb-test",e={test:!0,timestamp:(new Date).toISOString()};await c(t,e);const o=await i(t);return await l(t),null!==o&&!0===o.test}catch(t){return!1}},getAvailableStores:function(){return s},createStoreAPI:function(t){if(!s.includes(t))throw new Error(`Store '${t}' is not configured. Available stores: ${s.join(", ")}`);return{get:e=>i(e,t),save:(e,o)=>c(e,o,t),remove:e=>l(e,t),getAll:()=>g(t),exists:e=>u(e,t),clear:()=>d(t),calculateUsage:()=>m(t),storeName:t}},clearAllStores:async function(){try{for(const t of s)await d(t)}catch(t){throw t}},getAllStoresData:async function(){try{const t={};for(const e of s)t[e]=await g(e);return t}catch(t){return{}}},dbName:e,dbVersion:o,primaryStore:r,allStores:s}}"undefined"!=typeof module&&module.exports?module.exports=t:"undefined"!=typeof window&&(window.IndexedStorage=t),exports.IndexedStorage=t,exports.default=t,exports.useIndexedDB=e,exports.useStorageManager=function(t={}){const o=e(t);let r=null,n=null;const s={async getItem(t){const e=await o.get(t);return e||null},async setItem(t,e){const r={timestamp:(new Date).toISOString(),version:"1.0",...e};await o.save(t,r)},async removeItem(t){await o.remove(t)},hasItem:async t=>await o.exists(t),async clear(){await o.clear()},getAllKeys:async()=>(await o.getAll()).map((t=>t.id)),testAvailability:async()=>await o.testAvailability()};function a(t){if(0===t||null==t)return"0 Bytes";if(t<0)return"0 Bytes";const e=["Bytes","KB","MB","GB","TB"],o=Math.floor(Math.log(t)/Math.log(1024)),r=Math.min(o,e.length-1);return parseFloat((t/Math.pow(1024,r)).toFixed(2))+" "+e[r]}async function i(){return r||(n||(n=(async()=>{let t=null,e=null,o=!1;if("storage"in navigator&&"estimate"in navigator.storage)try{const r=await navigator.storage.estimate();t=r.quota,e=r.usage,o=!0,a(r.quota),a(r.usage)}catch(e){t=52428800,o=!1}else t=52428800,o=!1;a(t);const s={quota:t,usage:e,exactQuotaAvailable:o};return r=s,setTimeout((()=>{r=null,n=null}),3e5),s})(),n))}async function c(){return await o.calculateUsage()}async function l(t=null){try{const{totalSize:e,items:o}=await c();let r=0;t&&o[t]&&(r=o[t]);const{quota:n,usage:s,exactQuotaAvailable:l}=await i(),g=Math.round(e/n*100);return{totalSize:e,specificItemSize:r,quota:n,usage:l?s:e,exactQuotaAvailable:l,usagePercentage:g,apiUsagePercentage:l&&null!==s?Math.round(s/n*100):null,formattedTotalSize:a(e),formattedSpecificSize:a(r),formattedQuota:a(n),formattedUsage:a(l?s:e),items:Object.keys(o).map((t=>({key:t,size:o[t],formattedSize:a(o[t])})))}}catch(t){return null}}return{storage:s,getStorageEstimate:i,getStorageUsage:l,getStorageWarningLevel:async function(){const t=await l();if(!t)return"normal";const{usagePercentage:e,exactQuotaAvailable:o,apiUsagePercentage:r}=t,n=o&&null!==r?r:e;return n>=95?"critical":n>=80?"warning":"normal"},calculateUsage:c,formatBytes:a,testStorageAvailability:async function(){try{const t="storage-availability-test",e={test:!0,timestamp:(new Date).toISOString()};return await s.setItem(t,e),await s.removeItem(t),!0}catch(t){return!1}},migrateFromLocalStorage:async function(t){try{const e=localStorage.getItem(t);if(!e)return!1;if(await s.getItem(t))return!1;const o=JSON.parse(e);return await s.setItem(t,o),localStorage.removeItem(t),!0}catch(t){return!1}},createStoreManager:function(t){const e=o.createStoreAPI(t);return{storage:{async getItem(t){const o=await e.get(t);return o||null},async setItem(t,o){const r={timestamp:(new Date).toISOString(),version:"1.0",...o};await e.save(t,r)},async removeItem(t){await e.remove(t)},hasItem:async t=>await e.exists(t),async clear(){await e.clear()},getAllKeys:async()=>(await e.getAll()).map((t=>t.id)),testAvailability:async()=>await o.testAvailability()},storeName:t}},getAllStoresData:async function(){return await o.getAllStoresData()},clearAllStores:async function(){await o.clearAllStores()},getAvailableStores:function(){return o.getAvailableStores()},dbName:o.dbName,dbVersion:o.dbVersion,primaryStore:o.primaryStore,allStores:o.allStores}};