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) 5.4 kB
"use strict";var h=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var P=Object.getOwnPropertyNames;var V=Object.prototype.hasOwnProperty;var z=(r,e,t)=>e in r?h(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t;var L=(r,e)=>{for(var t in e)h(r,t,{get:e[t],enumerable:!0})},T=(r,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of P(e))!V.call(r,i)&&i!==t&&h(r,i,{get:()=>e[i],enumerable:!(o=S(e,i))||o.enumerable});return r};var D=r=>T(h({},"__esModule",{value:!0}),r);var m=(r,e,t)=>z(r,typeof e!="symbol"?e+"":e,t);var x={};L(x,{doc:()=>l,memoryVectorStore:()=>w});module.exports=D(x);var M=require("path");var n=require("fs"),g=require("path"),d=class{save(e,t){let o=(0,g.dirname)(e);(0,n.existsSync)(o)||(0,n.mkdirSync)(o,{recursive:!0}),(0,n.writeFileSync)(e,JSON.stringify(t),"utf8")}load(e){if(!(0,n.existsSync)(e))return[];let t=(0,n.readFileSync)(e,"utf8");return JSON.parse(t||"[]")}exists(e){return(0,n.existsSync)(e)}};var u=class{constructor(){m(this,"promise",Promise.resolve());m(this,"resolve",()=>{});m(this,"_isLocked",!1);this.lock()}lock(){this._isLocked=!0,this.promise=new Promise(e=>{this.resolve=e})}unLock(){this._isLocked=!1,this.resolve()}wait(){return this.promise}isLocked(){return this._isLocked}},v=(()=>{let r=new Map;return(e,t,o)=>{let i=r.get(e);i!=null&&clearTimeout(i),r.set(e,setTimeout(async()=>{try{await t()}catch(s){console.error(s)}},o))}})();function l(r,e){return{content:r,metadata:e}}var b=r=>[r[0],r[1].vector,r[1].metadata],p=new Map,y=class{constructor(e,t,o){this.vectorParser=e;this.storageProvider=t;this.options=o;m(this,"cache");m(this,"saveLock",new u);this.options.storagePath=this.options.storagePath??"default",this.saveLock.unLock(),this.initializeStore()}initializeStore(){p.has(this.options.storagePath)?this.cache=p.get(this.options.storagePath):(this.cache={dirty:!1,store:new Map},this.load(),p.set(this.options.storagePath,this.cache))}truncateLog(e,t=50){return e.length<=t?e:e.substring(0,t)+"..."}async add(e){let t=typeof e=="string"?l(e):l(e.content,e.metadata);this.options.debug&&console.log(`[LiteMemoryVectorStore] Adding document: ${this.truncateLog(t.content)}`);let o=await this.vectorParser(t.content);if(!Array.isArray(o))throw new Error("Vector parser must return an array");return this.cache.store.set(t.content,{metadata:t.metadata,vector:o}),this.cache.dirty=!0,this.options.autoSave&&this.save(),{document:t,vector:o}}cosineSimilarity(e,t){let o=0,i=0,s=0;for(let a=0;a<e.length;a++)o+=e[a]*t[a],i+=e[a]*e[a],s+=t[a]*t[a];return i===0||s===0?0:o/(Math.sqrt(i)*Math.sqrt(s))}async similaritySearch(e,t,o){await this.saveLock.wait();let i=this.cache.store.get(e)?.vector??await this.vectorParser(e),s=Array.from(this.cache.store.entries(),([c,f])=>({content:c,metadata:f.metadata}));o&&(s=s.filter(o));let a=s.map(c=>({item:c,score:this.cosineSimilarity(i,this.cache.store.get(c.content).vector)}));return a.sort((c,f)=>f.score-c.score),a.slice(0,t).map(c=>({content:c.item.content,metadata:c.item.metadata,score:c.score}))}async remove(e){let t=this.cache.store.size;this.cache.store.delete(e),this.cache.store.size!==t&&(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(),([e,t])=>({content:e,metadata:t.metadata}))}count(){return this.cache.store.size}async save(){return!this.cache.dirty||!this.options.storagePath?Promise.resolve():(this.saveLock.lock(),v(this.options.storagePath,async()=>{try{let e=(this.options.maxFileSizeMB||500)*1024*1024,t=Array.from(this.cache.store.entries(),b),o=JSON.stringify(t),i=Buffer.byteLength(o,"utf8");if(i>e&&t.length>0){for(this.options.debug&&console.log(`[LiteMemoryVectorStore] Data size (${this.formatSize(i)}) exceeds limit (${this.formatSize(e)})`);i>e&&t.length>0;)t.shift(),o=JSON.stringify(t),i=Buffer.byteLength(o,"utf8");this.options.debug&&console.log(`[LiteMemoryVectorStore] Trimmed to ${t.length} items (${this.formatSize(i)})`),this.cache.store.clear();for(let s of t)this.cache.store.set(s[0],{metadata:s[2],vector:s[1]})}this.storageProvider.save(this.options.storagePath,t),this.cache.dirty=!1,this.options.debug&&console.log(`[LiteMemoryVectorStore] Save completed. ${t.length} items saved (${this.formatSize(i)})`)}catch(e){console.error("Error saving vector store:",e)}finally{this.saveLock.unLock()}},100),this.saveLock.wait())}formatSize(e){return e<1024?`${e} bytes`:e<1024*1024?`${(e/1024).toFixed(2)} KB`:`${(e/(1024*1024)).toFixed(2)} MB`}load(){if(this.options.storagePath)try{if(this.storageProvider.exists(this.options.storagePath)){let e=this.storageProvider.load(this.options.storagePath);for(let t of e)this.cache.store.set(t[0],{vector:t[1],metadata:t[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(e){console.error("Error loading vector store:",e),this.cache.store.clear()}}};function w(r,e){let t={autoSave:!0,debug:!1,maxFileSizeMB:500,storagePath:(0,M.join)(process.cwd(),"node_modules/__mvsl__/data.json"),...e};return t.maxFileSizeMB=Math.max(Math.min(t.maxFileSizeMB,1e3),1),new y(r,new d,t)}0&&(module.exports={doc,memoryVectorStore});