@wiscale/velesdb-sdk 1.10.0 → 1.12.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/README.md CHANGED
@@ -2,17 +2,32 @@
2
2
 
3
3
  Official TypeScript SDK for [VelesDB](https://github.com/cyberlife-coder/VelesDB) -- the local-first vector database for AI and RAG. Sub-millisecond semantic search in Browser and Node.js.
4
4
 
5
- **v1.10.0** | Node.js >= 18 | Browser (WASM) | MIT License
5
+ **v1.12.0** | Node.js >= 18 | Browser (WASM) | MIT License
6
6
 
7
- ## What's New in v1.10.0
7
+ ## What's New in v1.12.0
8
8
 
9
- - **VelesQL LET clause** -- named score bindings for custom scoring formulas
10
- - **Component scores** -- `vector_score`, `bm25_score`, `graph_score` resolve independently in ORDER BY
11
- - **WITH options functional** -- `mode`, `timeout_ms`, `rerank` now wired to execution (were parsed but ignored)
12
- - **Agent Memory VelesQL** -- query semantic/episodic/procedural memory via standard VelesQL
13
- - **USING FUSION k parameter** -- configurable RRF constant for hybrid text search
9
+ - **Cross-collection MATCH queries** -- `@collection` annotation on MATCH node patterns enables cross-collection graph queries
10
+ - **MATCH via `/query` endpoint** -- MATCH queries can now be executed via `Database::execute_query`
11
+ - **BFS dedup** -- CSR and EdgeStore BFS no longer produce duplicate results for diamond graphs
12
+ - **`rrf_k` propagation** -- now properly propagated to `hybrid_search_with_filter`
13
+ - **`ComponentScores` optimization** -- changed to `&'static str` for zero-allocation score tagging
14
14
 
15
- ### Previous (v1.9.2)
15
+ ### Previous (v1.11.1)
16
+
17
+ - **Graph API parity** -- 7 new REST endpoints for complete graph operations (delete edge, edge count, list nodes, node edges, node payload, parallel BFS, graph search)
18
+ - **Bitmap pre-filter** -- adaptive strategy selection for filtered search
19
+ - **CSR graph traversal v2** -- lock-free adjacency with edge IDs and labels
20
+ - **Bulk insert v2** -- DirectVectorWriter + AsyncIndexBuilder pipeline
21
+
22
+ ### Previous (v1.11.0)
23
+
24
+ - **15 new VelesQL statements** -- SHOW COLLECTIONS, DESCRIBE, EXPLAIN, CREATE/DROP INDEX, ANALYZE, TRUNCATE, ALTER COLLECTION, FLUSH, multi-row INSERT, UPSERT, SELECT EDGES, INSERT NODE
25
+ - **203 BDD E2E tests** -- comprehensive end-to-end test coverage for all VelesQL features
26
+ - **TRUNCATE on graph collections** -- clears nodes + edges in a single statement
27
+ - **Python `execute_query()`** -- full VelesQL execution from Python bindings
28
+ - **Cyclomatic complexity ≤ 8** -- refactored 6 hotspots for Codacy compliance
29
+
30
+ ### Previous (v1.10.0)
16
31
 
17
32
  - **SearchQuality type** -- `SearchQuality` type and `quality` field in `SearchOptions`
18
33
  - **StorageMode in HnswParams** -- `storageMode` field in HNSW configuration
@@ -532,6 +547,23 @@ const degree = await db.getNodeDegree('social', 100);
532
547
  console.log(`In: ${degree.inDegree}, Out: ${degree.outDegree}`);
533
548
  ```
534
549
 
550
+ #### `db.traverseParallel(collection, request)`
551
+
552
+ Multi-source parallel BFS traversal with deduplication. Starts BFS from multiple source nodes simultaneously.
553
+
554
+ ```typescript
555
+ const result = await db.traverseParallel('social', {
556
+ sources: [100, 200, 300],
557
+ maxDepth: 3,
558
+ limit: 50,
559
+ relTypes: ['FOLLOWS']
560
+ });
561
+
562
+ for (const node of result.results) {
563
+ console.log(`Node ${node.targetId} at depth ${node.depth}`);
564
+ }
565
+ ```
566
+
535
567
  ---
536
568
 
537
569
  ### Property Indexes
package/dist/index.d.mts CHANGED
@@ -180,6 +180,17 @@ interface TraverseRequest {
180
180
  /** Filter by relationship types (empty = all types) */
181
181
  relTypes?: string[];
182
182
  }
183
+ /** Request for multi-source parallel BFS traversal */
184
+ interface TraverseParallelRequest {
185
+ /** Source node IDs to start traversal from */
186
+ sources: number[];
187
+ /** Maximum traversal depth */
188
+ maxDepth?: number;
189
+ /** Maximum number of results to return */
190
+ limit?: number;
191
+ /** Filter by relationship types (empty = all types) */
192
+ relTypes?: string[];
193
+ }
183
194
  /** A single traversal result item */
184
195
  interface TraversalResultItem {
185
196
  /** Target node ID reached */
@@ -321,7 +332,11 @@ interface AggregationQueryResponse {
321
332
  /** Execution statistics */
322
333
  stats: QueryStats;
323
334
  }
324
- /** Unified response type for `query()` (rows or aggregation). */
335
+ /** Unified response type for `query()` (rows, aggregation, or DDL).
336
+ *
337
+ * DDL statements (CREATE, DROP) and mutations (INSERT EDGE, DELETE) return
338
+ * a standard `QueryResponse` with an empty `results` array.
339
+ */
325
340
  type QueryApiResponse = QueryResponse | AggregationQueryResponse;
326
341
  /** Query explain request/response metadata */
327
342
  interface ExplainPlanStep {
@@ -469,6 +484,8 @@ interface IVelesDBBackend {
469
484
  getEdges(collection: string, options?: GetEdgesOptions): Promise<GraphEdge[]>;
470
485
  /** Traverse the graph using BFS or DFS from a source node */
471
486
  traverseGraph(collection: string, request: TraverseRequest): Promise<TraverseResponse>;
487
+ /** Multi-source parallel BFS traversal with deduplication */
488
+ traverseParallel(collection: string, request: TraverseParallelRequest): Promise<TraverseResponse>;
472
489
  /** Get the in-degree and out-degree of a node */
473
490
  getNodeDegree(collection: string, nodeId: number): Promise<DegreeResponse>;
474
491
  /** Train Product Quantization on a collection */
@@ -721,7 +738,11 @@ declare class VelesDB {
721
738
  *
722
739
  * @param collection - Collection name
723
740
  * @param queryString - VelesQL query string
724
- * @param params - Query parameters (vectors, scalars)
741
+ * @param params - Query parameters (vectors, scalars).
742
+ * For cross-collection MATCH queries, pass `_collection` to specify the
743
+ * primary collection (the one with graph edges). Nodes annotated with
744
+ * `@collection` in the MATCH pattern will have their payloads enriched
745
+ * from the named collection after traversal.
725
746
  * @param options - Query options (timeout, streaming)
726
747
  * @returns Query response with results and execution stats
727
748
  *
@@ -735,6 +756,16 @@ declare class VelesDB {
735
756
  * console.log(`ID ${r.id}, title: ${r.title}`);
736
757
  * }
737
758
  * ```
759
+ *
760
+ * @example Cross-collection MATCH
761
+ * ```typescript
762
+ * // Enrich Product nodes with Inventory data from the 'inventory' collection
763
+ * const response = await db.query('catalog_graph', `
764
+ * MATCH (p:Product)-[:STORED_IN]->(inv:Inventory@inventory)
765
+ * RETURN p.name, inv.price, inv.stock
766
+ * LIMIT 20
767
+ * `);
768
+ * ```
738
769
  */
739
770
  query(collection: string, queryString: string, params?: Record<string, unknown>, options?: QueryOptions): Promise<QueryApiResponse>;
740
771
  /**
@@ -910,6 +941,26 @@ declare class VelesDB {
910
941
  * ```
911
942
  */
912
943
  traverseGraph(collection: string, request: TraverseRequest): Promise<TraverseResponse>;
944
+ /**
945
+ * Multi-source parallel BFS traversal with deduplication.
946
+ *
947
+ * Starts BFS from multiple source nodes simultaneously and deduplicates
948
+ * results by path signature.
949
+ *
950
+ * @param collection - Collection name
951
+ * @param request - Parallel traverse request with sources array
952
+ * @returns Traverse response with results, stats, and pagination
953
+ *
954
+ * @example
955
+ * ```typescript
956
+ * const result = await db.traverseParallel('social', {
957
+ * sources: [100, 200, 300],
958
+ * maxDepth: 3,
959
+ * limit: 50,
960
+ * });
961
+ * ```
962
+ */
963
+ traverseParallel(collection: string, request: TraverseParallelRequest): Promise<TraverseResponse>;
913
964
  /**
914
965
  * Get the in-degree and out-degree of a node
915
966
  *
@@ -1034,6 +1085,7 @@ declare class WasmBackend implements IVelesDBBackend {
1034
1085
  addEdge(_collection: string, _edge: AddEdgeRequest): Promise<void>;
1035
1086
  getEdges(_collection: string, _options?: GetEdgesOptions): Promise<GraphEdge[]>;
1036
1087
  traverseGraph(_collection: string, _request: TraverseRequest): Promise<TraverseResponse>;
1088
+ traverseParallel(_collection: string, _request: TraverseParallelRequest): Promise<TraverseResponse>;
1037
1089
  getNodeDegree(_collection: string, _nodeId: number): Promise<DegreeResponse>;
1038
1090
  trainPq(_collection: string, _options?: PqTrainOptions): Promise<string>;
1039
1091
  streamInsert(_collection: string, _docs: VectorDocument[]): Promise<void>;
@@ -1120,6 +1172,7 @@ declare class RestBackend implements IVelesDBBackend {
1120
1172
  addEdge(collection: string, edge: AddEdgeRequest): Promise<void>;
1121
1173
  getEdges(collection: string, options?: GetEdgesOptions): Promise<GraphEdge[]>;
1122
1174
  traverseGraph(collection: string, req: TraverseRequest): Promise<TraverseResponse>;
1175
+ traverseParallel(collection: string, req: TraverseParallelRequest): Promise<TraverseResponse>;
1123
1176
  getNodeDegree(collection: string, nodeId: number): Promise<DegreeResponse>;
1124
1177
  createGraphCollection(name: string, config?: GraphCollectionConfig): Promise<void>;
1125
1178
  createIndex(collection: string, options: CreateIndexOptions): Promise<void>;
@@ -1328,4 +1381,4 @@ declare class VelesQLBuilder {
1328
1381
  */
1329
1382
  declare function velesql(): VelesQLBuilder;
1330
1383
 
1331
- export { type AddEdgeRequest, AgentMemoryClient, type AgentMemoryConfig, type AggregationQueryResponse, type BackendType, BackpressureError, type Collection, type CollectionConfig, type CollectionConfigResponse, type CollectionSanityChecks, type CollectionSanityDiagnostics, type CollectionSanityResponse, type CollectionStatsResponse, type CollectionType, ConnectionError, type CreateIndexOptions, type DegreeResponse, type DistanceMetric, type EdgesResponse, type EpisodicEvent, type ExplainCost, type ExplainFeatures, type ExplainPlanStep, type ExplainResponse, type FusionOptions, type FusionStrategy, type GetEdgesOptions, type GraphCollectionConfig, type GraphEdge, type GraphSchemaMode, type HnswParams, type IVelesDBBackend, type IndexInfo, type IndexType, type MultiQuerySearchOptions, type NearVectorOptions, NotFoundError, type PqTrainOptions, type ProceduralPattern, type QueryApiResponse, type QueryOptions, type QueryResponse, type QueryResult, type QueryStats, type RelDirection, type RelOptions, RestBackend, type RestPointId, type SearchOptions, type SearchQuality, type SearchResult, type SemanticEntry, type SparseVector, type StorageMode, type TraversalResultItem, type TraversalStats, type TraverseRequest, type TraverseResponse, ValidationError, type VectorDocument, VelesDB, type VelesDBConfig, VelesDBError, VelesQLBuilder, WasmBackend, velesql };
1384
+ export { type AddEdgeRequest, AgentMemoryClient, type AgentMemoryConfig, type AggregationQueryResponse, type BackendType, BackpressureError, type Collection, type CollectionConfig, type CollectionConfigResponse, type CollectionSanityChecks, type CollectionSanityDiagnostics, type CollectionSanityResponse, type CollectionStatsResponse, type CollectionType, ConnectionError, type CreateIndexOptions, type DegreeResponse, type DistanceMetric, type EdgesResponse, type EpisodicEvent, type ExplainCost, type ExplainFeatures, type ExplainPlanStep, type ExplainResponse, type FusionOptions, type FusionStrategy, type GetEdgesOptions, type GraphCollectionConfig, type GraphEdge, type GraphSchemaMode, type HnswParams, type IVelesDBBackend, type IndexInfo, type IndexType, type MultiQuerySearchOptions, type NearVectorOptions, NotFoundError, type PqTrainOptions, type ProceduralPattern, type QueryApiResponse, type QueryOptions, type QueryResponse, type QueryResult, type QueryStats, type RelDirection, type RelOptions, RestBackend, type RestPointId, type SearchOptions, type SearchQuality, type SearchResult, type SemanticEntry, type SparseVector, type StorageMode, type TraversalResultItem, type TraversalStats, type TraverseParallelRequest, type TraverseRequest, type TraverseResponse, ValidationError, type VectorDocument, VelesDB, type VelesDBConfig, VelesDBError, VelesQLBuilder, WasmBackend, velesql };
package/dist/index.d.ts CHANGED
@@ -180,6 +180,17 @@ interface TraverseRequest {
180
180
  /** Filter by relationship types (empty = all types) */
181
181
  relTypes?: string[];
182
182
  }
183
+ /** Request for multi-source parallel BFS traversal */
184
+ interface TraverseParallelRequest {
185
+ /** Source node IDs to start traversal from */
186
+ sources: number[];
187
+ /** Maximum traversal depth */
188
+ maxDepth?: number;
189
+ /** Maximum number of results to return */
190
+ limit?: number;
191
+ /** Filter by relationship types (empty = all types) */
192
+ relTypes?: string[];
193
+ }
183
194
  /** A single traversal result item */
184
195
  interface TraversalResultItem {
185
196
  /** Target node ID reached */
@@ -321,7 +332,11 @@ interface AggregationQueryResponse {
321
332
  /** Execution statistics */
322
333
  stats: QueryStats;
323
334
  }
324
- /** Unified response type for `query()` (rows or aggregation). */
335
+ /** Unified response type for `query()` (rows, aggregation, or DDL).
336
+ *
337
+ * DDL statements (CREATE, DROP) and mutations (INSERT EDGE, DELETE) return
338
+ * a standard `QueryResponse` with an empty `results` array.
339
+ */
325
340
  type QueryApiResponse = QueryResponse | AggregationQueryResponse;
326
341
  /** Query explain request/response metadata */
327
342
  interface ExplainPlanStep {
@@ -469,6 +484,8 @@ interface IVelesDBBackend {
469
484
  getEdges(collection: string, options?: GetEdgesOptions): Promise<GraphEdge[]>;
470
485
  /** Traverse the graph using BFS or DFS from a source node */
471
486
  traverseGraph(collection: string, request: TraverseRequest): Promise<TraverseResponse>;
487
+ /** Multi-source parallel BFS traversal with deduplication */
488
+ traverseParallel(collection: string, request: TraverseParallelRequest): Promise<TraverseResponse>;
472
489
  /** Get the in-degree and out-degree of a node */
473
490
  getNodeDegree(collection: string, nodeId: number): Promise<DegreeResponse>;
474
491
  /** Train Product Quantization on a collection */
@@ -721,7 +738,11 @@ declare class VelesDB {
721
738
  *
722
739
  * @param collection - Collection name
723
740
  * @param queryString - VelesQL query string
724
- * @param params - Query parameters (vectors, scalars)
741
+ * @param params - Query parameters (vectors, scalars).
742
+ * For cross-collection MATCH queries, pass `_collection` to specify the
743
+ * primary collection (the one with graph edges). Nodes annotated with
744
+ * `@collection` in the MATCH pattern will have their payloads enriched
745
+ * from the named collection after traversal.
725
746
  * @param options - Query options (timeout, streaming)
726
747
  * @returns Query response with results and execution stats
727
748
  *
@@ -735,6 +756,16 @@ declare class VelesDB {
735
756
  * console.log(`ID ${r.id}, title: ${r.title}`);
736
757
  * }
737
758
  * ```
759
+ *
760
+ * @example Cross-collection MATCH
761
+ * ```typescript
762
+ * // Enrich Product nodes with Inventory data from the 'inventory' collection
763
+ * const response = await db.query('catalog_graph', `
764
+ * MATCH (p:Product)-[:STORED_IN]->(inv:Inventory@inventory)
765
+ * RETURN p.name, inv.price, inv.stock
766
+ * LIMIT 20
767
+ * `);
768
+ * ```
738
769
  */
739
770
  query(collection: string, queryString: string, params?: Record<string, unknown>, options?: QueryOptions): Promise<QueryApiResponse>;
740
771
  /**
@@ -910,6 +941,26 @@ declare class VelesDB {
910
941
  * ```
911
942
  */
912
943
  traverseGraph(collection: string, request: TraverseRequest): Promise<TraverseResponse>;
944
+ /**
945
+ * Multi-source parallel BFS traversal with deduplication.
946
+ *
947
+ * Starts BFS from multiple source nodes simultaneously and deduplicates
948
+ * results by path signature.
949
+ *
950
+ * @param collection - Collection name
951
+ * @param request - Parallel traverse request with sources array
952
+ * @returns Traverse response with results, stats, and pagination
953
+ *
954
+ * @example
955
+ * ```typescript
956
+ * const result = await db.traverseParallel('social', {
957
+ * sources: [100, 200, 300],
958
+ * maxDepth: 3,
959
+ * limit: 50,
960
+ * });
961
+ * ```
962
+ */
963
+ traverseParallel(collection: string, request: TraverseParallelRequest): Promise<TraverseResponse>;
913
964
  /**
914
965
  * Get the in-degree and out-degree of a node
915
966
  *
@@ -1034,6 +1085,7 @@ declare class WasmBackend implements IVelesDBBackend {
1034
1085
  addEdge(_collection: string, _edge: AddEdgeRequest): Promise<void>;
1035
1086
  getEdges(_collection: string, _options?: GetEdgesOptions): Promise<GraphEdge[]>;
1036
1087
  traverseGraph(_collection: string, _request: TraverseRequest): Promise<TraverseResponse>;
1088
+ traverseParallel(_collection: string, _request: TraverseParallelRequest): Promise<TraverseResponse>;
1037
1089
  getNodeDegree(_collection: string, _nodeId: number): Promise<DegreeResponse>;
1038
1090
  trainPq(_collection: string, _options?: PqTrainOptions): Promise<string>;
1039
1091
  streamInsert(_collection: string, _docs: VectorDocument[]): Promise<void>;
@@ -1120,6 +1172,7 @@ declare class RestBackend implements IVelesDBBackend {
1120
1172
  addEdge(collection: string, edge: AddEdgeRequest): Promise<void>;
1121
1173
  getEdges(collection: string, options?: GetEdgesOptions): Promise<GraphEdge[]>;
1122
1174
  traverseGraph(collection: string, req: TraverseRequest): Promise<TraverseResponse>;
1175
+ traverseParallel(collection: string, req: TraverseParallelRequest): Promise<TraverseResponse>;
1123
1176
  getNodeDegree(collection: string, nodeId: number): Promise<DegreeResponse>;
1124
1177
  createGraphCollection(name: string, config?: GraphCollectionConfig): Promise<void>;
1125
1178
  createIndex(collection: string, options: CreateIndexOptions): Promise<void>;
@@ -1328,4 +1381,4 @@ declare class VelesQLBuilder {
1328
1381
  */
1329
1382
  declare function velesql(): VelesQLBuilder;
1330
1383
 
1331
- export { type AddEdgeRequest, AgentMemoryClient, type AgentMemoryConfig, type AggregationQueryResponse, type BackendType, BackpressureError, type Collection, type CollectionConfig, type CollectionConfigResponse, type CollectionSanityChecks, type CollectionSanityDiagnostics, type CollectionSanityResponse, type CollectionStatsResponse, type CollectionType, ConnectionError, type CreateIndexOptions, type DegreeResponse, type DistanceMetric, type EdgesResponse, type EpisodicEvent, type ExplainCost, type ExplainFeatures, type ExplainPlanStep, type ExplainResponse, type FusionOptions, type FusionStrategy, type GetEdgesOptions, type GraphCollectionConfig, type GraphEdge, type GraphSchemaMode, type HnswParams, type IVelesDBBackend, type IndexInfo, type IndexType, type MultiQuerySearchOptions, type NearVectorOptions, NotFoundError, type PqTrainOptions, type ProceduralPattern, type QueryApiResponse, type QueryOptions, type QueryResponse, type QueryResult, type QueryStats, type RelDirection, type RelOptions, RestBackend, type RestPointId, type SearchOptions, type SearchQuality, type SearchResult, type SemanticEntry, type SparseVector, type StorageMode, type TraversalResultItem, type TraversalStats, type TraverseRequest, type TraverseResponse, ValidationError, type VectorDocument, VelesDB, type VelesDBConfig, VelesDBError, VelesQLBuilder, WasmBackend, velesql };
1384
+ export { type AddEdgeRequest, AgentMemoryClient, type AgentMemoryConfig, type AggregationQueryResponse, type BackendType, BackpressureError, type Collection, type CollectionConfig, type CollectionConfigResponse, type CollectionSanityChecks, type CollectionSanityDiagnostics, type CollectionSanityResponse, type CollectionStatsResponse, type CollectionType, ConnectionError, type CreateIndexOptions, type DegreeResponse, type DistanceMetric, type EdgesResponse, type EpisodicEvent, type ExplainCost, type ExplainFeatures, type ExplainPlanStep, type ExplainResponse, type FusionOptions, type FusionStrategy, type GetEdgesOptions, type GraphCollectionConfig, type GraphEdge, type GraphSchemaMode, type HnswParams, type IVelesDBBackend, type IndexInfo, type IndexType, type MultiQuerySearchOptions, type NearVectorOptions, NotFoundError, type PqTrainOptions, type ProceduralPattern, type QueryApiResponse, type QueryOptions, type QueryResponse, type QueryResult, type QueryStats, type RelDirection, type RelOptions, RestBackend, type RestPointId, type SearchOptions, type SearchQuality, type SearchResult, type SemanticEntry, type SparseVector, type StorageMode, type TraversalResultItem, type TraversalStats, type TraverseParallelRequest, type TraverseRequest, type TraverseResponse, ValidationError, type VectorDocument, VelesDB, type VelesDBConfig, VelesDBError, VelesQLBuilder, WasmBackend, velesql };
package/dist/index.js CHANGED
@@ -582,6 +582,10 @@ var WasmBackend = class {
582
582
  this.ensureInitialized();
583
583
  wasmNotSupported("Graph traversal");
584
584
  }
585
+ async traverseParallel(_collection, _request) {
586
+ this.ensureInitialized();
587
+ wasmNotSupported("Graph parallel traversal");
588
+ }
585
589
  async getNodeDegree(_collection, _nodeId) {
586
590
  this.ensureInitialized();
587
591
  wasmNotSupported("Graph degree query");
@@ -902,6 +906,33 @@ async function createGraphCollection(transport, name, config) {
902
906
  });
903
907
  throwOnError(response);
904
908
  }
909
+ async function traverseParallel(transport, collection, request) {
910
+ const response = await transport.requestJson(
911
+ "POST",
912
+ `${collectionPath(collection)}/graph/traverse/parallel`,
913
+ {
914
+ sources: request.sources,
915
+ max_depth: request.maxDepth ?? 3,
916
+ limit: request.limit ?? 100,
917
+ rel_types: request.relTypes ?? []
918
+ }
919
+ );
920
+ throwOnError(response, `Collection '${collection}'`);
921
+ const data = response.data;
922
+ return {
923
+ results: data.results.map((r) => ({
924
+ targetId: r.target_id,
925
+ depth: r.depth,
926
+ path: r.path
927
+ })),
928
+ nextCursor: data.next_cursor ?? void 0,
929
+ hasMore: data.has_more,
930
+ stats: {
931
+ visited: data.stats.visited,
932
+ depthReached: data.stats.depth_reached
933
+ }
934
+ };
935
+ }
905
936
 
906
937
  // src/backends/query-backend.ts
907
938
  function isLikelyAggregationQuery(queryString) {
@@ -909,8 +940,11 @@ function isLikelyAggregationQuery(queryString) {
909
940
  queryString
910
941
  );
911
942
  }
943
+ function isLikelyDdlOrMutationQuery(queryString) {
944
+ return /^\s*(CREATE|DROP)\s+(COLLECTION|GRAPH|METADATA|INDEX)\b/i.test(queryString) || /^\s*DELETE\s+(FROM|EDGE)\b/i.test(queryString) || /^\s*INSERT\s+(INTO|EDGE|NODE)\b/i.test(queryString) || /^\s*UPSERT\s+INTO\b/i.test(queryString) || /^\s*(SHOW|DESCRIBE|EXPLAIN)\b/i.test(queryString) || /^\s*(FLUSH|ANALYZE|TRUNCATE)\b/i.test(queryString) || /^\s*ALTER\s+COLLECTION\b/i.test(queryString) || /^\s*SELECT\s+EDGES\b/i.test(queryString);
945
+ }
912
946
  async function query(transport, collection, queryString, params, options) {
913
- const endpoint = isLikelyAggregationQuery(queryString) ? "/aggregate" : "/query";
947
+ const endpoint = isLikelyDdlOrMutationQuery(queryString) ? "/query" : isLikelyAggregationQuery(queryString) ? "/aggregate" : "/query";
914
948
  const response = await transport.requestJson(
915
949
  "POST",
916
950
  endpoint,
@@ -1543,6 +1577,10 @@ var RestBackend = class {
1543
1577
  this.ensureInitialized();
1544
1578
  return traverseGraph(this.asCrudTransport(), collection, req);
1545
1579
  }
1580
+ async traverseParallel(collection, req) {
1581
+ this.ensureInitialized();
1582
+ return traverseParallel(this.asCrudTransport(), collection, req);
1583
+ }
1546
1584
  async getNodeDegree(collection, nodeId) {
1547
1585
  this.ensureInitialized();
1548
1586
  return getNodeDegree(this.asCrudTransport(), collection, nodeId);
@@ -1919,7 +1957,11 @@ var VelesDB = class {
1919
1957
  *
1920
1958
  * @param collection - Collection name
1921
1959
  * @param queryString - VelesQL query string
1922
- * @param params - Query parameters (vectors, scalars)
1960
+ * @param params - Query parameters (vectors, scalars).
1961
+ * For cross-collection MATCH queries, pass `_collection` to specify the
1962
+ * primary collection (the one with graph edges). Nodes annotated with
1963
+ * `@collection` in the MATCH pattern will have their payloads enriched
1964
+ * from the named collection after traversal.
1923
1965
  * @param options - Query options (timeout, streaming)
1924
1966
  * @returns Query response with results and execution stats
1925
1967
  *
@@ -1933,6 +1975,16 @@ var VelesDB = class {
1933
1975
  * console.log(`ID ${r.id}, title: ${r.title}`);
1934
1976
  * }
1935
1977
  * ```
1978
+ *
1979
+ * @example Cross-collection MATCH
1980
+ * ```typescript
1981
+ * // Enrich Product nodes with Inventory data from the 'inventory' collection
1982
+ * const response = await db.query('catalog_graph', `
1983
+ * MATCH (p:Product)-[:STORED_IN]->(inv:Inventory@inventory)
1984
+ * RETURN p.name, inv.price, inv.stock
1985
+ * LIMIT 20
1986
+ * `);
1987
+ * ```
1936
1988
  */
1937
1989
  async query(collection, queryString, params, options) {
1938
1990
  this.ensureInitialized();
@@ -2195,6 +2247,32 @@ var VelesDB = class {
2195
2247
  }
2196
2248
  return this.backend.traverseGraph(collection, request);
2197
2249
  }
2250
+ /**
2251
+ * Multi-source parallel BFS traversal with deduplication.
2252
+ *
2253
+ * Starts BFS from multiple source nodes simultaneously and deduplicates
2254
+ * results by path signature.
2255
+ *
2256
+ * @param collection - Collection name
2257
+ * @param request - Parallel traverse request with sources array
2258
+ * @returns Traverse response with results, stats, and pagination
2259
+ *
2260
+ * @example
2261
+ * ```typescript
2262
+ * const result = await db.traverseParallel('social', {
2263
+ * sources: [100, 200, 300],
2264
+ * maxDepth: 3,
2265
+ * limit: 50,
2266
+ * });
2267
+ * ```
2268
+ */
2269
+ async traverseParallel(collection, request) {
2270
+ this.ensureInitialized();
2271
+ if (!Array.isArray(request.sources) || request.sources.length === 0) {
2272
+ throw new ValidationError("At least one source node ID is required");
2273
+ }
2274
+ return this.backend.traverseParallel(collection, request);
2275
+ }
2198
2276
  /**
2199
2277
  * Get the in-degree and out-degree of a node
2200
2278
  *
package/dist/index.mjs CHANGED
@@ -536,6 +536,10 @@ var WasmBackend = class {
536
536
  this.ensureInitialized();
537
537
  wasmNotSupported("Graph traversal");
538
538
  }
539
+ async traverseParallel(_collection, _request) {
540
+ this.ensureInitialized();
541
+ wasmNotSupported("Graph parallel traversal");
542
+ }
539
543
  async getNodeDegree(_collection, _nodeId) {
540
544
  this.ensureInitialized();
541
545
  wasmNotSupported("Graph degree query");
@@ -856,6 +860,33 @@ async function createGraphCollection(transport, name, config) {
856
860
  });
857
861
  throwOnError(response);
858
862
  }
863
+ async function traverseParallel(transport, collection, request) {
864
+ const response = await transport.requestJson(
865
+ "POST",
866
+ `${collectionPath(collection)}/graph/traverse/parallel`,
867
+ {
868
+ sources: request.sources,
869
+ max_depth: request.maxDepth ?? 3,
870
+ limit: request.limit ?? 100,
871
+ rel_types: request.relTypes ?? []
872
+ }
873
+ );
874
+ throwOnError(response, `Collection '${collection}'`);
875
+ const data = response.data;
876
+ return {
877
+ results: data.results.map((r) => ({
878
+ targetId: r.target_id,
879
+ depth: r.depth,
880
+ path: r.path
881
+ })),
882
+ nextCursor: data.next_cursor ?? void 0,
883
+ hasMore: data.has_more,
884
+ stats: {
885
+ visited: data.stats.visited,
886
+ depthReached: data.stats.depth_reached
887
+ }
888
+ };
889
+ }
859
890
 
860
891
  // src/backends/query-backend.ts
861
892
  function isLikelyAggregationQuery(queryString) {
@@ -863,8 +894,11 @@ function isLikelyAggregationQuery(queryString) {
863
894
  queryString
864
895
  );
865
896
  }
897
+ function isLikelyDdlOrMutationQuery(queryString) {
898
+ return /^\s*(CREATE|DROP)\s+(COLLECTION|GRAPH|METADATA|INDEX)\b/i.test(queryString) || /^\s*DELETE\s+(FROM|EDGE)\b/i.test(queryString) || /^\s*INSERT\s+(INTO|EDGE|NODE)\b/i.test(queryString) || /^\s*UPSERT\s+INTO\b/i.test(queryString) || /^\s*(SHOW|DESCRIBE|EXPLAIN)\b/i.test(queryString) || /^\s*(FLUSH|ANALYZE|TRUNCATE)\b/i.test(queryString) || /^\s*ALTER\s+COLLECTION\b/i.test(queryString) || /^\s*SELECT\s+EDGES\b/i.test(queryString);
899
+ }
866
900
  async function query(transport, collection, queryString, params, options) {
867
- const endpoint = isLikelyAggregationQuery(queryString) ? "/aggregate" : "/query";
901
+ const endpoint = isLikelyDdlOrMutationQuery(queryString) ? "/query" : isLikelyAggregationQuery(queryString) ? "/aggregate" : "/query";
868
902
  const response = await transport.requestJson(
869
903
  "POST",
870
904
  endpoint,
@@ -1497,6 +1531,10 @@ var RestBackend = class {
1497
1531
  this.ensureInitialized();
1498
1532
  return traverseGraph(this.asCrudTransport(), collection, req);
1499
1533
  }
1534
+ async traverseParallel(collection, req) {
1535
+ this.ensureInitialized();
1536
+ return traverseParallel(this.asCrudTransport(), collection, req);
1537
+ }
1500
1538
  async getNodeDegree(collection, nodeId) {
1501
1539
  this.ensureInitialized();
1502
1540
  return getNodeDegree(this.asCrudTransport(), collection, nodeId);
@@ -1873,7 +1911,11 @@ var VelesDB = class {
1873
1911
  *
1874
1912
  * @param collection - Collection name
1875
1913
  * @param queryString - VelesQL query string
1876
- * @param params - Query parameters (vectors, scalars)
1914
+ * @param params - Query parameters (vectors, scalars).
1915
+ * For cross-collection MATCH queries, pass `_collection` to specify the
1916
+ * primary collection (the one with graph edges). Nodes annotated with
1917
+ * `@collection` in the MATCH pattern will have their payloads enriched
1918
+ * from the named collection after traversal.
1877
1919
  * @param options - Query options (timeout, streaming)
1878
1920
  * @returns Query response with results and execution stats
1879
1921
  *
@@ -1887,6 +1929,16 @@ var VelesDB = class {
1887
1929
  * console.log(`ID ${r.id}, title: ${r.title}`);
1888
1930
  * }
1889
1931
  * ```
1932
+ *
1933
+ * @example Cross-collection MATCH
1934
+ * ```typescript
1935
+ * // Enrich Product nodes with Inventory data from the 'inventory' collection
1936
+ * const response = await db.query('catalog_graph', `
1937
+ * MATCH (p:Product)-[:STORED_IN]->(inv:Inventory@inventory)
1938
+ * RETURN p.name, inv.price, inv.stock
1939
+ * LIMIT 20
1940
+ * `);
1941
+ * ```
1890
1942
  */
1891
1943
  async query(collection, queryString, params, options) {
1892
1944
  this.ensureInitialized();
@@ -2149,6 +2201,32 @@ var VelesDB = class {
2149
2201
  }
2150
2202
  return this.backend.traverseGraph(collection, request);
2151
2203
  }
2204
+ /**
2205
+ * Multi-source parallel BFS traversal with deduplication.
2206
+ *
2207
+ * Starts BFS from multiple source nodes simultaneously and deduplicates
2208
+ * results by path signature.
2209
+ *
2210
+ * @param collection - Collection name
2211
+ * @param request - Parallel traverse request with sources array
2212
+ * @returns Traverse response with results, stats, and pagination
2213
+ *
2214
+ * @example
2215
+ * ```typescript
2216
+ * const result = await db.traverseParallel('social', {
2217
+ * sources: [100, 200, 300],
2218
+ * maxDepth: 3,
2219
+ * limit: 50,
2220
+ * });
2221
+ * ```
2222
+ */
2223
+ async traverseParallel(collection, request) {
2224
+ this.ensureInitialized();
2225
+ if (!Array.isArray(request.sources) || request.sources.length === 0) {
2226
+ throw new ValidationError("At least one source node ID is required");
2227
+ }
2228
+ return this.backend.traverseParallel(collection, request);
2229
+ }
2152
2230
  /**
2153
2231
  * Get the in-degree and out-degree of a node
2154
2232
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wiscale/velesdb-sdk",
3
- "version": "1.10.0",
3
+ "version": "1.12.0",
4
4
  "description": "VelesDB TypeScript SDK: The Local Vector Database for AI & RAG. Microsecond semantic search in Browser & Node.js.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",