UNPKG

memory-vector-store

Version:

A lightweight memory-based vector store with persistent storage support for both Node.js and browser environments. Efficiently store, retrieve, and search vector embeddings with minimal dependencies.

2 lines (1 loc) 4.34 kB
var v=Object.defineProperty;var y=(o,t,e)=>t in o?v(o,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):o[t]=e;var n=(o,t,e)=>y(o,typeof t!="symbol"?t+"":t,e);var h=class{constructor(){n(this,"promise",Promise.resolve());n(this,"resolve",()=>{});n(this,"_isLocked",!1);this.lock()}lock(){this._isLocked=!0,this.promise=new Promise(t=>{this.resolve=t})}unLock(){this._isLocked=!1,this.resolve()}wait(){return this.promise}isLocked(){return this._isLocked}},u=(()=>{let o=new Map;return(t,e,r)=>{let i=o.get(t);i!=null&&clearTimeout(i),o.set(t,setTimeout(async()=>{try{await e()}catch(s){console.error(s)}},r))}})();function l(o,t){return{content:o,metadata:t}}var f=o=>[o[0],o[1].vector,o[1].metadata],d=new Map,g=class{constructor(t,e,r){this.vectorParser=t;this.storageProvider=e;this.options=r;n(this,"cache");n(this,"saveLock",new h);this.options.storagePath=this.options.storagePath??"default",this.saveLock.unLock(),this.initializeStore()}initializeStore(){d.has(this.options.storagePath)?this.cache=d.get(this.options.storagePath):(this.cache={dirty:!1,store:new Map},this.load(),d.set(this.options.storagePath,this.cache))}truncateLog(t,e=50){return t.length<=e?t:t.substring(0,e)+"..."}async add(t){let e=typeof t=="string"?l(t):l(t.content,t.metadata);this.options.debug&&console.log(`[LiteMemoryVectorStore] Adding document: ${this.truncateLog(e.content)}`);let r=await this.vectorParser(e.content);if(!Array.isArray(r))throw new Error("Vector parser must return an array");return this.cache.store.set(e.content,{metadata:e.metadata,vector:r}),this.cache.dirty=!0,this.options.autoSave&&this.save(),{document:e,vector:r}}cosineSimilarity(t,e){let r=0,i=0,s=0;for(let a=0;a<t.length;a++)r+=t[a]*e[a],i+=t[a]*t[a],s+=e[a]*e[a];return i===0||s===0?0:r/(Math.sqrt(i)*Math.sqrt(s))}async similaritySearch(t,e,r){await this.saveLock.wait();let i=this.cache.store.get(t)?.vector??await this.vectorParser(t),s=Array.from(this.cache.store.entries(),([c,m])=>({content:c,metadata:m.metadata}));r&&(s=s.filter(r));let a=s.map(c=>({item:c,score:this.cosineSimilarity(i,this.cache.store.get(c.content).vector)}));return a.sort((c,m)=>m.score-c.score),a.slice(0,e).map(c=>({content:c.item.content,metadata:c.item.metadata,score:c.score}))}async remove(t){let e=this.cache.store.size;this.cache.store.delete(t),this.cache.store.size!==e&&(this.cache.dirty=!0,this.options.autoSave&&this.save())}clear(){this.cache.store.size>0&&(this.cache.store.clear(),this.cache.dirty=!0,this.options.autoSave&&this.save())}getAll(){return Array.from(this.cache.store.entries(),([t,e])=>({content:t,metadata:e.metadata}))}count(){return this.cache.store.size}async save(){return!this.cache.dirty||!this.options.storagePath?Promise.resolve():(this.saveLock.lock(),u(this.options.storagePath,async()=>{try{let t=(this.options.maxFileSizeMB||500)*1024*1024,e=Array.from(this.cache.store.entries(),f),r=JSON.stringify(e),i=Buffer.byteLength(r,"utf8");if(i>t&&e.length>0){for(this.options.debug&&console.log(`[LiteMemoryVectorStore] Data size (${this.formatSize(i)}) exceeds limit (${this.formatSize(t)})`);i>t&&e.length>0;)e.shift(),r=JSON.stringify(e),i=Buffer.byteLength(r,"utf8");this.options.debug&&console.log(`[LiteMemoryVectorStore] Trimmed to ${e.length} items (${this.formatSize(i)})`),this.cache.store.clear();for(let s of e)this.cache.store.set(s[0],{metadata:s[2],vector:s[1]})}this.storageProvider.save(this.options.storagePath,e),this.cache.dirty=!1,this.options.debug&&console.log(`[LiteMemoryVectorStore] Save completed. ${e.length} items saved (${this.formatSize(i)})`)}catch(t){console.error("Error saving vector store:",t)}finally{this.saveLock.unLock()}},100),this.saveLock.wait())}formatSize(t){return t<1024?`${t} bytes`:t<1024*1024?`${(t/1024).toFixed(2)} KB`:`${(t/(1024*1024)).toFixed(2)} MB`}load(){if(this.options.storagePath)try{if(this.storageProvider.exists(this.options.storagePath)){let t=this.storageProvider.load(this.options.storagePath);for(let e of t)this.cache.store.set(e[0],{vector:e[1],metadata:e[2]});this.options.debug&&console.log(`[LiteMemoryVectorStore] Loaded ${this.cache.store.size} items.`)}else this.options.debug&&console.log(`[LiteMemoryVectorStore] No data file found at: ${this.options.storagePath}`)}catch(t){console.error("Error loading vector store:",t),this.cache.store.clear()}}};export{l as a,g as b};