@omendb/omendb 0.0.30 → 0.0.32

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.
Files changed (4) hide show
  1. package/README.md +9 -6
  2. package/index.d.ts +100 -12
  3. package/index.js +66 -0
  4. package/package.json +6 -6
package/README.md CHANGED
@@ -374,13 +374,16 @@ const merged = db.mergeFrom(otherDb);
374
374
 
375
375
  ## Performance
376
376
 
377
- **10K vectors, 128D, M=16, ef=100. Measured 2026-01-20 (Apple M3 Max):**
377
+ Node bindings call the same Rust core as the Rust and Python APIs, so authoritative ANN numbers are tracked at the repo root with the shared SIFT benchmark on Fedora/Linux medians.
378
378
 
379
- | Metric | Value |
380
- | ---------- | ------------ |
381
- | Search QPS | 11,542 |
382
- | Build | 30,826 vec/s |
383
- | Recall@10 | 89.7% |
379
+ Use the shared benchmark for comparable performance claims:
380
+
381
+ ```bash
382
+ cd python && uv run python benchmark.py
383
+ cd python && uv run python benchmark.py --publish
384
+ ```
385
+
386
+ Older Apple M3 Max wrapper numbers were local reference points only and are no longer treated as the authoritative baseline.
384
387
 
385
388
  ## License
386
389
 
package/index.d.ts CHANGED
@@ -209,6 +209,71 @@ export declare class VectorDatabase {
209
209
  * @returns Array of results in same order as input, null for missing IDs
210
210
  */
211
211
  getBatch(ids: Array<string>): Array<GetResult | undefined | null>
212
+ /**
213
+ * Add a typed directed edge between two document IDs.
214
+ *
215
+ * @param fromId - Source document ID
216
+ * @param toId - Target document ID
217
+ * @param edgeType - Edge type label (e.g. "related", "parent")
218
+ * @param weight - Edge weight (default: 1.0)
219
+ * @param metadata - Arbitrary JSON-compatible metadata
220
+ */
221
+ addEdge(fromId: string, toId: string, edgeType: string, weight?: number | undefined | null, metadata?: JsonValue | undefined | null): void
222
+ /**
223
+ * Remove the edge of the given type between two nodes.
224
+ *
225
+ * @returns true if an edge was found and removed
226
+ */
227
+ removeEdge(fromId: string, toId: string, edgeType: string): boolean
228
+ /**
229
+ * Get all edges for a node in the given direction.
230
+ *
231
+ * @param id - Node ID
232
+ * @param direction - "outgoing", "incoming", or "both" (default: "both")
233
+ * @returns Array of edges with fromId, toId, edgeType, weight, metadata
234
+ */
235
+ getEdges(id: string, direction?: string | undefined | null, edgeType?: string | undefined | null): Array<EdgeResult>
236
+ /**
237
+ * BFS traversal from a starting node.
238
+ *
239
+ * @param startId - Starting node ID
240
+ * @param direction - "outgoing", "incoming", or "both" (default: "outgoing")
241
+ * @param maxDepth - Maximum traversal depth (default: 1)
242
+ * @param edgeType - Filter by edge type
243
+ * @returns Reachable node IDs (not including startId)
244
+ */
245
+ traverse(startId: string, direction?: string | undefined | null, maxDepth?: number | undefined | null, edgeType?: string | undefined | null): Array<string>
246
+ /**
247
+ * Expand a list of IDs by following their edges (depth=1).
248
+ *
249
+ * @param ids - Starting node IDs
250
+ * @param direction - "outgoing", "incoming", or "both" (default: "outgoing")
251
+ * @param edgeType - Filter by edge type
252
+ * @returns Expanded ID set (includes original IDs + neighbors)
253
+ */
254
+ expand(ids: Array<string>, direction?: string | undefined | null, edgeType?: string | undefined | null): Array<string>
255
+ /** Number of edges in the graph. */
256
+ get edgeCount(): number
257
+ /** Look up a single edge by endpoints and type. */
258
+ getEdge(fromId: string, toId: string, edgeType: string): EdgeResult | null
259
+ /** Get neighbor IDs for a node. */
260
+ neighbors(id: string, direction?: string | undefined | null, edgeType?: string | undefined | null): Array<string>
261
+ /** Count edges for a node. */
262
+ nodeDegree(id: string, direction?: string | undefined | null, edgeType?: string | undefined | null): number
263
+ /** Check if a path exists between two nodes. */
264
+ hasPath(fromId: string, toId: string, direction?: string | undefined | null, maxDepth?: number | undefined | null, edgeType?: string | undefined | null): boolean
265
+ /** Find shortest path between two nodes. */
266
+ shortestPath(fromId: string, toId: string, direction?: string | undefined | null, maxDepth?: number | undefined | null, edgeType?: string | undefined | null): Array<string> | null
267
+ /** BFS traversal returning discovery edges. */
268
+ traverseEdges(startId: string, direction?: string | undefined | null, maxDepth?: number | undefined | null, edgeType?: string | undefined | null): Array<TraversalHitResult>
269
+ /** Extract ego-graph around a node. */
270
+ subgraph(id: string, maxDepth?: number | undefined | null, direction?: string | undefined | null, edgeType?: string | undefined | null): SubgraphResult
271
+ /** Batch add edges with a single WAL sync. */
272
+ addEdges(edges: Array<EdgeInput>): number
273
+ /** Get all unique edge types. */
274
+ edgeTypes(): Array<string>
275
+ /** Get all node IDs with edges. */
276
+ nodeIds(): Array<string>
212
277
  /**
213
278
  * Check if text search is enabled.
214
279
  *
@@ -258,11 +323,9 @@ export declare class VectorDatabase {
258
323
  /**
259
324
  * Search for k nearest neighbors.
260
325
  *
261
- * @param query - Query vector(s): number[] or Float32Array for single-vector stores;
262
- * number[][] or Float32Array[] for multi-vector stores
326
+ * @param query - Query vector (number[] or Float32Array)
263
327
  * @param k - Number of results to return
264
- * @param options - Optional search options. Single-vector: {filter?, ef?, maxDistance?}.
265
- * Multi-vector: {rerank?, rerankFactor?}
328
+ * @param options - Optional search options: {filter?, ef?, maxDistance?}
266
329
  * @returns Array of {id, distance, score, metadata}
267
330
  *
268
331
  * @example
@@ -273,12 +336,9 @@ export declare class VectorDatabase {
273
336
  * // With options
274
337
  * db.search([1, 0, 0, 0], 10, { filter: { category: "A" }, ef: 200 });
275
338
  * db.search([1, 0, 0, 0], 10, { maxDistance: 0.5 });
276
- *
277
- * // Multi-vector search
278
- * db.search([[0.1, 0.2], [0.3, 0.4]], 5, { rerank: true, rerankFactor: 8 });
279
339
  * ```
280
340
  */
281
- search(query: Array<number> | Float32Array | string | Array<Array<number>> | Array<Float32Array>, k: number, options?: { filter?: Record<string, unknown>; ef?: number; maxDistance?: number; rerank?: boolean; rerankFactor?: number } | undefined): Promise<Array<SearchResult>>
341
+ search(query: Array<number> | Float32Array | string, k: number, options?: { filter?: Record<string, unknown>; ef?: number; maxDistance?: number } | undefined): Promise<Array<SearchResult>>
282
342
  /**
283
343
  * Search multi-vector store with query tokens.
284
344
  *
@@ -287,7 +347,7 @@ export declare class VectorDatabase {
287
347
  * @param query - Query tokens (number[][] or Float32Array[])
288
348
  * @param k - Number of results to return
289
349
  * @param rerank - Enable MaxSim reranking for better quality (default: true)
290
- * @param rerankFactor - Fetch k*rerankFactor candidates before reranking (default: 32)
350
+ * @param rerankFactor - Fetch k*rerankFactor candidates before reranking (default: 20)
291
351
  * @returns Array of {id, distance, metadata}
292
352
  */
293
353
  searchMulti(query: Array<Array<number>> | Array<Float32Array>, k: number, rerank?: boolean | undefined | null, rerankFactor?: number | undefined | null): Array<SearchResult>
@@ -367,6 +427,22 @@ export declare class VectorDatabase {
367
427
  hybridSparseSearch(queryVector: Array<number> | Float32Array, sparseQuery: { indices: number[]; values: number[] } | Record<string, number>, k: number, options?: { alpha?: number; filter?: Record<string, unknown> } | undefined): Array<SparseSearchResult>
368
428
  }
369
429
 
430
+ export interface EdgeInput {
431
+ fromId: string
432
+ toId: string
433
+ edgeType: string
434
+ weight?: number
435
+ metadata?: Record<string, unknown> | null
436
+ }
437
+
438
+ export interface EdgeResult {
439
+ fromId: string
440
+ toId: string
441
+ edgeType: string
442
+ weight: number
443
+ metadata?: Record<string, unknown> | null
444
+ }
445
+
370
446
  export interface GetResult {
371
447
  id: string
372
448
  vector: Float32Array
@@ -462,12 +538,13 @@ export interface OpenOptions {
462
538
  metric?: string
463
539
  /**
464
540
  * Enable multi-vector mode for ColBERT-style retrieval
465
- * - true: Enable with default config (repetitions=8, partition_bits=4, dProj=16)
466
- * - { repetitions?, partitionBits?, seed?, dProj? }: Custom config
541
+ * - true: Enable with default config (repetitions=8, partitionBits=4, dProj=16)
542
+ * - { repetitions?, partitionBits?, seed?, dProj?, poolFactor? }: Custom config
467
543
  * - dProj: Dimension projection (16 = 8x smaller FDE, null = full token dim)
544
+ * - poolFactor: Optional token pooling ratio (2 halves stored tokens)
468
545
  * - false/null: Disabled (default, single-vector mode)
469
546
  */
470
- multiVector?: boolean | { repetitions?: number; partitionBits?: number; seed?: number; dProj?: number | null } | null | undefined
547
+ multiVector?: boolean | { repetitions?: number; partitionBits?: number; seed?: number; dProj?: number | null; poolFactor?: number | null } | null | undefined
471
548
  /** SQ8 refiner: rescore with full precision (default: true when quantized) */
472
549
  rescore?: boolean
473
550
  /** Candidate multiplier for rescoring (default: 3.0) */
@@ -511,8 +588,19 @@ export interface StatsResult {
511
588
  path: string
512
589
  }
513
590
 
591
+ export interface SubgraphResult {
592
+ nodeIds: Array<string>
593
+ edges: Array<EdgeResult>
594
+ }
595
+
514
596
  export interface TextSearchResult {
515
597
  id: string
516
598
  score: number
517
599
  metadata: Record<string, unknown>
518
600
  }
601
+
602
+ export interface TraversalHitResult {
603
+ id: string
604
+ depth: number
605
+ edge: EdgeResult
606
+ }
package/index.js CHANGED
@@ -365,6 +365,72 @@ class VectorDatabase {
365
365
  hybridSparseSearch(queryVector, sparseQuery, k, options) {
366
366
  return this._native.hybridSparseSearch(queryVector, sparseQuery, k, options);
367
367
  }
368
+
369
+ // --- Edge graph API ---
370
+
371
+ addEdge(fromId, toId, edgeType, weight, metadata) {
372
+ return this._native.addEdge(fromId, toId, edgeType, weight, metadata);
373
+ }
374
+
375
+ removeEdge(fromId, toId, edgeType) {
376
+ return this._native.removeEdge(fromId, toId, edgeType);
377
+ }
378
+
379
+ getEdges(id, direction, edgeType) {
380
+ return this._native.getEdges(id, direction, edgeType);
381
+ }
382
+
383
+ traverse(startId, direction, maxDepth, edgeType) {
384
+ return this._native.traverse(startId, direction, maxDepth, edgeType);
385
+ }
386
+
387
+ expand(ids, direction, edgeType) {
388
+ return this._native.expand(ids, direction, edgeType);
389
+ }
390
+
391
+ get edgeCount() {
392
+ return this._native.edgeCount;
393
+ }
394
+
395
+ getEdge(fromId, toId, edgeType) {
396
+ return this._native.getEdge(fromId, toId, edgeType);
397
+ }
398
+
399
+ neighbors(id, direction, edgeType) {
400
+ return this._native.neighbors(id, direction, edgeType);
401
+ }
402
+
403
+ nodeDegree(id, direction, edgeType) {
404
+ return this._native.nodeDegree(id, direction, edgeType);
405
+ }
406
+
407
+ hasPath(fromId, toId, direction, maxDepth, edgeType) {
408
+ return this._native.hasPath(fromId, toId, direction, maxDepth, edgeType);
409
+ }
410
+
411
+ shortestPath(fromId, toId, direction, maxDepth, edgeType) {
412
+ return this._native.shortestPath(fromId, toId, direction, maxDepth, edgeType);
413
+ }
414
+
415
+ traverseEdges(startId, direction, maxDepth, edgeType) {
416
+ return this._native.traverseEdges(startId, direction, maxDepth, edgeType);
417
+ }
418
+
419
+ subgraph(id, maxDepth, direction, edgeType) {
420
+ return this._native.subgraph(id, maxDepth, direction, edgeType);
421
+ }
422
+
423
+ addEdges(edges) {
424
+ return this._native.addEdges(edges);
425
+ }
426
+
427
+ edgeTypes() {
428
+ return this._native.edgeTypes();
429
+ }
430
+
431
+ nodeIds() {
432
+ return this._native.nodeIds();
433
+ }
368
434
  }
369
435
 
370
436
  function open(path, options, embeddingFn) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omendb/omendb",
3
- "version": "0.0.30",
3
+ "version": "0.0.32",
4
4
  "description": "Fast embedded vector database with HNSW + ACORN-1 filtered search",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -50,10 +50,10 @@
50
50
  "omendb.node"
51
51
  ],
52
52
  "optionalDependencies": {
53
- "@omendb/omendb-darwin-x64": "0.0.30",
54
- "@omendb/omendb-darwin-arm64": "0.0.30",
55
- "@omendb/omendb-linux-x64-gnu": "0.0.30",
56
- "@omendb/omendb-linux-arm64-gnu": "0.0.30",
57
- "@omendb/omendb-win32-x64-msvc": "0.0.30"
53
+ "@omendb/omendb-darwin-x64": "0.0.32",
54
+ "@omendb/omendb-darwin-arm64": "0.0.32",
55
+ "@omendb/omendb-linux-x64-gnu": "0.0.32",
56
+ "@omendb/omendb-linux-arm64-gnu": "0.0.32",
57
+ "@omendb/omendb-win32-x64-msvc": "0.0.32"
58
58
  }
59
59
  }