@dariushstony/smart-storage 0.1.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';var m=class{constructor(e,t){this.transforms=e;this.logger=t;}apply(e){return this.transforms.reduce((t,r)=>{var a;try{return r.serialize(t)}catch(i){throw (a=this.logger)==null||a.log("Transform serialize failed",i),new Error(`Transform pipeline failed: ${i instanceof Error?i.message:String(i)}`)}},e)}reverse(e){return this.transforms.reduceRight((t,r)=>{var a;try{return r.deserialize(t)}catch(i){throw (a=this.logger)==null||a.log("Transform deserialize failed",i),new Error(`Transform pipeline reversal failed: ${i instanceof Error?i.message:String(i)}`)}},e)}hasTransforms(){return this.transforms.length>0}};var f="APP_DATA";var E=["__proto__","constructor","prototype"];var S="local";function d(n,e){if(!e)throw new Error("Storage is not available (unavailable environment).");if(!n||n.trim()==="")throw new Error("Storage key cannot be empty or whitespace.");if(E.includes(n))throw new Error(`Storage key "${n}" is not allowed as it may cause prototype pollution.`)}function w(n){return n===null?false:Date.now()>n}function y(n){return new Blob([n]).size}function x(n){return n instanceof DOMException&&(n.name==="QuotaExceededError"||n.name==="NS_ERROR_DOM_QUOTA_REACHED")}function A(n){return n instanceof TypeError&&n.message.includes("circular")}function T(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function v(){return typeof window!="undefined"}var b=class{constructor(e,t){this.storageType=e;this.logger=t;this.storage=null;this.unloadHandler=null;this.initialize();}initialize(){var e;if(this.storageType==="in-memory"){this.storage=new Map;return}if(v())try{this.storage=this.storageType==="session"?sessionStorage:localStorage;}catch(t){(e=this.logger)==null||e.log("Web storage is not accessible. Falling back to in-memory storage.",t),this.storage=new Map;}else this.storage=new Map;}getStorage(){return this.storage}read(e){var t;return this.storage?this.storage instanceof Map?(t=this.storage.get(e))!=null?t:null:this.storage.getItem(e):null}write(e,t){this.storage&&(this.storage instanceof Map?this.storage.set(e,t):this.storage.setItem(e,t));}remove(e){this.storage&&(this.storage instanceof Map?this.storage.delete(e):this.storage.removeItem(e));}isAvailable(){return this.storage!==null}getStorageType(){return this.storage?this.storage instanceof Map?"memory":this.storage===localStorage?"localStorage":this.storage===sessionStorage?"sessionStorage":"unavailable":"unavailable"}registerUnloadHandler(e){v()&&!this.unloadHandler&&(this.unloadHandler=e,window.addEventListener("beforeunload",this.unloadHandler));}cleanup(){v()&&this.unloadHandler&&(window.removeEventListener("beforeunload",this.unloadHandler),this.unloadHandler=null);}};var l=class l{constructor(e={}){this.isCleaningUp=false;this.pendingSave=null;this.dirtyData=null;let{storageType:t=S,storageKey:r=f,logger:a,maxSizeBytes:i=4e6,maxItemsInMemory:s=1e3,debounceMs:o=100,transforms:c=[]}=e;this.logger=a,this.storageKey=r,this.maxSizeBytes=i,this.maxItemsInMemory=s,this.debounceMs=o,this.backend=new b(t,a),this.transformPipeline=new m(c,a),this.backend.registerUnloadHandler(()=>{this.dirtyData&&(this.saveAllDataImmediate(this.dirtyData),this.dirtyData=null);});}static getInstance(e={}){let{storageType:t=S,storageKey:r=f,logger:a,maxSizeBytes:i=4e6,maxItemsInMemory:s=1e3,debounceMs:o=100,transforms:c=[]}=e,g=`${t}-${r}`;l.instances.has(g)||l.instances.set(g,new l({storageType:t,storageKey:r,logger:a,maxSizeBytes:i,maxItemsInMemory:s,debounceMs:o,transforms:c}));let u=l.instances.get(g);if(!u)throw a==null||a.log("Failed to create or retrieve StorageVault instance",{key:g}),new Error(`Failed to create or retrieve StorageVault instance: ${g}`);return u}static disposeInstance(e={}){let{storageType:t=S,storageKey:r=f}=e,a=`${t}-${r}`,i=l.instances.get(a);return i&&(i.flush(),i.cleanup()),l.instances.delete(a)}static clearAllInstances(){l.instances.forEach(e=>{e.flush(),e.cleanup();}),l.instances.clear();}getAllData(){var t,r,a;if(!this.backend.getStorage())return {};if(this.dirtyData!==null)return Object.freeze((t=this.dirtyData)!=null?t:{});try{let i=this.backend.read(this.storageKey);if(!i)return {};let s=this.transformPipeline.reverse(i),o=JSON.parse(s);if(!T(o))throw new Error("Invalid storage data structure");return o}catch(i){(r=this.logger)==null||r.log("Storage data corrupted or invalid, clearing storage",{error:i,storageKey:this.storageKey});try{this.backend.remove(this.storageKey);}catch(s){(a=this.logger)==null||a.log("Failed to clear corrupted storage",s);}return {}}}saveAllDataImmediate(e){var r,a;let t=this.backend.getStorage();if(t){if(t instanceof Map){let i=Object.keys(e).length;i>this.maxItemsInMemory&&((r=this.logger)==null||r.log("In-memory storage item limit exceeded, cleaning up oldest items",{itemCount:i,maxItems:this.maxItemsInMemory}),this.enforceItemLimit(e));}try{let i=JSON.stringify(e),s=this.transformPipeline.apply(i),o=y(s);o>this.maxSizeBytes&&((a=this.logger)==null||a.log("Storage approaching quota limit",{byteSize:o,stringLength:s.length,maxSizeBytes:this.maxSizeBytes})),this.backend.write(this.storageKey,s);}catch(i){this.handleSaveError(i);}}}handleSaveError(e){var t,r,a,i,s,o;if(x(e)){if(this.isCleaningUp)throw (i=this.logger)==null||i.log("Already cleaning up, skipping recursive cleanup",e),new Error("Storage quota exceeded during cleanup");(t=this.logger)==null||t.log("Storage quota exceeded, attempting cleanup",e),this.isCleaningUp=true;try{let c=this.cleanupExpiredItems();(r=this.logger)==null||r.log(`Cleanup removed ${c} expired items`);let g=this.getAllData(),u=JSON.stringify(g),p=this.transformPipeline.apply(u);this.backend.write(this.storageKey,p);}catch(c){throw (a=this.logger)==null||a.log("Storage quota exceeded even after cleanup",c),new Error("Storage quota exceeded. Clear some data or use storage slices to reduce size.")}finally{this.isCleaningUp=false;}}else throw A(e)?((s=this.logger)==null||s.log("Circular reference detected in stored data",e),new Error("Cannot store data with circular references. Serialize manually before storing.")):((o=this.logger)==null||o.log("Error saving to storage",e),new Error(`Failed to save to storage: ${e instanceof Error?e.message:String(e)}`))}saveAllData(e){this.debounceMs>0?(this.dirtyData=e,this.pendingSave&&clearTimeout(this.pendingSave),this.pendingSave=setTimeout(()=>{var t;if(this.dirtyData)try{this.saveAllDataImmediate(this.dirtyData),this.dirtyData=null;}catch(r){(t=this.logger)==null||t.log("Debounced save failed",r);}this.pendingSave=null;},this.debounceMs)):this.saveAllDataImmediate(e);}removeIfExpired(e,t,r){return t?w(t.expiry)?(delete r[e],true):false:true}enforceItemLimit(e){let t=Object.keys(e);if(t.length<=this.maxItemsInMemory)return;let r=t.sort((i,s)=>{var g,u,p,D;let o=(u=(g=e[i])==null?void 0:g.expiry)!=null?u:1/0,c=(D=(p=e[s])==null?void 0:p.expiry)!=null?D:1/0;return o-c}),a=t.length-this.maxItemsInMemory;for(let i=0;i<a;i++){let s=r[i];s!==void 0&&delete e[s];}}cleanup(){this.pendingSave&&(clearTimeout(this.pendingSave),this.pendingSave=null),this.backend.cleanup();}setItem(e,t,r){if(d(e,this.backend.getStorage()),r!==void 0&&(!Number.isFinite(r)||r<0))throw new Error("TTL must be a non-negative finite number.");if(r===0)return this.removeItem(e);let a=this.getAllData(),i=r!==void 0?Date.now()+r:null;return a[e]={value:t,expiry:i},this.saveAllData(a),true}getItem(e){d(e,this.backend.getStorage());let t=this.getAllData(),r=t[e];return r?this.removeIfExpired(e,r,t)?(this.saveAllData(t),null):r.value:null}updateItem(e,t){d(e,this.backend.getStorage());let r=this.getAllData(),a=r[e];return a?this.removeIfExpired(e,a,r)?(this.saveAllData(r),false):(a.value=t,this.saveAllData(r),true):false}extendTTL(e,t){if(d(e,this.backend.getStorage()),!Number.isFinite(t)||t<=0)throw new Error("additionalTTL must be a positive finite number.");let r=this.getAllData(),a=r[e];return a?this.removeIfExpired(e,a,r)?(this.saveAllData(r),false):(a.expiry=a.expiry!==null?a.expiry+t:Date.now()+t,this.saveAllData(r),true):false}removeItem(e){d(e,this.backend.getStorage());let t=this.getAllData();return e in t?(delete t[e],this.saveAllData(t),true):false}clear(){var e;if(!this.backend.isAvailable())throw new Error("Storage is not available (unavailable environment).");this.pendingSave&&(clearTimeout(this.pendingSave),this.pendingSave=null),this.dirtyData=null;try{return this.backend.remove(this.storageKey),!0}catch(t){throw (e=this.logger)==null||e.log("Error clearing storage",{error:t,storageKey:this.storageKey}),new Error(`Failed to clear storage: ${t instanceof Error?t.message:String(t)}`)}}hasItem(e){d(e,this.backend.getStorage());let t=this.getAllData(),r=t[e];return r?this.removeIfExpired(e,r,t)?(this.saveAllData(t),false):true:false}getRemainingTTL(e){if(!this.backend.isAvailable())return null;let t=this.getAllData(),r=t[e];if(!r||r.expiry===null)return null;let a=r.expiry-Date.now();return a<=0?(delete t[e],this.saveAllData(t),null):a}cleanupExpiredItems(){if(!this.backend.isAvailable())return 0;let e=this.getAllData(),t=0,r=Date.now();for(let a in e)if(Object.prototype.hasOwnProperty.call(e,a)){let i=e[a];i&&i.expiry!==null&&r>i.expiry&&(delete e[a],t++);}return t>0&&this.saveAllDataImmediate(e),t}flush(){this.pendingSave&&(clearTimeout(this.pendingSave),this.pendingSave=null),this.dirtyData&&(this.saveAllDataImmediate(this.dirtyData),this.dirtyData=null);}getAllKeys(){if(!this.backend.isAvailable())return [];let e=this.getAllData(),t=[],r=Date.now();for(let a in e)if(Object.prototype.hasOwnProperty.call(e,a)){let i=e[a];i&&(i.expiry===null||r<=i.expiry)&&t.push(a);}return t}getAll(){if(!this.backend.isAvailable())return {};let e=this.getAllData(),t={},r=Date.now();for(let a in e)if(Object.prototype.hasOwnProperty.call(e,a)){let i=e[a];i&&(i.expiry===null||r<=i.expiry)&&(t[a]=i.value);}return t}getCurrentSize(){var e;if(!this.backend.isAvailable())return 0;try{let t=this.getAllData(),r=JSON.stringify(t);return y(r)}catch(t){return (e=this.logger)==null||e.log("Error calculating storage size",t),0}}getStats(){if(!this.backend.isAvailable())return {itemCount:0,sizeBytes:0,stringLength:0,maxSizeBytes:this.maxSizeBytes,quotaPercentage:0,storageType:"unavailable"};let e=this.getAllData(),t=Object.keys(e).length,r=JSON.stringify(e),a=y(r),i=a/this.maxSizeBytes*100;return {itemCount:t,sizeBytes:a,stringLength:r.length,maxSizeBytes:this.maxSizeBytes,quotaPercentage:i,storageType:this.backend.getStorageType()}}};l.instances=new Map;var h=l;function V(n,e={}){return h.getInstance({...e,storageKey:n})}function $(n,e={}){return h.disposeInstance({...e,storageKey:n})}exports.StorageVault=h;exports.disposeStorageSlice=$;exports.getStorageSlice=V;//# sourceMappingURL=index.cjs.map
1
+ 'use strict';var m=class{constructor(e,t){this.transforms=e;this.logger=t;}apply(e){return this.transforms.reduce((t,r)=>{var a;try{return r.serialize(t)}catch(i){throw (a=this.logger)==null||a.log("Transform serialize failed",i),new Error(`Transform pipeline failed: ${i instanceof Error?i.message:String(i)}`)}},e)}reverse(e){return this.transforms.reduceRight((t,r)=>{var a;try{return r.deserialize(t)}catch(i){throw (a=this.logger)==null||a.log("Transform deserialize failed",i),new Error(`Transform pipeline reversal failed: ${i instanceof Error?i.message:String(i)}`)}},e)}hasTransforms(){return this.transforms.length>0}};var f="APP_DATA";var E=["__proto__","constructor","prototype"];var S="local";function d(n,e){if(!e)throw new Error("Storage is not available (unavailable environment).");if(!n||n.trim()==="")throw new Error("Storage key cannot be empty or whitespace.");if(E.includes(n))throw new Error(`Storage key "${n}" is not allowed as it may cause prototype pollution.`)}function w(n){return n===null?false:Date.now()>n}function y(n){return new Blob([n]).size}function x(n){return n instanceof DOMException&&(n.name==="QuotaExceededError"||n.name==="NS_ERROR_DOM_QUOTA_REACHED")}function A(n){return n instanceof TypeError&&n.message.includes("circular")}function T(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function v(){return typeof window!="undefined"}var b=class{constructor(e,t){this.storageType=e;this.logger=t;this.storage=null;this.unloadHandler=null;this.initialize();}initialize(){var e;if(this.storageType==="in-memory"){this.storage=new Map;return}if(v())try{this.storage=this.storageType==="session"?sessionStorage:localStorage;}catch(t){(e=this.logger)==null||e.log("Web storage is not accessible. Falling back to in-memory storage.",t),this.storage=new Map;}else this.storage=new Map;}getStorage(){return this.storage}read(e){var t;return this.storage?this.storage instanceof Map?(t=this.storage.get(e))!=null?t:null:this.storage.getItem(e):null}write(e,t){this.storage&&(this.storage instanceof Map?this.storage.set(e,t):this.storage.setItem(e,t));}remove(e){this.storage&&(this.storage instanceof Map?this.storage.delete(e):this.storage.removeItem(e));}isAvailable(){return this.storage!==null}getStorageType(){return this.storage?this.storage instanceof Map?"memory":this.storage===localStorage?"localStorage":this.storage===sessionStorage?"sessionStorage":"unavailable":"unavailable"}registerUnloadHandler(e){v()&&!this.unloadHandler&&(this.unloadHandler=e,window.addEventListener("pagehide",this.unloadHandler));}cleanup(){v()&&this.unloadHandler&&(window.removeEventListener("pagehide",this.unloadHandler),this.unloadHandler=null);}};var l=class l{constructor(e={}){this.isCleaningUp=false;this.pendingSave=null;this.dirtyData=null;let{storageType:t=S,storageKey:r=f,logger:a,maxSizeBytes:i=4e6,maxItemsInMemory:s=1e3,debounceMs:o=100,transforms:c=[]}=e;this.logger=a,this.storageKey=r,this.maxSizeBytes=i,this.maxItemsInMemory=s,this.debounceMs=o,this.backend=new b(t,a),this.transformPipeline=new m(c,a),this.backend.registerUnloadHandler(()=>{this.dirtyData&&(this.saveAllDataImmediate(this.dirtyData),this.dirtyData=null);});}static getInstance(e={}){let{storageType:t=S,storageKey:r=f,logger:a,maxSizeBytes:i=4e6,maxItemsInMemory:s=1e3,debounceMs:o=100,transforms:c=[]}=e,g=`${t}-${r}`;l.instances.has(g)||l.instances.set(g,new l({storageType:t,storageKey:r,logger:a,maxSizeBytes:i,maxItemsInMemory:s,debounceMs:o,transforms:c}));let u=l.instances.get(g);if(!u)throw a==null||a.log("Failed to create or retrieve StorageVault instance",{key:g}),new Error(`Failed to create or retrieve StorageVault instance: ${g}`);return u}static disposeInstance(e={}){let{storageType:t=S,storageKey:r=f}=e,a=`${t}-${r}`,i=l.instances.get(a);return i&&(i.flush(),i.cleanup()),l.instances.delete(a)}static clearAllInstances(){l.instances.forEach(e=>{e.flush(),e.cleanup();}),l.instances.clear();}getAllData(){var t,r,a;if(!this.backend.getStorage())return {};if(this.dirtyData!==null)return Object.freeze((t=this.dirtyData)!=null?t:{});try{let i=this.backend.read(this.storageKey);if(!i)return {};let s=this.transformPipeline.reverse(i),o=JSON.parse(s);if(!T(o))throw new Error("Invalid storage data structure");return o}catch(i){(r=this.logger)==null||r.log("Storage data corrupted or invalid, clearing storage",{error:i,storageKey:this.storageKey});try{this.backend.remove(this.storageKey);}catch(s){(a=this.logger)==null||a.log("Failed to clear corrupted storage",s);}return {}}}saveAllDataImmediate(e){var r,a;let t=this.backend.getStorage();if(t){if(t instanceof Map){let i=Object.keys(e).length;i>this.maxItemsInMemory&&((r=this.logger)==null||r.log("In-memory storage item limit exceeded, cleaning up oldest items",{itemCount:i,maxItems:this.maxItemsInMemory}),this.enforceItemLimit(e));}try{let i=JSON.stringify(e),s=this.transformPipeline.apply(i),o=y(s);o>this.maxSizeBytes&&((a=this.logger)==null||a.log("Storage approaching quota limit",{byteSize:o,stringLength:s.length,maxSizeBytes:this.maxSizeBytes})),this.backend.write(this.storageKey,s);}catch(i){this.handleSaveError(i);}}}handleSaveError(e){var t,r,a,i,s,o;if(x(e)){if(this.isCleaningUp)throw (i=this.logger)==null||i.log("Already cleaning up, skipping recursive cleanup",e),new Error("Storage quota exceeded during cleanup");(t=this.logger)==null||t.log("Storage quota exceeded, attempting cleanup",e),this.isCleaningUp=true;try{let c=this.cleanupExpiredItems();(r=this.logger)==null||r.log(`Cleanup removed ${c} expired items`);let g=this.getAllData(),u=JSON.stringify(g),p=this.transformPipeline.apply(u);this.backend.write(this.storageKey,p);}catch(c){throw (a=this.logger)==null||a.log("Storage quota exceeded even after cleanup",c),new Error("Storage quota exceeded. Clear some data or use storage slices to reduce size.")}finally{this.isCleaningUp=false;}}else throw A(e)?((s=this.logger)==null||s.log("Circular reference detected in stored data",e),new Error("Cannot store data with circular references. Serialize manually before storing.")):((o=this.logger)==null||o.log("Error saving to storage",e),new Error(`Failed to save to storage: ${e instanceof Error?e.message:String(e)}`))}saveAllData(e){this.debounceMs>0?(this.dirtyData=e,this.pendingSave&&clearTimeout(this.pendingSave),this.pendingSave=setTimeout(()=>{var t;if(this.dirtyData)try{this.saveAllDataImmediate(this.dirtyData),this.dirtyData=null;}catch(r){(t=this.logger)==null||t.log("Debounced save failed",r);}this.pendingSave=null;},this.debounceMs)):this.saveAllDataImmediate(e);}removeIfExpired(e,t,r){return t?w(t.expiry)?(delete r[e],true):false:true}enforceItemLimit(e){let t=Object.keys(e);if(t.length<=this.maxItemsInMemory)return;let r=t.sort((i,s)=>{var g,u,p,D;let o=(u=(g=e[i])==null?void 0:g.expiry)!=null?u:1/0,c=(D=(p=e[s])==null?void 0:p.expiry)!=null?D:1/0;return o-c}),a=t.length-this.maxItemsInMemory;for(let i=0;i<a;i++){let s=r[i];s!==void 0&&delete e[s];}}cleanup(){this.pendingSave&&(clearTimeout(this.pendingSave),this.pendingSave=null),this.backend.cleanup();}setItem(e,t,r){if(d(e,this.backend.getStorage()),r!==void 0&&(!Number.isFinite(r)||r<0))throw new Error("TTL must be a non-negative finite number.");if(r===0)return this.removeItem(e);let a=this.getAllData(),i=r!==void 0?Date.now()+r:null;return a[e]={value:t,expiry:i},this.saveAllData(a),true}getItem(e){d(e,this.backend.getStorage());let t=this.getAllData(),r=t[e];return r?this.removeIfExpired(e,r,t)?(this.saveAllData(t),null):r.value:null}updateItem(e,t){d(e,this.backend.getStorage());let r=this.getAllData(),a=r[e];return a?this.removeIfExpired(e,a,r)?(this.saveAllData(r),false):(a.value=t,this.saveAllData(r),true):false}extendTTL(e,t){if(d(e,this.backend.getStorage()),!Number.isFinite(t)||t<=0)throw new Error("additionalTTL must be a positive finite number.");let r=this.getAllData(),a=r[e];return a?this.removeIfExpired(e,a,r)?(this.saveAllData(r),false):(a.expiry=a.expiry!==null?a.expiry+t:Date.now()+t,this.saveAllData(r),true):false}removeItem(e){d(e,this.backend.getStorage());let t=this.getAllData();return e in t?(delete t[e],this.saveAllData(t),true):false}clear(){var e;if(!this.backend.isAvailable())throw new Error("Storage is not available (unavailable environment).");this.pendingSave&&(clearTimeout(this.pendingSave),this.pendingSave=null),this.dirtyData=null;try{return this.backend.remove(this.storageKey),!0}catch(t){throw (e=this.logger)==null||e.log("Error clearing storage",{error:t,storageKey:this.storageKey}),new Error(`Failed to clear storage: ${t instanceof Error?t.message:String(t)}`)}}hasItem(e){d(e,this.backend.getStorage());let t=this.getAllData(),r=t[e];return r?this.removeIfExpired(e,r,t)?(this.saveAllData(t),false):true:false}getRemainingTTL(e){if(!this.backend.isAvailable())return null;let t=this.getAllData(),r=t[e];if(!r||r.expiry===null)return null;let a=r.expiry-Date.now();return a<=0?(delete t[e],this.saveAllData(t),null):a}cleanupExpiredItems(){if(!this.backend.isAvailable())return 0;let e=this.getAllData(),t=0,r=Date.now();for(let a in e)if(Object.prototype.hasOwnProperty.call(e,a)){let i=e[a];i&&i.expiry!==null&&r>i.expiry&&(delete e[a],t++);}return t>0&&this.saveAllDataImmediate(e),t}flush(){this.pendingSave&&(clearTimeout(this.pendingSave),this.pendingSave=null),this.dirtyData&&(this.saveAllDataImmediate(this.dirtyData),this.dirtyData=null);}getAllKeys(){if(!this.backend.isAvailable())return [];let e=this.getAllData(),t=[],r=Date.now();for(let a in e)if(Object.prototype.hasOwnProperty.call(e,a)){let i=e[a];i&&(i.expiry===null||r<=i.expiry)&&t.push(a);}return t}getAll(){if(!this.backend.isAvailable())return {};let e=this.getAllData(),t={},r=Date.now();for(let a in e)if(Object.prototype.hasOwnProperty.call(e,a)){let i=e[a];i&&(i.expiry===null||r<=i.expiry)&&(t[a]=i.value);}return t}getCurrentSize(){var e;if(!this.backend.isAvailable())return 0;try{let t=this.getAllData(),r=JSON.stringify(t);return y(r)}catch(t){return (e=this.logger)==null||e.log("Error calculating storage size",t),0}}getStats(){if(!this.backend.isAvailable())return {itemCount:0,sizeBytes:0,stringLength:0,maxSizeBytes:this.maxSizeBytes,quotaPercentage:0,storageType:"unavailable"};let e=this.getAllData(),t=Object.keys(e).length,r=JSON.stringify(e),a=y(r),i=a/this.maxSizeBytes*100;return {itemCount:t,sizeBytes:a,stringLength:r.length,maxSizeBytes:this.maxSizeBytes,quotaPercentage:i,storageType:this.backend.getStorageType()}}};l.instances=new Map;var h=l;function V(n,e={}){return h.getInstance({...e,storageKey:n})}function $(n,e={}){return h.disposeInstance({...e,storageKey:n})}exports.StorageVault=h;exports.disposeStorageSlice=$;exports.getStorageSlice=V;//# sourceMappingURL=index.cjs.map
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/transforms/pipeline.ts","../src/utils/constants.ts","../src/utils/helpers.ts","../src/core/storage-backend.ts","../src/core/vault.ts","../src/index.ts"],"names":["TransformPipeline","transforms","logger","data","current","transform","_a","e","DEFAULT_STORAGE_KEY","DANGEROUS_KEYS","DEFAULT_STORAGE_TYPE","validateKey","key","storage","isExpired","expiry","getByteSize","str","isQuotaExceededError","error","isCircularReferenceError","isValidDataRecord","parsed","isWindowAvailable","StorageBackend","storageType","value","handler","_StorageVault","options","storageKey","maxSizeBytes","maxItemsInMemory","debounceMs","instance","_b","_c","dataStr","deserializedStr","clearError","itemCount","transformedStr","byteSize","_d","_e","_f","removedCount","freshData","retryError","item","keys","sortedKeys","a","b","expiryA","expiryB","itemsToRemove","keyToDelete","ttl","newValue","additionalTTL","remainingTime","now","validKeys","result","sizeBytes","quotaPercentage","StorageVault","getStorageSlice","sliceKey","disposeStorageSlice"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { StorageLogger, StorageTransform } from '../utils/types';\n\n/**\n * Transform pipeline manager.\n * Handles chaining of multiple transforms for serialization and deserialization.\n */\nclass TransformPipeline {\n constructor(\n private transforms: StorageTransform[],\n private logger?: StorageLogger\n ) {}\n\n /**\n * Applies transform pipeline in order: serialize → transform1 → transform2 → ... → transformN\n *\n * @param data - The serialized JSON string.\n * @returns The transformed string ready for persistence.\n */\n apply(data: string): string {\n return this.transforms.reduce((current, transform) => {\n try {\n return transform.serialize(current);\n } catch (e) {\n this.logger?.log('Transform serialize failed', e);\n throw new Error(\n `Transform pipeline failed: ${e instanceof Error ? e.message : String(e)}`\n );\n }\n }, data);\n }\n\n /**\n * Reverses transform pipeline: transformN → ... → transform2 → transform1 → deserialize\n *\n * @param data - The transformed string from storage.\n * @returns The original serialized JSON string.\n */\n reverse(data: string): string {\n return this.transforms.reduceRight((current, transform) => {\n try {\n return transform.deserialize(current);\n } catch (e) {\n this.logger?.log('Transform deserialize failed', e);\n throw new Error(\n `Transform pipeline reversal failed: ${e instanceof Error ? e.message : String(e)}`\n );\n }\n }, data);\n }\n\n /**\n * Checks if any transforms are configured.\n */\n hasTransforms(): boolean {\n return this.transforms.length > 0;\n }\n}\n\nexport { TransformPipeline };\n","/**\n * Default storage key used when none is specified.\n */\nconst DEFAULT_STORAGE_KEY = 'APP_DATA';\n\n/**\n * Default maximum size in bytes (~4MB).\n * Typical localStorage quota is 5-10MB per origin.\n */\nconst DEFAULT_MAX_SIZE_BYTES = 4_000_000;\n\n/**\n * Default maximum items for in-memory storage to prevent memory leaks.\n */\nconst DEFAULT_MAX_ITEMS_IN_MEMORY = 1000;\n\n/**\n * Dangerous keys that could cause prototype pollution attacks.\n */\nconst DANGEROUS_KEYS = ['__proto__', 'constructor', 'prototype'] as const;\n\n/**\n * Default debounce time in milliseconds.\n * Balance between performance and data safety.\n */\nconst DEFAULT_DEBOUNCE_MS = 100;\n\n/**\n * Default storage type (localStorage).\n */\nconst DEFAULT_STORAGE_TYPE = 'local';\n\nexport {\n DEFAULT_STORAGE_KEY,\n DEFAULT_MAX_SIZE_BYTES,\n DEFAULT_MAX_ITEMS_IN_MEMORY,\n DANGEROUS_KEYS,\n DEFAULT_DEBOUNCE_MS,\n DEFAULT_STORAGE_TYPE,\n};\n","import { DANGEROUS_KEYS } from './constants';\n\n/**\n * Validates a storage key.\n *\n * @param key - The key to validate.\n * @param storage - The storage instance to check availability.\n * @throws Will throw if storage is unavailable.\n * @throws Will throw if key is empty, contains only whitespace, or is a dangerous key.\n */\nfunction validateKey(\n key: string,\n storage: Storage | Map<string, string> | null\n): void {\n if (!storage) {\n throw new Error('Storage is not available (unavailable environment).');\n }\n\n if (!key || key.trim() === '') {\n throw new Error('Storage key cannot be empty or whitespace.');\n }\n\n if (DANGEROUS_KEYS.includes(key as never)) {\n throw new Error(\n `Storage key \"${key}\" is not allowed as it may cause prototype pollution.`\n );\n }\n}\n\n/**\n * Checks if a stored item is expired.\n *\n * @param expiry - The expiry timestamp or null if no expiry.\n * @returns True if the item is expired; false otherwise.\n */\nfunction isExpired(expiry: number | null): boolean {\n if (expiry === null) return false;\n return Date.now() > expiry;\n}\n\n/**\n * Calculates the byte size of a string.\n *\n * @param str - The string to measure.\n * @returns The size in bytes.\n */\nfunction getByteSize(str: string): number {\n return new Blob([str]).size;\n}\n\n/**\n * Checks if an error is a quota exceeded error.\n *\n * @param error - The error to check.\n * @returns True if the error is a quota exceeded error.\n */\nfunction isQuotaExceededError(error: unknown): boolean {\n return (\n error instanceof DOMException &&\n (error.name === 'QuotaExceededError' ||\n error.name === 'NS_ERROR_DOM_QUOTA_REACHED')\n );\n}\n\n/**\n * Checks if an error is a circular reference error.\n *\n * @param error - The error to check.\n * @returns True if the error is a circular reference error.\n */\nfunction isCircularReferenceError(error: unknown): boolean {\n return error instanceof TypeError && error.message.includes('circular');\n}\n\n/**\n * Checks if the data record has the correct structure.\n *\n * @param parsed - The parsed data to validate.\n * @returns True if the data record has the correct structure; false otherwise.\n */\nfunction isValidDataRecord(parsed: unknown): boolean {\n return (\n typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)\n );\n}\n\n/**\n * Checks if the window is available.\n *\n * @returns True if the window is available.\n */\nfunction isWindowAvailable(): boolean {\n return typeof window !== 'undefined';\n}\n\nexport {\n validateKey,\n isExpired,\n getByteSize,\n isQuotaExceededError,\n isCircularReferenceError,\n isValidDataRecord,\n isWindowAvailable,\n};\n","import { isWindowAvailable } from '../utils/helpers';\nimport type { StorageLogger, StorageType } from '../utils/types';\n\n/**\n * Storage backend abstraction layer.\n * Handles initialization and access to different storage types.\n */\nclass StorageBackend {\n private storage: Storage | Map<string, string> | null = null;\n private unloadHandler: (() => void) | null = null;\n\n constructor(\n private storageType: StorageType,\n private logger?: StorageLogger\n ) {\n this.initialize();\n }\n\n /**\n * Initializes the storage backend based on the storage type.\n */\n private initialize(): void {\n // Explicitly requested in-memory storage\n if (this.storageType === 'in-memory') {\n this.storage = new Map();\n return;\n }\n\n // Try to use web storage (localStorage or sessionStorage)\n if (isWindowAvailable()) {\n try {\n this.storage =\n this.storageType === 'session' ? sessionStorage : localStorage;\n } catch (e) {\n // Fallback to in-memory storage (Map) if accessing web storage throws an error\n // This can happen in private browsing mode or when storage is disabled\n this.logger?.log(\n 'Web storage is not accessible. Falling back to in-memory storage.',\n e\n );\n this.storage = new Map();\n }\n } else {\n // SSR is expected behavior - use in-memory fallback without logging\n this.storage = new Map();\n }\n }\n\n /**\n * Gets the underlying storage instance.\n */\n getStorage(): Storage | Map<string, string> | null {\n return this.storage;\n }\n\n /**\n * Reads data from storage.\n */\n read(key: string): string | null {\n if (!this.storage) return null;\n\n if (this.storage instanceof Map) {\n return this.storage.get(key) ?? null;\n }\n\n return this.storage.getItem(key);\n }\n\n /**\n * Writes data to storage.\n */\n write(key: string, value: string): void {\n if (!this.storage) return;\n\n if (this.storage instanceof Map) {\n this.storage.set(key, value);\n } else {\n this.storage.setItem(key, value);\n }\n }\n\n /**\n * Removes data from storage.\n */\n remove(key: string): void {\n if (!this.storage) return;\n\n if (this.storage instanceof Map) {\n this.storage.delete(key);\n } else {\n this.storage.removeItem(key);\n }\n }\n\n /**\n * Checks if storage is available.\n */\n isAvailable(): boolean {\n return this.storage !== null;\n }\n\n /**\n * Gets the storage type.\n */\n getStorageType():\n | 'localStorage'\n | 'sessionStorage'\n | 'memory'\n | 'unavailable' {\n if (!this.storage) return 'unavailable';\n if (this.storage instanceof Map) return 'memory';\n if (this.storage === localStorage) return 'localStorage';\n if (this.storage === sessionStorage) return 'sessionStorage';\n return 'unavailable';\n }\n\n /**\n * Registers a beforeunload handler for the storage backend.\n */\n registerUnloadHandler(handler: () => void): void {\n if (isWindowAvailable() && !this.unloadHandler) {\n this.unloadHandler = handler;\n window.addEventListener('beforeunload', this.unloadHandler);\n }\n }\n\n /**\n * Cleans up event listeners.\n */\n cleanup(): void {\n if (isWindowAvailable() && this.unloadHandler) {\n window.removeEventListener('beforeunload', this.unloadHandler);\n this.unloadHandler = null;\n }\n }\n}\n\nexport { StorageBackend };\n","import { TransformPipeline } from '../transforms/pipeline';\nimport {\n DEFAULT_DEBOUNCE_MS,\n DEFAULT_MAX_ITEMS_IN_MEMORY,\n DEFAULT_MAX_SIZE_BYTES,\n DEFAULT_STORAGE_KEY,\n DEFAULT_STORAGE_TYPE,\n} from '../utils/constants';\nimport {\n getByteSize,\n isCircularReferenceError,\n isExpired,\n isQuotaExceededError,\n isValidDataRecord,\n validateKey,\n} from '../utils/helpers';\nimport type {\n DataRecord,\n StorageLogger,\n StorageStats,\n StorageVaultOptions,\n StoredData,\n} from '../utils/types';\nimport { StorageBackend } from './storage-backend';\n\n/**\n * StorageVault - A unified wrapper around Web Storage with TTL, transforms, and safe handling.\n *\n * @see README.md for comprehensive documentation\n */\nclass StorageVault {\n private static instances = new Map<string, StorageVault>();\n\n private backend: StorageBackend;\n private transformPipeline: TransformPipeline;\n private storageKey: string;\n private logger?: StorageLogger;\n private maxSizeBytes: number;\n private maxItemsInMemory: number;\n private debounceMs: number;\n private isCleaningUp = false;\n private pendingSave: ReturnType<typeof setTimeout> | null = null;\n private dirtyData: DataRecord | null = null;\n\n /**\n * Gets or creates a singleton instance of StorageVault.\n */\n static getInstance(options: StorageVaultOptions = {}): StorageVault {\n const {\n storageType = DEFAULT_STORAGE_TYPE,\n storageKey = DEFAULT_STORAGE_KEY,\n logger,\n maxSizeBytes = DEFAULT_MAX_SIZE_BYTES,\n maxItemsInMemory = DEFAULT_MAX_ITEMS_IN_MEMORY,\n debounceMs = DEFAULT_DEBOUNCE_MS,\n transforms = [],\n } = options;\n\n const key = `${storageType}-${storageKey}`;\n\n if (!StorageVault.instances.has(key)) {\n StorageVault.instances.set(\n key,\n new StorageVault({\n storageType,\n storageKey,\n logger,\n maxSizeBytes,\n maxItemsInMemory,\n debounceMs,\n transforms,\n })\n );\n }\n\n const instance = StorageVault.instances.get(key);\n if (!instance) {\n logger?.log('Failed to create or retrieve StorageVault instance', {\n key,\n });\n throw new Error(\n `Failed to create or retrieve StorageVault instance: ${key}`\n );\n }\n\n return instance;\n }\n\n /**\n * Removes an instance from the singleton map.\n */\n static disposeInstance(options: StorageVaultOptions = {}): boolean {\n const {\n storageType = DEFAULT_STORAGE_TYPE,\n storageKey = DEFAULT_STORAGE_KEY,\n } = options;\n\n const key = `${storageType}-${storageKey}`;\n const instance = StorageVault.instances.get(key);\n\n if (instance) {\n instance.flush();\n instance.cleanup();\n }\n\n return StorageVault.instances.delete(key);\n }\n\n /**\n * Clears all instances from memory. Useful for testing.\n */\n static clearAllInstances(): void {\n StorageVault.instances.forEach((instance) => {\n instance.flush();\n instance.cleanup();\n });\n StorageVault.instances.clear();\n }\n\n /**\n * Creates a new StorageVault instance (private - use getInstance instead).\n */\n private constructor(options: StorageVaultOptions = {}) {\n const {\n storageType = DEFAULT_STORAGE_TYPE,\n storageKey = DEFAULT_STORAGE_KEY,\n logger,\n maxSizeBytes = DEFAULT_MAX_SIZE_BYTES,\n maxItemsInMemory = DEFAULT_MAX_ITEMS_IN_MEMORY,\n debounceMs = DEFAULT_DEBOUNCE_MS,\n transforms = [],\n } = options;\n\n this.logger = logger;\n this.storageKey = storageKey;\n this.maxSizeBytes = maxSizeBytes;\n this.maxItemsInMemory = maxItemsInMemory;\n this.debounceMs = debounceMs;\n this.backend = new StorageBackend(storageType, logger);\n this.transformPipeline = new TransformPipeline(transforms, logger);\n\n // Setup beforeunload handler to flush pending writes\n this.backend.registerUnloadHandler(() => {\n if (this.dirtyData) {\n this.saveAllDataImmediate(this.dirtyData);\n this.dirtyData = null;\n }\n });\n }\n\n /**\n * Reads and deserializes all data from storage.\n */\n private getAllData(): DataRecord {\n const storage = this.backend.getStorage();\n if (!storage) return {};\n\n // Return dirty data if we have pending writes (read-after-write consistency)\n if (this.dirtyData !== null) {\n return Object.freeze(this.dirtyData ?? {});\n }\n\n try {\n const dataStr = this.backend.read(this.storageKey);\n if (!dataStr) return {};\n\n // Apply reverse transforms before JSON parsing\n const deserializedStr = this.transformPipeline.reverse(dataStr);\n const parsed = JSON.parse(deserializedStr) as unknown;\n\n // Validate structure to handle corrupted data\n if (!isValidDataRecord(parsed)) {\n throw new Error('Invalid storage data structure');\n }\n\n return parsed as DataRecord;\n } catch (e) {\n this.logger?.log('Storage data corrupted or invalid, clearing storage', {\n error: e,\n storageKey: this.storageKey,\n });\n\n // Clear corrupted storage\n try {\n this.backend.remove(this.storageKey);\n } catch (clearError) {\n this.logger?.log('Failed to clear corrupted storage', clearError);\n }\n\n return {};\n }\n }\n\n /**\n * Serializes and writes data immediately to storage.\n */\n private saveAllDataImmediate(data: DataRecord): void {\n const storage = this.backend.getStorage();\n if (!storage) return;\n\n // Enforce max items limit for in-memory storage\n if (storage instanceof Map) {\n const itemCount = Object.keys(data).length;\n if (itemCount > this.maxItemsInMemory) {\n this.logger?.log(\n 'In-memory storage item limit exceeded, cleaning up oldest items',\n {\n itemCount,\n maxItems: this.maxItemsInMemory,\n }\n );\n this.enforceItemLimit(data);\n }\n }\n\n try {\n const dataStr = JSON.stringify(data);\n const transformedStr = this.transformPipeline.apply(dataStr);\n const byteSize = getByteSize(transformedStr);\n\n // Check size and warn if approaching quota\n if (byteSize > this.maxSizeBytes) {\n this.logger?.log('Storage approaching quota limit', {\n byteSize,\n stringLength: transformedStr.length,\n maxSizeBytes: this.maxSizeBytes,\n });\n }\n\n this.backend.write(this.storageKey, transformedStr);\n } catch (e) {\n this.handleSaveError(e);\n }\n }\n\n /**\n * Handles errors during save operations.\n */\n private handleSaveError(error: unknown): void {\n if (isQuotaExceededError(error)) {\n if (!this.isCleaningUp) {\n this.logger?.log('Storage quota exceeded, attempting cleanup', error);\n this.isCleaningUp = true;\n\n try {\n const removedCount = this.cleanupExpiredItems();\n this.logger?.log(`Cleanup removed ${removedCount} expired items`);\n\n // Retry after cleanup\n const freshData = this.getAllData();\n const dataStr = JSON.stringify(freshData);\n const transformedStr = this.transformPipeline.apply(dataStr);\n this.backend.write(this.storageKey, transformedStr);\n } catch (retryError) {\n this.logger?.log(\n 'Storage quota exceeded even after cleanup',\n retryError\n );\n throw new Error(\n 'Storage quota exceeded. Clear some data or use storage slices to reduce size.'\n );\n } finally {\n this.isCleaningUp = false;\n }\n } else {\n this.logger?.log(\n 'Already cleaning up, skipping recursive cleanup',\n error\n );\n throw new Error('Storage quota exceeded during cleanup');\n }\n } else if (isCircularReferenceError(error)) {\n this.logger?.log('Circular reference detected in stored data', error);\n throw new Error(\n 'Cannot store data with circular references. Serialize manually before storing.'\n );\n } else {\n this.logger?.log('Error saving to storage', error);\n throw new Error(\n `Failed to save to storage: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * Saves data with optional debouncing.\n */\n private saveAllData(data: DataRecord): void {\n if (this.debounceMs > 0) {\n // Debounced write: store in memory first for read-after-write consistency\n this.dirtyData = data;\n\n if (this.pendingSave) {\n clearTimeout(this.pendingSave);\n }\n\n this.pendingSave = setTimeout(() => {\n if (this.dirtyData) {\n try {\n this.saveAllDataImmediate(this.dirtyData);\n this.dirtyData = null;\n } catch (e) {\n this.logger?.log('Debounced save failed', e);\n // Keep dirtyData so next flush/save can retry\n }\n }\n this.pendingSave = null;\n }, this.debounceMs);\n } else {\n // Immediate write (no debouncing)\n this.saveAllDataImmediate(data);\n }\n }\n\n /**\n * Removes an item if it's expired.\n */\n private removeIfExpired(\n key: string,\n item: StoredData<unknown> | undefined,\n data: DataRecord\n ): boolean {\n if (!item) return true;\n\n if (isExpired(item.expiry)) {\n delete data[key];\n return true;\n }\n\n return false;\n }\n\n /**\n * Enforces the maximum item limit for in-memory storage.\n */\n private enforceItemLimit(data: DataRecord): void {\n const keys = Object.keys(data);\n if (keys.length <= this.maxItemsInMemory) return;\n\n // Sort by expiry time (oldest first)\n const sortedKeys = keys.sort((a, b) => {\n const expiryA = data[a]?.expiry ?? Infinity;\n const expiryB = data[b]?.expiry ?? Infinity;\n return expiryA - expiryB;\n });\n\n // Remove oldest items until we're under the limit\n const itemsToRemove = keys.length - this.maxItemsInMemory;\n for (let i = 0; i < itemsToRemove; i++) {\n const keyToDelete = sortedKeys[i];\n if (keyToDelete !== undefined) {\n delete data[keyToDelete];\n }\n }\n }\n\n /**\n * Cleans up resources used by this instance.\n */\n private cleanup(): void {\n // Clear any pending timers\n if (this.pendingSave) {\n clearTimeout(this.pendingSave);\n this.pendingSave = null;\n }\n\n // Remove event listeners\n this.backend.cleanup();\n }\n\n // ==================== PUBLIC API ====================\n\n /**\n * Stores a value with an optional time-to-live (TTL).\n */\n setItem<T>(key: string, value: T, ttl?: number): boolean {\n validateKey(key, this.backend.getStorage());\n\n if (ttl !== undefined && (!Number.isFinite(ttl) || ttl < 0)) {\n throw new Error('TTL must be a non-negative finite number.');\n }\n\n // Handle TTL=0 case: immediately delete the item\n if (ttl === 0) {\n return this.removeItem(key);\n }\n\n const data = this.getAllData();\n const expiry = ttl !== undefined ? Date.now() + ttl : null;\n data[key] = { value, expiry };\n\n this.saveAllData(data);\n return true;\n }\n\n /**\n * Retrieves a stored value by key.\n */\n getItem<T>(key: string): T | null {\n validateKey(key, this.backend.getStorage());\n\n const data = this.getAllData();\n const item = data[key] as StoredData<T> | undefined;\n\n if (!item) return null;\n\n const expired = this.removeIfExpired(key, item, data);\n\n if (expired) {\n this.saveAllData(data);\n return null;\n }\n\n return item.value;\n }\n\n /**\n * Updates the value of an existing item without modifying its expiry time.\n */\n updateItem<T>(key: string, newValue: T): boolean {\n validateKey(key, this.backend.getStorage());\n\n const data = this.getAllData();\n const item = data[key];\n\n if (!item) return false;\n\n const expired = this.removeIfExpired(key, item, data);\n\n if (expired) {\n this.saveAllData(data);\n return false;\n }\n\n item.value = newValue;\n this.saveAllData(data);\n return true;\n }\n\n /**\n * Extends the expiry time of an existing item.\n */\n extendTTL(key: string, additionalTTL: number): boolean {\n validateKey(key, this.backend.getStorage());\n\n if (!Number.isFinite(additionalTTL) || additionalTTL <= 0) {\n throw new Error('additionalTTL must be a positive finite number.');\n }\n\n const data = this.getAllData();\n const item = data[key];\n\n if (!item) return false;\n\n const expired = this.removeIfExpired(key, item, data);\n\n if (expired) {\n this.saveAllData(data);\n return false;\n }\n\n item.expiry =\n item.expiry !== null\n ? item.expiry + additionalTTL\n : Date.now() + additionalTTL;\n this.saveAllData(data);\n return true;\n }\n\n /**\n * Removes an item from storage.\n */\n removeItem(key: string): boolean {\n validateKey(key, this.backend.getStorage());\n\n const data = this.getAllData();\n if (key in data) {\n delete data[key];\n this.saveAllData(data);\n return true;\n }\n\n return false;\n }\n\n /**\n * Clears all stored data under the vault's storage key.\n */\n clear(): boolean {\n if (!this.backend.isAvailable()) {\n throw new Error('Storage is not available (unavailable environment).');\n }\n\n // Cancel any pending writes\n if (this.pendingSave) {\n clearTimeout(this.pendingSave);\n this.pendingSave = null;\n }\n this.dirtyData = null;\n\n try {\n this.backend.remove(this.storageKey);\n return true;\n } catch (error) {\n this.logger?.log('Error clearing storage', {\n error,\n storageKey: this.storageKey,\n });\n throw new Error(\n `Failed to clear storage: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * Checks whether an item exists and is not expired.\n */\n hasItem(key: string): boolean {\n validateKey(key, this.backend.getStorage());\n\n const data = this.getAllData();\n const item = data[key];\n\n if (!item) return false;\n\n const expired = this.removeIfExpired(key, item, data);\n\n if (expired) {\n this.saveAllData(data);\n return false;\n }\n\n return true;\n }\n\n /**\n * Returns the remaining time-to-live (TTL) for a stored item.\n */\n getRemainingTTL(key: string): number | null {\n if (!this.backend.isAvailable()) return null;\n\n const data = this.getAllData();\n const item = data[key];\n\n if (!item || item.expiry === null) return null;\n\n const remainingTime = item.expiry - Date.now();\n\n if (remainingTime <= 0) {\n delete data[key];\n this.saveAllData(data);\n return null;\n }\n\n return remainingTime;\n }\n\n /**\n * Removes all expired items from storage.\n */\n cleanupExpiredItems(): number {\n if (!this.backend.isAvailable()) return 0;\n\n const data = this.getAllData();\n let removedCount = 0;\n const now = Date.now();\n\n for (const key in data) {\n if (Object.prototype.hasOwnProperty.call(data, key)) {\n const item = data[key];\n if (item && item.expiry !== null && now > item.expiry) {\n delete data[key];\n removedCount++;\n }\n }\n }\n\n if (removedCount > 0) {\n this.saveAllDataImmediate(data);\n }\n\n return removedCount;\n }\n\n /**\n * Flushes any pending debounced writes immediately.\n */\n flush(): void {\n if (this.pendingSave) {\n clearTimeout(this.pendingSave);\n this.pendingSave = null;\n }\n\n if (this.dirtyData) {\n this.saveAllDataImmediate(this.dirtyData);\n this.dirtyData = null;\n }\n }\n\n /**\n * Returns all keys currently stored in the vault (excluding expired items).\n */\n getAllKeys(): string[] {\n if (!this.backend.isAvailable()) return [];\n\n const data = this.getAllData();\n const validKeys: string[] = [];\n const now = Date.now();\n\n for (const key in data) {\n if (Object.prototype.hasOwnProperty.call(data, key)) {\n const item = data[key];\n if (item && (item.expiry === null || now <= item.expiry)) {\n validKeys.push(key);\n }\n }\n }\n\n return validKeys;\n }\n\n /**\n * Returns all stored items as a key-value object (excluding expired items).\n */\n getAll(): Record<string, unknown> {\n if (!this.backend.isAvailable()) return {};\n\n const data = this.getAllData();\n const result: Record<string, unknown> = {};\n const now = Date.now();\n\n for (const key in data) {\n if (Object.prototype.hasOwnProperty.call(data, key)) {\n const item = data[key];\n if (item && (item.expiry === null || now <= item.expiry)) {\n result[key] = item.value;\n }\n }\n }\n\n return result;\n }\n\n /**\n * Returns the current size of stored data in bytes.\n */\n getCurrentSize(): number {\n if (!this.backend.isAvailable()) return 0;\n\n try {\n const data = this.getAllData();\n const dataStr = JSON.stringify(data);\n return getByteSize(dataStr);\n } catch (e) {\n this.logger?.log('Error calculating storage size', e);\n return 0;\n }\n }\n\n /**\n * Returns storage statistics.\n */\n getStats(): StorageStats {\n if (!this.backend.isAvailable()) {\n return {\n itemCount: 0,\n sizeBytes: 0,\n stringLength: 0,\n maxSizeBytes: this.maxSizeBytes,\n quotaPercentage: 0,\n storageType: 'unavailable',\n };\n }\n\n const data = this.getAllData();\n const itemCount = Object.keys(data).length;\n const dataStr = JSON.stringify(data);\n const sizeBytes = getByteSize(dataStr);\n const quotaPercentage = (sizeBytes / this.maxSizeBytes) * 100;\n\n return {\n itemCount,\n sizeBytes,\n stringLength: dataStr.length,\n maxSizeBytes: this.maxSizeBytes,\n quotaPercentage,\n storageType: this.backend.getStorageType(),\n };\n }\n}\n\nexport { StorageVault };\n","/**\n * A unified wrapper around Web Storage (localStorage / sessionStorage) with optional in-memory fallback.\n * Supports TTL-based expiration, JSON serialization, transform pipelines, and safe handling for both browser and server environments.\n *\n * All data is stored as a single serialized object under one key to avoid cluttering the storage space.\n *\n * @storage STORAGE TYPES:\n * - 'local': Uses localStorage (persists across browser sessions, ~5-10MB quota)\n * - 'session': Uses sessionStorage (cleared when tab closes, ~5-10MB quota)\n * - 'in-memory': Uses Map (cleared on page reload, useful for testing or temporary data)\n * Specify type via: getStorageSlice('KEY', { storageType: 'session' })\n *\n * @security WARNING: Web Storage is accessible via JavaScript and is NOT secure for sensitive data.\n * Do NOT store authentication tokens, passwords, or other sensitive information here.\n * For sensitive data, use httpOnly cookies or secure server-side sessions instead.\n * All stored data should be treated as potentially compromised and validated on retrieval.\n *\n * @ssr HYDRATION WARNING: During server-side rendering, this vault uses in-memory storage.\n * When hydrating on the client, a new instance with localStorage will be created, but any\n * server-rendered state will be lost. If you need to preserve SSR data, pass initial data\n * as props and call setItem() in useEffect() or similar client-side hook.\n *\n * @serialization JSON LIMITATIONS: Values are serialized with JSON.stringify(), which has limitations:\n * - Functions, undefined, and Symbol values are silently dropped\n * - Date objects become strings (must be manually converted back)\n * - Circular references will throw an error\n * - Map, Set, and other non-plain objects lose their type information\n * For complex data types, serialize them manually before storing.\n *\n * @transforms TRANSFORM PIPELINE: You can chain multiple transforms (compression, encryption, encoding):\n * - Transforms are applied AFTER JSON.stringify (string → string transformations)\n * - Applied in order during writes: serialize → transform1 → transform2 → ... → persist\n * - Reversed during reads: persist → reverse transformN → ... → reverse transform1 → deserialize\n * - Use for: compression (LZ-String), encryption (Web Crypto), encoding (Base64), etc.\n *\n * @performance When to use slices (getStorageSlice):\n * - Split data by update frequency (e.g., user preferences vs. temporary cache)\n * - Isolate large datasets to avoid re-serializing everything on each write\n * - Separate critical data from experimental features\n * Example: getStorageSlice('USER_PREFS') vs getStorageSlice('TEMP_CACHE')\n *\n * @performance DEBOUNCING: Write operations are debounced by default (100ms) to batch rapid updates.\n * - Reads always see pending writes immediately (read-after-write consistency)\n * - Pending writes are automatically flushed on page unload to prevent data loss\n * - For time-critical operations, call flush() to force immediate persistence\n * - Set debounceMs: 0 to disable debouncing (writes become synchronous)\n * - Consider higher debounceMs (200-500ms) for battery-sensitive or high-frequency scenarios\n */\n\nimport { StorageVault } from './core/vault';\nimport type { StorageVaultOptions } from './utils/types';\n\n/**\n * Creates a new StorageVault instance with a custom storage key.\n * Use slices to split large or frequently updated data into independent storage blobs.\n *\n * @param sliceKey - The key to store the data under. Must be unique.\n * @param options - Configuration options for the vault.\n * @returns A StorageVault instance (singleton per sliceKey + storage type).\n *\n * @example\n * // Using different storage types\n * const persistent = getStorageSlice('USER_PREFS', { storageType: 'local' }); // Persists across sessions\n * const temporary = getStorageSlice('SESSION_DATA', { storageType: 'session' }); // Cleared when tab closes\n * const testData = getStorageSlice('TEST_DATA', { storageType: 'in-memory' }); // For testing, cleared on reload\n *\n * @example\n * // Good: Separate frequently-updated data from stable data\n * const userPrefs = getStorageSlice('USER_PREFERENCES'); // Updated rarely\n * const tempCache = getStorageSlice('TEMP_CACHE'); // Updated frequently\n *\n * @example\n * // Using transforms\n * import LZString from 'lz-string';\n *\n * const compressionTransform = {\n * serialize: (data: string) => LZString.compress(data),\n * deserialize: (data: string) => LZString.decompress(data)\n * };\n *\n * const vault = getStorageSlice('LARGE_DATA', {\n * transforms: [compressionTransform]\n * });\n */\nfunction getStorageSlice(\n sliceKey: string,\n options: Omit<StorageVaultOptions, 'storageKey'> = {}\n): StorageVault {\n return StorageVault.getInstance({\n ...options,\n storageKey: sliceKey,\n });\n}\n\n/**\n * Disposes a storage slice instance, removing it from the singleton cache.\n * Call this when you're done with a temporary slice to allow garbage collection.\n *\n * @param sliceKey - The key of the slice to dispose.\n * @param options - The same options used when creating the slice (must match exactly).\n * @returns True if the slice was found and disposed; false otherwise.\n *\n * @example\n * const tempVault = getStorageSlice('TEMP_SESSION', { storageType: 'session' });\n * // ... use vault ...\n * disposeStorageSlice('TEMP_SESSION', { storageType: 'session' }); // Clean up when done\n */\nfunction disposeStorageSlice(\n sliceKey: string,\n options: Omit<StorageVaultOptions, 'storageKey'> = {}\n): boolean {\n return StorageVault.disposeInstance({\n ...options,\n storageKey: sliceKey,\n });\n}\n\nexport {\n // Main API functions\n getStorageSlice,\n disposeStorageSlice,\n StorageVault,\n};\n\nexport type {\n StorageType,\n StorageLogger,\n StorageTransform,\n StorageVaultOptions,\n StorageStats,\n StoredData,\n DataRecord,\n} from './utils/types';\n"]}
1
+ {"version":3,"sources":["../src/transforms/pipeline.ts","../src/utils/constants.ts","../src/utils/helpers.ts","../src/core/storage-backend.ts","../src/core/vault.ts","../src/index.ts"],"names":["TransformPipeline","transforms","logger","data","current","transform","_a","e","DEFAULT_STORAGE_KEY","DANGEROUS_KEYS","DEFAULT_STORAGE_TYPE","validateKey","key","storage","isExpired","expiry","getByteSize","str","isQuotaExceededError","error","isCircularReferenceError","isValidDataRecord","parsed","isWindowAvailable","StorageBackend","storageType","value","handler","_StorageVault","options","storageKey","maxSizeBytes","maxItemsInMemory","debounceMs","instance","_b","_c","dataStr","deserializedStr","clearError","itemCount","transformedStr","byteSize","_d","_e","_f","removedCount","freshData","retryError","item","keys","sortedKeys","a","b","expiryA","expiryB","itemsToRemove","keyToDelete","ttl","newValue","additionalTTL","remainingTime","now","validKeys","result","sizeBytes","quotaPercentage","StorageVault","getStorageSlice","sliceKey","disposeStorageSlice"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { StorageLogger, StorageTransform } from '../utils/types';\n\n/**\n * Transform pipeline manager.\n * Handles chaining of multiple transforms for serialization and deserialization.\n */\nclass TransformPipeline {\n constructor(\n private transforms: StorageTransform[],\n private logger?: StorageLogger\n ) {}\n\n /**\n * Applies transform pipeline in order: serialize → transform1 → transform2 → ... → transformN\n *\n * @param data - The serialized JSON string.\n * @returns The transformed string ready for persistence.\n */\n apply(data: string): string {\n return this.transforms.reduce((current, transform) => {\n try {\n return transform.serialize(current);\n } catch (e) {\n this.logger?.log('Transform serialize failed', e);\n throw new Error(\n `Transform pipeline failed: ${e instanceof Error ? e.message : String(e)}`\n );\n }\n }, data);\n }\n\n /**\n * Reverses transform pipeline: transformN → ... → transform2 → transform1 → deserialize\n *\n * @param data - The transformed string from storage.\n * @returns The original serialized JSON string.\n */\n reverse(data: string): string {\n return this.transforms.reduceRight((current, transform) => {\n try {\n return transform.deserialize(current);\n } catch (e) {\n this.logger?.log('Transform deserialize failed', e);\n throw new Error(\n `Transform pipeline reversal failed: ${e instanceof Error ? e.message : String(e)}`\n );\n }\n }, data);\n }\n\n /**\n * Checks if any transforms are configured.\n */\n hasTransforms(): boolean {\n return this.transforms.length > 0;\n }\n}\n\nexport { TransformPipeline };\n","/**\n * Default storage key used when none is specified.\n */\nconst DEFAULT_STORAGE_KEY = 'APP_DATA';\n\n/**\n * Default maximum size in bytes (~4MB).\n * Typical localStorage quota is 5-10MB per origin.\n */\nconst DEFAULT_MAX_SIZE_BYTES = 4_000_000;\n\n/**\n * Default maximum items for in-memory storage to prevent memory leaks.\n */\nconst DEFAULT_MAX_ITEMS_IN_MEMORY = 1000;\n\n/**\n * Dangerous keys that could cause prototype pollution attacks.\n */\nconst DANGEROUS_KEYS = ['__proto__', 'constructor', 'prototype'] as const;\n\n/**\n * Default debounce time in milliseconds.\n * Balance between performance and data safety.\n */\nconst DEFAULT_DEBOUNCE_MS = 100;\n\n/**\n * Default storage type (localStorage).\n */\nconst DEFAULT_STORAGE_TYPE = 'local';\n\nexport {\n DEFAULT_STORAGE_KEY,\n DEFAULT_MAX_SIZE_BYTES,\n DEFAULT_MAX_ITEMS_IN_MEMORY,\n DANGEROUS_KEYS,\n DEFAULT_DEBOUNCE_MS,\n DEFAULT_STORAGE_TYPE,\n};\n","import { DANGEROUS_KEYS } from './constants';\n\n/**\n * Validates a storage key.\n *\n * @param key - The key to validate.\n * @param storage - The storage instance to check availability.\n * @throws Will throw if storage is unavailable.\n * @throws Will throw if key is empty, contains only whitespace, or is a dangerous key.\n */\nfunction validateKey(\n key: string,\n storage: Storage | Map<string, string> | null\n): void {\n if (!storage) {\n throw new Error('Storage is not available (unavailable environment).');\n }\n\n if (!key || key.trim() === '') {\n throw new Error('Storage key cannot be empty or whitespace.');\n }\n\n if (DANGEROUS_KEYS.includes(key as never)) {\n throw new Error(\n `Storage key \"${key}\" is not allowed as it may cause prototype pollution.`\n );\n }\n}\n\n/**\n * Checks if a stored item is expired.\n *\n * @param expiry - The expiry timestamp or null if no expiry.\n * @returns True if the item is expired; false otherwise.\n */\nfunction isExpired(expiry: number | null): boolean {\n if (expiry === null) return false;\n return Date.now() > expiry;\n}\n\n/**\n * Calculates the byte size of a string.\n *\n * @param str - The string to measure.\n * @returns The size in bytes.\n */\nfunction getByteSize(str: string): number {\n return new Blob([str]).size;\n}\n\n/**\n * Checks if an error is a quota exceeded error.\n *\n * @param error - The error to check.\n * @returns True if the error is a quota exceeded error.\n */\nfunction isQuotaExceededError(error: unknown): boolean {\n return (\n error instanceof DOMException &&\n (error.name === 'QuotaExceededError' ||\n error.name === 'NS_ERROR_DOM_QUOTA_REACHED')\n );\n}\n\n/**\n * Checks if an error is a circular reference error.\n *\n * @param error - The error to check.\n * @returns True if the error is a circular reference error.\n */\nfunction isCircularReferenceError(error: unknown): boolean {\n return error instanceof TypeError && error.message.includes('circular');\n}\n\n/**\n * Checks if the data record has the correct structure.\n *\n * @param parsed - The parsed data to validate.\n * @returns True if the data record has the correct structure; false otherwise.\n */\nfunction isValidDataRecord(parsed: unknown): boolean {\n return (\n typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)\n );\n}\n\n/**\n * Checks if the window is available.\n *\n * @returns True if the window is available.\n */\nfunction isWindowAvailable(): boolean {\n return typeof window !== 'undefined';\n}\n\nexport {\n validateKey,\n isExpired,\n getByteSize,\n isQuotaExceededError,\n isCircularReferenceError,\n isValidDataRecord,\n isWindowAvailable,\n};\n","import { isWindowAvailable } from '../utils/helpers';\nimport type { StorageLogger, StorageType } from '../utils/types';\n\n/**\n * Storage backend abstraction layer.\n * Handles initialization and access to different storage types.\n */\nclass StorageBackend {\n private storage: Storage | Map<string, string> | null = null;\n private unloadHandler: (() => void) | null = null;\n\n constructor(\n private storageType: StorageType,\n private logger?: StorageLogger\n ) {\n this.initialize();\n }\n\n /**\n * Initializes the storage backend based on the storage type.\n */\n private initialize(): void {\n // Explicitly requested in-memory storage\n if (this.storageType === 'in-memory') {\n this.storage = new Map();\n return;\n }\n\n // Try to use web storage (localStorage or sessionStorage)\n if (isWindowAvailable()) {\n try {\n this.storage =\n this.storageType === 'session' ? sessionStorage : localStorage;\n } catch (e) {\n // Fallback to in-memory storage (Map) if accessing web storage throws an error\n // This can happen in private browsing mode or when storage is disabled\n this.logger?.log(\n 'Web storage is not accessible. Falling back to in-memory storage.',\n e\n );\n this.storage = new Map();\n }\n } else {\n // SSR is expected behavior - use in-memory fallback without logging\n this.storage = new Map();\n }\n }\n\n /**\n * Gets the underlying storage instance.\n */\n getStorage(): Storage | Map<string, string> | null {\n return this.storage;\n }\n\n /**\n * Reads data from storage.\n */\n read(key: string): string | null {\n if (!this.storage) return null;\n\n if (this.storage instanceof Map) {\n return this.storage.get(key) ?? null;\n }\n\n return this.storage.getItem(key);\n }\n\n /**\n * Writes data to storage.\n */\n write(key: string, value: string): void {\n if (!this.storage) return;\n\n if (this.storage instanceof Map) {\n this.storage.set(key, value);\n } else {\n this.storage.setItem(key, value);\n }\n }\n\n /**\n * Removes data from storage.\n */\n remove(key: string): void {\n if (!this.storage) return;\n\n if (this.storage instanceof Map) {\n this.storage.delete(key);\n } else {\n this.storage.removeItem(key);\n }\n }\n\n /**\n * Checks if storage is available.\n */\n isAvailable(): boolean {\n return this.storage !== null;\n }\n\n /**\n * Gets the storage type.\n */\n getStorageType():\n | 'localStorage'\n | 'sessionStorage'\n | 'memory'\n | 'unavailable' {\n if (!this.storage) return 'unavailable';\n if (this.storage instanceof Map) return 'memory';\n if (this.storage === localStorage) return 'localStorage';\n if (this.storage === sessionStorage) return 'sessionStorage';\n return 'unavailable';\n }\n\n /**\n * Registers a pagehide handler for the storage backend.\n */\n registerUnloadHandler(handler: () => void): void {\n if (isWindowAvailable() && !this.unloadHandler) {\n this.unloadHandler = handler;\n window.addEventListener('pagehide', this.unloadHandler);\n }\n }\n\n /**\n * Cleans up event listeners.\n */\n cleanup(): void {\n if (isWindowAvailable() && this.unloadHandler) {\n window.removeEventListener('pagehide', this.unloadHandler);\n this.unloadHandler = null;\n }\n }\n}\n\nexport { StorageBackend };\n","import { TransformPipeline } from '../transforms/pipeline';\nimport {\n DEFAULT_DEBOUNCE_MS,\n DEFAULT_MAX_ITEMS_IN_MEMORY,\n DEFAULT_MAX_SIZE_BYTES,\n DEFAULT_STORAGE_KEY,\n DEFAULT_STORAGE_TYPE,\n} from '../utils/constants';\nimport {\n getByteSize,\n isCircularReferenceError,\n isExpired,\n isQuotaExceededError,\n isValidDataRecord,\n validateKey,\n} from '../utils/helpers';\nimport type {\n DataRecord,\n StorageLogger,\n StorageStats,\n StorageVaultOptions,\n StoredData,\n} from '../utils/types';\nimport { StorageBackend } from './storage-backend';\n\n/**\n * StorageVault - A unified wrapper around Web Storage with TTL, transforms, and safe handling.\n *\n * @see README.md for comprehensive documentation\n */\nclass StorageVault {\n private static instances = new Map<string, StorageVault>();\n\n private backend: StorageBackend;\n private transformPipeline: TransformPipeline;\n private storageKey: string;\n private logger?: StorageLogger;\n private maxSizeBytes: number;\n private maxItemsInMemory: number;\n private debounceMs: number;\n private isCleaningUp = false;\n private pendingSave: ReturnType<typeof setTimeout> | null = null;\n private dirtyData: DataRecord | null = null;\n\n /**\n * Gets or creates a singleton instance of StorageVault.\n */\n static getInstance(options: StorageVaultOptions = {}): StorageVault {\n const {\n storageType = DEFAULT_STORAGE_TYPE,\n storageKey = DEFAULT_STORAGE_KEY,\n logger,\n maxSizeBytes = DEFAULT_MAX_SIZE_BYTES,\n maxItemsInMemory = DEFAULT_MAX_ITEMS_IN_MEMORY,\n debounceMs = DEFAULT_DEBOUNCE_MS,\n transforms = [],\n } = options;\n\n const key = `${storageType}-${storageKey}`;\n\n if (!StorageVault.instances.has(key)) {\n StorageVault.instances.set(\n key,\n new StorageVault({\n storageType,\n storageKey,\n logger,\n maxSizeBytes,\n maxItemsInMemory,\n debounceMs,\n transforms,\n })\n );\n }\n\n const instance = StorageVault.instances.get(key);\n if (!instance) {\n logger?.log('Failed to create or retrieve StorageVault instance', {\n key,\n });\n throw new Error(\n `Failed to create or retrieve StorageVault instance: ${key}`\n );\n }\n\n return instance;\n }\n\n /**\n * Removes an instance from the singleton map.\n */\n static disposeInstance(options: StorageVaultOptions = {}): boolean {\n const {\n storageType = DEFAULT_STORAGE_TYPE,\n storageKey = DEFAULT_STORAGE_KEY,\n } = options;\n\n const key = `${storageType}-${storageKey}`;\n const instance = StorageVault.instances.get(key);\n\n if (instance) {\n instance.flush();\n instance.cleanup();\n }\n\n return StorageVault.instances.delete(key);\n }\n\n /**\n * Clears all instances from memory. Useful for testing.\n */\n static clearAllInstances(): void {\n StorageVault.instances.forEach((instance) => {\n instance.flush();\n instance.cleanup();\n });\n StorageVault.instances.clear();\n }\n\n /**\n * Creates a new StorageVault instance (private - use getInstance instead).\n */\n private constructor(options: StorageVaultOptions = {}) {\n const {\n storageType = DEFAULT_STORAGE_TYPE,\n storageKey = DEFAULT_STORAGE_KEY,\n logger,\n maxSizeBytes = DEFAULT_MAX_SIZE_BYTES,\n maxItemsInMemory = DEFAULT_MAX_ITEMS_IN_MEMORY,\n debounceMs = DEFAULT_DEBOUNCE_MS,\n transforms = [],\n } = options;\n\n this.logger = logger;\n this.storageKey = storageKey;\n this.maxSizeBytes = maxSizeBytes;\n this.maxItemsInMemory = maxItemsInMemory;\n this.debounceMs = debounceMs;\n this.backend = new StorageBackend(storageType, logger);\n this.transformPipeline = new TransformPipeline(transforms, logger);\n\n // Setup pagehide handler to flush pending writes\n this.backend.registerUnloadHandler(() => {\n if (this.dirtyData) {\n this.saveAllDataImmediate(this.dirtyData);\n this.dirtyData = null;\n }\n });\n }\n\n /**\n * Reads and deserializes all data from storage.\n */\n private getAllData(): DataRecord {\n const storage = this.backend.getStorage();\n if (!storage) return {};\n\n // Return dirty data if we have pending writes (read-after-write consistency)\n if (this.dirtyData !== null) {\n return Object.freeze(this.dirtyData ?? {});\n }\n\n try {\n const dataStr = this.backend.read(this.storageKey);\n if (!dataStr) return {};\n\n // Apply reverse transforms before JSON parsing\n const deserializedStr = this.transformPipeline.reverse(dataStr);\n const parsed = JSON.parse(deserializedStr) as unknown;\n\n // Validate structure to handle corrupted data\n if (!isValidDataRecord(parsed)) {\n throw new Error('Invalid storage data structure');\n }\n\n return parsed as DataRecord;\n } catch (e) {\n this.logger?.log('Storage data corrupted or invalid, clearing storage', {\n error: e,\n storageKey: this.storageKey,\n });\n\n // Clear corrupted storage\n try {\n this.backend.remove(this.storageKey);\n } catch (clearError) {\n this.logger?.log('Failed to clear corrupted storage', clearError);\n }\n\n return {};\n }\n }\n\n /**\n * Serializes and writes data immediately to storage.\n */\n private saveAllDataImmediate(data: DataRecord): void {\n const storage = this.backend.getStorage();\n if (!storage) return;\n\n // Enforce max items limit for in-memory storage\n if (storage instanceof Map) {\n const itemCount = Object.keys(data).length;\n if (itemCount > this.maxItemsInMemory) {\n this.logger?.log(\n 'In-memory storage item limit exceeded, cleaning up oldest items',\n {\n itemCount,\n maxItems: this.maxItemsInMemory,\n }\n );\n this.enforceItemLimit(data);\n }\n }\n\n try {\n const dataStr = JSON.stringify(data);\n const transformedStr = this.transformPipeline.apply(dataStr);\n const byteSize = getByteSize(transformedStr);\n\n // Check size and warn if approaching quota\n if (byteSize > this.maxSizeBytes) {\n this.logger?.log('Storage approaching quota limit', {\n byteSize,\n stringLength: transformedStr.length,\n maxSizeBytes: this.maxSizeBytes,\n });\n }\n\n this.backend.write(this.storageKey, transformedStr);\n } catch (e) {\n this.handleSaveError(e);\n }\n }\n\n /**\n * Handles errors during save operations.\n */\n private handleSaveError(error: unknown): void {\n if (isQuotaExceededError(error)) {\n if (!this.isCleaningUp) {\n this.logger?.log('Storage quota exceeded, attempting cleanup', error);\n this.isCleaningUp = true;\n\n try {\n const removedCount = this.cleanupExpiredItems();\n this.logger?.log(`Cleanup removed ${removedCount} expired items`);\n\n // Retry after cleanup\n const freshData = this.getAllData();\n const dataStr = JSON.stringify(freshData);\n const transformedStr = this.transformPipeline.apply(dataStr);\n this.backend.write(this.storageKey, transformedStr);\n } catch (retryError) {\n this.logger?.log(\n 'Storage quota exceeded even after cleanup',\n retryError\n );\n throw new Error(\n 'Storage quota exceeded. Clear some data or use storage slices to reduce size.'\n );\n } finally {\n this.isCleaningUp = false;\n }\n } else {\n this.logger?.log(\n 'Already cleaning up, skipping recursive cleanup',\n error\n );\n throw new Error('Storage quota exceeded during cleanup');\n }\n } else if (isCircularReferenceError(error)) {\n this.logger?.log('Circular reference detected in stored data', error);\n throw new Error(\n 'Cannot store data with circular references. Serialize manually before storing.'\n );\n } else {\n this.logger?.log('Error saving to storage', error);\n throw new Error(\n `Failed to save to storage: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * Saves data with optional debouncing.\n */\n private saveAllData(data: DataRecord): void {\n if (this.debounceMs > 0) {\n // Debounced write: store in memory first for read-after-write consistency\n this.dirtyData = data;\n\n if (this.pendingSave) {\n clearTimeout(this.pendingSave);\n }\n\n this.pendingSave = setTimeout(() => {\n if (this.dirtyData) {\n try {\n this.saveAllDataImmediate(this.dirtyData);\n this.dirtyData = null;\n } catch (e) {\n this.logger?.log('Debounced save failed', e);\n // Keep dirtyData so next flush/save can retry\n }\n }\n this.pendingSave = null;\n }, this.debounceMs);\n } else {\n // Immediate write (no debouncing)\n this.saveAllDataImmediate(data);\n }\n }\n\n /**\n * Removes an item if it's expired.\n */\n private removeIfExpired(\n key: string,\n item: StoredData<unknown> | undefined,\n data: DataRecord\n ): boolean {\n if (!item) return true;\n\n if (isExpired(item.expiry)) {\n delete data[key];\n return true;\n }\n\n return false;\n }\n\n /**\n * Enforces the maximum item limit for in-memory storage.\n */\n private enforceItemLimit(data: DataRecord): void {\n const keys = Object.keys(data);\n if (keys.length <= this.maxItemsInMemory) return;\n\n // Sort by expiry time (oldest first)\n const sortedKeys = keys.sort((a, b) => {\n const expiryA = data[a]?.expiry ?? Infinity;\n const expiryB = data[b]?.expiry ?? Infinity;\n return expiryA - expiryB;\n });\n\n // Remove oldest items until we're under the limit\n const itemsToRemove = keys.length - this.maxItemsInMemory;\n for (let i = 0; i < itemsToRemove; i++) {\n const keyToDelete = sortedKeys[i];\n if (keyToDelete !== undefined) {\n delete data[keyToDelete];\n }\n }\n }\n\n /**\n * Cleans up resources used by this instance.\n */\n private cleanup(): void {\n // Clear any pending timers\n if (this.pendingSave) {\n clearTimeout(this.pendingSave);\n this.pendingSave = null;\n }\n\n // Remove event listeners\n this.backend.cleanup();\n }\n\n // ==================== PUBLIC API ====================\n\n /**\n * Stores a value with an optional time-to-live (TTL).\n */\n setItem<T>(key: string, value: T, ttl?: number): boolean {\n validateKey(key, this.backend.getStorage());\n\n if (ttl !== undefined && (!Number.isFinite(ttl) || ttl < 0)) {\n throw new Error('TTL must be a non-negative finite number.');\n }\n\n // Handle TTL=0 case: immediately delete the item\n if (ttl === 0) {\n return this.removeItem(key);\n }\n\n const data = this.getAllData();\n const expiry = ttl !== undefined ? Date.now() + ttl : null;\n data[key] = { value, expiry };\n\n this.saveAllData(data);\n return true;\n }\n\n /**\n * Retrieves a stored value by key.\n */\n getItem<T>(key: string): T | null {\n validateKey(key, this.backend.getStorage());\n\n const data = this.getAllData();\n const item = data[key] as StoredData<T> | undefined;\n\n if (!item) return null;\n\n const expired = this.removeIfExpired(key, item, data);\n\n if (expired) {\n this.saveAllData(data);\n return null;\n }\n\n return item.value;\n }\n\n /**\n * Updates the value of an existing item without modifying its expiry time.\n */\n updateItem<T>(key: string, newValue: T): boolean {\n validateKey(key, this.backend.getStorage());\n\n const data = this.getAllData();\n const item = data[key];\n\n if (!item) return false;\n\n const expired = this.removeIfExpired(key, item, data);\n\n if (expired) {\n this.saveAllData(data);\n return false;\n }\n\n item.value = newValue;\n this.saveAllData(data);\n return true;\n }\n\n /**\n * Extends the expiry time of an existing item.\n */\n extendTTL(key: string, additionalTTL: number): boolean {\n validateKey(key, this.backend.getStorage());\n\n if (!Number.isFinite(additionalTTL) || additionalTTL <= 0) {\n throw new Error('additionalTTL must be a positive finite number.');\n }\n\n const data = this.getAllData();\n const item = data[key];\n\n if (!item) return false;\n\n const expired = this.removeIfExpired(key, item, data);\n\n if (expired) {\n this.saveAllData(data);\n return false;\n }\n\n item.expiry =\n item.expiry !== null\n ? item.expiry + additionalTTL\n : Date.now() + additionalTTL;\n this.saveAllData(data);\n return true;\n }\n\n /**\n * Removes an item from storage.\n */\n removeItem(key: string): boolean {\n validateKey(key, this.backend.getStorage());\n\n const data = this.getAllData();\n if (key in data) {\n delete data[key];\n this.saveAllData(data);\n return true;\n }\n\n return false;\n }\n\n /**\n * Clears all stored data under the vault's storage key.\n */\n clear(): boolean {\n if (!this.backend.isAvailable()) {\n throw new Error('Storage is not available (unavailable environment).');\n }\n\n // Cancel any pending writes\n if (this.pendingSave) {\n clearTimeout(this.pendingSave);\n this.pendingSave = null;\n }\n this.dirtyData = null;\n\n try {\n this.backend.remove(this.storageKey);\n return true;\n } catch (error) {\n this.logger?.log('Error clearing storage', {\n error,\n storageKey: this.storageKey,\n });\n throw new Error(\n `Failed to clear storage: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * Checks whether an item exists and is not expired.\n */\n hasItem(key: string): boolean {\n validateKey(key, this.backend.getStorage());\n\n const data = this.getAllData();\n const item = data[key];\n\n if (!item) return false;\n\n const expired = this.removeIfExpired(key, item, data);\n\n if (expired) {\n this.saveAllData(data);\n return false;\n }\n\n return true;\n }\n\n /**\n * Returns the remaining time-to-live (TTL) for a stored item.\n */\n getRemainingTTL(key: string): number | null {\n if (!this.backend.isAvailable()) return null;\n\n const data = this.getAllData();\n const item = data[key];\n\n if (!item || item.expiry === null) return null;\n\n const remainingTime = item.expiry - Date.now();\n\n if (remainingTime <= 0) {\n delete data[key];\n this.saveAllData(data);\n return null;\n }\n\n return remainingTime;\n }\n\n /**\n * Removes all expired items from storage.\n */\n cleanupExpiredItems(): number {\n if (!this.backend.isAvailable()) return 0;\n\n const data = this.getAllData();\n let removedCount = 0;\n const now = Date.now();\n\n for (const key in data) {\n if (Object.prototype.hasOwnProperty.call(data, key)) {\n const item = data[key];\n if (item && item.expiry !== null && now > item.expiry) {\n delete data[key];\n removedCount++;\n }\n }\n }\n\n if (removedCount > 0) {\n this.saveAllDataImmediate(data);\n }\n\n return removedCount;\n }\n\n /**\n * Flushes any pending debounced writes immediately.\n */\n flush(): void {\n if (this.pendingSave) {\n clearTimeout(this.pendingSave);\n this.pendingSave = null;\n }\n\n if (this.dirtyData) {\n this.saveAllDataImmediate(this.dirtyData);\n this.dirtyData = null;\n }\n }\n\n /**\n * Returns all keys currently stored in the vault (excluding expired items).\n */\n getAllKeys(): string[] {\n if (!this.backend.isAvailable()) return [];\n\n const data = this.getAllData();\n const validKeys: string[] = [];\n const now = Date.now();\n\n for (const key in data) {\n if (Object.prototype.hasOwnProperty.call(data, key)) {\n const item = data[key];\n if (item && (item.expiry === null || now <= item.expiry)) {\n validKeys.push(key);\n }\n }\n }\n\n return validKeys;\n }\n\n /**\n * Returns all stored items as a key-value object (excluding expired items).\n */\n getAll(): Record<string, unknown> {\n if (!this.backend.isAvailable()) return {};\n\n const data = this.getAllData();\n const result: Record<string, unknown> = {};\n const now = Date.now();\n\n for (const key in data) {\n if (Object.prototype.hasOwnProperty.call(data, key)) {\n const item = data[key];\n if (item && (item.expiry === null || now <= item.expiry)) {\n result[key] = item.value;\n }\n }\n }\n\n return result;\n }\n\n /**\n * Returns the current size of stored data in bytes.\n */\n getCurrentSize(): number {\n if (!this.backend.isAvailable()) return 0;\n\n try {\n const data = this.getAllData();\n const dataStr = JSON.stringify(data);\n return getByteSize(dataStr);\n } catch (e) {\n this.logger?.log('Error calculating storage size', e);\n return 0;\n }\n }\n\n /**\n * Returns storage statistics.\n */\n getStats(): StorageStats {\n if (!this.backend.isAvailable()) {\n return {\n itemCount: 0,\n sizeBytes: 0,\n stringLength: 0,\n maxSizeBytes: this.maxSizeBytes,\n quotaPercentage: 0,\n storageType: 'unavailable',\n };\n }\n\n const data = this.getAllData();\n const itemCount = Object.keys(data).length;\n const dataStr = JSON.stringify(data);\n const sizeBytes = getByteSize(dataStr);\n const quotaPercentage = (sizeBytes / this.maxSizeBytes) * 100;\n\n return {\n itemCount,\n sizeBytes,\n stringLength: dataStr.length,\n maxSizeBytes: this.maxSizeBytes,\n quotaPercentage,\n storageType: this.backend.getStorageType(),\n };\n }\n}\n\nexport { StorageVault };\n","/**\n * A unified wrapper around Web Storage (localStorage / sessionStorage) with optional in-memory fallback.\n * Supports TTL-based expiration, JSON serialization, transform pipelines, and safe handling for both browser and server environments.\n *\n * All data is stored as a single serialized object under one key to avoid cluttering the storage space.\n *\n * @storage STORAGE TYPES:\n * - 'local': Uses localStorage (persists across browser sessions, ~5-10MB quota)\n * - 'session': Uses sessionStorage (cleared when tab closes, ~5-10MB quota)\n * - 'in-memory': Uses Map (cleared on page reload, useful for testing or temporary data)\n * Specify type via: getStorageSlice('KEY', { storageType: 'session' })\n *\n * @security WARNING: Web Storage is accessible via JavaScript and is NOT secure for sensitive data.\n * Do NOT store authentication tokens, passwords, or other sensitive information here.\n * For sensitive data, use httpOnly cookies or secure server-side sessions instead.\n * All stored data should be treated as potentially compromised and validated on retrieval.\n *\n * @ssr HYDRATION WARNING: During server-side rendering, this vault uses in-memory storage.\n * When hydrating on the client, a new instance with localStorage will be created, but any\n * server-rendered state will be lost. If you need to preserve SSR data, pass initial data\n * as props and call setItem() in useEffect() or similar client-side hook.\n *\n * @serialization JSON LIMITATIONS: Values are serialized with JSON.stringify(), which has limitations:\n * - Functions, undefined, and Symbol values are silently dropped\n * - Date objects become strings (must be manually converted back)\n * - Circular references will throw an error\n * - Map, Set, and other non-plain objects lose their type information\n * For complex data types, serialize them manually before storing.\n *\n * @transforms TRANSFORM PIPELINE: You can chain multiple transforms (compression, encryption, encoding):\n * - Transforms are applied AFTER JSON.stringify (string → string transformations)\n * - Applied in order during writes: serialize → transform1 → transform2 → ... → persist\n * - Reversed during reads: persist → reverse transformN → ... → reverse transform1 → deserialize\n * - Use for: compression (LZ-String), encryption (Web Crypto), encoding (Base64), etc.\n *\n * @performance When to use slices (getStorageSlice):\n * - Split data by update frequency (e.g., user preferences vs. temporary cache)\n * - Isolate large datasets to avoid re-serializing everything on each write\n * - Separate critical data from experimental features\n * Example: getStorageSlice('USER_PREFS') vs getStorageSlice('TEMP_CACHE')\n *\n * @performance DEBOUNCING: Write operations are debounced by default (100ms) to batch rapid updates.\n * - Reads always see pending writes immediately (read-after-write consistency)\n * - Pending writes are automatically flushed on page unload to prevent data loss\n * - For time-critical operations, call flush() to force immediate persistence\n * - Set debounceMs: 0 to disable debouncing (writes become synchronous)\n * - Consider higher debounceMs (200-500ms) for battery-sensitive or high-frequency scenarios\n */\n\nimport { StorageVault } from './core/vault';\nimport type { StorageVaultOptions } from './utils/types';\n\n/**\n * Creates a new StorageVault instance with a custom storage key.\n * Use slices to split large or frequently updated data into independent storage blobs.\n *\n * @param sliceKey - The key to store the data under. Must be unique.\n * @param options - Configuration options for the vault.\n * @returns A StorageVault instance (singleton per sliceKey + storage type).\n *\n * @example\n * // Using different storage types\n * const persistent = getStorageSlice('USER_PREFS', { storageType: 'local' }); // Persists across sessions\n * const temporary = getStorageSlice('SESSION_DATA', { storageType: 'session' }); // Cleared when tab closes\n * const testData = getStorageSlice('TEST_DATA', { storageType: 'in-memory' }); // For testing, cleared on reload\n *\n * @example\n * // Good: Separate frequently-updated data from stable data\n * const userPrefs = getStorageSlice('USER_PREFERENCES'); // Updated rarely\n * const tempCache = getStorageSlice('TEMP_CACHE'); // Updated frequently\n *\n * @example\n * // Using transforms\n * import LZString from 'lz-string';\n *\n * const compressionTransform = {\n * serialize: (data: string) => LZString.compress(data),\n * deserialize: (data: string) => LZString.decompress(data)\n * };\n *\n * const vault = getStorageSlice('LARGE_DATA', {\n * transforms: [compressionTransform]\n * });\n */\nfunction getStorageSlice(\n sliceKey: string,\n options: Omit<StorageVaultOptions, 'storageKey'> = {}\n): StorageVault {\n return StorageVault.getInstance({\n ...options,\n storageKey: sliceKey,\n });\n}\n\n/**\n * Disposes a storage slice instance, removing it from the singleton cache.\n * Call this when you're done with a temporary slice to allow garbage collection.\n *\n * @param sliceKey - The key of the slice to dispose.\n * @param options - The same options used when creating the slice (must match exactly).\n * @returns True if the slice was found and disposed; false otherwise.\n *\n * @example\n * const tempVault = getStorageSlice('TEMP_SESSION', { storageType: 'session' });\n * // ... use vault ...\n * disposeStorageSlice('TEMP_SESSION', { storageType: 'session' }); // Clean up when done\n */\nfunction disposeStorageSlice(\n sliceKey: string,\n options: Omit<StorageVaultOptions, 'storageKey'> = {}\n): boolean {\n return StorageVault.disposeInstance({\n ...options,\n storageKey: sliceKey,\n });\n}\n\nexport {\n // Main API functions\n getStorageSlice,\n disposeStorageSlice,\n StorageVault,\n};\n\nexport type {\n StorageType,\n StorageLogger,\n StorageTransform,\n StorageVaultOptions,\n StorageStats,\n StoredData,\n DataRecord,\n} from './utils/types';\n"]}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- var m=class{constructor(e,t){this.transforms=e;this.logger=t;}apply(e){return this.transforms.reduce((t,r)=>{var a;try{return r.serialize(t)}catch(i){throw (a=this.logger)==null||a.log("Transform serialize failed",i),new Error(`Transform pipeline failed: ${i instanceof Error?i.message:String(i)}`)}},e)}reverse(e){return this.transforms.reduceRight((t,r)=>{var a;try{return r.deserialize(t)}catch(i){throw (a=this.logger)==null||a.log("Transform deserialize failed",i),new Error(`Transform pipeline reversal failed: ${i instanceof Error?i.message:String(i)}`)}},e)}hasTransforms(){return this.transforms.length>0}};var f="APP_DATA";var E=["__proto__","constructor","prototype"];var S="local";function d(n,e){if(!e)throw new Error("Storage is not available (unavailable environment).");if(!n||n.trim()==="")throw new Error("Storage key cannot be empty or whitespace.");if(E.includes(n))throw new Error(`Storage key "${n}" is not allowed as it may cause prototype pollution.`)}function w(n){return n===null?false:Date.now()>n}function y(n){return new Blob([n]).size}function x(n){return n instanceof DOMException&&(n.name==="QuotaExceededError"||n.name==="NS_ERROR_DOM_QUOTA_REACHED")}function A(n){return n instanceof TypeError&&n.message.includes("circular")}function T(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function v(){return typeof window!="undefined"}var b=class{constructor(e,t){this.storageType=e;this.logger=t;this.storage=null;this.unloadHandler=null;this.initialize();}initialize(){var e;if(this.storageType==="in-memory"){this.storage=new Map;return}if(v())try{this.storage=this.storageType==="session"?sessionStorage:localStorage;}catch(t){(e=this.logger)==null||e.log("Web storage is not accessible. Falling back to in-memory storage.",t),this.storage=new Map;}else this.storage=new Map;}getStorage(){return this.storage}read(e){var t;return this.storage?this.storage instanceof Map?(t=this.storage.get(e))!=null?t:null:this.storage.getItem(e):null}write(e,t){this.storage&&(this.storage instanceof Map?this.storage.set(e,t):this.storage.setItem(e,t));}remove(e){this.storage&&(this.storage instanceof Map?this.storage.delete(e):this.storage.removeItem(e));}isAvailable(){return this.storage!==null}getStorageType(){return this.storage?this.storage instanceof Map?"memory":this.storage===localStorage?"localStorage":this.storage===sessionStorage?"sessionStorage":"unavailable":"unavailable"}registerUnloadHandler(e){v()&&!this.unloadHandler&&(this.unloadHandler=e,window.addEventListener("beforeunload",this.unloadHandler));}cleanup(){v()&&this.unloadHandler&&(window.removeEventListener("beforeunload",this.unloadHandler),this.unloadHandler=null);}};var l=class l{constructor(e={}){this.isCleaningUp=false;this.pendingSave=null;this.dirtyData=null;let{storageType:t=S,storageKey:r=f,logger:a,maxSizeBytes:i=4e6,maxItemsInMemory:s=1e3,debounceMs:o=100,transforms:c=[]}=e;this.logger=a,this.storageKey=r,this.maxSizeBytes=i,this.maxItemsInMemory=s,this.debounceMs=o,this.backend=new b(t,a),this.transformPipeline=new m(c,a),this.backend.registerUnloadHandler(()=>{this.dirtyData&&(this.saveAllDataImmediate(this.dirtyData),this.dirtyData=null);});}static getInstance(e={}){let{storageType:t=S,storageKey:r=f,logger:a,maxSizeBytes:i=4e6,maxItemsInMemory:s=1e3,debounceMs:o=100,transforms:c=[]}=e,g=`${t}-${r}`;l.instances.has(g)||l.instances.set(g,new l({storageType:t,storageKey:r,logger:a,maxSizeBytes:i,maxItemsInMemory:s,debounceMs:o,transforms:c}));let u=l.instances.get(g);if(!u)throw a==null||a.log("Failed to create or retrieve StorageVault instance",{key:g}),new Error(`Failed to create or retrieve StorageVault instance: ${g}`);return u}static disposeInstance(e={}){let{storageType:t=S,storageKey:r=f}=e,a=`${t}-${r}`,i=l.instances.get(a);return i&&(i.flush(),i.cleanup()),l.instances.delete(a)}static clearAllInstances(){l.instances.forEach(e=>{e.flush(),e.cleanup();}),l.instances.clear();}getAllData(){var t,r,a;if(!this.backend.getStorage())return {};if(this.dirtyData!==null)return Object.freeze((t=this.dirtyData)!=null?t:{});try{let i=this.backend.read(this.storageKey);if(!i)return {};let s=this.transformPipeline.reverse(i),o=JSON.parse(s);if(!T(o))throw new Error("Invalid storage data structure");return o}catch(i){(r=this.logger)==null||r.log("Storage data corrupted or invalid, clearing storage",{error:i,storageKey:this.storageKey});try{this.backend.remove(this.storageKey);}catch(s){(a=this.logger)==null||a.log("Failed to clear corrupted storage",s);}return {}}}saveAllDataImmediate(e){var r,a;let t=this.backend.getStorage();if(t){if(t instanceof Map){let i=Object.keys(e).length;i>this.maxItemsInMemory&&((r=this.logger)==null||r.log("In-memory storage item limit exceeded, cleaning up oldest items",{itemCount:i,maxItems:this.maxItemsInMemory}),this.enforceItemLimit(e));}try{let i=JSON.stringify(e),s=this.transformPipeline.apply(i),o=y(s);o>this.maxSizeBytes&&((a=this.logger)==null||a.log("Storage approaching quota limit",{byteSize:o,stringLength:s.length,maxSizeBytes:this.maxSizeBytes})),this.backend.write(this.storageKey,s);}catch(i){this.handleSaveError(i);}}}handleSaveError(e){var t,r,a,i,s,o;if(x(e)){if(this.isCleaningUp)throw (i=this.logger)==null||i.log("Already cleaning up, skipping recursive cleanup",e),new Error("Storage quota exceeded during cleanup");(t=this.logger)==null||t.log("Storage quota exceeded, attempting cleanup",e),this.isCleaningUp=true;try{let c=this.cleanupExpiredItems();(r=this.logger)==null||r.log(`Cleanup removed ${c} expired items`);let g=this.getAllData(),u=JSON.stringify(g),p=this.transformPipeline.apply(u);this.backend.write(this.storageKey,p);}catch(c){throw (a=this.logger)==null||a.log("Storage quota exceeded even after cleanup",c),new Error("Storage quota exceeded. Clear some data or use storage slices to reduce size.")}finally{this.isCleaningUp=false;}}else throw A(e)?((s=this.logger)==null||s.log("Circular reference detected in stored data",e),new Error("Cannot store data with circular references. Serialize manually before storing.")):((o=this.logger)==null||o.log("Error saving to storage",e),new Error(`Failed to save to storage: ${e instanceof Error?e.message:String(e)}`))}saveAllData(e){this.debounceMs>0?(this.dirtyData=e,this.pendingSave&&clearTimeout(this.pendingSave),this.pendingSave=setTimeout(()=>{var t;if(this.dirtyData)try{this.saveAllDataImmediate(this.dirtyData),this.dirtyData=null;}catch(r){(t=this.logger)==null||t.log("Debounced save failed",r);}this.pendingSave=null;},this.debounceMs)):this.saveAllDataImmediate(e);}removeIfExpired(e,t,r){return t?w(t.expiry)?(delete r[e],true):false:true}enforceItemLimit(e){let t=Object.keys(e);if(t.length<=this.maxItemsInMemory)return;let r=t.sort((i,s)=>{var g,u,p,D;let o=(u=(g=e[i])==null?void 0:g.expiry)!=null?u:1/0,c=(D=(p=e[s])==null?void 0:p.expiry)!=null?D:1/0;return o-c}),a=t.length-this.maxItemsInMemory;for(let i=0;i<a;i++){let s=r[i];s!==void 0&&delete e[s];}}cleanup(){this.pendingSave&&(clearTimeout(this.pendingSave),this.pendingSave=null),this.backend.cleanup();}setItem(e,t,r){if(d(e,this.backend.getStorage()),r!==void 0&&(!Number.isFinite(r)||r<0))throw new Error("TTL must be a non-negative finite number.");if(r===0)return this.removeItem(e);let a=this.getAllData(),i=r!==void 0?Date.now()+r:null;return a[e]={value:t,expiry:i},this.saveAllData(a),true}getItem(e){d(e,this.backend.getStorage());let t=this.getAllData(),r=t[e];return r?this.removeIfExpired(e,r,t)?(this.saveAllData(t),null):r.value:null}updateItem(e,t){d(e,this.backend.getStorage());let r=this.getAllData(),a=r[e];return a?this.removeIfExpired(e,a,r)?(this.saveAllData(r),false):(a.value=t,this.saveAllData(r),true):false}extendTTL(e,t){if(d(e,this.backend.getStorage()),!Number.isFinite(t)||t<=0)throw new Error("additionalTTL must be a positive finite number.");let r=this.getAllData(),a=r[e];return a?this.removeIfExpired(e,a,r)?(this.saveAllData(r),false):(a.expiry=a.expiry!==null?a.expiry+t:Date.now()+t,this.saveAllData(r),true):false}removeItem(e){d(e,this.backend.getStorage());let t=this.getAllData();return e in t?(delete t[e],this.saveAllData(t),true):false}clear(){var e;if(!this.backend.isAvailable())throw new Error("Storage is not available (unavailable environment).");this.pendingSave&&(clearTimeout(this.pendingSave),this.pendingSave=null),this.dirtyData=null;try{return this.backend.remove(this.storageKey),!0}catch(t){throw (e=this.logger)==null||e.log("Error clearing storage",{error:t,storageKey:this.storageKey}),new Error(`Failed to clear storage: ${t instanceof Error?t.message:String(t)}`)}}hasItem(e){d(e,this.backend.getStorage());let t=this.getAllData(),r=t[e];return r?this.removeIfExpired(e,r,t)?(this.saveAllData(t),false):true:false}getRemainingTTL(e){if(!this.backend.isAvailable())return null;let t=this.getAllData(),r=t[e];if(!r||r.expiry===null)return null;let a=r.expiry-Date.now();return a<=0?(delete t[e],this.saveAllData(t),null):a}cleanupExpiredItems(){if(!this.backend.isAvailable())return 0;let e=this.getAllData(),t=0,r=Date.now();for(let a in e)if(Object.prototype.hasOwnProperty.call(e,a)){let i=e[a];i&&i.expiry!==null&&r>i.expiry&&(delete e[a],t++);}return t>0&&this.saveAllDataImmediate(e),t}flush(){this.pendingSave&&(clearTimeout(this.pendingSave),this.pendingSave=null),this.dirtyData&&(this.saveAllDataImmediate(this.dirtyData),this.dirtyData=null);}getAllKeys(){if(!this.backend.isAvailable())return [];let e=this.getAllData(),t=[],r=Date.now();for(let a in e)if(Object.prototype.hasOwnProperty.call(e,a)){let i=e[a];i&&(i.expiry===null||r<=i.expiry)&&t.push(a);}return t}getAll(){if(!this.backend.isAvailable())return {};let e=this.getAllData(),t={},r=Date.now();for(let a in e)if(Object.prototype.hasOwnProperty.call(e,a)){let i=e[a];i&&(i.expiry===null||r<=i.expiry)&&(t[a]=i.value);}return t}getCurrentSize(){var e;if(!this.backend.isAvailable())return 0;try{let t=this.getAllData(),r=JSON.stringify(t);return y(r)}catch(t){return (e=this.logger)==null||e.log("Error calculating storage size",t),0}}getStats(){if(!this.backend.isAvailable())return {itemCount:0,sizeBytes:0,stringLength:0,maxSizeBytes:this.maxSizeBytes,quotaPercentage:0,storageType:"unavailable"};let e=this.getAllData(),t=Object.keys(e).length,r=JSON.stringify(e),a=y(r),i=a/this.maxSizeBytes*100;return {itemCount:t,sizeBytes:a,stringLength:r.length,maxSizeBytes:this.maxSizeBytes,quotaPercentage:i,storageType:this.backend.getStorageType()}}};l.instances=new Map;var h=l;function V(n,e={}){return h.getInstance({...e,storageKey:n})}function $(n,e={}){return h.disposeInstance({...e,storageKey:n})}export{h as StorageVault,$ as disposeStorageSlice,V as getStorageSlice};//# sourceMappingURL=index.js.map
1
+ var m=class{constructor(e,t){this.transforms=e;this.logger=t;}apply(e){return this.transforms.reduce((t,r)=>{var a;try{return r.serialize(t)}catch(i){throw (a=this.logger)==null||a.log("Transform serialize failed",i),new Error(`Transform pipeline failed: ${i instanceof Error?i.message:String(i)}`)}},e)}reverse(e){return this.transforms.reduceRight((t,r)=>{var a;try{return r.deserialize(t)}catch(i){throw (a=this.logger)==null||a.log("Transform deserialize failed",i),new Error(`Transform pipeline reversal failed: ${i instanceof Error?i.message:String(i)}`)}},e)}hasTransforms(){return this.transforms.length>0}};var f="APP_DATA";var E=["__proto__","constructor","prototype"];var S="local";function d(n,e){if(!e)throw new Error("Storage is not available (unavailable environment).");if(!n||n.trim()==="")throw new Error("Storage key cannot be empty or whitespace.");if(E.includes(n))throw new Error(`Storage key "${n}" is not allowed as it may cause prototype pollution.`)}function w(n){return n===null?false:Date.now()>n}function y(n){return new Blob([n]).size}function x(n){return n instanceof DOMException&&(n.name==="QuotaExceededError"||n.name==="NS_ERROR_DOM_QUOTA_REACHED")}function A(n){return n instanceof TypeError&&n.message.includes("circular")}function T(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function v(){return typeof window!="undefined"}var b=class{constructor(e,t){this.storageType=e;this.logger=t;this.storage=null;this.unloadHandler=null;this.initialize();}initialize(){var e;if(this.storageType==="in-memory"){this.storage=new Map;return}if(v())try{this.storage=this.storageType==="session"?sessionStorage:localStorage;}catch(t){(e=this.logger)==null||e.log("Web storage is not accessible. Falling back to in-memory storage.",t),this.storage=new Map;}else this.storage=new Map;}getStorage(){return this.storage}read(e){var t;return this.storage?this.storage instanceof Map?(t=this.storage.get(e))!=null?t:null:this.storage.getItem(e):null}write(e,t){this.storage&&(this.storage instanceof Map?this.storage.set(e,t):this.storage.setItem(e,t));}remove(e){this.storage&&(this.storage instanceof Map?this.storage.delete(e):this.storage.removeItem(e));}isAvailable(){return this.storage!==null}getStorageType(){return this.storage?this.storage instanceof Map?"memory":this.storage===localStorage?"localStorage":this.storage===sessionStorage?"sessionStorage":"unavailable":"unavailable"}registerUnloadHandler(e){v()&&!this.unloadHandler&&(this.unloadHandler=e,window.addEventListener("pagehide",this.unloadHandler));}cleanup(){v()&&this.unloadHandler&&(window.removeEventListener("pagehide",this.unloadHandler),this.unloadHandler=null);}};var l=class l{constructor(e={}){this.isCleaningUp=false;this.pendingSave=null;this.dirtyData=null;let{storageType:t=S,storageKey:r=f,logger:a,maxSizeBytes:i=4e6,maxItemsInMemory:s=1e3,debounceMs:o=100,transforms:c=[]}=e;this.logger=a,this.storageKey=r,this.maxSizeBytes=i,this.maxItemsInMemory=s,this.debounceMs=o,this.backend=new b(t,a),this.transformPipeline=new m(c,a),this.backend.registerUnloadHandler(()=>{this.dirtyData&&(this.saveAllDataImmediate(this.dirtyData),this.dirtyData=null);});}static getInstance(e={}){let{storageType:t=S,storageKey:r=f,logger:a,maxSizeBytes:i=4e6,maxItemsInMemory:s=1e3,debounceMs:o=100,transforms:c=[]}=e,g=`${t}-${r}`;l.instances.has(g)||l.instances.set(g,new l({storageType:t,storageKey:r,logger:a,maxSizeBytes:i,maxItemsInMemory:s,debounceMs:o,transforms:c}));let u=l.instances.get(g);if(!u)throw a==null||a.log("Failed to create or retrieve StorageVault instance",{key:g}),new Error(`Failed to create or retrieve StorageVault instance: ${g}`);return u}static disposeInstance(e={}){let{storageType:t=S,storageKey:r=f}=e,a=`${t}-${r}`,i=l.instances.get(a);return i&&(i.flush(),i.cleanup()),l.instances.delete(a)}static clearAllInstances(){l.instances.forEach(e=>{e.flush(),e.cleanup();}),l.instances.clear();}getAllData(){var t,r,a;if(!this.backend.getStorage())return {};if(this.dirtyData!==null)return Object.freeze((t=this.dirtyData)!=null?t:{});try{let i=this.backend.read(this.storageKey);if(!i)return {};let s=this.transformPipeline.reverse(i),o=JSON.parse(s);if(!T(o))throw new Error("Invalid storage data structure");return o}catch(i){(r=this.logger)==null||r.log("Storage data corrupted or invalid, clearing storage",{error:i,storageKey:this.storageKey});try{this.backend.remove(this.storageKey);}catch(s){(a=this.logger)==null||a.log("Failed to clear corrupted storage",s);}return {}}}saveAllDataImmediate(e){var r,a;let t=this.backend.getStorage();if(t){if(t instanceof Map){let i=Object.keys(e).length;i>this.maxItemsInMemory&&((r=this.logger)==null||r.log("In-memory storage item limit exceeded, cleaning up oldest items",{itemCount:i,maxItems:this.maxItemsInMemory}),this.enforceItemLimit(e));}try{let i=JSON.stringify(e),s=this.transformPipeline.apply(i),o=y(s);o>this.maxSizeBytes&&((a=this.logger)==null||a.log("Storage approaching quota limit",{byteSize:o,stringLength:s.length,maxSizeBytes:this.maxSizeBytes})),this.backend.write(this.storageKey,s);}catch(i){this.handleSaveError(i);}}}handleSaveError(e){var t,r,a,i,s,o;if(x(e)){if(this.isCleaningUp)throw (i=this.logger)==null||i.log("Already cleaning up, skipping recursive cleanup",e),new Error("Storage quota exceeded during cleanup");(t=this.logger)==null||t.log("Storage quota exceeded, attempting cleanup",e),this.isCleaningUp=true;try{let c=this.cleanupExpiredItems();(r=this.logger)==null||r.log(`Cleanup removed ${c} expired items`);let g=this.getAllData(),u=JSON.stringify(g),p=this.transformPipeline.apply(u);this.backend.write(this.storageKey,p);}catch(c){throw (a=this.logger)==null||a.log("Storage quota exceeded even after cleanup",c),new Error("Storage quota exceeded. Clear some data or use storage slices to reduce size.")}finally{this.isCleaningUp=false;}}else throw A(e)?((s=this.logger)==null||s.log("Circular reference detected in stored data",e),new Error("Cannot store data with circular references. Serialize manually before storing.")):((o=this.logger)==null||o.log("Error saving to storage",e),new Error(`Failed to save to storage: ${e instanceof Error?e.message:String(e)}`))}saveAllData(e){this.debounceMs>0?(this.dirtyData=e,this.pendingSave&&clearTimeout(this.pendingSave),this.pendingSave=setTimeout(()=>{var t;if(this.dirtyData)try{this.saveAllDataImmediate(this.dirtyData),this.dirtyData=null;}catch(r){(t=this.logger)==null||t.log("Debounced save failed",r);}this.pendingSave=null;},this.debounceMs)):this.saveAllDataImmediate(e);}removeIfExpired(e,t,r){return t?w(t.expiry)?(delete r[e],true):false:true}enforceItemLimit(e){let t=Object.keys(e);if(t.length<=this.maxItemsInMemory)return;let r=t.sort((i,s)=>{var g,u,p,D;let o=(u=(g=e[i])==null?void 0:g.expiry)!=null?u:1/0,c=(D=(p=e[s])==null?void 0:p.expiry)!=null?D:1/0;return o-c}),a=t.length-this.maxItemsInMemory;for(let i=0;i<a;i++){let s=r[i];s!==void 0&&delete e[s];}}cleanup(){this.pendingSave&&(clearTimeout(this.pendingSave),this.pendingSave=null),this.backend.cleanup();}setItem(e,t,r){if(d(e,this.backend.getStorage()),r!==void 0&&(!Number.isFinite(r)||r<0))throw new Error("TTL must be a non-negative finite number.");if(r===0)return this.removeItem(e);let a=this.getAllData(),i=r!==void 0?Date.now()+r:null;return a[e]={value:t,expiry:i},this.saveAllData(a),true}getItem(e){d(e,this.backend.getStorage());let t=this.getAllData(),r=t[e];return r?this.removeIfExpired(e,r,t)?(this.saveAllData(t),null):r.value:null}updateItem(e,t){d(e,this.backend.getStorage());let r=this.getAllData(),a=r[e];return a?this.removeIfExpired(e,a,r)?(this.saveAllData(r),false):(a.value=t,this.saveAllData(r),true):false}extendTTL(e,t){if(d(e,this.backend.getStorage()),!Number.isFinite(t)||t<=0)throw new Error("additionalTTL must be a positive finite number.");let r=this.getAllData(),a=r[e];return a?this.removeIfExpired(e,a,r)?(this.saveAllData(r),false):(a.expiry=a.expiry!==null?a.expiry+t:Date.now()+t,this.saveAllData(r),true):false}removeItem(e){d(e,this.backend.getStorage());let t=this.getAllData();return e in t?(delete t[e],this.saveAllData(t),true):false}clear(){var e;if(!this.backend.isAvailable())throw new Error("Storage is not available (unavailable environment).");this.pendingSave&&(clearTimeout(this.pendingSave),this.pendingSave=null),this.dirtyData=null;try{return this.backend.remove(this.storageKey),!0}catch(t){throw (e=this.logger)==null||e.log("Error clearing storage",{error:t,storageKey:this.storageKey}),new Error(`Failed to clear storage: ${t instanceof Error?t.message:String(t)}`)}}hasItem(e){d(e,this.backend.getStorage());let t=this.getAllData(),r=t[e];return r?this.removeIfExpired(e,r,t)?(this.saveAllData(t),false):true:false}getRemainingTTL(e){if(!this.backend.isAvailable())return null;let t=this.getAllData(),r=t[e];if(!r||r.expiry===null)return null;let a=r.expiry-Date.now();return a<=0?(delete t[e],this.saveAllData(t),null):a}cleanupExpiredItems(){if(!this.backend.isAvailable())return 0;let e=this.getAllData(),t=0,r=Date.now();for(let a in e)if(Object.prototype.hasOwnProperty.call(e,a)){let i=e[a];i&&i.expiry!==null&&r>i.expiry&&(delete e[a],t++);}return t>0&&this.saveAllDataImmediate(e),t}flush(){this.pendingSave&&(clearTimeout(this.pendingSave),this.pendingSave=null),this.dirtyData&&(this.saveAllDataImmediate(this.dirtyData),this.dirtyData=null);}getAllKeys(){if(!this.backend.isAvailable())return [];let e=this.getAllData(),t=[],r=Date.now();for(let a in e)if(Object.prototype.hasOwnProperty.call(e,a)){let i=e[a];i&&(i.expiry===null||r<=i.expiry)&&t.push(a);}return t}getAll(){if(!this.backend.isAvailable())return {};let e=this.getAllData(),t={},r=Date.now();for(let a in e)if(Object.prototype.hasOwnProperty.call(e,a)){let i=e[a];i&&(i.expiry===null||r<=i.expiry)&&(t[a]=i.value);}return t}getCurrentSize(){var e;if(!this.backend.isAvailable())return 0;try{let t=this.getAllData(),r=JSON.stringify(t);return y(r)}catch(t){return (e=this.logger)==null||e.log("Error calculating storage size",t),0}}getStats(){if(!this.backend.isAvailable())return {itemCount:0,sizeBytes:0,stringLength:0,maxSizeBytes:this.maxSizeBytes,quotaPercentage:0,storageType:"unavailable"};let e=this.getAllData(),t=Object.keys(e).length,r=JSON.stringify(e),a=y(r),i=a/this.maxSizeBytes*100;return {itemCount:t,sizeBytes:a,stringLength:r.length,maxSizeBytes:this.maxSizeBytes,quotaPercentage:i,storageType:this.backend.getStorageType()}}};l.instances=new Map;var h=l;function V(n,e={}){return h.getInstance({...e,storageKey:n})}function $(n,e={}){return h.disposeInstance({...e,storageKey:n})}export{h as StorageVault,$ as disposeStorageSlice,V as getStorageSlice};//# sourceMappingURL=index.js.map
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/transforms/pipeline.ts","../src/utils/constants.ts","../src/utils/helpers.ts","../src/core/storage-backend.ts","../src/core/vault.ts","../src/index.ts"],"names":["TransformPipeline","transforms","logger","data","current","transform","_a","e","DEFAULT_STORAGE_KEY","DANGEROUS_KEYS","DEFAULT_STORAGE_TYPE","validateKey","key","storage","isExpired","expiry","getByteSize","str","isQuotaExceededError","error","isCircularReferenceError","isValidDataRecord","parsed","isWindowAvailable","StorageBackend","storageType","value","handler","_StorageVault","options","storageKey","maxSizeBytes","maxItemsInMemory","debounceMs","instance","_b","_c","dataStr","deserializedStr","clearError","itemCount","transformedStr","byteSize","_d","_e","_f","removedCount","freshData","retryError","item","keys","sortedKeys","a","b","expiryA","expiryB","itemsToRemove","keyToDelete","ttl","newValue","additionalTTL","remainingTime","now","validKeys","result","sizeBytes","quotaPercentage","StorageVault","getStorageSlice","sliceKey","disposeStorageSlice"],"mappings":"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","file":"index.js","sourcesContent":["import type { StorageLogger, StorageTransform } from '../utils/types';\n\n/**\n * Transform pipeline manager.\n * Handles chaining of multiple transforms for serialization and deserialization.\n */\nclass TransformPipeline {\n constructor(\n private transforms: StorageTransform[],\n private logger?: StorageLogger\n ) {}\n\n /**\n * Applies transform pipeline in order: serialize → transform1 → transform2 → ... → transformN\n *\n * @param data - The serialized JSON string.\n * @returns The transformed string ready for persistence.\n */\n apply(data: string): string {\n return this.transforms.reduce((current, transform) => {\n try {\n return transform.serialize(current);\n } catch (e) {\n this.logger?.log('Transform serialize failed', e);\n throw new Error(\n `Transform pipeline failed: ${e instanceof Error ? e.message : String(e)}`\n );\n }\n }, data);\n }\n\n /**\n * Reverses transform pipeline: transformN → ... → transform2 → transform1 → deserialize\n *\n * @param data - The transformed string from storage.\n * @returns The original serialized JSON string.\n */\n reverse(data: string): string {\n return this.transforms.reduceRight((current, transform) => {\n try {\n return transform.deserialize(current);\n } catch (e) {\n this.logger?.log('Transform deserialize failed', e);\n throw new Error(\n `Transform pipeline reversal failed: ${e instanceof Error ? e.message : String(e)}`\n );\n }\n }, data);\n }\n\n /**\n * Checks if any transforms are configured.\n */\n hasTransforms(): boolean {\n return this.transforms.length > 0;\n }\n}\n\nexport { TransformPipeline };\n","/**\n * Default storage key used when none is specified.\n */\nconst DEFAULT_STORAGE_KEY = 'APP_DATA';\n\n/**\n * Default maximum size in bytes (~4MB).\n * Typical localStorage quota is 5-10MB per origin.\n */\nconst DEFAULT_MAX_SIZE_BYTES = 4_000_000;\n\n/**\n * Default maximum items for in-memory storage to prevent memory leaks.\n */\nconst DEFAULT_MAX_ITEMS_IN_MEMORY = 1000;\n\n/**\n * Dangerous keys that could cause prototype pollution attacks.\n */\nconst DANGEROUS_KEYS = ['__proto__', 'constructor', 'prototype'] as const;\n\n/**\n * Default debounce time in milliseconds.\n * Balance between performance and data safety.\n */\nconst DEFAULT_DEBOUNCE_MS = 100;\n\n/**\n * Default storage type (localStorage).\n */\nconst DEFAULT_STORAGE_TYPE = 'local';\n\nexport {\n DEFAULT_STORAGE_KEY,\n DEFAULT_MAX_SIZE_BYTES,\n DEFAULT_MAX_ITEMS_IN_MEMORY,\n DANGEROUS_KEYS,\n DEFAULT_DEBOUNCE_MS,\n DEFAULT_STORAGE_TYPE,\n};\n","import { DANGEROUS_KEYS } from './constants';\n\n/**\n * Validates a storage key.\n *\n * @param key - The key to validate.\n * @param storage - The storage instance to check availability.\n * @throws Will throw if storage is unavailable.\n * @throws Will throw if key is empty, contains only whitespace, or is a dangerous key.\n */\nfunction validateKey(\n key: string,\n storage: Storage | Map<string, string> | null\n): void {\n if (!storage) {\n throw new Error('Storage is not available (unavailable environment).');\n }\n\n if (!key || key.trim() === '') {\n throw new Error('Storage key cannot be empty or whitespace.');\n }\n\n if (DANGEROUS_KEYS.includes(key as never)) {\n throw new Error(\n `Storage key \"${key}\" is not allowed as it may cause prototype pollution.`\n );\n }\n}\n\n/**\n * Checks if a stored item is expired.\n *\n * @param expiry - The expiry timestamp or null if no expiry.\n * @returns True if the item is expired; false otherwise.\n */\nfunction isExpired(expiry: number | null): boolean {\n if (expiry === null) return false;\n return Date.now() > expiry;\n}\n\n/**\n * Calculates the byte size of a string.\n *\n * @param str - The string to measure.\n * @returns The size in bytes.\n */\nfunction getByteSize(str: string): number {\n return new Blob([str]).size;\n}\n\n/**\n * Checks if an error is a quota exceeded error.\n *\n * @param error - The error to check.\n * @returns True if the error is a quota exceeded error.\n */\nfunction isQuotaExceededError(error: unknown): boolean {\n return (\n error instanceof DOMException &&\n (error.name === 'QuotaExceededError' ||\n error.name === 'NS_ERROR_DOM_QUOTA_REACHED')\n );\n}\n\n/**\n * Checks if an error is a circular reference error.\n *\n * @param error - The error to check.\n * @returns True if the error is a circular reference error.\n */\nfunction isCircularReferenceError(error: unknown): boolean {\n return error instanceof TypeError && error.message.includes('circular');\n}\n\n/**\n * Checks if the data record has the correct structure.\n *\n * @param parsed - The parsed data to validate.\n * @returns True if the data record has the correct structure; false otherwise.\n */\nfunction isValidDataRecord(parsed: unknown): boolean {\n return (\n typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)\n );\n}\n\n/**\n * Checks if the window is available.\n *\n * @returns True if the window is available.\n */\nfunction isWindowAvailable(): boolean {\n return typeof window !== 'undefined';\n}\n\nexport {\n validateKey,\n isExpired,\n getByteSize,\n isQuotaExceededError,\n isCircularReferenceError,\n isValidDataRecord,\n isWindowAvailable,\n};\n","import { isWindowAvailable } from '../utils/helpers';\nimport type { StorageLogger, StorageType } from '../utils/types';\n\n/**\n * Storage backend abstraction layer.\n * Handles initialization and access to different storage types.\n */\nclass StorageBackend {\n private storage: Storage | Map<string, string> | null = null;\n private unloadHandler: (() => void) | null = null;\n\n constructor(\n private storageType: StorageType,\n private logger?: StorageLogger\n ) {\n this.initialize();\n }\n\n /**\n * Initializes the storage backend based on the storage type.\n */\n private initialize(): void {\n // Explicitly requested in-memory storage\n if (this.storageType === 'in-memory') {\n this.storage = new Map();\n return;\n }\n\n // Try to use web storage (localStorage or sessionStorage)\n if (isWindowAvailable()) {\n try {\n this.storage =\n this.storageType === 'session' ? sessionStorage : localStorage;\n } catch (e) {\n // Fallback to in-memory storage (Map) if accessing web storage throws an error\n // This can happen in private browsing mode or when storage is disabled\n this.logger?.log(\n 'Web storage is not accessible. Falling back to in-memory storage.',\n e\n );\n this.storage = new Map();\n }\n } else {\n // SSR is expected behavior - use in-memory fallback without logging\n this.storage = new Map();\n }\n }\n\n /**\n * Gets the underlying storage instance.\n */\n getStorage(): Storage | Map<string, string> | null {\n return this.storage;\n }\n\n /**\n * Reads data from storage.\n */\n read(key: string): string | null {\n if (!this.storage) return null;\n\n if (this.storage instanceof Map) {\n return this.storage.get(key) ?? null;\n }\n\n return this.storage.getItem(key);\n }\n\n /**\n * Writes data to storage.\n */\n write(key: string, value: string): void {\n if (!this.storage) return;\n\n if (this.storage instanceof Map) {\n this.storage.set(key, value);\n } else {\n this.storage.setItem(key, value);\n }\n }\n\n /**\n * Removes data from storage.\n */\n remove(key: string): void {\n if (!this.storage) return;\n\n if (this.storage instanceof Map) {\n this.storage.delete(key);\n } else {\n this.storage.removeItem(key);\n }\n }\n\n /**\n * Checks if storage is available.\n */\n isAvailable(): boolean {\n return this.storage !== null;\n }\n\n /**\n * Gets the storage type.\n */\n getStorageType():\n | 'localStorage'\n | 'sessionStorage'\n | 'memory'\n | 'unavailable' {\n if (!this.storage) return 'unavailable';\n if (this.storage instanceof Map) return 'memory';\n if (this.storage === localStorage) return 'localStorage';\n if (this.storage === sessionStorage) return 'sessionStorage';\n return 'unavailable';\n }\n\n /**\n * Registers a beforeunload handler for the storage backend.\n */\n registerUnloadHandler(handler: () => void): void {\n if (isWindowAvailable() && !this.unloadHandler) {\n this.unloadHandler = handler;\n window.addEventListener('beforeunload', this.unloadHandler);\n }\n }\n\n /**\n * Cleans up event listeners.\n */\n cleanup(): void {\n if (isWindowAvailable() && this.unloadHandler) {\n window.removeEventListener('beforeunload', this.unloadHandler);\n this.unloadHandler = null;\n }\n }\n}\n\nexport { StorageBackend };\n","import { TransformPipeline } from '../transforms/pipeline';\nimport {\n DEFAULT_DEBOUNCE_MS,\n DEFAULT_MAX_ITEMS_IN_MEMORY,\n DEFAULT_MAX_SIZE_BYTES,\n DEFAULT_STORAGE_KEY,\n DEFAULT_STORAGE_TYPE,\n} from '../utils/constants';\nimport {\n getByteSize,\n isCircularReferenceError,\n isExpired,\n isQuotaExceededError,\n isValidDataRecord,\n validateKey,\n} from '../utils/helpers';\nimport type {\n DataRecord,\n StorageLogger,\n StorageStats,\n StorageVaultOptions,\n StoredData,\n} from '../utils/types';\nimport { StorageBackend } from './storage-backend';\n\n/**\n * StorageVault - A unified wrapper around Web Storage with TTL, transforms, and safe handling.\n *\n * @see README.md for comprehensive documentation\n */\nclass StorageVault {\n private static instances = new Map<string, StorageVault>();\n\n private backend: StorageBackend;\n private transformPipeline: TransformPipeline;\n private storageKey: string;\n private logger?: StorageLogger;\n private maxSizeBytes: number;\n private maxItemsInMemory: number;\n private debounceMs: number;\n private isCleaningUp = false;\n private pendingSave: ReturnType<typeof setTimeout> | null = null;\n private dirtyData: DataRecord | null = null;\n\n /**\n * Gets or creates a singleton instance of StorageVault.\n */\n static getInstance(options: StorageVaultOptions = {}): StorageVault {\n const {\n storageType = DEFAULT_STORAGE_TYPE,\n storageKey = DEFAULT_STORAGE_KEY,\n logger,\n maxSizeBytes = DEFAULT_MAX_SIZE_BYTES,\n maxItemsInMemory = DEFAULT_MAX_ITEMS_IN_MEMORY,\n debounceMs = DEFAULT_DEBOUNCE_MS,\n transforms = [],\n } = options;\n\n const key = `${storageType}-${storageKey}`;\n\n if (!StorageVault.instances.has(key)) {\n StorageVault.instances.set(\n key,\n new StorageVault({\n storageType,\n storageKey,\n logger,\n maxSizeBytes,\n maxItemsInMemory,\n debounceMs,\n transforms,\n })\n );\n }\n\n const instance = StorageVault.instances.get(key);\n if (!instance) {\n logger?.log('Failed to create or retrieve StorageVault instance', {\n key,\n });\n throw new Error(\n `Failed to create or retrieve StorageVault instance: ${key}`\n );\n }\n\n return instance;\n }\n\n /**\n * Removes an instance from the singleton map.\n */\n static disposeInstance(options: StorageVaultOptions = {}): boolean {\n const {\n storageType = DEFAULT_STORAGE_TYPE,\n storageKey = DEFAULT_STORAGE_KEY,\n } = options;\n\n const key = `${storageType}-${storageKey}`;\n const instance = StorageVault.instances.get(key);\n\n if (instance) {\n instance.flush();\n instance.cleanup();\n }\n\n return StorageVault.instances.delete(key);\n }\n\n /**\n * Clears all instances from memory. Useful for testing.\n */\n static clearAllInstances(): void {\n StorageVault.instances.forEach((instance) => {\n instance.flush();\n instance.cleanup();\n });\n StorageVault.instances.clear();\n }\n\n /**\n * Creates a new StorageVault instance (private - use getInstance instead).\n */\n private constructor(options: StorageVaultOptions = {}) {\n const {\n storageType = DEFAULT_STORAGE_TYPE,\n storageKey = DEFAULT_STORAGE_KEY,\n logger,\n maxSizeBytes = DEFAULT_MAX_SIZE_BYTES,\n maxItemsInMemory = DEFAULT_MAX_ITEMS_IN_MEMORY,\n debounceMs = DEFAULT_DEBOUNCE_MS,\n transforms = [],\n } = options;\n\n this.logger = logger;\n this.storageKey = storageKey;\n this.maxSizeBytes = maxSizeBytes;\n this.maxItemsInMemory = maxItemsInMemory;\n this.debounceMs = debounceMs;\n this.backend = new StorageBackend(storageType, logger);\n this.transformPipeline = new TransformPipeline(transforms, logger);\n\n // Setup beforeunload handler to flush pending writes\n this.backend.registerUnloadHandler(() => {\n if (this.dirtyData) {\n this.saveAllDataImmediate(this.dirtyData);\n this.dirtyData = null;\n }\n });\n }\n\n /**\n * Reads and deserializes all data from storage.\n */\n private getAllData(): DataRecord {\n const storage = this.backend.getStorage();\n if (!storage) return {};\n\n // Return dirty data if we have pending writes (read-after-write consistency)\n if (this.dirtyData !== null) {\n return Object.freeze(this.dirtyData ?? {});\n }\n\n try {\n const dataStr = this.backend.read(this.storageKey);\n if (!dataStr) return {};\n\n // Apply reverse transforms before JSON parsing\n const deserializedStr = this.transformPipeline.reverse(dataStr);\n const parsed = JSON.parse(deserializedStr) as unknown;\n\n // Validate structure to handle corrupted data\n if (!isValidDataRecord(parsed)) {\n throw new Error('Invalid storage data structure');\n }\n\n return parsed as DataRecord;\n } catch (e) {\n this.logger?.log('Storage data corrupted or invalid, clearing storage', {\n error: e,\n storageKey: this.storageKey,\n });\n\n // Clear corrupted storage\n try {\n this.backend.remove(this.storageKey);\n } catch (clearError) {\n this.logger?.log('Failed to clear corrupted storage', clearError);\n }\n\n return {};\n }\n }\n\n /**\n * Serializes and writes data immediately to storage.\n */\n private saveAllDataImmediate(data: DataRecord): void {\n const storage = this.backend.getStorage();\n if (!storage) return;\n\n // Enforce max items limit for in-memory storage\n if (storage instanceof Map) {\n const itemCount = Object.keys(data).length;\n if (itemCount > this.maxItemsInMemory) {\n this.logger?.log(\n 'In-memory storage item limit exceeded, cleaning up oldest items',\n {\n itemCount,\n maxItems: this.maxItemsInMemory,\n }\n );\n this.enforceItemLimit(data);\n }\n }\n\n try {\n const dataStr = JSON.stringify(data);\n const transformedStr = this.transformPipeline.apply(dataStr);\n const byteSize = getByteSize(transformedStr);\n\n // Check size and warn if approaching quota\n if (byteSize > this.maxSizeBytes) {\n this.logger?.log('Storage approaching quota limit', {\n byteSize,\n stringLength: transformedStr.length,\n maxSizeBytes: this.maxSizeBytes,\n });\n }\n\n this.backend.write(this.storageKey, transformedStr);\n } catch (e) {\n this.handleSaveError(e);\n }\n }\n\n /**\n * Handles errors during save operations.\n */\n private handleSaveError(error: unknown): void {\n if (isQuotaExceededError(error)) {\n if (!this.isCleaningUp) {\n this.logger?.log('Storage quota exceeded, attempting cleanup', error);\n this.isCleaningUp = true;\n\n try {\n const removedCount = this.cleanupExpiredItems();\n this.logger?.log(`Cleanup removed ${removedCount} expired items`);\n\n // Retry after cleanup\n const freshData = this.getAllData();\n const dataStr = JSON.stringify(freshData);\n const transformedStr = this.transformPipeline.apply(dataStr);\n this.backend.write(this.storageKey, transformedStr);\n } catch (retryError) {\n this.logger?.log(\n 'Storage quota exceeded even after cleanup',\n retryError\n );\n throw new Error(\n 'Storage quota exceeded. Clear some data or use storage slices to reduce size.'\n );\n } finally {\n this.isCleaningUp = false;\n }\n } else {\n this.logger?.log(\n 'Already cleaning up, skipping recursive cleanup',\n error\n );\n throw new Error('Storage quota exceeded during cleanup');\n }\n } else if (isCircularReferenceError(error)) {\n this.logger?.log('Circular reference detected in stored data', error);\n throw new Error(\n 'Cannot store data with circular references. Serialize manually before storing.'\n );\n } else {\n this.logger?.log('Error saving to storage', error);\n throw new Error(\n `Failed to save to storage: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * Saves data with optional debouncing.\n */\n private saveAllData(data: DataRecord): void {\n if (this.debounceMs > 0) {\n // Debounced write: store in memory first for read-after-write consistency\n this.dirtyData = data;\n\n if (this.pendingSave) {\n clearTimeout(this.pendingSave);\n }\n\n this.pendingSave = setTimeout(() => {\n if (this.dirtyData) {\n try {\n this.saveAllDataImmediate(this.dirtyData);\n this.dirtyData = null;\n } catch (e) {\n this.logger?.log('Debounced save failed', e);\n // Keep dirtyData so next flush/save can retry\n }\n }\n this.pendingSave = null;\n }, this.debounceMs);\n } else {\n // Immediate write (no debouncing)\n this.saveAllDataImmediate(data);\n }\n }\n\n /**\n * Removes an item if it's expired.\n */\n private removeIfExpired(\n key: string,\n item: StoredData<unknown> | undefined,\n data: DataRecord\n ): boolean {\n if (!item) return true;\n\n if (isExpired(item.expiry)) {\n delete data[key];\n return true;\n }\n\n return false;\n }\n\n /**\n * Enforces the maximum item limit for in-memory storage.\n */\n private enforceItemLimit(data: DataRecord): void {\n const keys = Object.keys(data);\n if (keys.length <= this.maxItemsInMemory) return;\n\n // Sort by expiry time (oldest first)\n const sortedKeys = keys.sort((a, b) => {\n const expiryA = data[a]?.expiry ?? Infinity;\n const expiryB = data[b]?.expiry ?? Infinity;\n return expiryA - expiryB;\n });\n\n // Remove oldest items until we're under the limit\n const itemsToRemove = keys.length - this.maxItemsInMemory;\n for (let i = 0; i < itemsToRemove; i++) {\n const keyToDelete = sortedKeys[i];\n if (keyToDelete !== undefined) {\n delete data[keyToDelete];\n }\n }\n }\n\n /**\n * Cleans up resources used by this instance.\n */\n private cleanup(): void {\n // Clear any pending timers\n if (this.pendingSave) {\n clearTimeout(this.pendingSave);\n this.pendingSave = null;\n }\n\n // Remove event listeners\n this.backend.cleanup();\n }\n\n // ==================== PUBLIC API ====================\n\n /**\n * Stores a value with an optional time-to-live (TTL).\n */\n setItem<T>(key: string, value: T, ttl?: number): boolean {\n validateKey(key, this.backend.getStorage());\n\n if (ttl !== undefined && (!Number.isFinite(ttl) || ttl < 0)) {\n throw new Error('TTL must be a non-negative finite number.');\n }\n\n // Handle TTL=0 case: immediately delete the item\n if (ttl === 0) {\n return this.removeItem(key);\n }\n\n const data = this.getAllData();\n const expiry = ttl !== undefined ? Date.now() + ttl : null;\n data[key] = { value, expiry };\n\n this.saveAllData(data);\n return true;\n }\n\n /**\n * Retrieves a stored value by key.\n */\n getItem<T>(key: string): T | null {\n validateKey(key, this.backend.getStorage());\n\n const data = this.getAllData();\n const item = data[key] as StoredData<T> | undefined;\n\n if (!item) return null;\n\n const expired = this.removeIfExpired(key, item, data);\n\n if (expired) {\n this.saveAllData(data);\n return null;\n }\n\n return item.value;\n }\n\n /**\n * Updates the value of an existing item without modifying its expiry time.\n */\n updateItem<T>(key: string, newValue: T): boolean {\n validateKey(key, this.backend.getStorage());\n\n const data = this.getAllData();\n const item = data[key];\n\n if (!item) return false;\n\n const expired = this.removeIfExpired(key, item, data);\n\n if (expired) {\n this.saveAllData(data);\n return false;\n }\n\n item.value = newValue;\n this.saveAllData(data);\n return true;\n }\n\n /**\n * Extends the expiry time of an existing item.\n */\n extendTTL(key: string, additionalTTL: number): boolean {\n validateKey(key, this.backend.getStorage());\n\n if (!Number.isFinite(additionalTTL) || additionalTTL <= 0) {\n throw new Error('additionalTTL must be a positive finite number.');\n }\n\n const data = this.getAllData();\n const item = data[key];\n\n if (!item) return false;\n\n const expired = this.removeIfExpired(key, item, data);\n\n if (expired) {\n this.saveAllData(data);\n return false;\n }\n\n item.expiry =\n item.expiry !== null\n ? item.expiry + additionalTTL\n : Date.now() + additionalTTL;\n this.saveAllData(data);\n return true;\n }\n\n /**\n * Removes an item from storage.\n */\n removeItem(key: string): boolean {\n validateKey(key, this.backend.getStorage());\n\n const data = this.getAllData();\n if (key in data) {\n delete data[key];\n this.saveAllData(data);\n return true;\n }\n\n return false;\n }\n\n /**\n * Clears all stored data under the vault's storage key.\n */\n clear(): boolean {\n if (!this.backend.isAvailable()) {\n throw new Error('Storage is not available (unavailable environment).');\n }\n\n // Cancel any pending writes\n if (this.pendingSave) {\n clearTimeout(this.pendingSave);\n this.pendingSave = null;\n }\n this.dirtyData = null;\n\n try {\n this.backend.remove(this.storageKey);\n return true;\n } catch (error) {\n this.logger?.log('Error clearing storage', {\n error,\n storageKey: this.storageKey,\n });\n throw new Error(\n `Failed to clear storage: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * Checks whether an item exists and is not expired.\n */\n hasItem(key: string): boolean {\n validateKey(key, this.backend.getStorage());\n\n const data = this.getAllData();\n const item = data[key];\n\n if (!item) return false;\n\n const expired = this.removeIfExpired(key, item, data);\n\n if (expired) {\n this.saveAllData(data);\n return false;\n }\n\n return true;\n }\n\n /**\n * Returns the remaining time-to-live (TTL) for a stored item.\n */\n getRemainingTTL(key: string): number | null {\n if (!this.backend.isAvailable()) return null;\n\n const data = this.getAllData();\n const item = data[key];\n\n if (!item || item.expiry === null) return null;\n\n const remainingTime = item.expiry - Date.now();\n\n if (remainingTime <= 0) {\n delete data[key];\n this.saveAllData(data);\n return null;\n }\n\n return remainingTime;\n }\n\n /**\n * Removes all expired items from storage.\n */\n cleanupExpiredItems(): number {\n if (!this.backend.isAvailable()) return 0;\n\n const data = this.getAllData();\n let removedCount = 0;\n const now = Date.now();\n\n for (const key in data) {\n if (Object.prototype.hasOwnProperty.call(data, key)) {\n const item = data[key];\n if (item && item.expiry !== null && now > item.expiry) {\n delete data[key];\n removedCount++;\n }\n }\n }\n\n if (removedCount > 0) {\n this.saveAllDataImmediate(data);\n }\n\n return removedCount;\n }\n\n /**\n * Flushes any pending debounced writes immediately.\n */\n flush(): void {\n if (this.pendingSave) {\n clearTimeout(this.pendingSave);\n this.pendingSave = null;\n }\n\n if (this.dirtyData) {\n this.saveAllDataImmediate(this.dirtyData);\n this.dirtyData = null;\n }\n }\n\n /**\n * Returns all keys currently stored in the vault (excluding expired items).\n */\n getAllKeys(): string[] {\n if (!this.backend.isAvailable()) return [];\n\n const data = this.getAllData();\n const validKeys: string[] = [];\n const now = Date.now();\n\n for (const key in data) {\n if (Object.prototype.hasOwnProperty.call(data, key)) {\n const item = data[key];\n if (item && (item.expiry === null || now <= item.expiry)) {\n validKeys.push(key);\n }\n }\n }\n\n return validKeys;\n }\n\n /**\n * Returns all stored items as a key-value object (excluding expired items).\n */\n getAll(): Record<string, unknown> {\n if (!this.backend.isAvailable()) return {};\n\n const data = this.getAllData();\n const result: Record<string, unknown> = {};\n const now = Date.now();\n\n for (const key in data) {\n if (Object.prototype.hasOwnProperty.call(data, key)) {\n const item = data[key];\n if (item && (item.expiry === null || now <= item.expiry)) {\n result[key] = item.value;\n }\n }\n }\n\n return result;\n }\n\n /**\n * Returns the current size of stored data in bytes.\n */\n getCurrentSize(): number {\n if (!this.backend.isAvailable()) return 0;\n\n try {\n const data = this.getAllData();\n const dataStr = JSON.stringify(data);\n return getByteSize(dataStr);\n } catch (e) {\n this.logger?.log('Error calculating storage size', e);\n return 0;\n }\n }\n\n /**\n * Returns storage statistics.\n */\n getStats(): StorageStats {\n if (!this.backend.isAvailable()) {\n return {\n itemCount: 0,\n sizeBytes: 0,\n stringLength: 0,\n maxSizeBytes: this.maxSizeBytes,\n quotaPercentage: 0,\n storageType: 'unavailable',\n };\n }\n\n const data = this.getAllData();\n const itemCount = Object.keys(data).length;\n const dataStr = JSON.stringify(data);\n const sizeBytes = getByteSize(dataStr);\n const quotaPercentage = (sizeBytes / this.maxSizeBytes) * 100;\n\n return {\n itemCount,\n sizeBytes,\n stringLength: dataStr.length,\n maxSizeBytes: this.maxSizeBytes,\n quotaPercentage,\n storageType: this.backend.getStorageType(),\n };\n }\n}\n\nexport { StorageVault };\n","/**\n * A unified wrapper around Web Storage (localStorage / sessionStorage) with optional in-memory fallback.\n * Supports TTL-based expiration, JSON serialization, transform pipelines, and safe handling for both browser and server environments.\n *\n * All data is stored as a single serialized object under one key to avoid cluttering the storage space.\n *\n * @storage STORAGE TYPES:\n * - 'local': Uses localStorage (persists across browser sessions, ~5-10MB quota)\n * - 'session': Uses sessionStorage (cleared when tab closes, ~5-10MB quota)\n * - 'in-memory': Uses Map (cleared on page reload, useful for testing or temporary data)\n * Specify type via: getStorageSlice('KEY', { storageType: 'session' })\n *\n * @security WARNING: Web Storage is accessible via JavaScript and is NOT secure for sensitive data.\n * Do NOT store authentication tokens, passwords, or other sensitive information here.\n * For sensitive data, use httpOnly cookies or secure server-side sessions instead.\n * All stored data should be treated as potentially compromised and validated on retrieval.\n *\n * @ssr HYDRATION WARNING: During server-side rendering, this vault uses in-memory storage.\n * When hydrating on the client, a new instance with localStorage will be created, but any\n * server-rendered state will be lost. If you need to preserve SSR data, pass initial data\n * as props and call setItem() in useEffect() or similar client-side hook.\n *\n * @serialization JSON LIMITATIONS: Values are serialized with JSON.stringify(), which has limitations:\n * - Functions, undefined, and Symbol values are silently dropped\n * - Date objects become strings (must be manually converted back)\n * - Circular references will throw an error\n * - Map, Set, and other non-plain objects lose their type information\n * For complex data types, serialize them manually before storing.\n *\n * @transforms TRANSFORM PIPELINE: You can chain multiple transforms (compression, encryption, encoding):\n * - Transforms are applied AFTER JSON.stringify (string → string transformations)\n * - Applied in order during writes: serialize → transform1 → transform2 → ... → persist\n * - Reversed during reads: persist → reverse transformN → ... → reverse transform1 → deserialize\n * - Use for: compression (LZ-String), encryption (Web Crypto), encoding (Base64), etc.\n *\n * @performance When to use slices (getStorageSlice):\n * - Split data by update frequency (e.g., user preferences vs. temporary cache)\n * - Isolate large datasets to avoid re-serializing everything on each write\n * - Separate critical data from experimental features\n * Example: getStorageSlice('USER_PREFS') vs getStorageSlice('TEMP_CACHE')\n *\n * @performance DEBOUNCING: Write operations are debounced by default (100ms) to batch rapid updates.\n * - Reads always see pending writes immediately (read-after-write consistency)\n * - Pending writes are automatically flushed on page unload to prevent data loss\n * - For time-critical operations, call flush() to force immediate persistence\n * - Set debounceMs: 0 to disable debouncing (writes become synchronous)\n * - Consider higher debounceMs (200-500ms) for battery-sensitive or high-frequency scenarios\n */\n\nimport { StorageVault } from './core/vault';\nimport type { StorageVaultOptions } from './utils/types';\n\n/**\n * Creates a new StorageVault instance with a custom storage key.\n * Use slices to split large or frequently updated data into independent storage blobs.\n *\n * @param sliceKey - The key to store the data under. Must be unique.\n * @param options - Configuration options for the vault.\n * @returns A StorageVault instance (singleton per sliceKey + storage type).\n *\n * @example\n * // Using different storage types\n * const persistent = getStorageSlice('USER_PREFS', { storageType: 'local' }); // Persists across sessions\n * const temporary = getStorageSlice('SESSION_DATA', { storageType: 'session' }); // Cleared when tab closes\n * const testData = getStorageSlice('TEST_DATA', { storageType: 'in-memory' }); // For testing, cleared on reload\n *\n * @example\n * // Good: Separate frequently-updated data from stable data\n * const userPrefs = getStorageSlice('USER_PREFERENCES'); // Updated rarely\n * const tempCache = getStorageSlice('TEMP_CACHE'); // Updated frequently\n *\n * @example\n * // Using transforms\n * import LZString from 'lz-string';\n *\n * const compressionTransform = {\n * serialize: (data: string) => LZString.compress(data),\n * deserialize: (data: string) => LZString.decompress(data)\n * };\n *\n * const vault = getStorageSlice('LARGE_DATA', {\n * transforms: [compressionTransform]\n * });\n */\nfunction getStorageSlice(\n sliceKey: string,\n options: Omit<StorageVaultOptions, 'storageKey'> = {}\n): StorageVault {\n return StorageVault.getInstance({\n ...options,\n storageKey: sliceKey,\n });\n}\n\n/**\n * Disposes a storage slice instance, removing it from the singleton cache.\n * Call this when you're done with a temporary slice to allow garbage collection.\n *\n * @param sliceKey - The key of the slice to dispose.\n * @param options - The same options used when creating the slice (must match exactly).\n * @returns True if the slice was found and disposed; false otherwise.\n *\n * @example\n * const tempVault = getStorageSlice('TEMP_SESSION', { storageType: 'session' });\n * // ... use vault ...\n * disposeStorageSlice('TEMP_SESSION', { storageType: 'session' }); // Clean up when done\n */\nfunction disposeStorageSlice(\n sliceKey: string,\n options: Omit<StorageVaultOptions, 'storageKey'> = {}\n): boolean {\n return StorageVault.disposeInstance({\n ...options,\n storageKey: sliceKey,\n });\n}\n\nexport {\n // Main API functions\n getStorageSlice,\n disposeStorageSlice,\n StorageVault,\n};\n\nexport type {\n StorageType,\n StorageLogger,\n StorageTransform,\n StorageVaultOptions,\n StorageStats,\n StoredData,\n DataRecord,\n} from './utils/types';\n"]}
1
+ {"version":3,"sources":["../src/transforms/pipeline.ts","../src/utils/constants.ts","../src/utils/helpers.ts","../src/core/storage-backend.ts","../src/core/vault.ts","../src/index.ts"],"names":["TransformPipeline","transforms","logger","data","current","transform","_a","e","DEFAULT_STORAGE_KEY","DANGEROUS_KEYS","DEFAULT_STORAGE_TYPE","validateKey","key","storage","isExpired","expiry","getByteSize","str","isQuotaExceededError","error","isCircularReferenceError","isValidDataRecord","parsed","isWindowAvailable","StorageBackend","storageType","value","handler","_StorageVault","options","storageKey","maxSizeBytes","maxItemsInMemory","debounceMs","instance","_b","_c","dataStr","deserializedStr","clearError","itemCount","transformedStr","byteSize","_d","_e","_f","removedCount","freshData","retryError","item","keys","sortedKeys","a","b","expiryA","expiryB","itemsToRemove","keyToDelete","ttl","newValue","additionalTTL","remainingTime","now","validKeys","result","sizeBytes","quotaPercentage","StorageVault","getStorageSlice","sliceKey","disposeStorageSlice"],"mappings":"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","file":"index.js","sourcesContent":["import type { StorageLogger, StorageTransform } from '../utils/types';\n\n/**\n * Transform pipeline manager.\n * Handles chaining of multiple transforms for serialization and deserialization.\n */\nclass TransformPipeline {\n constructor(\n private transforms: StorageTransform[],\n private logger?: StorageLogger\n ) {}\n\n /**\n * Applies transform pipeline in order: serialize → transform1 → transform2 → ... → transformN\n *\n * @param data - The serialized JSON string.\n * @returns The transformed string ready for persistence.\n */\n apply(data: string): string {\n return this.transforms.reduce((current, transform) => {\n try {\n return transform.serialize(current);\n } catch (e) {\n this.logger?.log('Transform serialize failed', e);\n throw new Error(\n `Transform pipeline failed: ${e instanceof Error ? e.message : String(e)}`\n );\n }\n }, data);\n }\n\n /**\n * Reverses transform pipeline: transformN → ... → transform2 → transform1 → deserialize\n *\n * @param data - The transformed string from storage.\n * @returns The original serialized JSON string.\n */\n reverse(data: string): string {\n return this.transforms.reduceRight((current, transform) => {\n try {\n return transform.deserialize(current);\n } catch (e) {\n this.logger?.log('Transform deserialize failed', e);\n throw new Error(\n `Transform pipeline reversal failed: ${e instanceof Error ? e.message : String(e)}`\n );\n }\n }, data);\n }\n\n /**\n * Checks if any transforms are configured.\n */\n hasTransforms(): boolean {\n return this.transforms.length > 0;\n }\n}\n\nexport { TransformPipeline };\n","/**\n * Default storage key used when none is specified.\n */\nconst DEFAULT_STORAGE_KEY = 'APP_DATA';\n\n/**\n * Default maximum size in bytes (~4MB).\n * Typical localStorage quota is 5-10MB per origin.\n */\nconst DEFAULT_MAX_SIZE_BYTES = 4_000_000;\n\n/**\n * Default maximum items for in-memory storage to prevent memory leaks.\n */\nconst DEFAULT_MAX_ITEMS_IN_MEMORY = 1000;\n\n/**\n * Dangerous keys that could cause prototype pollution attacks.\n */\nconst DANGEROUS_KEYS = ['__proto__', 'constructor', 'prototype'] as const;\n\n/**\n * Default debounce time in milliseconds.\n * Balance between performance and data safety.\n */\nconst DEFAULT_DEBOUNCE_MS = 100;\n\n/**\n * Default storage type (localStorage).\n */\nconst DEFAULT_STORAGE_TYPE = 'local';\n\nexport {\n DEFAULT_STORAGE_KEY,\n DEFAULT_MAX_SIZE_BYTES,\n DEFAULT_MAX_ITEMS_IN_MEMORY,\n DANGEROUS_KEYS,\n DEFAULT_DEBOUNCE_MS,\n DEFAULT_STORAGE_TYPE,\n};\n","import { DANGEROUS_KEYS } from './constants';\n\n/**\n * Validates a storage key.\n *\n * @param key - The key to validate.\n * @param storage - The storage instance to check availability.\n * @throws Will throw if storage is unavailable.\n * @throws Will throw if key is empty, contains only whitespace, or is a dangerous key.\n */\nfunction validateKey(\n key: string,\n storage: Storage | Map<string, string> | null\n): void {\n if (!storage) {\n throw new Error('Storage is not available (unavailable environment).');\n }\n\n if (!key || key.trim() === '') {\n throw new Error('Storage key cannot be empty or whitespace.');\n }\n\n if (DANGEROUS_KEYS.includes(key as never)) {\n throw new Error(\n `Storage key \"${key}\" is not allowed as it may cause prototype pollution.`\n );\n }\n}\n\n/**\n * Checks if a stored item is expired.\n *\n * @param expiry - The expiry timestamp or null if no expiry.\n * @returns True if the item is expired; false otherwise.\n */\nfunction isExpired(expiry: number | null): boolean {\n if (expiry === null) return false;\n return Date.now() > expiry;\n}\n\n/**\n * Calculates the byte size of a string.\n *\n * @param str - The string to measure.\n * @returns The size in bytes.\n */\nfunction getByteSize(str: string): number {\n return new Blob([str]).size;\n}\n\n/**\n * Checks if an error is a quota exceeded error.\n *\n * @param error - The error to check.\n * @returns True if the error is a quota exceeded error.\n */\nfunction isQuotaExceededError(error: unknown): boolean {\n return (\n error instanceof DOMException &&\n (error.name === 'QuotaExceededError' ||\n error.name === 'NS_ERROR_DOM_QUOTA_REACHED')\n );\n}\n\n/**\n * Checks if an error is a circular reference error.\n *\n * @param error - The error to check.\n * @returns True if the error is a circular reference error.\n */\nfunction isCircularReferenceError(error: unknown): boolean {\n return error instanceof TypeError && error.message.includes('circular');\n}\n\n/**\n * Checks if the data record has the correct structure.\n *\n * @param parsed - The parsed data to validate.\n * @returns True if the data record has the correct structure; false otherwise.\n */\nfunction isValidDataRecord(parsed: unknown): boolean {\n return (\n typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)\n );\n}\n\n/**\n * Checks if the window is available.\n *\n * @returns True if the window is available.\n */\nfunction isWindowAvailable(): boolean {\n return typeof window !== 'undefined';\n}\n\nexport {\n validateKey,\n isExpired,\n getByteSize,\n isQuotaExceededError,\n isCircularReferenceError,\n isValidDataRecord,\n isWindowAvailable,\n};\n","import { isWindowAvailable } from '../utils/helpers';\nimport type { StorageLogger, StorageType } from '../utils/types';\n\n/**\n * Storage backend abstraction layer.\n * Handles initialization and access to different storage types.\n */\nclass StorageBackend {\n private storage: Storage | Map<string, string> | null = null;\n private unloadHandler: (() => void) | null = null;\n\n constructor(\n private storageType: StorageType,\n private logger?: StorageLogger\n ) {\n this.initialize();\n }\n\n /**\n * Initializes the storage backend based on the storage type.\n */\n private initialize(): void {\n // Explicitly requested in-memory storage\n if (this.storageType === 'in-memory') {\n this.storage = new Map();\n return;\n }\n\n // Try to use web storage (localStorage or sessionStorage)\n if (isWindowAvailable()) {\n try {\n this.storage =\n this.storageType === 'session' ? sessionStorage : localStorage;\n } catch (e) {\n // Fallback to in-memory storage (Map) if accessing web storage throws an error\n // This can happen in private browsing mode or when storage is disabled\n this.logger?.log(\n 'Web storage is not accessible. Falling back to in-memory storage.',\n e\n );\n this.storage = new Map();\n }\n } else {\n // SSR is expected behavior - use in-memory fallback without logging\n this.storage = new Map();\n }\n }\n\n /**\n * Gets the underlying storage instance.\n */\n getStorage(): Storage | Map<string, string> | null {\n return this.storage;\n }\n\n /**\n * Reads data from storage.\n */\n read(key: string): string | null {\n if (!this.storage) return null;\n\n if (this.storage instanceof Map) {\n return this.storage.get(key) ?? null;\n }\n\n return this.storage.getItem(key);\n }\n\n /**\n * Writes data to storage.\n */\n write(key: string, value: string): void {\n if (!this.storage) return;\n\n if (this.storage instanceof Map) {\n this.storage.set(key, value);\n } else {\n this.storage.setItem(key, value);\n }\n }\n\n /**\n * Removes data from storage.\n */\n remove(key: string): void {\n if (!this.storage) return;\n\n if (this.storage instanceof Map) {\n this.storage.delete(key);\n } else {\n this.storage.removeItem(key);\n }\n }\n\n /**\n * Checks if storage is available.\n */\n isAvailable(): boolean {\n return this.storage !== null;\n }\n\n /**\n * Gets the storage type.\n */\n getStorageType():\n | 'localStorage'\n | 'sessionStorage'\n | 'memory'\n | 'unavailable' {\n if (!this.storage) return 'unavailable';\n if (this.storage instanceof Map) return 'memory';\n if (this.storage === localStorage) return 'localStorage';\n if (this.storage === sessionStorage) return 'sessionStorage';\n return 'unavailable';\n }\n\n /**\n * Registers a pagehide handler for the storage backend.\n */\n registerUnloadHandler(handler: () => void): void {\n if (isWindowAvailable() && !this.unloadHandler) {\n this.unloadHandler = handler;\n window.addEventListener('pagehide', this.unloadHandler);\n }\n }\n\n /**\n * Cleans up event listeners.\n */\n cleanup(): void {\n if (isWindowAvailable() && this.unloadHandler) {\n window.removeEventListener('pagehide', this.unloadHandler);\n this.unloadHandler = null;\n }\n }\n}\n\nexport { StorageBackend };\n","import { TransformPipeline } from '../transforms/pipeline';\nimport {\n DEFAULT_DEBOUNCE_MS,\n DEFAULT_MAX_ITEMS_IN_MEMORY,\n DEFAULT_MAX_SIZE_BYTES,\n DEFAULT_STORAGE_KEY,\n DEFAULT_STORAGE_TYPE,\n} from '../utils/constants';\nimport {\n getByteSize,\n isCircularReferenceError,\n isExpired,\n isQuotaExceededError,\n isValidDataRecord,\n validateKey,\n} from '../utils/helpers';\nimport type {\n DataRecord,\n StorageLogger,\n StorageStats,\n StorageVaultOptions,\n StoredData,\n} from '../utils/types';\nimport { StorageBackend } from './storage-backend';\n\n/**\n * StorageVault - A unified wrapper around Web Storage with TTL, transforms, and safe handling.\n *\n * @see README.md for comprehensive documentation\n */\nclass StorageVault {\n private static instances = new Map<string, StorageVault>();\n\n private backend: StorageBackend;\n private transformPipeline: TransformPipeline;\n private storageKey: string;\n private logger?: StorageLogger;\n private maxSizeBytes: number;\n private maxItemsInMemory: number;\n private debounceMs: number;\n private isCleaningUp = false;\n private pendingSave: ReturnType<typeof setTimeout> | null = null;\n private dirtyData: DataRecord | null = null;\n\n /**\n * Gets or creates a singleton instance of StorageVault.\n */\n static getInstance(options: StorageVaultOptions = {}): StorageVault {\n const {\n storageType = DEFAULT_STORAGE_TYPE,\n storageKey = DEFAULT_STORAGE_KEY,\n logger,\n maxSizeBytes = DEFAULT_MAX_SIZE_BYTES,\n maxItemsInMemory = DEFAULT_MAX_ITEMS_IN_MEMORY,\n debounceMs = DEFAULT_DEBOUNCE_MS,\n transforms = [],\n } = options;\n\n const key = `${storageType}-${storageKey}`;\n\n if (!StorageVault.instances.has(key)) {\n StorageVault.instances.set(\n key,\n new StorageVault({\n storageType,\n storageKey,\n logger,\n maxSizeBytes,\n maxItemsInMemory,\n debounceMs,\n transforms,\n })\n );\n }\n\n const instance = StorageVault.instances.get(key);\n if (!instance) {\n logger?.log('Failed to create or retrieve StorageVault instance', {\n key,\n });\n throw new Error(\n `Failed to create or retrieve StorageVault instance: ${key}`\n );\n }\n\n return instance;\n }\n\n /**\n * Removes an instance from the singleton map.\n */\n static disposeInstance(options: StorageVaultOptions = {}): boolean {\n const {\n storageType = DEFAULT_STORAGE_TYPE,\n storageKey = DEFAULT_STORAGE_KEY,\n } = options;\n\n const key = `${storageType}-${storageKey}`;\n const instance = StorageVault.instances.get(key);\n\n if (instance) {\n instance.flush();\n instance.cleanup();\n }\n\n return StorageVault.instances.delete(key);\n }\n\n /**\n * Clears all instances from memory. Useful for testing.\n */\n static clearAllInstances(): void {\n StorageVault.instances.forEach((instance) => {\n instance.flush();\n instance.cleanup();\n });\n StorageVault.instances.clear();\n }\n\n /**\n * Creates a new StorageVault instance (private - use getInstance instead).\n */\n private constructor(options: StorageVaultOptions = {}) {\n const {\n storageType = DEFAULT_STORAGE_TYPE,\n storageKey = DEFAULT_STORAGE_KEY,\n logger,\n maxSizeBytes = DEFAULT_MAX_SIZE_BYTES,\n maxItemsInMemory = DEFAULT_MAX_ITEMS_IN_MEMORY,\n debounceMs = DEFAULT_DEBOUNCE_MS,\n transforms = [],\n } = options;\n\n this.logger = logger;\n this.storageKey = storageKey;\n this.maxSizeBytes = maxSizeBytes;\n this.maxItemsInMemory = maxItemsInMemory;\n this.debounceMs = debounceMs;\n this.backend = new StorageBackend(storageType, logger);\n this.transformPipeline = new TransformPipeline(transforms, logger);\n\n // Setup pagehide handler to flush pending writes\n this.backend.registerUnloadHandler(() => {\n if (this.dirtyData) {\n this.saveAllDataImmediate(this.dirtyData);\n this.dirtyData = null;\n }\n });\n }\n\n /**\n * Reads and deserializes all data from storage.\n */\n private getAllData(): DataRecord {\n const storage = this.backend.getStorage();\n if (!storage) return {};\n\n // Return dirty data if we have pending writes (read-after-write consistency)\n if (this.dirtyData !== null) {\n return Object.freeze(this.dirtyData ?? {});\n }\n\n try {\n const dataStr = this.backend.read(this.storageKey);\n if (!dataStr) return {};\n\n // Apply reverse transforms before JSON parsing\n const deserializedStr = this.transformPipeline.reverse(dataStr);\n const parsed = JSON.parse(deserializedStr) as unknown;\n\n // Validate structure to handle corrupted data\n if (!isValidDataRecord(parsed)) {\n throw new Error('Invalid storage data structure');\n }\n\n return parsed as DataRecord;\n } catch (e) {\n this.logger?.log('Storage data corrupted or invalid, clearing storage', {\n error: e,\n storageKey: this.storageKey,\n });\n\n // Clear corrupted storage\n try {\n this.backend.remove(this.storageKey);\n } catch (clearError) {\n this.logger?.log('Failed to clear corrupted storage', clearError);\n }\n\n return {};\n }\n }\n\n /**\n * Serializes and writes data immediately to storage.\n */\n private saveAllDataImmediate(data: DataRecord): void {\n const storage = this.backend.getStorage();\n if (!storage) return;\n\n // Enforce max items limit for in-memory storage\n if (storage instanceof Map) {\n const itemCount = Object.keys(data).length;\n if (itemCount > this.maxItemsInMemory) {\n this.logger?.log(\n 'In-memory storage item limit exceeded, cleaning up oldest items',\n {\n itemCount,\n maxItems: this.maxItemsInMemory,\n }\n );\n this.enforceItemLimit(data);\n }\n }\n\n try {\n const dataStr = JSON.stringify(data);\n const transformedStr = this.transformPipeline.apply(dataStr);\n const byteSize = getByteSize(transformedStr);\n\n // Check size and warn if approaching quota\n if (byteSize > this.maxSizeBytes) {\n this.logger?.log('Storage approaching quota limit', {\n byteSize,\n stringLength: transformedStr.length,\n maxSizeBytes: this.maxSizeBytes,\n });\n }\n\n this.backend.write(this.storageKey, transformedStr);\n } catch (e) {\n this.handleSaveError(e);\n }\n }\n\n /**\n * Handles errors during save operations.\n */\n private handleSaveError(error: unknown): void {\n if (isQuotaExceededError(error)) {\n if (!this.isCleaningUp) {\n this.logger?.log('Storage quota exceeded, attempting cleanup', error);\n this.isCleaningUp = true;\n\n try {\n const removedCount = this.cleanupExpiredItems();\n this.logger?.log(`Cleanup removed ${removedCount} expired items`);\n\n // Retry after cleanup\n const freshData = this.getAllData();\n const dataStr = JSON.stringify(freshData);\n const transformedStr = this.transformPipeline.apply(dataStr);\n this.backend.write(this.storageKey, transformedStr);\n } catch (retryError) {\n this.logger?.log(\n 'Storage quota exceeded even after cleanup',\n retryError\n );\n throw new Error(\n 'Storage quota exceeded. Clear some data or use storage slices to reduce size.'\n );\n } finally {\n this.isCleaningUp = false;\n }\n } else {\n this.logger?.log(\n 'Already cleaning up, skipping recursive cleanup',\n error\n );\n throw new Error('Storage quota exceeded during cleanup');\n }\n } else if (isCircularReferenceError(error)) {\n this.logger?.log('Circular reference detected in stored data', error);\n throw new Error(\n 'Cannot store data with circular references. Serialize manually before storing.'\n );\n } else {\n this.logger?.log('Error saving to storage', error);\n throw new Error(\n `Failed to save to storage: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * Saves data with optional debouncing.\n */\n private saveAllData(data: DataRecord): void {\n if (this.debounceMs > 0) {\n // Debounced write: store in memory first for read-after-write consistency\n this.dirtyData = data;\n\n if (this.pendingSave) {\n clearTimeout(this.pendingSave);\n }\n\n this.pendingSave = setTimeout(() => {\n if (this.dirtyData) {\n try {\n this.saveAllDataImmediate(this.dirtyData);\n this.dirtyData = null;\n } catch (e) {\n this.logger?.log('Debounced save failed', e);\n // Keep dirtyData so next flush/save can retry\n }\n }\n this.pendingSave = null;\n }, this.debounceMs);\n } else {\n // Immediate write (no debouncing)\n this.saveAllDataImmediate(data);\n }\n }\n\n /**\n * Removes an item if it's expired.\n */\n private removeIfExpired(\n key: string,\n item: StoredData<unknown> | undefined,\n data: DataRecord\n ): boolean {\n if (!item) return true;\n\n if (isExpired(item.expiry)) {\n delete data[key];\n return true;\n }\n\n return false;\n }\n\n /**\n * Enforces the maximum item limit for in-memory storage.\n */\n private enforceItemLimit(data: DataRecord): void {\n const keys = Object.keys(data);\n if (keys.length <= this.maxItemsInMemory) return;\n\n // Sort by expiry time (oldest first)\n const sortedKeys = keys.sort((a, b) => {\n const expiryA = data[a]?.expiry ?? Infinity;\n const expiryB = data[b]?.expiry ?? Infinity;\n return expiryA - expiryB;\n });\n\n // Remove oldest items until we're under the limit\n const itemsToRemove = keys.length - this.maxItemsInMemory;\n for (let i = 0; i < itemsToRemove; i++) {\n const keyToDelete = sortedKeys[i];\n if (keyToDelete !== undefined) {\n delete data[keyToDelete];\n }\n }\n }\n\n /**\n * Cleans up resources used by this instance.\n */\n private cleanup(): void {\n // Clear any pending timers\n if (this.pendingSave) {\n clearTimeout(this.pendingSave);\n this.pendingSave = null;\n }\n\n // Remove event listeners\n this.backend.cleanup();\n }\n\n // ==================== PUBLIC API ====================\n\n /**\n * Stores a value with an optional time-to-live (TTL).\n */\n setItem<T>(key: string, value: T, ttl?: number): boolean {\n validateKey(key, this.backend.getStorage());\n\n if (ttl !== undefined && (!Number.isFinite(ttl) || ttl < 0)) {\n throw new Error('TTL must be a non-negative finite number.');\n }\n\n // Handle TTL=0 case: immediately delete the item\n if (ttl === 0) {\n return this.removeItem(key);\n }\n\n const data = this.getAllData();\n const expiry = ttl !== undefined ? Date.now() + ttl : null;\n data[key] = { value, expiry };\n\n this.saveAllData(data);\n return true;\n }\n\n /**\n * Retrieves a stored value by key.\n */\n getItem<T>(key: string): T | null {\n validateKey(key, this.backend.getStorage());\n\n const data = this.getAllData();\n const item = data[key] as StoredData<T> | undefined;\n\n if (!item) return null;\n\n const expired = this.removeIfExpired(key, item, data);\n\n if (expired) {\n this.saveAllData(data);\n return null;\n }\n\n return item.value;\n }\n\n /**\n * Updates the value of an existing item without modifying its expiry time.\n */\n updateItem<T>(key: string, newValue: T): boolean {\n validateKey(key, this.backend.getStorage());\n\n const data = this.getAllData();\n const item = data[key];\n\n if (!item) return false;\n\n const expired = this.removeIfExpired(key, item, data);\n\n if (expired) {\n this.saveAllData(data);\n return false;\n }\n\n item.value = newValue;\n this.saveAllData(data);\n return true;\n }\n\n /**\n * Extends the expiry time of an existing item.\n */\n extendTTL(key: string, additionalTTL: number): boolean {\n validateKey(key, this.backend.getStorage());\n\n if (!Number.isFinite(additionalTTL) || additionalTTL <= 0) {\n throw new Error('additionalTTL must be a positive finite number.');\n }\n\n const data = this.getAllData();\n const item = data[key];\n\n if (!item) return false;\n\n const expired = this.removeIfExpired(key, item, data);\n\n if (expired) {\n this.saveAllData(data);\n return false;\n }\n\n item.expiry =\n item.expiry !== null\n ? item.expiry + additionalTTL\n : Date.now() + additionalTTL;\n this.saveAllData(data);\n return true;\n }\n\n /**\n * Removes an item from storage.\n */\n removeItem(key: string): boolean {\n validateKey(key, this.backend.getStorage());\n\n const data = this.getAllData();\n if (key in data) {\n delete data[key];\n this.saveAllData(data);\n return true;\n }\n\n return false;\n }\n\n /**\n * Clears all stored data under the vault's storage key.\n */\n clear(): boolean {\n if (!this.backend.isAvailable()) {\n throw new Error('Storage is not available (unavailable environment).');\n }\n\n // Cancel any pending writes\n if (this.pendingSave) {\n clearTimeout(this.pendingSave);\n this.pendingSave = null;\n }\n this.dirtyData = null;\n\n try {\n this.backend.remove(this.storageKey);\n return true;\n } catch (error) {\n this.logger?.log('Error clearing storage', {\n error,\n storageKey: this.storageKey,\n });\n throw new Error(\n `Failed to clear storage: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * Checks whether an item exists and is not expired.\n */\n hasItem(key: string): boolean {\n validateKey(key, this.backend.getStorage());\n\n const data = this.getAllData();\n const item = data[key];\n\n if (!item) return false;\n\n const expired = this.removeIfExpired(key, item, data);\n\n if (expired) {\n this.saveAllData(data);\n return false;\n }\n\n return true;\n }\n\n /**\n * Returns the remaining time-to-live (TTL) for a stored item.\n */\n getRemainingTTL(key: string): number | null {\n if (!this.backend.isAvailable()) return null;\n\n const data = this.getAllData();\n const item = data[key];\n\n if (!item || item.expiry === null) return null;\n\n const remainingTime = item.expiry - Date.now();\n\n if (remainingTime <= 0) {\n delete data[key];\n this.saveAllData(data);\n return null;\n }\n\n return remainingTime;\n }\n\n /**\n * Removes all expired items from storage.\n */\n cleanupExpiredItems(): number {\n if (!this.backend.isAvailable()) return 0;\n\n const data = this.getAllData();\n let removedCount = 0;\n const now = Date.now();\n\n for (const key in data) {\n if (Object.prototype.hasOwnProperty.call(data, key)) {\n const item = data[key];\n if (item && item.expiry !== null && now > item.expiry) {\n delete data[key];\n removedCount++;\n }\n }\n }\n\n if (removedCount > 0) {\n this.saveAllDataImmediate(data);\n }\n\n return removedCount;\n }\n\n /**\n * Flushes any pending debounced writes immediately.\n */\n flush(): void {\n if (this.pendingSave) {\n clearTimeout(this.pendingSave);\n this.pendingSave = null;\n }\n\n if (this.dirtyData) {\n this.saveAllDataImmediate(this.dirtyData);\n this.dirtyData = null;\n }\n }\n\n /**\n * Returns all keys currently stored in the vault (excluding expired items).\n */\n getAllKeys(): string[] {\n if (!this.backend.isAvailable()) return [];\n\n const data = this.getAllData();\n const validKeys: string[] = [];\n const now = Date.now();\n\n for (const key in data) {\n if (Object.prototype.hasOwnProperty.call(data, key)) {\n const item = data[key];\n if (item && (item.expiry === null || now <= item.expiry)) {\n validKeys.push(key);\n }\n }\n }\n\n return validKeys;\n }\n\n /**\n * Returns all stored items as a key-value object (excluding expired items).\n */\n getAll(): Record<string, unknown> {\n if (!this.backend.isAvailable()) return {};\n\n const data = this.getAllData();\n const result: Record<string, unknown> = {};\n const now = Date.now();\n\n for (const key in data) {\n if (Object.prototype.hasOwnProperty.call(data, key)) {\n const item = data[key];\n if (item && (item.expiry === null || now <= item.expiry)) {\n result[key] = item.value;\n }\n }\n }\n\n return result;\n }\n\n /**\n * Returns the current size of stored data in bytes.\n */\n getCurrentSize(): number {\n if (!this.backend.isAvailable()) return 0;\n\n try {\n const data = this.getAllData();\n const dataStr = JSON.stringify(data);\n return getByteSize(dataStr);\n } catch (e) {\n this.logger?.log('Error calculating storage size', e);\n return 0;\n }\n }\n\n /**\n * Returns storage statistics.\n */\n getStats(): StorageStats {\n if (!this.backend.isAvailable()) {\n return {\n itemCount: 0,\n sizeBytes: 0,\n stringLength: 0,\n maxSizeBytes: this.maxSizeBytes,\n quotaPercentage: 0,\n storageType: 'unavailable',\n };\n }\n\n const data = this.getAllData();\n const itemCount = Object.keys(data).length;\n const dataStr = JSON.stringify(data);\n const sizeBytes = getByteSize(dataStr);\n const quotaPercentage = (sizeBytes / this.maxSizeBytes) * 100;\n\n return {\n itemCount,\n sizeBytes,\n stringLength: dataStr.length,\n maxSizeBytes: this.maxSizeBytes,\n quotaPercentage,\n storageType: this.backend.getStorageType(),\n };\n }\n}\n\nexport { StorageVault };\n","/**\n * A unified wrapper around Web Storage (localStorage / sessionStorage) with optional in-memory fallback.\n * Supports TTL-based expiration, JSON serialization, transform pipelines, and safe handling for both browser and server environments.\n *\n * All data is stored as a single serialized object under one key to avoid cluttering the storage space.\n *\n * @storage STORAGE TYPES:\n * - 'local': Uses localStorage (persists across browser sessions, ~5-10MB quota)\n * - 'session': Uses sessionStorage (cleared when tab closes, ~5-10MB quota)\n * - 'in-memory': Uses Map (cleared on page reload, useful for testing or temporary data)\n * Specify type via: getStorageSlice('KEY', { storageType: 'session' })\n *\n * @security WARNING: Web Storage is accessible via JavaScript and is NOT secure for sensitive data.\n * Do NOT store authentication tokens, passwords, or other sensitive information here.\n * For sensitive data, use httpOnly cookies or secure server-side sessions instead.\n * All stored data should be treated as potentially compromised and validated on retrieval.\n *\n * @ssr HYDRATION WARNING: During server-side rendering, this vault uses in-memory storage.\n * When hydrating on the client, a new instance with localStorage will be created, but any\n * server-rendered state will be lost. If you need to preserve SSR data, pass initial data\n * as props and call setItem() in useEffect() or similar client-side hook.\n *\n * @serialization JSON LIMITATIONS: Values are serialized with JSON.stringify(), which has limitations:\n * - Functions, undefined, and Symbol values are silently dropped\n * - Date objects become strings (must be manually converted back)\n * - Circular references will throw an error\n * - Map, Set, and other non-plain objects lose their type information\n * For complex data types, serialize them manually before storing.\n *\n * @transforms TRANSFORM PIPELINE: You can chain multiple transforms (compression, encryption, encoding):\n * - Transforms are applied AFTER JSON.stringify (string → string transformations)\n * - Applied in order during writes: serialize → transform1 → transform2 → ... → persist\n * - Reversed during reads: persist → reverse transformN → ... → reverse transform1 → deserialize\n * - Use for: compression (LZ-String), encryption (Web Crypto), encoding (Base64), etc.\n *\n * @performance When to use slices (getStorageSlice):\n * - Split data by update frequency (e.g., user preferences vs. temporary cache)\n * - Isolate large datasets to avoid re-serializing everything on each write\n * - Separate critical data from experimental features\n * Example: getStorageSlice('USER_PREFS') vs getStorageSlice('TEMP_CACHE')\n *\n * @performance DEBOUNCING: Write operations are debounced by default (100ms) to batch rapid updates.\n * - Reads always see pending writes immediately (read-after-write consistency)\n * - Pending writes are automatically flushed on page unload to prevent data loss\n * - For time-critical operations, call flush() to force immediate persistence\n * - Set debounceMs: 0 to disable debouncing (writes become synchronous)\n * - Consider higher debounceMs (200-500ms) for battery-sensitive or high-frequency scenarios\n */\n\nimport { StorageVault } from './core/vault';\nimport type { StorageVaultOptions } from './utils/types';\n\n/**\n * Creates a new StorageVault instance with a custom storage key.\n * Use slices to split large or frequently updated data into independent storage blobs.\n *\n * @param sliceKey - The key to store the data under. Must be unique.\n * @param options - Configuration options for the vault.\n * @returns A StorageVault instance (singleton per sliceKey + storage type).\n *\n * @example\n * // Using different storage types\n * const persistent = getStorageSlice('USER_PREFS', { storageType: 'local' }); // Persists across sessions\n * const temporary = getStorageSlice('SESSION_DATA', { storageType: 'session' }); // Cleared when tab closes\n * const testData = getStorageSlice('TEST_DATA', { storageType: 'in-memory' }); // For testing, cleared on reload\n *\n * @example\n * // Good: Separate frequently-updated data from stable data\n * const userPrefs = getStorageSlice('USER_PREFERENCES'); // Updated rarely\n * const tempCache = getStorageSlice('TEMP_CACHE'); // Updated frequently\n *\n * @example\n * // Using transforms\n * import LZString from 'lz-string';\n *\n * const compressionTransform = {\n * serialize: (data: string) => LZString.compress(data),\n * deserialize: (data: string) => LZString.decompress(data)\n * };\n *\n * const vault = getStorageSlice('LARGE_DATA', {\n * transforms: [compressionTransform]\n * });\n */\nfunction getStorageSlice(\n sliceKey: string,\n options: Omit<StorageVaultOptions, 'storageKey'> = {}\n): StorageVault {\n return StorageVault.getInstance({\n ...options,\n storageKey: sliceKey,\n });\n}\n\n/**\n * Disposes a storage slice instance, removing it from the singleton cache.\n * Call this when you're done with a temporary slice to allow garbage collection.\n *\n * @param sliceKey - The key of the slice to dispose.\n * @param options - The same options used when creating the slice (must match exactly).\n * @returns True if the slice was found and disposed; false otherwise.\n *\n * @example\n * const tempVault = getStorageSlice('TEMP_SESSION', { storageType: 'session' });\n * // ... use vault ...\n * disposeStorageSlice('TEMP_SESSION', { storageType: 'session' }); // Clean up when done\n */\nfunction disposeStorageSlice(\n sliceKey: string,\n options: Omit<StorageVaultOptions, 'storageKey'> = {}\n): boolean {\n return StorageVault.disposeInstance({\n ...options,\n storageKey: sliceKey,\n });\n}\n\nexport {\n // Main API functions\n getStorageSlice,\n disposeStorageSlice,\n StorageVault,\n};\n\nexport type {\n StorageType,\n StorageLogger,\n StorageTransform,\n StorageVaultOptions,\n StorageStats,\n StoredData,\n DataRecord,\n} from './utils/types';\n"]}
package/package.json CHANGED
@@ -2,13 +2,13 @@
2
2
  "name": "@dariushstony/smart-storage",
3
3
  "repository": {
4
4
  "type": "git",
5
- "url": "git+https://github.com/DariushStony/smart-storage.git"
5
+ "url": "https://github.com/DariushStony/smart-storage.git"
6
6
  },
7
7
  "bugs": {
8
8
  "url": "https://github.com/DariushStony/smart-storage/issues"
9
9
  },
10
10
  "homepage": "https://github.com/DariushStony/smart-storage#readme",
11
- "version": "0.1.0",
11
+ "version": "1.0.0",
12
12
  "private": false,
13
13
  "description": "A robust, SSR-safe, production-ready wrapper around Web Storage (localStorage/sessionStorage) with TTL, transforms, debouncing, and automatic cleanup",
14
14
  "keywords": [
@@ -27,7 +27,6 @@
27
27
  ],
28
28
  "author": "Dariush Hadipour",
29
29
  "license": "MIT",
30
- "packageManager": "pnpm@9.0.0",
31
30
  "type": "module",
32
31
  "files": [
33
32
  "dist"