@wiscale/velesdb-sdk 1.12.0 → 1.13.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/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- // src/types.ts
1
+ // src/types/errors.ts
2
2
  var VelesDBError = class extends Error {
3
3
  constructor(message, code, cause) {
4
4
  super(message);
@@ -32,6 +32,610 @@ var BackpressureError = class extends VelesDBError {
32
32
  }
33
33
  };
34
34
 
35
+ // src/capabilities.ts
36
+ var REST_CAPABILITIES = Object.freeze({
37
+ vectorSearch: true,
38
+ textSearch: true,
39
+ hybridSearch: true,
40
+ multiQuerySearch: true,
41
+ sparseSearch: true,
42
+ scroll: true,
43
+ graphTraversal: true,
44
+ secondaryIndexes: true,
45
+ agentMemory: true,
46
+ streamInsert: true,
47
+ pqTraining: true,
48
+ velesqlQuery: true,
49
+ collectionIntrospection: true
50
+ });
51
+ var WASM_CAPABILITIES = Object.freeze({
52
+ vectorSearch: true,
53
+ textSearch: true,
54
+ hybridSearch: true,
55
+ multiQuerySearch: true,
56
+ sparseSearch: false,
57
+ scroll: false,
58
+ graphTraversal: false,
59
+ secondaryIndexes: false,
60
+ agentMemory: false,
61
+ streamInsert: false,
62
+ pqTraining: false,
63
+ velesqlQuery: true,
64
+ collectionIntrospection: false
65
+ });
66
+
67
+ // src/backends/wasm-helpers.ts
68
+ function normalizeIdString(id) {
69
+ const trimmed = id.trim();
70
+ return /^\d+$/.test(trimmed) ? trimmed : null;
71
+ }
72
+ function canonicalPayloadKeyFromResultId(id) {
73
+ if (typeof id === "bigint") {
74
+ return id.toString();
75
+ }
76
+ if (typeof id === "number") {
77
+ return String(Math.trunc(id));
78
+ }
79
+ const normalized = normalizeIdString(id);
80
+ if (normalized !== null) {
81
+ return normalized.replace(/^0+(?=\d)/, "");
82
+ }
83
+ return String(toNumericId(id));
84
+ }
85
+ function canonicalPayloadKey(id) {
86
+ if (typeof id === "number") {
87
+ return String(Math.trunc(id));
88
+ }
89
+ const normalized = normalizeIdString(id);
90
+ if (normalized !== null) {
91
+ return normalized.replace(/^0+(?=\d)/, "");
92
+ }
93
+ return String(toNumericId(id));
94
+ }
95
+ function sparseVectorToArrays(sv) {
96
+ const indices = [];
97
+ const values = [];
98
+ for (const [k, v] of Object.entries(sv)) {
99
+ indices.push(Number(k));
100
+ values.push(v);
101
+ }
102
+ return { indices, values };
103
+ }
104
+ function toNumericId(id) {
105
+ if (typeof id === "number") {
106
+ return id;
107
+ }
108
+ const normalized = normalizeIdString(id);
109
+ if (normalized !== null) {
110
+ const parsed = Number(normalized);
111
+ if (Number.isSafeInteger(parsed)) {
112
+ return parsed;
113
+ }
114
+ }
115
+ let hash = 0;
116
+ for (let i = 0; i < id.length; i++) {
117
+ const char = id.charCodeAt(i);
118
+ hash = (hash << 5) - hash + char;
119
+ hash = hash & hash;
120
+ }
121
+ return Math.abs(hash);
122
+ }
123
+ function buildWasmContext(wasmModule, collections) {
124
+ return {
125
+ wasmModule,
126
+ getCollection: (name) => collections.get(name),
127
+ canonicalPayloadKeyFromResultId: (id) => canonicalPayloadKeyFromResultId(id),
128
+ canonicalPayloadKey: (id) => canonicalPayloadKey(id),
129
+ sparseVectorToArrays: (sv) => sparseVectorToArrays(sv),
130
+ toNumericId: (id) => toNumericId(id)
131
+ };
132
+ }
133
+ function buildCollectionInfo(name, data) {
134
+ return {
135
+ name,
136
+ dimension: data.config.dimension ?? 0,
137
+ metric: data.config.metric ?? "cosine",
138
+ count: data.store.len,
139
+ createdAt: data.createdAt
140
+ };
141
+ }
142
+
143
+ // src/backends/wasm-search.ts
144
+ function searchSparseOnly(ctx, collection, indices, values, k) {
145
+ const sparseResults = collection.store.sparse_search(
146
+ new Uint32Array(indices),
147
+ new Float32Array(values),
148
+ k
149
+ );
150
+ return sparseResults.map((r) => ({
151
+ id: String(r.doc_id),
152
+ score: r.score,
153
+ payload: collection.payloads.get(ctx.canonicalPayloadKeyFromResultId(r.doc_id))
154
+ }));
155
+ }
156
+ function searchHybridFusion(ctx, collection, queryVector, indices, values, k) {
157
+ const denseResults = collection.store.search(queryVector, k);
158
+ const sparseResults = collection.store.sparse_search(
159
+ new Uint32Array(indices),
160
+ new Float32Array(values),
161
+ k
162
+ );
163
+ const denseForFuse = denseResults.map(
164
+ ([id, score]) => [Number(id), score]
165
+ );
166
+ const sparseForFuse = sparseResults.map(
167
+ (r) => [Number(r.doc_id), r.score]
168
+ );
169
+ const fused = ctx.wasmModule.hybrid_search_fuse(
170
+ denseForFuse,
171
+ sparseForFuse,
172
+ 60,
173
+ k
174
+ );
175
+ return fused.slice(0, k).map((r) => ({
176
+ id: String(r.doc_id),
177
+ score: r.score,
178
+ payload: collection.payloads.get(ctx.canonicalPayloadKeyFromResultId(r.doc_id))
179
+ }));
180
+ }
181
+ function searchWithFilter(ctx, collection, queryVector, k, filter) {
182
+ const results = collection.store.search_with_filter(
183
+ queryVector,
184
+ k,
185
+ filter
186
+ );
187
+ return results.map((r) => ({
188
+ id: String(r.id),
189
+ score: r.score,
190
+ payload: r.payload || collection.payloads.get(ctx.canonicalPayloadKeyFromResultId(r.id))
191
+ }));
192
+ }
193
+ function searchDenseOnly(ctx, collection, queryVector, k) {
194
+ const rawResults = collection.store.search(queryVector, k);
195
+ return rawResults.map(([id, score]) => {
196
+ const result = { id: String(id), score };
197
+ const payload = collection.payloads.get(ctx.canonicalPayloadKeyFromResultId(id));
198
+ if (payload) {
199
+ result.payload = payload;
200
+ }
201
+ return result;
202
+ });
203
+ }
204
+ async function wasmSearch(ctx, collectionName, query3, options) {
205
+ const collection = ctx.getCollection(collectionName);
206
+ if (!collection) {
207
+ throw new NotFoundError(`Collection '${collectionName}'`);
208
+ }
209
+ const queryVector = query3 instanceof Float32Array ? query3 : new Float32Array(query3);
210
+ if (queryVector.length !== collection.config.dimension) {
211
+ throw new VelesDBError(
212
+ `Query dimension mismatch: expected ${collection.config.dimension}, got ${queryVector.length}`,
213
+ "DIMENSION_MISMATCH"
214
+ );
215
+ }
216
+ const k = options?.k ?? 10;
217
+ if (options?.sparseVector) {
218
+ const { indices, values } = ctx.sparseVectorToArrays(options.sparseVector);
219
+ const hasDense = queryVector.length > 0 && collection.config.dimension !== void 0 && collection.config.dimension > 0;
220
+ return hasDense ? searchHybridFusion(ctx, collection, queryVector, indices, values, k) : searchSparseOnly(ctx, collection, indices, values, k);
221
+ }
222
+ if (options?.filter) {
223
+ return searchWithFilter(ctx, collection, queryVector, k, options.filter);
224
+ }
225
+ return searchDenseOnly(ctx, collection, queryVector, k);
226
+ }
227
+ async function wasmSearchBatch(ctx, collectionName, searches) {
228
+ const results = [];
229
+ for (const s of searches) {
230
+ results.push(
231
+ await wasmSearch(ctx, collectionName, s.vector, {
232
+ k: s.k,
233
+ filter: s.filter,
234
+ quality: s.quality
235
+ })
236
+ );
237
+ }
238
+ return results;
239
+ }
240
+ function mapWasmResult(ctx, collection, r) {
241
+ if (Array.isArray(r)) {
242
+ const key2 = ctx.canonicalPayloadKeyFromResultId(r[0]);
243
+ return { id: String(r[0]), score: r[1], payload: collection.payloads.get(key2) };
244
+ }
245
+ const key = ctx.canonicalPayloadKeyFromResultId(r.id);
246
+ return { id: String(r.id), score: r.score, payload: r.payload ?? collection.payloads.get(key) };
247
+ }
248
+ async function wasmTextSearch(ctx, collectionName, query3, options) {
249
+ const collection = ctx.getCollection(collectionName);
250
+ if (!collection) {
251
+ throw new NotFoundError(`Collection '${collectionName}'`);
252
+ }
253
+ const k = options?.k ?? 10;
254
+ const raw = collection.store.text_search(query3, k, void 0);
255
+ return raw.map((r) => mapWasmResult(ctx, collection, r));
256
+ }
257
+ async function wasmHybridSearch(ctx, collectionName, vector, textQuery, options) {
258
+ const collection = ctx.getCollection(collectionName);
259
+ if (!collection) {
260
+ throw new NotFoundError(`Collection '${collectionName}'`);
261
+ }
262
+ const queryVector = vector instanceof Float32Array ? vector : new Float32Array(vector);
263
+ const k = options?.k ?? 10;
264
+ const vectorWeight = options?.vectorWeight ?? 0.5;
265
+ const raw = collection.store.hybrid_search(
266
+ queryVector,
267
+ textQuery,
268
+ k,
269
+ vectorWeight
270
+ );
271
+ return raw.map((r) => {
272
+ const key = ctx.canonicalPayloadKeyFromResultId(r.id);
273
+ return { id: String(r.id), score: r.score, payload: r.payload ?? collection.payloads.get(key) };
274
+ });
275
+ }
276
+ async function wasmMultiQuerySearch(ctx, collectionName, vectors, options) {
277
+ const collection = ctx.getCollection(collectionName);
278
+ if (!collection) {
279
+ throw new NotFoundError(`Collection '${collectionName}'`);
280
+ }
281
+ if (vectors.length === 0) {
282
+ return [];
283
+ }
284
+ const numVectors = vectors.length;
285
+ const dimension = collection.config.dimension ?? 0;
286
+ const flat = new Float32Array(numVectors * dimension);
287
+ vectors.forEach((vector, idx) => {
288
+ const src = vector instanceof Float32Array ? vector : new Float32Array(vector);
289
+ flat.set(src, idx * dimension);
290
+ });
291
+ const strategy = options?.fusion ?? "rrf";
292
+ const raw = collection.store.multi_query_search(
293
+ flat,
294
+ numVectors,
295
+ options?.k ?? 10,
296
+ strategy,
297
+ options?.fusionParams?.k ?? 60
298
+ );
299
+ return raw.map((r) => mapWasmResult(ctx, collection, r));
300
+ }
301
+ async function wasmQuery(ctx, collectionName, _queryString, params, _options) {
302
+ const collection = ctx.getCollection(collectionName);
303
+ if (!collection) {
304
+ throw new NotFoundError(`Collection '${collectionName}'`);
305
+ }
306
+ const paramsVector = params?.q;
307
+ if (!Array.isArray(paramsVector) && !(paramsVector instanceof Float32Array)) {
308
+ throw new VelesDBError(
309
+ "WASM query() expects params.q to contain the query embedding vector.",
310
+ "BAD_REQUEST"
311
+ );
312
+ }
313
+ const requestedK = params?.k;
314
+ const k = typeof requestedK === "number" && Number.isInteger(requestedK) && requestedK > 0 ? requestedK : 10;
315
+ const raw = collection.store.query(
316
+ paramsVector instanceof Float32Array ? paramsVector : new Float32Array(paramsVector),
317
+ k
318
+ );
319
+ return {
320
+ results: raw,
321
+ stats: {
322
+ executionTimeMs: 0,
323
+ strategy: "wasm-query",
324
+ scannedNodes: raw.length
325
+ }
326
+ };
327
+ }
328
+
329
+ // src/errors.ts
330
+ var VelesError = class extends VelesDBError {
331
+ constructor(message, code, cause) {
332
+ super(message, code, cause);
333
+ this.name = "VelesError";
334
+ }
335
+ };
336
+ var CollectionExistsError = class extends VelesError {
337
+ constructor(message) {
338
+ super(message, "VELES-001");
339
+ this.name = "CollectionExistsError";
340
+ }
341
+ };
342
+ var CollectionNotFoundError = class extends VelesError {
343
+ constructor(message) {
344
+ super(message, "VELES-002");
345
+ this.name = "CollectionNotFoundError";
346
+ }
347
+ };
348
+ var PointNotFoundError = class extends VelesError {
349
+ constructor(message) {
350
+ super(message, "VELES-003");
351
+ this.name = "PointNotFoundError";
352
+ }
353
+ };
354
+ var DimensionMismatchError = class extends VelesError {
355
+ constructor(message) {
356
+ super(message, "VELES-004");
357
+ this.name = "DimensionMismatchError";
358
+ }
359
+ };
360
+ var InvalidVectorError = class extends VelesError {
361
+ constructor(message) {
362
+ super(message, "VELES-005");
363
+ this.name = "InvalidVectorError";
364
+ }
365
+ };
366
+ var StorageError = class extends VelesError {
367
+ constructor(message) {
368
+ super(message, "VELES-006");
369
+ this.name = "StorageError";
370
+ }
371
+ };
372
+ var IndexError = class extends VelesError {
373
+ constructor(message) {
374
+ super(message, "VELES-007");
375
+ this.name = "IndexError";
376
+ }
377
+ };
378
+ var IndexCorruptedError = class extends VelesError {
379
+ constructor(message) {
380
+ super(message, "VELES-008");
381
+ this.name = "IndexCorruptedError";
382
+ }
383
+ };
384
+ var ConfigError = class extends VelesError {
385
+ constructor(message) {
386
+ super(message, "VELES-009");
387
+ this.name = "ConfigError";
388
+ }
389
+ };
390
+ var QueryError = class extends VelesError {
391
+ constructor(message) {
392
+ super(message, "VELES-010");
393
+ this.name = "QueryError";
394
+ }
395
+ };
396
+ var IoError = class extends VelesError {
397
+ constructor(message) {
398
+ super(message, "VELES-011");
399
+ this.name = "IoError";
400
+ }
401
+ };
402
+ var SerializationError = class extends VelesError {
403
+ constructor(message) {
404
+ super(message, "VELES-012");
405
+ this.name = "SerializationError";
406
+ }
407
+ };
408
+ var InternalError = class extends VelesError {
409
+ constructor(message) {
410
+ super(message, "VELES-013");
411
+ this.name = "InternalError";
412
+ }
413
+ };
414
+ var VectorNotAllowedError = class extends VelesError {
415
+ constructor(message) {
416
+ super(message, "VELES-014");
417
+ this.name = "VectorNotAllowedError";
418
+ }
419
+ };
420
+ var SearchNotSupportedError = class extends VelesError {
421
+ constructor(message) {
422
+ super(message, "VELES-015");
423
+ this.name = "SearchNotSupportedError";
424
+ }
425
+ };
426
+ var VectorRequiredError = class extends VelesError {
427
+ constructor(message) {
428
+ super(message, "VELES-016");
429
+ this.name = "VectorRequiredError";
430
+ }
431
+ };
432
+ var SchemaValidationError = class extends VelesError {
433
+ constructor(message) {
434
+ super(message, "VELES-017");
435
+ this.name = "SchemaValidationError";
436
+ }
437
+ };
438
+ var GraphNotSupportedError = class extends VelesError {
439
+ constructor(message) {
440
+ super(message, "VELES-018");
441
+ this.name = "GraphNotSupportedError";
442
+ }
443
+ };
444
+ var EdgeExistsError = class extends VelesError {
445
+ constructor(message) {
446
+ super(message, "VELES-019");
447
+ this.name = "EdgeExistsError";
448
+ }
449
+ };
450
+ var EdgeNotFoundError = class extends VelesError {
451
+ constructor(message) {
452
+ super(message, "VELES-020");
453
+ this.name = "EdgeNotFoundError";
454
+ }
455
+ };
456
+ var InvalidEdgeLabelError = class extends VelesError {
457
+ constructor(message) {
458
+ super(message, "VELES-021");
459
+ this.name = "InvalidEdgeLabelError";
460
+ }
461
+ };
462
+ var NodeNotFoundError = class extends VelesError {
463
+ constructor(message) {
464
+ super(message, "VELES-022");
465
+ this.name = "NodeNotFoundError";
466
+ }
467
+ };
468
+ var OverflowError = class extends VelesError {
469
+ constructor(message) {
470
+ super(message, "VELES-023");
471
+ this.name = "OverflowError";
472
+ }
473
+ };
474
+ var ColumnStoreError = class extends VelesError {
475
+ constructor(message) {
476
+ super(message, "VELES-024");
477
+ this.name = "ColumnStoreError";
478
+ }
479
+ };
480
+ var GpuError = class extends VelesError {
481
+ constructor(message) {
482
+ super(message, "VELES-025");
483
+ this.name = "GpuError";
484
+ }
485
+ };
486
+ var EpochMismatchError = class extends VelesError {
487
+ constructor(message) {
488
+ super(message, "VELES-026");
489
+ this.name = "EpochMismatchError";
490
+ }
491
+ };
492
+ var GuardRailError = class extends VelesError {
493
+ constructor(message) {
494
+ super(message, "VELES-027");
495
+ this.name = "GuardRailError";
496
+ }
497
+ };
498
+ var InvalidQuantizerConfigError = class extends VelesError {
499
+ constructor(message) {
500
+ super(message, "VELES-028");
501
+ this.name = "InvalidQuantizerConfigError";
502
+ }
503
+ };
504
+ var TrainingFailedError = class extends VelesError {
505
+ constructor(message) {
506
+ super(message, "VELES-029");
507
+ this.name = "TrainingFailedError";
508
+ }
509
+ };
510
+ var SparseIndexError = class extends VelesError {
511
+ constructor(message) {
512
+ super(message, "VELES-030");
513
+ this.name = "SparseIndexError";
514
+ }
515
+ };
516
+ var DatabaseLockedError = class extends VelesError {
517
+ constructor(message) {
518
+ super(message, "VELES-031");
519
+ this.name = "DatabaseLockedError";
520
+ }
521
+ };
522
+ var InvalidDimensionError = class extends VelesError {
523
+ constructor(message) {
524
+ super(message, "VELES-032");
525
+ this.name = "InvalidDimensionError";
526
+ }
527
+ };
528
+ var AllocationFailedError = class extends VelesError {
529
+ constructor(message) {
530
+ super(message, "VELES-033");
531
+ this.name = "AllocationFailedError";
532
+ }
533
+ };
534
+ var InvalidCollectionNameError = class extends VelesError {
535
+ constructor(message) {
536
+ super(message, "VELES-034");
537
+ this.name = "InvalidCollectionNameError";
538
+ }
539
+ };
540
+ var SnapshotBuildFailedError = class extends VelesError {
541
+ constructor(message) {
542
+ super(message, "VELES-035");
543
+ this.name = "SnapshotBuildFailedError";
544
+ }
545
+ };
546
+ var IncompatibleSchemaVersionError = class extends VelesError {
547
+ constructor(message) {
548
+ super(message, "VELES-036");
549
+ this.name = "IncompatibleSchemaVersionError";
550
+ }
551
+ };
552
+ var VELES_ERROR_CODES = [
553
+ "VELES-001",
554
+ "VELES-002",
555
+ "VELES-003",
556
+ "VELES-004",
557
+ "VELES-005",
558
+ "VELES-006",
559
+ "VELES-007",
560
+ "VELES-008",
561
+ "VELES-009",
562
+ "VELES-010",
563
+ "VELES-011",
564
+ "VELES-012",
565
+ "VELES-013",
566
+ "VELES-014",
567
+ "VELES-015",
568
+ "VELES-016",
569
+ "VELES-017",
570
+ "VELES-018",
571
+ "VELES-019",
572
+ "VELES-020",
573
+ "VELES-021",
574
+ "VELES-022",
575
+ "VELES-023",
576
+ "VELES-024",
577
+ "VELES-025",
578
+ "VELES-026",
579
+ "VELES-027",
580
+ "VELES-028",
581
+ "VELES-029",
582
+ "VELES-030",
583
+ "VELES-031",
584
+ "VELES-032",
585
+ "VELES-033",
586
+ "VELES-034",
587
+ "VELES-035",
588
+ "VELES-036"
589
+ ];
590
+ var CODE_TO_CLASS = {
591
+ "VELES-001": CollectionExistsError,
592
+ "VELES-002": CollectionNotFoundError,
593
+ "VELES-003": PointNotFoundError,
594
+ "VELES-004": DimensionMismatchError,
595
+ "VELES-005": InvalidVectorError,
596
+ "VELES-006": StorageError,
597
+ "VELES-007": IndexError,
598
+ "VELES-008": IndexCorruptedError,
599
+ "VELES-009": ConfigError,
600
+ "VELES-010": QueryError,
601
+ "VELES-011": IoError,
602
+ "VELES-012": SerializationError,
603
+ "VELES-013": InternalError,
604
+ "VELES-014": VectorNotAllowedError,
605
+ "VELES-015": SearchNotSupportedError,
606
+ "VELES-016": VectorRequiredError,
607
+ "VELES-017": SchemaValidationError,
608
+ "VELES-018": GraphNotSupportedError,
609
+ "VELES-019": EdgeExistsError,
610
+ "VELES-020": EdgeNotFoundError,
611
+ "VELES-021": InvalidEdgeLabelError,
612
+ "VELES-022": NodeNotFoundError,
613
+ "VELES-023": OverflowError,
614
+ "VELES-024": ColumnStoreError,
615
+ "VELES-025": GpuError,
616
+ "VELES-026": EpochMismatchError,
617
+ "VELES-027": GuardRailError,
618
+ "VELES-028": InvalidQuantizerConfigError,
619
+ "VELES-029": TrainingFailedError,
620
+ "VELES-030": SparseIndexError,
621
+ "VELES-031": DatabaseLockedError,
622
+ "VELES-032": InvalidDimensionError,
623
+ "VELES-033": AllocationFailedError,
624
+ "VELES-034": InvalidCollectionNameError,
625
+ "VELES-035": SnapshotBuildFailedError,
626
+ "VELES-036": IncompatibleSchemaVersionError
627
+ };
628
+ function parseVelesError(code, message) {
629
+ if (code === null || code === void 0) {
630
+ return new VelesError(message, "VELES-UNKNOWN");
631
+ }
632
+ const Cls = CODE_TO_CLASS[code];
633
+ if (Cls !== void 0) {
634
+ return new Cls(message);
635
+ }
636
+ return new VelesError(message, code);
637
+ }
638
+
35
639
  // src/backends/shared.ts
36
640
  function throwOnError(response, resourceLabel) {
37
641
  if (!response.error) {
@@ -40,20 +644,87 @@ function throwOnError(response, resourceLabel) {
40
644
  if (response.error.code === "NOT_FOUND" && resourceLabel !== void 0) {
41
645
  throw new NotFoundError(resourceLabel);
42
646
  }
43
- throw new VelesDBError(response.error.message, response.error.code);
647
+ throw parseVelesError(response.error.code, response.error.message);
44
648
  }
45
649
  function returnNullOnNotFound(response) {
46
650
  if (!response.error) {
47
651
  return void 0;
48
652
  }
49
- if (response.error.code === "NOT_FOUND") {
653
+ if (isNotFoundError(response.error.code)) {
50
654
  return true;
51
655
  }
52
- throw new VelesDBError(response.error.message, response.error.code);
656
+ throw parseVelesError(response.error.code, response.error.message);
657
+ }
658
+ function isNotFoundError(code) {
659
+ if (code === void 0) {
660
+ return false;
661
+ }
662
+ if (code === "NOT_FOUND") {
663
+ return true;
664
+ }
665
+ const err = parseVelesError(code, "");
666
+ return err instanceof CollectionNotFoundError || err instanceof PointNotFoundError || err instanceof EdgeNotFoundError || err instanceof NodeNotFoundError;
53
667
  }
54
668
  function collectionPath(collection) {
55
669
  return `/collections/${encodeURIComponent(collection)}`;
56
670
  }
671
+ var MAX_COLLECTION_NAME_LENGTH = 128;
672
+ var WINDOWS_RESERVED_NAMES = /* @__PURE__ */ new Set([
673
+ "CON",
674
+ "PRN",
675
+ "AUX",
676
+ "NUL",
677
+ "COM1",
678
+ "COM2",
679
+ "COM3",
680
+ "COM4",
681
+ "COM5",
682
+ "COM6",
683
+ "COM7",
684
+ "COM8",
685
+ "COM9",
686
+ "LPT1",
687
+ "LPT2",
688
+ "LPT3",
689
+ "LPT4",
690
+ "LPT5",
691
+ "LPT6",
692
+ "LPT7",
693
+ "LPT8",
694
+ "LPT9"
695
+ ]);
696
+ function validateCollectionName(name) {
697
+ if (typeof name !== "string" || name.length === 0) {
698
+ throw new InvalidCollectionNameError(
699
+ "Collection name must be a non-empty string"
700
+ );
701
+ }
702
+ if (name.length > MAX_COLLECTION_NAME_LENGTH) {
703
+ throw new InvalidCollectionNameError(
704
+ `Collection name '${name}' exceeds maximum length of ${MAX_COLLECTION_NAME_LENGTH} characters`
705
+ );
706
+ }
707
+ if (name === "." || name === "..") {
708
+ throw new InvalidCollectionNameError(
709
+ `Collection name '${name}' is not allowed (path traversal)`
710
+ );
711
+ }
712
+ if (name.startsWith("-")) {
713
+ throw new InvalidCollectionNameError(
714
+ `Collection name '${name}' must not start with a hyphen`
715
+ );
716
+ }
717
+ if (!/^[A-Za-z0-9_-]+$/.test(name)) {
718
+ throw new InvalidCollectionNameError(
719
+ `Collection name '${name}' contains forbidden characters; only ASCII letters, digits, underscores, and hyphens are allowed`
720
+ );
721
+ }
722
+ if (WINDOWS_RESERVED_NAMES.has(name.toUpperCase())) {
723
+ throw new InvalidCollectionNameError(
724
+ `Collection name '${name}' is a Windows reserved device name`
725
+ );
726
+ }
727
+ }
57
728
  function toNumberArray(v) {
58
729
  return v instanceof Float32Array ? Array.from(v) : v;
59
730
  }
@@ -64,6 +735,127 @@ function wasmNotSupported(feature) {
64
735
  );
65
736
  }
66
737
 
738
+ // src/backends/wasm-stubs.ts
739
+ async function wasmCreateIndex(_collection, _options) {
740
+ wasmNotSupported("Index management (createIndex)");
741
+ }
742
+ async function wasmListIndexes(_collection) {
743
+ wasmNotSupported("Index management (listIndexes)");
744
+ }
745
+ async function wasmHasIndex(_collection, _label, _property) {
746
+ wasmNotSupported("Index management (hasIndex)");
747
+ }
748
+ async function wasmDropIndex(_collection, _label, _property) {
749
+ wasmNotSupported("Index management (dropIndex)");
750
+ }
751
+ async function wasmAddEdge(_collection, _edge) {
752
+ wasmNotSupported("Knowledge Graph operations");
753
+ }
754
+ async function wasmGetEdges(_collection, _options) {
755
+ wasmNotSupported("Knowledge Graph operations");
756
+ }
757
+ async function wasmTraverseGraph(_collection, _request) {
758
+ wasmNotSupported("Graph traversal");
759
+ }
760
+ async function wasmTraverseParallel(_collection, _request) {
761
+ wasmNotSupported("Graph parallel traversal");
762
+ }
763
+ async function wasmGetNodeDegree(_collection, _nodeId) {
764
+ wasmNotSupported("Graph degree query");
765
+ }
766
+ async function wasmQueryExplain(_queryString, _params, _options) {
767
+ if (_options?.analyze) {
768
+ wasmNotSupported("EXPLAIN ANALYZE");
769
+ }
770
+ wasmNotSupported("Query explain");
771
+ }
772
+ async function wasmCollectionSanity(_collection) {
773
+ wasmNotSupported("Collection sanity endpoint");
774
+ }
775
+ async function wasmScroll(_collection, _request) {
776
+ wasmNotSupported("scroll");
777
+ }
778
+ async function wasmTrainPq(_collection, _options) {
779
+ wasmNotSupported("PQ training");
780
+ }
781
+ async function wasmStreamInsert(_collection, _docs) {
782
+ wasmNotSupported("Streaming insert");
783
+ }
784
+ async function wasmStreamUpsertPoints(_collection, _docs) {
785
+ wasmNotSupported("Streaming batch upsert");
786
+ }
787
+ async function wasmCreateGraphCollection(_name, _config) {
788
+ wasmNotSupported("Graph collections");
789
+ }
790
+ async function wasmGetCollectionStats(_collection) {
791
+ wasmNotSupported("Collection stats");
792
+ }
793
+ async function wasmAnalyzeCollection(_collection) {
794
+ wasmNotSupported("Collection analyze");
795
+ }
796
+ async function wasmGetCollectionConfig(_collection) {
797
+ wasmNotSupported("Collection config");
798
+ }
799
+ async function wasmSearchIds(_collection, _query, _options) {
800
+ wasmNotSupported("searchIds");
801
+ }
802
+ async function wasmStoreSemanticFact(_collection, _entry) {
803
+ wasmNotSupported("Agent memory");
804
+ }
805
+ async function wasmSearchSemanticMemory(_collection, _embedding, _k) {
806
+ wasmNotSupported("Agent memory");
807
+ }
808
+ async function wasmRecordEpisodicEvent(_collection, _event) {
809
+ wasmNotSupported("Agent memory");
810
+ }
811
+ async function wasmRecallEpisodicEvents(_collection, _embedding, _k) {
812
+ wasmNotSupported("Agent memory");
813
+ }
814
+ async function wasmStoreProceduralPattern(_collection, _pattern) {
815
+ wasmNotSupported("Agent memory");
816
+ }
817
+ async function wasmMatchProceduralPatterns(_collection, _embedding, _k) {
818
+ wasmNotSupported("Agent memory");
819
+ }
820
+
821
+ // src/backends/wasm-wave4-stubs.ts
822
+ function wasmRebuildIndex(_c) {
823
+ return Promise.resolve(wasmNotSupported("Index rebuild"));
824
+ }
825
+ function wasmGetGuardrails() {
826
+ return Promise.resolve(wasmNotSupported("Guardrails"));
827
+ }
828
+ function wasmUpdateGuardrails(_r) {
829
+ return Promise.resolve(wasmNotSupported("Guardrails"));
830
+ }
831
+ function wasmAggregate(_q, _p, _o) {
832
+ return Promise.resolve(wasmNotSupported("Aggregate queries"));
833
+ }
834
+ function wasmMatchQuery(_c, _q, _p, _o) {
835
+ return Promise.resolve(wasmNotSupported("MATCH queries"));
836
+ }
837
+ function wasmRemoveEdge(_c, _id) {
838
+ return Promise.resolve(wasmNotSupported("Graph edge removal"));
839
+ }
840
+ function wasmGetEdgeCount(_c) {
841
+ return Promise.resolve(wasmNotSupported("Graph edge count"));
842
+ }
843
+ function wasmListNodes(_c) {
844
+ return Promise.resolve(wasmNotSupported("Graph list nodes"));
845
+ }
846
+ function wasmGetNodeEdges(_c, _id, _o) {
847
+ return Promise.resolve(wasmNotSupported("Graph node edges"));
848
+ }
849
+ function wasmGetNodePayload(_c, _id) {
850
+ return Promise.resolve(wasmNotSupported("Graph node payload (read)"));
851
+ }
852
+ function wasmUpsertNodePayload(_c, _id, _p) {
853
+ return Promise.resolve(wasmNotSupported("Graph node payload (upsert)"));
854
+ }
855
+ function wasmGraphSearch(_c, _r) {
856
+ return Promise.resolve(wasmNotSupported("Graph search"));
857
+ }
858
+
67
859
  // src/backends/wasm.ts
68
860
  var WasmBackend = class {
69
861
  constructor() {
@@ -71,6 +863,9 @@ var WasmBackend = class {
71
863
  this.collections = /* @__PURE__ */ new Map();
72
864
  this._initialized = false;
73
865
  }
866
+ // ========================================================================
867
+ // Lifecycle
868
+ // ========================================================================
74
869
  async init() {
75
870
  if (this._initialized) {
76
871
  return;
@@ -89,45 +884,32 @@ var WasmBackend = class {
89
884
  isInitialized() {
90
885
  return this._initialized;
91
886
  }
92
- ensureInitialized() {
93
- if (!this._initialized || !this.wasmModule) {
94
- throw new ConnectionError("WASM backend not initialized");
887
+ async close() {
888
+ for (const [, data] of this.collections) {
889
+ data.store.free();
95
890
  }
891
+ this.collections.clear();
892
+ this._initialized = false;
96
893
  }
97
- normalizeIdString(id) {
98
- const trimmed = id.trim();
99
- return /^\d+$/.test(trimmed) ? trimmed : null;
894
+ capabilities() {
895
+ return WASM_CAPABILITIES;
100
896
  }
101
- canonicalPayloadKeyFromResultId(id) {
102
- if (typeof id === "bigint") {
103
- return id.toString();
104
- }
105
- if (typeof id === "number") {
106
- return String(Math.trunc(id));
107
- }
108
- const normalized = this.normalizeIdString(id);
109
- if (normalized !== null) {
110
- return normalized.replace(/^0+(?=\d)/, "");
111
- }
112
- return String(this.toNumericId(id));
113
- }
114
- canonicalPayloadKey(id) {
115
- if (typeof id === "number") {
116
- return String(Math.trunc(id));
117
- }
118
- const normalized = this.normalizeIdString(id);
119
- if (normalized !== null) {
120
- return normalized.replace(/^0+(?=\d)/, "");
897
+ ensureInitialized() {
898
+ if (!this._initialized || !this.wasmModule) {
899
+ throw new ConnectionError("WASM backend not initialized");
121
900
  }
122
- return String(this.toNumericId(id));
123
901
  }
902
+ // ========================================================================
903
+ // Collection management
904
+ // ========================================================================
124
905
  async createCollection(name, config) {
125
906
  this.ensureInitialized();
126
907
  if (this.collections.has(name)) {
127
908
  throw new VelesDBError(`Collection '${name}' already exists`, "COLLECTION_EXISTS");
128
909
  }
910
+ const dimension = config.dimension ?? 0;
129
911
  const metric = config.metric ?? "cosine";
130
- const store = new this.wasmModule.VectorStore(config.dimension, metric);
912
+ const store = new this.wasmModule.VectorStore(dimension, metric);
131
913
  this.collections.set(name, {
132
914
  config: { ...config, metric },
133
915
  store,
@@ -146,39 +928,27 @@ var WasmBackend = class {
146
928
  }
147
929
  async getCollection(name) {
148
930
  this.ensureInitialized();
149
- const collection = this.collections.get(name);
150
- if (!collection) {
151
- return null;
152
- }
153
- return {
154
- name,
155
- dimension: collection.config.dimension ?? 0,
156
- metric: collection.config.metric ?? "cosine",
157
- count: collection.store.len,
158
- createdAt: collection.createdAt
159
- };
931
+ const data = this.collections.get(name);
932
+ return data ? buildCollectionInfo(name, data) : null;
160
933
  }
161
934
  async listCollections() {
162
935
  this.ensureInitialized();
163
936
  const result = [];
164
937
  for (const [name, data] of this.collections) {
165
- result.push({
166
- name,
167
- dimension: data.config.dimension ?? 0,
168
- metric: data.config.metric ?? "cosine",
169
- count: data.store.len,
170
- createdAt: data.createdAt
171
- });
938
+ result.push(buildCollectionInfo(name, data));
172
939
  }
173
940
  return result;
174
941
  }
175
- async insert(collectionName, doc) {
942
+ // ========================================================================
943
+ // Point CRUD
944
+ // ========================================================================
945
+ async upsert(collectionName, doc) {
176
946
  this.ensureInitialized();
177
947
  const collection = this.collections.get(collectionName);
178
948
  if (!collection) {
179
949
  throw new NotFoundError(`Collection '${collectionName}'`);
180
950
  }
181
- const id = this.toNumericId(doc.id);
951
+ const id = toNumericId(doc.id);
182
952
  const vector = doc.vector instanceof Float32Array ? doc.vector : new Float32Array(doc.vector);
183
953
  if (vector.length !== collection.config.dimension) {
184
954
  throw new VelesDBError(
@@ -192,20 +962,19 @@ var WasmBackend = class {
192
962
  collection.store.insert(BigInt(id), vector);
193
963
  }
194
964
  if (doc.payload) {
195
- collection.payloads.set(this.canonicalPayloadKey(doc.id), doc.payload);
965
+ collection.payloads.set(canonicalPayloadKey(doc.id), doc.payload);
196
966
  }
197
967
  }
198
- async insertBatch(collectionName, docs) {
968
+ async upsertBatch(collectionName, docs) {
199
969
  this.ensureInitialized();
200
970
  const collection = this.collections.get(collectionName);
201
971
  if (!collection) {
202
972
  throw new NotFoundError(`Collection '${collectionName}'`);
203
973
  }
204
974
  for (const doc of docs) {
205
- const vectorLen = doc.vector.length;
206
- if (vectorLen !== collection.config.dimension) {
975
+ if (doc.vector.length !== collection.config.dimension) {
207
976
  throw new VelesDBError(
208
- `Vector dimension mismatch for doc ${doc.id}: expected ${collection.config.dimension}, got ${vectorLen}`,
977
+ `Vector dimension mismatch for doc ${doc.id}: expected ${collection.config.dimension}, got ${doc.vector.length}`,
209
978
  "DIMENSION_MISMATCH"
210
979
  );
211
980
  }
@@ -213,7 +982,7 @@ var WasmBackend = class {
213
982
  collection.store.reserve(docs.length);
214
983
  const batch = [];
215
984
  for (const doc of docs) {
216
- const id = BigInt(this.toNumericId(doc.id));
985
+ const id = BigInt(toNumericId(doc.id));
217
986
  const vector = doc.vector instanceof Float32Array ? doc.vector : new Float32Array(doc.vector);
218
987
  if (doc.payload) {
219
988
  collection.store.insert_with_payload(id, vector, doc.payload);
@@ -226,95 +995,20 @@ var WasmBackend = class {
226
995
  }
227
996
  for (const doc of docs) {
228
997
  if (doc.payload) {
229
- collection.payloads.set(this.canonicalPayloadKey(doc.id), doc.payload);
998
+ collection.payloads.set(canonicalPayloadKey(doc.id), doc.payload);
230
999
  }
231
1000
  }
232
1001
  }
233
- async search(collectionName, query2, options) {
234
- this.ensureInitialized();
235
- const collection = this.collections.get(collectionName);
236
- if (!collection) {
237
- throw new NotFoundError(`Collection '${collectionName}'`);
238
- }
239
- const queryVector = query2 instanceof Float32Array ? query2 : new Float32Array(query2);
240
- if (queryVector.length !== collection.config.dimension) {
241
- throw new VelesDBError(
242
- `Query dimension mismatch: expected ${collection.config.dimension}, got ${queryVector.length}`,
243
- "DIMENSION_MISMATCH"
244
- );
245
- }
246
- const k = options?.k ?? 10;
247
- if (options?.sparseVector) {
248
- const { indices, values } = this.sparseVectorToArrays(options.sparseVector);
249
- if (queryVector.length > 0 && collection.config.dimension && collection.config.dimension > 0) {
250
- const denseResults = collection.store.search(queryVector, k);
251
- const sparseResults = collection.store.sparse_search(
252
- new Uint32Array(indices),
253
- new Float32Array(values),
254
- k
255
- );
256
- const sparseArray = sparseResults;
257
- const denseForFuse = denseResults.map(([id, score]) => [Number(id), score]);
258
- const sparseForFuse = sparseArray.map((r) => [Number(r.doc_id), r.score]);
259
- const fused = this.wasmModule.hybrid_search_fuse(denseForFuse, sparseForFuse, 60);
260
- return fused.slice(0, k).map((r) => ({
261
- id: String(r.doc_id),
262
- score: r.score,
263
- payload: collection.payloads.get(this.canonicalPayloadKeyFromResultId(r.doc_id))
264
- }));
265
- } else {
266
- const sparseResults = collection.store.sparse_search(
267
- new Uint32Array(indices),
268
- new Float32Array(values),
269
- k
270
- );
271
- return sparseResults.map((r) => ({
272
- id: String(r.doc_id),
273
- score: r.score,
274
- payload: collection.payloads.get(this.canonicalPayloadKeyFromResultId(r.doc_id))
275
- }));
276
- }
277
- }
278
- if (options?.filter) {
279
- const results = collection.store.search_with_filter(queryVector, k, options.filter);
280
- return results.map((r) => ({
281
- id: String(r.id),
282
- score: r.score,
283
- payload: r.payload || collection.payloads.get(this.canonicalPayloadKeyFromResultId(r.id))
284
- }));
285
- }
286
- const rawResults = collection.store.search(queryVector, k);
287
- return rawResults.map(([id, score]) => {
288
- const stringId = String(id);
289
- const result = {
290
- id: stringId,
291
- score
292
- };
293
- const payload = collection.payloads.get(this.canonicalPayloadKeyFromResultId(id));
294
- if (payload) {
295
- result.payload = payload;
296
- }
297
- return result;
298
- });
299
- }
300
- async searchBatch(collectionName, searches) {
301
- this.ensureInitialized();
302
- const results = [];
303
- for (const s of searches) {
304
- results.push(await this.search(collectionName, s.vector, { k: s.k, filter: s.filter }));
305
- }
306
- return results;
307
- }
308
1002
  async delete(collectionName, id) {
309
1003
  this.ensureInitialized();
310
1004
  const collection = this.collections.get(collectionName);
311
1005
  if (!collection) {
312
1006
  throw new NotFoundError(`Collection '${collectionName}'`);
313
1007
  }
314
- const numericId = this.toNumericId(id);
1008
+ const numericId = toNumericId(id);
315
1009
  const removed = collection.store.remove(BigInt(numericId));
316
1010
  if (removed) {
317
- collection.payloads.delete(this.canonicalPayloadKey(id));
1011
+ collection.payloads.delete(canonicalPayloadKey(id));
318
1012
  }
319
1013
  return removed;
320
1014
  }
@@ -324,291 +1018,691 @@ var WasmBackend = class {
324
1018
  if (!collection) {
325
1019
  throw new NotFoundError(`Collection '${collectionName}'`);
326
1020
  }
327
- const numericId = this.toNumericId(id);
1021
+ const numericId = toNumericId(id);
328
1022
  const point = collection.store.get(BigInt(numericId));
329
1023
  if (!point) {
330
1024
  return null;
331
1025
  }
332
- const payload = point.payload ?? collection.payloads.get(this.canonicalPayloadKey(numericId));
1026
+ const payload = point.payload ?? collection.payloads.get(canonicalPayloadKey(numericId));
333
1027
  return {
334
1028
  id: String(point.id),
335
1029
  vector: Array.isArray(point.vector) ? point.vector : Array.from(point.vector),
336
1030
  payload
337
1031
  };
338
1032
  }
339
- async textSearch(_collection, _query, _options) {
1033
+ // ========================================================================
1034
+ // Collection utilities
1035
+ // ========================================================================
1036
+ async isEmpty(collectionName) {
340
1037
  this.ensureInitialized();
341
- const collection = this.collections.get(_collection);
1038
+ const collection = this.collections.get(collectionName);
342
1039
  if (!collection) {
343
- throw new NotFoundError(`Collection '${_collection}'`);
344
- }
345
- const k = _options?.k ?? 10;
346
- const field = void 0;
347
- const raw = collection.store.text_search(_query, k, field);
348
- return raw.map((r) => {
349
- if (Array.isArray(r)) {
350
- const key2 = this.canonicalPayloadKeyFromResultId(r[0]);
351
- return { id: String(r[0]), score: r[1], payload: collection.payloads.get(key2) };
352
- }
353
- const key = this.canonicalPayloadKeyFromResultId(r.id);
354
- return { id: String(r.id), score: r.score, payload: r.payload ?? collection.payloads.get(key) };
355
- });
1040
+ throw new NotFoundError(`Collection '${collectionName}'`);
1041
+ }
1042
+ return collection.store.is_empty;
1043
+ }
1044
+ async flush(collectionName) {
1045
+ this.ensureInitialized();
1046
+ const collection = this.collections.get(collectionName);
1047
+ if (!collection) {
1048
+ throw new NotFoundError(`Collection '${collectionName}'`);
1049
+ }
1050
+ }
1051
+ // ========================================================================
1052
+ // Search & Query -- delegates to wasm-search.ts
1053
+ // ========================================================================
1054
+ async search(c, q, o) {
1055
+ this.ensureInitialized();
1056
+ return wasmSearch(buildWasmContext(this.wasmModule, this.collections), c, q, o);
1057
+ }
1058
+ async searchBatch(c, s) {
1059
+ this.ensureInitialized();
1060
+ return wasmSearchBatch(buildWasmContext(this.wasmModule, this.collections), c, s);
1061
+ }
1062
+ async textSearch(c, q, o) {
1063
+ this.ensureInitialized();
1064
+ return wasmTextSearch(buildWasmContext(this.wasmModule, this.collections), c, q, o);
1065
+ }
1066
+ async hybridSearch(c, v, t, o) {
1067
+ this.ensureInitialized();
1068
+ return wasmHybridSearch(buildWasmContext(this.wasmModule, this.collections), c, v, t, o);
1069
+ }
1070
+ async query(c, q, p, o) {
1071
+ this.ensureInitialized();
1072
+ return wasmQuery(buildWasmContext(this.wasmModule, this.collections), c, q, p, o);
1073
+ }
1074
+ async multiQuerySearch(c, v, o) {
1075
+ this.ensureInitialized();
1076
+ return wasmMultiQuerySearch(buildWasmContext(this.wasmModule, this.collections), c, v, o);
1077
+ }
1078
+ // ========================================================================
1079
+ // Stubs -- delegates to wasm-stubs.ts & wasm-wave4-stubs.ts
1080
+ // ========================================================================
1081
+ async queryExplain(q, p, o) {
1082
+ this.ensureInitialized();
1083
+ return wasmQueryExplain(q, p, o);
1084
+ }
1085
+ async collectionSanity(c) {
1086
+ this.ensureInitialized();
1087
+ return wasmCollectionSanity(c);
1088
+ }
1089
+ async scroll(c, r) {
1090
+ this.ensureInitialized();
1091
+ return wasmScroll(c, r);
1092
+ }
1093
+ async createIndex(c, o) {
1094
+ this.ensureInitialized();
1095
+ return wasmCreateIndex(c, o);
1096
+ }
1097
+ async listIndexes(c) {
1098
+ this.ensureInitialized();
1099
+ return wasmListIndexes(c);
1100
+ }
1101
+ async hasIndex(c, l, p) {
1102
+ this.ensureInitialized();
1103
+ return wasmHasIndex(c, l, p);
356
1104
  }
357
- async hybridSearch(_collection, _vector, _textQuery, _options) {
1105
+ async dropIndex(c, l, p) {
358
1106
  this.ensureInitialized();
359
- const collection = this.collections.get(_collection);
360
- if (!collection) {
361
- throw new NotFoundError(`Collection '${_collection}'`);
362
- }
363
- const queryVector = _vector instanceof Float32Array ? _vector : new Float32Array(_vector);
364
- const k = _options?.k ?? 10;
365
- const vectorWeight = _options?.vectorWeight ?? 0.5;
366
- const raw = collection.store.hybrid_search(queryVector, _textQuery, k, vectorWeight);
367
- return raw.map((r) => {
368
- const key = this.canonicalPayloadKeyFromResultId(r.id);
369
- return {
370
- id: String(r.id),
371
- score: r.score,
372
- payload: r.payload ?? collection.payloads.get(key)
373
- };
374
- });
1107
+ return wasmDropIndex(c, l, p);
375
1108
  }
376
- async query(_collection, _queryString, _params, _options) {
1109
+ async addEdge(c, e) {
377
1110
  this.ensureInitialized();
378
- const collection = this.collections.get(_collection);
379
- if (!collection) {
380
- throw new NotFoundError(`Collection '${_collection}'`);
381
- }
382
- const paramsVector = _params?.q;
383
- if (!Array.isArray(paramsVector) && !(paramsVector instanceof Float32Array)) {
384
- throw new VelesDBError(
385
- "WASM query() expects params.q to contain the query embedding vector.",
386
- "BAD_REQUEST"
387
- );
388
- }
389
- const requestedK = _params?.k;
390
- const k = typeof requestedK === "number" && Number.isInteger(requestedK) && requestedK > 0 ? requestedK : 10;
391
- const raw = collection.store.query(
392
- paramsVector instanceof Float32Array ? paramsVector : new Float32Array(paramsVector),
393
- k
394
- );
395
- return {
396
- results: raw,
397
- stats: {
398
- executionTimeMs: 0,
399
- strategy: "wasm-query",
400
- scannedNodes: raw.length
401
- }
402
- };
1111
+ return wasmAddEdge(c, e);
403
1112
  }
404
- async multiQuerySearch(_collection, _vectors, _options) {
1113
+ async getEdges(c, o) {
405
1114
  this.ensureInitialized();
406
- const collection = this.collections.get(_collection);
407
- if (!collection) {
408
- throw new NotFoundError(`Collection '${_collection}'`);
409
- }
410
- if (_vectors.length === 0) {
411
- return [];
412
- }
413
- const numVectors = _vectors.length;
414
- const dimension = collection.config.dimension ?? 0;
415
- const flat = new Float32Array(numVectors * dimension);
416
- _vectors.forEach((vector, idx) => {
417
- const src = vector instanceof Float32Array ? vector : new Float32Array(vector);
418
- flat.set(src, idx * dimension);
419
- });
420
- const strategy = _options?.fusion ?? "rrf";
421
- if (strategy === "weighted") {
422
- throw new VelesDBError(
423
- "Fusion strategy 'weighted' is not supported in WASM backend.",
424
- "NOT_SUPPORTED"
425
- );
426
- }
427
- const raw = collection.store.multi_query_search(
428
- flat,
429
- numVectors,
430
- _options?.k ?? 10,
431
- strategy,
432
- _options?.fusionParams?.k ?? 60
433
- );
434
- return raw.map((r) => {
435
- if (Array.isArray(r)) {
436
- const key2 = this.canonicalPayloadKeyFromResultId(r[0]);
437
- return { id: String(r[0]), score: r[1], payload: collection.payloads.get(key2) };
438
- }
439
- const key = this.canonicalPayloadKeyFromResultId(r.id);
440
- return { id: String(r.id), score: r.score, payload: r.payload ?? collection.payloads.get(key) };
441
- });
1115
+ return wasmGetEdges(c, o);
442
1116
  }
443
- async queryExplain(_queryString, _params) {
1117
+ async traverseGraph(c, r) {
444
1118
  this.ensureInitialized();
445
- wasmNotSupported("Query explain");
1119
+ return wasmTraverseGraph(c, r);
446
1120
  }
447
- async collectionSanity(_collection) {
1121
+ async traverseParallel(c, r) {
448
1122
  this.ensureInitialized();
449
- wasmNotSupported("Collection sanity endpoint");
1123
+ return wasmTraverseParallel(c, r);
450
1124
  }
451
- async isEmpty(collectionName) {
1125
+ async getNodeDegree(c, n) {
452
1126
  this.ensureInitialized();
453
- const collection = this.collections.get(collectionName);
454
- if (!collection) {
455
- throw new NotFoundError(`Collection '${collectionName}'`);
456
- }
457
- return collection.store.is_empty();
1127
+ return wasmGetNodeDegree(c, n);
458
1128
  }
459
- async flush(collectionName) {
1129
+ async trainPq(c, o) {
460
1130
  this.ensureInitialized();
461
- const collection = this.collections.get(collectionName);
462
- if (!collection) {
463
- throw new NotFoundError(`Collection '${collectionName}'`);
464
- }
1131
+ return wasmTrainPq(c, o);
465
1132
  }
466
- async close() {
467
- for (const [, data] of this.collections) {
468
- data.store.free();
469
- }
470
- this.collections.clear();
471
- this._initialized = false;
1133
+ async streamInsert(c, d) {
1134
+ this.ensureInitialized();
1135
+ return wasmStreamInsert(c, d);
472
1136
  }
473
- sparseVectorToArrays(sv) {
474
- const indices = [];
475
- const values = [];
476
- for (const [k, v] of Object.entries(sv)) {
477
- indices.push(Number(k));
478
- values.push(v);
479
- }
480
- return { indices, values };
1137
+ async streamUpsertPoints(c, d) {
1138
+ this.ensureInitialized();
1139
+ return wasmStreamUpsertPoints(c, d);
481
1140
  }
482
- toNumericId(id) {
483
- if (typeof id === "number") {
484
- return id;
485
- }
486
- const normalized = this.normalizeIdString(id);
487
- if (normalized !== null) {
488
- const parsed = Number(normalized);
489
- if (Number.isSafeInteger(parsed)) {
490
- return parsed;
491
- }
492
- }
493
- let hash = 0;
494
- for (let i = 0; i < id.length; i++) {
495
- const char = id.charCodeAt(i);
496
- hash = (hash << 5) - hash + char;
497
- hash = hash & hash;
498
- }
499
- return Math.abs(hash);
1141
+ async createGraphCollection(n, c) {
1142
+ this.ensureInitialized();
1143
+ return wasmCreateGraphCollection(n, c);
500
1144
  }
501
- // ========================================================================
502
- // Index Management (EPIC-009) - Stubs for WASM backend
503
- // Note: Full implementation requires velesdb-wasm support
504
- // ========================================================================
505
- async createIndex(_collection, _options) {
1145
+ async getCollectionStats(c) {
506
1146
  this.ensureInitialized();
507
- throw new Error(
508
- "WasmBackend: createIndex is not yet supported. Index operations require the REST backend with velesdb-server."
509
- );
1147
+ return wasmGetCollectionStats(c);
510
1148
  }
511
- async listIndexes(_collection) {
1149
+ async analyzeCollection(c) {
512
1150
  this.ensureInitialized();
513
- return [];
1151
+ return wasmAnalyzeCollection(c);
514
1152
  }
515
- async hasIndex(_collection, _label, _property) {
1153
+ async getCollectionConfig(c) {
516
1154
  this.ensureInitialized();
517
- return false;
1155
+ return wasmGetCollectionConfig(c);
518
1156
  }
519
- async dropIndex(_collection, _label, _property) {
1157
+ async searchIds(c, q, o) {
520
1158
  this.ensureInitialized();
521
- return false;
1159
+ return wasmSearchIds(c, q, o);
522
1160
  }
523
- // ========================================================================
524
- // Knowledge Graph (EPIC-016 US-041) - Stubs for WASM backend
525
- // Note: Graph operations require server-side EdgeStore
526
- // ========================================================================
527
- async addEdge(_collection, _edge) {
1161
+ async storeSemanticFact(c, e) {
528
1162
  this.ensureInitialized();
529
- wasmNotSupported("Knowledge Graph operations");
1163
+ return wasmStoreSemanticFact(c, e);
530
1164
  }
531
- async getEdges(_collection, _options) {
1165
+ async searchSemanticMemory(c, e, k) {
532
1166
  this.ensureInitialized();
533
- wasmNotSupported("Knowledge Graph operations");
1167
+ return wasmSearchSemanticMemory(c, e, k);
534
1168
  }
535
- async traverseGraph(_collection, _request) {
1169
+ async recordEpisodicEvent(c, e) {
536
1170
  this.ensureInitialized();
537
- wasmNotSupported("Graph traversal");
1171
+ return wasmRecordEpisodicEvent(c, e);
538
1172
  }
539
- async traverseParallel(_collection, _request) {
1173
+ async recallEpisodicEvents(c, e, k) {
540
1174
  this.ensureInitialized();
541
- wasmNotSupported("Graph parallel traversal");
1175
+ return wasmRecallEpisodicEvents(c, e, k);
542
1176
  }
543
- async getNodeDegree(_collection, _nodeId) {
1177
+ async storeProceduralPattern(c, p) {
544
1178
  this.ensureInitialized();
545
- wasmNotSupported("Graph degree query");
1179
+ return wasmStoreProceduralPattern(c, p);
546
1180
  }
547
- // ========================================================================
548
- // Sparse / PQ / Streaming (v1.5)
549
- // ========================================================================
550
- async trainPq(_collection, _options) {
1181
+ async matchProceduralPatterns(c, e, k) {
551
1182
  this.ensureInitialized();
552
- wasmNotSupported("PQ training");
1183
+ return wasmMatchProceduralPatterns(c, e, k);
553
1184
  }
554
- async streamInsert(_collection, _docs) {
1185
+ // Wave 4 stubs
1186
+ async rebuildIndex(c) {
555
1187
  this.ensureInitialized();
556
- wasmNotSupported("Streaming insert");
1188
+ return wasmRebuildIndex(c);
557
1189
  }
558
- // ========================================================================
559
- // Graph Collection / Stats / Agent Memory (Phase 8) - WASM stubs
560
- // ========================================================================
561
- async createGraphCollection(_name, _config) {
1190
+ async getGuardrails() {
562
1191
  this.ensureInitialized();
563
- wasmNotSupported("Graph collections");
1192
+ return wasmGetGuardrails();
564
1193
  }
565
- async getCollectionStats(_collection) {
1194
+ async updateGuardrails(r) {
566
1195
  this.ensureInitialized();
567
- wasmNotSupported("Collection stats");
1196
+ return wasmUpdateGuardrails(r);
568
1197
  }
569
- async analyzeCollection(_collection) {
1198
+ async aggregate(_q, _p, _o) {
570
1199
  this.ensureInitialized();
571
- wasmNotSupported("Collection analyze");
1200
+ return wasmAggregate(_q, _p, _o);
572
1201
  }
573
- async getCollectionConfig(_collection) {
1202
+ async matchQuery(c, q, p, o) {
574
1203
  this.ensureInitialized();
575
- wasmNotSupported("Collection config");
1204
+ return wasmMatchQuery(c, q, p, o);
576
1205
  }
577
- async searchIds(_collection, _query, _options) {
1206
+ async removeEdge(c, id) {
578
1207
  this.ensureInitialized();
579
- wasmNotSupported("searchIds");
1208
+ return wasmRemoveEdge(c, id);
580
1209
  }
581
- async storeSemanticFact(_collection, _entry) {
1210
+ async getEdgeCount(c) {
582
1211
  this.ensureInitialized();
583
- wasmNotSupported("Agent memory");
1212
+ return wasmGetEdgeCount(c);
584
1213
  }
585
- async searchSemanticMemory(_collection, _embedding, _k) {
1214
+ async listNodes(c) {
586
1215
  this.ensureInitialized();
587
- wasmNotSupported("Agent memory");
1216
+ return wasmListNodes(c);
588
1217
  }
589
- async recordEpisodicEvent(_collection, _event) {
1218
+ async getNodeEdges(c, id, o) {
590
1219
  this.ensureInitialized();
591
- wasmNotSupported("Agent memory");
1220
+ return wasmGetNodeEdges(c, id, o);
592
1221
  }
593
- async recallEpisodicEvents(_collection, _embedding, _k) {
1222
+ async getNodePayload(c, id) {
594
1223
  this.ensureInitialized();
595
- wasmNotSupported("Agent memory");
1224
+ return wasmGetNodePayload(c, id);
596
1225
  }
597
- async storeProceduralPattern(_collection, _pattern) {
1226
+ async upsertNodePayload(c, id, p) {
598
1227
  this.ensureInitialized();
599
- wasmNotSupported("Agent memory");
1228
+ return wasmUpsertNodePayload(c, id, p);
600
1229
  }
601
- async matchProceduralPatterns(_collection, _embedding, _k) {
1230
+ async graphSearch(c, r) {
602
1231
  this.ensureInitialized();
603
- wasmNotSupported("Agent memory");
1232
+ return wasmGraphSearch(c, r);
1233
+ }
1234
+ };
1235
+
1236
+ // src/backends/crud-backend.ts
1237
+ function parseRestPointId(id) {
1238
+ if (typeof id !== "number" || !Number.isFinite(id) || id < 0 || !Number.isInteger(id) || id > Number.MAX_SAFE_INTEGER) {
1239
+ throw new ValidationError(
1240
+ `REST backend requires numeric u64-compatible IDs in JS safe integer range (0..${Number.MAX_SAFE_INTEGER}). Received: ${String(id)}`
1241
+ );
1242
+ }
1243
+ return id;
1244
+ }
1245
+ function sparseVectorToRestFormat(sv) {
1246
+ const result = {};
1247
+ for (const [k, v] of Object.entries(sv)) {
1248
+ result[String(k)] = v;
1249
+ }
1250
+ return result;
1251
+ }
1252
+ function toDeferredIndexingWire(opts) {
1253
+ if (!opts) return void 0;
1254
+ const wire = {};
1255
+ if (opts.enabled !== void 0) wire.enabled = opts.enabled;
1256
+ if (opts.mergeThreshold !== void 0) wire.merge_threshold = opts.mergeThreshold;
1257
+ if (opts.maxBufferAgeMs !== void 0) wire.max_buffer_age_ms = opts.maxBufferAgeMs;
1258
+ return wire;
1259
+ }
1260
+ function toAsyncIndexBuilderWire(opts) {
1261
+ if (!opts) return void 0;
1262
+ const wire = {};
1263
+ if (opts.mergeThreshold !== void 0) wire.merge_threshold = opts.mergeThreshold;
1264
+ if (opts.segmentCount !== void 0) wire.segment_count = opts.segmentCount;
1265
+ return wire;
1266
+ }
1267
+ async function createCollection(transport, name, config) {
1268
+ const body = {
1269
+ name,
1270
+ dimension: config.dimension,
1271
+ metric: config.metric ?? "cosine",
1272
+ storage_mode: config.storageMode ?? "full",
1273
+ collection_type: config.collectionType ?? "vector",
1274
+ description: config.description,
1275
+ hnsw_m: config.hnsw?.m,
1276
+ hnsw_ef_construction: config.hnsw?.efConstruction,
1277
+ hnsw_alpha: config.hnsw?.alpha,
1278
+ hnsw_max_elements: config.hnsw?.maxElements
1279
+ };
1280
+ if (config.pqRescoreOversampling !== void 0) {
1281
+ body.pq_rescore_oversampling = config.pqRescoreOversampling;
1282
+ }
1283
+ const deferredWire = toDeferredIndexingWire(config.deferredIndexing);
1284
+ if (deferredWire !== void 0) {
1285
+ body.deferred_indexing = deferredWire;
1286
+ }
1287
+ const asyncWire = toAsyncIndexBuilderWire(config.asyncIndexBuilder);
1288
+ if (asyncWire !== void 0) {
1289
+ body.async_index_builder = asyncWire;
1290
+ }
1291
+ const response = await transport.requestJson("POST", "/collections", body);
1292
+ throwOnError(response);
1293
+ }
1294
+ async function deleteCollection(transport, name) {
1295
+ const response = await transport.requestJson(
1296
+ "DELETE",
1297
+ collectionPath(name)
1298
+ );
1299
+ throwOnError(response, `Collection '${name}'`);
1300
+ }
1301
+ async function getCollection(transport, name) {
1302
+ const response = await transport.requestJson(
1303
+ "GET",
1304
+ collectionPath(name)
1305
+ );
1306
+ if (returnNullOnNotFound(response)) {
1307
+ return null;
1308
+ }
1309
+ return response.data ?? null;
1310
+ }
1311
+ async function listCollections(transport) {
1312
+ const response = await transport.requestJson("GET", "/collections");
1313
+ throwOnError(response);
1314
+ return response.data ?? [];
1315
+ }
1316
+ async function upsert(transport, collection, doc) {
1317
+ const restId = parseRestPointId(doc.id);
1318
+ const vector = toNumberArray(doc.vector);
1319
+ const response = await transport.requestJson(
1320
+ "POST",
1321
+ `${collectionPath(collection)}/points`,
1322
+ { points: [{ id: restId, vector, payload: doc.payload }] }
1323
+ );
1324
+ throwOnError(response, `Collection '${collection}'`);
1325
+ }
1326
+ async function upsertBatch(transport, collection, docs) {
1327
+ const vectors = docs.map((doc) => ({
1328
+ id: parseRestPointId(doc.id),
1329
+ vector: toNumberArray(doc.vector),
1330
+ payload: doc.payload
1331
+ }));
1332
+ const response = await transport.requestJson(
1333
+ "POST",
1334
+ `${collectionPath(collection)}/points`,
1335
+ { points: vectors }
1336
+ );
1337
+ throwOnError(response, `Collection '${collection}'`);
1338
+ }
1339
+ async function deletePoint(transport, collection, id) {
1340
+ const restId = parseRestPointId(id);
1341
+ const response = await transport.requestJson(
1342
+ "DELETE",
1343
+ `${collectionPath(collection)}/points/${encodeURIComponent(String(restId))}`
1344
+ );
1345
+ if (returnNullOnNotFound(response)) {
1346
+ return false;
1347
+ }
1348
+ return response.data?.deleted ?? false;
1349
+ }
1350
+ async function get(transport, collection, id) {
1351
+ const restId = parseRestPointId(id);
1352
+ const response = await transport.requestJson(
1353
+ "GET",
1354
+ `${collectionPath(collection)}/points/${encodeURIComponent(String(restId))}`
1355
+ );
1356
+ if (returnNullOnNotFound(response)) {
1357
+ return null;
1358
+ }
1359
+ return response.data ?? null;
1360
+ }
1361
+ async function isEmpty(transport, collection) {
1362
+ const response = await transport.requestJson(
1363
+ "GET",
1364
+ `${collectionPath(collection)}/empty`
1365
+ );
1366
+ throwOnError(response, `Collection '${collection}'`);
1367
+ return response.data?.is_empty ?? true;
1368
+ }
1369
+ async function flush(transport, collection) {
1370
+ const response = await transport.requestJson(
1371
+ "POST",
1372
+ `${collectionPath(collection)}/flush`
1373
+ );
1374
+ throwOnError(response, `Collection '${collection}'`);
1375
+ }
1376
+
1377
+ // src/backends/rest-http.ts
1378
+ var STATUS_ERROR_CODES = {
1379
+ 400: "BAD_REQUEST",
1380
+ 401: "UNAUTHORIZED",
1381
+ 403: "FORBIDDEN",
1382
+ 404: "NOT_FOUND",
1383
+ 409: "CONFLICT",
1384
+ 429: "RATE_LIMITED",
1385
+ 500: "INTERNAL_ERROR",
1386
+ 503: "SERVICE_UNAVAILABLE"
1387
+ };
1388
+ function mapStatusToErrorCode(status) {
1389
+ return STATUS_ERROR_CODES[status] ?? "UNKNOWN_ERROR";
1390
+ }
1391
+ function stringField(obj, ...keys) {
1392
+ for (const key of keys) {
1393
+ if (typeof obj[key] === "string") return obj[key];
1394
+ }
1395
+ return void 0;
1396
+ }
1397
+ function extractErrorPayload(data) {
1398
+ if (!data || typeof data !== "object") return {};
1399
+ const payload = data;
1400
+ const nested = typeof payload.error === "object" && payload.error ? payload.error : payload;
1401
+ return {
1402
+ code: stringField(nested, "code") ?? stringField(payload, "code"),
1403
+ message: stringField(nested, "message") ?? stringField(payload, "message", "error")
1404
+ };
1405
+ }
1406
+ function parseNodeId(value) {
1407
+ if (value === null || value === void 0) {
1408
+ return 0;
1409
+ }
1410
+ if (typeof value === "bigint") {
1411
+ return value;
1412
+ }
1413
+ if (typeof value === "string") {
1414
+ const num = Number(value);
1415
+ return num > Number.MAX_SAFE_INTEGER ? BigInt(value) : num;
1416
+ }
1417
+ if (typeof value === "number") {
1418
+ return value;
1419
+ }
1420
+ return 0;
1421
+ }
1422
+ function buildHeaders(config) {
1423
+ const headers = { "Content-Type": "application/json" };
1424
+ if (config.apiKey) headers["Authorization"] = `Bearer ${config.apiKey}`;
1425
+ return headers;
1426
+ }
1427
+ function wrapCatchError(error) {
1428
+ if (error instanceof Error && error.name === "AbortError") {
1429
+ throw new ConnectionError("Request timeout");
1430
+ }
1431
+ const message = error instanceof Error ? error.message : "Unknown error";
1432
+ const cause = error instanceof Error ? error : void 0;
1433
+ throw new ConnectionError(`Request failed: ${message}`, cause);
1434
+ }
1435
+ async function request(config, method, path, body) {
1436
+ const controller = new AbortController();
1437
+ const timeoutId = setTimeout(() => controller.abort(), config.timeout);
1438
+ try {
1439
+ const response = await fetch(`${config.baseUrl}${path}`, {
1440
+ method,
1441
+ headers: buildHeaders(config),
1442
+ body: body ? JSON.stringify(body) : void 0,
1443
+ signal: controller.signal
1444
+ });
1445
+ clearTimeout(timeoutId);
1446
+ const data = await response.json().catch(() => ({}));
1447
+ if (!response.ok) {
1448
+ const ep = extractErrorPayload(data);
1449
+ return { error: {
1450
+ code: ep.code ?? mapStatusToErrorCode(response.status),
1451
+ message: ep.message ?? `HTTP ${response.status}`
1452
+ } };
1453
+ }
1454
+ return { data };
1455
+ } catch (error) {
1456
+ clearTimeout(timeoutId);
1457
+ wrapCatchError(error);
1458
+ }
1459
+ }
1460
+ function buildBaseTransport(config) {
1461
+ return {
1462
+ requestJson: (m, p, b) => request(config, m, p, b)
1463
+ };
1464
+ }
1465
+ function buildCrudTransport(config) {
1466
+ return {
1467
+ requestJson: (m, p, b) => request(config, m, p, b)
1468
+ };
1469
+ }
1470
+ function buildSearchTransport(config) {
1471
+ return {
1472
+ requestJson: (m, p, b) => request(config, m, p, b),
1473
+ sparseToRest: (sv) => sparseVectorToRestFormat(sv)
1474
+ };
1475
+ }
1476
+ function buildQueryTransport(config) {
1477
+ return {
1478
+ requestJson: (m, p, b) => request(config, m, p, b),
1479
+ parseNodeId: (v) => parseNodeId(v)
1480
+ };
1481
+ }
1482
+ function buildStreamingTransport(config) {
1483
+ return {
1484
+ requestJson: (m, p, b) => request(config, m, p, b),
1485
+ baseUrl: config.baseUrl,
1486
+ apiKey: config.apiKey,
1487
+ timeout: config.timeout,
1488
+ parseRestPointId,
1489
+ sparseVectorToRestFormat,
1490
+ mapStatusToErrorCode: (s) => mapStatusToErrorCode(s),
1491
+ extractErrorPayload: (d) => extractErrorPayload(d)
1492
+ };
1493
+ }
1494
+ function buildAgentMemoryTransport(config, searchFn) {
1495
+ return {
1496
+ requestJson: (m, p, b) => request(config, m, p, b),
1497
+ searchVectors: (c, e, k, f2) => searchFn(c, e, { k, filter: f2 })
1498
+ };
1499
+ }
1500
+
1501
+ // src/backends/missing-endpoints.ts
1502
+ async function rebuildIndex(transport, collection) {
1503
+ const response = await transport.requestJson(
1504
+ "POST",
1505
+ `${collectionPath(collection)}/index/rebuild`
1506
+ );
1507
+ throwOnError(response, `Collection '${collection}'`);
1508
+ const data = response.data;
1509
+ return {
1510
+ message: data.message,
1511
+ collection: data.collection,
1512
+ compactedEntries: data.compacted_entries
1513
+ };
1514
+ }
1515
+ function mapGuardRailsWire(data) {
1516
+ return {
1517
+ maxDepth: data.max_depth,
1518
+ maxCardinality: data.max_cardinality,
1519
+ memoryLimitBytes: data.memory_limit_bytes,
1520
+ timeoutMs: data.timeout_ms,
1521
+ rateLimitQps: data.rate_limit_qps,
1522
+ circuitFailureThreshold: data.circuit_failure_threshold,
1523
+ circuitRecoverySeconds: data.circuit_recovery_seconds
1524
+ };
1525
+ }
1526
+ function toGuardRailsWireUpdate(req) {
1527
+ const wire = {};
1528
+ if (req.maxDepth !== void 0) wire.max_depth = req.maxDepth;
1529
+ if (req.maxCardinality !== void 0) wire.max_cardinality = req.maxCardinality;
1530
+ if (req.memoryLimitBytes !== void 0) wire.memory_limit_bytes = req.memoryLimitBytes;
1531
+ if (req.timeoutMs !== void 0) wire.timeout_ms = req.timeoutMs;
1532
+ if (req.rateLimitQps !== void 0) wire.rate_limit_qps = req.rateLimitQps;
1533
+ if (req.circuitFailureThreshold !== void 0) {
1534
+ wire.circuit_failure_threshold = req.circuitFailureThreshold;
1535
+ }
1536
+ if (req.circuitRecoverySeconds !== void 0) {
1537
+ wire.circuit_recovery_seconds = req.circuitRecoverySeconds;
1538
+ }
1539
+ return wire;
1540
+ }
1541
+ async function getGuardrails(transport) {
1542
+ const response = await transport.requestJson("GET", "/guardrails");
1543
+ throwOnError(response);
1544
+ return mapGuardRailsWire(response.data);
1545
+ }
1546
+ async function updateGuardrails(transport, req) {
1547
+ const response = await transport.requestJson(
1548
+ "PUT",
1549
+ "/guardrails",
1550
+ toGuardRailsWireUpdate(req)
1551
+ );
1552
+ throwOnError(response);
1553
+ return mapGuardRailsWire(response.data);
1554
+ }
1555
+ async function aggregate(transport, queryString, params, options) {
1556
+ const body = {
1557
+ query: queryString,
1558
+ params: params ?? {}
1559
+ };
1560
+ if (options?.collection !== void 0) {
1561
+ body.collection = options.collection;
1562
+ }
1563
+ const response = await transport.requestJson(
1564
+ "POST",
1565
+ "/aggregate",
1566
+ body
1567
+ );
1568
+ throwOnError(response);
1569
+ const data = response.data;
1570
+ return {
1571
+ result: data.result,
1572
+ timingMs: data.timing_ms,
1573
+ meta: {
1574
+ velesqlContractVersion: data.meta.velesql_contract_version,
1575
+ count: data.meta.count
1576
+ }
1577
+ };
1578
+ }
1579
+ async function matchQuery(transport, collection, queryString, params, options) {
1580
+ const body = {
1581
+ query: queryString,
1582
+ params: params ?? {}
1583
+ };
1584
+ if (options?.vector !== void 0) {
1585
+ body.vector = toNumberArray(options.vector);
1586
+ }
1587
+ if (options?.threshold !== void 0) {
1588
+ body.threshold = options.threshold;
1589
+ }
1590
+ const response = await transport.requestJson(
1591
+ "POST",
1592
+ `${collectionPath(collection)}/match`,
1593
+ body
1594
+ );
1595
+ throwOnError(response, `Collection '${collection}'`);
1596
+ const data = response.data;
1597
+ const items = data.results.map((r) => ({
1598
+ bindings: r.bindings,
1599
+ score: r.score,
1600
+ depth: r.depth,
1601
+ projected: r.projected ?? {}
1602
+ }));
1603
+ return {
1604
+ results: items,
1605
+ tookMs: data.took_ms,
1606
+ count: data.count,
1607
+ meta: { velesqlContractVersion: data.meta.velesql_contract_version }
1608
+ };
1609
+ }
1610
+ async function removeEdge(transport, collection, edgeId) {
1611
+ const response = await transport.requestJson(
1612
+ "DELETE",
1613
+ `${collectionPath(collection)}/graph/edges/${edgeId}`
1614
+ );
1615
+ if (response.error !== void 0) {
1616
+ const { code, message } = response.error;
1617
+ const err = parseVelesError(code, message);
1618
+ if (err instanceof EdgeNotFoundError) {
1619
+ return false;
1620
+ }
1621
+ if (code === "NOT_FOUND") {
1622
+ return false;
1623
+ }
1624
+ throwOnError(response, `Collection '${collection}'`);
604
1625
  }
605
- };
1626
+ return true;
1627
+ }
1628
+ async function getEdgeCount(transport, collection) {
1629
+ const response = await transport.requestJson(
1630
+ "GET",
1631
+ `${collectionPath(collection)}/graph/edges/count`
1632
+ );
1633
+ throwOnError(response, `Collection '${collection}'`);
1634
+ return response.data?.count ?? 0;
1635
+ }
1636
+ async function listNodes(transport, collection) {
1637
+ const response = await transport.requestJson(
1638
+ "GET",
1639
+ `${collectionPath(collection)}/graph/nodes`
1640
+ );
1641
+ throwOnError(response, `Collection '${collection}'`);
1642
+ const data = response.data;
1643
+ return { nodeIds: data.node_ids, count: data.count };
1644
+ }
1645
+ function idToNumber(id) {
1646
+ return typeof id === "string" ? Number(id) : id;
1647
+ }
1648
+ async function getNodeEdges(transport, collection, nodeId, options) {
1649
+ const params = new URLSearchParams();
1650
+ if (options?.direction) params.set("direction", options.direction);
1651
+ if (options?.label) params.set("label", options.label);
1652
+ const qs = params.toString();
1653
+ const url = `${collectionPath(collection)}/graph/nodes/${nodeId}/edges` + (qs ? `?${qs}` : "");
1654
+ const response = await transport.requestJson("GET", url);
1655
+ throwOnError(response, `Collection '${collection}'`);
1656
+ return (response.data?.edges ?? []).map((e) => ({
1657
+ id: idToNumber(e.id),
1658
+ source: idToNumber(e.source),
1659
+ target: idToNumber(e.target),
1660
+ label: e.label,
1661
+ properties: e.properties
1662
+ }));
1663
+ }
1664
+ async function getNodePayload(transport, collection, nodeId) {
1665
+ const response = await transport.requestJson("GET", `${collectionPath(collection)}/graph/nodes/${nodeId}/payload`);
1666
+ throwOnError(response, `Collection '${collection}'`);
1667
+ const data = response.data;
1668
+ return {
1669
+ nodeId: idToNumber(data.node_id),
1670
+ payload: data.payload
1671
+ };
1672
+ }
1673
+ async function upsertNodePayload(transport, collection, nodeId, payload) {
1674
+ const response = await transport.requestJson(
1675
+ "PUT",
1676
+ `${collectionPath(collection)}/graph/nodes/${nodeId}/payload`,
1677
+ { payload }
1678
+ );
1679
+ throwOnError(response, `Collection '${collection}'`);
1680
+ }
1681
+ async function graphSearch(transport, collection, request2) {
1682
+ const response = await transport.requestJson(
1683
+ "POST",
1684
+ `${collectionPath(collection)}/graph/search`,
1685
+ {
1686
+ vector: toNumberArray(request2.vector),
1687
+ top_k: request2.k ?? 10
1688
+ }
1689
+ );
1690
+ throwOnError(response, `Collection '${collection}'`);
1691
+ const items = (response.data?.results ?? []).map(
1692
+ (r) => ({
1693
+ id: idToNumber(r.id),
1694
+ score: r.score,
1695
+ payload: r.payload
1696
+ })
1697
+ );
1698
+ return { results: items };
1699
+ }
606
1700
 
607
1701
  // src/backends/agent-memory-backend.ts
608
1702
  var _idCounter = 0;
609
1703
  var _lastTimestamp = 0;
610
1704
  function generateUniqueId() {
611
- let now = Date.now();
1705
+ const now = Date.now();
612
1706
  if (now <= _lastTimestamp) {
613
1707
  _idCounter++;
614
1708
  if (_idCounter >= 1e3) {
@@ -689,14 +1783,23 @@ async function matchProceduralPatterns(transport, collection, embedding, k = 5)
689
1783
  return transport.searchVectors(collection, embedding, k, { _memory_type: "procedural" });
690
1784
  }
691
1785
 
1786
+ // src/search-quality.ts
1787
+ function searchQualityToMode(quality) {
1788
+ if (quality === void 0) {
1789
+ return {};
1790
+ }
1791
+ return { mode: quality };
1792
+ }
1793
+
692
1794
  // src/backends/search-backend.ts
693
- async function search(transport, collection, query2, options) {
694
- const queryVector = toNumberArray(query2);
1795
+ async function search(transport, collection, query3, options) {
1796
+ const queryVector = toNumberArray(query3);
695
1797
  const body = {
696
1798
  vector: queryVector,
697
1799
  top_k: options?.k ?? 10,
698
1800
  filter: options?.filter,
699
- include_vectors: options?.includeVectors ?? false
1801
+ include_vectors: options?.includeVectors ?? false,
1802
+ ...searchQualityToMode(options?.quality)
700
1803
  };
701
1804
  if (options?.sparseVector) {
702
1805
  body.sparse_vector = transport.sparseToRest(options.sparseVector);
@@ -713,7 +1816,8 @@ async function searchBatch(transport, collection, searches) {
713
1816
  const formattedSearches = searches.map((s) => ({
714
1817
  vector: toNumberArray(s.vector),
715
1818
  top_k: s.k ?? 10,
716
- filter: s.filter
1819
+ filter: s.filter,
1820
+ ...searchQualityToMode(s.quality)
717
1821
  }));
718
1822
  const response = await transport.requestJson(
719
1823
  "POST",
@@ -723,12 +1827,12 @@ async function searchBatch(transport, collection, searches) {
723
1827
  throwOnError(response, `Collection '${collection}'`);
724
1828
  return response.data?.results.map((r) => r.results) ?? [];
725
1829
  }
726
- async function textSearch(transport, collection, query2, options) {
1830
+ async function textSearch(transport, collection, query3, options) {
727
1831
  const response = await transport.requestJson(
728
1832
  "POST",
729
1833
  `${collectionPath(collection)}/search/text`,
730
1834
  {
731
- query: query2,
1835
+ query: query3,
732
1836
  top_k: options?.k ?? 10,
733
1837
  filter: options?.filter
734
1838
  }
@@ -771,15 +1875,16 @@ async function multiQuerySearch(transport, collection, vectors, options) {
771
1875
  throwOnError(response, `Collection '${collection}'`);
772
1876
  return response.data?.results ?? [];
773
1877
  }
774
- async function searchIds(transport, collection, query2, options) {
775
- const queryVector = toNumberArray(query2);
1878
+ async function searchIds(transport, collection, query3, options) {
1879
+ const queryVector = toNumberArray(query3);
776
1880
  const response = await transport.requestJson(
777
1881
  "POST",
778
1882
  `${collectionPath(collection)}/search/ids`,
779
1883
  {
780
1884
  vector: queryVector,
781
1885
  top_k: options?.k ?? 10,
782
- filter: options?.filter
1886
+ filter: options?.filter,
1887
+ ...searchQualityToMode(options?.quality)
783
1888
  }
784
1889
  );
785
1890
  throwOnError(response, `Collection '${collection}'`);
@@ -801,6 +1906,16 @@ async function addEdge(transport, collection, edge) {
801
1906
  );
802
1907
  throwOnError(response, `Collection '${collection}'`);
803
1908
  }
1909
+ function toGraphEdge(e) {
1910
+ const toNum = (v) => typeof v === "string" ? Number(v) : v;
1911
+ return {
1912
+ id: toNum(e.id),
1913
+ source: toNum(e.source),
1914
+ target: toNum(e.target),
1915
+ label: e.label,
1916
+ properties: e.properties
1917
+ };
1918
+ }
804
1919
  async function getEdges(transport, collection, options) {
805
1920
  const queryParams = options?.label ? `?label=${encodeURIComponent(options.label)}` : "";
806
1921
  const response = await transport.requestJson(
@@ -808,19 +1923,19 @@ async function getEdges(transport, collection, options) {
808
1923
  `${collectionPath(collection)}/graph/edges${queryParams}`
809
1924
  );
810
1925
  throwOnError(response, `Collection '${collection}'`);
811
- return response.data?.edges ?? [];
1926
+ return (response.data?.edges ?? []).map(toGraphEdge);
812
1927
  }
813
- async function traverseGraph(transport, collection, request) {
1928
+ async function traverseGraph(transport, collection, request2) {
814
1929
  const response = await transport.requestJson(
815
1930
  "POST",
816
1931
  `${collectionPath(collection)}/graph/traverse`,
817
1932
  {
818
- source: request.source,
819
- strategy: request.strategy ?? "bfs",
820
- max_depth: request.maxDepth ?? 3,
821
- limit: request.limit ?? 100,
822
- cursor: request.cursor,
823
- rel_types: request.relTypes ?? []
1933
+ source: request2.source,
1934
+ strategy: request2.strategy ?? "bfs",
1935
+ max_depth: request2.maxDepth ?? 3,
1936
+ limit: request2.limit ?? 100,
1937
+ cursor: request2.cursor,
1938
+ rel_types: request2.relTypes ?? []
824
1939
  }
825
1940
  );
826
1941
  throwOnError(response, `Collection '${collection}'`);
@@ -860,15 +1975,15 @@ async function createGraphCollection(transport, name, config) {
860
1975
  });
861
1976
  throwOnError(response);
862
1977
  }
863
- async function traverseParallel(transport, collection, request) {
1978
+ async function traverseParallel(transport, collection, request2) {
864
1979
  const response = await transport.requestJson(
865
1980
  "POST",
866
1981
  `${collectionPath(collection)}/graph/traverse/parallel`,
867
1982
  {
868
- sources: request.sources,
869
- max_depth: request.maxDepth ?? 3,
870
- limit: request.limit ?? 100,
871
- rel_types: request.relTypes ?? []
1983
+ sources: request2.sources,
1984
+ max_depth: request2.maxDepth ?? 3,
1985
+ limit: request2.limit ?? 100,
1986
+ rel_types: request2.relTypes ?? []
872
1987
  }
873
1988
  );
874
1989
  throwOnError(response, `Collection '${collection}'`);
@@ -931,14 +2046,18 @@ async function query(transport, collection, queryString, params, options) {
931
2046
  }
932
2047
  };
933
2048
  }
934
- async function queryExplain(transport, queryString, params) {
2049
+ async function queryExplain(transport, queryString, params, options) {
2050
+ const body = {
2051
+ query: queryString,
2052
+ params: params ?? {}
2053
+ };
2054
+ if (options?.analyze) {
2055
+ body.analyze = true;
2056
+ }
935
2057
  const response = await transport.requestJson(
936
2058
  "POST",
937
2059
  "/query/explain",
938
- {
939
- query: queryString,
940
- params: params ?? {}
941
- }
2060
+ body
942
2061
  );
943
2062
  throwOnError(response);
944
2063
  const data = response.data;
@@ -950,7 +2069,8 @@ async function queryExplain(transport, queryString, params) {
950
2069
  step: step.step,
951
2070
  operation: step.operation,
952
2071
  description: step.description,
953
- estimatedRows: step.estimated_rows
2072
+ estimatedRows: step.estimated_rows,
2073
+ estimationMethod: step.estimation_method ?? null
954
2074
  })),
955
2075
  estimatedCost: {
956
2076
  usesIndex: data.estimated_cost.uses_index,
@@ -968,7 +2088,22 @@ async function queryExplain(transport, queryString, params) {
968
2088
  hasFusion: data.features.has_fusion,
969
2089
  limit: data.features.limit,
970
2090
  offset: data.features.offset
971
- }
2091
+ },
2092
+ actualStats: data.actual_stats ? {
2093
+ actualRows: data.actual_stats.actual_rows,
2094
+ actualTimeMs: data.actual_stats.actual_time_ms,
2095
+ loops: data.actual_stats.loops,
2096
+ nodesVisited: data.actual_stats.nodes_visited,
2097
+ edgesTraversed: data.actual_stats.edges_traversed
2098
+ } : data.actual_stats === null ? null : void 0,
2099
+ nodeStats: data.node_stats ? data.node_stats.map((ns) => ({
2100
+ nodeLabel: ns.node_label,
2101
+ actualTimeMs: ns.actual_time_ms,
2102
+ actualRowsIn: ns.actual_rows_in,
2103
+ actualRowsOut: ns.actual_rows_out,
2104
+ loops: ns.loops,
2105
+ estimated: ns.estimated
2106
+ })) : data.node_stats === null ? null : void 0
972
2107
  };
973
2108
  }
974
2109
  async function collectionSanity(transport, collection) {
@@ -999,8 +2134,49 @@ async function collectionSanity(transport, collection) {
999
2134
  };
1000
2135
  }
1001
2136
 
2137
+ // src/backends/scroll-backend.ts
2138
+ async function scroll(transport, collection, request2) {
2139
+ const body = {};
2140
+ if (request2?.cursor !== void 0) {
2141
+ body.cursor = request2.cursor;
2142
+ }
2143
+ if (request2?.batchSize !== void 0) {
2144
+ body.batch_size = request2.batchSize;
2145
+ }
2146
+ if (request2?.filter !== void 0) {
2147
+ body.filter = request2.filter;
2148
+ }
2149
+ const response = await transport.requestJson(
2150
+ "POST",
2151
+ `${collectionPath(collection)}/points/scroll`,
2152
+ body
2153
+ );
2154
+ throwOnError(response, `Collection '${collection}'`);
2155
+ const data = response.data;
2156
+ return {
2157
+ points: data.points,
2158
+ nextCursor: data.next_cursor
2159
+ };
2160
+ }
2161
+
1002
2162
  // src/backends/admin-backend.ts
1003
2163
  function mapStatsResponse(data) {
2164
+ let columnStats;
2165
+ if (data.column_stats) {
2166
+ columnStats = {};
2167
+ for (const [key, col] of Object.entries(data.column_stats)) {
2168
+ columnStats[key] = {
2169
+ name: col.name,
2170
+ nullCount: col.null_count,
2171
+ distinctCount: col.distinct_count,
2172
+ minValue: col.min_value,
2173
+ maxValue: col.max_value,
2174
+ avgSizeBytes: col.avg_size_bytes,
2175
+ histogramBuckets: col.histogram_buckets,
2176
+ histogramStale: col.histogram_stale
2177
+ };
2178
+ }
2179
+ }
1004
2180
  return {
1005
2181
  totalPoints: data.total_points,
1006
2182
  totalSizeBytes: data.total_size_bytes,
@@ -1008,7 +2184,8 @@ function mapStatsResponse(data) {
1008
2184
  deletedCount: data.deleted_count,
1009
2185
  avgRowSizeBytes: data.avg_row_size_bytes,
1010
2186
  payloadSizeBytes: data.payload_size_bytes,
1011
- lastAnalyzedEpochMs: data.last_analyzed_epoch_ms
2187
+ lastAnalyzedEpochMs: data.last_analyzed_epoch_ms,
2188
+ columnStats
1012
2189
  };
1013
2190
  }
1014
2191
  async function getCollectionStats(transport, collection) {
@@ -1029,10 +2206,7 @@ async function analyzeCollection(transport, collection) {
1029
2206
  throwOnError(response, `Collection '${collection}'`);
1030
2207
  return mapStatsResponse(response.data);
1031
2208
  }
1032
- async function getCollectionConfig(transport, collection) {
1033
- const response = await transport.requestJson("GET", `${collectionPath(collection)}/config`);
1034
- throwOnError(response, `Collection '${collection}'`);
1035
- const data = response.data;
2209
+ function mapConfigResponse(data) {
1036
2210
  return {
1037
2211
  name: data.name,
1038
2212
  dimension: data.dimension,
@@ -1041,9 +2215,22 @@ async function getCollectionConfig(transport, collection) {
1041
2215
  pointCount: data.point_count,
1042
2216
  metadataOnly: data.metadata_only,
1043
2217
  graphSchema: data.graph_schema,
1044
- embeddingDimension: data.embedding_dimension
2218
+ embeddingDimension: data.embedding_dimension,
2219
+ schemaVersion: data.schema_version,
2220
+ pqRescoreOversampling: data.pq_rescore_oversampling,
2221
+ hnswParams: data.hnsw_params,
2222
+ deferredIndexing: data.deferred_indexing,
2223
+ asyncIndexBuilder: data.async_index_builder
1045
2224
  };
1046
2225
  }
2226
+ async function getCollectionConfig(transport, collection) {
2227
+ const response = await transport.requestJson(
2228
+ "GET",
2229
+ `${collectionPath(collection)}/config`
2230
+ );
2231
+ throwOnError(response, `Collection '${collection}'`);
2232
+ return mapConfigResponse(response.data);
2233
+ }
1047
2234
 
1048
2235
  // src/backends/index-backend.ts
1049
2236
  async function createIndex(transport, collection, options) {
@@ -1088,208 +2275,160 @@ async function dropIndex(transport, collection, label, property) {
1088
2275
  }
1089
2276
 
1090
2277
  // src/backends/streaming-backend.ts
1091
- async function trainPq(transport, collection, options) {
1092
- const m = options?.m ?? 8;
1093
- const k = options?.k ?? 256;
1094
- const withClause = options?.opq ? `WITH (m=${m}, k=${k}, opq=true)` : `WITH (m=${m}, k=${k})`;
1095
- const queryString = `TRAIN QUANTIZER ON ${collection} ${withClause}`;
1096
- const response = await transport.requestJson(
1097
- "POST",
1098
- "/query",
1099
- { query: queryString }
1100
- );
1101
- throwOnError(response);
1102
- return response.data?.message ?? "PQ training initiated";
1103
- }
1104
- async function streamInsert(transport, collection, docs) {
1105
- for (const doc of docs) {
1106
- const restId = transport.parseRestPointId(doc.id);
1107
- const vector = toNumberArray(doc.vector);
1108
- const body = {
1109
- id: restId,
1110
- vector,
1111
- payload: doc.payload
1112
- };
1113
- if (doc.sparseVector) {
1114
- body.sparse_vector = transport.sparseVectorToRestFormat(doc.sparseVector);
1115
- }
1116
- const url = `${transport.baseUrl}${collectionPath(collection)}/stream/insert`;
1117
- const headers = {
1118
- "Content-Type": "application/json"
1119
- };
1120
- if (transport.apiKey) {
1121
- headers["Authorization"] = `Bearer ${transport.apiKey}`;
1122
- }
1123
- const controller = new AbortController();
1124
- const timeoutId = setTimeout(() => controller.abort(), transport.timeout);
1125
- try {
1126
- const response = await fetch(url, {
1127
- method: "POST",
1128
- headers,
1129
- body: JSON.stringify(body),
1130
- signal: controller.signal
1131
- });
1132
- clearTimeout(timeoutId);
1133
- if (response.status === 429) {
1134
- throw new BackpressureError();
1135
- }
1136
- if (!response.ok && response.status !== 202) {
1137
- const data = await response.json().catch(() => ({}));
1138
- const errorPayload = transport.extractErrorPayload(data);
1139
- throw new VelesDBError(
1140
- errorPayload.message ?? `HTTP ${response.status}`,
1141
- errorPayload.code ?? transport.mapStatusToErrorCode(response.status)
1142
- );
1143
- }
1144
- } catch (error) {
1145
- clearTimeout(timeoutId);
1146
- if (error instanceof BackpressureError || error instanceof VelesDBError) {
1147
- throw error;
1148
- }
1149
- if (error instanceof Error && error.name === "AbortError") {
1150
- throw new ConnectionError("Request timeout");
1151
- }
1152
- throw new ConnectionError(
1153
- `Stream insert failed: ${error instanceof Error ? error.message : "Unknown error"}`,
1154
- error instanceof Error ? error : void 0
1155
- );
1156
- }
1157
- }
1158
- }
1159
-
1160
- // src/backends/crud-backend.ts
1161
- function parseRestPointId(id) {
1162
- if (typeof id !== "number" || !Number.isFinite(id) || id < 0 || !Number.isInteger(id) || id > Number.MAX_SAFE_INTEGER) {
1163
- throw new ValidationError(
1164
- `REST backend requires numeric u64-compatible IDs in JS safe integer range (0..${Number.MAX_SAFE_INTEGER}). Received: ${String(id)}`
1165
- );
1166
- }
1167
- return id;
1168
- }
1169
- function sparseVectorToRestFormat(sv) {
1170
- const result = {};
1171
- for (const [k, v] of Object.entries(sv)) {
1172
- result[String(k)] = v;
1173
- }
1174
- return result;
1175
- }
1176
- async function createCollection(transport, name, config) {
1177
- const response = await transport.requestJson("POST", "/collections", {
1178
- name,
1179
- dimension: config.dimension,
1180
- metric: config.metric ?? "cosine",
1181
- storage_mode: config.storageMode ?? "full",
1182
- collection_type: config.collectionType ?? "vector",
1183
- description: config.description,
1184
- hnsw_m: config.hnsw?.m,
1185
- hnsw_ef_construction: config.hnsw?.efConstruction
1186
- });
1187
- throwOnError(response);
1188
- }
1189
- async function deleteCollection(transport, name) {
1190
- const response = await transport.requestJson(
1191
- "DELETE",
1192
- collectionPath(name)
1193
- );
1194
- throwOnError(response, `Collection '${name}'`);
1195
- }
1196
- async function getCollection(transport, name) {
1197
- const response = await transport.requestJson(
1198
- "GET",
1199
- collectionPath(name)
1200
- );
1201
- if (returnNullOnNotFound(response)) {
1202
- return null;
1203
- }
1204
- return response.data ?? null;
1205
- }
1206
- async function listCollections(transport) {
1207
- const response = await transport.requestJson("GET", "/collections");
1208
- throwOnError(response);
1209
- return response.data ?? [];
1210
- }
1211
- async function insert(transport, collection, doc) {
1212
- const restId = parseRestPointId(doc.id);
1213
- const vector = toNumberArray(doc.vector);
1214
- const response = await transport.requestJson(
1215
- "POST",
1216
- `${collectionPath(collection)}/points`,
1217
- { points: [{ id: restId, vector, payload: doc.payload }] }
1218
- );
1219
- throwOnError(response, `Collection '${collection}'`);
1220
- }
1221
- async function insertBatch(transport, collection, docs) {
1222
- const vectors = docs.map((doc) => ({
1223
- id: parseRestPointId(doc.id),
1224
- vector: toNumberArray(doc.vector),
1225
- payload: doc.payload
1226
- }));
1227
- const response = await transport.requestJson(
1228
- "POST",
1229
- `${collectionPath(collection)}/points`,
1230
- { points: vectors }
1231
- );
1232
- throwOnError(response, `Collection '${collection}'`);
1233
- }
1234
- async function deletePoint(transport, collection, id) {
1235
- const restId = parseRestPointId(id);
1236
- const response = await transport.requestJson(
1237
- "DELETE",
1238
- `${collectionPath(collection)}/points/${encodeURIComponent(String(restId))}`
1239
- );
1240
- if (returnNullOnNotFound(response)) {
1241
- return false;
1242
- }
1243
- return response.data?.deleted ?? false;
1244
- }
1245
- async function get(transport, collection, id) {
1246
- const restId = parseRestPointId(id);
1247
- const response = await transport.requestJson(
1248
- "GET",
1249
- `${collectionPath(collection)}/points/${encodeURIComponent(String(restId))}`
1250
- );
1251
- if (returnNullOnNotFound(response)) {
1252
- return null;
1253
- }
1254
- return response.data ?? null;
1255
- }
1256
- async function isEmpty(transport, collection) {
1257
- const response = await transport.requestJson(
1258
- "GET",
1259
- `${collectionPath(collection)}/empty`
1260
- );
1261
- throwOnError(response, `Collection '${collection}'`);
1262
- return response.data?.is_empty ?? true;
1263
- }
1264
- async function flush(transport, collection) {
2278
+ async function trainPq(transport, collection, options) {
2279
+ validateCollectionName(collection);
2280
+ const m = options?.m ?? 8;
2281
+ const k = options?.k ?? 256;
2282
+ const withClause = options?.opq ? `WITH (m=${m}, k=${k}, opq=true)` : `WITH (m=${m}, k=${k})`;
2283
+ const queryString = `TRAIN QUANTIZER ON ${collection} ${withClause}`;
1265
2284
  const response = await transport.requestJson(
1266
2285
  "POST",
1267
- `${collectionPath(collection)}/flush`
2286
+ "/query",
2287
+ { query: queryString }
1268
2288
  );
1269
- throwOnError(response, `Collection '${collection}'`);
2289
+ throwOnError(response);
2290
+ return response.data?.message ?? "PQ training initiated";
2291
+ }
2292
+ async function streamInsert(transport, collection, docs) {
2293
+ for (const doc of docs) {
2294
+ const restId = transport.parseRestPointId(doc.id);
2295
+ const vector = toNumberArray(doc.vector);
2296
+ const body = {
2297
+ id: restId,
2298
+ vector,
2299
+ payload: doc.payload ?? null
2300
+ };
2301
+ if (doc.sparseVector) {
2302
+ body.sparse_vector = transport.sparseVectorToRestFormat(doc.sparseVector);
2303
+ }
2304
+ const url = `${transport.baseUrl}${collectionPath(collection)}/stream/insert`;
2305
+ const headers = {
2306
+ "Content-Type": "application/json"
2307
+ };
2308
+ if (transport.apiKey) {
2309
+ headers["Authorization"] = `Bearer ${transport.apiKey}`;
2310
+ }
2311
+ const controller = new AbortController();
2312
+ const timeoutId = setTimeout(() => controller.abort(), transport.timeout);
2313
+ try {
2314
+ const response = await fetch(url, {
2315
+ method: "POST",
2316
+ headers,
2317
+ body: JSON.stringify(body),
2318
+ signal: controller.signal
2319
+ });
2320
+ clearTimeout(timeoutId);
2321
+ if (response.status === 429) {
2322
+ throw new BackpressureError();
2323
+ }
2324
+ if (!response.ok && response.status !== 202) {
2325
+ const data = await response.json().catch(() => ({}));
2326
+ const errorPayload = transport.extractErrorPayload(data);
2327
+ throw new VelesDBError(
2328
+ errorPayload.message ?? `HTTP ${response.status}`,
2329
+ errorPayload.code ?? transport.mapStatusToErrorCode(response.status)
2330
+ );
2331
+ }
2332
+ } catch (error) {
2333
+ clearTimeout(timeoutId);
2334
+ if (error instanceof BackpressureError || error instanceof VelesDBError) {
2335
+ throw error;
2336
+ }
2337
+ if (error instanceof Error && error.name === "AbortError") {
2338
+ throw new ConnectionError("Request timeout");
2339
+ }
2340
+ throw new ConnectionError(
2341
+ `Stream insert failed: ${error instanceof Error ? error.message : "Unknown error"}`,
2342
+ error instanceof Error ? error : void 0
2343
+ );
2344
+ }
2345
+ }
2346
+ }
2347
+ async function streamUpsertPoints(transport, collection, docs) {
2348
+ const ndjsonLines = docs.map((doc) => {
2349
+ const restId = transport.parseRestPointId(doc.id);
2350
+ const vector = toNumberArray(doc.vector);
2351
+ const point = {
2352
+ id: restId,
2353
+ vector,
2354
+ payload: doc.payload ?? null
2355
+ };
2356
+ if (doc.sparseVector) {
2357
+ point.sparse_vector = transport.sparseVectorToRestFormat(doc.sparseVector);
2358
+ }
2359
+ return JSON.stringify(point);
2360
+ });
2361
+ const body = ndjsonLines.join("\n");
2362
+ const url = `${transport.baseUrl}${collectionPath(collection)}/points/stream`;
2363
+ const headers = {
2364
+ "Content-Type": "application/x-ndjson"
2365
+ };
2366
+ if (transport.apiKey) {
2367
+ headers["Authorization"] = `Bearer ${transport.apiKey}`;
2368
+ }
2369
+ const controller = new AbortController();
2370
+ const timeoutId = setTimeout(() => controller.abort(), transport.timeout);
2371
+ try {
2372
+ const response = await fetch(url, {
2373
+ method: "POST",
2374
+ headers,
2375
+ body,
2376
+ signal: controller.signal
2377
+ });
2378
+ clearTimeout(timeoutId);
2379
+ if (response.status === 429) {
2380
+ throw new BackpressureError();
2381
+ }
2382
+ if (!response.ok) {
2383
+ const data2 = await response.json().catch(() => ({}));
2384
+ const errorPayload = transport.extractErrorPayload(data2);
2385
+ throw new VelesDBError(
2386
+ errorPayload.message ?? `HTTP ${response.status}`,
2387
+ errorPayload.code ?? transport.mapStatusToErrorCode(response.status)
2388
+ );
2389
+ }
2390
+ const data = await response.json().catch(() => ({}));
2391
+ return {
2392
+ message: typeof data.message === "string" ? data.message : "Stream processed",
2393
+ inserted: typeof data.inserted === "number" ? data.inserted : 0,
2394
+ malformed: typeof data.malformed === "number" ? data.malformed : 0,
2395
+ failedUpserts: typeof data.failed_upserts === "number" ? data.failed_upserts : 0,
2396
+ networkErrors: typeof data.network_errors === "number" ? data.network_errors : 0
2397
+ };
2398
+ } catch (error) {
2399
+ clearTimeout(timeoutId);
2400
+ if (error instanceof BackpressureError || error instanceof VelesDBError) {
2401
+ throw error;
2402
+ }
2403
+ if (error instanceof Error && error.name === "AbortError") {
2404
+ throw new ConnectionError("Request timeout");
2405
+ }
2406
+ throw new ConnectionError(
2407
+ `Stream upsert failed: ${error instanceof Error ? error.message : "Unknown error"}`,
2408
+ error instanceof Error ? error : void 0
2409
+ );
2410
+ }
1270
2411
  }
1271
2412
 
1272
2413
  // src/backends/rest.ts
1273
2414
  var RestBackend = class {
1274
2415
  constructor(url, apiKey, timeout = 3e4) {
1275
2416
  this._initialized = false;
1276
- this.baseUrl = url.replace(/\/$/, "");
1277
- this.apiKey = apiKey;
1278
- this.timeout = timeout;
2417
+ this.httpConfig = { baseUrl: url.replace(/\/$/, ""), apiKey, timeout };
1279
2418
  }
1280
2419
  async init() {
1281
2420
  if (this._initialized) {
1282
2421
  return;
1283
2422
  }
1284
2423
  try {
1285
- const response = await this.request("GET", "/health");
2424
+ const response = await request(this.httpConfig, "GET", "/health");
1286
2425
  if (response.error) {
1287
2426
  throw new Error(response.error.message);
1288
2427
  }
1289
2428
  this._initialized = true;
1290
2429
  } catch (error) {
1291
2430
  throw new ConnectionError(
1292
- `Failed to connect to VelesDB server at ${this.baseUrl}`,
2431
+ `Failed to connect to VelesDB server at ${this.httpConfig.baseUrl}`,
1293
2432
  error instanceof Error ? error : void 0
1294
2433
  );
1295
2434
  }
@@ -1297,320 +2436,242 @@ var RestBackend = class {
1297
2436
  isInitialized() {
1298
2437
  return this._initialized;
1299
2438
  }
2439
+ capabilities() {
2440
+ return REST_CAPABILITIES;
2441
+ }
2442
+ async close() {
2443
+ this._initialized = false;
2444
+ }
1300
2445
  ensureInitialized() {
1301
2446
  if (!this._initialized) {
1302
2447
  throw new ConnectionError("REST backend not initialized");
1303
2448
  }
1304
2449
  }
1305
- mapStatusToErrorCode(status) {
1306
- switch (status) {
1307
- case 400:
1308
- return "BAD_REQUEST";
1309
- case 401:
1310
- return "UNAUTHORIZED";
1311
- case 403:
1312
- return "FORBIDDEN";
1313
- case 404:
1314
- return "NOT_FOUND";
1315
- case 409:
1316
- return "CONFLICT";
1317
- case 429:
1318
- return "RATE_LIMITED";
1319
- case 500:
1320
- return "INTERNAL_ERROR";
1321
- case 503:
1322
- return "SERVICE_UNAVAILABLE";
1323
- default:
1324
- return "UNKNOWN_ERROR";
1325
- }
2450
+ // Collection CRUD
2451
+ async createCollection(n, c) {
2452
+ this.ensureInitialized();
2453
+ return createCollection(buildCrudTransport(this.httpConfig), n, c);
1326
2454
  }
1327
- extractErrorPayload(data) {
1328
- if (!data || typeof data !== "object") {
1329
- return {};
1330
- }
1331
- const payload = data;
1332
- const nestedError = payload.error && typeof payload.error === "object" ? payload.error : void 0;
1333
- const codeField = nestedError?.code ?? payload.code;
1334
- const code = typeof codeField === "string" ? codeField : void 0;
1335
- const messageField = nestedError?.message ?? payload.message ?? payload.error;
1336
- const message = typeof messageField === "string" ? messageField : void 0;
1337
- return { code, message };
2455
+ async deleteCollection(n) {
2456
+ this.ensureInitialized();
2457
+ return deleteCollection(buildCrudTransport(this.httpConfig), n);
1338
2458
  }
1339
- parseNodeId(value) {
1340
- if (value === null || value === void 0) {
1341
- return 0;
1342
- }
1343
- if (typeof value === "bigint") {
1344
- return value;
1345
- }
1346
- if (typeof value === "string") {
1347
- const num = Number(value);
1348
- return num > Number.MAX_SAFE_INTEGER ? BigInt(value) : num;
1349
- }
1350
- if (typeof value === "number") {
1351
- return value;
1352
- }
1353
- return 0;
2459
+ async getCollection(n) {
2460
+ this.ensureInitialized();
2461
+ return getCollection(buildCrudTransport(this.httpConfig), n);
1354
2462
  }
1355
- async request(method, path, body) {
1356
- const url = `${this.baseUrl}${path}`;
1357
- const headers = { "Content-Type": "application/json" };
1358
- if (this.apiKey) {
1359
- headers["Authorization"] = `Bearer ${this.apiKey}`;
1360
- }
1361
- const controller = new AbortController();
1362
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
1363
- try {
1364
- const response = await fetch(url, {
1365
- method,
1366
- headers,
1367
- body: body ? JSON.stringify(body) : void 0,
1368
- signal: controller.signal
1369
- });
1370
- clearTimeout(timeoutId);
1371
- const data = await response.json().catch(() => ({}));
1372
- if (!response.ok) {
1373
- const errorPayload = this.extractErrorPayload(data);
1374
- return {
1375
- error: {
1376
- code: errorPayload.code ?? this.mapStatusToErrorCode(response.status),
1377
- message: errorPayload.message ?? `HTTP ${response.status}`
1378
- }
1379
- };
1380
- }
1381
- return { data };
1382
- } catch (error) {
1383
- clearTimeout(timeoutId);
1384
- if (error instanceof Error && error.name === "AbortError") {
1385
- throw new ConnectionError("Request timeout");
1386
- }
1387
- throw new ConnectionError(
1388
- `Request failed: ${error instanceof Error ? error.message : "Unknown error"}`,
1389
- error instanceof Error ? error : void 0
1390
- );
1391
- }
2463
+ async listCollections() {
2464
+ this.ensureInitialized();
2465
+ return listCollections(buildCrudTransport(this.httpConfig));
1392
2466
  }
1393
- // ==========================================================================
1394
- // Transport adapters
1395
- // ==========================================================================
1396
- asCrudTransport() {
1397
- return {
1398
- requestJson: (m, p, b) => this.request(m, p, b)
1399
- };
2467
+ async upsert(c, d) {
2468
+ this.ensureInitialized();
2469
+ return upsert(buildCrudTransport(this.httpConfig), c, d);
1400
2470
  }
1401
- asSearchTransport() {
1402
- return {
1403
- requestJson: (m, p, b) => this.request(m, p, b),
1404
- sparseToRest: (sv) => sparseVectorToRestFormat(sv)
1405
- };
2471
+ async upsertBatch(c, d) {
2472
+ this.ensureInitialized();
2473
+ return upsertBatch(buildCrudTransport(this.httpConfig), c, d);
1406
2474
  }
1407
- asAgentMemoryTransport() {
1408
- return {
1409
- requestJson: (m, p, b) => this.request(m, p, b),
1410
- searchVectors: (c, e, k, f) => this.search(c, e, { k, filter: f })
1411
- };
2475
+ async delete(c, id) {
2476
+ this.ensureInitialized();
2477
+ return deletePoint(buildCrudTransport(this.httpConfig), c, id);
1412
2478
  }
1413
- asQueryTransport() {
1414
- return {
1415
- requestJson: (m, p, b) => this.request(m, p, b),
1416
- parseNodeId: (v) => this.parseNodeId(v)
1417
- };
2479
+ async get(c, id) {
2480
+ this.ensureInitialized();
2481
+ return get(buildCrudTransport(this.httpConfig), c, id);
1418
2482
  }
1419
- asStreamingTransport() {
1420
- return {
1421
- requestJson: (m, p, b) => this.request(m, p, b),
1422
- baseUrl: this.baseUrl,
1423
- apiKey: this.apiKey,
1424
- timeout: this.timeout,
1425
- parseRestPointId,
1426
- sparseVectorToRestFormat,
1427
- mapStatusToErrorCode: (s) => this.mapStatusToErrorCode(s),
1428
- extractErrorPayload: (d) => this.extractErrorPayload(d)
1429
- };
2483
+ async isEmpty(c) {
2484
+ this.ensureInitialized();
2485
+ return isEmpty(buildCrudTransport(this.httpConfig), c);
1430
2486
  }
1431
- // ==========================================================================
1432
- // Collection CRUD — delegates to crud-backend.ts
1433
- // ==========================================================================
1434
- async createCollection(name, config) {
2487
+ async flush(c) {
1435
2488
  this.ensureInitialized();
1436
- return createCollection(this.asCrudTransport(), name, config);
2489
+ return flush(buildCrudTransport(this.httpConfig), c);
1437
2490
  }
1438
- async deleteCollection(name) {
2491
+ // Additional REST endpoints (Sprint 2 Wave 4)
2492
+ async rebuildIndex(c) {
1439
2493
  this.ensureInitialized();
1440
- return deleteCollection(this.asCrudTransport(), name);
2494
+ return rebuildIndex(buildBaseTransport(this.httpConfig), c);
1441
2495
  }
1442
- async getCollection(name) {
2496
+ async getGuardrails() {
1443
2497
  this.ensureInitialized();
1444
- return getCollection(this.asCrudTransport(), name);
2498
+ return getGuardrails(buildBaseTransport(this.httpConfig));
1445
2499
  }
1446
- async listCollections() {
2500
+ async updateGuardrails(r) {
1447
2501
  this.ensureInitialized();
1448
- return listCollections(this.asCrudTransport());
2502
+ return updateGuardrails(buildBaseTransport(this.httpConfig), r);
1449
2503
  }
1450
- async insert(collection, doc) {
2504
+ async aggregate(q, p, o) {
1451
2505
  this.ensureInitialized();
1452
- return insert(this.asCrudTransport(), collection, doc);
2506
+ return aggregate(buildBaseTransport(this.httpConfig), q, p, o);
1453
2507
  }
1454
- async insertBatch(collection, docs) {
2508
+ async matchQuery(c, q, p, o) {
1455
2509
  this.ensureInitialized();
1456
- return insertBatch(this.asCrudTransport(), collection, docs);
2510
+ return matchQuery(buildBaseTransport(this.httpConfig), c, q, p, o);
1457
2511
  }
1458
- async delete(collection, id) {
2512
+ async removeEdge(c, id) {
1459
2513
  this.ensureInitialized();
1460
- return deletePoint(this.asCrudTransport(), collection, id);
2514
+ return removeEdge(buildBaseTransport(this.httpConfig), c, id);
1461
2515
  }
1462
- async get(collection, id) {
2516
+ async getEdgeCount(c) {
1463
2517
  this.ensureInitialized();
1464
- return get(this.asCrudTransport(), collection, id);
2518
+ return getEdgeCount(buildBaseTransport(this.httpConfig), c);
1465
2519
  }
1466
- async isEmpty(collection) {
2520
+ async listNodes(c) {
1467
2521
  this.ensureInitialized();
1468
- return isEmpty(this.asCrudTransport(), collection);
2522
+ return listNodes(buildBaseTransport(this.httpConfig), c);
1469
2523
  }
1470
- async flush(collection) {
2524
+ async getNodeEdges(c, id, o) {
1471
2525
  this.ensureInitialized();
1472
- return flush(this.asCrudTransport(), collection);
2526
+ return getNodeEdges(buildBaseTransport(this.httpConfig), c, id, o);
1473
2527
  }
1474
- async close() {
1475
- this._initialized = false;
2528
+ async getNodePayload(c, id) {
2529
+ this.ensureInitialized();
2530
+ return getNodePayload(buildBaseTransport(this.httpConfig), c, id);
2531
+ }
2532
+ async upsertNodePayload(c, id, p) {
2533
+ this.ensureInitialized();
2534
+ return upsertNodePayload(buildBaseTransport(this.httpConfig), c, id, p);
2535
+ }
2536
+ async graphSearch(c, r) {
2537
+ this.ensureInitialized();
2538
+ return graphSearch(buildBaseTransport(this.httpConfig), c, r);
1476
2539
  }
1477
- // ==========================================================================
1478
- // Search — delegates to search-backend.ts
1479
- // ==========================================================================
2540
+ // Search
1480
2541
  async search(c, q, o) {
1481
2542
  this.ensureInitialized();
1482
- return search(this.asSearchTransport(), c, q, o);
2543
+ return search(buildSearchTransport(this.httpConfig), c, q, o);
1483
2544
  }
1484
- async searchBatch(collection, searches) {
2545
+ async searchBatch(c, s) {
1485
2546
  this.ensureInitialized();
1486
- return searchBatch(this.asSearchTransport(), collection, searches);
2547
+ return searchBatch(buildSearchTransport(this.httpConfig), c, s);
1487
2548
  }
1488
2549
  async textSearch(c, q, o) {
1489
2550
  this.ensureInitialized();
1490
- return textSearch(this.asSearchTransport(), c, q, o);
2551
+ return textSearch(buildSearchTransport(this.httpConfig), c, q, o);
1491
2552
  }
1492
2553
  async hybridSearch(c, v, t, o) {
1493
2554
  this.ensureInitialized();
1494
- return hybridSearch(this.asSearchTransport(), c, v, t, o);
2555
+ return hybridSearch(buildSearchTransport(this.httpConfig), c, v, t, o);
1495
2556
  }
1496
2557
  async multiQuerySearch(c, v, o) {
1497
2558
  this.ensureInitialized();
1498
- return multiQuerySearch(this.asSearchTransport(), c, v, o);
2559
+ return multiQuerySearch(buildSearchTransport(this.httpConfig), c, v, o);
1499
2560
  }
1500
2561
  async searchIds(c, q, o) {
1501
2562
  this.ensureInitialized();
1502
- return searchIds(this.asSearchTransport(), c, q, o);
2563
+ return searchIds(buildSearchTransport(this.httpConfig), c, q, o);
1503
2564
  }
1504
- // ==========================================================================
1505
- // Query — delegates to query-backend.ts
1506
- // ==========================================================================
2565
+ // Query
1507
2566
  async query(c, q, p, o) {
1508
2567
  this.ensureInitialized();
1509
- return query(this.asQueryTransport(), c, q, p, o);
2568
+ return query(buildQueryTransport(this.httpConfig), c, q, p, o);
1510
2569
  }
1511
- async queryExplain(q, p) {
2570
+ async queryExplain(q, p, o) {
1512
2571
  this.ensureInitialized();
1513
- return queryExplain(this.asQueryTransport(), q, p);
2572
+ return queryExplain(buildQueryTransport(this.httpConfig), q, p, o);
1514
2573
  }
1515
- async collectionSanity(collection) {
2574
+ async collectionSanity(c) {
1516
2575
  this.ensureInitialized();
1517
- return collectionSanity(this.asQueryTransport(), collection);
2576
+ return collectionSanity(buildQueryTransport(this.httpConfig), c);
1518
2577
  }
1519
- // ==========================================================================
1520
- // Graph delegates to graph-backend.ts
1521
- // ==========================================================================
1522
- async addEdge(collection, edge) {
2578
+ // Scroll
2579
+ async scroll(c, r) {
1523
2580
  this.ensureInitialized();
1524
- return addEdge(this.asCrudTransport(), collection, edge);
2581
+ return scroll(buildCrudTransport(this.httpConfig), c, r);
1525
2582
  }
1526
- async getEdges(collection, options) {
2583
+ // Graph
2584
+ async addEdge(c, e) {
1527
2585
  this.ensureInitialized();
1528
- return getEdges(this.asCrudTransport(), collection, options);
2586
+ return addEdge(buildCrudTransport(this.httpConfig), c, e);
1529
2587
  }
1530
- async traverseGraph(collection, req) {
2588
+ async getEdges(c, o) {
1531
2589
  this.ensureInitialized();
1532
- return traverseGraph(this.asCrudTransport(), collection, req);
2590
+ return getEdges(buildCrudTransport(this.httpConfig), c, o);
1533
2591
  }
1534
- async traverseParallel(collection, req) {
2592
+ async traverseGraph(c, r) {
1535
2593
  this.ensureInitialized();
1536
- return traverseParallel(this.asCrudTransport(), collection, req);
2594
+ return traverseGraph(buildCrudTransport(this.httpConfig), c, r);
1537
2595
  }
1538
- async getNodeDegree(collection, nodeId) {
2596
+ async traverseParallel(c, r) {
1539
2597
  this.ensureInitialized();
1540
- return getNodeDegree(this.asCrudTransport(), collection, nodeId);
2598
+ return traverseParallel(buildCrudTransport(this.httpConfig), c, r);
1541
2599
  }
1542
- async createGraphCollection(name, config) {
2600
+ async getNodeDegree(c, id) {
1543
2601
  this.ensureInitialized();
1544
- return createGraphCollection(this.asCrudTransport(), name, config);
2602
+ return getNodeDegree(buildCrudTransport(this.httpConfig), c, id);
1545
2603
  }
1546
- // ==========================================================================
1547
- // Index — delegates to index-backend.ts
1548
- // ==========================================================================
1549
- async createIndex(collection, options) {
2604
+ async createGraphCollection(n, c) {
1550
2605
  this.ensureInitialized();
1551
- return createIndex(this.asCrudTransport(), collection, options);
2606
+ return createGraphCollection(buildCrudTransport(this.httpConfig), n, c);
1552
2607
  }
1553
- async listIndexes(collection) {
2608
+ // Index
2609
+ async createIndex(c, o) {
1554
2610
  this.ensureInitialized();
1555
- return listIndexes(this.asCrudTransport(), collection);
2611
+ return createIndex(buildCrudTransport(this.httpConfig), c, o);
1556
2612
  }
1557
- async hasIndex(collection, label, property) {
2613
+ async listIndexes(c) {
1558
2614
  this.ensureInitialized();
1559
- return hasIndex(this.asCrudTransport(), collection, label, property);
2615
+ return listIndexes(buildCrudTransport(this.httpConfig), c);
1560
2616
  }
1561
- async dropIndex(collection, label, property) {
2617
+ async hasIndex(c, l, p) {
1562
2618
  this.ensureInitialized();
1563
- return dropIndex(this.asCrudTransport(), collection, label, property);
2619
+ return hasIndex(buildCrudTransport(this.httpConfig), c, l, p);
1564
2620
  }
1565
- // ==========================================================================
1566
- // Admin — delegates to admin-backend.ts
1567
- // ==========================================================================
1568
- async getCollectionStats(collection) {
2621
+ async dropIndex(c, l, p) {
1569
2622
  this.ensureInitialized();
1570
- return getCollectionStats(this.asCrudTransport(), collection);
2623
+ return dropIndex(buildCrudTransport(this.httpConfig), c, l, p);
1571
2624
  }
1572
- async analyzeCollection(collection) {
2625
+ // Admin
2626
+ async getCollectionStats(c) {
1573
2627
  this.ensureInitialized();
1574
- return analyzeCollection(this.asCrudTransport(), collection);
2628
+ return getCollectionStats(buildCrudTransport(this.httpConfig), c);
1575
2629
  }
1576
- async getCollectionConfig(collection) {
2630
+ async analyzeCollection(c) {
1577
2631
  this.ensureInitialized();
1578
- return getCollectionConfig(this.asCrudTransport(), collection);
2632
+ return analyzeCollection(buildCrudTransport(this.httpConfig), c);
1579
2633
  }
1580
- // ==========================================================================
1581
- // Streaming / PQ — delegates to streaming-backend.ts
1582
- // ==========================================================================
1583
- async trainPq(collection, options) {
2634
+ async getCollectionConfig(c) {
1584
2635
  this.ensureInitialized();
1585
- return trainPq(this.asStreamingTransport(), collection, options);
2636
+ return getCollectionConfig(buildCrudTransport(this.httpConfig), c);
1586
2637
  }
1587
- async streamInsert(collection, docs) {
2638
+ // Streaming / PQ
2639
+ async trainPq(c, o) {
2640
+ this.ensureInitialized();
2641
+ return trainPq(buildStreamingTransport(this.httpConfig), c, o);
2642
+ }
2643
+ async streamInsert(c, d) {
1588
2644
  this.ensureInitialized();
1589
- return streamInsert(this.asStreamingTransport(), collection, docs);
2645
+ return streamInsert(buildStreamingTransport(this.httpConfig), c, d);
1590
2646
  }
1591
- // ==========================================================================
1592
- // Agent Memory — delegates to agent-memory-backend.ts
1593
- // ==========================================================================
1594
- async storeSemanticFact(collection, entry) {
2647
+ async streamUpsertPoints(c, d) {
1595
2648
  this.ensureInitialized();
1596
- return storeSemanticFact(this.asAgentMemoryTransport(), collection, entry);
2649
+ return streamUpsertPoints(buildStreamingTransport(this.httpConfig), c, d);
1597
2650
  }
1598
- async searchSemanticMemory(collection, embedding, k = 5) {
1599
- return searchSemanticMemory(this.asAgentMemoryTransport(), collection, embedding, k);
2651
+ // Agent Memory
2652
+ async storeSemanticFact(c, e) {
2653
+ this.ensureInitialized();
2654
+ return storeSemanticFact(buildAgentMemoryTransport(this.httpConfig, (col, emb, opts) => this.search(col, emb, opts)), c, e);
2655
+ }
2656
+ async searchSemanticMemory(c, e, k = 5) {
2657
+ this.ensureInitialized();
2658
+ return searchSemanticMemory(buildAgentMemoryTransport(this.httpConfig, (col, emb, opts) => this.search(col, emb, opts)), c, e, k);
1600
2659
  }
1601
- async recordEpisodicEvent(collection, event) {
2660
+ async recordEpisodicEvent(c, e) {
1602
2661
  this.ensureInitialized();
1603
- return recordEpisodicEvent(this.asAgentMemoryTransport(), collection, event);
2662
+ return recordEpisodicEvent(buildAgentMemoryTransport(this.httpConfig, (col, emb, opts) => this.search(col, emb, opts)), c, e);
1604
2663
  }
1605
- async recallEpisodicEvents(collection, embedding, k = 5) {
1606
- return recallEpisodicEvents(this.asAgentMemoryTransport(), collection, embedding, k);
2664
+ async recallEpisodicEvents(c, e, k = 5) {
2665
+ this.ensureInitialized();
2666
+ return recallEpisodicEvents(buildAgentMemoryTransport(this.httpConfig, (col, emb, opts) => this.search(col, emb, opts)), c, e, k);
1607
2667
  }
1608
- async storeProceduralPattern(collection, pattern) {
2668
+ async storeProceduralPattern(c, p) {
1609
2669
  this.ensureInitialized();
1610
- return storeProceduralPattern(this.asAgentMemoryTransport(), collection, pattern);
2670
+ return storeProceduralPattern(buildAgentMemoryTransport(this.httpConfig, (col, emb, opts) => this.search(col, emb, opts)), c, p);
1611
2671
  }
1612
- async matchProceduralPatterns(collection, embedding, k = 5) {
1613
- return matchProceduralPatterns(this.asAgentMemoryTransport(), collection, embedding, k);
2672
+ async matchProceduralPatterns(c, e, k = 5) {
2673
+ this.ensureInitialized();
2674
+ return matchProceduralPatterns(buildAgentMemoryTransport(this.httpConfig, (col, emb, opts) => this.search(col, emb, opts)), c, e, k);
1614
2675
  }
1615
2676
  };
1616
2677
 
@@ -1650,7 +2711,7 @@ var AgentMemoryClient = class {
1650
2711
  }
1651
2712
  };
1652
2713
 
1653
- // src/client.ts
2714
+ // src/client/validation.ts
1654
2715
  function requireNonEmptyString(value, label) {
1655
2716
  if (!value || typeof value !== "string") {
1656
2717
  throw new ValidationError(`${label} must be a non-empty string`);
@@ -1669,13 +2730,187 @@ function validateDocsBatch(docs, validateDoc) {
1669
2730
  validateDoc(doc);
1670
2731
  }
1671
2732
  }
2733
+ function validateDocument(doc, config) {
2734
+ if (doc.id === void 0 || doc.id === null) {
2735
+ throw new ValidationError("Document ID is required");
2736
+ }
2737
+ requireVector(doc.vector, "Vector");
2738
+ validateRestPointId(doc.id, config);
2739
+ }
2740
+ function validateRestPointId(id, config) {
2741
+ if (config.backend === "rest" && (typeof id !== "number" || !Number.isInteger(id) || id < 0 || id > Number.MAX_SAFE_INTEGER)) {
2742
+ throw new ValidationError(
2743
+ `REST backend requires numeric u64-compatible document IDs in JS safe integer range (0..${Number.MAX_SAFE_INTEGER})`
2744
+ );
2745
+ }
2746
+ }
2747
+
2748
+ // src/client/search-methods.ts
2749
+ function search2(backend, collection, query3, options) {
2750
+ requireVector(query3, "Query");
2751
+ return backend.search(collection, query3, options);
2752
+ }
2753
+ function searchBatch2(backend, collection, searches) {
2754
+ if (!Array.isArray(searches)) {
2755
+ throw new ValidationError("Searches must be an array");
2756
+ }
2757
+ for (const s of searches) {
2758
+ requireVector(s.vector, "Each search vector");
2759
+ }
2760
+ return backend.searchBatch(collection, searches);
2761
+ }
2762
+ function textSearch2(backend, collection, query3, options) {
2763
+ requireNonEmptyString(query3, "Query");
2764
+ return backend.textSearch(collection, query3, options);
2765
+ }
2766
+ function hybridSearch2(backend, collection, vector, textQuery, options) {
2767
+ requireVector(vector, "Vector");
2768
+ requireNonEmptyString(textQuery, "Text query");
2769
+ return backend.hybridSearch(collection, vector, textQuery, options);
2770
+ }
2771
+ function multiQuerySearch2(backend, collection, vectors, options) {
2772
+ if (!Array.isArray(vectors) || vectors.length === 0) {
2773
+ throw new ValidationError("Vectors must be a non-empty array");
2774
+ }
2775
+ for (const v of vectors) {
2776
+ requireVector(v, "Each vector");
2777
+ }
2778
+ return backend.multiQuerySearch(collection, vectors, options);
2779
+ }
2780
+ function trainPq2(backend, collection, options) {
2781
+ return backend.trainPq(collection, options);
2782
+ }
2783
+ function streamInsert2(backend, config, collection, docs) {
2784
+ validateDocsBatch(docs, (doc) => validateDocument(doc, config));
2785
+ return backend.streamInsert(collection, docs);
2786
+ }
2787
+ function streamUpsertPoints2(backend, config, collection, docs) {
2788
+ validateDocsBatch(docs, (doc) => validateDocument(doc, config));
2789
+ return backend.streamUpsertPoints(collection, docs);
2790
+ }
2791
+ function scroll2(backend, collection, request2) {
2792
+ requireNonEmptyString(collection, "Collection name");
2793
+ if (request2?.batchSize !== void 0) {
2794
+ if (request2.batchSize < 1 || request2.batchSize > 1e4) {
2795
+ throw new ValidationError("batchSize must be between 1 and 10000");
2796
+ }
2797
+ }
2798
+ return backend.scroll(collection, request2);
2799
+ }
2800
+ function searchIds2(backend, collection, query3, options) {
2801
+ return backend.searchIds(collection, query3, options);
2802
+ }
2803
+ function query2(backend, collection, queryString, params, options) {
2804
+ requireNonEmptyString(collection, "Collection name");
2805
+ requireNonEmptyString(queryString, "Query string");
2806
+ return backend.query(collection, queryString, params, options);
2807
+ }
2808
+ function queryExplain2(backend, queryString, params, options) {
2809
+ requireNonEmptyString(queryString, "Query string");
2810
+ return backend.queryExplain(queryString, params, options);
2811
+ }
2812
+ function collectionSanity2(backend, collection) {
2813
+ requireNonEmptyString(collection, "Collection name");
2814
+ return backend.collectionSanity(collection);
2815
+ }
2816
+ function getCollectionStats2(backend, collection) {
2817
+ return backend.getCollectionStats(collection);
2818
+ }
2819
+ function analyzeCollection2(backend, collection) {
2820
+ return backend.analyzeCollection(collection);
2821
+ }
2822
+ function getCollectionConfig2(backend, collection) {
2823
+ return backend.getCollectionConfig(collection);
2824
+ }
2825
+ function rebuildIndex2(backend, collection) {
2826
+ requireNonEmptyString(collection, "Collection");
2827
+ return backend.rebuildIndex(collection);
2828
+ }
2829
+ function getGuardrails2(backend) {
2830
+ return backend.getGuardrails();
2831
+ }
2832
+ function updateGuardrails2(backend, req) {
2833
+ return backend.updateGuardrails(req);
2834
+ }
2835
+ function aggregate2(backend, queryString, params, options) {
2836
+ requireNonEmptyString(queryString, "Query string");
2837
+ return backend.aggregate(queryString, params, options);
2838
+ }
2839
+
2840
+ // src/client/graph-methods.ts
2841
+ function addEdge2(backend, collection, edge) {
2842
+ if (!edge.label || typeof edge.label !== "string") {
2843
+ throw new ValidationError("Edge label is required and must be a string");
2844
+ }
2845
+ if (typeof edge.source !== "number" || typeof edge.target !== "number") {
2846
+ throw new ValidationError("Edge source and target must be numbers");
2847
+ }
2848
+ return backend.addEdge(collection, edge);
2849
+ }
2850
+ function getEdges2(backend, collection, options) {
2851
+ return backend.getEdges(collection, options);
2852
+ }
2853
+ function traverseGraph2(backend, collection, request2) {
2854
+ if (typeof request2.source !== "number") {
2855
+ throw new ValidationError("Source node ID must be a number");
2856
+ }
2857
+ if (request2.strategy && !["bfs", "dfs"].includes(request2.strategy)) {
2858
+ throw new ValidationError("Strategy must be 'bfs' or 'dfs'");
2859
+ }
2860
+ return backend.traverseGraph(collection, request2);
2861
+ }
2862
+ function traverseParallel2(backend, collection, request2) {
2863
+ if (!Array.isArray(request2.sources) || request2.sources.length === 0) {
2864
+ throw new ValidationError("At least one source node ID is required");
2865
+ }
2866
+ return backend.traverseParallel(collection, request2);
2867
+ }
2868
+ function getNodeDegree2(backend, collection, nodeId) {
2869
+ if (typeof nodeId !== "number") {
2870
+ throw new ValidationError("Node ID must be a number");
2871
+ }
2872
+ return backend.getNodeDegree(collection, nodeId);
2873
+ }
2874
+ function createGraphCollection2(backend, name, config) {
2875
+ requireNonEmptyString(name, "Collection name");
2876
+ return backend.createGraphCollection(name, config);
2877
+ }
2878
+ function matchQuery2(backend, collection, queryString, params, options) {
2879
+ requireNonEmptyString(collection, "Collection");
2880
+ requireNonEmptyString(queryString, "Query string");
2881
+ return backend.matchQuery(collection, queryString, params, options);
2882
+ }
2883
+ function removeEdge2(backend, collection, edgeId) {
2884
+ requireNonEmptyString(collection, "Collection");
2885
+ return backend.removeEdge(collection, edgeId);
2886
+ }
2887
+ function getEdgeCount2(backend, collection) {
2888
+ requireNonEmptyString(collection, "Collection");
2889
+ return backend.getEdgeCount(collection);
2890
+ }
2891
+ function listNodes2(backend, collection) {
2892
+ requireNonEmptyString(collection, "Collection");
2893
+ return backend.listNodes(collection);
2894
+ }
2895
+ function getNodeEdges2(backend, collection, nodeId, options) {
2896
+ requireNonEmptyString(collection, "Collection");
2897
+ return backend.getNodeEdges(collection, nodeId, options);
2898
+ }
2899
+ function getNodePayload2(backend, collection, nodeId) {
2900
+ requireNonEmptyString(collection, "Collection");
2901
+ return backend.getNodePayload(collection, nodeId);
2902
+ }
2903
+ function upsertNodePayload2(backend, collection, nodeId, payload) {
2904
+ requireNonEmptyString(collection, "Collection");
2905
+ return backend.upsertNodePayload(collection, nodeId, payload);
2906
+ }
2907
+ function graphSearch2(backend, collection, request2) {
2908
+ requireNonEmptyString(collection, "Collection");
2909
+ return backend.graphSearch(collection, request2);
2910
+ }
2911
+
2912
+ // src/client.ts
1672
2913
  var VelesDB = class {
1673
- /**
1674
- * Create a new VelesDB client
1675
- *
1676
- * @param config - Client configuration
1677
- * @throws {ValidationError} If configuration is invalid
1678
- */
1679
2914
  constructor(config) {
1680
2915
  this.initialized = false;
1681
2916
  this.validateConfig(config);
@@ -1703,10 +2938,7 @@ var VelesDB = class {
1703
2938
  throw new ValidationError(`Unknown backend: ${config.backend}`);
1704
2939
  }
1705
2940
  }
1706
- /**
1707
- * Initialize the client
1708
- * Must be called before any other operations
1709
- */
2941
+ /** Initialize the client. Must be called before any other operations. */
1710
2942
  async init() {
1711
2943
  if (this.initialized) {
1712
2944
  return;
@@ -1714,9 +2946,7 @@ var VelesDB = class {
1714
2946
  await this.backend.init();
1715
2947
  this.initialized = true;
1716
2948
  }
1717
- /**
1718
- * Check if client is initialized
1719
- */
2949
+ /** Check if client is initialized. */
1720
2950
  isInitialized() {
1721
2951
  return this.initialized;
1722
2952
  }
@@ -1725,358 +2955,161 @@ var VelesDB = class {
1725
2955
  throw new ValidationError("Client not initialized. Call init() first.");
1726
2956
  }
1727
2957
  }
1728
- /**
1729
- * Create a new collection
1730
- *
1731
- * @param name - Collection name
1732
- * @param config - Collection configuration
1733
- */
2958
+ // ========================================================================
2959
+ // Collection CRUD
2960
+ // ========================================================================
1734
2961
  async createCollection(name, config) {
1735
2962
  this.ensureInitialized();
1736
2963
  requireNonEmptyString(name, "Collection name");
1737
- const isMetadataOnly = config.collectionType === "metadata_only";
1738
- if (!isMetadataOnly && (!config.dimension || config.dimension <= 0)) {
1739
- throw new ValidationError("Dimension must be a positive integer for vector collections");
1740
- }
1741
- await this.backend.createCollection(name, config);
1742
- }
1743
- /**
1744
- * Create a metadata-only collection (no vectors, just payload data)
1745
- *
1746
- * Useful for storing reference data that can be JOINed with vector collections.
1747
- *
1748
- * @param name - Collection name
1749
- *
1750
- * @example
1751
- * ```typescript
1752
- * await db.createMetadataCollection('products');
1753
- * await db.insertMetadata('products', { id: 'P001', name: 'Widget', price: 99 });
1754
- * ```
1755
- */
2964
+ const isMetadataOnly = config.collectionType === "metadata_only";
2965
+ if (!isMetadataOnly && (!config.dimension || config.dimension <= 0)) {
2966
+ throw new ValidationError("Dimension must be a positive integer for vector collections");
2967
+ }
2968
+ await this.backend.createCollection(name, config);
2969
+ }
1756
2970
  async createMetadataCollection(name) {
1757
2971
  this.ensureInitialized();
1758
2972
  requireNonEmptyString(name, "Collection name");
1759
2973
  await this.backend.createCollection(name, { collectionType: "metadata_only" });
1760
2974
  }
1761
- /**
1762
- * Delete a collection
1763
- *
1764
- * @param name - Collection name
1765
- */
1766
2975
  async deleteCollection(name) {
1767
2976
  this.ensureInitialized();
1768
2977
  await this.backend.deleteCollection(name);
1769
2978
  }
1770
- /**
1771
- * Get collection information
1772
- *
1773
- * @param name - Collection name
1774
- * @returns Collection info or null if not found
1775
- */
1776
2979
  async getCollection(name) {
1777
2980
  this.ensureInitialized();
1778
2981
  return this.backend.getCollection(name);
1779
2982
  }
1780
- /**
1781
- * List all collections
1782
- *
1783
- * @returns Array of collections
1784
- */
1785
2983
  async listCollections() {
1786
2984
  this.ensureInitialized();
1787
2985
  return this.backend.listCollections();
1788
2986
  }
1789
- /**
1790
- * Insert a vector document
1791
- *
1792
- * @param collection - Collection name
1793
- * @param doc - Document to insert
1794
- */
1795
- async insert(collection, doc) {
2987
+ // ========================================================================
2988
+ // Point CRUD
2989
+ // ========================================================================
2990
+ async upsert(collection, doc) {
1796
2991
  this.ensureInitialized();
1797
- this.validateDocument(doc);
1798
- await this.backend.insert(collection, doc);
2992
+ validateDocument(doc, this.config);
2993
+ await this.backend.upsert(collection, doc);
1799
2994
  }
1800
- /**
1801
- * Insert multiple vector documents
1802
- *
1803
- * @param collection - Collection name
1804
- * @param docs - Documents to insert
1805
- */
1806
- async insertBatch(collection, docs) {
2995
+ async upsertBatch(collection, docs) {
1807
2996
  this.ensureInitialized();
1808
- validateDocsBatch(docs, (doc) => this.validateDocument(doc));
1809
- await this.backend.insertBatch(collection, docs);
2997
+ validateDocsBatch(docs, (doc) => validateDocument(doc, this.config));
2998
+ await this.backend.upsertBatch(collection, docs);
1810
2999
  }
1811
- validateDocument(doc) {
1812
- if (doc.id === void 0 || doc.id === null) {
1813
- throw new ValidationError("Document ID is required");
1814
- }
1815
- requireVector(doc.vector, "Vector");
1816
- this.validateRestPointId(doc.id);
3000
+ async delete(collection, id) {
3001
+ this.ensureInitialized();
3002
+ validateRestPointId(id, this.config);
3003
+ return this.backend.delete(collection, id);
1817
3004
  }
1818
- validateRestPointId(id) {
1819
- if (this.config.backend === "rest" && (typeof id !== "number" || !Number.isInteger(id) || id < 0 || id > Number.MAX_SAFE_INTEGER)) {
1820
- throw new ValidationError(
1821
- `REST backend requires numeric u64-compatible document IDs in JS safe integer range (0..${Number.MAX_SAFE_INTEGER})`
1822
- );
1823
- }
3005
+ async get(collection, id) {
3006
+ this.ensureInitialized();
3007
+ validateRestPointId(id, this.config);
3008
+ return this.backend.get(collection, id);
1824
3009
  }
1825
- /**
1826
- * Search for similar vectors
1827
- *
1828
- * @param collection - Collection name
1829
- * @param query - Query vector
1830
- * @param options - Search options
1831
- * @returns Search results sorted by relevance
1832
- */
1833
- async search(collection, query2, options) {
3010
+ async isEmpty(collection) {
1834
3011
  this.ensureInitialized();
1835
- requireVector(query2, "Query");
1836
- return this.backend.search(collection, query2, options);
3012
+ return this.backend.isEmpty(collection);
1837
3013
  }
1838
- /**
1839
- * Search for multiple vectors in parallel
1840
- *
1841
- * @param collection - Collection name
1842
- * @param searches - List of search queries
1843
- * @returns List of search results for each query
1844
- */
1845
- async searchBatch(collection, searches) {
3014
+ async flush(collection) {
1846
3015
  this.ensureInitialized();
1847
- if (!Array.isArray(searches)) {
1848
- throw new ValidationError("Searches must be an array");
1849
- }
1850
- for (const s of searches) {
1851
- requireVector(s.vector, "Each search vector");
3016
+ await this.backend.flush(collection);
3017
+ }
3018
+ async close() {
3019
+ if (this.initialized) {
3020
+ await this.backend.close();
3021
+ this.initialized = false;
1852
3022
  }
1853
- return this.backend.searchBatch(collection, searches);
1854
3023
  }
1855
- /**
1856
- * Delete a vector by ID
1857
- *
1858
- * @param collection - Collection name
1859
- * @param id - Document ID
1860
- * @returns true if deleted, false if not found
1861
- */
1862
- async delete(collection, id) {
3024
+ // ========================================================================
3025
+ // Search & Query -- delegates to client/search-methods.ts
3026
+ // ========================================================================
3027
+ async search(collection, query3, options) {
1863
3028
  this.ensureInitialized();
1864
- this.validateRestPointId(id);
1865
- return this.backend.delete(collection, id);
3029
+ return search2(this.backend, collection, query3, options);
1866
3030
  }
1867
- /**
1868
- * Get a vector by ID
1869
- *
1870
- * @param collection - Collection name
1871
- * @param id - Document ID
1872
- * @returns Document or null if not found
1873
- */
1874
- async get(collection, id) {
3031
+ async searchBatch(collection, searches) {
1875
3032
  this.ensureInitialized();
1876
- this.validateRestPointId(id);
1877
- return this.backend.get(collection, id);
3033
+ return searchBatch2(this.backend, collection, searches);
1878
3034
  }
1879
- /**
1880
- * Perform full-text search using BM25
1881
- *
1882
- * @param collection - Collection name
1883
- * @param query - Text query
1884
- * @param options - Search options (k, filter)
1885
- * @returns Search results sorted by BM25 score
1886
- */
1887
- async textSearch(collection, query2, options) {
3035
+ async textSearch(collection, query3, options) {
1888
3036
  this.ensureInitialized();
1889
- requireNonEmptyString(query2, "Query");
1890
- return this.backend.textSearch(collection, query2, options);
3037
+ return textSearch2(this.backend, collection, query3, options);
1891
3038
  }
1892
- /**
1893
- * Perform hybrid search combining vector similarity and BM25 text search
1894
- *
1895
- * @param collection - Collection name
1896
- * @param vector - Query vector
1897
- * @param textQuery - Text query for BM25
1898
- * @param options - Search options (k, vectorWeight, filter)
1899
- * @returns Search results sorted by fused score
1900
- */
1901
3039
  async hybridSearch(collection, vector, textQuery, options) {
1902
3040
  this.ensureInitialized();
1903
- requireVector(vector, "Vector");
1904
- requireNonEmptyString(textQuery, "Text query");
1905
- return this.backend.hybridSearch(collection, vector, textQuery, options);
3041
+ return hybridSearch2(this.backend, collection, vector, textQuery, options);
3042
+ }
3043
+ async multiQuerySearch(collection, vectors, options) {
3044
+ this.ensureInitialized();
3045
+ return multiQuerySearch2(this.backend, collection, vectors, options);
1906
3046
  }
1907
- /**
1908
- * Execute a VelesQL multi-model query (EPIC-031 US-011)
1909
- *
1910
- * Supports hybrid vector + graph queries with VelesQL syntax.
1911
- *
1912
- * @param collection - Collection name
1913
- * @param queryString - VelesQL query string
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.
1919
- * @param options - Query options (timeout, streaming)
1920
- * @returns Query response with results and execution stats
1921
- *
1922
- * @example
1923
- * ```typescript
1924
- * const response = await db.query('docs', `
1925
- * MATCH (d:Doc) WHERE vector NEAR $q LIMIT 20
1926
- * `, { q: queryVector });
1927
- *
1928
- * for (const r of response.results) {
1929
- * console.log(`ID ${r.id}, title: ${r.title}`);
1930
- * }
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
- * ```
1942
- */
1943
3047
  async query(collection, queryString, params, options) {
1944
3048
  this.ensureInitialized();
1945
- requireNonEmptyString(collection, "Collection name");
1946
- requireNonEmptyString(queryString, "Query string");
1947
- return this.backend.query(collection, queryString, params, options);
3049
+ return query2(this.backend, collection, queryString, params, options);
1948
3050
  }
1949
- /**
1950
- * Explain the execution plan for a VelesQL query without running it
1951
- *
1952
- * @param queryString - VelesQL query string to explain
1953
- * @param params - Optional query parameters (vectors, scalars)
1954
- * @returns Explain response with the query execution plan
1955
- */
1956
- async queryExplain(queryString, params) {
3051
+ async queryExplain(queryString, params, options) {
1957
3052
  this.ensureInitialized();
1958
- requireNonEmptyString(queryString, "Query string");
1959
- return this.backend.queryExplain(queryString, params);
3053
+ return queryExplain2(this.backend, queryString, params, options);
1960
3054
  }
1961
3055
  async collectionSanity(collection) {
1962
3056
  this.ensureInitialized();
1963
- requireNonEmptyString(collection, "Collection name");
1964
- return this.backend.collectionSanity(collection);
3057
+ return collectionSanity2(this.backend, collection);
1965
3058
  }
1966
- /**
1967
- * Multi-query fusion search combining results from multiple query vectors
1968
- *
1969
- * Ideal for RAG pipelines using Multiple Query Generation (MQG).
1970
- *
1971
- * @param collection - Collection name
1972
- * @param vectors - Array of query vectors
1973
- * @param options - Search options (k, fusion strategy, fusionParams, filter)
1974
- * @returns Fused search results
1975
- *
1976
- * @example
1977
- * ```typescript
1978
- * // RRF fusion (default)
1979
- * const results = await db.multiQuerySearch('docs', [emb1, emb2, emb3], {
1980
- * k: 10,
1981
- * fusion: 'rrf',
1982
- * fusionParams: { k: 60 }
1983
- * });
1984
- *
1985
- * // Weighted fusion
1986
- * const results = await db.multiQuerySearch('docs', [emb1, emb2], {
1987
- * k: 10,
1988
- * fusion: 'weighted',
1989
- * fusionParams: { avgWeight: 0.6, maxWeight: 0.3, hitWeight: 0.1 }
1990
- * });
1991
- * ```
1992
- */
1993
- async multiQuerySearch(collection, vectors, options) {
3059
+ async scroll(collection, request2) {
1994
3060
  this.ensureInitialized();
1995
- if (!Array.isArray(vectors) || vectors.length === 0) {
1996
- throw new ValidationError("Vectors must be a non-empty array");
1997
- }
1998
- for (const v of vectors) {
1999
- requireVector(v, "Each vector");
2000
- }
2001
- return this.backend.multiQuerySearch(collection, vectors, options);
3061
+ return scroll2(this.backend, collection, request2);
2002
3062
  }
2003
- /**
2004
- * Train Product Quantization on a collection
2005
- *
2006
- * @param collection - Collection name
2007
- * @param options - PQ training options (m, k, opq)
2008
- * @returns Server response message
2009
- */
2010
3063
  async trainPq(collection, options) {
2011
3064
  this.ensureInitialized();
2012
- return this.backend.trainPq(collection, options);
3065
+ return trainPq2(this.backend, collection, options);
2013
3066
  }
2014
- /**
2015
- * Stream-insert documents with backpressure support
2016
- *
2017
- * Sends documents sequentially to respect server backpressure.
2018
- * Throws BackpressureError on 429 responses.
2019
- *
2020
- * @param collection - Collection name
2021
- * @param docs - Documents to insert
2022
- */
2023
3067
  async streamInsert(collection, docs) {
2024
3068
  this.ensureInitialized();
2025
- validateDocsBatch(docs, (doc) => this.validateDocument(doc));
2026
- await this.backend.streamInsert(collection, docs);
3069
+ return streamInsert2(this.backend, this.config, collection, docs);
2027
3070
  }
2028
- /**
2029
- * Check if a collection is empty
2030
- *
2031
- * @param collection - Collection name
2032
- * @returns true if empty, false otherwise
2033
- */
2034
- async isEmpty(collection) {
3071
+ async streamUpsertPoints(collection, docs) {
2035
3072
  this.ensureInitialized();
2036
- return this.backend.isEmpty(collection);
3073
+ return streamUpsertPoints2(this.backend, this.config, collection, docs);
2037
3074
  }
2038
- /**
2039
- * Flush pending changes to disk
2040
- *
2041
- * @param collection - Collection name
2042
- */
2043
- async flush(collection) {
3075
+ async searchIds(collection, query3, options) {
2044
3076
  this.ensureInitialized();
2045
- await this.backend.flush(collection);
3077
+ return searchIds2(this.backend, collection, query3, options);
2046
3078
  }
2047
- /**
2048
- * Close the client and release resources
2049
- */
2050
- async close() {
2051
- if (this.initialized) {
2052
- await this.backend.close();
2053
- this.initialized = false;
2054
- }
3079
+ // ========================================================================
3080
+ // Admin / Stats -- delegates to client/search-methods.ts
3081
+ // ========================================================================
3082
+ async rebuildIndex(collection) {
3083
+ this.ensureInitialized();
3084
+ return rebuildIndex2(this.backend, collection);
2055
3085
  }
2056
- /**
2057
- * Get the current backend type
2058
- */
2059
- get backendType() {
2060
- return this.config.backend;
3086
+ async getGuardrails() {
3087
+ this.ensureInitialized();
3088
+ return getGuardrails2(this.backend);
3089
+ }
3090
+ async updateGuardrails(req) {
3091
+ this.ensureInitialized();
3092
+ return updateGuardrails2(this.backend, req);
3093
+ }
3094
+ async aggregate(queryString, params, options) {
3095
+ this.ensureInitialized();
3096
+ return aggregate2(this.backend, queryString, params, options);
3097
+ }
3098
+ async getCollectionStats(collection) {
3099
+ this.ensureInitialized();
3100
+ return getCollectionStats2(this.backend, collection);
3101
+ }
3102
+ async analyzeCollection(collection) {
3103
+ this.ensureInitialized();
3104
+ return analyzeCollection2(this.backend, collection);
3105
+ }
3106
+ async getCollectionConfig(collection) {
3107
+ this.ensureInitialized();
3108
+ return getCollectionConfig2(this.backend, collection);
2061
3109
  }
2062
3110
  // ========================================================================
2063
3111
  // Index Management (EPIC-009)
2064
3112
  // ========================================================================
2065
- /**
2066
- * Create a property index for O(1) equality lookups or O(log n) range queries
2067
- *
2068
- * @param collection - Collection name
2069
- * @param options - Index configuration (label, property, indexType)
2070
- *
2071
- * @example
2072
- * ```typescript
2073
- * // Create hash index for fast email lookups
2074
- * await db.createIndex('users', { label: 'Person', property: 'email' });
2075
- *
2076
- * // Create range index for timestamp queries
2077
- * await db.createIndex('events', { label: 'Event', property: 'timestamp', indexType: 'range' });
2078
- * ```
2079
- */
2080
3113
  async createIndex(collection, options) {
2081
3114
  this.ensureInitialized();
2082
3115
  if (!options.label || !options.property) {
@@ -2084,234 +3117,89 @@ var VelesDB = class {
2084
3117
  }
2085
3118
  await this.backend.createIndex(collection, options);
2086
3119
  }
2087
- /**
2088
- * List all indexes on a collection
2089
- *
2090
- * @param collection - Collection name
2091
- * @returns Array of index information
2092
- */
2093
3120
  async listIndexes(collection) {
2094
3121
  this.ensureInitialized();
2095
3122
  return this.backend.listIndexes(collection);
2096
3123
  }
2097
- /**
2098
- * Check if an index exists
2099
- *
2100
- * @param collection - Collection name
2101
- * @param label - Node label
2102
- * @param property - Property name
2103
- * @returns true if index exists
2104
- */
2105
3124
  async hasIndex(collection, label, property) {
2106
3125
  this.ensureInitialized();
2107
3126
  return this.backend.hasIndex(collection, label, property);
2108
3127
  }
2109
- /**
2110
- * Drop an index
2111
- *
2112
- * @param collection - Collection name
2113
- * @param label - Node label
2114
- * @param property - Property name
2115
- * @returns true if index was dropped, false if it didn't exist
2116
- */
2117
3128
  async dropIndex(collection, label, property) {
2118
3129
  this.ensureInitialized();
2119
3130
  return this.backend.dropIndex(collection, label, property);
2120
3131
  }
2121
3132
  // ========================================================================
2122
- // Knowledge Graph (EPIC-016 US-041)
3133
+ // Knowledge Graph -- delegates to client/graph-methods.ts
2123
3134
  // ========================================================================
2124
- /**
2125
- * Add an edge to the collection's knowledge graph
2126
- *
2127
- * @param collection - Collection name
2128
- * @param edge - Edge to add (id, source, target, label, properties)
2129
- *
2130
- * @example
2131
- * ```typescript
2132
- * await db.addEdge('social', {
2133
- * id: 1,
2134
- * source: 100,
2135
- * target: 200,
2136
- * label: 'FOLLOWS',
2137
- * properties: { since: '2024-01-01' }
2138
- * });
2139
- * ```
2140
- */
2141
3135
  async addEdge(collection, edge) {
2142
3136
  this.ensureInitialized();
2143
- if (!edge.label || typeof edge.label !== "string") {
2144
- throw new ValidationError("Edge label is required and must be a string");
2145
- }
2146
- if (typeof edge.source !== "number" || typeof edge.target !== "number") {
2147
- throw new ValidationError("Edge source and target must be numbers");
2148
- }
2149
- await this.backend.addEdge(collection, edge);
3137
+ return addEdge2(this.backend, collection, edge);
2150
3138
  }
2151
- /**
2152
- * Get edges from the collection's knowledge graph
2153
- *
2154
- * @param collection - Collection name
2155
- * @param options - Query options (filter by label)
2156
- * @returns Array of edges
2157
- *
2158
- * @example
2159
- * ```typescript
2160
- * // Get all edges with label "FOLLOWS"
2161
- * const edges = await db.getEdges('social', { label: 'FOLLOWS' });
2162
- * ```
2163
- */
2164
3139
  async getEdges(collection, options) {
2165
3140
  this.ensureInitialized();
2166
- return this.backend.getEdges(collection, options);
3141
+ return getEdges2(this.backend, collection, options);
2167
3142
  }
2168
- // ========================================================================
2169
- // Graph Traversal (EPIC-016 US-050)
2170
- // ========================================================================
2171
- /**
2172
- * Traverse the graph using BFS or DFS from a source node
2173
- *
2174
- * @param collection - Collection name
2175
- * @param request - Traversal request options
2176
- * @returns Traversal response with results and stats
2177
- *
2178
- * @example
2179
- * ```typescript
2180
- * // BFS traversal from node 100
2181
- * const result = await db.traverseGraph('social', {
2182
- * source: 100,
2183
- * strategy: 'bfs',
2184
- * maxDepth: 3,
2185
- * limit: 100,
2186
- * relTypes: ['FOLLOWS', 'KNOWS']
2187
- * });
2188
- *
2189
- * for (const node of result.results) {
2190
- * console.log(`Reached node ${node.targetId} at depth ${node.depth}`);
2191
- * }
2192
- * ```
2193
- */
2194
- async traverseGraph(collection, request) {
3143
+ async traverseGraph(collection, request2) {
2195
3144
  this.ensureInitialized();
2196
- if (typeof request.source !== "number") {
2197
- throw new ValidationError("Source node ID must be a number");
2198
- }
2199
- if (request.strategy && !["bfs", "dfs"].includes(request.strategy)) {
2200
- throw new ValidationError("Strategy must be 'bfs' or 'dfs'");
2201
- }
2202
- return this.backend.traverseGraph(collection, request);
3145
+ return traverseGraph2(this.backend, collection, request2);
2203
3146
  }
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) {
3147
+ async traverseParallel(collection, request2) {
2224
3148
  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);
3149
+ return traverseParallel2(this.backend, collection, request2);
2229
3150
  }
2230
- /**
2231
- * Get the in-degree and out-degree of a node
2232
- *
2233
- * @param collection - Collection name
2234
- * @param nodeId - Node ID
2235
- * @returns Degree response with inDegree and outDegree
2236
- *
2237
- * @example
2238
- * ```typescript
2239
- * const degree = await db.getNodeDegree('social', 100);
2240
- * console.log(`In: ${degree.inDegree}, Out: ${degree.outDegree}`);
2241
- * ```
2242
- */
2243
3151
  async getNodeDegree(collection, nodeId) {
2244
3152
  this.ensureInitialized();
2245
- if (typeof nodeId !== "number") {
2246
- throw new ValidationError("Node ID must be a number");
2247
- }
2248
- return this.backend.getNodeDegree(collection, nodeId);
3153
+ return getNodeDegree2(this.backend, collection, nodeId);
2249
3154
  }
2250
- // ========================================================================
2251
- // Graph Collection Management (Phase 8)
2252
- // ========================================================================
2253
- /**
2254
- * Create a graph collection
2255
- *
2256
- * @param name - Collection name
2257
- * @param config - Optional graph collection configuration
2258
- */
2259
3155
  async createGraphCollection(name, config) {
2260
3156
  this.ensureInitialized();
2261
- requireNonEmptyString(name, "Collection name");
2262
- await this.backend.createGraphCollection(name, config);
3157
+ return createGraphCollection2(this.backend, name, config);
2263
3158
  }
2264
- /**
2265
- * Get collection statistics (requires prior analyze)
2266
- *
2267
- * @param collection - Collection name
2268
- * @returns Statistics or null if not yet analyzed
2269
- */
2270
- async getCollectionStats(collection) {
3159
+ async matchQuery(collection, queryString, params, options) {
2271
3160
  this.ensureInitialized();
2272
- return this.backend.getCollectionStats(collection);
3161
+ return matchQuery2(this.backend, collection, queryString, params, options);
2273
3162
  }
2274
- /**
2275
- * Analyze a collection to compute statistics
2276
- *
2277
- * @param collection - Collection name
2278
- * @returns Computed statistics
2279
- */
2280
- async analyzeCollection(collection) {
3163
+ async removeEdge(collection, edgeId) {
2281
3164
  this.ensureInitialized();
2282
- return this.backend.analyzeCollection(collection);
3165
+ return removeEdge2(this.backend, collection, edgeId);
2283
3166
  }
2284
- /**
2285
- * Get collection configuration
2286
- *
2287
- * @param collection - Collection name
2288
- * @returns Collection configuration details
2289
- */
2290
- async getCollectionConfig(collection) {
3167
+ async getEdgeCount(collection) {
2291
3168
  this.ensureInitialized();
2292
- return this.backend.getCollectionConfig(collection);
3169
+ return getEdgeCount2(this.backend, collection);
2293
3170
  }
2294
- /**
2295
- * Search returning only IDs and scores (lightweight)
2296
- *
2297
- * @param collection - Collection name
2298
- * @param query - Query vector
2299
- * @param options - Search options
2300
- * @returns Array of id/score pairs
2301
- */
2302
- async searchIds(collection, query2, options) {
3171
+ async listNodes(collection) {
3172
+ this.ensureInitialized();
3173
+ return listNodes2(this.backend, collection);
3174
+ }
3175
+ async getNodeEdges(collection, nodeId, options) {
3176
+ this.ensureInitialized();
3177
+ return getNodeEdges2(this.backend, collection, nodeId, options);
3178
+ }
3179
+ async getNodePayload(collection, nodeId) {
3180
+ this.ensureInitialized();
3181
+ return getNodePayload2(this.backend, collection, nodeId);
3182
+ }
3183
+ async upsertNodePayload(collection, nodeId, payload) {
3184
+ this.ensureInitialized();
3185
+ return upsertNodePayload2(this.backend, collection, nodeId, payload);
3186
+ }
3187
+ async graphSearch(collection, request2) {
2303
3188
  this.ensureInitialized();
2304
- return this.backend.searchIds(collection, query2, options);
3189
+ return graphSearch2(this.backend, collection, request2);
3190
+ }
3191
+ // ========================================================================
3192
+ // Capabilities & Backend Info
3193
+ // ========================================================================
3194
+ capabilities() {
3195
+ return this.backend.capabilities();
3196
+ }
3197
+ get backendType() {
3198
+ return this.config.backend;
2305
3199
  }
2306
3200
  // ========================================================================
2307
3201
  // Agent Memory (Phase 8)
2308
3202
  // ========================================================================
2309
- /**
2310
- * Create an agent memory interface
2311
- *
2312
- * @param config - Optional agent memory configuration
2313
- * @returns AgentMemoryClient instance
2314
- */
2315
3203
  agentMemory(config) {
2316
3204
  this.ensureInitialized();
2317
3205
  return new AgentMemoryClient(this.backend, config);
@@ -2411,6 +3299,16 @@ var VelesQLBuilder = class _VelesQLBuilder {
2411
3299
  *
2412
3300
  * @param condition - WHERE condition
2413
3301
  * @param params - Optional parameters
3302
+ *
3303
+ * @example
3304
+ * ```typescript
3305
+ * // Substring matching with CONTAINS_TEXT
3306
+ * velesql()
3307
+ * .match('d', 'Document')
3308
+ * .where("content CONTAINS_TEXT 'keyword'")
3309
+ * .limit(10)
3310
+ * .toVelesQL();
3311
+ * ```
2414
3312
  */
2415
3313
  where(condition, params) {
2416
3314
  const newParams = params ? { ...this.state.params, ...params } : this.state.params;
@@ -2619,16 +3517,205 @@ var VelesQLBuilder = class _VelesQLBuilder {
2619
3517
  function velesql() {
2620
3518
  return new VelesQLBuilder();
2621
3519
  }
3520
+
3521
+ // src/filter.ts
3522
+ function isTypedFilter(input) {
3523
+ if (typeof input !== "object" || input === null) {
3524
+ return false;
3525
+ }
3526
+ if (!("condition" in input)) {
3527
+ return false;
3528
+ }
3529
+ const cond = input.condition;
3530
+ return typeof cond === "object" && cond !== null;
3531
+ }
3532
+ function normalizeFilter(input) {
3533
+ if (input === void 0) {
3534
+ return void 0;
3535
+ }
3536
+ return input;
3537
+ }
3538
+ var f = {
3539
+ // --- Comparison -----------------------------------------------------------
3540
+ /** `field == value` */
3541
+ eq(field, value) {
3542
+ return { condition: { type: "eq", field, value } };
3543
+ },
3544
+ /** `field != value` */
3545
+ neq(field, value) {
3546
+ return { condition: { type: "neq", field, value } };
3547
+ },
3548
+ /** `field > value` */
3549
+ gt(field, value) {
3550
+ return { condition: { type: "gt", field, value } };
3551
+ },
3552
+ /** `field >= value` */
3553
+ gte(field, value) {
3554
+ return { condition: { type: "gte", field, value } };
3555
+ },
3556
+ /** `field < value` */
3557
+ lt(field, value) {
3558
+ return { condition: { type: "lt", field, value } };
3559
+ },
3560
+ /** `field <= value` */
3561
+ lte(field, value) {
3562
+ return { condition: { type: "lte", field, value } };
3563
+ },
3564
+ // --- Set / string / null --------------------------------------------------
3565
+ /** `field IN (values...)` — the values list is copied. */
3566
+ in(field, values) {
3567
+ return { condition: { type: "in", field, values: [...values] } };
3568
+ },
3569
+ /** Substring containment: `field LIKE '%value%'` (case-sensitive). */
3570
+ contains(field, value) {
3571
+ return { condition: { type: "contains", field, value } };
3572
+ },
3573
+ /** `field IS NULL` */
3574
+ isNull(field) {
3575
+ return { condition: { type: "is_null", field } };
3576
+ },
3577
+ /** `field IS NOT NULL` */
3578
+ isNotNull(field) {
3579
+ return { condition: { type: "is_not_null", field } };
3580
+ },
3581
+ // --- SQL patterns ---------------------------------------------------------
3582
+ /** SQL LIKE pattern matching (case-sensitive). Supports `%` and `_`. */
3583
+ like(field, pattern) {
3584
+ return { condition: { type: "like", field, pattern } };
3585
+ },
3586
+ /** SQL ILIKE pattern matching (case-insensitive). */
3587
+ ilike(field, pattern) {
3588
+ return { condition: { type: "ilike", field, pattern } };
3589
+ },
3590
+ // --- Array ----------------------------------------------------------------
3591
+ /** `value IN field` (field must be an array). */
3592
+ arrayContains(field, value) {
3593
+ return { condition: { type: "array_contains", field, value } };
3594
+ },
3595
+ /** At least one of `values` is present in the array field. */
3596
+ arrayContainsAny(field, values) {
3597
+ return { condition: { type: "array_contains_any", field, values: [...values] } };
3598
+ },
3599
+ /** Every value in `values` is present in the array field. */
3600
+ arrayContainsAll(field, values) {
3601
+ return { condition: { type: "array_contains_all", field, values: [...values] } };
3602
+ },
3603
+ // --- Geo ------------------------------------------------------------------
3604
+ /** Haversine distance comparison: `distance(field, (lat, lng)) <op> threshold`. */
3605
+ geoDistance(field, lat, lng, operator, threshold) {
3606
+ return {
3607
+ condition: { type: "geo_distance", field, lat, lng, operator, threshold }
3608
+ };
3609
+ },
3610
+ /** Bounding-box containment: point field falls inside `[lat_min, lat_max] x [lng_min, lng_max]`. */
3611
+ geoBbox(field, bounds) {
3612
+ return {
3613
+ condition: {
3614
+ type: "geo_bbox",
3615
+ field,
3616
+ lat_min: bounds.lat_min,
3617
+ lng_min: bounds.lng_min,
3618
+ lat_max: bounds.lat_max,
3619
+ lng_max: bounds.lng_max
3620
+ }
3621
+ };
3622
+ },
3623
+ // --- Convenience combinators ----------------------------------------------
3624
+ /** `field NOT IN (values...)` — shorthand for `not(in(field, values))`. */
3625
+ notIn(field, values) {
3626
+ return { condition: { type: "not", condition: { type: "in", field, values: [...values] } } };
3627
+ },
3628
+ /** `field BETWEEN low AND high` — shorthand for `and([gte(field, low), lte(field, high)])`. */
3629
+ between(field, low, high) {
3630
+ return {
3631
+ condition: {
3632
+ type: "and",
3633
+ conditions: [
3634
+ { type: "gte", field, value: low },
3635
+ { type: "lte", field, value: high }
3636
+ ]
3637
+ }
3638
+ };
3639
+ },
3640
+ // --- Logical --------------------------------------------------------------
3641
+ /** Logical AND — the filters list is copied and flattened to root conditions. */
3642
+ and(filters) {
3643
+ return {
3644
+ condition: {
3645
+ type: "and",
3646
+ conditions: filters.map((item) => item.condition)
3647
+ }
3648
+ };
3649
+ },
3650
+ /** Logical OR — the filters list is copied and flattened to root conditions. */
3651
+ or(filters) {
3652
+ return {
3653
+ condition: {
3654
+ type: "or",
3655
+ conditions: filters.map((item) => item.condition)
3656
+ }
3657
+ };
3658
+ },
3659
+ /** Logical NOT — wraps a single filter. */
3660
+ not(filter) {
3661
+ return { condition: { type: "not", condition: filter.condition } };
3662
+ }
3663
+ };
2622
3664
  export {
2623
3665
  AgentMemoryClient,
3666
+ AllocationFailedError,
2624
3667
  BackpressureError,
3668
+ CollectionExistsError,
3669
+ CollectionNotFoundError,
3670
+ ColumnStoreError,
3671
+ ConfigError,
2625
3672
  ConnectionError,
3673
+ DatabaseLockedError,
3674
+ DimensionMismatchError,
3675
+ EdgeExistsError,
3676
+ EdgeNotFoundError,
3677
+ EpochMismatchError,
3678
+ GpuError,
3679
+ GraphNotSupportedError,
3680
+ GuardRailError,
3681
+ IncompatibleSchemaVersionError,
3682
+ IndexCorruptedError,
3683
+ IndexError,
3684
+ InternalError,
3685
+ InvalidCollectionNameError,
3686
+ InvalidDimensionError,
3687
+ InvalidEdgeLabelError,
3688
+ InvalidQuantizerConfigError,
3689
+ InvalidVectorError,
3690
+ IoError,
3691
+ NodeNotFoundError,
2626
3692
  NotFoundError,
3693
+ OverflowError,
3694
+ PointNotFoundError,
3695
+ QueryError,
3696
+ REST_CAPABILITIES,
2627
3697
  RestBackend,
3698
+ SchemaValidationError,
3699
+ SearchNotSupportedError,
3700
+ SerializationError,
3701
+ SnapshotBuildFailedError,
3702
+ SparseIndexError,
3703
+ StorageError,
3704
+ TrainingFailedError,
3705
+ VELES_ERROR_CODES,
2628
3706
  ValidationError,
3707
+ VectorNotAllowedError,
3708
+ VectorRequiredError,
2629
3709
  VelesDB,
2630
3710
  VelesDBError,
3711
+ VelesError,
2631
3712
  VelesQLBuilder,
3713
+ WASM_CAPABILITIES,
2632
3714
  WasmBackend,
3715
+ f,
3716
+ isTypedFilter,
3717
+ normalizeFilter,
3718
+ parseVelesError,
3719
+ searchQualityToMode,
2633
3720
  velesql
2634
3721
  };