@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/README.md +71 -17
- package/dist/index.d.mts +1148 -534
- package/dist/index.d.ts +1148 -534
- package/dist/index.js +2395 -1263
- package/dist/index.mjs +2350 -1263
- package/package.json +1 -1
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
|
|
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
|
|
744
|
+
if (isNotFoundError(response.error.code)) {
|
|
96
745
|
return true;
|
|
97
746
|
}
|
|
98
|
-
throw
|
|
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
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
-
|
|
144
|
-
|
|
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
|
-
|
|
161
|
-
if (
|
|
162
|
-
|
|
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(
|
|
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
|
|
196
|
-
|
|
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
|
-
|
|
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 =
|
|
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(
|
|
1056
|
+
collection.payloads.set(canonicalPayloadKey(doc.id), doc.payload);
|
|
242
1057
|
}
|
|
243
1058
|
}
|
|
244
|
-
async
|
|
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
|
-
|
|
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 ${
|
|
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(
|
|
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(
|
|
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 =
|
|
1099
|
+
const numericId = toNumericId(id);
|
|
361
1100
|
const removed = collection.store.remove(BigInt(numericId));
|
|
362
1101
|
if (removed) {
|
|
363
|
-
collection.payloads.delete(
|
|
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 =
|
|
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(
|
|
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
|
-
|
|
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(
|
|
1137
|
+
const collection = this.collections.get(collectionName);
|
|
388
1138
|
if (!collection) {
|
|
389
|
-
throw new NotFoundError(`Collection '${
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
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
|
|
1196
|
+
async dropIndex(c, l, p) {
|
|
404
1197
|
this.ensureInitialized();
|
|
405
|
-
|
|
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
|
|
1200
|
+
async addEdge(c, e) {
|
|
423
1201
|
this.ensureInitialized();
|
|
424
|
-
|
|
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
|
|
1204
|
+
async getEdges(c, o) {
|
|
451
1205
|
this.ensureInitialized();
|
|
452
|
-
|
|
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
|
|
1208
|
+
async traverseGraph(c, r) {
|
|
490
1209
|
this.ensureInitialized();
|
|
491
|
-
|
|
1210
|
+
return wasmTraverseGraph(c, r);
|
|
492
1211
|
}
|
|
493
|
-
async
|
|
1212
|
+
async traverseParallel(c, r) {
|
|
494
1213
|
this.ensureInitialized();
|
|
495
|
-
|
|
1214
|
+
return wasmTraverseParallel(c, r);
|
|
496
1215
|
}
|
|
497
|
-
async
|
|
1216
|
+
async getNodeDegree(c, n) {
|
|
498
1217
|
this.ensureInitialized();
|
|
499
|
-
|
|
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
|
|
1220
|
+
async trainPq(c, o) {
|
|
506
1221
|
this.ensureInitialized();
|
|
507
|
-
|
|
508
|
-
if (!collection) {
|
|
509
|
-
throw new NotFoundError(`Collection '${collectionName}'`);
|
|
510
|
-
}
|
|
1222
|
+
return wasmTrainPq(c, o);
|
|
511
1223
|
}
|
|
512
|
-
async
|
|
513
|
-
|
|
514
|
-
|
|
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
|
-
|
|
520
|
-
|
|
521
|
-
|
|
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
|
-
|
|
529
|
-
|
|
530
|
-
|
|
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
|
-
|
|
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
|
|
1240
|
+
async analyzeCollection(c) {
|
|
558
1241
|
this.ensureInitialized();
|
|
559
|
-
return
|
|
1242
|
+
return wasmAnalyzeCollection(c);
|
|
560
1243
|
}
|
|
561
|
-
async
|
|
1244
|
+
async getCollectionConfig(c) {
|
|
562
1245
|
this.ensureInitialized();
|
|
563
|
-
return
|
|
1246
|
+
return wasmGetCollectionConfig(c);
|
|
564
1247
|
}
|
|
565
|
-
async
|
|
1248
|
+
async searchIds(c, q, o) {
|
|
566
1249
|
this.ensureInitialized();
|
|
567
|
-
return
|
|
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
|
-
|
|
1254
|
+
return wasmStoreSemanticFact(c, e);
|
|
576
1255
|
}
|
|
577
|
-
async
|
|
1256
|
+
async searchSemanticMemory(c, e, k) {
|
|
578
1257
|
this.ensureInitialized();
|
|
579
|
-
|
|
1258
|
+
return wasmSearchSemanticMemory(c, e, k);
|
|
580
1259
|
}
|
|
581
|
-
async
|
|
1260
|
+
async recordEpisodicEvent(c, e) {
|
|
582
1261
|
this.ensureInitialized();
|
|
583
|
-
|
|
1262
|
+
return wasmRecordEpisodicEvent(c, e);
|
|
584
1263
|
}
|
|
585
|
-
async
|
|
1264
|
+
async recallEpisodicEvents(c, e, k) {
|
|
586
1265
|
this.ensureInitialized();
|
|
587
|
-
|
|
1266
|
+
return wasmRecallEpisodicEvents(c, e, k);
|
|
588
1267
|
}
|
|
589
|
-
async
|
|
1268
|
+
async storeProceduralPattern(c, p) {
|
|
590
1269
|
this.ensureInitialized();
|
|
591
|
-
|
|
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
|
-
|
|
1274
|
+
return wasmMatchProceduralPatterns(c, e, k);
|
|
599
1275
|
}
|
|
600
|
-
|
|
1276
|
+
// Wave 4 stubs
|
|
1277
|
+
async rebuildIndex(c) {
|
|
601
1278
|
this.ensureInitialized();
|
|
602
|
-
|
|
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
|
-
|
|
1283
|
+
return wasmGetGuardrails();
|
|
610
1284
|
}
|
|
611
|
-
async
|
|
1285
|
+
async updateGuardrails(r) {
|
|
612
1286
|
this.ensureInitialized();
|
|
613
|
-
|
|
1287
|
+
return wasmUpdateGuardrails(r);
|
|
614
1288
|
}
|
|
615
|
-
async
|
|
1289
|
+
async aggregate(_q, _p, _o) {
|
|
616
1290
|
this.ensureInitialized();
|
|
617
|
-
|
|
1291
|
+
return wasmAggregate(_q, _p, _o);
|
|
618
1292
|
}
|
|
619
|
-
async
|
|
1293
|
+
async matchQuery(c, q, p, o) {
|
|
620
1294
|
this.ensureInitialized();
|
|
621
|
-
|
|
1295
|
+
return wasmMatchQuery(c, q, p, o);
|
|
622
1296
|
}
|
|
623
|
-
async
|
|
1297
|
+
async removeEdge(c, id) {
|
|
624
1298
|
this.ensureInitialized();
|
|
625
|
-
|
|
1299
|
+
return wasmRemoveEdge(c, id);
|
|
626
1300
|
}
|
|
627
|
-
async
|
|
1301
|
+
async getEdgeCount(c) {
|
|
628
1302
|
this.ensureInitialized();
|
|
629
|
-
|
|
1303
|
+
return wasmGetEdgeCount(c);
|
|
630
1304
|
}
|
|
631
|
-
async
|
|
1305
|
+
async listNodes(c) {
|
|
632
1306
|
this.ensureInitialized();
|
|
633
|
-
|
|
1307
|
+
return wasmListNodes(c);
|
|
634
1308
|
}
|
|
635
|
-
async
|
|
1309
|
+
async getNodeEdges(c, id, o) {
|
|
636
1310
|
this.ensureInitialized();
|
|
637
|
-
|
|
1311
|
+
return wasmGetNodeEdges(c, id, o);
|
|
638
1312
|
}
|
|
639
|
-
async
|
|
1313
|
+
async getNodePayload(c, id) {
|
|
640
1314
|
this.ensureInitialized();
|
|
641
|
-
|
|
1315
|
+
return wasmGetNodePayload(c, id);
|
|
642
1316
|
}
|
|
643
|
-
async
|
|
1317
|
+
async upsertNodePayload(c, id, p) {
|
|
644
1318
|
this.ensureInitialized();
|
|
645
|
-
|
|
1319
|
+
return wasmUpsertNodePayload(c, id, p);
|
|
646
1320
|
}
|
|
647
|
-
async
|
|
1321
|
+
async graphSearch(c, r) {
|
|
648
1322
|
this.ensureInitialized();
|
|
649
|
-
|
|
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
|
-
|
|
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,
|
|
740
|
-
const queryVector = toNumberArray(
|
|
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,
|
|
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:
|
|
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,
|
|
821
|
-
const queryVector = toNumberArray(
|
|
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,
|
|
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:
|
|
865
|
-
strategy:
|
|
866
|
-
max_depth:
|
|
867
|
-
limit:
|
|
868
|
-
cursor:
|
|
869
|
-
rel_types:
|
|
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,
|
|
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:
|
|
915
|
-
max_depth:
|
|
916
|
-
limit:
|
|
917
|
-
rel_types:
|
|
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
|
-
|
|
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
|
-
|
|
1139
|
-
const
|
|
1140
|
-
const
|
|
1141
|
-
const
|
|
1142
|
-
const
|
|
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
|
-
|
|
2377
|
+
"/query",
|
|
2378
|
+
{ query: queryString }
|
|
1314
2379
|
);
|
|
1315
|
-
throwOnError(response
|
|
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.
|
|
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.
|
|
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
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
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
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
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
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
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
|
|
1402
|
-
|
|
1403
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
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
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
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
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
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
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
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
|
|
2580
|
+
return flush(buildCrudTransport(this.httpConfig), c);
|
|
1483
2581
|
}
|
|
1484
|
-
|
|
2582
|
+
// Additional REST endpoints (Sprint 2 Wave 4)
|
|
2583
|
+
async rebuildIndex(c) {
|
|
1485
2584
|
this.ensureInitialized();
|
|
1486
|
-
return
|
|
2585
|
+
return rebuildIndex(buildBaseTransport(this.httpConfig), c);
|
|
1487
2586
|
}
|
|
1488
|
-
async
|
|
2587
|
+
async getGuardrails() {
|
|
1489
2588
|
this.ensureInitialized();
|
|
1490
|
-
return
|
|
2589
|
+
return getGuardrails(buildBaseTransport(this.httpConfig));
|
|
1491
2590
|
}
|
|
1492
|
-
async
|
|
2591
|
+
async updateGuardrails(r) {
|
|
1493
2592
|
this.ensureInitialized();
|
|
1494
|
-
return
|
|
2593
|
+
return updateGuardrails(buildBaseTransport(this.httpConfig), r);
|
|
1495
2594
|
}
|
|
1496
|
-
async
|
|
2595
|
+
async aggregate(q, p, o) {
|
|
1497
2596
|
this.ensureInitialized();
|
|
1498
|
-
return
|
|
2597
|
+
return aggregate(buildBaseTransport(this.httpConfig), q, p, o);
|
|
1499
2598
|
}
|
|
1500
|
-
async
|
|
2599
|
+
async matchQuery(c, q, p, o) {
|
|
1501
2600
|
this.ensureInitialized();
|
|
1502
|
-
return
|
|
2601
|
+
return matchQuery(buildBaseTransport(this.httpConfig), c, q, p, o);
|
|
1503
2602
|
}
|
|
1504
|
-
async
|
|
2603
|
+
async removeEdge(c, id) {
|
|
1505
2604
|
this.ensureInitialized();
|
|
1506
|
-
return
|
|
2605
|
+
return removeEdge(buildBaseTransport(this.httpConfig), c, id);
|
|
1507
2606
|
}
|
|
1508
|
-
async
|
|
2607
|
+
async getEdgeCount(c) {
|
|
1509
2608
|
this.ensureInitialized();
|
|
1510
|
-
return
|
|
2609
|
+
return getEdgeCount(buildBaseTransport(this.httpConfig), c);
|
|
1511
2610
|
}
|
|
1512
|
-
async
|
|
2611
|
+
async listNodes(c) {
|
|
1513
2612
|
this.ensureInitialized();
|
|
1514
|
-
return
|
|
2613
|
+
return listNodes(buildBaseTransport(this.httpConfig), c);
|
|
1515
2614
|
}
|
|
1516
|
-
async
|
|
2615
|
+
async getNodeEdges(c, id, o) {
|
|
1517
2616
|
this.ensureInitialized();
|
|
1518
|
-
return
|
|
2617
|
+
return getNodeEdges(buildBaseTransport(this.httpConfig), c, id, o);
|
|
1519
2618
|
}
|
|
1520
|
-
async
|
|
1521
|
-
this.
|
|
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.
|
|
2634
|
+
return search(buildSearchTransport(this.httpConfig), c, q, o);
|
|
1529
2635
|
}
|
|
1530
|
-
async searchBatch(
|
|
2636
|
+
async searchBatch(c, s) {
|
|
1531
2637
|
this.ensureInitialized();
|
|
1532
|
-
return searchBatch(this.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
2663
|
+
return queryExplain(buildQueryTransport(this.httpConfig), q, p, o);
|
|
1560
2664
|
}
|
|
1561
|
-
async collectionSanity(
|
|
2665
|
+
async collectionSanity(c) {
|
|
1562
2666
|
this.ensureInitialized();
|
|
1563
|
-
return collectionSanity(this.
|
|
2667
|
+
return collectionSanity(buildQueryTransport(this.httpConfig), c);
|
|
1564
2668
|
}
|
|
1565
|
-
//
|
|
1566
|
-
|
|
1567
|
-
// ==========================================================================
|
|
1568
|
-
async addEdge(collection, edge) {
|
|
2669
|
+
// Scroll
|
|
2670
|
+
async scroll(c, r) {
|
|
1569
2671
|
this.ensureInitialized();
|
|
1570
|
-
return
|
|
2672
|
+
return scroll(buildCrudTransport(this.httpConfig), c, r);
|
|
1571
2673
|
}
|
|
1572
|
-
|
|
2674
|
+
// Graph
|
|
2675
|
+
async addEdge(c, e) {
|
|
1573
2676
|
this.ensureInitialized();
|
|
1574
|
-
return
|
|
2677
|
+
return addEdge(buildCrudTransport(this.httpConfig), c, e);
|
|
1575
2678
|
}
|
|
1576
|
-
async
|
|
2679
|
+
async getEdges(c, o) {
|
|
1577
2680
|
this.ensureInitialized();
|
|
1578
|
-
return
|
|
2681
|
+
return getEdges(buildCrudTransport(this.httpConfig), c, o);
|
|
1579
2682
|
}
|
|
1580
|
-
async
|
|
2683
|
+
async traverseGraph(c, r) {
|
|
1581
2684
|
this.ensureInitialized();
|
|
1582
|
-
return
|
|
2685
|
+
return traverseGraph(buildCrudTransport(this.httpConfig), c, r);
|
|
1583
2686
|
}
|
|
1584
|
-
async
|
|
2687
|
+
async traverseParallel(c, r) {
|
|
1585
2688
|
this.ensureInitialized();
|
|
1586
|
-
return
|
|
2689
|
+
return traverseParallel(buildCrudTransport(this.httpConfig), c, r);
|
|
1587
2690
|
}
|
|
1588
|
-
async
|
|
2691
|
+
async getNodeDegree(c, id) {
|
|
1589
2692
|
this.ensureInitialized();
|
|
1590
|
-
return
|
|
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
|
|
2697
|
+
return createGraphCollection(buildCrudTransport(this.httpConfig), n, c);
|
|
1598
2698
|
}
|
|
1599
|
-
|
|
2699
|
+
// Index
|
|
2700
|
+
async createIndex(c, o) {
|
|
1600
2701
|
this.ensureInitialized();
|
|
1601
|
-
return
|
|
2702
|
+
return createIndex(buildCrudTransport(this.httpConfig), c, o);
|
|
1602
2703
|
}
|
|
1603
|
-
async
|
|
2704
|
+
async listIndexes(c) {
|
|
1604
2705
|
this.ensureInitialized();
|
|
1605
|
-
return
|
|
2706
|
+
return listIndexes(buildCrudTransport(this.httpConfig), c);
|
|
1606
2707
|
}
|
|
1607
|
-
async
|
|
2708
|
+
async hasIndex(c, l, p) {
|
|
1608
2709
|
this.ensureInitialized();
|
|
1609
|
-
return
|
|
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
|
|
2714
|
+
return dropIndex(buildCrudTransport(this.httpConfig), c, l, p);
|
|
1617
2715
|
}
|
|
1618
|
-
|
|
2716
|
+
// Admin
|
|
2717
|
+
async getCollectionStats(c) {
|
|
1619
2718
|
this.ensureInitialized();
|
|
1620
|
-
return
|
|
2719
|
+
return getCollectionStats(buildCrudTransport(this.httpConfig), c);
|
|
1621
2720
|
}
|
|
1622
|
-
async
|
|
2721
|
+
async analyzeCollection(c) {
|
|
1623
2722
|
this.ensureInitialized();
|
|
1624
|
-
return
|
|
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
|
|
2727
|
+
return getCollectionConfig(buildCrudTransport(this.httpConfig), c);
|
|
1632
2728
|
}
|
|
1633
|
-
|
|
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.
|
|
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
|
|
2740
|
+
return streamUpsertPoints(buildStreamingTransport(this.httpConfig), c, d);
|
|
1643
2741
|
}
|
|
1644
|
-
|
|
1645
|
-
|
|
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(
|
|
2751
|
+
async recordEpisodicEvent(c, e) {
|
|
1648
2752
|
this.ensureInitialized();
|
|
1649
|
-
return recordEpisodicEvent(this.
|
|
2753
|
+
return recordEpisodicEvent(buildAgentMemoryTransport(this.httpConfig, (col, emb, opts) => this.search(col, emb, opts)), c, e);
|
|
1650
2754
|
}
|
|
1651
|
-
async recallEpisodicEvents(
|
|
1652
|
-
|
|
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(
|
|
2759
|
+
async storeProceduralPattern(c, p) {
|
|
1655
2760
|
this.ensureInitialized();
|
|
1656
|
-
return storeProceduralPattern(this.
|
|
2761
|
+
return storeProceduralPattern(buildAgentMemoryTransport(this.httpConfig, (col, emb, opts) => this.search(col, emb, opts)), c, p);
|
|
1657
2762
|
}
|
|
1658
|
-
async matchProceduralPatterns(
|
|
1659
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
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
|
-
|
|
1844
|
-
await this.backend.
|
|
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) =>
|
|
1855
|
-
await this.backend.
|
|
3088
|
+
validateDocsBatch(docs, (doc) => validateDocument(doc, this.config));
|
|
3089
|
+
await this.backend.upsertBatch(collection, docs);
|
|
1856
3090
|
}
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
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
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
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
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
3168
|
+
return searchIds2(this.backend, collection, query3, options);
|
|
2092
3169
|
}
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
async
|
|
2097
|
-
|
|
2098
|
-
|
|
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
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
3260
|
+
return getEdgeCount2(this.backend, collection);
|
|
2339
3261
|
}
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
async
|
|
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
|
|
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
|
});
|