eigen-db 4.1.0 → 4.2.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.
@@ -1 +1 @@
1
- {"version":3,"file":"eigen-db.js","sources":["../src/lib/errors.ts","../src/lib/storage.ts","../src/lib/compute.ts","../src/lib/lexicon.ts","../src/lib/memory-manager.ts","../src/lib/result-set.ts","../src/lib/simd-binary.ts","../src/lib/wasm-compute.ts","../src/lib/vector-db.ts"],"sourcesContent":["/**\n * Thrown when the database exceeds the 4GB WebAssembly 32-bit memory limit,\n * or the browser's available RAM.\n */\nexport class VectorCapacityExceededError extends Error {\n constructor(maxVectors: number) {\n super(`Capacity exceeded. Max vectors for this dimension size is ~${maxVectors}.`);\n this.name = \"VectorCapacityExceededError\";\n }\n}\n","/**\n * Storage abstraction for append-only binary files.\n * Supports OPFS for browser and in-memory for testing.\n */\n\nexport interface StorageProvider {\n /** Read the entire contents of a file. Returns empty Uint8Array if file doesn't exist. */\n readAll(fileName: string): Promise<Uint8Array>;\n\n /** Append data to a file (creates if it doesn't exist). */\n append(fileName: string, data: Uint8Array): Promise<void>;\n\n /** Write data to a file, replacing all existing content. */\n write(fileName: string, data: Uint8Array): Promise<void>;\n\n /** Delete the storage directory and all files. */\n destroy(): Promise<void>;\n}\n\n/**\n * OPFS-backed storage provider for browser environments.\n * Uses Origin Private File System for high-performance persistent storage.\n */\nexport class OPFSStorageProvider implements StorageProvider {\n private dirHandle: FileSystemDirectoryHandle | null = null;\n private dirName: string;\n\n constructor(dirName: string) {\n this.dirName = dirName;\n }\n\n private async getDir(): Promise<FileSystemDirectoryHandle> {\n if (!this.dirHandle) {\n const root = await navigator.storage.getDirectory();\n this.dirHandle = await root.getDirectoryHandle(this.dirName, { create: true });\n }\n return this.dirHandle;\n }\n\n async readAll(fileName: string): Promise<Uint8Array> {\n try {\n const dir = await this.getDir();\n const fileHandle = await dir.getFileHandle(fileName);\n const file = await fileHandle.getFile();\n const buffer = await file.arrayBuffer();\n return new Uint8Array(buffer);\n } catch {\n return new Uint8Array(0);\n }\n }\n\n async append(fileName: string, data: Uint8Array): Promise<void> {\n const dir = await this.getDir();\n const fileHandle = await dir.getFileHandle(fileName, { create: true });\n const writable = await fileHandle.createWritable({ keepExistingData: true });\n const file = await fileHandle.getFile();\n await writable.seek(file.size);\n await writable.write(data as unknown as BufferSource);\n await writable.close();\n }\n\n async write(fileName: string, data: Uint8Array): Promise<void> {\n const dir = await this.getDir();\n const fileHandle = await dir.getFileHandle(fileName, { create: true });\n const writable = await fileHandle.createWritable({ keepExistingData: false });\n await writable.write(data as unknown as BufferSource);\n await writable.close();\n }\n\n async destroy(): Promise<void> {\n const root = await navigator.storage.getDirectory();\n await root.removeEntry(this.dirName, { recursive: true });\n this.dirHandle = null;\n }\n}\n\n/**\n * In-memory storage provider for testing.\n */\nexport class InMemoryStorageProvider implements StorageProvider {\n private files = new Map<string, Uint8Array[]>();\n\n async readAll(fileName: string): Promise<Uint8Array> {\n const chunks = this.files.get(fileName);\n if (!chunks || chunks.length === 0) return new Uint8Array(0);\n\n const totalSize = chunks.reduce((sum, c) => sum + c.byteLength, 0);\n const result = new Uint8Array(totalSize);\n let offset = 0;\n for (const chunk of chunks) {\n result.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return result;\n }\n\n async append(fileName: string, data: Uint8Array): Promise<void> {\n if (!this.files.has(fileName)) {\n this.files.set(fileName, []);\n }\n this.files.get(fileName)!.push(new Uint8Array(data));\n }\n\n async write(fileName: string, data: Uint8Array): Promise<void> {\n this.files.set(fileName, [new Uint8Array(data)]);\n }\n\n async destroy(): Promise<void> {\n this.files.clear();\n }\n}\n","/**\n * Pure JavaScript compute functions for vector operations.\n * These serve as the reference implementation and fallback when WASM SIMD is unavailable.\n */\n\n/**\n * Normalizes a vector in-place to unit length.\n * After normalization, cosine similarity reduces to a simple dot product.\n */\nexport function normalize(vec: Float32Array): void {\n let sumSq = 0;\n for (let i = 0; i < vec.length; i++) {\n sumSq += vec[i] * vec[i];\n }\n const mag = Math.sqrt(sumSq);\n if (mag === 0) return;\n const invMag = 1 / mag;\n for (let i = 0; i < vec.length; i++) {\n vec[i] *= invMag;\n }\n}\n\n/**\n * Computes dot products of query against all vectors in the database.\n * Writes scores to the output array.\n *\n * @param query - Normalized query vector (length = dimensions)\n * @param db - Contiguous flat array of normalized vectors (length = dbSize * dimensions)\n * @param scores - Output array for dot product scores (length = dbSize)\n * @param dbSize - Number of vectors in the database\n * @param dimensions - Dimensionality of each vector\n */\nexport function searchAll(\n query: Float32Array,\n db: Float32Array,\n scores: Float32Array,\n dbSize: number,\n dimensions: number,\n): void {\n for (let i = 0; i < dbSize; i++) {\n let dot = 0;\n const offset = i * dimensions;\n for (let j = 0; j < dimensions; j++) {\n dot += query[j] * db[offset + j];\n }\n scores[i] = dot;\n }\n}\n","/**\n * Lexicon: length-prefixed UTF-8 encoding for text strings.\n *\n * Format: Each entry is [4-byte uint32 length][UTF-8 bytes]\n * This allows efficient sequential reading and appending.\n */\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\n/**\n * Encodes an array of strings into a length-prefixed binary format.\n */\nexport function encodeLexicon(texts: string[]): Uint8Array {\n const encoded = texts.map((t) => encoder.encode(t));\n const totalSize = encoded.reduce((sum, e) => sum + 4 + e.byteLength, 0);\n\n const buffer = new ArrayBuffer(totalSize);\n const view = new DataView(buffer);\n const bytes = new Uint8Array(buffer);\n let offset = 0;\n\n for (const e of encoded) {\n view.setUint32(offset, e.byteLength, true); // little-endian\n offset += 4;\n bytes.set(e, offset);\n offset += e.byteLength;\n }\n\n return bytes;\n}\n\n/**\n * Decodes all strings from a length-prefixed binary buffer.\n */\nexport function decodeLexicon(data: Uint8Array): string[] {\n const result: string[] = [];\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n let offset = 0;\n\n while (offset < data.byteLength) {\n const len = view.getUint32(offset, true);\n offset += 4;\n const text = decoder.decode(data.subarray(offset, offset + len));\n result.push(text);\n offset += len;\n }\n\n return result;\n}\n\n/**\n * Decodes a single string at a given index from the lexicon.\n * Returns the string and the byte offset of the next entry.\n */\nexport function decodeLexiconAt(data: Uint8Array, index: number): string {\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n let offset = 0;\n\n for (let i = 0; i < index; i++) {\n const len = view.getUint32(offset, true);\n offset += 4 + len;\n }\n\n const len = view.getUint32(offset, true);\n offset += 4;\n return decoder.decode(data.subarray(offset, offset + len));\n}\n\n/**\n * Builds an index of byte offsets for each entry in the lexicon.\n * Enables O(1) access to any entry by index.\n */\nexport function buildLexiconIndex(data: Uint8Array): Uint32Array {\n const offsets: number[] = [];\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n let offset = 0;\n\n while (offset < data.byteLength) {\n offsets.push(offset);\n const len = view.getUint32(offset, true);\n offset += 4 + len;\n }\n\n return new Uint32Array(offsets);\n}\n\n/**\n * Decodes a string at a given byte offset in the lexicon.\n */\nexport function decodeLexiconAtOffset(data: Uint8Array, byteOffset: number): string {\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n const len = view.getUint32(byteOffset, true);\n return decoder.decode(data.subarray(byteOffset + 4, byteOffset + 4 + len));\n}\n","/**\n * Memory Manager for WASM shared memory.\n *\n * Memory Layout:\n * [ 0x00000 ] -> Query Vector Buffer (Fixed, dimensions * 4 bytes, aligned to 64KB page)\n * [ DB_OFFSET ] -> Vector Database (Grows dynamically)\n * [ Dynamic ] -> Scores Buffer (Mapped after DB during search)\n */\n\n/** WASM page size is 64KB */\nconst PAGE_SIZE = 65536;\n\n/** Maximum WASM memory: ~4GB (65536 pages of 64KB each) */\nconst MAX_PAGES = 65536;\n\nexport class MemoryManager {\n readonly memory: WebAssembly.Memory;\n readonly dimensions: number;\n readonly queryOffset: number;\n readonly dbOffset: number;\n private _vectorCount: number;\n\n constructor(dimensions: number, initialVectorCount: number = 0) {\n this.dimensions = dimensions;\n\n // Query buffer: dimensions * 4 bytes, aligned to page boundary\n this.queryOffset = 0;\n const queryBytes = dimensions * 4;\n this.dbOffset = Math.ceil(queryBytes / PAGE_SIZE) * PAGE_SIZE;\n\n // Calculate initial memory needed\n const dbBytes = initialVectorCount * dimensions * 4;\n const totalBytes = this.dbOffset + dbBytes;\n const initialPages = Math.max(1, Math.ceil(totalBytes / PAGE_SIZE));\n\n this.memory = new WebAssembly.Memory({ initial: initialPages });\n this._vectorCount = initialVectorCount;\n }\n\n /** Current number of vectors stored */\n get vectorCount(): number {\n return this._vectorCount;\n }\n\n /** Byte offset where the scores buffer starts (right after DB) */\n get scoresOffset(): number {\n return this.dbOffset + this._vectorCount * this.dimensions * 4;\n }\n\n /** Total bytes needed for scores buffer */\n get scoresBytes(): number {\n return this._vectorCount * 4;\n }\n\n /**\n * Maximum vectors that can be stored given the 4GB WASM memory limit.\n * Accounts for query buffer, DB space, and scores buffer.\n */\n get maxVectors(): number {\n const availableBytes = MAX_PAGES * PAGE_SIZE - this.dbOffset;\n // Each vector needs: dimensions * 4 bytes (DB) + 4 bytes (score)\n const bytesPerVector = this.dimensions * 4 + 4;\n return Math.floor(availableBytes / bytesPerVector);\n }\n\n /**\n * Ensures memory is large enough for the current DB + scores buffer.\n * Calls memory.grow() if needed.\n */\n ensureCapacity(additionalVectors: number): void {\n const newTotal = this._vectorCount + additionalVectors;\n const requiredBytes =\n this.dbOffset + newTotal * this.dimensions * 4 + newTotal * 4; // DB + scores\n const currentBytes = this.memory.buffer.byteLength;\n\n if (requiredBytes > currentBytes) {\n const pagesNeeded = Math.ceil((requiredBytes - currentBytes) / PAGE_SIZE);\n const currentPages = currentBytes / PAGE_SIZE;\n if (currentPages + pagesNeeded > MAX_PAGES) {\n throw new Error(\"WASM memory limit exceeded\");\n }\n this.memory.grow(pagesNeeded);\n }\n }\n\n /**\n * Write a query vector into the query buffer region.\n */\n writeQuery(vector: Float32Array): void {\n new Float32Array(this.memory.buffer, this.queryOffset, this.dimensions).set(vector);\n }\n\n /**\n * Append vectors to the database region.\n * Returns the byte offset where the new vectors were written.\n */\n appendVectors(vectors: Float32Array[]): number {\n const startOffset = this.dbOffset + this._vectorCount * this.dimensions * 4;\n let offset = startOffset;\n for (const vec of vectors) {\n new Float32Array(this.memory.buffer, offset, this.dimensions).set(vec);\n offset += this.dimensions * 4;\n }\n this._vectorCount += vectors.length;\n return startOffset;\n }\n\n /**\n * Load raw vector bytes directly into the database region.\n * Used for bulk loading from OPFS.\n */\n loadVectorBytes(data: Uint8Array, vectorCount: number): void {\n new Uint8Array(this.memory.buffer, this.dbOffset, data.byteLength).set(data);\n this._vectorCount = vectorCount;\n }\n\n /**\n * Read the scores buffer as a Float32Array view.\n */\n readScores(): Float32Array {\n return new Float32Array(this.memory.buffer, this.scoresOffset, this._vectorCount);\n }\n\n /**\n * Read the DB region for a specific vector index.\n */\n readVector(index: number): Float32Array {\n const offset = this.dbOffset + index * this.dimensions * 4;\n return new Float32Array(this.memory.buffer, offset, this.dimensions);\n }\n\n /**\n * Write a vector to a specific slot in the database region.\n */\n writeVector(index: number, vector: Float32Array): void {\n const offset = this.dbOffset + index * this.dimensions * 4;\n new Float32Array(this.memory.buffer, offset, this.dimensions).set(vector);\n }\n\n /**\n * Reset the vector count to zero, logically clearing the database.\n * WASM memory is not freed but will be overwritten on next writes.\n */\n reset(): void {\n this._vectorCount = 0;\n }\n}\n","/**\n * RESULT HELPERS\n *\n * Utility functions for sorting scores and producing query results.\n * Two modes:\n * 1. topKResults — eagerly materializes a ResultItem[] (default query path)\n * 2. iterableResults — returns a lazy Iterable<ResultItem> where keys are\n * resolved only as each item is consumed (for pagination / streaming)\n *\n * Distance is defined as `1 - dotProduct`. For normalized vectors (the default),\n * this equals cosine distance, ranging from 0 (identical) to 2 (opposite).\n */\n\nexport interface ResultItem {\n key: string;\n distance: number;\n}\n\nexport type KeyResolver = (index: number) => string;\n\n/**\n * Sort by ascending distance and return the top K results as a plain array.\n * All keys are resolved eagerly.\n * If maxDistance is provided, results with distance > maxDistance are excluded.\n */\nexport function topKResults(\n scores: Float32Array,\n resolveKey: KeyResolver,\n topK: number,\n maxDistance?: number,\n): ResultItem[] {\n const n = scores.length;\n if (n === 0) return [];\n\n const indices = new Uint32Array(n);\n for (let i = 0; i < n; i++) indices[i] = i;\n indices.sort((a, b) => scores[b] - scores[a]);\n\n const k = Math.min(topK, n);\n const results: ResultItem[] = [];\n for (let i = 0; i < k; i++) {\n const idx = indices[i];\n const distance = 1 - scores[idx];\n if (maxDistance !== undefined && distance > maxDistance) break;\n results.push({ key: resolveKey(idx), distance });\n }\n return results;\n}\n\n/**\n * Sort by ascending distance and return a lazy iterable over the top K results.\n * Keys are resolved only when each item is consumed, saving allocations\n * when the caller iterates partially (e.g., pagination).\n *\n * If maxDistance is provided, iteration stops when distance > maxDistance.\n *\n * The returned iterable is re-iterable — each call to [Symbol.iterator]()\n * produces a fresh cursor over the same pre-sorted data.\n */\nexport function iterableResults(\n scores: Float32Array,\n resolveKey: KeyResolver,\n topK: number,\n maxDistance?: number,\n): Iterable<ResultItem> {\n const n = scores.length;\n if (n === 0) return [];\n\n const indices = new Uint32Array(n);\n for (let i = 0; i < n; i++) indices[i] = i;\n indices.sort((a, b) => scores[b] - scores[a]);\n\n const k = Math.min(topK, n);\n\n return {\n [Symbol.iterator](): Iterator<ResultItem> {\n let i = 0;\n return {\n next(): IteratorResult<ResultItem> {\n if (i >= k) return { done: true, value: undefined };\n const idx = indices[i++];\n const distance = 1 - scores[idx];\n if (maxDistance !== undefined && distance > maxDistance) return { done: true, value: undefined };\n return {\n done: false,\n value: { key: resolveKey(idx), distance },\n };\n },\n };\n },\n };\n}\n","// AUTO-GENERATED - Do not edit. Run: npx tsx scripts/compile-wat.ts\nconst SIMD_WASM_BASE64 = \"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\";\n\nexport function getSimdWasmBinary(): Uint8Array {\n const binaryString = atob(SIMD_WASM_BASE64);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return bytes;\n}\n","/**\n * WASM SIMD compute layer.\n * Compiles the hand-written WAT module and provides typed wrappers\n * that operate on shared WebAssembly.Memory.\n */\n\nexport interface WasmExports {\n normalize(ptr: number, dimensions: number): void;\n search_all(queryPtr: number, dbPtr: number, scoresPtr: number, dbSize: number, dimensions: number): void;\n}\n\n/**\n * Instantiates a WASM module with the given memory and returns typed exports.\n */\nexport async function instantiateWasm(wasmBinary: Uint8Array, memory: WebAssembly.Memory): Promise<WasmExports> {\n const importObject = { env: { memory } };\n const result = await WebAssembly.instantiate(wasmBinary, importObject);\n // WebAssembly.instantiate with a buffer returns { instance, module }\n const instance = (result as unknown as { instance: WebAssembly.Instance }).instance;\n return instance.exports as unknown as WasmExports;\n}\n","/**\n * VectorDB — Key-Value Vector Database\n *\n * Decoupled from embedding providers. Users pass pre-computed vectors\n * as number arrays (or Float32Array) with string keys.\n *\n * Supports:\n * - set/get/setMany/getMany for key-value CRUD\n * - query for similarity search (dot product on normalized vectors)\n * - flush to persist, close to flush+release, clear to wipe\n * - Last-write-wins semantics for duplicate keys (append-only storage)\n */\n\nimport { normalize, searchAll } from \"./compute\";\nimport { VectorCapacityExceededError } from \"./errors\";\nimport { decodeLexicon, encodeLexicon } from \"./lexicon\";\nimport { MemoryManager } from \"./memory-manager\";\nimport type { ResultItem } from \"./result-set\";\nimport { iterableResults, topKResults } from \"./result-set\";\nimport { getSimdWasmBinary } from \"./simd-binary\";\nimport type { StorageProvider } from \"./storage\";\nimport { OPFSStorageProvider } from \"./storage\";\nimport type { OpenOptions, OpenOptionsInternal, QueryOptions, SetOptions, VectorInput } from \"./types\";\nimport { instantiateWasm, type WasmExports } from \"./wasm-compute\";\n\nconst VECTORS_FILE = \"vectors.bin\";\nconst KEYS_FILE = \"keys.bin\";\n\nexport class VectorDB {\n private readonly memoryManager: MemoryManager;\n private readonly storage: StorageProvider;\n private readonly dimensions: number;\n private readonly shouldNormalize: boolean;\n private wasmExports: WasmExports | null;\n\n /** Maps key to its slot index in the vector array */\n private keyToSlot: Map<string, number>;\n\n /** Maps slot index back to its key */\n private slotToKey: string[];\n\n /** Whether this instance has been closed */\n private closed = false;\n\n private constructor(\n memoryManager: MemoryManager,\n storage: StorageProvider,\n dimensions: number,\n shouldNormalize: boolean,\n wasmExports: WasmExports | null,\n keyToSlot: Map<string, number>,\n slotToKey: string[],\n ) {\n this.memoryManager = memoryManager;\n this.storage = storage;\n this.dimensions = dimensions;\n this.shouldNormalize = shouldNormalize;\n this.wasmExports = wasmExports;\n this.keyToSlot = keyToSlot;\n this.slotToKey = slotToKey;\n }\n\n /**\n * Opens a VectorDB instance.\n * Loads existing data from storage into WASM memory.\n */\n static async open(options: OpenOptions): Promise<VectorDB>;\n static async open(options: OpenOptionsInternal): Promise<VectorDB>;\n static async open(options: OpenOptionsInternal): Promise<VectorDB> {\n const name = options.name ?? \"default\";\n const storage = options.storage ?? new OPFSStorageProvider(name);\n const shouldNormalize = options.normalize !== false;\n\n // Load existing data from storage\n const [vectorBytes, keysBytes] = await Promise.all([storage.readAll(VECTORS_FILE), storage.readAll(KEYS_FILE)]);\n\n // Decode stored keys\n const keys = keysBytes.byteLength > 0 ? decodeLexicon(keysBytes) : [];\n const vectorCount = vectorBytes.byteLength / (options.dimensions * 4);\n\n // Build key-to-slot mapping.\n // flush() always writes deduplicated state, so keys are unique on load.\n const keyToSlot = new Map<string, number>();\n const slotToKey: string[] = [];\n\n for (let i = 0; i < keys.length; i++) {\n keyToSlot.set(keys[i], i);\n slotToKey[i] = keys[i];\n }\n\n // Initialize memory manager\n const mm = new MemoryManager(options.dimensions, vectorCount);\n\n if (vectorBytes.byteLength > 0) {\n mm.loadVectorBytes(vectorBytes, vectorCount);\n }\n\n // Try to instantiate WASM SIMD module\n let wasmExports: WasmExports | null = null;\n const wasmBinary = options.wasmBinary !== undefined ? options.wasmBinary : getSimdWasmBinary();\n if (wasmBinary !== null) {\n try {\n wasmExports = await instantiateWasm(wasmBinary, mm.memory);\n } catch {\n // Fall back to JS compute\n }\n }\n\n return new VectorDB(mm, storage, options.dimensions, shouldNormalize, wasmExports, keyToSlot, slotToKey);\n }\n\n /** Total number of key-value pairs in the database */\n get size(): number {\n return this.keyToSlot.size;\n }\n\n /**\n * Set a key-value pair. If the key already exists, its vector is overwritten (last-write-wins).\n * The value is a number[] or Float32Array of length equal to the configured dimensions.\n */\n set(key: string, value: VectorInput, options?: SetOptions): void {\n this.assertOpen();\n\n if (value.length !== this.dimensions) {\n throw new Error(`Vector dimension mismatch: expected ${this.dimensions}, got ${value.length}`);\n }\n\n // Convert to Float32Array (also clones to avoid mutating caller's array)\n const vec = new Float32Array(value);\n\n // Normalize if needed\n const doNormalize = options?.normalize ?? this.shouldNormalize;\n if (doNormalize) {\n this.normalizeVector(vec);\n }\n\n const existingSlot = this.keyToSlot.get(key);\n if (existingSlot !== undefined) {\n // Overwrite existing slot\n this.memoryManager.writeVector(existingSlot, vec);\n } else {\n // Append new entry\n const newTotal = this.memoryManager.vectorCount + 1;\n if (newTotal > this.memoryManager.maxVectors) {\n throw new VectorCapacityExceededError(this.memoryManager.maxVectors);\n }\n this.memoryManager.ensureCapacity(1);\n const slotIndex = this.memoryManager.vectorCount;\n this.memoryManager.appendVectors([vec]);\n this.keyToSlot.set(key, slotIndex);\n this.slotToKey[slotIndex] = key;\n }\n }\n\n /**\n * Get the stored vector for a key. Returns undefined if the key does not exist.\n * Returns a copy of the stored vector as a plain number array.\n */\n get(key: string): number[] | undefined {\n this.assertOpen();\n\n const slot = this.keyToSlot.get(key);\n if (slot === undefined) return undefined;\n\n // Return a plain array copy so callers can't corrupt WASM memory\n return Array.from(this.memoryManager.readVector(slot));\n }\n\n /**\n * Set multiple key-value pairs at once. Last-write-wins applies within the batch.\n */\n setMany(entries: [string, VectorInput][]): void {\n for (const [key, value] of entries) {\n this.set(key, value);\n }\n }\n\n /**\n * Get vectors for multiple keys. Returns undefined for keys that don't exist.\n */\n getMany(keys: string[]): (number[] | undefined)[] {\n return keys.map((key) => this.get(key));\n }\n\n /**\n * Search for the most similar vectors to the given query vector.\n *\n * Default: returns a plain ResultItem[] sorted by ascending distance.\n * With `{ iterable: true }`: returns a lazy Iterable<ResultItem> where keys\n * are resolved only as each item is consumed.\n *\n * Distance is defined as `1 - dotProduct`. With normalization (default),\n * this equals cosine distance: 0 = identical, 2 = opposite.\n */\n query(value: VectorInput, options: QueryOptions & { iterable: true }): Iterable<ResultItem>;\n query(value: VectorInput, options?: QueryOptions): ResultItem[];\n query(value: VectorInput, options?: QueryOptions): ResultItem[] | Iterable<ResultItem> {\n this.assertOpen();\n\n const k = options?.topK ?? Infinity;\n const maxDistance = options?.maxDistance;\n const iterable = options && \"iterable\" in options && options.iterable;\n\n if (this.size === 0) {\n return [];\n }\n\n if (value.length !== this.dimensions) {\n throw new Error(`Query vector dimension mismatch: expected ${this.dimensions}, got ${value.length}`);\n }\n\n // Convert to Float32Array and optionally normalize the query vector\n const queryVec = new Float32Array(value);\n const doNormalize = options?.normalize ?? this.shouldNormalize;\n if (doNormalize) {\n this.normalizeVector(queryVec);\n }\n\n // Write query to WASM memory\n this.memoryManager.writeQuery(queryVec);\n\n // Ensure memory has space for scores buffer\n this.memoryManager.ensureCapacity(0);\n\n // Total vectors in memory\n const totalVectors = this.memoryManager.vectorCount;\n\n // Execute search\n const scoresOffset = this.memoryManager.scoresOffset;\n if (this.wasmExports) {\n this.wasmExports.search_all(\n this.memoryManager.queryOffset,\n this.memoryManager.dbOffset,\n scoresOffset,\n totalVectors,\n this.dimensions,\n );\n } else {\n const queryView = new Float32Array(\n this.memoryManager.memory.buffer,\n this.memoryManager.queryOffset,\n this.dimensions,\n );\n const dbView = new Float32Array(\n this.memoryManager.memory.buffer,\n this.memoryManager.dbOffset,\n totalVectors * this.dimensions,\n );\n const scoresView = new Float32Array(this.memoryManager.memory.buffer, scoresOffset, totalVectors);\n searchAll(queryView, dbView, scoresView, totalVectors, this.dimensions);\n }\n\n // Read scores (make a copy so the buffer can be reused)\n const scores = new Float32Array(this.memoryManager.readScores());\n\n // Resolve key from slot index\n const slotToKey = this.slotToKey;\n const resolveKey = (slotIndex: number): string => {\n return slotToKey[slotIndex];\n };\n\n if (iterable) {\n return iterableResults(scores, resolveKey, k, maxDistance);\n }\n return topKResults(scores, resolveKey, k, maxDistance);\n }\n\n /**\n * Persist the current in-memory state to storage.\n */\n async flush(): Promise<void> {\n this.assertOpen();\n\n const totalVectors = this.memoryManager.vectorCount;\n\n // Serialize vectors from WASM memory\n const vectorBytes = new Uint8Array(totalVectors * this.dimensions * 4);\n if (totalVectors > 0) {\n const src = new Uint8Array(\n this.memoryManager.memory.buffer,\n this.memoryManager.dbOffset,\n totalVectors * this.dimensions * 4,\n );\n vectorBytes.set(src);\n }\n\n // Serialize keys using lexicon format\n const keysBytes = encodeLexicon(this.slotToKey);\n\n await Promise.all([this.storage.write(VECTORS_FILE, vectorBytes), this.storage.write(KEYS_FILE, keysBytes)]);\n }\n\n /**\n * Flush data to storage and release the instance.\n * The instance cannot be used after close.\n */\n async close(): Promise<void> {\n if (this.closed) return;\n await this.flush();\n this.closed = true;\n }\n\n /**\n * Clear all data from the database and storage.\n */\n async clear(): Promise<void> {\n this.assertOpen();\n\n this.keyToSlot.clear();\n this.slotToKey.length = 0;\n this.memoryManager.reset();\n\n await this.storage.destroy();\n }\n\n /**\n * Normalize a vector using WASM (if available) or JS fallback.\n */\n private normalizeVector(vec: Float32Array): void {\n if (this.wasmExports) {\n const ptr = this.memoryManager.queryOffset;\n new Float32Array(this.memoryManager.memory.buffer, ptr, vec.length).set(vec);\n this.wasmExports.normalize(ptr, vec.length);\n const normalized = new Float32Array(this.memoryManager.memory.buffer, ptr, vec.length);\n vec.set(normalized);\n } else {\n normalize(vec);\n }\n }\n\n private assertOpen(): void {\n if (this.closed) {\n throw new Error(\"VectorDB instance has been closed\");\n }\n }\n}\n"],"names":["VectorCapacityExceededError","maxVectors","OPFSStorageProvider","dirName","root","fileName","buffer","data","fileHandle","writable","file","InMemoryStorageProvider","chunks","totalSize","sum","c","result","offset","chunk","normalize","vec","sumSq","i","mag","invMag","searchAll","query","db","scores","dbSize","dimensions","dot","j","encoder","decoder","encodeLexicon","texts","encoded","t","e","view","bytes","decodeLexicon","len","text","PAGE_SIZE","MAX_PAGES","MemoryManager","initialVectorCount","queryBytes","dbBytes","totalBytes","initialPages","availableBytes","bytesPerVector","additionalVectors","newTotal","requiredBytes","currentBytes","pagesNeeded","vector","vectors","startOffset","vectorCount","index","topKResults","resolveKey","topK","maxDistance","n","indices","a","b","k","results","idx","distance","iterableResults","SIMD_WASM_BASE64","getSimdWasmBinary","binaryString","instantiateWasm","wasmBinary","memory","importObject","VECTORS_FILE","KEYS_FILE","VectorDB","memoryManager","storage","shouldNormalize","wasmExports","keyToSlot","slotToKey","options","name","vectorBytes","keysBytes","keys","mm","key","value","existingSlot","slotIndex","slot","entries","iterable","queryVec","totalVectors","scoresOffset","queryView","dbView","scoresView","src","ptr","normalized"],"mappings":"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"}
1
+ {"version":3,"file":"eigen-db.js","sources":["../src/lib/errors.ts","../src/lib/storage.ts","../src/lib/compute.ts","../src/lib/lexicon.ts","../src/lib/memory-manager.ts","../src/lib/result-set.ts","../src/lib/simd-binary.ts","../src/lib/wasm-compute.ts","../src/lib/vector-db.ts"],"sourcesContent":["/**\n * Thrown when the database exceeds the 4GB WebAssembly 32-bit memory limit,\n * or the browser's available RAM.\n */\nexport class VectorCapacityExceededError extends Error {\n constructor(maxVectors: number) {\n super(`Capacity exceeded. Max vectors for this dimension size is ~${maxVectors}.`);\n this.name = \"VectorCapacityExceededError\";\n }\n}\n","/**\n * Storage abstraction for append-only binary files.\n * Supports OPFS for browser and in-memory for testing.\n */\n\nexport interface StorageProvider {\n /** Read the entire contents of a file. Returns empty Uint8Array if file doesn't exist. */\n readAll(fileName: string): Promise<Uint8Array>;\n\n /** Append data to a file (creates if it doesn't exist). */\n append(fileName: string, data: Uint8Array): Promise<void>;\n\n /** Write data to a file, replacing all existing content. */\n write(fileName: string, data: Uint8Array): Promise<void>;\n\n /** Delete the storage directory and all files. */\n destroy(): Promise<void>;\n}\n\n/**\n * OPFS-backed storage provider for browser environments.\n * Uses Origin Private File System for high-performance persistent storage.\n */\nexport class OPFSStorageProvider implements StorageProvider {\n private dirHandle: FileSystemDirectoryHandle | null = null;\n private dirName: string;\n\n constructor(dirName: string) {\n this.dirName = dirName;\n }\n\n private async getDir(): Promise<FileSystemDirectoryHandle> {\n if (!this.dirHandle) {\n const root = await navigator.storage.getDirectory();\n this.dirHandle = await root.getDirectoryHandle(this.dirName, { create: true });\n }\n return this.dirHandle;\n }\n\n async readAll(fileName: string): Promise<Uint8Array> {\n try {\n const dir = await this.getDir();\n const fileHandle = await dir.getFileHandle(fileName);\n const file = await fileHandle.getFile();\n const buffer = await file.arrayBuffer();\n return new Uint8Array(buffer);\n } catch {\n return new Uint8Array(0);\n }\n }\n\n async append(fileName: string, data: Uint8Array): Promise<void> {\n const dir = await this.getDir();\n const fileHandle = await dir.getFileHandle(fileName, { create: true });\n const writable = await fileHandle.createWritable({ keepExistingData: true });\n const file = await fileHandle.getFile();\n await writable.seek(file.size);\n await writable.write(data as unknown as BufferSource);\n await writable.close();\n }\n\n async write(fileName: string, data: Uint8Array): Promise<void> {\n const dir = await this.getDir();\n const fileHandle = await dir.getFileHandle(fileName, { create: true });\n const writable = await fileHandle.createWritable({ keepExistingData: false });\n await writable.write(data as unknown as BufferSource);\n await writable.close();\n }\n\n async destroy(): Promise<void> {\n const root = await navigator.storage.getDirectory();\n await root.removeEntry(this.dirName, { recursive: true });\n this.dirHandle = null;\n }\n}\n\n/**\n * In-memory storage provider for testing.\n */\nexport class InMemoryStorageProvider implements StorageProvider {\n private files = new Map<string, Uint8Array[]>();\n\n async readAll(fileName: string): Promise<Uint8Array> {\n const chunks = this.files.get(fileName);\n if (!chunks || chunks.length === 0) return new Uint8Array(0);\n\n const totalSize = chunks.reduce((sum, c) => sum + c.byteLength, 0);\n const result = new Uint8Array(totalSize);\n let offset = 0;\n for (const chunk of chunks) {\n result.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return result;\n }\n\n async append(fileName: string, data: Uint8Array): Promise<void> {\n if (!this.files.has(fileName)) {\n this.files.set(fileName, []);\n }\n this.files.get(fileName)!.push(new Uint8Array(data));\n }\n\n async write(fileName: string, data: Uint8Array): Promise<void> {\n this.files.set(fileName, [new Uint8Array(data)]);\n }\n\n async destroy(): Promise<void> {\n this.files.clear();\n }\n}\n","/**\n * Pure JavaScript compute functions for vector operations.\n * These serve as the reference implementation and fallback when WASM SIMD is unavailable.\n */\n\n/**\n * Normalizes a vector in-place to unit length.\n * After normalization, cosine similarity reduces to a simple dot product.\n */\nexport function normalize(vec: Float32Array): void {\n let sumSq = 0;\n for (let i = 0; i < vec.length; i++) {\n sumSq += vec[i] * vec[i];\n }\n const mag = Math.sqrt(sumSq);\n if (mag === 0) return;\n const invMag = 1 / mag;\n for (let i = 0; i < vec.length; i++) {\n vec[i] *= invMag;\n }\n}\n\n/**\n * Computes dot products of query against all vectors in the database.\n * Writes scores to the output array.\n *\n * @param query - Normalized query vector (length = dimensions)\n * @param db - Contiguous flat array of normalized vectors (length = dbSize * dimensions)\n * @param scores - Output array for dot product scores (length = dbSize)\n * @param dbSize - Number of vectors in the database\n * @param dimensions - Dimensionality of each vector\n */\nexport function searchAll(\n query: Float32Array,\n db: Float32Array,\n scores: Float32Array,\n dbSize: number,\n dimensions: number,\n): void {\n for (let i = 0; i < dbSize; i++) {\n let dot = 0;\n const offset = i * dimensions;\n for (let j = 0; j < dimensions; j++) {\n dot += query[j] * db[offset + j];\n }\n scores[i] = dot;\n }\n}\n","/**\n * Lexicon: length-prefixed UTF-8 encoding for text strings.\n *\n * Format: Each entry is [4-byte uint32 length][UTF-8 bytes]\n * This allows efficient sequential reading and appending.\n */\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\n/**\n * Encodes an array of strings into a length-prefixed binary format.\n */\nexport function encodeLexicon(texts: string[]): Uint8Array {\n const encoded = texts.map((t) => encoder.encode(t));\n const totalSize = encoded.reduce((sum, e) => sum + 4 + e.byteLength, 0);\n\n const buffer = new ArrayBuffer(totalSize);\n const view = new DataView(buffer);\n const bytes = new Uint8Array(buffer);\n let offset = 0;\n\n for (const e of encoded) {\n view.setUint32(offset, e.byteLength, true); // little-endian\n offset += 4;\n bytes.set(e, offset);\n offset += e.byteLength;\n }\n\n return bytes;\n}\n\n/**\n * Decodes all strings from a length-prefixed binary buffer.\n */\nexport function decodeLexicon(data: Uint8Array): string[] {\n const result: string[] = [];\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n let offset = 0;\n\n while (offset < data.byteLength) {\n const len = view.getUint32(offset, true);\n offset += 4;\n const text = decoder.decode(data.subarray(offset, offset + len));\n result.push(text);\n offset += len;\n }\n\n return result;\n}\n\n/**\n * Decodes a single string at a given index from the lexicon.\n * Returns the string and the byte offset of the next entry.\n */\nexport function decodeLexiconAt(data: Uint8Array, index: number): string {\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n let offset = 0;\n\n for (let i = 0; i < index; i++) {\n const len = view.getUint32(offset, true);\n offset += 4 + len;\n }\n\n const len = view.getUint32(offset, true);\n offset += 4;\n return decoder.decode(data.subarray(offset, offset + len));\n}\n\n/**\n * Builds an index of byte offsets for each entry in the lexicon.\n * Enables O(1) access to any entry by index.\n */\nexport function buildLexiconIndex(data: Uint8Array): Uint32Array {\n const offsets: number[] = [];\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n let offset = 0;\n\n while (offset < data.byteLength) {\n offsets.push(offset);\n const len = view.getUint32(offset, true);\n offset += 4 + len;\n }\n\n return new Uint32Array(offsets);\n}\n\n/**\n * Decodes a string at a given byte offset in the lexicon.\n */\nexport function decodeLexiconAtOffset(data: Uint8Array, byteOffset: number): string {\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n const len = view.getUint32(byteOffset, true);\n return decoder.decode(data.subarray(byteOffset + 4, byteOffset + 4 + len));\n}\n","/**\n * Memory Manager for WASM shared memory.\n *\n * Memory Layout:\n * [ 0x00000 ] -> Query Vector Buffer (Fixed, dimensions * 4 bytes, aligned to 64KB page)\n * [ DB_OFFSET ] -> Vector Database (Grows dynamically)\n * [ Dynamic ] -> Scores Buffer (Mapped after DB during search)\n */\n\n/** WASM page size is 64KB */\nconst PAGE_SIZE = 65536;\n\n/** Maximum WASM memory: ~4GB (65536 pages of 64KB each) */\nconst MAX_PAGES = 65536;\n\nexport class MemoryManager {\n readonly memory: WebAssembly.Memory;\n readonly dimensions: number;\n readonly queryOffset: number;\n readonly dbOffset: number;\n private _vectorCount: number;\n\n constructor(dimensions: number, initialVectorCount: number = 0) {\n this.dimensions = dimensions;\n\n // Query buffer: dimensions * 4 bytes, aligned to page boundary\n this.queryOffset = 0;\n const queryBytes = dimensions * 4;\n this.dbOffset = Math.ceil(queryBytes / PAGE_SIZE) * PAGE_SIZE;\n\n // Calculate initial memory needed\n const dbBytes = initialVectorCount * dimensions * 4;\n const totalBytes = this.dbOffset + dbBytes;\n const initialPages = Math.max(1, Math.ceil(totalBytes / PAGE_SIZE));\n\n this.memory = new WebAssembly.Memory({ initial: initialPages });\n this._vectorCount = initialVectorCount;\n }\n\n /** Current number of vectors stored */\n get vectorCount(): number {\n return this._vectorCount;\n }\n\n /** Byte offset where the scores buffer starts (right after DB) */\n get scoresOffset(): number {\n return this.dbOffset + this._vectorCount * this.dimensions * 4;\n }\n\n /** Total bytes needed for scores buffer */\n get scoresBytes(): number {\n return this._vectorCount * 4;\n }\n\n /**\n * Maximum vectors that can be stored given the 4GB WASM memory limit.\n * Accounts for query buffer, DB space, and scores buffer.\n */\n get maxVectors(): number {\n const availableBytes = MAX_PAGES * PAGE_SIZE - this.dbOffset;\n // Each vector needs: dimensions * 4 bytes (DB) + 4 bytes (score)\n const bytesPerVector = this.dimensions * 4 + 4;\n return Math.floor(availableBytes / bytesPerVector);\n }\n\n /**\n * Ensures memory is large enough for the current DB + scores buffer.\n * Calls memory.grow() if needed.\n */\n ensureCapacity(additionalVectors: number): void {\n const newTotal = this._vectorCount + additionalVectors;\n const requiredBytes =\n this.dbOffset + newTotal * this.dimensions * 4 + newTotal * 4; // DB + scores\n const currentBytes = this.memory.buffer.byteLength;\n\n if (requiredBytes > currentBytes) {\n const pagesNeeded = Math.ceil((requiredBytes - currentBytes) / PAGE_SIZE);\n const currentPages = currentBytes / PAGE_SIZE;\n if (currentPages + pagesNeeded > MAX_PAGES) {\n throw new Error(\"WASM memory limit exceeded\");\n }\n this.memory.grow(pagesNeeded);\n }\n }\n\n /**\n * Write a query vector into the query buffer region.\n */\n writeQuery(vector: Float32Array): void {\n new Float32Array(this.memory.buffer, this.queryOffset, this.dimensions).set(vector);\n }\n\n /**\n * Append vectors to the database region.\n * Returns the byte offset where the new vectors were written.\n */\n appendVectors(vectors: Float32Array[]): number {\n const startOffset = this.dbOffset + this._vectorCount * this.dimensions * 4;\n let offset = startOffset;\n for (const vec of vectors) {\n new Float32Array(this.memory.buffer, offset, this.dimensions).set(vec);\n offset += this.dimensions * 4;\n }\n this._vectorCount += vectors.length;\n return startOffset;\n }\n\n /**\n * Load raw vector bytes directly into the database region.\n * Used for bulk loading from OPFS.\n */\n loadVectorBytes(data: Uint8Array, vectorCount: number): void {\n new Uint8Array(this.memory.buffer, this.dbOffset, data.byteLength).set(data);\n this._vectorCount = vectorCount;\n }\n\n /**\n * Read the scores buffer as a Float32Array view.\n */\n readScores(): Float32Array {\n return new Float32Array(this.memory.buffer, this.scoresOffset, this._vectorCount);\n }\n\n /**\n * Read the DB region for a specific vector index.\n */\n readVector(index: number): Float32Array {\n const offset = this.dbOffset + index * this.dimensions * 4;\n return new Float32Array(this.memory.buffer, offset, this.dimensions);\n }\n\n /**\n * Write a vector to a specific slot in the database region.\n */\n writeVector(index: number, vector: Float32Array): void {\n const offset = this.dbOffset + index * this.dimensions * 4;\n new Float32Array(this.memory.buffer, offset, this.dimensions).set(vector);\n }\n\n /**\n * Reset the vector count to zero, logically clearing the database.\n * WASM memory is not freed but will be overwritten on next writes.\n */\n reset(): void {\n this._vectorCount = 0;\n }\n\n /**\n * Set the vector count after bulk-loading data directly into the DB region.\n * Use when writing raw bytes to the DB region externally (e.g., streaming import).\n */\n setVectorCount(count: number): void {\n this._vectorCount = count;\n }\n}\n","/**\n * RESULT HELPERS\n *\n * Utility functions for sorting scores and producing query results.\n * Two modes:\n * 1. topKResults — eagerly materializes a ResultItem[] (default query path)\n * 2. iterableResults — returns a lazy Iterable<ResultItem> where keys are\n * resolved only as each item is consumed (for pagination / streaming)\n *\n * Similarity is the dot product of query and stored vectors. For normalized\n * vectors (the default), this equals cosine similarity, ranging from 1\n * (identical) to -1 (opposite).\n */\n\nexport interface ResultItem {\n key: string;\n similarity: number;\n}\n\nexport type KeyResolver = (index: number) => string;\n\n/**\n * Sort by descending similarity and return the top K results as a plain array.\n * All keys are resolved eagerly.\n * If minSimilarity is provided, results with similarity < minSimilarity are excluded.\n */\nexport function topKResults(\n scores: Float32Array,\n resolveKey: KeyResolver,\n topK: number,\n minSimilarity?: number,\n): ResultItem[] {\n const n = scores.length;\n if (n === 0) return [];\n\n const indices = new Uint32Array(n);\n for (let i = 0; i < n; i++) indices[i] = i;\n indices.sort((a, b) => scores[b] - scores[a]);\n\n const k = Math.min(topK, n);\n const results: ResultItem[] = [];\n for (let i = 0; i < k; i++) {\n const idx = indices[i];\n const similarity = scores[idx];\n if (minSimilarity !== undefined && similarity < minSimilarity) break;\n results.push({ key: resolveKey(idx), similarity });\n }\n return results;\n}\n\n/**\n * Sort by descending similarity and return a lazy iterable over the top K results.\n * Keys are resolved only when each item is consumed, saving allocations\n * when the caller iterates partially (e.g., pagination).\n *\n * If minSimilarity is provided, iteration stops when similarity < minSimilarity.\n *\n * The returned iterable is re-iterable — each call to [Symbol.iterator]()\n * produces a fresh cursor over the same pre-sorted data.\n */\nexport function iterableResults(\n scores: Float32Array,\n resolveKey: KeyResolver,\n topK: number,\n minSimilarity?: number,\n): Iterable<ResultItem> {\n const n = scores.length;\n if (n === 0) return [];\n\n const indices = new Uint32Array(n);\n for (let i = 0; i < n; i++) indices[i] = i;\n indices.sort((a, b) => scores[b] - scores[a]);\n\n const k = Math.min(topK, n);\n\n return {\n [Symbol.iterator](): Iterator<ResultItem> {\n let i = 0;\n return {\n next(): IteratorResult<ResultItem> {\n if (i >= k) return { done: true, value: undefined };\n const idx = indices[i++];\n const similarity = scores[idx];\n if (minSimilarity !== undefined && similarity < minSimilarity) return { done: true, value: undefined };\n return {\n done: false,\n value: { key: resolveKey(idx), similarity },\n };\n },\n };\n },\n };\n}\n","// AUTO-GENERATED - Do not edit. Run: npx tsx scripts/compile-wat.ts\nconst SIMD_WASM_BASE64 = \"AGFzbQEAAAABDgJgAn9/AGAFf39/f38AAg8BA2VudgZtZW1vcnkCAAEDAwIAAQcaAglub3JtYWxpemUAAApzZWFyY2hfYWxsAAEKgQ4C3wQFAX8EewN9AXsDf/0MAAAAAAAAAAAAAAAAAAAAACED/QwAAAAAAAAAAAAAAAAAAAAAIQT9DAAAAAAAAAAAAAAAAAAAAAAhBf0MAAAAAAAAAAAAAAAAAAAAACEGIAFBcHEhCyABQXxxIQxBACECAkADQCACIAtPDQEgACACQQJ0aiENIAMgDf0ABAAgDf0ABAD95gH95AEhAyAEIA39AAQQIA39AAQQ/eYB/eQBIQQgBSAN/QAEICAN/QAEIP3mAf3kASEFIAYgDf0ABDAgDf0ABDD95gH95AEhBiACQRBqIQIMAAsLIAMgBP3kASAFIAb95AH95AEhAwJAA0AgAiAMTw0BIAAgAkECdGohDSADIA39AAQAIA39AAQA/eYB/eQBIQMgAkEEaiECDAALCyAD/R8AIAP9HwGSIAP9HwIgA/0fA5KSIQcCQANAIAIgAU8NASAAIAJBAnRqIQ0gByANKgIAIA0qAgCUkiEHIAJBAWohAgwACwsgB5EhCCAIQwAAAABbBEAPC0MAAIA/IAiVIQkgCf0TIQpBACECAkADQCACIAtPDQEgACACQQJ0aiENIA0gDf0ABAAgCv3mAf0LBAAgDSAN/QAEECAK/eYB/QsEECANIA39AAQgIAr95gH9CwQgIA0gDf0ABDAgCv3mAf0LBDAgAkEQaiECDAALCwJAA0AgAiAMTw0BIAAgAkECdGohDSANIA39AAQAIAr95gH9CwQAIAJBBGohAgwACwsCQANAIAIgAU8NASAAIAJBAnRqIQ0gDSANKgIAIAmUOAIAIAJBAWohAgwACwsLnQkEAn8MewJ9CX8gBEFwcSEXIARBfHEhGCAEQQJ0IRwgA0F+cSEdQQAhBQJAA0AgBSAdTw0BIAEgBSAcbGohFSAVIBxqIRb9DAAAAAAAAAAAAAAAAAAAAAAhB/0MAAAAAAAAAAAAAAAAAAAAACEI/QwAAAAAAAAAAAAAAAAAAAAAIQn9DAAAAAAAAAAAAAAAAAAAAAAhCv0MAAAAAAAAAAAAAAAAAAAAACEL/QwAAAAAAAAAAAAAAAAAAAAAIQz9DAAAAAAAAAAAAAAAAAAAAAAhDf0MAAAAAAAAAAAAAAAAAAAAACEOQQAhBgJAA0AgBiAXTw0BIAAgBkECdGohGSAVIAZBAnRqIRogFiAGQQJ0aiEbIBn9AAQAIQ8gGf0ABBAhECAZ/QAEICERIBn9AAQwIRIgByAPIBr9AAQA/eYB/eQBIQcgCCAQIBr9AAQQ/eYB/eQBIQggCSARIBr9AAQg/eYB/eQBIQkgCiASIBr9AAQw/eYB/eQBIQogCyAPIBv9AAQA/eYB/eQBIQsgDCAQIBv9AAQQ/eYB/eQBIQwgDSARIBv9AAQg/eYB/eQBIQ0gDiASIBv9AAQw/eYB/eQBIQ4gBkEQaiEGDAALCyAHIAj95AEgCSAK/eQB/eQBIQcgCyAM/eQBIA0gDv3kAf3kASELAkADQCAGIBhPDQEgACAGQQJ0aiEZIBUgBkECdGohGiAWIAZBAnRqIRsgGf0ABAAhDyAHIA8gGv0ABAD95gH95AEhByALIA8gG/0ABAD95gH95AEhCyAGQQRqIQYMAAsLIAf9HwAgB/0fAZIgB/0fAiAH/R8DkpIhEyAL/R8AIAv9HwGSIAv9HwIgC/0fA5KSIRQCQANAIAYgBE8NASAAIAZBAnRqIRkgFSAGQQJ0aiEaIBYgBkECdGohGyATIBkqAgAgGioCAJSSIRMgFCAZKgIAIBsqAgCUkiEUIAZBAWohBgwACwsgAiAFQQJ0aiATOAIAIAIgBUEBakECdGogFDgCACAFQQJqIQUMAAsLIAUgA0kEQCABIAUgHGxqIRX9DAAAAAAAAAAAAAAAAAAAAAAhB/0MAAAAAAAAAAAAAAAAAAAAACEI/QwAAAAAAAAAAAAAAAAAAAAAIQn9DAAAAAAAAAAAAAAAAAAAAAAhCkEAIQYCQANAIAYgF08NASAAIAZBAnRqIRkgFSAGQQJ0aiEaIAcgGf0ABAAgGv0ABAD95gH95AEhByAIIBn9AAQQIBr9AAQQ/eYB/eQBIQggCSAZ/QAEICAa/QAEIP3mAf3kASEJIAogGf0ABDAgGv0ABDD95gH95AEhCiAGQRBqIQYMAAsLIAcgCP3kASAJIAr95AH95AEhBwJAA0AgBiAYTw0BIAAgBkECdGohGSAVIAZBAnRqIRogByAZ/QAEACAa/QAEAP3mAf3kASEHIAZBBGohBgwACwsgB/0fACAH/R8BkiAH/R8CIAf9HwOSkiETAkADQCAGIARPDQEgACAGQQJ0aiEZIBUgBkECdGohGiATIBkqAgAgGioCAJSSIRMgBkEBaiEGDAALCyACIAVBAnRqIBM4AgALCw==\";\n\nexport function getSimdWasmBinary(): Uint8Array {\n const binaryString = atob(SIMD_WASM_BASE64);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return bytes;\n}\n","/**\n * WASM SIMD compute layer.\n * Compiles the hand-written WAT module and provides typed wrappers\n * that operate on shared WebAssembly.Memory.\n */\n\nexport interface WasmExports {\n normalize(ptr: number, dimensions: number): void;\n search_all(queryPtr: number, dbPtr: number, scoresPtr: number, dbSize: number, dimensions: number): void;\n}\n\n/**\n * Instantiates a WASM module with the given memory and returns typed exports.\n */\nexport async function instantiateWasm(wasmBinary: Uint8Array, memory: WebAssembly.Memory): Promise<WasmExports> {\n const importObject = { env: { memory } };\n const result = await WebAssembly.instantiate(wasmBinary, importObject);\n // WebAssembly.instantiate with a buffer returns { instance, module }\n const instance = (result as unknown as { instance: WebAssembly.Instance }).instance;\n return instance.exports as unknown as WasmExports;\n}\n","/**\n * VectorDB — Key-Value Vector Database\n *\n * Decoupled from embedding providers. Users pass pre-computed vectors\n * as number arrays (or Float32Array) with string keys.\n *\n * Supports:\n * - set/get/setMany/getMany for key-value CRUD\n * - query for similarity search (dot product on normalized vectors)\n * - flush to persist, close to flush+release, clear to wipe\n * - Streaming export/import using Web Streams API\n * - Last-write-wins semantics for duplicate keys (append-only storage)\n */\n\nimport { normalize, searchAll } from \"./compute\";\nimport { VectorCapacityExceededError } from \"./errors\";\nimport { decodeLexicon, encodeLexicon } from \"./lexicon\";\nimport { MemoryManager } from \"./memory-manager\";\nimport type { ResultItem } from \"./result-set\";\nimport { iterableResults, topKResults } from \"./result-set\";\nimport { getSimdWasmBinary } from \"./simd-binary\";\nimport type { StorageProvider } from \"./storage\";\nimport { OPFSStorageProvider } from \"./storage\";\nimport type { OpenOptions, OpenOptionsInternal, QueryOptions, SetOptions, VectorInput } from \"./types\";\nimport { instantiateWasm, type WasmExports } from \"./wasm-compute\";\n\nconst VECTORS_FILE = \"vectors.bin\";\nconst KEYS_FILE = \"keys.bin\";\n\n/** Binary export format magic bytes: \"EGDB\" */\nconst EXPORT_MAGIC = 0x42444745; // \"EGDB\" in little-endian\nconst EXPORT_VERSION = 1;\nconst EXPORT_HEADER_BYTES = 24;\n\n/** Chunk size for streaming export/import (64KB, matches WASM page size) */\nconst STREAM_CHUNK_SIZE = 65536;\n\nexport class VectorDB {\n private readonly memoryManager: MemoryManager;\n private readonly storage: StorageProvider;\n private readonly dimensions: number;\n private readonly shouldNormalize: boolean;\n private wasmExports: WasmExports | null;\n\n /** Maps key to its slot index in the vector array */\n private keyToSlot: Map<string, number>;\n\n /** Maps slot index back to its key */\n private slotToKey: string[];\n\n /** Whether this instance has been closed */\n private closed = false;\n\n private constructor(\n memoryManager: MemoryManager,\n storage: StorageProvider,\n dimensions: number,\n shouldNormalize: boolean,\n wasmExports: WasmExports | null,\n keyToSlot: Map<string, number>,\n slotToKey: string[],\n ) {\n this.memoryManager = memoryManager;\n this.storage = storage;\n this.dimensions = dimensions;\n this.shouldNormalize = shouldNormalize;\n this.wasmExports = wasmExports;\n this.keyToSlot = keyToSlot;\n this.slotToKey = slotToKey;\n }\n\n /**\n * Opens a VectorDB instance.\n * Loads existing data from storage into WASM memory.\n */\n static async open(options: OpenOptions): Promise<VectorDB>;\n static async open(options: OpenOptionsInternal): Promise<VectorDB>;\n static async open(options: OpenOptionsInternal): Promise<VectorDB> {\n const name = options.name ?? \"default\";\n const storage = options.storage ?? new OPFSStorageProvider(name);\n const shouldNormalize = options.normalize !== false;\n\n // Load existing data from storage\n const [vectorBytes, keysBytes] = await Promise.all([storage.readAll(VECTORS_FILE), storage.readAll(KEYS_FILE)]);\n\n // Decode stored keys\n const keys = keysBytes.byteLength > 0 ? decodeLexicon(keysBytes) : [];\n const vectorCount = vectorBytes.byteLength / (options.dimensions * 4);\n\n // Build key-to-slot mapping.\n // flush() always writes deduplicated state, so keys are unique on load.\n const keyToSlot = new Map<string, number>();\n const slotToKey: string[] = [];\n\n for (let i = 0; i < keys.length; i++) {\n keyToSlot.set(keys[i], i);\n slotToKey[i] = keys[i];\n }\n\n // Initialize memory manager\n const mm = new MemoryManager(options.dimensions, vectorCount);\n\n if (vectorBytes.byteLength > 0) {\n mm.loadVectorBytes(vectorBytes, vectorCount);\n }\n\n // Try to instantiate WASM SIMD module\n let wasmExports: WasmExports | null = null;\n const wasmBinary = options.wasmBinary !== undefined ? options.wasmBinary : getSimdWasmBinary();\n if (wasmBinary !== null) {\n try {\n wasmExports = await instantiateWasm(wasmBinary, mm.memory);\n } catch {\n // Fall back to JS compute\n }\n }\n\n return new VectorDB(mm, storage, options.dimensions, shouldNormalize, wasmExports, keyToSlot, slotToKey);\n }\n\n /** Total number of key-value pairs in the database */\n get size(): number {\n return this.keyToSlot.size;\n }\n\n /**\n * Set a key-value pair. If the key already exists, its vector is overwritten (last-write-wins).\n * The value is a number[] or Float32Array of length equal to the configured dimensions.\n */\n set(key: string, value: VectorInput, options?: SetOptions): void {\n this.assertOpen();\n\n if (value.length !== this.dimensions) {\n throw new Error(`Vector dimension mismatch: expected ${this.dimensions}, got ${value.length}`);\n }\n\n // Convert to Float32Array (also clones to avoid mutating caller's array)\n const vec = new Float32Array(value);\n\n // Normalize if needed\n const doNormalize = options?.normalize ?? this.shouldNormalize;\n if (doNormalize) {\n this.normalizeVector(vec);\n }\n\n const existingSlot = this.keyToSlot.get(key);\n if (existingSlot !== undefined) {\n // Overwrite existing slot\n this.memoryManager.writeVector(existingSlot, vec);\n } else {\n // Append new entry\n const newTotal = this.memoryManager.vectorCount + 1;\n if (newTotal > this.memoryManager.maxVectors) {\n throw new VectorCapacityExceededError(this.memoryManager.maxVectors);\n }\n this.memoryManager.ensureCapacity(1);\n const slotIndex = this.memoryManager.vectorCount;\n this.memoryManager.appendVectors([vec]);\n this.keyToSlot.set(key, slotIndex);\n this.slotToKey[slotIndex] = key;\n }\n }\n\n /**\n * Get the stored vector for a key. Returns undefined if the key does not exist.\n * Returns a copy of the stored vector as a plain number array.\n */\n get(key: string): number[] | undefined {\n this.assertOpen();\n\n const slot = this.keyToSlot.get(key);\n if (slot === undefined) return undefined;\n\n // Return a plain array copy so callers can't corrupt WASM memory\n return Array.from(this.memoryManager.readVector(slot));\n }\n\n /**\n * Set multiple key-value pairs at once. Last-write-wins applies within the batch.\n */\n setMany(entries: [string, VectorInput][]): void {\n for (const [key, value] of entries) {\n this.set(key, value);\n }\n }\n\n /**\n * Get vectors for multiple keys. Returns undefined for keys that don't exist.\n */\n getMany(keys: string[]): (number[] | undefined)[] {\n return keys.map((key) => this.get(key));\n }\n\n /**\n * Search for the most similar vectors to the given query vector.\n *\n * Default: returns a plain ResultItem[] sorted by descending similarity.\n * With `{ iterable: true }`: returns a lazy Iterable<ResultItem> where keys\n * are resolved only as each item is consumed.\n *\n * Similarity is the dot product of query and stored vectors. With\n * normalization (default), this equals cosine similarity: 1 = identical,\n * -1 = opposite.\n */\n query(value: VectorInput, options: QueryOptions & { iterable: true }): Iterable<ResultItem>;\n query(value: VectorInput, options?: QueryOptions): ResultItem[];\n query(value: VectorInput, options?: QueryOptions): ResultItem[] | Iterable<ResultItem> {\n this.assertOpen();\n\n const k = options?.topK ?? Infinity;\n const minSimilarity = options?.minSimilarity;\n const iterable = options && \"iterable\" in options && options.iterable;\n\n if (this.size === 0) {\n return [];\n }\n\n if (value.length !== this.dimensions) {\n throw new Error(`Query vector dimension mismatch: expected ${this.dimensions}, got ${value.length}`);\n }\n\n // Convert to Float32Array and optionally normalize the query vector\n const queryVec = new Float32Array(value);\n const doNormalize = options?.normalize ?? this.shouldNormalize;\n if (doNormalize) {\n this.normalizeVector(queryVec);\n }\n\n // Write query to WASM memory\n this.memoryManager.writeQuery(queryVec);\n\n // Ensure memory has space for scores buffer\n this.memoryManager.ensureCapacity(0);\n\n // Total vectors in memory\n const totalVectors = this.memoryManager.vectorCount;\n\n // Execute search\n const scoresOffset = this.memoryManager.scoresOffset;\n if (this.wasmExports) {\n this.wasmExports.search_all(\n this.memoryManager.queryOffset,\n this.memoryManager.dbOffset,\n scoresOffset,\n totalVectors,\n this.dimensions,\n );\n } else {\n const queryView = new Float32Array(\n this.memoryManager.memory.buffer,\n this.memoryManager.queryOffset,\n this.dimensions,\n );\n const dbView = new Float32Array(\n this.memoryManager.memory.buffer,\n this.memoryManager.dbOffset,\n totalVectors * this.dimensions,\n );\n const scoresView = new Float32Array(this.memoryManager.memory.buffer, scoresOffset, totalVectors);\n searchAll(queryView, dbView, scoresView, totalVectors, this.dimensions);\n }\n\n // Read scores (make a copy so the buffer can be reused)\n const scores = new Float32Array(this.memoryManager.readScores());\n\n // Resolve key from slot index\n const slotToKey = this.slotToKey;\n const resolveKey = (slotIndex: number): string => {\n return slotToKey[slotIndex];\n };\n\n if (iterable) {\n return iterableResults(scores, resolveKey, k, minSimilarity);\n }\n return topKResults(scores, resolveKey, k, minSimilarity);\n }\n\n /**\n * Persist the current in-memory state to storage.\n */\n async flush(): Promise<void> {\n this.assertOpen();\n\n const totalVectors = this.memoryManager.vectorCount;\n\n // Serialize vectors from WASM memory\n const vectorBytes = new Uint8Array(totalVectors * this.dimensions * 4);\n if (totalVectors > 0) {\n const src = new Uint8Array(\n this.memoryManager.memory.buffer,\n this.memoryManager.dbOffset,\n totalVectors * this.dimensions * 4,\n );\n vectorBytes.set(src);\n }\n\n // Serialize keys using lexicon format\n const keysBytes = encodeLexicon(this.slotToKey);\n\n await Promise.all([this.storage.write(VECTORS_FILE, vectorBytes), this.storage.write(KEYS_FILE, keysBytes)]);\n }\n\n /**\n * Flush data to storage and release the instance.\n * The instance cannot be used after close.\n */\n async close(): Promise<void> {\n if (this.closed) return;\n await this.flush();\n this.closed = true;\n }\n\n /**\n * Clear all data from the database and storage.\n */\n async clear(): Promise<void> {\n this.assertOpen();\n\n this.keyToSlot.clear();\n this.slotToKey.length = 0;\n this.memoryManager.reset();\n\n await this.storage.destroy();\n }\n\n /**\n * Export the entire database as a ReadableStream of binary chunks.\n *\n * Format: [Header 24 bytes][Vector data][Keys data]\n * Header: magic(4) + version(4) + dimensions(4) + vectorCount(4) + vectorDataLen(4) + keysDataLen(4)\n *\n * Vectors are streamed in 64KB chunks from WASM memory to avoid large\n * heap allocations.\n */\n async export(): Promise<ReadableStream<Uint8Array>> {\n this.assertOpen();\n\n const totalVectors = this.memoryManager.vectorCount;\n const vectorDataLen = totalVectors * this.dimensions * 4;\n\n // Encode keys (typically much smaller than vectors)\n const keysBytes = encodeLexicon(this.slotToKey);\n const keysDataLen = keysBytes.byteLength;\n\n // Build header\n const header = new ArrayBuffer(EXPORT_HEADER_BYTES);\n const headerView = new DataView(header);\n headerView.setUint32(0, EXPORT_MAGIC, true);\n headerView.setUint32(4, EXPORT_VERSION, true);\n headerView.setUint32(8, this.dimensions, true);\n headerView.setUint32(12, totalVectors, true);\n headerView.setUint32(16, vectorDataLen, true);\n headerView.setUint32(20, keysDataLen, true);\n\n const mm = this.memoryManager;\n let phase: \"header\" | \"vectors\" | \"keys\" | \"done\" = \"header\";\n let vectorOffset = 0;\n\n return new ReadableStream<Uint8Array>({\n pull(controller) {\n switch (phase) {\n case \"header\":\n controller.enqueue(new Uint8Array(header));\n phase = vectorDataLen > 0 ? \"vectors\" : keysDataLen > 0 ? \"keys\" : \"done\";\n if (phase === \"done\") controller.close();\n break;\n\n case \"vectors\": {\n const remaining = vectorDataLen - vectorOffset;\n const chunkSize = Math.min(remaining, STREAM_CHUNK_SIZE);\n const chunk = new Uint8Array(chunkSize);\n chunk.set(new Uint8Array(mm.memory.buffer, mm.dbOffset + vectorOffset, chunkSize));\n controller.enqueue(chunk);\n vectorOffset += chunkSize;\n if (vectorOffset >= vectorDataLen) {\n phase = keysDataLen > 0 ? \"keys\" : \"done\";\n if (phase === \"done\") controller.close();\n }\n break;\n }\n\n case \"keys\":\n controller.enqueue(keysBytes);\n phase = \"done\";\n controller.close();\n break;\n }\n },\n });\n }\n\n /**\n * Import data from a ReadableStream, replacing all existing data.\n * Performs a dimension check against the configured dimensions.\n *\n * Vectors are streamed directly into WASM memory in chunks to avoid\n * large heap allocations.\n */\n async import(stream: ReadableStream<Uint8Array>): Promise<void> {\n this.assertOpen();\n\n const sr = new StreamReader(stream);\n\n // Read and validate header\n const headerBytes = await sr.readExact(EXPORT_HEADER_BYTES);\n const headerView = new DataView(headerBytes.buffer, headerBytes.byteOffset, headerBytes.byteLength);\n\n const magic = headerView.getUint32(0, true);\n if (magic !== EXPORT_MAGIC) {\n throw new Error(\"Invalid import data: unrecognized format\");\n }\n\n const version = headerView.getUint32(4, true);\n if (version !== EXPORT_VERSION) {\n throw new Error(`Unsupported import version: expected ${EXPORT_VERSION}, got ${version}`);\n }\n\n const dimensions = headerView.getUint32(8, true);\n if (dimensions !== this.dimensions) {\n throw new Error(`Import dimension mismatch: expected ${this.dimensions}, got ${dimensions}`);\n }\n\n const vectorCount = headerView.getUint32(12, true);\n const vectorDataLen = headerView.getUint32(16, true);\n const keysDataLen = headerView.getUint32(20, true);\n\n // Clear existing state\n this.keyToSlot.clear();\n this.slotToKey.length = 0;\n this.memoryManager.reset();\n\n // Stream vectors directly into WASM memory in chunks\n if (vectorCount > 0) {\n this.memoryManager.ensureCapacity(vectorCount);\n\n let offset = 0;\n await sr.readChunked(vectorDataLen, (chunk) => {\n new Uint8Array(this.memoryManager.memory.buffer, this.memoryManager.dbOffset + offset, chunk.byteLength).set(\n chunk,\n );\n offset += chunk.byteLength;\n });\n\n this.memoryManager.setVectorCount(vectorCount);\n }\n\n // Read and decode keys (typically much smaller than vectors)\n if (keysDataLen > 0) {\n const keysBytes = await sr.readExact(keysDataLen);\n const keys = decodeLexicon(keysBytes);\n for (let i = 0; i < keys.length; i++) {\n this.keyToSlot.set(keys[i], i);\n this.slotToKey[i] = keys[i];\n }\n }\n\n sr.release();\n }\n\n /**\n * Normalize a vector using WASM (if available) or JS fallback.\n */\n private normalizeVector(vec: Float32Array): void {\n if (this.wasmExports) {\n const ptr = this.memoryManager.queryOffset;\n new Float32Array(this.memoryManager.memory.buffer, ptr, vec.length).set(vec);\n this.wasmExports.normalize(ptr, vec.length);\n const normalized = new Float32Array(this.memoryManager.memory.buffer, ptr, vec.length);\n vec.set(normalized);\n } else {\n normalize(vec);\n }\n }\n\n private assertOpen(): void {\n if (this.closed) {\n throw new Error(\"VectorDB instance has been closed\");\n }\n }\n}\n\n/**\n * Helper for reading exact byte counts from a ReadableStream.\n * Handles chunk boundaries transparently.\n */\nclass StreamReader {\n private reader: ReadableStreamDefaultReader<Uint8Array>;\n private buffer = new Uint8Array(0);\n\n constructor(stream: ReadableStream<Uint8Array>) {\n this.reader = stream.getReader();\n }\n\n /** Read exactly `n` bytes, accumulating from stream chunks as needed. */\n async readExact(n: number): Promise<Uint8Array> {\n if (n === 0) return new Uint8Array(0);\n\n // Fast path: buffer already has enough data\n if (this.buffer.byteLength >= n) {\n const result = this.buffer.subarray(0, n);\n this.buffer = this.buffer.subarray(n);\n return result;\n }\n\n // Collect chunks until we have enough bytes\n const chunks: Uint8Array[] = [];\n let total = this.buffer.byteLength;\n if (total > 0) {\n chunks.push(this.buffer);\n this.buffer = new Uint8Array(0);\n }\n\n while (total < n) {\n const { done, value } = await this.reader.read();\n if (done) throw new Error(\"Invalid import data: unexpected end of stream\");\n chunks.push(value);\n total += value.byteLength;\n }\n\n // Combine into a single buffer\n const combined = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n combined.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n if (total > n) {\n this.buffer = combined.subarray(n);\n return combined.subarray(0, n);\n }\n return combined;\n }\n\n /**\n * Read `totalBytes` from the stream in chunks, calling `onChunk` for each.\n * Avoids allocating a single large buffer for the full data.\n */\n async readChunked(totalBytes: number, onChunk: (chunk: Uint8Array) => void): Promise<void> {\n let remaining = totalBytes;\n\n // Drain buffered leftover first\n if (this.buffer.byteLength > 0) {\n const take = Math.min(this.buffer.byteLength, remaining);\n onChunk(this.buffer.subarray(0, take));\n remaining -= take;\n this.buffer = this.buffer.subarray(take);\n }\n\n while (remaining > 0) {\n const { done, value } = await this.reader.read();\n if (done) throw new Error(\"Invalid import data: unexpected end of stream\");\n\n if (value.byteLength <= remaining) {\n onChunk(value);\n remaining -= value.byteLength;\n } else {\n onChunk(value.subarray(0, remaining));\n this.buffer = value.slice(remaining);\n remaining = 0;\n }\n }\n }\n\n /** Release the stream reader lock. */\n release(): void {\n this.reader.releaseLock();\n }\n}\n"],"names":["VectorCapacityExceededError","maxVectors","OPFSStorageProvider","dirName","root","fileName","buffer","data","fileHandle","writable","file","InMemoryStorageProvider","chunks","totalSize","sum","c","result","offset","chunk","normalize","vec","sumSq","i","mag","invMag","searchAll","query","db","scores","dbSize","dimensions","dot","j","encoder","decoder","encodeLexicon","texts","encoded","t","e","view","bytes","decodeLexicon","len","text","PAGE_SIZE","MAX_PAGES","MemoryManager","initialVectorCount","queryBytes","dbBytes","totalBytes","initialPages","availableBytes","bytesPerVector","additionalVectors","newTotal","requiredBytes","currentBytes","pagesNeeded","vector","vectors","startOffset","vectorCount","index","count","topKResults","resolveKey","topK","minSimilarity","n","indices","a","b","k","results","idx","similarity","iterableResults","SIMD_WASM_BASE64","getSimdWasmBinary","binaryString","instantiateWasm","wasmBinary","memory","importObject","VECTORS_FILE","KEYS_FILE","EXPORT_MAGIC","EXPORT_VERSION","EXPORT_HEADER_BYTES","STREAM_CHUNK_SIZE","VectorDB","memoryManager","storage","shouldNormalize","wasmExports","keyToSlot","slotToKey","options","name","vectorBytes","keysBytes","keys","mm","key","value","existingSlot","slotIndex","slot","entries","iterable","queryVec","totalVectors","scoresOffset","queryView","dbView","scoresView","src","vectorDataLen","keysDataLen","header","headerView","phase","vectorOffset","controller","remaining","chunkSize","stream","sr","StreamReader","headerBytes","version","ptr","normalized","total","done","combined","onChunk","take"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- (function(h,l){typeof exports=="object"&&typeof module<"u"?l(exports):typeof define=="function"&&define.amd?define(["exports"],l):(h=typeof globalThis<"u"?globalThis:h||self,l(h.EigenDB={}))})(this,(function(h){"use strict";class l extends Error{constructor(e){super(`Capacity exceeded. Max vectors for this dimension size is ~${e}.`),this.name="VectorCapacityExceededError"}}class u{dirHandle=null;dirName;constructor(e){this.dirName=e}async getDir(){if(!this.dirHandle){const e=await navigator.storage.getDirectory();this.dirHandle=await e.getDirectoryHandle(this.dirName,{create:!0})}return this.dirHandle}async readAll(e){try{const r=await(await(await(await this.getDir()).getFileHandle(e)).getFile()).arrayBuffer();return new Uint8Array(r)}catch{return new Uint8Array(0)}}async append(e,A){const t=await(await this.getDir()).getFileHandle(e,{create:!0}),r=await t.createWritable({keepExistingData:!0}),o=await t.getFile();await r.seek(o.size),await r.write(A),await r.close()}async write(e,A){const r=await(await(await this.getDir()).getFileHandle(e,{create:!0})).createWritable({keepExistingData:!1});await r.write(A),await r.close()}async destroy(){await(await navigator.storage.getDirectory()).removeEntry(this.dirName,{recursive:!0}),this.dirHandle=null}}class E{files=new Map;async readAll(e){const A=this.files.get(e);if(!A||A.length===0)return new Uint8Array(0);const s=A.reduce((o,a)=>o+a.byteLength,0),t=new Uint8Array(s);let r=0;for(const o of A)t.set(o,r),r+=o.byteLength;return t}async append(e,A){this.files.has(e)||this.files.set(e,[]),this.files.get(e).push(new Uint8Array(A))}async write(e,A){this.files.set(e,[new Uint8Array(A)])}async destroy(){this.files.clear()}}function b(n){let e=0;for(let t=0;t<n.length;t++)e+=n[t]*n[t];const A=Math.sqrt(e);if(A===0)return;const s=1/A;for(let t=0;t<n.length;t++)n[t]*=s}function M(n,e,A,s,t){for(let r=0;r<s;r++){let o=0;const a=r*t;for(let i=0;i<t;i++)o+=n[i]*e[a+i];A[r]=o}}const S=new TextEncoder,D=new TextDecoder;function k(n){const e=n.map(a=>S.encode(a)),A=e.reduce((a,i)=>a+4+i.byteLength,0),s=new ArrayBuffer(A),t=new DataView(s),r=new Uint8Array(s);let o=0;for(const a of e)t.setUint32(o,a.byteLength,!0),o+=4,r.set(a,o),o+=a.byteLength;return r}function v(n){const e=[],A=new DataView(n.buffer,n.byteOffset,n.byteLength);let s=0;for(;s<n.byteLength;){const t=A.getUint32(s,!0);s+=4;const r=D.decode(n.subarray(s,s+t));e.push(r),s+=t}return e}const y=65536,w=65536;class G{memory;dimensions;queryOffset;dbOffset;_vectorCount;constructor(e,A=0){this.dimensions=e,this.queryOffset=0;const s=e*4;this.dbOffset=Math.ceil(s/y)*y;const t=A*e*4,r=this.dbOffset+t,o=Math.max(1,Math.ceil(r/y));this.memory=new WebAssembly.Memory({initial:o}),this._vectorCount=A}get vectorCount(){return this._vectorCount}get scoresOffset(){return this.dbOffset+this._vectorCount*this.dimensions*4}get scoresBytes(){return this._vectorCount*4}get maxVectors(){const e=w*y-this.dbOffset,A=this.dimensions*4+4;return Math.floor(e/A)}ensureCapacity(e){const A=this._vectorCount+e,s=this.dbOffset+A*this.dimensions*4+A*4,t=this.memory.buffer.byteLength;if(s>t){const r=Math.ceil((s-t)/y);if(t/y+r>w)throw new Error("WASM memory limit exceeded");this.memory.grow(r)}}writeQuery(e){new Float32Array(this.memory.buffer,this.queryOffset,this.dimensions).set(e)}appendVectors(e){const A=this.dbOffset+this._vectorCount*this.dimensions*4;let s=A;for(const t of e)new Float32Array(this.memory.buffer,s,this.dimensions).set(t),s+=this.dimensions*4;return this._vectorCount+=e.length,A}loadVectorBytes(e,A){new Uint8Array(this.memory.buffer,this.dbOffset,e.byteLength).set(e),this._vectorCount=A}readScores(){return new Float32Array(this.memory.buffer,this.scoresOffset,this._vectorCount)}readVector(e){const A=this.dbOffset+e*this.dimensions*4;return new Float32Array(this.memory.buffer,A,this.dimensions)}writeVector(e,A){const s=this.dbOffset+e*this.dimensions*4;new Float32Array(this.memory.buffer,s,this.dimensions).set(A)}reset(){this._vectorCount=0}}function p(n,e,A,s){const t=n.length;if(t===0)return[];const r=new Uint32Array(t);for(let i=0;i<t;i++)r[i]=i;r.sort((i,c)=>n[c]-n[i]);const o=Math.min(A,t),a=[];for(let i=0;i<o;i++){const c=r[i],g=1-n[c];if(s!==void 0&&g>s)break;a.push({key:e(c),distance:g})}return a}function F(n,e,A,s){const t=n.length;if(t===0)return[];const r=new Uint32Array(t);for(let a=0;a<t;a++)r[a]=a;r.sort((a,i)=>n[i]-n[a]);const o=Math.min(A,t);return{[Symbol.iterator](){let a=0;return{next(){if(a>=o)return{done:!0,value:void 0};const i=r[a++],c=1-n[i];return s!==void 0&&c>s?{done:!0,value:void 0}:{done:!1,value:{key:e(i),distance:c}}}}}}}const H="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";function O(){const n=atob(H),e=new Uint8Array(n.length);for(let A=0;A<n.length;A++)e[A]=n.charCodeAt(A);return e}async function x(n,e){const A={env:{memory:e}};return(await WebAssembly.instantiate(n,A)).instance.exports}const Q="vectors.bin",C="keys.bin";class I{memoryManager;storage;dimensions;shouldNormalize;wasmExports;keyToSlot;slotToKey;closed=!1;constructor(e,A,s,t,r,o,a){this.memoryManager=e,this.storage=A,this.dimensions=s,this.shouldNormalize=t,this.wasmExports=r,this.keyToSlot=o,this.slotToKey=a}static async open(e){const A=e.name??"default",s=e.storage??new u(A),t=e.normalize!==!1,[r,o]=await Promise.all([s.readAll(Q),s.readAll(C)]),a=o.byteLength>0?v(o):[],i=r.byteLength/(e.dimensions*4),c=new Map,g=[];for(let f=0;f<a.length;f++)c.set(a[f],f),g[f]=a[f];const d=new G(e.dimensions,i);r.byteLength>0&&d.loadVectorBytes(r,i);let B=null;const m=e.wasmBinary!==void 0?e.wasmBinary:O();if(m!==null)try{B=await x(m,d.memory)}catch{}return new I(d,s,e.dimensions,t,B,c,g)}get size(){return this.keyToSlot.size}set(e,A,s){if(this.assertOpen(),A.length!==this.dimensions)throw new Error(`Vector dimension mismatch: expected ${this.dimensions}, got ${A.length}`);const t=new Float32Array(A);(s?.normalize??this.shouldNormalize)&&this.normalizeVector(t);const o=this.keyToSlot.get(e);if(o!==void 0)this.memoryManager.writeVector(o,t);else{if(this.memoryManager.vectorCount+1>this.memoryManager.maxVectors)throw new l(this.memoryManager.maxVectors);this.memoryManager.ensureCapacity(1);const i=this.memoryManager.vectorCount;this.memoryManager.appendVectors([t]),this.keyToSlot.set(e,i),this.slotToKey[i]=e}}get(e){this.assertOpen();const A=this.keyToSlot.get(e);if(A!==void 0)return Array.from(this.memoryManager.readVector(A))}setMany(e){for(const[A,s]of e)this.set(A,s)}getMany(e){return e.map(A=>this.get(A))}query(e,A){this.assertOpen();const s=A?.topK??1/0,t=A?.maxDistance,r=A&&"iterable"in A&&A.iterable;if(this.size===0)return[];if(e.length!==this.dimensions)throw new Error(`Query vector dimension mismatch: expected ${this.dimensions}, got ${e.length}`);const o=new Float32Array(e);(A?.normalize??this.shouldNormalize)&&this.normalizeVector(o),this.memoryManager.writeQuery(o),this.memoryManager.ensureCapacity(0);const i=this.memoryManager.vectorCount,c=this.memoryManager.scoresOffset;if(this.wasmExports)this.wasmExports.search_all(this.memoryManager.queryOffset,this.memoryManager.dbOffset,c,i,this.dimensions);else{const m=new Float32Array(this.memoryManager.memory.buffer,this.memoryManager.queryOffset,this.dimensions),f=new Float32Array(this.memoryManager.memory.buffer,this.memoryManager.dbOffset,i*this.dimensions),R=new Float32Array(this.memoryManager.memory.buffer,c,i);M(m,f,R,i,this.dimensions)}const g=new Float32Array(this.memoryManager.readScores()),d=this.slotToKey,B=m=>d[m];return r?F(g,B,s,t):p(g,B,s,t)}async flush(){this.assertOpen();const e=this.memoryManager.vectorCount,A=new Uint8Array(e*this.dimensions*4);if(e>0){const t=new Uint8Array(this.memoryManager.memory.buffer,this.memoryManager.dbOffset,e*this.dimensions*4);A.set(t)}const s=k(this.slotToKey);await Promise.all([this.storage.write(Q,A),this.storage.write(C,s)])}async close(){this.closed||(await this.flush(),this.closed=!0)}async clear(){this.assertOpen(),this.keyToSlot.clear(),this.slotToKey.length=0,this.memoryManager.reset(),await this.storage.destroy()}normalizeVector(e){if(this.wasmExports){const A=this.memoryManager.queryOffset;new Float32Array(this.memoryManager.memory.buffer,A,e.length).set(e),this.wasmExports.normalize(A,e.length);const s=new Float32Array(this.memoryManager.memory.buffer,A,e.length);e.set(s)}else b(e)}assertOpen(){if(this.closed)throw new Error("VectorDB instance has been closed")}}h.DB=I,h.InMemoryStorageProvider=E,h.OPFSStorageProvider=u,h.VectorCapacityExceededError=l,Object.defineProperty(h,Symbol.toStringTag,{value:"Module"})}));
1
+ (function(l,d){typeof exports=="object"&&typeof module<"u"?d(exports):typeof define=="function"&&define.amd?define(["exports"],d):(l=typeof globalThis<"u"?globalThis:l||self,d(l.EigenDB={}))})(this,(function(l){"use strict";class d extends Error{constructor(e){super(`Capacity exceeded. Max vectors for this dimension size is ~${e}.`),this.name="VectorCapacityExceededError"}}class B{dirHandle=null;dirName;constructor(e){this.dirName=e}async getDir(){if(!this.dirHandle){const e=await navigator.storage.getDirectory();this.dirHandle=await e.getDirectoryHandle(this.dirName,{create:!0})}return this.dirHandle}async readAll(e){try{const r=await(await(await(await this.getDir()).getFileHandle(e)).getFile()).arrayBuffer();return new Uint8Array(r)}catch{return new Uint8Array(0)}}async append(e,t){const A=await(await this.getDir()).getFileHandle(e,{create:!0}),r=await A.createWritable({keepExistingData:!0}),n=await A.getFile();await r.seek(n.size),await r.write(t),await r.close()}async write(e,t){const r=await(await(await this.getDir()).getFileHandle(e,{create:!0})).createWritable({keepExistingData:!1});await r.write(t),await r.close()}async destroy(){await(await navigator.storage.getDirectory()).removeEntry(this.dirName,{recursive:!0}),this.dirHandle=null}}class D{files=new Map;async readAll(e){const t=this.files.get(e);if(!t||t.length===0)return new Uint8Array(0);const s=t.reduce((n,o)=>n+o.byteLength,0),A=new Uint8Array(s);let r=0;for(const n of t)A.set(n,r),r+=n.byteLength;return A}async append(e,t){this.files.has(e)||this.files.set(e,[]),this.files.get(e).push(new Uint8Array(t))}async write(e,t){this.files.set(e,[new Uint8Array(t)])}async destroy(){this.files.clear()}}function v(a){let e=0;for(let A=0;A<a.length;A++)e+=a[A]*a[A];const t=Math.sqrt(e);if(t===0)return;const s=1/t;for(let A=0;A<a.length;A++)a[A]*=s}function p(a,e,t,s,A){for(let r=0;r<s;r++){let n=0;const o=r*A;for(let i=0;i<A;i++)n+=a[i]*e[o+i];t[r]=n}}const O=new TextEncoder,U=new TextDecoder;function Q(a){const e=a.map(o=>O.encode(o)),t=e.reduce((o,i)=>o+4+i.byteLength,0),s=new ArrayBuffer(t),A=new DataView(s),r=new Uint8Array(s);let n=0;for(const o of e)A.setUint32(n,o.byteLength,!0),n+=4,r.set(o,n),n+=o.byteLength;return r}function E(a){const e=[],t=new DataView(a.buffer,a.byteOffset,a.byteLength);let s=0;for(;s<a.byteLength;){const A=t.getUint32(s,!0);s+=4;const r=U.decode(a.subarray(s,s+A));e.push(r),s+=A}return e}const u=65536,C=65536;class L{memory;dimensions;queryOffset;dbOffset;_vectorCount;constructor(e,t=0){this.dimensions=e,this.queryOffset=0;const s=e*4;this.dbOffset=Math.ceil(s/u)*u;const A=t*e*4,r=this.dbOffset+A,n=Math.max(1,Math.ceil(r/u));this.memory=new WebAssembly.Memory({initial:n}),this._vectorCount=t}get vectorCount(){return this._vectorCount}get scoresOffset(){return this.dbOffset+this._vectorCount*this.dimensions*4}get scoresBytes(){return this._vectorCount*4}get maxVectors(){const e=C*u-this.dbOffset,t=this.dimensions*4+4;return Math.floor(e/t)}ensureCapacity(e){const t=this._vectorCount+e,s=this.dbOffset+t*this.dimensions*4+t*4,A=this.memory.buffer.byteLength;if(s>A){const r=Math.ceil((s-A)/u);if(A/u+r>C)throw new Error("WASM memory limit exceeded");this.memory.grow(r)}}writeQuery(e){new Float32Array(this.memory.buffer,this.queryOffset,this.dimensions).set(e)}appendVectors(e){const t=this.dbOffset+this._vectorCount*this.dimensions*4;let s=t;for(const A of e)new Float32Array(this.memory.buffer,s,this.dimensions).set(A),s+=this.dimensions*4;return this._vectorCount+=e.length,t}loadVectorBytes(e,t){new Uint8Array(this.memory.buffer,this.dbOffset,e.byteLength).set(e),this._vectorCount=t}readScores(){return new Float32Array(this.memory.buffer,this.scoresOffset,this._vectorCount)}readVector(e){const t=this.dbOffset+e*this.dimensions*4;return new Float32Array(this.memory.buffer,t,this.dimensions)}writeVector(e,t){const s=this.dbOffset+e*this.dimensions*4;new Float32Array(this.memory.buffer,s,this.dimensions).set(t)}reset(){this._vectorCount=0}setVectorCount(e){this._vectorCount=e}}function x(a,e,t,s){const A=a.length;if(A===0)return[];const r=new Uint32Array(A);for(let i=0;i<A;i++)r[i]=i;r.sort((i,c)=>a[c]-a[i]);const n=Math.min(t,A),o=[];for(let i=0;i<n;i++){const c=r[i],h=a[c];if(s!==void 0&&h<s)break;o.push({key:e(c),similarity:h})}return o}function G(a,e,t,s){const A=a.length;if(A===0)return[];const r=new Uint32Array(A);for(let o=0;o<A;o++)r[o]=o;r.sort((o,i)=>a[i]-a[o]);const n=Math.min(t,A);return{[Symbol.iterator](){let o=0;return{next(){if(o>=n)return{done:!0,value:void 0};const i=r[o++],c=a[i];return s!==void 0&&c<s?{done:!0,value:void 0}:{done:!1,value:{key:e(i),similarity:c}}}}}}}const T="AGFzbQEAAAABDgJgAn9/AGAFf39/f38AAg8BA2VudgZtZW1vcnkCAAEDAwIAAQcaAglub3JtYWxpemUAAApzZWFyY2hfYWxsAAEKgQ4C3wQFAX8EewN9AXsDf/0MAAAAAAAAAAAAAAAAAAAAACED/QwAAAAAAAAAAAAAAAAAAAAAIQT9DAAAAAAAAAAAAAAAAAAAAAAhBf0MAAAAAAAAAAAAAAAAAAAAACEGIAFBcHEhCyABQXxxIQxBACECAkADQCACIAtPDQEgACACQQJ0aiENIAMgDf0ABAAgDf0ABAD95gH95AEhAyAEIA39AAQQIA39AAQQ/eYB/eQBIQQgBSAN/QAEICAN/QAEIP3mAf3kASEFIAYgDf0ABDAgDf0ABDD95gH95AEhBiACQRBqIQIMAAsLIAMgBP3kASAFIAb95AH95AEhAwJAA0AgAiAMTw0BIAAgAkECdGohDSADIA39AAQAIA39AAQA/eYB/eQBIQMgAkEEaiECDAALCyAD/R8AIAP9HwGSIAP9HwIgA/0fA5KSIQcCQANAIAIgAU8NASAAIAJBAnRqIQ0gByANKgIAIA0qAgCUkiEHIAJBAWohAgwACwsgB5EhCCAIQwAAAABbBEAPC0MAAIA/IAiVIQkgCf0TIQpBACECAkADQCACIAtPDQEgACACQQJ0aiENIA0gDf0ABAAgCv3mAf0LBAAgDSAN/QAEECAK/eYB/QsEECANIA39AAQgIAr95gH9CwQgIA0gDf0ABDAgCv3mAf0LBDAgAkEQaiECDAALCwJAA0AgAiAMTw0BIAAgAkECdGohDSANIA39AAQAIAr95gH9CwQAIAJBBGohAgwACwsCQANAIAIgAU8NASAAIAJBAnRqIQ0gDSANKgIAIAmUOAIAIAJBAWohAgwACwsLnQkEAn8MewJ9CX8gBEFwcSEXIARBfHEhGCAEQQJ0IRwgA0F+cSEdQQAhBQJAA0AgBSAdTw0BIAEgBSAcbGohFSAVIBxqIRb9DAAAAAAAAAAAAAAAAAAAAAAhB/0MAAAAAAAAAAAAAAAAAAAAACEI/QwAAAAAAAAAAAAAAAAAAAAAIQn9DAAAAAAAAAAAAAAAAAAAAAAhCv0MAAAAAAAAAAAAAAAAAAAAACEL/QwAAAAAAAAAAAAAAAAAAAAAIQz9DAAAAAAAAAAAAAAAAAAAAAAhDf0MAAAAAAAAAAAAAAAAAAAAACEOQQAhBgJAA0AgBiAXTw0BIAAgBkECdGohGSAVIAZBAnRqIRogFiAGQQJ0aiEbIBn9AAQAIQ8gGf0ABBAhECAZ/QAEICERIBn9AAQwIRIgByAPIBr9AAQA/eYB/eQBIQcgCCAQIBr9AAQQ/eYB/eQBIQggCSARIBr9AAQg/eYB/eQBIQkgCiASIBr9AAQw/eYB/eQBIQogCyAPIBv9AAQA/eYB/eQBIQsgDCAQIBv9AAQQ/eYB/eQBIQwgDSARIBv9AAQg/eYB/eQBIQ0gDiASIBv9AAQw/eYB/eQBIQ4gBkEQaiEGDAALCyAHIAj95AEgCSAK/eQB/eQBIQcgCyAM/eQBIA0gDv3kAf3kASELAkADQCAGIBhPDQEgACAGQQJ0aiEZIBUgBkECdGohGiAWIAZBAnRqIRsgGf0ABAAhDyAHIA8gGv0ABAD95gH95AEhByALIA8gG/0ABAD95gH95AEhCyAGQQRqIQYMAAsLIAf9HwAgB/0fAZIgB/0fAiAH/R8DkpIhEyAL/R8AIAv9HwGSIAv9HwIgC/0fA5KSIRQCQANAIAYgBE8NASAAIAZBAnRqIRkgFSAGQQJ0aiEaIBYgBkECdGohGyATIBkqAgAgGioCAJSSIRMgFCAZKgIAIBsqAgCUkiEUIAZBAWohBgwACwsgAiAFQQJ0aiATOAIAIAIgBUEBakECdGogFDgCACAFQQJqIQUMAAsLIAUgA0kEQCABIAUgHGxqIRX9DAAAAAAAAAAAAAAAAAAAAAAhB/0MAAAAAAAAAAAAAAAAAAAAACEI/QwAAAAAAAAAAAAAAAAAAAAAIQn9DAAAAAAAAAAAAAAAAAAAAAAhCkEAIQYCQANAIAYgF08NASAAIAZBAnRqIRkgFSAGQQJ0aiEaIAcgGf0ABAAgGv0ABAD95gH95AEhByAIIBn9AAQQIBr9AAQQ/eYB/eQBIQggCSAZ/QAEICAa/QAEIP3mAf3kASEJIAogGf0ABDAgGv0ABDD95gH95AEhCiAGQRBqIQYMAAsLIAcgCP3kASAJIAr95AH95AEhBwJAA0AgBiAYTw0BIAAgBkECdGohGSAVIAZBAnRqIRogByAZ/QAEACAa/QAEAP3mAf3kASEHIAZBBGohBgwACwsgB/0fACAH/R8BkiAH/R8CIAf9HwOSkiETAkADQCAGIARPDQEgACAGQQJ0aiEZIBUgBkECdGohGiATIBkqAgAgGioCAJSSIRMgBkEBaiEGDAALCyACIAVBAnRqIBM4AgALCw==";function R(){const a=atob(T),e=new Uint8Array(a.length);for(let t=0;t<a.length;t++)e[t]=a.charCodeAt(t);return e}async function H(a,e){const t={env:{memory:e}};return(await WebAssembly.instantiate(a,t)).instance.exports}const b="vectors.bin",M="keys.bin",S=1111770949,w=1,k=24,V=65536;class I{memoryManager;storage;dimensions;shouldNormalize;wasmExports;keyToSlot;slotToKey;closed=!1;constructor(e,t,s,A,r,n,o){this.memoryManager=e,this.storage=t,this.dimensions=s,this.shouldNormalize=A,this.wasmExports=r,this.keyToSlot=n,this.slotToKey=o}static async open(e){const t=e.name??"default",s=e.storage??new B(t),A=e.normalize!==!1,[r,n]=await Promise.all([s.readAll(b),s.readAll(M)]),o=n.byteLength>0?E(n):[],i=r.byteLength/(e.dimensions*4),c=new Map,h=[];for(let m=0;m<o.length;m++)c.set(o[m],m),h[m]=o[m];const g=new L(e.dimensions,i);r.byteLength>0&&g.loadVectorBytes(r,i);let f=null;const y=e.wasmBinary!==void 0?e.wasmBinary:R();if(y!==null)try{f=await H(y,g.memory)}catch{}return new I(g,s,e.dimensions,A,f,c,h)}get size(){return this.keyToSlot.size}set(e,t,s){if(this.assertOpen(),t.length!==this.dimensions)throw new Error(`Vector dimension mismatch: expected ${this.dimensions}, got ${t.length}`);const A=new Float32Array(t);(s?.normalize??this.shouldNormalize)&&this.normalizeVector(A);const n=this.keyToSlot.get(e);if(n!==void 0)this.memoryManager.writeVector(n,A);else{if(this.memoryManager.vectorCount+1>this.memoryManager.maxVectors)throw new d(this.memoryManager.maxVectors);this.memoryManager.ensureCapacity(1);const i=this.memoryManager.vectorCount;this.memoryManager.appendVectors([A]),this.keyToSlot.set(e,i),this.slotToKey[i]=e}}get(e){this.assertOpen();const t=this.keyToSlot.get(e);if(t!==void 0)return Array.from(this.memoryManager.readVector(t))}setMany(e){for(const[t,s]of e)this.set(t,s)}getMany(e){return e.map(t=>this.get(t))}query(e,t){this.assertOpen();const s=t?.topK??1/0,A=t?.minSimilarity,r=t&&"iterable"in t&&t.iterable;if(this.size===0)return[];if(e.length!==this.dimensions)throw new Error(`Query vector dimension mismatch: expected ${this.dimensions}, got ${e.length}`);const n=new Float32Array(e);(t?.normalize??this.shouldNormalize)&&this.normalizeVector(n),this.memoryManager.writeQuery(n),this.memoryManager.ensureCapacity(0);const i=this.memoryManager.vectorCount,c=this.memoryManager.scoresOffset;if(this.wasmExports)this.wasmExports.search_all(this.memoryManager.queryOffset,this.memoryManager.dbOffset,c,i,this.dimensions);else{const y=new Float32Array(this.memoryManager.memory.buffer,this.memoryManager.queryOffset,this.dimensions),m=new Float32Array(this.memoryManager.memory.buffer,this.memoryManager.dbOffset,i*this.dimensions),q=new Float32Array(this.memoryManager.memory.buffer,c,i);p(y,m,q,i,this.dimensions)}const h=new Float32Array(this.memoryManager.readScores()),g=this.slotToKey,f=y=>g[y];return r?G(h,f,s,A):x(h,f,s,A)}async flush(){this.assertOpen();const e=this.memoryManager.vectorCount,t=new Uint8Array(e*this.dimensions*4);if(e>0){const A=new Uint8Array(this.memoryManager.memory.buffer,this.memoryManager.dbOffset,e*this.dimensions*4);t.set(A)}const s=Q(this.slotToKey);await Promise.all([this.storage.write(b,t),this.storage.write(M,s)])}async close(){this.closed||(await this.flush(),this.closed=!0)}async clear(){this.assertOpen(),this.keyToSlot.clear(),this.slotToKey.length=0,this.memoryManager.reset(),await this.storage.destroy()}async export(){this.assertOpen();const e=this.memoryManager.vectorCount,t=e*this.dimensions*4,s=Q(this.slotToKey),A=s.byteLength,r=new ArrayBuffer(k),n=new DataView(r);n.setUint32(0,S,!0),n.setUint32(4,w,!0),n.setUint32(8,this.dimensions,!0),n.setUint32(12,e,!0),n.setUint32(16,t,!0),n.setUint32(20,A,!0);const o=this.memoryManager;let i="header",c=0;return new ReadableStream({pull(h){switch(i){case"header":h.enqueue(new Uint8Array(r)),i=t>0?"vectors":A>0?"keys":"done",i==="done"&&h.close();break;case"vectors":{const g=t-c,f=Math.min(g,V),y=new Uint8Array(f);y.set(new Uint8Array(o.memory.buffer,o.dbOffset+c,f)),h.enqueue(y),c+=f,c>=t&&(i=A>0?"keys":"done",i==="done"&&h.close());break}case"keys":h.enqueue(s),i="done",h.close();break}}})}async import(e){this.assertOpen();const t=new F(e),s=await t.readExact(k),A=new DataView(s.buffer,s.byteOffset,s.byteLength);if(A.getUint32(0,!0)!==S)throw new Error("Invalid import data: unrecognized format");const n=A.getUint32(4,!0);if(n!==w)throw new Error(`Unsupported import version: expected ${w}, got ${n}`);const o=A.getUint32(8,!0);if(o!==this.dimensions)throw new Error(`Import dimension mismatch: expected ${this.dimensions}, got ${o}`);const i=A.getUint32(12,!0),c=A.getUint32(16,!0),h=A.getUint32(20,!0);if(this.keyToSlot.clear(),this.slotToKey.length=0,this.memoryManager.reset(),i>0){this.memoryManager.ensureCapacity(i);let g=0;await t.readChunked(c,f=>{new Uint8Array(this.memoryManager.memory.buffer,this.memoryManager.dbOffset+g,f.byteLength).set(f),g+=f.byteLength}),this.memoryManager.setVectorCount(i)}if(h>0){const g=await t.readExact(h),f=E(g);for(let y=0;y<f.length;y++)this.keyToSlot.set(f[y],y),this.slotToKey[y]=f[y]}t.release()}normalizeVector(e){if(this.wasmExports){const t=this.memoryManager.queryOffset;new Float32Array(this.memoryManager.memory.buffer,t,e.length).set(e),this.wasmExports.normalize(t,e.length);const s=new Float32Array(this.memoryManager.memory.buffer,t,e.length);e.set(s)}else v(e)}assertOpen(){if(this.closed)throw new Error("VectorDB instance has been closed")}}class F{reader;buffer=new Uint8Array(0);constructor(e){this.reader=e.getReader()}async readExact(e){if(e===0)return new Uint8Array(0);if(this.buffer.byteLength>=e){const n=this.buffer.subarray(0,e);return this.buffer=this.buffer.subarray(e),n}const t=[];let s=this.buffer.byteLength;for(s>0&&(t.push(this.buffer),this.buffer=new Uint8Array(0));s<e;){const{done:n,value:o}=await this.reader.read();if(n)throw new Error("Invalid import data: unexpected end of stream");t.push(o),s+=o.byteLength}const A=new Uint8Array(s);let r=0;for(const n of t)A.set(n,r),r+=n.byteLength;return s>e?(this.buffer=A.subarray(e),A.subarray(0,e)):A}async readChunked(e,t){let s=e;if(this.buffer.byteLength>0){const A=Math.min(this.buffer.byteLength,s);t(this.buffer.subarray(0,A)),s-=A,this.buffer=this.buffer.subarray(A)}for(;s>0;){const{done:A,value:r}=await this.reader.read();if(A)throw new Error("Invalid import data: unexpected end of stream");r.byteLength<=s?(t(r),s-=r.byteLength):(t(r.subarray(0,s)),this.buffer=r.slice(s),s=0)}}release(){this.reader.releaseLock()}}l.DB=I,l.InMemoryStorageProvider=D,l.OPFSStorageProvider=B,l.VectorCapacityExceededError=d,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})}));
2
2
  //# sourceMappingURL=eigen-db.umd.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"eigen-db.umd.cjs","sources":["../src/lib/errors.ts","../src/lib/storage.ts","../src/lib/compute.ts","../src/lib/lexicon.ts","../src/lib/memory-manager.ts","../src/lib/result-set.ts","../src/lib/simd-binary.ts","../src/lib/wasm-compute.ts","../src/lib/vector-db.ts"],"sourcesContent":["/**\n * Thrown when the database exceeds the 4GB WebAssembly 32-bit memory limit,\n * or the browser's available RAM.\n */\nexport class VectorCapacityExceededError extends Error {\n constructor(maxVectors: number) {\n super(`Capacity exceeded. Max vectors for this dimension size is ~${maxVectors}.`);\n this.name = \"VectorCapacityExceededError\";\n }\n}\n","/**\n * Storage abstraction for append-only binary files.\n * Supports OPFS for browser and in-memory for testing.\n */\n\nexport interface StorageProvider {\n /** Read the entire contents of a file. Returns empty Uint8Array if file doesn't exist. */\n readAll(fileName: string): Promise<Uint8Array>;\n\n /** Append data to a file (creates if it doesn't exist). */\n append(fileName: string, data: Uint8Array): Promise<void>;\n\n /** Write data to a file, replacing all existing content. */\n write(fileName: string, data: Uint8Array): Promise<void>;\n\n /** Delete the storage directory and all files. */\n destroy(): Promise<void>;\n}\n\n/**\n * OPFS-backed storage provider for browser environments.\n * Uses Origin Private File System for high-performance persistent storage.\n */\nexport class OPFSStorageProvider implements StorageProvider {\n private dirHandle: FileSystemDirectoryHandle | null = null;\n private dirName: string;\n\n constructor(dirName: string) {\n this.dirName = dirName;\n }\n\n private async getDir(): Promise<FileSystemDirectoryHandle> {\n if (!this.dirHandle) {\n const root = await navigator.storage.getDirectory();\n this.dirHandle = await root.getDirectoryHandle(this.dirName, { create: true });\n }\n return this.dirHandle;\n }\n\n async readAll(fileName: string): Promise<Uint8Array> {\n try {\n const dir = await this.getDir();\n const fileHandle = await dir.getFileHandle(fileName);\n const file = await fileHandle.getFile();\n const buffer = await file.arrayBuffer();\n return new Uint8Array(buffer);\n } catch {\n return new Uint8Array(0);\n }\n }\n\n async append(fileName: string, data: Uint8Array): Promise<void> {\n const dir = await this.getDir();\n const fileHandle = await dir.getFileHandle(fileName, { create: true });\n const writable = await fileHandle.createWritable({ keepExistingData: true });\n const file = await fileHandle.getFile();\n await writable.seek(file.size);\n await writable.write(data as unknown as BufferSource);\n await writable.close();\n }\n\n async write(fileName: string, data: Uint8Array): Promise<void> {\n const dir = await this.getDir();\n const fileHandle = await dir.getFileHandle(fileName, { create: true });\n const writable = await fileHandle.createWritable({ keepExistingData: false });\n await writable.write(data as unknown as BufferSource);\n await writable.close();\n }\n\n async destroy(): Promise<void> {\n const root = await navigator.storage.getDirectory();\n await root.removeEntry(this.dirName, { recursive: true });\n this.dirHandle = null;\n }\n}\n\n/**\n * In-memory storage provider for testing.\n */\nexport class InMemoryStorageProvider implements StorageProvider {\n private files = new Map<string, Uint8Array[]>();\n\n async readAll(fileName: string): Promise<Uint8Array> {\n const chunks = this.files.get(fileName);\n if (!chunks || chunks.length === 0) return new Uint8Array(0);\n\n const totalSize = chunks.reduce((sum, c) => sum + c.byteLength, 0);\n const result = new Uint8Array(totalSize);\n let offset = 0;\n for (const chunk of chunks) {\n result.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return result;\n }\n\n async append(fileName: string, data: Uint8Array): Promise<void> {\n if (!this.files.has(fileName)) {\n this.files.set(fileName, []);\n }\n this.files.get(fileName)!.push(new Uint8Array(data));\n }\n\n async write(fileName: string, data: Uint8Array): Promise<void> {\n this.files.set(fileName, [new Uint8Array(data)]);\n }\n\n async destroy(): Promise<void> {\n this.files.clear();\n }\n}\n","/**\n * Pure JavaScript compute functions for vector operations.\n * These serve as the reference implementation and fallback when WASM SIMD is unavailable.\n */\n\n/**\n * Normalizes a vector in-place to unit length.\n * After normalization, cosine similarity reduces to a simple dot product.\n */\nexport function normalize(vec: Float32Array): void {\n let sumSq = 0;\n for (let i = 0; i < vec.length; i++) {\n sumSq += vec[i] * vec[i];\n }\n const mag = Math.sqrt(sumSq);\n if (mag === 0) return;\n const invMag = 1 / mag;\n for (let i = 0; i < vec.length; i++) {\n vec[i] *= invMag;\n }\n}\n\n/**\n * Computes dot products of query against all vectors in the database.\n * Writes scores to the output array.\n *\n * @param query - Normalized query vector (length = dimensions)\n * @param db - Contiguous flat array of normalized vectors (length = dbSize * dimensions)\n * @param scores - Output array for dot product scores (length = dbSize)\n * @param dbSize - Number of vectors in the database\n * @param dimensions - Dimensionality of each vector\n */\nexport function searchAll(\n query: Float32Array,\n db: Float32Array,\n scores: Float32Array,\n dbSize: number,\n dimensions: number,\n): void {\n for (let i = 0; i < dbSize; i++) {\n let dot = 0;\n const offset = i * dimensions;\n for (let j = 0; j < dimensions; j++) {\n dot += query[j] * db[offset + j];\n }\n scores[i] = dot;\n }\n}\n","/**\n * Lexicon: length-prefixed UTF-8 encoding for text strings.\n *\n * Format: Each entry is [4-byte uint32 length][UTF-8 bytes]\n * This allows efficient sequential reading and appending.\n */\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\n/**\n * Encodes an array of strings into a length-prefixed binary format.\n */\nexport function encodeLexicon(texts: string[]): Uint8Array {\n const encoded = texts.map((t) => encoder.encode(t));\n const totalSize = encoded.reduce((sum, e) => sum + 4 + e.byteLength, 0);\n\n const buffer = new ArrayBuffer(totalSize);\n const view = new DataView(buffer);\n const bytes = new Uint8Array(buffer);\n let offset = 0;\n\n for (const e of encoded) {\n view.setUint32(offset, e.byteLength, true); // little-endian\n offset += 4;\n bytes.set(e, offset);\n offset += e.byteLength;\n }\n\n return bytes;\n}\n\n/**\n * Decodes all strings from a length-prefixed binary buffer.\n */\nexport function decodeLexicon(data: Uint8Array): string[] {\n const result: string[] = [];\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n let offset = 0;\n\n while (offset < data.byteLength) {\n const len = view.getUint32(offset, true);\n offset += 4;\n const text = decoder.decode(data.subarray(offset, offset + len));\n result.push(text);\n offset += len;\n }\n\n return result;\n}\n\n/**\n * Decodes a single string at a given index from the lexicon.\n * Returns the string and the byte offset of the next entry.\n */\nexport function decodeLexiconAt(data: Uint8Array, index: number): string {\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n let offset = 0;\n\n for (let i = 0; i < index; i++) {\n const len = view.getUint32(offset, true);\n offset += 4 + len;\n }\n\n const len = view.getUint32(offset, true);\n offset += 4;\n return decoder.decode(data.subarray(offset, offset + len));\n}\n\n/**\n * Builds an index of byte offsets for each entry in the lexicon.\n * Enables O(1) access to any entry by index.\n */\nexport function buildLexiconIndex(data: Uint8Array): Uint32Array {\n const offsets: number[] = [];\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n let offset = 0;\n\n while (offset < data.byteLength) {\n offsets.push(offset);\n const len = view.getUint32(offset, true);\n offset += 4 + len;\n }\n\n return new Uint32Array(offsets);\n}\n\n/**\n * Decodes a string at a given byte offset in the lexicon.\n */\nexport function decodeLexiconAtOffset(data: Uint8Array, byteOffset: number): string {\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n const len = view.getUint32(byteOffset, true);\n return decoder.decode(data.subarray(byteOffset + 4, byteOffset + 4 + len));\n}\n","/**\n * Memory Manager for WASM shared memory.\n *\n * Memory Layout:\n * [ 0x00000 ] -> Query Vector Buffer (Fixed, dimensions * 4 bytes, aligned to 64KB page)\n * [ DB_OFFSET ] -> Vector Database (Grows dynamically)\n * [ Dynamic ] -> Scores Buffer (Mapped after DB during search)\n */\n\n/** WASM page size is 64KB */\nconst PAGE_SIZE = 65536;\n\n/** Maximum WASM memory: ~4GB (65536 pages of 64KB each) */\nconst MAX_PAGES = 65536;\n\nexport class MemoryManager {\n readonly memory: WebAssembly.Memory;\n readonly dimensions: number;\n readonly queryOffset: number;\n readonly dbOffset: number;\n private _vectorCount: number;\n\n constructor(dimensions: number, initialVectorCount: number = 0) {\n this.dimensions = dimensions;\n\n // Query buffer: dimensions * 4 bytes, aligned to page boundary\n this.queryOffset = 0;\n const queryBytes = dimensions * 4;\n this.dbOffset = Math.ceil(queryBytes / PAGE_SIZE) * PAGE_SIZE;\n\n // Calculate initial memory needed\n const dbBytes = initialVectorCount * dimensions * 4;\n const totalBytes = this.dbOffset + dbBytes;\n const initialPages = Math.max(1, Math.ceil(totalBytes / PAGE_SIZE));\n\n this.memory = new WebAssembly.Memory({ initial: initialPages });\n this._vectorCount = initialVectorCount;\n }\n\n /** Current number of vectors stored */\n get vectorCount(): number {\n return this._vectorCount;\n }\n\n /** Byte offset where the scores buffer starts (right after DB) */\n get scoresOffset(): number {\n return this.dbOffset + this._vectorCount * this.dimensions * 4;\n }\n\n /** Total bytes needed for scores buffer */\n get scoresBytes(): number {\n return this._vectorCount * 4;\n }\n\n /**\n * Maximum vectors that can be stored given the 4GB WASM memory limit.\n * Accounts for query buffer, DB space, and scores buffer.\n */\n get maxVectors(): number {\n const availableBytes = MAX_PAGES * PAGE_SIZE - this.dbOffset;\n // Each vector needs: dimensions * 4 bytes (DB) + 4 bytes (score)\n const bytesPerVector = this.dimensions * 4 + 4;\n return Math.floor(availableBytes / bytesPerVector);\n }\n\n /**\n * Ensures memory is large enough for the current DB + scores buffer.\n * Calls memory.grow() if needed.\n */\n ensureCapacity(additionalVectors: number): void {\n const newTotal = this._vectorCount + additionalVectors;\n const requiredBytes =\n this.dbOffset + newTotal * this.dimensions * 4 + newTotal * 4; // DB + scores\n const currentBytes = this.memory.buffer.byteLength;\n\n if (requiredBytes > currentBytes) {\n const pagesNeeded = Math.ceil((requiredBytes - currentBytes) / PAGE_SIZE);\n const currentPages = currentBytes / PAGE_SIZE;\n if (currentPages + pagesNeeded > MAX_PAGES) {\n throw new Error(\"WASM memory limit exceeded\");\n }\n this.memory.grow(pagesNeeded);\n }\n }\n\n /**\n * Write a query vector into the query buffer region.\n */\n writeQuery(vector: Float32Array): void {\n new Float32Array(this.memory.buffer, this.queryOffset, this.dimensions).set(vector);\n }\n\n /**\n * Append vectors to the database region.\n * Returns the byte offset where the new vectors were written.\n */\n appendVectors(vectors: Float32Array[]): number {\n const startOffset = this.dbOffset + this._vectorCount * this.dimensions * 4;\n let offset = startOffset;\n for (const vec of vectors) {\n new Float32Array(this.memory.buffer, offset, this.dimensions).set(vec);\n offset += this.dimensions * 4;\n }\n this._vectorCount += vectors.length;\n return startOffset;\n }\n\n /**\n * Load raw vector bytes directly into the database region.\n * Used for bulk loading from OPFS.\n */\n loadVectorBytes(data: Uint8Array, vectorCount: number): void {\n new Uint8Array(this.memory.buffer, this.dbOffset, data.byteLength).set(data);\n this._vectorCount = vectorCount;\n }\n\n /**\n * Read the scores buffer as a Float32Array view.\n */\n readScores(): Float32Array {\n return new Float32Array(this.memory.buffer, this.scoresOffset, this._vectorCount);\n }\n\n /**\n * Read the DB region for a specific vector index.\n */\n readVector(index: number): Float32Array {\n const offset = this.dbOffset + index * this.dimensions * 4;\n return new Float32Array(this.memory.buffer, offset, this.dimensions);\n }\n\n /**\n * Write a vector to a specific slot in the database region.\n */\n writeVector(index: number, vector: Float32Array): void {\n const offset = this.dbOffset + index * this.dimensions * 4;\n new Float32Array(this.memory.buffer, offset, this.dimensions).set(vector);\n }\n\n /**\n * Reset the vector count to zero, logically clearing the database.\n * WASM memory is not freed but will be overwritten on next writes.\n */\n reset(): void {\n this._vectorCount = 0;\n }\n}\n","/**\n * RESULT HELPERS\n *\n * Utility functions for sorting scores and producing query results.\n * Two modes:\n * 1. topKResults — eagerly materializes a ResultItem[] (default query path)\n * 2. iterableResults — returns a lazy Iterable<ResultItem> where keys are\n * resolved only as each item is consumed (for pagination / streaming)\n *\n * Distance is defined as `1 - dotProduct`. For normalized vectors (the default),\n * this equals cosine distance, ranging from 0 (identical) to 2 (opposite).\n */\n\nexport interface ResultItem {\n key: string;\n distance: number;\n}\n\nexport type KeyResolver = (index: number) => string;\n\n/**\n * Sort by ascending distance and return the top K results as a plain array.\n * All keys are resolved eagerly.\n * If maxDistance is provided, results with distance > maxDistance are excluded.\n */\nexport function topKResults(\n scores: Float32Array,\n resolveKey: KeyResolver,\n topK: number,\n maxDistance?: number,\n): ResultItem[] {\n const n = scores.length;\n if (n === 0) return [];\n\n const indices = new Uint32Array(n);\n for (let i = 0; i < n; i++) indices[i] = i;\n indices.sort((a, b) => scores[b] - scores[a]);\n\n const k = Math.min(topK, n);\n const results: ResultItem[] = [];\n for (let i = 0; i < k; i++) {\n const idx = indices[i];\n const distance = 1 - scores[idx];\n if (maxDistance !== undefined && distance > maxDistance) break;\n results.push({ key: resolveKey(idx), distance });\n }\n return results;\n}\n\n/**\n * Sort by ascending distance and return a lazy iterable over the top K results.\n * Keys are resolved only when each item is consumed, saving allocations\n * when the caller iterates partially (e.g., pagination).\n *\n * If maxDistance is provided, iteration stops when distance > maxDistance.\n *\n * The returned iterable is re-iterable — each call to [Symbol.iterator]()\n * produces a fresh cursor over the same pre-sorted data.\n */\nexport function iterableResults(\n scores: Float32Array,\n resolveKey: KeyResolver,\n topK: number,\n maxDistance?: number,\n): Iterable<ResultItem> {\n const n = scores.length;\n if (n === 0) return [];\n\n const indices = new Uint32Array(n);\n for (let i = 0; i < n; i++) indices[i] = i;\n indices.sort((a, b) => scores[b] - scores[a]);\n\n const k = Math.min(topK, n);\n\n return {\n [Symbol.iterator](): Iterator<ResultItem> {\n let i = 0;\n return {\n next(): IteratorResult<ResultItem> {\n if (i >= k) return { done: true, value: undefined };\n const idx = indices[i++];\n const distance = 1 - scores[idx];\n if (maxDistance !== undefined && distance > maxDistance) return { done: true, value: undefined };\n return {\n done: false,\n value: { key: resolveKey(idx), distance },\n };\n },\n };\n },\n };\n}\n","// AUTO-GENERATED - Do not edit. Run: npx tsx scripts/compile-wat.ts\nconst SIMD_WASM_BASE64 = \"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\";\n\nexport function getSimdWasmBinary(): Uint8Array {\n const binaryString = atob(SIMD_WASM_BASE64);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return bytes;\n}\n","/**\n * WASM SIMD compute layer.\n * Compiles the hand-written WAT module and provides typed wrappers\n * that operate on shared WebAssembly.Memory.\n */\n\nexport interface WasmExports {\n normalize(ptr: number, dimensions: number): void;\n search_all(queryPtr: number, dbPtr: number, scoresPtr: number, dbSize: number, dimensions: number): void;\n}\n\n/**\n * Instantiates a WASM module with the given memory and returns typed exports.\n */\nexport async function instantiateWasm(wasmBinary: Uint8Array, memory: WebAssembly.Memory): Promise<WasmExports> {\n const importObject = { env: { memory } };\n const result = await WebAssembly.instantiate(wasmBinary, importObject);\n // WebAssembly.instantiate with a buffer returns { instance, module }\n const instance = (result as unknown as { instance: WebAssembly.Instance }).instance;\n return instance.exports as unknown as WasmExports;\n}\n","/**\n * VectorDB — Key-Value Vector Database\n *\n * Decoupled from embedding providers. Users pass pre-computed vectors\n * as number arrays (or Float32Array) with string keys.\n *\n * Supports:\n * - set/get/setMany/getMany for key-value CRUD\n * - query for similarity search (dot product on normalized vectors)\n * - flush to persist, close to flush+release, clear to wipe\n * - Last-write-wins semantics for duplicate keys (append-only storage)\n */\n\nimport { normalize, searchAll } from \"./compute\";\nimport { VectorCapacityExceededError } from \"./errors\";\nimport { decodeLexicon, encodeLexicon } from \"./lexicon\";\nimport { MemoryManager } from \"./memory-manager\";\nimport type { ResultItem } from \"./result-set\";\nimport { iterableResults, topKResults } from \"./result-set\";\nimport { getSimdWasmBinary } from \"./simd-binary\";\nimport type { StorageProvider } from \"./storage\";\nimport { OPFSStorageProvider } from \"./storage\";\nimport type { OpenOptions, OpenOptionsInternal, QueryOptions, SetOptions, VectorInput } from \"./types\";\nimport { instantiateWasm, type WasmExports } from \"./wasm-compute\";\n\nconst VECTORS_FILE = \"vectors.bin\";\nconst KEYS_FILE = \"keys.bin\";\n\nexport class VectorDB {\n private readonly memoryManager: MemoryManager;\n private readonly storage: StorageProvider;\n private readonly dimensions: number;\n private readonly shouldNormalize: boolean;\n private wasmExports: WasmExports | null;\n\n /** Maps key to its slot index in the vector array */\n private keyToSlot: Map<string, number>;\n\n /** Maps slot index back to its key */\n private slotToKey: string[];\n\n /** Whether this instance has been closed */\n private closed = false;\n\n private constructor(\n memoryManager: MemoryManager,\n storage: StorageProvider,\n dimensions: number,\n shouldNormalize: boolean,\n wasmExports: WasmExports | null,\n keyToSlot: Map<string, number>,\n slotToKey: string[],\n ) {\n this.memoryManager = memoryManager;\n this.storage = storage;\n this.dimensions = dimensions;\n this.shouldNormalize = shouldNormalize;\n this.wasmExports = wasmExports;\n this.keyToSlot = keyToSlot;\n this.slotToKey = slotToKey;\n }\n\n /**\n * Opens a VectorDB instance.\n * Loads existing data from storage into WASM memory.\n */\n static async open(options: OpenOptions): Promise<VectorDB>;\n static async open(options: OpenOptionsInternal): Promise<VectorDB>;\n static async open(options: OpenOptionsInternal): Promise<VectorDB> {\n const name = options.name ?? \"default\";\n const storage = options.storage ?? new OPFSStorageProvider(name);\n const shouldNormalize = options.normalize !== false;\n\n // Load existing data from storage\n const [vectorBytes, keysBytes] = await Promise.all([storage.readAll(VECTORS_FILE), storage.readAll(KEYS_FILE)]);\n\n // Decode stored keys\n const keys = keysBytes.byteLength > 0 ? decodeLexicon(keysBytes) : [];\n const vectorCount = vectorBytes.byteLength / (options.dimensions * 4);\n\n // Build key-to-slot mapping.\n // flush() always writes deduplicated state, so keys are unique on load.\n const keyToSlot = new Map<string, number>();\n const slotToKey: string[] = [];\n\n for (let i = 0; i < keys.length; i++) {\n keyToSlot.set(keys[i], i);\n slotToKey[i] = keys[i];\n }\n\n // Initialize memory manager\n const mm = new MemoryManager(options.dimensions, vectorCount);\n\n if (vectorBytes.byteLength > 0) {\n mm.loadVectorBytes(vectorBytes, vectorCount);\n }\n\n // Try to instantiate WASM SIMD module\n let wasmExports: WasmExports | null = null;\n const wasmBinary = options.wasmBinary !== undefined ? options.wasmBinary : getSimdWasmBinary();\n if (wasmBinary !== null) {\n try {\n wasmExports = await instantiateWasm(wasmBinary, mm.memory);\n } catch {\n // Fall back to JS compute\n }\n }\n\n return new VectorDB(mm, storage, options.dimensions, shouldNormalize, wasmExports, keyToSlot, slotToKey);\n }\n\n /** Total number of key-value pairs in the database */\n get size(): number {\n return this.keyToSlot.size;\n }\n\n /**\n * Set a key-value pair. If the key already exists, its vector is overwritten (last-write-wins).\n * The value is a number[] or Float32Array of length equal to the configured dimensions.\n */\n set(key: string, value: VectorInput, options?: SetOptions): void {\n this.assertOpen();\n\n if (value.length !== this.dimensions) {\n throw new Error(`Vector dimension mismatch: expected ${this.dimensions}, got ${value.length}`);\n }\n\n // Convert to Float32Array (also clones to avoid mutating caller's array)\n const vec = new Float32Array(value);\n\n // Normalize if needed\n const doNormalize = options?.normalize ?? this.shouldNormalize;\n if (doNormalize) {\n this.normalizeVector(vec);\n }\n\n const existingSlot = this.keyToSlot.get(key);\n if (existingSlot !== undefined) {\n // Overwrite existing slot\n this.memoryManager.writeVector(existingSlot, vec);\n } else {\n // Append new entry\n const newTotal = this.memoryManager.vectorCount + 1;\n if (newTotal > this.memoryManager.maxVectors) {\n throw new VectorCapacityExceededError(this.memoryManager.maxVectors);\n }\n this.memoryManager.ensureCapacity(1);\n const slotIndex = this.memoryManager.vectorCount;\n this.memoryManager.appendVectors([vec]);\n this.keyToSlot.set(key, slotIndex);\n this.slotToKey[slotIndex] = key;\n }\n }\n\n /**\n * Get the stored vector for a key. Returns undefined if the key does not exist.\n * Returns a copy of the stored vector as a plain number array.\n */\n get(key: string): number[] | undefined {\n this.assertOpen();\n\n const slot = this.keyToSlot.get(key);\n if (slot === undefined) return undefined;\n\n // Return a plain array copy so callers can't corrupt WASM memory\n return Array.from(this.memoryManager.readVector(slot));\n }\n\n /**\n * Set multiple key-value pairs at once. Last-write-wins applies within the batch.\n */\n setMany(entries: [string, VectorInput][]): void {\n for (const [key, value] of entries) {\n this.set(key, value);\n }\n }\n\n /**\n * Get vectors for multiple keys. Returns undefined for keys that don't exist.\n */\n getMany(keys: string[]): (number[] | undefined)[] {\n return keys.map((key) => this.get(key));\n }\n\n /**\n * Search for the most similar vectors to the given query vector.\n *\n * Default: returns a plain ResultItem[] sorted by ascending distance.\n * With `{ iterable: true }`: returns a lazy Iterable<ResultItem> where keys\n * are resolved only as each item is consumed.\n *\n * Distance is defined as `1 - dotProduct`. With normalization (default),\n * this equals cosine distance: 0 = identical, 2 = opposite.\n */\n query(value: VectorInput, options: QueryOptions & { iterable: true }): Iterable<ResultItem>;\n query(value: VectorInput, options?: QueryOptions): ResultItem[];\n query(value: VectorInput, options?: QueryOptions): ResultItem[] | Iterable<ResultItem> {\n this.assertOpen();\n\n const k = options?.topK ?? Infinity;\n const maxDistance = options?.maxDistance;\n const iterable = options && \"iterable\" in options && options.iterable;\n\n if (this.size === 0) {\n return [];\n }\n\n if (value.length !== this.dimensions) {\n throw new Error(`Query vector dimension mismatch: expected ${this.dimensions}, got ${value.length}`);\n }\n\n // Convert to Float32Array and optionally normalize the query vector\n const queryVec = new Float32Array(value);\n const doNormalize = options?.normalize ?? this.shouldNormalize;\n if (doNormalize) {\n this.normalizeVector(queryVec);\n }\n\n // Write query to WASM memory\n this.memoryManager.writeQuery(queryVec);\n\n // Ensure memory has space for scores buffer\n this.memoryManager.ensureCapacity(0);\n\n // Total vectors in memory\n const totalVectors = this.memoryManager.vectorCount;\n\n // Execute search\n const scoresOffset = this.memoryManager.scoresOffset;\n if (this.wasmExports) {\n this.wasmExports.search_all(\n this.memoryManager.queryOffset,\n this.memoryManager.dbOffset,\n scoresOffset,\n totalVectors,\n this.dimensions,\n );\n } else {\n const queryView = new Float32Array(\n this.memoryManager.memory.buffer,\n this.memoryManager.queryOffset,\n this.dimensions,\n );\n const dbView = new Float32Array(\n this.memoryManager.memory.buffer,\n this.memoryManager.dbOffset,\n totalVectors * this.dimensions,\n );\n const scoresView = new Float32Array(this.memoryManager.memory.buffer, scoresOffset, totalVectors);\n searchAll(queryView, dbView, scoresView, totalVectors, this.dimensions);\n }\n\n // Read scores (make a copy so the buffer can be reused)\n const scores = new Float32Array(this.memoryManager.readScores());\n\n // Resolve key from slot index\n const slotToKey = this.slotToKey;\n const resolveKey = (slotIndex: number): string => {\n return slotToKey[slotIndex];\n };\n\n if (iterable) {\n return iterableResults(scores, resolveKey, k, maxDistance);\n }\n return topKResults(scores, resolveKey, k, maxDistance);\n }\n\n /**\n * Persist the current in-memory state to storage.\n */\n async flush(): Promise<void> {\n this.assertOpen();\n\n const totalVectors = this.memoryManager.vectorCount;\n\n // Serialize vectors from WASM memory\n const vectorBytes = new Uint8Array(totalVectors * this.dimensions * 4);\n if (totalVectors > 0) {\n const src = new Uint8Array(\n this.memoryManager.memory.buffer,\n this.memoryManager.dbOffset,\n totalVectors * this.dimensions * 4,\n );\n vectorBytes.set(src);\n }\n\n // Serialize keys using lexicon format\n const keysBytes = encodeLexicon(this.slotToKey);\n\n await Promise.all([this.storage.write(VECTORS_FILE, vectorBytes), this.storage.write(KEYS_FILE, keysBytes)]);\n }\n\n /**\n * Flush data to storage and release the instance.\n * The instance cannot be used after close.\n */\n async close(): Promise<void> {\n if (this.closed) return;\n await this.flush();\n this.closed = true;\n }\n\n /**\n * Clear all data from the database and storage.\n */\n async clear(): Promise<void> {\n this.assertOpen();\n\n this.keyToSlot.clear();\n this.slotToKey.length = 0;\n this.memoryManager.reset();\n\n await this.storage.destroy();\n }\n\n /**\n * Normalize a vector using WASM (if available) or JS fallback.\n */\n private normalizeVector(vec: Float32Array): void {\n if (this.wasmExports) {\n const ptr = this.memoryManager.queryOffset;\n new Float32Array(this.memoryManager.memory.buffer, ptr, vec.length).set(vec);\n this.wasmExports.normalize(ptr, vec.length);\n const normalized = new Float32Array(this.memoryManager.memory.buffer, ptr, vec.length);\n vec.set(normalized);\n } else {\n normalize(vec);\n }\n }\n\n private assertOpen(): void {\n if (this.closed) {\n throw new Error(\"VectorDB instance has been closed\");\n }\n }\n}\n"],"names":["VectorCapacityExceededError","maxVectors","OPFSStorageProvider","dirName","root","fileName","buffer","data","fileHandle","writable","file","InMemoryStorageProvider","chunks","totalSize","sum","c","result","offset","chunk","normalize","vec","sumSq","i","mag","invMag","searchAll","query","db","scores","dbSize","dimensions","dot","j","encoder","decoder","encodeLexicon","texts","encoded","t","e","view","bytes","decodeLexicon","len","text","PAGE_SIZE","MAX_PAGES","MemoryManager","initialVectorCount","queryBytes","dbBytes","totalBytes","initialPages","availableBytes","bytesPerVector","additionalVectors","newTotal","requiredBytes","currentBytes","pagesNeeded","vector","vectors","startOffset","vectorCount","index","topKResults","resolveKey","topK","maxDistance","n","indices","a","b","k","results","idx","distance","iterableResults","SIMD_WASM_BASE64","getSimdWasmBinary","binaryString","instantiateWasm","wasmBinary","memory","importObject","VECTORS_FILE","KEYS_FILE","VectorDB","memoryManager","storage","shouldNormalize","wasmExports","keyToSlot","slotToKey","options","name","vectorBytes","keysBytes","keys","mm","key","value","existingSlot","slotIndex","slot","entries","iterable","queryVec","totalVectors","scoresOffset","queryView","dbView","scoresView","src","ptr","normalized"],"mappings":"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"}
1
+ {"version":3,"file":"eigen-db.umd.cjs","sources":["../src/lib/errors.ts","../src/lib/storage.ts","../src/lib/compute.ts","../src/lib/lexicon.ts","../src/lib/memory-manager.ts","../src/lib/result-set.ts","../src/lib/simd-binary.ts","../src/lib/wasm-compute.ts","../src/lib/vector-db.ts"],"sourcesContent":["/**\n * Thrown when the database exceeds the 4GB WebAssembly 32-bit memory limit,\n * or the browser's available RAM.\n */\nexport class VectorCapacityExceededError extends Error {\n constructor(maxVectors: number) {\n super(`Capacity exceeded. Max vectors for this dimension size is ~${maxVectors}.`);\n this.name = \"VectorCapacityExceededError\";\n }\n}\n","/**\n * Storage abstraction for append-only binary files.\n * Supports OPFS for browser and in-memory for testing.\n */\n\nexport interface StorageProvider {\n /** Read the entire contents of a file. Returns empty Uint8Array if file doesn't exist. */\n readAll(fileName: string): Promise<Uint8Array>;\n\n /** Append data to a file (creates if it doesn't exist). */\n append(fileName: string, data: Uint8Array): Promise<void>;\n\n /** Write data to a file, replacing all existing content. */\n write(fileName: string, data: Uint8Array): Promise<void>;\n\n /** Delete the storage directory and all files. */\n destroy(): Promise<void>;\n}\n\n/**\n * OPFS-backed storage provider for browser environments.\n * Uses Origin Private File System for high-performance persistent storage.\n */\nexport class OPFSStorageProvider implements StorageProvider {\n private dirHandle: FileSystemDirectoryHandle | null = null;\n private dirName: string;\n\n constructor(dirName: string) {\n this.dirName = dirName;\n }\n\n private async getDir(): Promise<FileSystemDirectoryHandle> {\n if (!this.dirHandle) {\n const root = await navigator.storage.getDirectory();\n this.dirHandle = await root.getDirectoryHandle(this.dirName, { create: true });\n }\n return this.dirHandle;\n }\n\n async readAll(fileName: string): Promise<Uint8Array> {\n try {\n const dir = await this.getDir();\n const fileHandle = await dir.getFileHandle(fileName);\n const file = await fileHandle.getFile();\n const buffer = await file.arrayBuffer();\n return new Uint8Array(buffer);\n } catch {\n return new Uint8Array(0);\n }\n }\n\n async append(fileName: string, data: Uint8Array): Promise<void> {\n const dir = await this.getDir();\n const fileHandle = await dir.getFileHandle(fileName, { create: true });\n const writable = await fileHandle.createWritable({ keepExistingData: true });\n const file = await fileHandle.getFile();\n await writable.seek(file.size);\n await writable.write(data as unknown as BufferSource);\n await writable.close();\n }\n\n async write(fileName: string, data: Uint8Array): Promise<void> {\n const dir = await this.getDir();\n const fileHandle = await dir.getFileHandle(fileName, { create: true });\n const writable = await fileHandle.createWritable({ keepExistingData: false });\n await writable.write(data as unknown as BufferSource);\n await writable.close();\n }\n\n async destroy(): Promise<void> {\n const root = await navigator.storage.getDirectory();\n await root.removeEntry(this.dirName, { recursive: true });\n this.dirHandle = null;\n }\n}\n\n/**\n * In-memory storage provider for testing.\n */\nexport class InMemoryStorageProvider implements StorageProvider {\n private files = new Map<string, Uint8Array[]>();\n\n async readAll(fileName: string): Promise<Uint8Array> {\n const chunks = this.files.get(fileName);\n if (!chunks || chunks.length === 0) return new Uint8Array(0);\n\n const totalSize = chunks.reduce((sum, c) => sum + c.byteLength, 0);\n const result = new Uint8Array(totalSize);\n let offset = 0;\n for (const chunk of chunks) {\n result.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return result;\n }\n\n async append(fileName: string, data: Uint8Array): Promise<void> {\n if (!this.files.has(fileName)) {\n this.files.set(fileName, []);\n }\n this.files.get(fileName)!.push(new Uint8Array(data));\n }\n\n async write(fileName: string, data: Uint8Array): Promise<void> {\n this.files.set(fileName, [new Uint8Array(data)]);\n }\n\n async destroy(): Promise<void> {\n this.files.clear();\n }\n}\n","/**\n * Pure JavaScript compute functions for vector operations.\n * These serve as the reference implementation and fallback when WASM SIMD is unavailable.\n */\n\n/**\n * Normalizes a vector in-place to unit length.\n * After normalization, cosine similarity reduces to a simple dot product.\n */\nexport function normalize(vec: Float32Array): void {\n let sumSq = 0;\n for (let i = 0; i < vec.length; i++) {\n sumSq += vec[i] * vec[i];\n }\n const mag = Math.sqrt(sumSq);\n if (mag === 0) return;\n const invMag = 1 / mag;\n for (let i = 0; i < vec.length; i++) {\n vec[i] *= invMag;\n }\n}\n\n/**\n * Computes dot products of query against all vectors in the database.\n * Writes scores to the output array.\n *\n * @param query - Normalized query vector (length = dimensions)\n * @param db - Contiguous flat array of normalized vectors (length = dbSize * dimensions)\n * @param scores - Output array for dot product scores (length = dbSize)\n * @param dbSize - Number of vectors in the database\n * @param dimensions - Dimensionality of each vector\n */\nexport function searchAll(\n query: Float32Array,\n db: Float32Array,\n scores: Float32Array,\n dbSize: number,\n dimensions: number,\n): void {\n for (let i = 0; i < dbSize; i++) {\n let dot = 0;\n const offset = i * dimensions;\n for (let j = 0; j < dimensions; j++) {\n dot += query[j] * db[offset + j];\n }\n scores[i] = dot;\n }\n}\n","/**\n * Lexicon: length-prefixed UTF-8 encoding for text strings.\n *\n * Format: Each entry is [4-byte uint32 length][UTF-8 bytes]\n * This allows efficient sequential reading and appending.\n */\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\n/**\n * Encodes an array of strings into a length-prefixed binary format.\n */\nexport function encodeLexicon(texts: string[]): Uint8Array {\n const encoded = texts.map((t) => encoder.encode(t));\n const totalSize = encoded.reduce((sum, e) => sum + 4 + e.byteLength, 0);\n\n const buffer = new ArrayBuffer(totalSize);\n const view = new DataView(buffer);\n const bytes = new Uint8Array(buffer);\n let offset = 0;\n\n for (const e of encoded) {\n view.setUint32(offset, e.byteLength, true); // little-endian\n offset += 4;\n bytes.set(e, offset);\n offset += e.byteLength;\n }\n\n return bytes;\n}\n\n/**\n * Decodes all strings from a length-prefixed binary buffer.\n */\nexport function decodeLexicon(data: Uint8Array): string[] {\n const result: string[] = [];\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n let offset = 0;\n\n while (offset < data.byteLength) {\n const len = view.getUint32(offset, true);\n offset += 4;\n const text = decoder.decode(data.subarray(offset, offset + len));\n result.push(text);\n offset += len;\n }\n\n return result;\n}\n\n/**\n * Decodes a single string at a given index from the lexicon.\n * Returns the string and the byte offset of the next entry.\n */\nexport function decodeLexiconAt(data: Uint8Array, index: number): string {\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n let offset = 0;\n\n for (let i = 0; i < index; i++) {\n const len = view.getUint32(offset, true);\n offset += 4 + len;\n }\n\n const len = view.getUint32(offset, true);\n offset += 4;\n return decoder.decode(data.subarray(offset, offset + len));\n}\n\n/**\n * Builds an index of byte offsets for each entry in the lexicon.\n * Enables O(1) access to any entry by index.\n */\nexport function buildLexiconIndex(data: Uint8Array): Uint32Array {\n const offsets: number[] = [];\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n let offset = 0;\n\n while (offset < data.byteLength) {\n offsets.push(offset);\n const len = view.getUint32(offset, true);\n offset += 4 + len;\n }\n\n return new Uint32Array(offsets);\n}\n\n/**\n * Decodes a string at a given byte offset in the lexicon.\n */\nexport function decodeLexiconAtOffset(data: Uint8Array, byteOffset: number): string {\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n const len = view.getUint32(byteOffset, true);\n return decoder.decode(data.subarray(byteOffset + 4, byteOffset + 4 + len));\n}\n","/**\n * Memory Manager for WASM shared memory.\n *\n * Memory Layout:\n * [ 0x00000 ] -> Query Vector Buffer (Fixed, dimensions * 4 bytes, aligned to 64KB page)\n * [ DB_OFFSET ] -> Vector Database (Grows dynamically)\n * [ Dynamic ] -> Scores Buffer (Mapped after DB during search)\n */\n\n/** WASM page size is 64KB */\nconst PAGE_SIZE = 65536;\n\n/** Maximum WASM memory: ~4GB (65536 pages of 64KB each) */\nconst MAX_PAGES = 65536;\n\nexport class MemoryManager {\n readonly memory: WebAssembly.Memory;\n readonly dimensions: number;\n readonly queryOffset: number;\n readonly dbOffset: number;\n private _vectorCount: number;\n\n constructor(dimensions: number, initialVectorCount: number = 0) {\n this.dimensions = dimensions;\n\n // Query buffer: dimensions * 4 bytes, aligned to page boundary\n this.queryOffset = 0;\n const queryBytes = dimensions * 4;\n this.dbOffset = Math.ceil(queryBytes / PAGE_SIZE) * PAGE_SIZE;\n\n // Calculate initial memory needed\n const dbBytes = initialVectorCount * dimensions * 4;\n const totalBytes = this.dbOffset + dbBytes;\n const initialPages = Math.max(1, Math.ceil(totalBytes / PAGE_SIZE));\n\n this.memory = new WebAssembly.Memory({ initial: initialPages });\n this._vectorCount = initialVectorCount;\n }\n\n /** Current number of vectors stored */\n get vectorCount(): number {\n return this._vectorCount;\n }\n\n /** Byte offset where the scores buffer starts (right after DB) */\n get scoresOffset(): number {\n return this.dbOffset + this._vectorCount * this.dimensions * 4;\n }\n\n /** Total bytes needed for scores buffer */\n get scoresBytes(): number {\n return this._vectorCount * 4;\n }\n\n /**\n * Maximum vectors that can be stored given the 4GB WASM memory limit.\n * Accounts for query buffer, DB space, and scores buffer.\n */\n get maxVectors(): number {\n const availableBytes = MAX_PAGES * PAGE_SIZE - this.dbOffset;\n // Each vector needs: dimensions * 4 bytes (DB) + 4 bytes (score)\n const bytesPerVector = this.dimensions * 4 + 4;\n return Math.floor(availableBytes / bytesPerVector);\n }\n\n /**\n * Ensures memory is large enough for the current DB + scores buffer.\n * Calls memory.grow() if needed.\n */\n ensureCapacity(additionalVectors: number): void {\n const newTotal = this._vectorCount + additionalVectors;\n const requiredBytes =\n this.dbOffset + newTotal * this.dimensions * 4 + newTotal * 4; // DB + scores\n const currentBytes = this.memory.buffer.byteLength;\n\n if (requiredBytes > currentBytes) {\n const pagesNeeded = Math.ceil((requiredBytes - currentBytes) / PAGE_SIZE);\n const currentPages = currentBytes / PAGE_SIZE;\n if (currentPages + pagesNeeded > MAX_PAGES) {\n throw new Error(\"WASM memory limit exceeded\");\n }\n this.memory.grow(pagesNeeded);\n }\n }\n\n /**\n * Write a query vector into the query buffer region.\n */\n writeQuery(vector: Float32Array): void {\n new Float32Array(this.memory.buffer, this.queryOffset, this.dimensions).set(vector);\n }\n\n /**\n * Append vectors to the database region.\n * Returns the byte offset where the new vectors were written.\n */\n appendVectors(vectors: Float32Array[]): number {\n const startOffset = this.dbOffset + this._vectorCount * this.dimensions * 4;\n let offset = startOffset;\n for (const vec of vectors) {\n new Float32Array(this.memory.buffer, offset, this.dimensions).set(vec);\n offset += this.dimensions * 4;\n }\n this._vectorCount += vectors.length;\n return startOffset;\n }\n\n /**\n * Load raw vector bytes directly into the database region.\n * Used for bulk loading from OPFS.\n */\n loadVectorBytes(data: Uint8Array, vectorCount: number): void {\n new Uint8Array(this.memory.buffer, this.dbOffset, data.byteLength).set(data);\n this._vectorCount = vectorCount;\n }\n\n /**\n * Read the scores buffer as a Float32Array view.\n */\n readScores(): Float32Array {\n return new Float32Array(this.memory.buffer, this.scoresOffset, this._vectorCount);\n }\n\n /**\n * Read the DB region for a specific vector index.\n */\n readVector(index: number): Float32Array {\n const offset = this.dbOffset + index * this.dimensions * 4;\n return new Float32Array(this.memory.buffer, offset, this.dimensions);\n }\n\n /**\n * Write a vector to a specific slot in the database region.\n */\n writeVector(index: number, vector: Float32Array): void {\n const offset = this.dbOffset + index * this.dimensions * 4;\n new Float32Array(this.memory.buffer, offset, this.dimensions).set(vector);\n }\n\n /**\n * Reset the vector count to zero, logically clearing the database.\n * WASM memory is not freed but will be overwritten on next writes.\n */\n reset(): void {\n this._vectorCount = 0;\n }\n\n /**\n * Set the vector count after bulk-loading data directly into the DB region.\n * Use when writing raw bytes to the DB region externally (e.g., streaming import).\n */\n setVectorCount(count: number): void {\n this._vectorCount = count;\n }\n}\n","/**\n * RESULT HELPERS\n *\n * Utility functions for sorting scores and producing query results.\n * Two modes:\n * 1. topKResults — eagerly materializes a ResultItem[] (default query path)\n * 2. iterableResults — returns a lazy Iterable<ResultItem> where keys are\n * resolved only as each item is consumed (for pagination / streaming)\n *\n * Similarity is the dot product of query and stored vectors. For normalized\n * vectors (the default), this equals cosine similarity, ranging from 1\n * (identical) to -1 (opposite).\n */\n\nexport interface ResultItem {\n key: string;\n similarity: number;\n}\n\nexport type KeyResolver = (index: number) => string;\n\n/**\n * Sort by descending similarity and return the top K results as a plain array.\n * All keys are resolved eagerly.\n * If minSimilarity is provided, results with similarity < minSimilarity are excluded.\n */\nexport function topKResults(\n scores: Float32Array,\n resolveKey: KeyResolver,\n topK: number,\n minSimilarity?: number,\n): ResultItem[] {\n const n = scores.length;\n if (n === 0) return [];\n\n const indices = new Uint32Array(n);\n for (let i = 0; i < n; i++) indices[i] = i;\n indices.sort((a, b) => scores[b] - scores[a]);\n\n const k = Math.min(topK, n);\n const results: ResultItem[] = [];\n for (let i = 0; i < k; i++) {\n const idx = indices[i];\n const similarity = scores[idx];\n if (minSimilarity !== undefined && similarity < minSimilarity) break;\n results.push({ key: resolveKey(idx), similarity });\n }\n return results;\n}\n\n/**\n * Sort by descending similarity and return a lazy iterable over the top K results.\n * Keys are resolved only when each item is consumed, saving allocations\n * when the caller iterates partially (e.g., pagination).\n *\n * If minSimilarity is provided, iteration stops when similarity < minSimilarity.\n *\n * The returned iterable is re-iterable — each call to [Symbol.iterator]()\n * produces a fresh cursor over the same pre-sorted data.\n */\nexport function iterableResults(\n scores: Float32Array,\n resolveKey: KeyResolver,\n topK: number,\n minSimilarity?: number,\n): Iterable<ResultItem> {\n const n = scores.length;\n if (n === 0) return [];\n\n const indices = new Uint32Array(n);\n for (let i = 0; i < n; i++) indices[i] = i;\n indices.sort((a, b) => scores[b] - scores[a]);\n\n const k = Math.min(topK, n);\n\n return {\n [Symbol.iterator](): Iterator<ResultItem> {\n let i = 0;\n return {\n next(): IteratorResult<ResultItem> {\n if (i >= k) return { done: true, value: undefined };\n const idx = indices[i++];\n const similarity = scores[idx];\n if (minSimilarity !== undefined && similarity < minSimilarity) return { done: true, value: undefined };\n return {\n done: false,\n value: { key: resolveKey(idx), similarity },\n };\n },\n };\n },\n };\n}\n","// AUTO-GENERATED - Do not edit. Run: npx tsx scripts/compile-wat.ts\nconst SIMD_WASM_BASE64 = \"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\";\n\nexport function getSimdWasmBinary(): Uint8Array {\n const binaryString = atob(SIMD_WASM_BASE64);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return bytes;\n}\n","/**\n * WASM SIMD compute layer.\n * Compiles the hand-written WAT module and provides typed wrappers\n * that operate on shared WebAssembly.Memory.\n */\n\nexport interface WasmExports {\n normalize(ptr: number, dimensions: number): void;\n search_all(queryPtr: number, dbPtr: number, scoresPtr: number, dbSize: number, dimensions: number): void;\n}\n\n/**\n * Instantiates a WASM module with the given memory and returns typed exports.\n */\nexport async function instantiateWasm(wasmBinary: Uint8Array, memory: WebAssembly.Memory): Promise<WasmExports> {\n const importObject = { env: { memory } };\n const result = await WebAssembly.instantiate(wasmBinary, importObject);\n // WebAssembly.instantiate with a buffer returns { instance, module }\n const instance = (result as unknown as { instance: WebAssembly.Instance }).instance;\n return instance.exports as unknown as WasmExports;\n}\n","/**\n * VectorDB — Key-Value Vector Database\n *\n * Decoupled from embedding providers. Users pass pre-computed vectors\n * as number arrays (or Float32Array) with string keys.\n *\n * Supports:\n * - set/get/setMany/getMany for key-value CRUD\n * - query for similarity search (dot product on normalized vectors)\n * - flush to persist, close to flush+release, clear to wipe\n * - Streaming export/import using Web Streams API\n * - Last-write-wins semantics for duplicate keys (append-only storage)\n */\n\nimport { normalize, searchAll } from \"./compute\";\nimport { VectorCapacityExceededError } from \"./errors\";\nimport { decodeLexicon, encodeLexicon } from \"./lexicon\";\nimport { MemoryManager } from \"./memory-manager\";\nimport type { ResultItem } from \"./result-set\";\nimport { iterableResults, topKResults } from \"./result-set\";\nimport { getSimdWasmBinary } from \"./simd-binary\";\nimport type { StorageProvider } from \"./storage\";\nimport { OPFSStorageProvider } from \"./storage\";\nimport type { OpenOptions, OpenOptionsInternal, QueryOptions, SetOptions, VectorInput } from \"./types\";\nimport { instantiateWasm, type WasmExports } from \"./wasm-compute\";\n\nconst VECTORS_FILE = \"vectors.bin\";\nconst KEYS_FILE = \"keys.bin\";\n\n/** Binary export format magic bytes: \"EGDB\" */\nconst EXPORT_MAGIC = 0x42444745; // \"EGDB\" in little-endian\nconst EXPORT_VERSION = 1;\nconst EXPORT_HEADER_BYTES = 24;\n\n/** Chunk size for streaming export/import (64KB, matches WASM page size) */\nconst STREAM_CHUNK_SIZE = 65536;\n\nexport class VectorDB {\n private readonly memoryManager: MemoryManager;\n private readonly storage: StorageProvider;\n private readonly dimensions: number;\n private readonly shouldNormalize: boolean;\n private wasmExports: WasmExports | null;\n\n /** Maps key to its slot index in the vector array */\n private keyToSlot: Map<string, number>;\n\n /** Maps slot index back to its key */\n private slotToKey: string[];\n\n /** Whether this instance has been closed */\n private closed = false;\n\n private constructor(\n memoryManager: MemoryManager,\n storage: StorageProvider,\n dimensions: number,\n shouldNormalize: boolean,\n wasmExports: WasmExports | null,\n keyToSlot: Map<string, number>,\n slotToKey: string[],\n ) {\n this.memoryManager = memoryManager;\n this.storage = storage;\n this.dimensions = dimensions;\n this.shouldNormalize = shouldNormalize;\n this.wasmExports = wasmExports;\n this.keyToSlot = keyToSlot;\n this.slotToKey = slotToKey;\n }\n\n /**\n * Opens a VectorDB instance.\n * Loads existing data from storage into WASM memory.\n */\n static async open(options: OpenOptions): Promise<VectorDB>;\n static async open(options: OpenOptionsInternal): Promise<VectorDB>;\n static async open(options: OpenOptionsInternal): Promise<VectorDB> {\n const name = options.name ?? \"default\";\n const storage = options.storage ?? new OPFSStorageProvider(name);\n const shouldNormalize = options.normalize !== false;\n\n // Load existing data from storage\n const [vectorBytes, keysBytes] = await Promise.all([storage.readAll(VECTORS_FILE), storage.readAll(KEYS_FILE)]);\n\n // Decode stored keys\n const keys = keysBytes.byteLength > 0 ? decodeLexicon(keysBytes) : [];\n const vectorCount = vectorBytes.byteLength / (options.dimensions * 4);\n\n // Build key-to-slot mapping.\n // flush() always writes deduplicated state, so keys are unique on load.\n const keyToSlot = new Map<string, number>();\n const slotToKey: string[] = [];\n\n for (let i = 0; i < keys.length; i++) {\n keyToSlot.set(keys[i], i);\n slotToKey[i] = keys[i];\n }\n\n // Initialize memory manager\n const mm = new MemoryManager(options.dimensions, vectorCount);\n\n if (vectorBytes.byteLength > 0) {\n mm.loadVectorBytes(vectorBytes, vectorCount);\n }\n\n // Try to instantiate WASM SIMD module\n let wasmExports: WasmExports | null = null;\n const wasmBinary = options.wasmBinary !== undefined ? options.wasmBinary : getSimdWasmBinary();\n if (wasmBinary !== null) {\n try {\n wasmExports = await instantiateWasm(wasmBinary, mm.memory);\n } catch {\n // Fall back to JS compute\n }\n }\n\n return new VectorDB(mm, storage, options.dimensions, shouldNormalize, wasmExports, keyToSlot, slotToKey);\n }\n\n /** Total number of key-value pairs in the database */\n get size(): number {\n return this.keyToSlot.size;\n }\n\n /**\n * Set a key-value pair. If the key already exists, its vector is overwritten (last-write-wins).\n * The value is a number[] or Float32Array of length equal to the configured dimensions.\n */\n set(key: string, value: VectorInput, options?: SetOptions): void {\n this.assertOpen();\n\n if (value.length !== this.dimensions) {\n throw new Error(`Vector dimension mismatch: expected ${this.dimensions}, got ${value.length}`);\n }\n\n // Convert to Float32Array (also clones to avoid mutating caller's array)\n const vec = new Float32Array(value);\n\n // Normalize if needed\n const doNormalize = options?.normalize ?? this.shouldNormalize;\n if (doNormalize) {\n this.normalizeVector(vec);\n }\n\n const existingSlot = this.keyToSlot.get(key);\n if (existingSlot !== undefined) {\n // Overwrite existing slot\n this.memoryManager.writeVector(existingSlot, vec);\n } else {\n // Append new entry\n const newTotal = this.memoryManager.vectorCount + 1;\n if (newTotal > this.memoryManager.maxVectors) {\n throw new VectorCapacityExceededError(this.memoryManager.maxVectors);\n }\n this.memoryManager.ensureCapacity(1);\n const slotIndex = this.memoryManager.vectorCount;\n this.memoryManager.appendVectors([vec]);\n this.keyToSlot.set(key, slotIndex);\n this.slotToKey[slotIndex] = key;\n }\n }\n\n /**\n * Get the stored vector for a key. Returns undefined if the key does not exist.\n * Returns a copy of the stored vector as a plain number array.\n */\n get(key: string): number[] | undefined {\n this.assertOpen();\n\n const slot = this.keyToSlot.get(key);\n if (slot === undefined) return undefined;\n\n // Return a plain array copy so callers can't corrupt WASM memory\n return Array.from(this.memoryManager.readVector(slot));\n }\n\n /**\n * Set multiple key-value pairs at once. Last-write-wins applies within the batch.\n */\n setMany(entries: [string, VectorInput][]): void {\n for (const [key, value] of entries) {\n this.set(key, value);\n }\n }\n\n /**\n * Get vectors for multiple keys. Returns undefined for keys that don't exist.\n */\n getMany(keys: string[]): (number[] | undefined)[] {\n return keys.map((key) => this.get(key));\n }\n\n /**\n * Search for the most similar vectors to the given query vector.\n *\n * Default: returns a plain ResultItem[] sorted by descending similarity.\n * With `{ iterable: true }`: returns a lazy Iterable<ResultItem> where keys\n * are resolved only as each item is consumed.\n *\n * Similarity is the dot product of query and stored vectors. With\n * normalization (default), this equals cosine similarity: 1 = identical,\n * -1 = opposite.\n */\n query(value: VectorInput, options: QueryOptions & { iterable: true }): Iterable<ResultItem>;\n query(value: VectorInput, options?: QueryOptions): ResultItem[];\n query(value: VectorInput, options?: QueryOptions): ResultItem[] | Iterable<ResultItem> {\n this.assertOpen();\n\n const k = options?.topK ?? Infinity;\n const minSimilarity = options?.minSimilarity;\n const iterable = options && \"iterable\" in options && options.iterable;\n\n if (this.size === 0) {\n return [];\n }\n\n if (value.length !== this.dimensions) {\n throw new Error(`Query vector dimension mismatch: expected ${this.dimensions}, got ${value.length}`);\n }\n\n // Convert to Float32Array and optionally normalize the query vector\n const queryVec = new Float32Array(value);\n const doNormalize = options?.normalize ?? this.shouldNormalize;\n if (doNormalize) {\n this.normalizeVector(queryVec);\n }\n\n // Write query to WASM memory\n this.memoryManager.writeQuery(queryVec);\n\n // Ensure memory has space for scores buffer\n this.memoryManager.ensureCapacity(0);\n\n // Total vectors in memory\n const totalVectors = this.memoryManager.vectorCount;\n\n // Execute search\n const scoresOffset = this.memoryManager.scoresOffset;\n if (this.wasmExports) {\n this.wasmExports.search_all(\n this.memoryManager.queryOffset,\n this.memoryManager.dbOffset,\n scoresOffset,\n totalVectors,\n this.dimensions,\n );\n } else {\n const queryView = new Float32Array(\n this.memoryManager.memory.buffer,\n this.memoryManager.queryOffset,\n this.dimensions,\n );\n const dbView = new Float32Array(\n this.memoryManager.memory.buffer,\n this.memoryManager.dbOffset,\n totalVectors * this.dimensions,\n );\n const scoresView = new Float32Array(this.memoryManager.memory.buffer, scoresOffset, totalVectors);\n searchAll(queryView, dbView, scoresView, totalVectors, this.dimensions);\n }\n\n // Read scores (make a copy so the buffer can be reused)\n const scores = new Float32Array(this.memoryManager.readScores());\n\n // Resolve key from slot index\n const slotToKey = this.slotToKey;\n const resolveKey = (slotIndex: number): string => {\n return slotToKey[slotIndex];\n };\n\n if (iterable) {\n return iterableResults(scores, resolveKey, k, minSimilarity);\n }\n return topKResults(scores, resolveKey, k, minSimilarity);\n }\n\n /**\n * Persist the current in-memory state to storage.\n */\n async flush(): Promise<void> {\n this.assertOpen();\n\n const totalVectors = this.memoryManager.vectorCount;\n\n // Serialize vectors from WASM memory\n const vectorBytes = new Uint8Array(totalVectors * this.dimensions * 4);\n if (totalVectors > 0) {\n const src = new Uint8Array(\n this.memoryManager.memory.buffer,\n this.memoryManager.dbOffset,\n totalVectors * this.dimensions * 4,\n );\n vectorBytes.set(src);\n }\n\n // Serialize keys using lexicon format\n const keysBytes = encodeLexicon(this.slotToKey);\n\n await Promise.all([this.storage.write(VECTORS_FILE, vectorBytes), this.storage.write(KEYS_FILE, keysBytes)]);\n }\n\n /**\n * Flush data to storage and release the instance.\n * The instance cannot be used after close.\n */\n async close(): Promise<void> {\n if (this.closed) return;\n await this.flush();\n this.closed = true;\n }\n\n /**\n * Clear all data from the database and storage.\n */\n async clear(): Promise<void> {\n this.assertOpen();\n\n this.keyToSlot.clear();\n this.slotToKey.length = 0;\n this.memoryManager.reset();\n\n await this.storage.destroy();\n }\n\n /**\n * Export the entire database as a ReadableStream of binary chunks.\n *\n * Format: [Header 24 bytes][Vector data][Keys data]\n * Header: magic(4) + version(4) + dimensions(4) + vectorCount(4) + vectorDataLen(4) + keysDataLen(4)\n *\n * Vectors are streamed in 64KB chunks from WASM memory to avoid large\n * heap allocations.\n */\n async export(): Promise<ReadableStream<Uint8Array>> {\n this.assertOpen();\n\n const totalVectors = this.memoryManager.vectorCount;\n const vectorDataLen = totalVectors * this.dimensions * 4;\n\n // Encode keys (typically much smaller than vectors)\n const keysBytes = encodeLexicon(this.slotToKey);\n const keysDataLen = keysBytes.byteLength;\n\n // Build header\n const header = new ArrayBuffer(EXPORT_HEADER_BYTES);\n const headerView = new DataView(header);\n headerView.setUint32(0, EXPORT_MAGIC, true);\n headerView.setUint32(4, EXPORT_VERSION, true);\n headerView.setUint32(8, this.dimensions, true);\n headerView.setUint32(12, totalVectors, true);\n headerView.setUint32(16, vectorDataLen, true);\n headerView.setUint32(20, keysDataLen, true);\n\n const mm = this.memoryManager;\n let phase: \"header\" | \"vectors\" | \"keys\" | \"done\" = \"header\";\n let vectorOffset = 0;\n\n return new ReadableStream<Uint8Array>({\n pull(controller) {\n switch (phase) {\n case \"header\":\n controller.enqueue(new Uint8Array(header));\n phase = vectorDataLen > 0 ? \"vectors\" : keysDataLen > 0 ? \"keys\" : \"done\";\n if (phase === \"done\") controller.close();\n break;\n\n case \"vectors\": {\n const remaining = vectorDataLen - vectorOffset;\n const chunkSize = Math.min(remaining, STREAM_CHUNK_SIZE);\n const chunk = new Uint8Array(chunkSize);\n chunk.set(new Uint8Array(mm.memory.buffer, mm.dbOffset + vectorOffset, chunkSize));\n controller.enqueue(chunk);\n vectorOffset += chunkSize;\n if (vectorOffset >= vectorDataLen) {\n phase = keysDataLen > 0 ? \"keys\" : \"done\";\n if (phase === \"done\") controller.close();\n }\n break;\n }\n\n case \"keys\":\n controller.enqueue(keysBytes);\n phase = \"done\";\n controller.close();\n break;\n }\n },\n });\n }\n\n /**\n * Import data from a ReadableStream, replacing all existing data.\n * Performs a dimension check against the configured dimensions.\n *\n * Vectors are streamed directly into WASM memory in chunks to avoid\n * large heap allocations.\n */\n async import(stream: ReadableStream<Uint8Array>): Promise<void> {\n this.assertOpen();\n\n const sr = new StreamReader(stream);\n\n // Read and validate header\n const headerBytes = await sr.readExact(EXPORT_HEADER_BYTES);\n const headerView = new DataView(headerBytes.buffer, headerBytes.byteOffset, headerBytes.byteLength);\n\n const magic = headerView.getUint32(0, true);\n if (magic !== EXPORT_MAGIC) {\n throw new Error(\"Invalid import data: unrecognized format\");\n }\n\n const version = headerView.getUint32(4, true);\n if (version !== EXPORT_VERSION) {\n throw new Error(`Unsupported import version: expected ${EXPORT_VERSION}, got ${version}`);\n }\n\n const dimensions = headerView.getUint32(8, true);\n if (dimensions !== this.dimensions) {\n throw new Error(`Import dimension mismatch: expected ${this.dimensions}, got ${dimensions}`);\n }\n\n const vectorCount = headerView.getUint32(12, true);\n const vectorDataLen = headerView.getUint32(16, true);\n const keysDataLen = headerView.getUint32(20, true);\n\n // Clear existing state\n this.keyToSlot.clear();\n this.slotToKey.length = 0;\n this.memoryManager.reset();\n\n // Stream vectors directly into WASM memory in chunks\n if (vectorCount > 0) {\n this.memoryManager.ensureCapacity(vectorCount);\n\n let offset = 0;\n await sr.readChunked(vectorDataLen, (chunk) => {\n new Uint8Array(this.memoryManager.memory.buffer, this.memoryManager.dbOffset + offset, chunk.byteLength).set(\n chunk,\n );\n offset += chunk.byteLength;\n });\n\n this.memoryManager.setVectorCount(vectorCount);\n }\n\n // Read and decode keys (typically much smaller than vectors)\n if (keysDataLen > 0) {\n const keysBytes = await sr.readExact(keysDataLen);\n const keys = decodeLexicon(keysBytes);\n for (let i = 0; i < keys.length; i++) {\n this.keyToSlot.set(keys[i], i);\n this.slotToKey[i] = keys[i];\n }\n }\n\n sr.release();\n }\n\n /**\n * Normalize a vector using WASM (if available) or JS fallback.\n */\n private normalizeVector(vec: Float32Array): void {\n if (this.wasmExports) {\n const ptr = this.memoryManager.queryOffset;\n new Float32Array(this.memoryManager.memory.buffer, ptr, vec.length).set(vec);\n this.wasmExports.normalize(ptr, vec.length);\n const normalized = new Float32Array(this.memoryManager.memory.buffer, ptr, vec.length);\n vec.set(normalized);\n } else {\n normalize(vec);\n }\n }\n\n private assertOpen(): void {\n if (this.closed) {\n throw new Error(\"VectorDB instance has been closed\");\n }\n }\n}\n\n/**\n * Helper for reading exact byte counts from a ReadableStream.\n * Handles chunk boundaries transparently.\n */\nclass StreamReader {\n private reader: ReadableStreamDefaultReader<Uint8Array>;\n private buffer = new Uint8Array(0);\n\n constructor(stream: ReadableStream<Uint8Array>) {\n this.reader = stream.getReader();\n }\n\n /** Read exactly `n` bytes, accumulating from stream chunks as needed. */\n async readExact(n: number): Promise<Uint8Array> {\n if (n === 0) return new Uint8Array(0);\n\n // Fast path: buffer already has enough data\n if (this.buffer.byteLength >= n) {\n const result = this.buffer.subarray(0, n);\n this.buffer = this.buffer.subarray(n);\n return result;\n }\n\n // Collect chunks until we have enough bytes\n const chunks: Uint8Array[] = [];\n let total = this.buffer.byteLength;\n if (total > 0) {\n chunks.push(this.buffer);\n this.buffer = new Uint8Array(0);\n }\n\n while (total < n) {\n const { done, value } = await this.reader.read();\n if (done) throw new Error(\"Invalid import data: unexpected end of stream\");\n chunks.push(value);\n total += value.byteLength;\n }\n\n // Combine into a single buffer\n const combined = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n combined.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n if (total > n) {\n this.buffer = combined.subarray(n);\n return combined.subarray(0, n);\n }\n return combined;\n }\n\n /**\n * Read `totalBytes` from the stream in chunks, calling `onChunk` for each.\n * Avoids allocating a single large buffer for the full data.\n */\n async readChunked(totalBytes: number, onChunk: (chunk: Uint8Array) => void): Promise<void> {\n let remaining = totalBytes;\n\n // Drain buffered leftover first\n if (this.buffer.byteLength > 0) {\n const take = Math.min(this.buffer.byteLength, remaining);\n onChunk(this.buffer.subarray(0, take));\n remaining -= take;\n this.buffer = this.buffer.subarray(take);\n }\n\n while (remaining > 0) {\n const { done, value } = await this.reader.read();\n if (done) throw new Error(\"Invalid import data: unexpected end of stream\");\n\n if (value.byteLength <= remaining) {\n onChunk(value);\n remaining -= value.byteLength;\n } else {\n onChunk(value.subarray(0, remaining));\n this.buffer = value.slice(remaining);\n remaining = 0;\n }\n }\n }\n\n /** Release the stream reader lock. */\n release(): void {\n this.reader.releaseLock();\n }\n}\n"],"names":["VectorCapacityExceededError","maxVectors","OPFSStorageProvider","dirName","root","fileName","buffer","data","fileHandle","writable","file","InMemoryStorageProvider","chunks","totalSize","sum","c","result","offset","chunk","normalize","vec","sumSq","i","mag","invMag","searchAll","query","db","scores","dbSize","dimensions","dot","j","encoder","decoder","encodeLexicon","texts","encoded","t","e","view","bytes","decodeLexicon","len","text","PAGE_SIZE","MAX_PAGES","MemoryManager","initialVectorCount","queryBytes","dbBytes","totalBytes","initialPages","availableBytes","bytesPerVector","additionalVectors","newTotal","requiredBytes","currentBytes","pagesNeeded","vector","vectors","startOffset","vectorCount","index","count","topKResults","resolveKey","topK","minSimilarity","n","indices","a","b","k","results","idx","similarity","iterableResults","SIMD_WASM_BASE64","getSimdWasmBinary","binaryString","instantiateWasm","wasmBinary","memory","importObject","VECTORS_FILE","KEYS_FILE","EXPORT_MAGIC","EXPORT_VERSION","EXPORT_HEADER_BYTES","STREAM_CHUNK_SIZE","VectorDB","memoryManager","storage","shouldNormalize","wasmExports","keyToSlot","slotToKey","options","name","vectorBytes","keysBytes","keys","mm","key","value","existingSlot","slotIndex","slot","entries","iterable","queryVec","totalVectors","scoresOffset","queryView","dbView","scoresView","src","vectorDataLen","keysDataLen","header","headerView","phase","vectorOffset","controller","remaining","chunkSize","stream","sr","StreamReader","headerBytes","version","ptr","normalized","total","done","combined","onChunk","take"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eigen-db",
3
- "version": "4.1.0",
3
+ "version": "4.2.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",