@wiscale/velesdb-wasm 1.5.1 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-2026 Wiscale France
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # VelesDB WASM
2
2
 
3
3
  [![npm](https://img.shields.io/npm/v/@wiscale/velesdb-wasm)](https://www.npmjs.com/package/@wiscale/velesdb-wasm)
4
- [![License](https://img.shields.io/badge/license-ELv2-blue)](https://github.com/cyberlife-coder/VelesDB/blob/main/LICENSE)
4
+ [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
5
5
 
6
6
  WebAssembly build of [VelesDB](https://github.com/cyberlife-coder/VelesDB) - vector search in the browser.
7
7
 
@@ -11,6 +11,10 @@ WebAssembly build of [VelesDB](https://github.com/cyberlife-coder/VelesDB) - vec
11
11
  - **SIMD optimized** - Uses WASM SIMD128 for fast distance calculations
12
12
  - **Multiple metrics** - Cosine, Euclidean, Dot Product, Hamming, Jaccard
13
13
  - **Memory optimization** - SQ8 (4x) and Binary (32x) quantization
14
+ - **Knowledge Graph** - In-memory graph store with BFS/DFS traversal
15
+ - **Agent Memory** - Semantic memory for AI agents (store/query knowledge facts)
16
+ - **VelesQL parser** - Parse and validate VelesQL queries client-side
17
+ - **Sparse search** - Inverted index with RRF hybrid fusion
14
18
  - **Lightweight** - Minimal bundle size
15
19
 
16
20
  ## Installation
@@ -89,18 +93,26 @@ class VectorStore {
89
93
 
90
94
  // Methods
91
95
  insert(id: bigint, vector: Float32Array): void;
92
- insert_with_payload(id: bigint, vector: Float32Array, payload: object): void; insert_batch(batch: Array<[bigint, number[]]>): void; // Bulk insert
96
+ insert_with_payload(id: bigint, vector: Float32Array, payload: object): void;
97
+ insert_batch(batch: Array<[bigint, number[]]>): void; // Bulk insert
93
98
  search(query: Float32Array, k: number): Array<[bigint, number]>;
94
- search_with_filter(query: Float32Array, k: number, filter: object): Array<{id, score, payload}>; text_search(query: string, k: number, field?: string): Array<{id, score, payload}>; get(id: bigint): {id, vector, payload} | null; remove(id: bigint): boolean;
99
+ search_with_filter(query: Float32Array, k: number, filter: object): Array<{id, score, payload}>;
100
+ text_search(query: string, k: number, field?: string): Array<{id, score, payload}>;
101
+ get(id: bigint): {id, vector, payload} | null;
102
+ remove(id: bigint): boolean;
95
103
  clear(): void;
96
104
  reserve(additional: number): void; // Pre-allocate memory
97
105
  memory_usage(): number; // Accurate for each storage mode
98
106
 
99
107
  //
100
108
  multi_query_search(vectors: Float32Array, num_vectors: number, k: number, strategy?: string, rrf_k?: number): Array<[bigint, number]>;
101
- hybrid_search(vector: Float32Array, text_query: string, k: number, vector_weight?: number, field?: string): Array<{id, score, payload}>;
109
+ hybrid_search(vector: Float32Array, text_query: string, k: number, vector_weight?: number): Array<{id, score, payload}>;
102
110
  batch_search(vectors: Float32Array, num_vectors: number, k: number): Array<Array<[bigint, number]>>;
103
111
 
112
+ // Sparse search (inverted index)
113
+ sparse_insert(doc_id: bigint, indices: Uint32Array, values: Float32Array): void;
114
+ sparse_search(indices: Uint32Array, values: Float32Array, k: number): Array<{doc_id, score}>;
115
+
104
116
  // Metadata-only store
105
117
  static new_metadata_only(): VectorStore;
106
118
  readonly is_metadata_only: boolean;
@@ -256,38 +268,114 @@ The WASM build is optimized for client-side use cases but has some limitations c
256
268
  | Full-text search (BM25) | ✅ | ✅ |
257
269
  | Multi-query fusion (MQG) | ✅ | ✅ |
258
270
  | Batch search | ✅ | ✅ |
259
- | Full VelesQL queries | | ✅ |
260
- | Knowledge Graph operations | | ✅ |
271
+ | Sparse search | | ✅ |
272
+ | Knowledge Graph (nodes, edges, traversal) | | ✅ |
273
+ | Agent Memory (SemanticMemory) | ✅ | ✅ |
274
+ | VelesQL parsing & validation | ✅ | ✅ |
275
+ | VelesQL query execution | ❌ | ✅ |
261
276
  | JOIN operations | ❌ | ✅ |
262
277
  | Aggregations (GROUP BY) | ❌ | ✅ |
263
278
  | Persistence | IndexedDB | Disk (mmap) |
264
279
  | Max vectors | ~100K (browser RAM) | Millions |
265
280
 
266
- ### Unsupported Operations
281
+ ### VelesQL (Parser Only)
267
282
 
268
- When you try to use unsupported features, you'll get clear error messages:
283
+ VelesQL parsing and validation are available in WASM. You can parse queries, inspect their AST, and validate syntax client-side. However, query **execution** (running queries against data) requires the REST server.
269
284
 
270
285
  ```javascript
271
- // VelesQL string queries not supported in WASM
272
- // Use the native API instead:
286
+ import { VelesQL } from '@wiscale/velesdb-wasm';
287
+
288
+ // Parse and inspect a query
289
+ const parsed = VelesQL.parse("SELECT * FROM docs WHERE vector NEAR $v LIMIT 10");
290
+ console.log(parsed.tableName); // "docs"
291
+ console.log(parsed.hasVectorSearch); // true
292
+ console.log(parsed.limit); // 10
293
+
294
+ // Validate syntax
295
+ VelesQL.isValid("SELECT * FROM docs"); // true
296
+ VelesQL.isValid("SELEC * FROM docs"); // false
297
+
298
+ // Parse MATCH (graph) queries
299
+ const match = VelesQL.parse("MATCH (p:Person)-[:KNOWS]->(f:Person) RETURN f.name");
300
+ console.log(match.isMatch); // true
301
+ console.log(match.matchNodeCount); // 2
302
+ console.log(match.matchRelationshipCount); // 1
303
+ ```
273
304
 
274
- // Instead of: store.query("SELECT * FROM docs WHERE vector NEAR $v")
275
- // Use:
276
- const results = store.search(queryVector, 10);
305
+ ### Knowledge Graph (GraphStore)
277
306
 
278
- // Instead of: store.query("SELECT * FROM docs WHERE category = 'tech'")
279
- // Use:
280
- const results = store.search_with_filter(queryVector, 10, {
281
- condition: { type: "eq", field: "category", value: "tech" }
282
- });
307
+ Build and traverse in-memory knowledge graphs entirely in the browser:
308
+
309
+ ```javascript
310
+ import { GraphStore, GraphNode, GraphEdge } from '@wiscale/velesdb-wasm';
311
+
312
+ const graph = new GraphStore();
313
+
314
+ // Create nodes
315
+ const alice = new GraphNode(1n, "Person");
316
+ alice.set_string_property("name", "Alice");
317
+ const bob = new GraphNode(2n, "Person");
318
+ bob.set_string_property("name", "Bob");
319
+
320
+ graph.add_node(alice);
321
+ graph.add_node(bob);
322
+
323
+ // Create edges
324
+ const edge = new GraphEdge(1n, 1n, 2n, "KNOWS");
325
+ graph.add_edge(edge);
326
+
327
+ // Traverse
328
+ const neighbors = graph.get_neighbors(1n); // [2n]
329
+ const outgoing = graph.get_outgoing(1n); // [GraphEdge]
330
+ const bfsResults = graph.bfs_traverse(1n, 3, 100); // BFS up to depth 3
331
+ ```
332
+
333
+ ### Agent Memory (SemanticMemory)
334
+
335
+ Store and retrieve knowledge facts by semantic similarity for AI agent workloads:
336
+
337
+ ```javascript
338
+ import { SemanticMemory } from '@wiscale/velesdb-wasm';
339
+
340
+ const memory = new SemanticMemory(384);
341
+
342
+ // Store knowledge with embedding vectors
343
+ memory.store(1n, "Paris is the capital of France", embedding1);
344
+ memory.store(2n, "Berlin is the capital of Germany", embedding2);
345
+
346
+ // Query by similarity
347
+ const results = memory.query(queryEmbedding, 5);
348
+ // [{id, score, content}, ...]
349
+
350
+ console.log(memory.len); // 2
351
+ console.log(memory.dimension); // 384
352
+ ```
353
+
354
+ ### Sparse Search (SparseIndex)
355
+
356
+ Inverted-index search with sparse vectors and RRF hybrid fusion:
357
+
358
+ ```javascript
359
+ import { SparseIndex, hybrid_search_fuse } from '@wiscale/velesdb-wasm';
360
+
361
+ const index = new SparseIndex();
362
+
363
+ // Insert sparse vectors (term indices + weights)
364
+ index.insert(1n, new Uint32Array([10, 20, 30]), new Float32Array([1.0, 0.5, 0.3]));
365
+ index.insert(2n, new Uint32Array([10, 40]), new Float32Array([0.8, 1.2]));
366
+
367
+ // Search
368
+ const results = index.search(new Uint32Array([10, 20]), new Float32Array([1.0, 1.0]), 5);
369
+
370
+ // Fuse dense + sparse results with RRF
371
+ const fused = hybrid_search_fuse(denseResults, sparseResults, 60, 10);
283
372
  ```
284
373
 
285
374
  ### When to Use REST Backend
286
375
 
287
376
  Consider using the [REST server](https://github.com/cyberlife-coder/VelesDB) if you need:
288
377
 
289
- - **Full VelesQL support** - Complex SQL-like queries with JOINs and aggregations
290
- - **Knowledge Graph** - Entity relationships and graph traversal
378
+ - **VelesQL query execution** - Running queries against data (JOINs, aggregations, server-side filtering)
291
379
  - **Large datasets** - More than 100K vectors
292
380
  - **Server-side processing** - Centralized vector database
293
381
 
@@ -342,6 +430,6 @@ Typical latencies on modern browsers:
342
430
 
343
431
  ## License
344
432
 
345
- Elastic License 2.0 (ELv2)
433
+ MIT License (bindings). The core engine (`velesdb-core` and `velesdb-server`) is under VelesDB Core License 1.0.
346
434
 
347
- See [LICENSE](https://github.com/cyberlife-coder/VelesDB/blob/main/LICENSE) for details.
435
+ See [LICENSE](./LICENSE) for WASM bindings license, [root LICENSE](https://github.com/cyberlife-coder/VelesDB/blob/main/LICENSE) for core engine.
package/package.json CHANGED
@@ -5,8 +5,8 @@
5
5
  "Julien Lange <contact@wiscale.fr>"
6
6
  ],
7
7
  "description": "VelesDB for WebAssembly - Vector search in the browser",
8
- "version": "1.5.1",
9
- "license": "SEE LICENSE IN ../../LICENSE",
8
+ "version": "1.6.0",
9
+ "license": "MIT",
10
10
  "repository": {
11
11
  "type": "git",
12
12
  "url": "https://github.com/cyberlife-coder/velesdb"
package/velesdb_wasm.d.ts CHANGED
@@ -531,7 +531,9 @@ export enum StorageMode {
531
531
  */
532
532
  Binary = 2,
533
533
  /**
534
- * Product Quantization (currently mapped to SQ8 path in WASM runtime)
534
+ * Product Quantization **WASM limitation**: PQ requires `rayon`/`persistence`
535
+ * which are unavailable in WASM. This variant uses the SQ8 codepath as a
536
+ * fallback. For true PQ, use the native `velesdb-core` crate.
535
537
  */
536
538
  ProductQuantization = 3,
537
539
  }
@@ -616,6 +618,17 @@ export class VectorStore {
616
618
  get(id: bigint): any;
617
619
  /**
618
620
  * Hybrid search (vector + text). `vector_weight` 0-1 (default 0.5).
621
+ *
622
+ * For `Full` storage mode, this computes per-vector distance and text
623
+ * matching in a single pass. For quantized modes (`SQ8`, `Binary`,
624
+ * `ProductQuantization`), a decomposed approach is used: vector scores
625
+ * are obtained via the quantization-aware `compute_scores` path, text
626
+ * matches are evaluated independently on payloads, and the two result
627
+ * sets are fused with the requested weight. Quantized vector scores are
628
+ * approximate, so recall may differ slightly from `Full` mode.
629
+ *
630
+ * Returns `[{id, score, payload}, ...]` sorted by combined score
631
+ * descending, truncated to `k` results.
619
632
  */
620
633
  hybrid_search(query_vector: Float32Array, text_query: string, k: number, vector_weight?: number | null): any;
621
634
  /**
@@ -953,21 +966,21 @@ export interface InitOutput {
953
966
  readonly vectorstore_with_capacity: (a: number, b: number, c: number, d: number, e: number) => void;
954
967
  readonly velesql_isValid: (a: number, b: number) => number;
955
968
  readonly velesql_parse: (a: number, b: number, c: number) => void;
956
- readonly __wbg_set_traversalprogress_is_complete: (a: number, b: number) => void;
957
969
  readonly __wbg_set_traversalprogress_current_depth: (a: number, b: number) => void;
958
970
  readonly __wbg_set_traversalprogress_estimated_total: (a: number, b: number) => void;
959
971
  readonly __wbg_set_traversalprogress_visited_count: (a: number, b: number) => void;
972
+ readonly __wbg_set_traversalprogress_is_complete: (a: number, b: number) => void;
960
973
  readonly __wbg_get_traversalprogress_is_complete: (a: number) => number;
961
974
  readonly __wbg_get_traversalprogress_current_depth: (a: number) => number;
962
975
  readonly __wbg_get_traversalprogress_estimated_total: (a: number) => number;
963
976
  readonly __wbg_get_traversalprogress_visited_count: (a: number) => number;
964
977
  readonly graphnode_id: (a: number) => bigint;
965
978
  readonly __wbg_traversalprogress_free: (a: number, b: number) => void;
966
- readonly __wasm_bindgen_func_elem_1295: (a: number, b: number) => void;
967
- readonly __wasm_bindgen_func_elem_284: (a: number, b: number) => void;
968
- readonly __wasm_bindgen_func_elem_1296: (a: number, b: number, c: number, d: number) => void;
969
- readonly __wasm_bindgen_func_elem_1327: (a: number, b: number, c: number, d: number) => void;
970
- readonly __wasm_bindgen_func_elem_285: (a: number, b: number, c: number) => void;
979
+ readonly __wasm_bindgen_func_elem_1318: (a: number, b: number) => void;
980
+ readonly __wasm_bindgen_func_elem_289: (a: number, b: number) => void;
981
+ readonly __wasm_bindgen_func_elem_1319: (a: number, b: number, c: number, d: number) => void;
982
+ readonly __wasm_bindgen_func_elem_1364: (a: number, b: number, c: number, d: number) => void;
983
+ readonly __wasm_bindgen_func_elem_290: (a: number, b: number, c: number) => void;
971
984
  readonly __wbindgen_export: (a: number, b: number) => number;
972
985
  readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
973
986
  readonly __wbindgen_export3: (a: number) => void;
package/velesdb_wasm.js CHANGED
@@ -1366,7 +1366,9 @@ export const StorageMode = Object.freeze({
1366
1366
  */
1367
1367
  Binary: 2, "2": "Binary",
1368
1368
  /**
1369
- * Product Quantization (currently mapped to SQ8 path in WASM runtime)
1369
+ * Product Quantization **WASM limitation**: PQ requires `rayon`/`persistence`
1370
+ * which are unavailable in WASM. This variant uses the SQ8 codepath as a
1371
+ * fallback. For true PQ, use the native `velesdb-core` crate.
1370
1372
  */
1371
1373
  ProductQuantization: 3, "3": "ProductQuantization",
1372
1374
  });
@@ -1628,6 +1630,17 @@ export class VectorStore {
1628
1630
  }
1629
1631
  /**
1630
1632
  * Hybrid search (vector + text). `vector_weight` 0-1 (default 0.5).
1633
+ *
1634
+ * For `Full` storage mode, this computes per-vector distance and text
1635
+ * matching in a single pass. For quantized modes (`SQ8`, `Binary`,
1636
+ * `ProductQuantization`), a decomposed approach is used: vector scores
1637
+ * are obtained via the quantization-aware `compute_scores` path, text
1638
+ * matches are evaluated independently on payloads, and the two result
1639
+ * sets are fused with the requested weight. Quantized vector scores are
1640
+ * approximate, so recall may differ slightly from `Full` mode.
1641
+ *
1642
+ * Returns `[{id, score, payload}, ...]` sorted by combined score
1643
+ * descending, truncated to `k` results.
1631
1644
  * @param {Float32Array} query_vector
1632
1645
  * @param {string} text_query
1633
1646
  * @param {number} k
@@ -2512,7 +2525,7 @@ function __wbg_get_imports() {
2512
2525
  const a = state0.a;
2513
2526
  state0.a = 0;
2514
2527
  try {
2515
- return __wasm_bindgen_func_elem_1327(a, state0.b, arg0, arg1);
2528
+ return __wasm_bindgen_func_elem_1364(a, state0.b, arg0, arg1);
2516
2529
  } finally {
2517
2530
  state0.a = a;
2518
2531
  }
@@ -2546,7 +2559,7 @@ function __wbg_get_imports() {
2546
2559
  const a = state0.a;
2547
2560
  state0.a = 0;
2548
2561
  try {
2549
- return __wasm_bindgen_func_elem_1327(a, state0.b, arg0, arg1);
2562
+ return __wasm_bindgen_func_elem_1364(a, state0.b, arg0, arg1);
2550
2563
  } finally {
2551
2564
  state0.a = a;
2552
2565
  }
@@ -2679,13 +2692,13 @@ function __wbg_get_imports() {
2679
2692
  return addHeapObject(ret);
2680
2693
  },
2681
2694
  __wbindgen_cast_0000000000000001: function(arg0, arg1) {
2682
- // Cast intrinsic for `Closure(Closure { dtor_idx: 136, function: Function { arguments: [Externref], shim_idx: 137, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
2683
- const ret = makeMutClosure(arg0, arg1, wasm.__wasm_bindgen_func_elem_1295, __wasm_bindgen_func_elem_1296);
2695
+ // Cast intrinsic for `Closure(Closure { dtor_idx: 138, function: Function { arguments: [Externref], shim_idx: 139, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
2696
+ const ret = makeMutClosure(arg0, arg1, wasm.__wasm_bindgen_func_elem_1318, __wasm_bindgen_func_elem_1319);
2684
2697
  return addHeapObject(ret);
2685
2698
  },
2686
2699
  __wbindgen_cast_0000000000000002: function(arg0, arg1) {
2687
2700
  // Cast intrinsic for `Closure(Closure { dtor_idx: 9, function: Function { arguments: [NamedExternref("Event")], shim_idx: 10, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
2688
- const ret = makeMutClosure(arg0, arg1, wasm.__wasm_bindgen_func_elem_284, __wasm_bindgen_func_elem_285);
2701
+ const ret = makeMutClosure(arg0, arg1, wasm.__wasm_bindgen_func_elem_289, __wasm_bindgen_func_elem_290);
2689
2702
  return addHeapObject(ret);
2690
2703
  },
2691
2704
  __wbindgen_cast_0000000000000003: function(arg0) {
@@ -2722,14 +2735,14 @@ function __wbg_get_imports() {
2722
2735
  };
2723
2736
  }
2724
2737
 
2725
- function __wasm_bindgen_func_elem_285(arg0, arg1, arg2) {
2726
- wasm.__wasm_bindgen_func_elem_285(arg0, arg1, addHeapObject(arg2));
2738
+ function __wasm_bindgen_func_elem_290(arg0, arg1, arg2) {
2739
+ wasm.__wasm_bindgen_func_elem_290(arg0, arg1, addHeapObject(arg2));
2727
2740
  }
2728
2741
 
2729
- function __wasm_bindgen_func_elem_1296(arg0, arg1, arg2) {
2742
+ function __wasm_bindgen_func_elem_1319(arg0, arg1, arg2) {
2730
2743
  try {
2731
2744
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
2732
- wasm.__wasm_bindgen_func_elem_1296(retptr, arg0, arg1, addHeapObject(arg2));
2745
+ wasm.__wasm_bindgen_func_elem_1319(retptr, arg0, arg1, addHeapObject(arg2));
2733
2746
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
2734
2747
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
2735
2748
  if (r1) {
@@ -2740,8 +2753,8 @@ function __wasm_bindgen_func_elem_1296(arg0, arg1, arg2) {
2740
2753
  }
2741
2754
  }
2742
2755
 
2743
- function __wasm_bindgen_func_elem_1327(arg0, arg1, arg2, arg3) {
2744
- wasm.__wasm_bindgen_func_elem_1327(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
2756
+ function __wasm_bindgen_func_elem_1364(arg0, arg1, arg2, arg3) {
2757
+ wasm.__wasm_bindgen_func_elem_1364(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
2745
2758
  }
2746
2759
 
2747
2760
 
Binary file