hyperspace-sdk-ts 3.1.1 → 3.1.3

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/client.js CHANGED
@@ -33,13 +33,14 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.HyperspaceClient = exports.HyperbolicMath = exports.DurabilityLevel = exports.TribunalContext = exports.CognitiveMath = void 0;
36
+ exports.HyperspaceClient = exports.HyperbolicMath = exports.DurabilityLevel = exports.TribunalContext = exports.CognitiveMathExport = void 0;
37
37
  const grpc = __importStar(require("@grpc/grpc-js"));
38
38
  const hyperspace_grpc_pb_1 = require("./proto/hyperspace_grpc_pb");
39
39
  const hyperspace_pb_1 = require("./proto/hyperspace_pb");
40
40
  Object.defineProperty(exports, "DurabilityLevel", { enumerable: true, get: function () { return hyperspace_pb_1.DurabilityLevel; } });
41
41
  const hyperspace_pb = __importStar(require("./proto/hyperspace_pb")); // New, for direct access to types
42
- exports.CognitiveMath = __importStar(require("./math"));
42
+ const CognitiveMath = __importStar(require("./math"));
43
+ exports.CognitiveMathExport = __importStar(require("./math"));
43
44
  var agents_1 = require("./agents");
44
45
  Object.defineProperty(exports, "TribunalContext", { enumerable: true, get: function () { return agents_1.TribunalContext; } });
45
46
  exports.HyperbolicMath = {
@@ -224,7 +225,82 @@ class HyperspaceClient {
224
225
  });
225
226
  return out;
226
227
  }
228
+ toProtoFilter(f) {
229
+ const pf = new hyperspace_pb.Filter();
230
+ if (f.match) {
231
+ const m = new hyperspace_pb.Match();
232
+ m.setKey(f.match.key);
233
+ m.setValue(f.match.value);
234
+ pf.setMatch(m);
235
+ }
236
+ else if (f.prefix) {
237
+ const p = new hyperspace_pb.Prefix();
238
+ p.setKey(f.prefix.key);
239
+ p.setPrefix(f.prefix.prefix);
240
+ pf.setPrefix(p);
241
+ }
242
+ else if (f.range) {
243
+ const r = new hyperspace_pb.Range();
244
+ r.setKey(f.range.key);
245
+ if (f.range.gte !== undefined) {
246
+ if (Number.isInteger(f.range.gte))
247
+ r.setGte(f.range.gte);
248
+ else
249
+ r.setGteF64(f.range.gte);
250
+ }
251
+ if (f.range.lte !== undefined) {
252
+ if (Number.isInteger(f.range.lte))
253
+ r.setLte(f.range.lte);
254
+ else
255
+ r.setLteF64(f.range.lte);
256
+ }
257
+ pf.setRange(r);
258
+ }
259
+ else if (f.inCone) {
260
+ const c = new hyperspace_pb.InCone();
261
+ c.setAxesList(f.inCone.axes);
262
+ c.setAperturesList(f.inCone.apertures);
263
+ c.setCen(f.inCone.cen[0] || 0);
264
+ pf.setInCone(c);
265
+ }
266
+ else if (f.inBall) {
267
+ const b = new hyperspace_pb.InBall();
268
+ b.setCenterList(f.inBall.center);
269
+ b.setRadius(f.inBall.radius);
270
+ pf.setInBall(b);
271
+ }
272
+ else if (f.inBox) {
273
+ const b = new hyperspace_pb.InBox();
274
+ b.setMinBoundsList(f.inBox.minBounds);
275
+ b.setMaxBoundsList(f.inBox.maxBounds);
276
+ pf.setInBox(b);
277
+ }
278
+ else if (f.and) {
279
+ const andOp = new hyperspace_pb.FilterAnd();
280
+ andOp.setConditionsList(f.and.map(cond => this.toProtoFilter(cond)));
281
+ pf.setAndOp(andOp);
282
+ }
283
+ else if (f.or) {
284
+ const orOp = new hyperspace_pb.FilterOr();
285
+ orOp.setConditionsList(f.or.map(cond => this.toProtoFilter(cond)));
286
+ pf.setOrOp(orOp);
287
+ }
288
+ else if (f.not) {
289
+ const notOp = new hyperspace_pb.FilterNot();
290
+ notOp.setCondition(this.toProtoFilter(f.not));
291
+ pf.setNotOp(notOp);
292
+ }
293
+ return pf;
294
+ }
227
295
  constructor(host = 'localhost:50051', apiKey, userId) {
296
+ this.collectionKeys = {};
297
+ this.encryptionContexts = {};
298
+ this.collectionMetrics = {};
299
+ this.collectionNoiseSigmas = {};
300
+ this.collectionSchemas = {};
301
+ this.host = host;
302
+ this.apiKey = apiKey;
303
+ this.userId = userId;
228
304
  const options = {
229
305
  'grpc.max_send_message_length': 64 * 1024 * 1024,
230
306
  'grpc.max_receive_message_length': 64 * 1024 * 1024,
@@ -243,13 +319,246 @@ class HyperspaceClient {
243
319
  this.metadata.add('x-hyperspace-user-id', userId);
244
320
  }
245
321
  }
322
+ registerCollectionKey(collectionName, key, metric = "l2", noiseSigma = 0.02, schema) {
323
+ this.collectionKeys[collectionName] = key;
324
+ this.collectionMetrics[collectionName] = metric;
325
+ this.collectionNoiseSigmas[collectionName] = noiseSigma;
326
+ if (schema) {
327
+ this.collectionSchemas[collectionName] = schema;
328
+ }
329
+ if (this.encryptionContexts[collectionName]) {
330
+ delete this.encryptionContexts[collectionName];
331
+ }
332
+ }
333
+ deriveKeys(password, collectionName) {
334
+ const crypto = require('crypto');
335
+ const salt = crypto.createHash('sha256').update(collectionName).digest();
336
+ const aesKey = crypto.pbkdf2Sync(password, salt, 100000, 32, 'sha256');
337
+ const hmacKey = crypto.pbkdf2Sync(password, salt, 100000, 32, 'sha256');
338
+ return { aesKey, hmacKey };
339
+ }
340
+ encryptPayload(plaintext, aesKey) {
341
+ const crypto = require('crypto');
342
+ const iv = crypto.randomBytes(12);
343
+ const pbkdf2Salt = crypto.randomBytes(16);
344
+ const derivedAesKey = crypto.pbkdf2Sync(aesKey, pbkdf2Salt, 100000, 32, 'sha256');
345
+ const cipherPayload = crypto.createCipheriv('aes-256-gcm', derivedAesKey, iv);
346
+ const encryptedPayload = Buffer.concat([cipherPayload.update(plaintext), cipherPayload.final()]);
347
+ const payloadTag = cipherPayload.getAuthTag();
348
+ return Buffer.concat([pbkdf2Salt, iv, encryptedPayload, payloadTag]);
349
+ }
350
+ decryptPayload(data, aesKey) {
351
+ const crypto = require('crypto');
352
+ if (data.length < 16 + 12 + 16) {
353
+ throw new Error("Invalid encrypted payload size");
354
+ }
355
+ const pbkdf2Salt = data.subarray(0, 16);
356
+ const iv = data.subarray(16, 28);
357
+ const ciphertext = data.subarray(28, data.length - 16);
358
+ const tag = data.subarray(data.length - 16);
359
+ const derivedAesKey = crypto.pbkdf2Sync(aesKey, pbkdf2Salt, 100000, 32, 'sha256');
360
+ const decipher = crypto.createDecipheriv('aes-256-gcm', derivedAesKey, iv);
361
+ decipher.setAuthTag(tag);
362
+ return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
363
+ }
364
+ hashMetadataKey(key, hmacKey) {
365
+ const crypto = require('crypto');
366
+ const hash = crypto.createHmac('sha256', hmacKey).update(key).digest('hex');
367
+ return "tag_" + hash.slice(0, 16);
368
+ }
369
+ hashMetadataValue(value, hmacKey) {
370
+ const crypto = require('crypto');
371
+ const hash = crypto.createHmac('sha256', hmacKey).update(value).digest('hex');
372
+ return "val_" + hash;
373
+ }
374
+ async _getEncryptionContext(collection, vectorDim, metric = "l2") {
375
+ if (!collection)
376
+ return null;
377
+ const key = this.collectionKeys[collection];
378
+ if (!key)
379
+ return null;
380
+ if (!this.collectionSchemas[collection]) {
381
+ try {
382
+ const stats = await this.getCollectionStats(collection);
383
+ if (stats && stats.schema) {
384
+ this.collectionSchemas[collection] = stats.schema;
385
+ }
386
+ }
387
+ catch (e) { }
388
+ }
389
+ if (!this.encryptionContexts[collection]) {
390
+ const { aesKey, hmacKey } = this.deriveKeys(key, collection);
391
+ this.encryptionContexts[collection] = {
392
+ aesKey,
393
+ hmacKey,
394
+ projectionMatrices: {}
395
+ };
396
+ }
397
+ const context = this.encryptionContexts[collection];
398
+ if (vectorDim !== undefined) {
399
+ if (!context.projectionMatrices[vectorDim]) {
400
+ const isLorentz = ["lorentz", "poincare"].includes(metric.toLowerCase());
401
+ const matrixDim = metric.toLowerCase() === "poincare" ? vectorDim + 1 : vectorDim;
402
+ if (isLorentz) {
403
+ context.projectionMatrices[vectorDim] = CognitiveMath.generateLorentzMatrix(matrixDim, context.hmacKey);
404
+ }
405
+ else {
406
+ context.projectionMatrices[vectorDim] = CognitiveMath.generateOrthogonalMatrix(matrixDim, context.hmacKey);
407
+ }
408
+ }
409
+ }
410
+ return context;
411
+ }
412
+ _projectSingleBlock(subVec, metric, context, blockId) {
413
+ const dim = subVec.length;
414
+ if (dim === 0)
415
+ return [];
416
+ const cacheKey = blockId ? `${dim}_${blockId}` : `${dim}`;
417
+ if (!context.projectionMatrices[cacheKey]) {
418
+ const isLorentz = ["lorentz", "poincare"].includes(metric.toLowerCase());
419
+ const matrixDim = metric.toLowerCase() === "poincare" ? dim + 1 : dim;
420
+ const crypto = require('crypto');
421
+ let seed = context.hmacKey;
422
+ if (blockId) {
423
+ seed = crypto.createHash('sha256').update(seed).update(blockId).digest();
424
+ }
425
+ if (isLorentz) {
426
+ context.projectionMatrices[cacheKey] = CognitiveMath.generateLorentzMatrix(matrixDim, seed);
427
+ }
428
+ else {
429
+ context.projectionMatrices[cacheKey] = CognitiveMath.generateOrthogonalMatrix(matrixDim, seed);
430
+ }
431
+ }
432
+ const matrix = context.projectionMatrices[cacheKey];
433
+ if (metric.toLowerCase() === "poincare") {
434
+ const lorentzVec = CognitiveMath.poincareToLorentz(subVec);
435
+ const projLorentz = CognitiveMath.projectVector(lorentzVec, matrix);
436
+ return CognitiveMath.lorentzToPoincare(projLorentz);
437
+ }
438
+ else {
439
+ return CognitiveMath.projectVector(subVec, matrix);
440
+ }
441
+ }
442
+ _projectCollectionVector(collection, vector, context, metric = "l2") {
443
+ const schema = this.collectionSchemas[collection];
444
+ if (!schema || !schema.components || schema.components.length === 0) {
445
+ return this._projectSingleBlock(vector, metric, context);
446
+ }
447
+ const components = schema.components;
448
+ const cascade = schema.cascadePipeline || [];
449
+ const componentCutoffs = {};
450
+ for (const layer of cascade) {
451
+ const compName = layer.componentName;
452
+ const cutoff = layer.cutoffDimension;
453
+ if (compName && cutoff) {
454
+ if (!componentCutoffs[compName]) {
455
+ componentCutoffs[compName] = [];
456
+ }
457
+ componentCutoffs[compName].push(cutoff);
458
+ }
459
+ }
460
+ for (const compName in componentCutoffs) {
461
+ componentCutoffs[compName] = Array.from(new Set(componentCutoffs[compName])).sort((a, b) => a - b);
462
+ }
463
+ const projectedParts = [];
464
+ let currentOffset = 0;
465
+ for (const comp of components) {
466
+ const compName = comp.name;
467
+ const compMetric = comp.metric;
468
+ const compDim = comp.fullDimension;
469
+ if (currentOffset >= vector.length) {
470
+ break;
471
+ }
472
+ let subVec = vector.slice(currentOffset, currentOffset + compDim);
473
+ if (subVec.length < compDim) {
474
+ subVec = subVec.concat(new Array(compDim - subVec.length).fill(0));
475
+ }
476
+ const cutoffs = componentCutoffs[compName] || [];
477
+ const validCutoffs = cutoffs.filter(c => c < compDim);
478
+ let projSub = [];
479
+ if (validCutoffs.length === 0) {
480
+ projSub = this._projectSingleBlock(subVec, compMetric, context);
481
+ }
482
+ else {
483
+ let blockStart = 0;
484
+ for (const cutoff of validCutoffs) {
485
+ const blockData = subVec.slice(blockStart, cutoff);
486
+ const projBlock = this._projectSingleBlock(blockData, compMetric, context, `${compName}_block_${blockStart}_${cutoff}`);
487
+ projSub = projSub.concat(projBlock);
488
+ blockStart = cutoff;
489
+ }
490
+ if (blockStart < compDim) {
491
+ const blockData = subVec.slice(blockStart, compDim);
492
+ const projBlock = this._projectSingleBlock(blockData, compMetric, context, `${compName}_block_${blockStart}_${compDim}`);
493
+ projSub = projSub.concat(projBlock);
494
+ }
495
+ }
496
+ projectedParts.push(...projSub);
497
+ currentOffset += compDim;
498
+ }
499
+ if (currentOffset < vector.length) {
500
+ projectedParts.push(...vector.slice(currentOffset));
501
+ }
502
+ return projectedParts;
503
+ }
504
+ _encryptFilters(filters, context) {
505
+ if (!filters)
506
+ return filters;
507
+ return filters.map(f => {
508
+ const nf = { ...f };
509
+ if (nf.match) {
510
+ nf.match = {
511
+ key: this.hashMetadataKey(nf.match.key, context.hmacKey),
512
+ value: this.hashMetadataValue(nf.match.value, context.hmacKey)
513
+ };
514
+ }
515
+ if (nf.prefix) {
516
+ nf.prefix = {
517
+ key: this.hashMetadataKey(nf.prefix.key, context.hmacKey),
518
+ prefix: this.hashMetadataValue(nf.prefix.prefix, context.hmacKey)
519
+ };
520
+ }
521
+ if (nf.and) {
522
+ nf.and = this._encryptFilters(nf.and, context);
523
+ }
524
+ if (nf.or) {
525
+ nf.or = this._encryptFilters(nf.or, context);
526
+ }
527
+ if (nf.not) {
528
+ nf.not = this._encryptFilters([nf.not], context)[0];
529
+ }
530
+ return nf;
531
+ });
532
+ }
246
533
  // ... (create/delete unchanged) ...
247
- createCollection(name, dimension, metric) {
534
+ createCollection(name, schema, encryptionKey = '', noiseSigma = 0.02) {
535
+ const metric = (schema.components && schema.components[0]) ? schema.components[0].metric : "l2";
536
+ if (encryptionKey) {
537
+ this.registerCollectionKey(name, encryptionKey, metric, noiseSigma, schema);
538
+ }
248
539
  return new Promise((resolve, reject) => {
249
540
  const req = new hyperspace_pb_1.CreateCollectionRequest();
250
541
  req.setName(name);
251
- req.setDimension(dimension);
252
- req.setMetric(metric);
542
+ const protoSchema = new hyperspace_pb.CollectionSchema();
543
+ const components = schema.components.map(c => {
544
+ const comp = new hyperspace_pb.VectorComponent();
545
+ comp.setName(c.name);
546
+ comp.setMetric(c.metric);
547
+ comp.setFullDimension(c.fullDimension);
548
+ comp.setWeight(c.weight);
549
+ return comp;
550
+ });
551
+ protoSchema.setComponentsList(components);
552
+ const pipeline = schema.cascadePipeline.map(l => {
553
+ const layer = new hyperspace_pb.MrlLayer();
554
+ layer.setComponentName(l.componentName);
555
+ layer.setCutoffDimension(l.cutoffDimension);
556
+ layer.setStoreInRam(l.storeInRam);
557
+ layer.setRerankTopK(l.rerankTopK);
558
+ return layer;
559
+ });
560
+ protoSchema.setCascadePipelineList(pipeline);
561
+ req.setSchema(protoSchema);
253
562
  this.client.createCollection(req, this.metadata, (err, resp) => {
254
563
  if (err)
255
564
  return reject(err);
@@ -268,22 +577,79 @@ class HyperspaceClient {
268
577
  });
269
578
  });
270
579
  }
580
+ freezeCollection(name) {
581
+ return new Promise((resolve, reject) => {
582
+ const req = new hyperspace_pb.FreezeCollectionRequest();
583
+ req.setName(name);
584
+ this.client.freezeCollection(req, this.metadata, (err, resp) => {
585
+ if (err)
586
+ return reject(err);
587
+ resolve(resp.getStatus());
588
+ });
589
+ });
590
+ }
591
+ unfreezeCollection(name) {
592
+ return new Promise((resolve, reject) => {
593
+ const req = new hyperspace_pb.UnfreezeCollectionRequest();
594
+ req.setName(name);
595
+ this.client.unfreezeCollection(req, this.metadata, (err, resp) => {
596
+ if (err)
597
+ return reject(err);
598
+ resolve(resp.getStatus());
599
+ });
600
+ });
601
+ }
271
602
  listCollections() {
272
603
  return new Promise((resolve, reject) => {
273
604
  const req = new hyperspace_pb_1.Empty();
274
605
  this.client.listCollections(req, this.metadata, (err, resp) => {
275
606
  if (err)
276
607
  return reject(err);
277
- const list = resp.getCollectionsList().map(c => ({
278
- name: c.getName(),
279
- count: c.getCount(),
280
- dimension: c.getDimension(),
281
- metric: c.getMetric()
282
- }));
608
+ const list = resp.getCollectionsList().map(c => {
609
+ const info = {
610
+ name: c.getName(),
611
+ count: c.getCount()
612
+ };
613
+ const protoSchema = c.getSchema();
614
+ if (protoSchema) {
615
+ info.schema = {
616
+ components: protoSchema.getComponentsList().map((comp) => ({
617
+ name: comp.getName(),
618
+ metric: comp.getMetric(),
619
+ fullDimension: comp.getFullDimension(),
620
+ weight: comp.getWeight()
621
+ })),
622
+ cascadePipeline: protoSchema.getCascadePipelineList().map((layer) => ({
623
+ componentName: layer.getComponentName(),
624
+ cutoffDimension: layer.getCutoffDimension(),
625
+ storeInRam: layer.getStoreInRam(),
626
+ rerankTopK: layer.getRerankTopK()
627
+ }))
628
+ };
629
+ }
630
+ return info;
631
+ });
283
632
  resolve(list);
284
633
  });
285
634
  });
286
635
  }
636
+ getPoints(ids, collection = '') {
637
+ return new Promise((resolve, reject) => {
638
+ const req = new hyperspace_pb_1.GetPointsRequest();
639
+ req.setCollection(collection);
640
+ req.setIdsList(ids);
641
+ this.client.getPoints(req, this.metadata, (err, resp) => {
642
+ if (err)
643
+ return reject(err);
644
+ const points = resp.getPointsList().map((p) => ({
645
+ id: p.getId(),
646
+ vector: p.getVectorList(),
647
+ metadata: p.getMetadataMap().toObject()
648
+ }));
649
+ resolve(points);
650
+ });
651
+ });
652
+ }
287
653
  delete(id, collection = '') {
288
654
  return new Promise((resolve, reject) => {
289
655
  const req = new hyperspace_pb.DeleteRequest();
@@ -296,33 +662,87 @@ class HyperspaceClient {
296
662
  });
297
663
  });
298
664
  }
299
- insert(id, vector, meta, collection = '', durability = hyperspace_pb_1.DurabilityLevel.DEFAULT_LEVEL, typedMetadata) {
300
- return new Promise((resolve, reject) => {
301
- const req = new hyperspace_pb_1.InsertRequest();
302
- req.setVectorList(HyperspaceClient.toVectorList(vector));
303
- req.setId(id);
304
- if (meta) {
305
- const map = req.getMetadataMap();
306
- for (const k in meta)
307
- map.set(k, meta[k]);
665
+ insert(id, vector, meta, collection = '', durability = hyperspace_pb_1.DurabilityLevel.DEFAULT_LEVEL, typedMetadata, payload // Sidecar Payload Storage (v3.2)
666
+ ) {
667
+ return new Promise(async (resolve, reject) => {
668
+ var _a;
669
+ try {
670
+ const req = new hyperspace_pb_1.InsertRequest();
671
+ let vectorList = HyperspaceClient.toVectorList(vector);
672
+ const metric = this.collectionMetrics[collection] || "l2";
673
+ const context = await this._getEncryptionContext(collection, vectorList.length, metric);
674
+ if (context) {
675
+ const sigma = (_a = this.collectionNoiseSigmas[collection]) !== null && _a !== void 0 ? _a : 0.02;
676
+ if (sigma > 0.0) {
677
+ vectorList = CognitiveMath.injectAnisotropicNoise(vectorList, context.hmacKey, sigma);
678
+ }
679
+ vectorList = this._projectCollectionVector(collection, vectorList, context, metric);
680
+ let rawPayload = null;
681
+ if (payload) {
682
+ rawPayload = Buffer.from(payload);
683
+ }
684
+ if (rawPayload) {
685
+ const encrypted = this.encryptPayload(rawPayload, context.aesKey);
686
+ req.setPayload(new Uint8Array(encrypted));
687
+ }
688
+ if (meta) {
689
+ const map = req.getMetadataMap();
690
+ for (const k in meta) {
691
+ const ek = this.hashMetadataKey(k, context.hmacKey);
692
+ const ev = this.hashMetadataValue(meta[k], context.hmacKey);
693
+ map.set(ek, ev);
694
+ }
695
+ }
696
+ if (typedMetadata) {
697
+ const map = req.getTypedMetadataMap();
698
+ for (const k in typedMetadata) {
699
+ const ek = this.hashMetadataKey(k, context.hmacKey);
700
+ const ev = this.hashMetadataValue(String(typedMetadata[k]), context.hmacKey);
701
+ map.set(ek, HyperspaceClient.toProtoMetadataValue(ev));
702
+ }
703
+ }
704
+ }
705
+ else {
706
+ if (meta) {
707
+ const map = req.getMetadataMap();
708
+ for (const k in meta)
709
+ map.set(k, meta[k]);
710
+ }
711
+ if (typedMetadata) {
712
+ const map = req.getTypedMetadataMap();
713
+ for (const k in typedMetadata)
714
+ map.set(k, HyperspaceClient.toProtoMetadataValue(typedMetadata[k]));
715
+ }
716
+ if (payload) {
717
+ req.setPayload(payload);
718
+ }
719
+ }
720
+ req.setVectorList(vectorList);
721
+ req.setId(id);
722
+ req.setCollection(collection);
723
+ req.setOriginNodeId('');
724
+ req.setLogicalClock(0);
725
+ req.setDurability(durability);
726
+ this.client.insert(req, this.metadata, (err, resp) => {
727
+ if (err)
728
+ return reject(err);
729
+ resolve(resp.getSuccess());
730
+ });
308
731
  }
309
- if (typedMetadata) {
310
- const map = req.getTypedMetadataMap();
311
- for (const k in typedMetadata)
312
- map.set(k, HyperspaceClient.toProtoMetadataValue(typedMetadata[k]));
732
+ catch (e) {
733
+ reject(e);
313
734
  }
314
- req.setCollection(collection);
315
- req.setOriginNodeId('');
316
- req.setLogicalClock(0);
317
- req.setDurability(durability);
318
- this.client.insert(req, this.metadata, (err, resp) => {
319
- if (err)
320
- return reject(err);
321
- resolve(resp.getSuccess());
322
- });
323
735
  });
324
736
  }
325
737
  insertText(id, text, meta, collection = '', durability = hyperspace_pb_1.DurabilityLevel.DEFAULT_LEVEL) {
738
+ if (this.collectionKeys[collection]) {
739
+ if (!this.embedder) {
740
+ return Promise.reject(new Error("An embedder must be configured to use insertText on encrypted collections."));
741
+ }
742
+ return Promise.resolve(this.embedder.encode(text)).then(vector => {
743
+ return this.insert(id, vector, meta, collection, durability, undefined, Buffer.from(text, 'utf-8'));
744
+ });
745
+ }
326
746
  return new Promise((resolve, reject) => {
327
747
  const req = new hyperspace_pb_1.InsertTextRequest();
328
748
  req.setText(text);
@@ -383,126 +803,145 @@ class HyperspaceClient {
383
803
  });
384
804
  }
385
805
  search(vector, topK, collection = '', options) {
386
- return new Promise((resolve, reject) => {
387
- const req = new hyperspace_pb_1.SearchRequest();
388
- req.setVectorList(HyperspaceClient.toVectorList(vector));
389
- req.setTopK(topK);
390
- req.setCollection(collection);
391
- if (options === null || options === void 0 ? void 0 : options.filters) {
392
- const protoFilters = options.filters.map(f => {
393
- const pf = new hyperspace_pb.Filter();
394
- if (f.match) {
395
- const m = new hyperspace_pb.Match();
396
- m.setKey(f.match.key);
397
- m.setValue(f.match.value);
398
- pf.setMatch(m);
806
+ return new Promise(async (resolve, reject) => {
807
+ var _a;
808
+ try {
809
+ const req = new hyperspace_pb_1.SearchRequest();
810
+ let vectorList = HyperspaceClient.toVectorList(vector);
811
+ req.setTopK(topK);
812
+ req.setCollection(collection);
813
+ const metric = this.collectionMetrics[collection] || "l2";
814
+ const context = await this._getEncryptionContext(collection, vectorList.length, metric);
815
+ let optFilters = options === null || options === void 0 ? void 0 : options.filters;
816
+ let optFilter = options === null || options === void 0 ? void 0 : options.filter;
817
+ let includePayload = options === null || options === void 0 ? void 0 : options.includePayload;
818
+ if (context) {
819
+ const sigma = (_a = this.collectionNoiseSigmas[collection]) !== null && _a !== void 0 ? _a : 0.02;
820
+ if (sigma > 0.0) {
821
+ vectorList = CognitiveMath.injectAnisotropicNoise(vectorList, context.hmacKey, sigma);
399
822
  }
400
- else if (f.range) {
401
- const r = new hyperspace_pb.Range();
402
- r.setKey(f.range.key);
403
- if (f.range.gte !== undefined) {
404
- if (Number.isInteger(f.range.gte))
405
- r.setGte(f.range.gte);
406
- else
407
- r.setGteF64(f.range.gte);
823
+ vectorList = this._projectCollectionVector(collection, vectorList, context, metric);
824
+ if (optFilter) {
825
+ const hashedFilter = {};
826
+ for (const k in optFilter) {
827
+ const ek = this.hashMetadataKey(k, context.hmacKey);
828
+ const ev = this.hashMetadataValue(optFilter[k], context.hmacKey);
829
+ hashedFilter[ek] = ev;
408
830
  }
409
- if (f.range.lte !== undefined) {
410
- if (Number.isInteger(f.range.lte))
411
- r.setLte(f.range.lte);
412
- else
413
- r.setLteF64(f.range.lte);
414
- }
415
- pf.setRange(r);
831
+ optFilter = hashedFilter;
832
+ }
833
+ if (optFilters) {
834
+ optFilters = this._encryptFilters(optFilters, context);
835
+ }
836
+ includePayload = true;
837
+ }
838
+ req.setVectorList(vectorList);
839
+ if (optFilter) {
840
+ const map = req.getFilterMap();
841
+ for (const k in optFilter) {
842
+ map.set(k, optFilter[k]);
416
843
  }
417
- return pf;
844
+ }
845
+ if ((options === null || options === void 0 ? void 0 : options.restartFactor) !== undefined) {
846
+ const map = req.getFilterMap();
847
+ map.set('wave_restart_factor', options.restartFactor.toString());
848
+ }
849
+ if ((options === null || options === void 0 ? void 0 : options.useWave) !== undefined) {
850
+ req.setUseWave(options.useWave);
851
+ }
852
+ if (optFilters) {
853
+ req.setFiltersList(optFilters.map(f => this.toProtoFilter(f)));
854
+ }
855
+ if (options === null || options === void 0 ? void 0 : options.hybridQuery)
856
+ req.setHybridQuery(options.hybridQuery);
857
+ if ((options === null || options === void 0 ? void 0 : options.hybridAlpha) !== undefined)
858
+ req.setHybridAlpha(options.hybridAlpha);
859
+ if ((options === null || options === void 0 ? void 0 : options.mrlDimension) !== undefined)
860
+ req.setMrlDimension(options.mrlDimension);
861
+ if ((options === null || options === void 0 ? void 0 : options.useWasserstein) !== undefined)
862
+ req.setUseWasserstein(options.useWasserstein);
863
+ if (includePayload !== undefined)
864
+ req.setIncludePayload(includePayload);
865
+ if (options === null || options === void 0 ? void 0 : options.componentWeights) {
866
+ const map = req.getComponentWeightsMap();
867
+ for (const k in options.componentWeights) {
868
+ map.set(k, options.componentWeights[k]);
869
+ }
870
+ }
871
+ if (options === null || options === void 0 ? void 0 : options.bm25) {
872
+ const bm25Msg = new hyperspace_pb_1.Bm25Options();
873
+ if (options.bm25.method !== undefined)
874
+ bm25Msg.setMethod(options.bm25.method);
875
+ if (options.bm25.k1 !== undefined)
876
+ bm25Msg.setK1(options.bm25.k1);
877
+ if (options.bm25.b !== undefined)
878
+ bm25Msg.setB(options.bm25.b);
879
+ if (options.bm25.delta !== undefined)
880
+ bm25Msg.setDelta(options.bm25.delta);
881
+ if (options.bm25.language !== undefined)
882
+ bm25Msg.setLanguage(options.bm25.language);
883
+ if (options.bm25.ngrams !== undefined)
884
+ bm25Msg.setNgrams(options.bm25.ngrams);
885
+ if (options.bm25.fusionMethod !== undefined)
886
+ bm25Msg.setFusionMethod(options.bm25.fusionMethod);
887
+ req.setBm25Options(bm25Msg);
888
+ }
889
+ this.client.search(req, this.metadata, (err, resp) => {
890
+ if (err)
891
+ return reject(err);
892
+ const results = resp.getResultsList().map(r => {
893
+ const metaMap = r.getMetadataMap();
894
+ const meta = {};
895
+ if (metaMap.getLength() > 0) {
896
+ metaMap.forEach((entry, key) => {
897
+ meta[key] = entry;
898
+ });
899
+ }
900
+ let payloadBytes = r.getPayload_asU8();
901
+ if (context && payloadBytes && payloadBytes.length > 0) {
902
+ try {
903
+ const decrypted = this.decryptPayload(Buffer.from(payloadBytes), context.aesKey);
904
+ payloadBytes = new Uint8Array(decrypted);
905
+ }
906
+ catch (e) {
907
+ // Decryption error
908
+ }
909
+ }
910
+ return {
911
+ id: r.getId(),
912
+ distance: r.getDistance(),
913
+ metadata: meta,
914
+ typedMetadata: HyperspaceClient.parseTypedMetadata(r.getTypedMetadataMap()),
915
+ payload: payloadBytes
916
+ };
917
+ });
918
+ resolve(results);
418
919
  });
419
- req.setFiltersList(protoFilters);
420
920
  }
421
- if (options === null || options === void 0 ? void 0 : options.hybridQuery)
422
- req.setHybridQuery(options.hybridQuery);
423
- if ((options === null || options === void 0 ? void 0 : options.hybridAlpha) !== undefined)
424
- req.setHybridAlpha(options.hybridAlpha);
425
- if (options === null || options === void 0 ? void 0 : options.bm25) {
426
- // @ts-ignore: Bm25Options might not be in generated proto yet
427
- const bm25Msg = new hyperspace_pb.Bm25Options();
428
- if (options.bm25.method !== undefined)
429
- bm25Msg.setMethod(options.bm25.method);
430
- if (options.bm25.k1 !== undefined)
431
- bm25Msg.setK1(options.bm25.k1);
432
- if (options.bm25.b !== undefined)
433
- bm25Msg.setB(options.bm25.b);
434
- if (options.bm25.delta !== undefined)
435
- bm25Msg.setDelta(options.bm25.delta);
436
- if (options.bm25.language !== undefined)
437
- bm25Msg.setLanguage(options.bm25.language);
438
- if (options.bm25.ngrams !== undefined)
439
- bm25Msg.setNgrams(options.bm25.ngrams);
440
- if (options.bm25.fusionMethod !== undefined)
441
- bm25Msg.setFusionMethod(options.bm25.fusionMethod);
442
- // @ts-ignore
443
- req.setBm25Options(bm25Msg);
921
+ catch (e) {
922
+ reject(e);
444
923
  }
445
- this.client.search(req, this.metadata, (err, resp) => {
446
- if (err)
447
- return reject(err);
448
- const results = resp.getResultsList().map(r => {
449
- const metaMap = r.getMetadataMap();
450
- const meta = {};
451
- if (metaMap.getLength() > 0) {
452
- metaMap.forEach((entry, key) => {
453
- meta[key] = entry;
454
- });
455
- }
456
- return {
457
- id: r.getId(),
458
- distance: r.getDistance(),
459
- metadata: meta,
460
- typedMetadata: HyperspaceClient.parseTypedMetadata(r.getTypedMetadataMap())
461
- };
462
- });
463
- resolve(results);
464
- });
465
924
  });
466
925
  }
467
926
  searchText(text, topK, collection = '', options) {
927
+ if (this.collectionKeys[collection]) {
928
+ if (!this.embedder) {
929
+ return Promise.reject(new Error("An embedder must be configured to use searchText on encrypted collections."));
930
+ }
931
+ return Promise.resolve(this.embedder.encode(text)).then(vector => {
932
+ return this.search(vector, topK, collection, options);
933
+ });
934
+ }
468
935
  return new Promise((resolve, reject) => {
469
936
  const req = new hyperspace_pb_1.SearchTextRequest();
470
937
  req.setText(text);
471
938
  req.setTopK(topK);
472
939
  req.setCollection(collection);
473
940
  if (options === null || options === void 0 ? void 0 : options.filters) {
474
- const protoFilters = options.filters.map(f => {
475
- const pf = new hyperspace_pb.Filter();
476
- if (f.match) {
477
- const m = new hyperspace_pb.Match();
478
- m.setKey(f.match.key);
479
- m.setValue(f.match.value);
480
- pf.setMatch(m);
481
- }
482
- else if (f.range) {
483
- const r = new hyperspace_pb.Range();
484
- r.setKey(f.range.key);
485
- if (f.range.gte !== undefined) {
486
- if (Number.isInteger(f.range.gte))
487
- r.setGte(f.range.gte);
488
- else
489
- r.setGteF64(f.range.gte);
490
- }
491
- if (f.range.lte !== undefined) {
492
- if (Number.isInteger(f.range.lte))
493
- r.setLte(f.range.lte);
494
- else
495
- r.setLteF64(f.range.lte);
496
- }
497
- pf.setRange(r);
498
- }
499
- return pf;
500
- });
501
- req.setFiltersList(protoFilters);
941
+ req.setFiltersList(options.filters.map(f => this.toProtoFilter(f)));
502
942
  }
503
943
  if (options === null || options === void 0 ? void 0 : options.bm25) {
504
- // @ts-ignore
505
- const bm25Msg = new hyperspace_pb.Bm25Options();
944
+ const bm25Msg = new hyperspace_pb_1.Bm25Options();
506
945
  if (options.bm25.method !== undefined)
507
946
  bm25Msg.setMethod(options.bm25.method);
508
947
  if (options.bm25.k1 !== undefined)
@@ -517,13 +956,14 @@ class HyperspaceClient {
517
956
  bm25Msg.setNgrams(options.bm25.ngrams);
518
957
  if (options.bm25.fusionMethod !== undefined)
519
958
  bm25Msg.setFusionMethod(options.bm25.fusionMethod);
520
- // @ts-ignore
521
959
  req.setBm25Options(bm25Msg);
522
960
  }
523
961
  if ((options === null || options === void 0 ? void 0 : options.hybridAlpha) !== undefined) {
524
- // @ts-ignore
525
962
  req.setHybridAlpha(options.hybridAlpha);
526
963
  }
964
+ if ((options === null || options === void 0 ? void 0 : options.includePayload) !== undefined) {
965
+ req.setIncludePayload(options.includePayload);
966
+ }
527
967
  this.client.searchText(req, this.metadata, (err, resp) => {
528
968
  if (err)
529
969
  return reject(err);
@@ -539,7 +979,8 @@ class HyperspaceClient {
539
979
  id: r.getId(),
540
980
  distance: r.getDistance(),
541
981
  metadata: meta,
542
- typedMetadata: HyperspaceClient.parseTypedMetadata(r.getTypedMetadataMap())
982
+ typedMetadata: HyperspaceClient.parseTypedMetadata(r.getTypedMetadataMap()),
983
+ payload: r.getPayload_asU8()
543
984
  };
544
985
  });
545
986
  resolve(results);
@@ -571,7 +1012,8 @@ class HyperspaceClient {
571
1012
  id: r.getId(),
572
1013
  distance: r.getDistance(),
573
1014
  metadata: meta,
574
- typedMetadata: HyperspaceClient.parseTypedMetadata(r.getTypedMetadataMap())
1015
+ typedMetadata: HyperspaceClient.parseTypedMetadata(r.getTypedMetadataMap()),
1016
+ payload: r.getPayload_asU8()
575
1017
  };
576
1018
  }));
577
1019
  resolve(batch);
@@ -722,34 +1164,7 @@ class HyperspaceClient {
722
1164
  }
723
1165
  }
724
1166
  if (options === null || options === void 0 ? void 0 : options.filters) {
725
- const protoFilters = options.filters.map(f => {
726
- const pf = new hyperspace_pb.Filter();
727
- if (f.match) {
728
- const m = new hyperspace_pb.Match();
729
- m.setKey(f.match.key);
730
- m.setValue(f.match.value);
731
- pf.setMatch(m);
732
- }
733
- else if (f.range) {
734
- const r = new hyperspace_pb.Range();
735
- r.setKey(f.range.key);
736
- if (f.range.gte !== undefined) {
737
- if (Number.isInteger(f.range.gte))
738
- r.setGte(f.range.gte);
739
- else
740
- r.setGteF64(f.range.gte);
741
- }
742
- if (f.range.lte !== undefined) {
743
- if (Number.isInteger(f.range.lte))
744
- r.setLte(f.range.lte);
745
- else
746
- r.setLteF64(f.range.lte);
747
- }
748
- pf.setRange(r);
749
- }
750
- return pf;
751
- });
752
- req.setFiltersList(protoFilters);
1167
+ req.setFiltersList(options.filters.map(f => this.toProtoFilter(f)));
753
1168
  }
754
1169
  this.client.traverse(req, this.metadata, (err, resp) => {
755
1170
  if (err)
@@ -836,6 +1251,251 @@ class HyperspaceClient {
836
1251
  }
837
1252
  return stream;
838
1253
  }
1254
+ getCollectionStats(name) {
1255
+ return new Promise((resolve, reject) => {
1256
+ const req = new hyperspace_pb_1.CollectionStatsRequest();
1257
+ req.setName(name);
1258
+ this.client.getCollectionStats(req, this.metadata, (err, resp) => {
1259
+ if (err)
1260
+ return reject(err);
1261
+ const stats = {
1262
+ count: resp.getCount(),
1263
+ indexingQueue: resp.getIndexingQueue(),
1264
+ diskUsageBytes: resp.getDiskUsageBytes(),
1265
+ ramUsageBytes: resp.getRamUsageBytes(),
1266
+ activeTasks: resp.getActiveTasks()
1267
+ };
1268
+ const protoSchema = resp.getSchema();
1269
+ if (protoSchema) {
1270
+ stats.schema = {
1271
+ components: protoSchema.getComponentsList().map((comp) => ({
1272
+ name: comp.getName(),
1273
+ metric: comp.getMetric(),
1274
+ fullDimension: comp.getFullDimension(),
1275
+ weight: comp.getWeight()
1276
+ })),
1277
+ cascadePipeline: protoSchema.getCascadePipelineList().map((layer) => ({
1278
+ componentName: layer.getComponentName(),
1279
+ cutoffDimension: layer.getCutoffDimension(),
1280
+ storeInRam: layer.getStoreInRam(),
1281
+ rerankTopK: layer.getRerankTopK()
1282
+ }))
1283
+ };
1284
+ }
1285
+ resolve(stats);
1286
+ });
1287
+ });
1288
+ }
1289
+ async exists(name) {
1290
+ try {
1291
+ await this.getCollectionStats(name);
1292
+ return true;
1293
+ }
1294
+ catch (e) {
1295
+ if (e.code === grpc.status.NOT_FOUND || (e.message && e.message.includes('not found'))) {
1296
+ return false;
1297
+ }
1298
+ throw e;
1299
+ }
1300
+ }
1301
+ async getCacheStats(name) {
1302
+ const ip = this.host.split(':')[0];
1303
+ const url = `http://${ip}:50050/api/collections/${name}/cache/stats`;
1304
+ const headers = {};
1305
+ if (this.apiKey)
1306
+ headers['x-api-key'] = this.apiKey;
1307
+ if (this.userId)
1308
+ headers['x-hyperspace-user-id'] = this.userId;
1309
+ const res = await fetch(url, { headers });
1310
+ if (!res.ok) {
1311
+ throw new Error(`Failed to get cache stats: ${res.statusText} (${await res.text()})`);
1312
+ }
1313
+ return res.json();
1314
+ }
1315
+ async clearCache(name) {
1316
+ const ip = this.host.split(':')[0];
1317
+ const url = `http://${ip}:50050/api/collections/${name}/cache/clear`;
1318
+ const headers = { 'Content-Type': 'application/json' };
1319
+ if (this.apiKey)
1320
+ headers['x-api-key'] = this.apiKey;
1321
+ if (this.userId)
1322
+ headers['x-hyperspace-user-id'] = this.userId;
1323
+ const res = await fetch(url, {
1324
+ method: 'POST',
1325
+ headers,
1326
+ body: JSON.stringify({})
1327
+ });
1328
+ if (!res.ok) {
1329
+ throw new Error(`Failed to clear cache: ${res.statusText} (${await res.text()})`);
1330
+ }
1331
+ const data = await res.json();
1332
+ return data.status === 'success';
1333
+ }
1334
+ async updateCacheConfig(name, policy, annThreshold) {
1335
+ const ip = this.host.split(':')[0];
1336
+ const url = `http://${ip}:50050/api/collections/${name}/cache/config`;
1337
+ const headers = { 'Content-Type': 'application/json' };
1338
+ if (this.apiKey)
1339
+ headers['x-api-key'] = this.apiKey;
1340
+ if (this.userId)
1341
+ headers['x-hyperspace-user-id'] = this.userId;
1342
+ const res = await fetch(url, {
1343
+ method: 'POST',
1344
+ headers,
1345
+ body: JSON.stringify({
1346
+ policy,
1347
+ ann_threshold: annThreshold
1348
+ })
1349
+ });
1350
+ if (!res.ok) {
1351
+ throw new Error(`Failed to update cache config: ${res.statusText} (${await res.text()})`);
1352
+ }
1353
+ const data = await res.json();
1354
+ return data.status === 'success';
1355
+ }
1356
+ updateCollection(name, config) {
1357
+ return new Promise((resolve, reject) => {
1358
+ const req = new hyperspace_pb_1.ConfigUpdate();
1359
+ req.setCollection(name);
1360
+ if (config.efSearch !== undefined)
1361
+ req.setEfSearch(config.efSearch);
1362
+ if (config.efConstruction !== undefined)
1363
+ req.setEfConstruction(config.efConstruction);
1364
+ if (config.m !== undefined)
1365
+ req.setM(config.m);
1366
+ this.client.configure(req, this.metadata, (err, resp) => {
1367
+ if (err)
1368
+ return reject(err);
1369
+ resolve(resp.getStatus() === 'success' || (!!resp.getStatus() && resp.getStatus().includes('updated')));
1370
+ });
1371
+ });
1372
+ }
1373
+ createSnapshot() {
1374
+ return new Promise((resolve, reject) => {
1375
+ this.client.triggerSnapshot(new hyperspace_pb_1.Empty(), this.metadata, (err, resp) => {
1376
+ if (err)
1377
+ return reject(err);
1378
+ resolve(resp.getStatus() === 'success');
1379
+ });
1380
+ });
1381
+ }
1382
+ vacuum() {
1383
+ return new Promise((resolve, reject) => {
1384
+ this.client.triggerVacuum(new hyperspace_pb_1.Empty(), this.metadata, (err, resp) => {
1385
+ if (err)
1386
+ return reject(err);
1387
+ resolve(resp.getStatus() === 'success');
1388
+ });
1389
+ });
1390
+ }
1391
+ getMetrics(onData, onError) {
1392
+ const req = new hyperspace_pb_1.MonitorRequest();
1393
+ const stream = this.client.monitor(req, this.metadata);
1394
+ stream.on('data', onData);
1395
+ if (onError) {
1396
+ stream.on('error', onError);
1397
+ }
1398
+ return stream;
1399
+ }
1400
+ searchMultiCollection(collections, query) {
1401
+ return new Promise((resolve, reject) => {
1402
+ const req = new hyperspace_pb_1.SearchMultiCollectionRequest();
1403
+ req.setCollectionsList(collections);
1404
+ req.setVectorList(HyperspaceClient.toVectorList(query));
1405
+ req.setTopK(10);
1406
+ this.client.searchMultiCollection(req, this.metadata, (err, resp) => {
1407
+ if (err)
1408
+ return reject(err);
1409
+ resolve(resp.toObject());
1410
+ });
1411
+ });
1412
+ }
1413
+ triggerReconsolidation(collection, targetVector, learningRate = 0.01) {
1414
+ return new Promise((resolve, reject) => {
1415
+ const req = new hyperspace_pb_1.ReconsolidationRequest();
1416
+ req.setCollection(collection);
1417
+ req.setTargetVectorList(targetVector);
1418
+ req.setLearningRate(learningRate);
1419
+ this.client.triggerReconsolidation(req, this.metadata, (err, resp) => {
1420
+ if (err)
1421
+ return reject(err);
1422
+ resolve(resp.getStatus() === 'success');
1423
+ });
1424
+ });
1425
+ }
1426
+ getSubsumptionTree(rootId, maxDepth = 3, collection = '') {
1427
+ return new Promise((resolve, reject) => {
1428
+ const req = new hyperspace_pb.GetSubsumptionTreeRequest();
1429
+ req.setRootId(rootId);
1430
+ req.setMaxDepth(maxDepth);
1431
+ req.setCollection(collection);
1432
+ this.client.getSubsumptionTree(req, this.metadata, (err, resp) => {
1433
+ if (err)
1434
+ return reject(err);
1435
+ const nodes = resp.getNodesList().map((n) => ({
1436
+ id: n.getId(),
1437
+ metadata: n.getMetadataMap().toObject(),
1438
+ edgeTypes: n.getEdgeTypesList()
1439
+ }));
1440
+ resolve(nodes);
1441
+ });
1442
+ });
1443
+ }
1444
+ async exploreGraph(startId, maxDepth = 2, maxNodes = 256, collection = '') {
1445
+ const req = new hyperspace_pb_1.TraverseRequest();
1446
+ req.setStartId(startId);
1447
+ req.setMaxDepth(maxDepth);
1448
+ req.setMaxNodes(maxNodes);
1449
+ req.setCollection(collection);
1450
+ req.setTraversalMode(1); // DIFFUSIVE
1451
+ req.setBreadthLimit(10);
1452
+ return new Promise((resolve, reject) => {
1453
+ this.client.traverse(req, this.metadata, (err, resp) => {
1454
+ if (err)
1455
+ return reject(err);
1456
+ const nodes = resp.getNodesList().map((n) => ({
1457
+ id: n.getId(),
1458
+ metadata: n.getMetadataMap().toObject(),
1459
+ edgeTypes: n.getEdgeTypesList(),
1460
+ neighbors: n.getNeighborsList()
1461
+ }));
1462
+ resolve({
1463
+ nodes,
1464
+ centerId: startId,
1465
+ count: nodes.length
1466
+ });
1467
+ });
1468
+ });
1469
+ }
1470
+ async predictMomentum(trajectoryIds, steps = 1.0, collection = '', curvature = 1.0) {
1471
+ if (trajectoryIds.length < 2)
1472
+ return [];
1473
+ const pts = await this.getPoints(trajectoryIds, collection);
1474
+ const idToVec = new Map();
1475
+ pts.forEach(p => idToVec.set(p.id, p.vector));
1476
+ const vectors = trajectoryIds.map(id => idToVec.get(id)).filter(v => !!v);
1477
+ if (vectors.length < 2)
1478
+ return [];
1479
+ const past = vectors[vectors.length - 2];
1480
+ const current = vectors[vectors.length - 1];
1481
+ const { koopmanExtrapolate } = require('./math');
1482
+ return koopmanExtrapolate(past, current, steps, curvature);
1483
+ }
1484
+ async getTrustScore(trajectoryIds, collection = '', curvature = 1.0) {
1485
+ const pts = await this.getPoints(trajectoryIds, collection);
1486
+ const idToVec = new Map();
1487
+ pts.forEach(p => idToVec.set(p.id, p.vector));
1488
+ const vectors = trajectoryIds.map(id => idToVec.get(id)).filter(v => !!v);
1489
+ if (vectors.length < 3)
1490
+ return 0.0;
1491
+ const { lyapunovConvergence } = require('./math');
1492
+ try {
1493
+ return lyapunovConvergence(vectors, curvature);
1494
+ }
1495
+ catch (e) {
1496
+ return 1.0;
1497
+ }
1498
+ }
839
1499
  close() {
840
1500
  this.client.close();
841
1501
  }