@wiscale/velesdb-sdk 1.12.0 → 1.13.1

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