@delali/narsil 0.2.4-next.52 → 0.2.4-next.55
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 +8 -4
- package/dist/adapters/filesystem.mjs +1 -1
- package/dist/adapters/indexeddb.mjs +1 -1
- package/dist/{capabilities-CuTSXvbN.d.ts → capabilities-DlYw0Ov0.d.ts} +13 -2
- package/dist/{chunk-U36IDJN7.mjs → chunk-4NVPQ6S5.mjs} +2 -2
- package/dist/{chunk-WM7IS45M.mjs → chunk-5T6AOR37.mjs} +2 -2
- package/dist/{chunk-ULJ36FK4.mjs → chunk-BH5SYB5W.mjs} +73 -46
- package/dist/{chunk-3GWP2TO6.mjs → chunk-D2S642IV.mjs} +4 -2
- package/dist/{chunk-P4ELXVJQ.mjs → chunk-FRQVMFY7.mjs} +7 -1
- package/dist/{chunk-ZT5BRDFW.mjs → chunk-L225SHNB.mjs} +2 -2
- package/dist/{chunk-72AXTIBW.mjs → chunk-NTZYA3SJ.mjs} +3 -3
- package/dist/{chunk-EY2ULUMT.mjs → chunk-RGS7FMCB.mjs} +25 -5
- package/dist/{chunk-YPYULM5E.mjs → chunk-TVT5V4E7.mjs} +84 -33
- package/dist/{chunk-T62YOSGS.mjs → chunk-U2AL3SON.mjs} +16 -98
- package/dist/chunk-UTOFOJOR.mjs +135 -0
- package/dist/{chunk-2FO7KZ6K.mjs → chunk-XNQAIO74.mjs} +53 -8
- package/dist/{client-BMJWVxOP.d.ts → client-CQUqt9Ir.d.ts} +13 -4
- package/dist/client.d.ts +8 -8
- package/dist/client.mjs +20 -14
- package/dist/{config-qMLpi5T4.d.ts → config-CNas6wJH.d.ts} +2 -2
- package/dist/{config-BcYZkdMw.d.ts → config-bXxnJrQc.d.ts} +80 -35
- package/dist/direct-executor-RBA5O7EN.mjs +12 -0
- package/dist/distribution/coordinator/etcd.d.ts +2 -2
- package/dist/distribution/coordinator/etcd.mjs +1 -1
- package/dist/distribution/coordinator/in-memory.d.ts +2 -2
- package/dist/distribution/transport/grpc.mjs +1 -1
- package/dist/distribution.d.ts +8 -8
- package/dist/distribution.mjs +12 -12
- package/dist/embeddings/openai.mjs +1 -1
- package/dist/{engine-zhms1qId.d.ts → engine-Dj4I91Jv.d.ts} +21 -8
- package/dist/index.browser.mjs +169 -72
- package/dist/index.d.ts +7 -7
- package/dist/index.mjs +10 -10
- package/dist/{memory-OmgkX_Z2.d.ts → memory-xrXOZMbw.d.ts} +58 -13
- package/dist/persistence/durability/checkpoint-worker.d.ts +1 -1
- package/dist/persistence/durability/checkpoint-worker.mjs +10 -10
- package/dist/react.d.ts +11 -11
- package/dist/react.mjs +16 -4
- package/dist/{schema-OSWaaZzx.d.ts → schema-mLpXZBEh.d.ts} +13 -6
- package/dist/server.d.ts +13 -10
- package/dist/server.mjs +68 -20
- package/dist/{tasks-DiF1c9v2.d.ts → tasks-Df73Tjgq.d.ts} +9 -5
- package/dist/{thread-TLCX43WV.mjs → thread-5UP6MGED.mjs} +8 -8
- package/dist/{types-LEzMyjVX.d.ts → types-BTIVO8DI.d.ts} +1 -1
- package/dist/vector/search-worker.d.ts +1 -1
- package/dist/vector/search-worker.mjs +3 -3
- package/dist/workers/entry.mjs +23 -10
- package/package.json +7 -7
- package/dist/chunk-WFKIGEBY.mjs +0 -11
- package/dist/direct-executor-UJC36S2D.mjs +0 -12
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { MAX_INDEX_NAME_LENGTH, INDEX_NAME_PATTERN, MAX_DOC_ID_LENGTH, DEFAULT_LIMIT, DEFAULT_SUGGEST_LIMIT, MAX_SUGGEST_LIMIT, MAX_SUGGEST_SCATTER_LIMIT, DEFAULT_OFFSET } from './chunk-
|
|
2
|
-
import { clampRowCount, sortSignatureOf, requireSortableFields, decodePageCursor, requireMatchingCursor, resolveProjection, encodePageCursor, requireWithinResultWindow, normalizeSort, fanOutQuery, applySorting, applyPagination, countsWithoutScores, fanOutMatchCount, tokenize, fnv1aBytes, fulltextMatches, mergeFacets, pruneStatsToQueryTerms, partitionsIn } from './chunk-
|
|
3
|
-
import { flattenSchema } from './chunk-
|
|
1
|
+
import { MAX_INDEX_NAME_LENGTH, INDEX_NAME_PATTERN, MAX_DOC_ID_LENGTH, DEFAULT_LIMIT, DEFAULT_SUGGEST_LIMIT, MAX_SUGGEST_LIMIT, MAX_SUGGEST_SCATTER_LIMIT, ABSOLUTE_WINDOWS_PATH_PATTERN, MODULE_URL_SCHEME_PATTERN, DEFAULT_OFFSET } from './chunk-D2S642IV.mjs';
|
|
2
|
+
import { clampRowCount, sortSignatureOf, requireSortableFields, decodePageCursor, requireMatchingCursor, resolveProjection, encodePageCursor, requireWithinResultWindow, normalizeSort, fanOutQuery, applySorting, applyPagination, projectionKeepsField, countsWithoutScores, fanOutMatchCount, tokenize, fnv1aBytes, fulltextMatches, mergeFacets, pruneStatsToQueryTerms, partitionsIn } from './chunk-5T6AOR37.mjs';
|
|
3
|
+
import { flattenSchema } from './chunk-L225SHNB.mjs';
|
|
4
4
|
import { MIN_OVERSAMPLE } from './chunk-ZJ4CSAB2.mjs';
|
|
5
5
|
import { compareCodePoints, compareComparableKeys } from './chunk-2GWVQWGA.mjs';
|
|
6
|
-
import { NarsilError, ErrorCodes } from './chunk-
|
|
6
|
+
import { NarsilError, ErrorCodes } from './chunk-FRQVMFY7.mjs';
|
|
7
7
|
|
|
8
8
|
// src/search/cursor-binding.ts
|
|
9
9
|
var ABSENT_TAG = 0;
|
|
@@ -171,32 +171,37 @@ function now() {
|
|
|
171
171
|
return Date.now();
|
|
172
172
|
}
|
|
173
173
|
function validateIndexName(name) {
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
const given = name;
|
|
175
|
+
if (typeof given !== "string" || name.length === 0) {
|
|
176
|
+
throw new NarsilError(ErrorCodes.CONFIG_INVALID, "Index name must be a string of at least one character", {
|
|
177
|
+
received: given === null ? "null" : typeof given
|
|
178
|
+
});
|
|
176
179
|
}
|
|
177
180
|
if (name.length > MAX_INDEX_NAME_LENGTH) {
|
|
178
|
-
throw new NarsilError(
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
indexName: name,
|
|
183
|
-
length: name.length
|
|
184
|
-
}
|
|
185
|
-
);
|
|
181
|
+
throw new NarsilError(ErrorCodes.CONFIG_INVALID, `Index name must not exceed ${MAX_INDEX_NAME_LENGTH} characters`, {
|
|
182
|
+
indexName: name,
|
|
183
|
+
length: name.length
|
|
184
|
+
});
|
|
186
185
|
}
|
|
187
186
|
if (!INDEX_NAME_PATTERN.test(name)) {
|
|
188
187
|
throw new NarsilError(
|
|
189
|
-
ErrorCodes.
|
|
188
|
+
ErrorCodes.CONFIG_INVALID,
|
|
190
189
|
`Index name "${name}" contains invalid characters; use alphanumeric, dots, hyphens, and underscores only`,
|
|
191
190
|
{ indexName: name }
|
|
192
191
|
);
|
|
193
192
|
}
|
|
194
193
|
if (name.includes("..")) {
|
|
195
|
-
throw new NarsilError(ErrorCodes.
|
|
194
|
+
throw new NarsilError(ErrorCodes.CONFIG_INVALID, `Index name "${name}" must not contain ".."`, { indexName: name });
|
|
196
195
|
}
|
|
197
196
|
}
|
|
198
197
|
function validateDocId(docId) {
|
|
199
|
-
|
|
198
|
+
const given = docId;
|
|
199
|
+
if (typeof given !== "string") {
|
|
200
|
+
throw new NarsilError(ErrorCodes.DOC_VALIDATION_FAILED, "Document ID must be a string", {
|
|
201
|
+
received: given === null ? "null" : Array.isArray(given) ? "array" : typeof given
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
if (docId.length === 0) {
|
|
200
205
|
throw new NarsilError(ErrorCodes.DOC_VALIDATION_FAILED, "Document ID must not be empty", { docId });
|
|
201
206
|
}
|
|
202
207
|
if (docId.length > MAX_DOC_ID_LENGTH) {
|
|
@@ -237,6 +242,16 @@ function requirePositiveSafeInteger(field, value) {
|
|
|
237
242
|
throw new NarsilError(ErrorCodes.CONFIG_INVALID, `${field} must be a positive safe integer`, { field, value });
|
|
238
243
|
}
|
|
239
244
|
}
|
|
245
|
+
function validateBootstrapModule(bootstrapModule) {
|
|
246
|
+
if (bootstrapModule === void 0) return;
|
|
247
|
+
const absolute = bootstrapModule.startsWith("/") || ABSOLUTE_WINDOWS_PATH_PATTERN.test(bootstrapModule) || MODULE_URL_SCHEME_PATTERN.test(bootstrapModule);
|
|
248
|
+
if (absolute) return;
|
|
249
|
+
throw new NarsilError(
|
|
250
|
+
ErrorCodes.CONFIG_INVALID,
|
|
251
|
+
`workers.bootstrapModule is "${bootstrapModule}", which a worker would resolve against Narsil's own directory, so pass an absolute path or a URL such as new URL('./bootstrap.js', import.meta.url).href`,
|
|
252
|
+
{ bootstrapModule }
|
|
253
|
+
);
|
|
254
|
+
}
|
|
240
255
|
function validateWorkerConfig(workers, lifecycle) {
|
|
241
256
|
if (workers === void 0) return;
|
|
242
257
|
requirePositiveSafeInteger("workers.count", workers.count);
|
|
@@ -247,6 +262,7 @@ function validateWorkerConfig(workers, lifecycle) {
|
|
|
247
262
|
mainCopyQueries: workers.mainCopyQueries
|
|
248
263
|
});
|
|
249
264
|
}
|
|
265
|
+
validateBootstrapModule(workers.bootstrapModule);
|
|
250
266
|
const closeAfter = lifecycle?.idleTimeoutMs;
|
|
251
267
|
if (workers.idleTimeoutMs !== void 0 && closeAfter !== void 0 && workers.idleTimeoutMs > closeAfter) {
|
|
252
268
|
throw new NarsilError(
|
|
@@ -568,21 +584,19 @@ function findDensestWindow(positions, text, windowSize) {
|
|
|
568
584
|
}
|
|
569
585
|
function applySnippetTruncation(taggedText, originalText, positions, maxLen, preTag, postTag) {
|
|
570
586
|
if (maxLen <= 0 || originalText.length <= maxLen) {
|
|
571
|
-
return { snippet: taggedText,
|
|
587
|
+
return { snippet: taggedText, visiblePositions: positions };
|
|
572
588
|
}
|
|
573
589
|
const window = findDensestWindow(positions, originalText, maxLen);
|
|
574
590
|
const snippetRaw = originalText.substring(window.start, window.end);
|
|
575
|
-
const
|
|
591
|
+
const visiblePositions = [];
|
|
592
|
+
const withinSnippet = [];
|
|
576
593
|
for (const pos of positions) {
|
|
577
|
-
if (pos.start
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
end: pos.end - window.start
|
|
581
|
-
});
|
|
582
|
-
}
|
|
594
|
+
if (pos.start < window.start || pos.end > window.end) continue;
|
|
595
|
+
visiblePositions.push(pos);
|
|
596
|
+
withinSnippet.push({ start: pos.start - window.start, end: pos.end - window.start });
|
|
583
597
|
}
|
|
584
598
|
let snippet = snippetRaw;
|
|
585
|
-
const sortedDesc = [...
|
|
599
|
+
const sortedDesc = [...withinSnippet].sort((a, b) => b.start - a.start);
|
|
586
600
|
for (const pos of sortedDesc) {
|
|
587
601
|
snippet = snippet.substring(0, pos.start) + preTag + snippet.substring(pos.start, pos.end) + postTag + snippet.substring(pos.end);
|
|
588
602
|
}
|
|
@@ -590,7 +604,7 @@ function applySnippetTruncation(taggedText, originalText, positions, maxLen, pre
|
|
|
590
604
|
const needsTrailingEllipsis = window.end < originalText.length;
|
|
591
605
|
if (needsLeadingEllipsis) snippet = `...${snippet}`;
|
|
592
606
|
if (needsTrailingEllipsis) snippet = `${snippet}...`;
|
|
593
|
-
return { snippet,
|
|
607
|
+
return { snippet, visiblePositions };
|
|
594
608
|
}
|
|
595
609
|
function highlightField(text, queryTokens, language, options) {
|
|
596
610
|
const preTag = options?.preTag ?? "<mark>";
|
|
@@ -637,7 +651,7 @@ function highlightField(text, queryTokens, language, options) {
|
|
|
637
651
|
return { snippet: text, positions: [] };
|
|
638
652
|
}
|
|
639
653
|
if (maxSnippetLength > 0 && text.length > maxSnippetLength) {
|
|
640
|
-
const { snippet,
|
|
654
|
+
const { snippet, visiblePositions } = applySnippetTruncation(
|
|
641
655
|
text,
|
|
642
656
|
text,
|
|
643
657
|
mergedPositions,
|
|
@@ -645,7 +659,7 @@ function highlightField(text, queryTokens, language, options) {
|
|
|
645
659
|
preTag,
|
|
646
660
|
postTag
|
|
647
661
|
);
|
|
648
|
-
return { snippet, positions:
|
|
662
|
+
return { snippet, positions: visiblePositions };
|
|
649
663
|
}
|
|
650
664
|
let result = text;
|
|
651
665
|
const sortedDesc = [...mergedPositions].sort((a, b) => b.start - a.start);
|
|
@@ -656,7 +670,7 @@ function highlightField(text, queryTokens, language, options) {
|
|
|
656
670
|
}
|
|
657
671
|
|
|
658
672
|
// src/engine/query/highlight.ts
|
|
659
|
-
function applyHighlights(hits, params, language, analysis) {
|
|
673
|
+
function applyHighlights(hits, params, language, analysis, readStoredDocument) {
|
|
660
674
|
if (!params.highlight) return;
|
|
661
675
|
const queryTokenResult = tokenize(params.term ?? "", language, {
|
|
662
676
|
stem: true,
|
|
@@ -682,9 +696,14 @@ function applyHighlights(hits, params, language, analysis) {
|
|
|
682
696
|
}
|
|
683
697
|
for (const hit of hits) {
|
|
684
698
|
const highlights = {};
|
|
699
|
+
const projected = hit.document;
|
|
700
|
+
let stored;
|
|
685
701
|
for (const field of params.highlight.fields) {
|
|
686
|
-
|
|
687
|
-
|
|
702
|
+
let fieldValue = projected[field];
|
|
703
|
+
if (typeof fieldValue !== "string" && readStoredDocument !== void 0) {
|
|
704
|
+
stored ??= readStoredDocument(hit.id);
|
|
705
|
+
fieldValue = stored?.[field];
|
|
706
|
+
}
|
|
688
707
|
if (typeof fieldValue === "string") {
|
|
689
708
|
highlights[field] = highlightField(fieldValue, queryTokenResult.tokens, language, {
|
|
690
709
|
preTag: params.highlight.preTag,
|
|
@@ -778,6 +797,32 @@ function vectorSearchersOf(context) {
|
|
|
778
797
|
function resolveVectorIndex(context, fieldName) {
|
|
779
798
|
return vectorSearchersOf(context).get(fieldName);
|
|
780
799
|
}
|
|
800
|
+
var SEARCH_MODES = /* @__PURE__ */ new Set(["fulltext", "vector", "hybrid"]);
|
|
801
|
+
function requireKnownMode(params) {
|
|
802
|
+
if (params.mode === void 0 || SEARCH_MODES.has(params.mode)) return;
|
|
803
|
+
throw new NarsilError(
|
|
804
|
+
ErrorCodes.SEARCH_INVALID_MODE,
|
|
805
|
+
`A search takes the mode "fulltext", "vector", or "hybrid", while this query names "${String(params.mode)}"`,
|
|
806
|
+
{ mode: String(params.mode), modes: [...SEARCH_MODES] }
|
|
807
|
+
);
|
|
808
|
+
}
|
|
809
|
+
function requireVectorSearchable(params, context, needsVector) {
|
|
810
|
+
if (!needsVector) return;
|
|
811
|
+
const field = params.vector?.field;
|
|
812
|
+
if (field === void 0) {
|
|
813
|
+
throw new NarsilError(
|
|
814
|
+
ErrorCodes.SEARCH_INVALID_MODE,
|
|
815
|
+
`A "${params.mode}" query needs a vector clause naming the field to search`,
|
|
816
|
+
{ mode: params.mode }
|
|
817
|
+
);
|
|
818
|
+
}
|
|
819
|
+
if (vectorSearchersOf(context).has(field)) return;
|
|
820
|
+
throw new NarsilError(
|
|
821
|
+
ErrorCodes.SEARCH_INVALID_FIELD,
|
|
822
|
+
`Field "${field}" has no vector index, so a vector search cannot use it`,
|
|
823
|
+
{ field, vectorFields: [...vectorSearchersOf(context).keys()] }
|
|
824
|
+
);
|
|
825
|
+
}
|
|
781
826
|
function clampAlpha(alpha) {
|
|
782
827
|
if (alpha === void 0) return 0.5;
|
|
783
828
|
if (!Number.isFinite(alpha)) return 0.5;
|
|
@@ -1065,6 +1110,7 @@ async function executeQuery(params, context) {
|
|
|
1065
1110
|
const offset = clampOffset(params.offset);
|
|
1066
1111
|
requireWithinResultWindow(limit, offset);
|
|
1067
1112
|
const sortFields = normalizeSort(params.sort);
|
|
1113
|
+
requireKnownMode(params);
|
|
1068
1114
|
const sortSignature = sortSignatureOf(params.sort);
|
|
1069
1115
|
const hasTerm = params.term !== void 0 && params.term.trim().length > 0;
|
|
1070
1116
|
const hasVector = params.vector !== void 0 && params.vector.value !== void 0;
|
|
@@ -1078,6 +1124,7 @@ async function executeQuery(params, context) {
|
|
|
1078
1124
|
);
|
|
1079
1125
|
}
|
|
1080
1126
|
requireSortableFields(params.sort, config.schema);
|
|
1127
|
+
requireVectorSearchable(params, context, isVectorOnly || isHybridMode);
|
|
1081
1128
|
let paginated;
|
|
1082
1129
|
let nextCursor;
|
|
1083
1130
|
let count;
|
|
@@ -1201,7 +1248,9 @@ async function executeQuery(params, context) {
|
|
|
1201
1248
|
}
|
|
1202
1249
|
}
|
|
1203
1250
|
if (params.highlight) {
|
|
1204
|
-
|
|
1251
|
+
const dropped = params.highlight.fields.some((field) => !projectionKeepsField(projection, field));
|
|
1252
|
+
const readStoredDocument = dropped ? (docId) => manager.get(docId, { kind: "full" }) : void 0;
|
|
1253
|
+
applyHighlights(paginated, params, language, manager.analysis, readStoredDocument);
|
|
1205
1254
|
}
|
|
1206
1255
|
const elapsed = now() - startTime;
|
|
1207
1256
|
return {
|
|
@@ -1217,10 +1266,12 @@ async function executeQuery(params, context) {
|
|
|
1217
1266
|
async function executePreflight(params, context) {
|
|
1218
1267
|
const { manager, language, config, workerSearch, indexName } = context;
|
|
1219
1268
|
const startTime = now();
|
|
1269
|
+
requireKnownMode(params);
|
|
1220
1270
|
const hasTerm = params.term !== void 0 && params.term.trim().length > 0;
|
|
1221
1271
|
const hasVector = params.vector !== void 0 && params.vector.value !== void 0;
|
|
1222
1272
|
const isHybridMode = params.mode === "hybrid" || hasTerm && hasVector;
|
|
1223
1273
|
const isVectorOnly = (params.mode === "vector" || hasVector && !hasTerm) && !isHybridMode;
|
|
1274
|
+
requireVectorSearchable(params, context, isVectorOnly || isHybridMode);
|
|
1224
1275
|
const requestedVectorField = params.vector?.field;
|
|
1225
1276
|
const hasGlobalVectorIndex = requestedVectorField !== void 0 && vectorSearchersOf(context).has(requestedVectorField);
|
|
1226
1277
|
let totalMatched;
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { OSQ_STEPS, OSQ_GRID, OSQ_REFINE_ROUNDS, OSQ_REFINE_TOLERANCE, OSQ4_NARROW_DIMENSION_LIMIT, DEFAULT_OSQ4_NARROW_OVERSAMPLE, DEFAULT_OVERSAMPLE_BY_BITS, OSQ_QUERY_BITS, OSQ_LAMBDA } from './chunk-ZJ4CSAB2.mjs';
|
|
2
|
-
import { COMPACTION_TOMBSTONE_RATIO, COMPACTION_ABSOLUTE_THRESHOLD, MAX_LAYER_CAP, PLACEMENT_ROOM_REQUESTS, INITIAL_LIST_CAPACITY, DEFAULT_EF_SEARCH, INITIAL_UPPER_SLOTS } from './chunk-
|
|
2
|
+
import { COMPACTION_TOMBSTONE_RATIO, COMPACTION_ABSOLUTE_THRESHOLD, nativeSearchCoreIsEnabled, loadNativeCore, stopUsingTheNativeSearchCore, noteFallback, MAX_LAYER_CAP, PLACEMENT_ROOM_REQUESTS, INITIAL_LIST_CAPACITY, DEFAULT_EF_SEARCH, INITIAL_UPPER_SLOTS } from './chunk-UTOFOJOR.mjs';
|
|
3
3
|
import { compareCodePoints } from './chunk-2GWVQWGA.mjs';
|
|
4
|
-
import { NarsilError, ErrorCodes } from './chunk-
|
|
5
|
-
import {
|
|
6
|
-
import { createRequire } from 'module';
|
|
7
|
-
import { join, dirname } from 'path';
|
|
4
|
+
import { NarsilError, ErrorCodes } from './chunk-FRQVMFY7.mjs';
|
|
5
|
+
import { readSync, closeSync, openSync } from 'fs';
|
|
8
6
|
|
|
9
7
|
// src/vector/constants.ts
|
|
10
8
|
var WASM_PAGE_BYTES = 65536;
|
|
@@ -185,97 +183,6 @@ function arenaFloat32Distance(simd, byteA, byteB, dimension, metric, magnitudeA,
|
|
|
185
183
|
return 1 - dot / (magnitudeA * magnitudeB);
|
|
186
184
|
}
|
|
187
185
|
|
|
188
|
-
// src/vector/native/backend.ts
|
|
189
|
-
var nativeSearchCoreEnabled = true;
|
|
190
|
-
function nativeSearchCoreIsEnabled() {
|
|
191
|
-
return nativeSearchCoreEnabled;
|
|
192
|
-
}
|
|
193
|
-
function stopUsingTheNativeSearchCore(error) {
|
|
194
|
-
if (!nativeSearchCoreEnabled) return;
|
|
195
|
-
nativeSearchCoreEnabled = false;
|
|
196
|
-
console.warn(
|
|
197
|
-
"The native search core raised an error, so this thread searches through WebAssembly from now on:",
|
|
198
|
-
error instanceof Error ? error.message : String(error)
|
|
199
|
-
);
|
|
200
|
-
}
|
|
201
|
-
function noteFallback(operation) {
|
|
202
|
-
}
|
|
203
|
-
var NATIVE_CORE_ABI_VERSION = 2;
|
|
204
|
-
var BINARY_FILE_NAME = "narsil-core.node";
|
|
205
|
-
var MUSL_DIRECTORY = "musl";
|
|
206
|
-
var PLATFORMS_WITH_A_BINARY = /* @__PURE__ */ new Set([
|
|
207
|
-
"darwin-arm64",
|
|
208
|
-
"darwin-x64",
|
|
209
|
-
"linux-arm64",
|
|
210
|
-
"linux-x64",
|
|
211
|
-
"win32-arm64",
|
|
212
|
-
"win32-x64"
|
|
213
|
-
]);
|
|
214
|
-
var loaded;
|
|
215
|
-
function usesMuslLibc() {
|
|
216
|
-
try {
|
|
217
|
-
const report = process.report.getReport();
|
|
218
|
-
return report.header?.glibcVersionRuntime === void 0;
|
|
219
|
-
} catch {
|
|
220
|
-
return false;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
function publishedBinaryPath(require2) {
|
|
224
|
-
const target = `${process.platform}-${process.arch}`;
|
|
225
|
-
if (!PLATFORMS_WITH_A_BINARY.has(target)) return null;
|
|
226
|
-
try {
|
|
227
|
-
const manifest = require2.resolve(`@delali/narsil-native-${target}/package.json`);
|
|
228
|
-
const segments = process.platform === "linux" && usesMuslLibc() ? [MUSL_DIRECTORY, BINARY_FILE_NAME] : [BINARY_FILE_NAME];
|
|
229
|
-
return join(dirname(manifest), ...segments);
|
|
230
|
-
} catch {
|
|
231
|
-
return null;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
function namedBinaryPath() {
|
|
235
|
-
const named = process.env.NARSIL_NATIVE_CORE_PATH;
|
|
236
|
-
return named !== void 0 && named.length > 0 ? named : null;
|
|
237
|
-
}
|
|
238
|
-
function refuseToSearchWithoutTheCore(reason) {
|
|
239
|
-
throw new NarsilError(ErrorCodes.CONFIG_INVALID, `NARSIL_REQUIRE_NATIVE_CORE is 1, and ${reason}`, {
|
|
240
|
-
platform: `${process.platform}-${process.arch}`
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
function reportMissingCore(reason, named) {
|
|
244
|
-
if (process.env.NARSIL_REQUIRE_NATIVE_CORE === "1") refuseToSearchWithoutTheCore(reason);
|
|
245
|
-
if (named) console.warn(`Narsil searches through WebAssembly in this process, because ${reason}.`);
|
|
246
|
-
return null;
|
|
247
|
-
}
|
|
248
|
-
function loadedCore(path) {
|
|
249
|
-
const require2 = createRequire(import.meta.url);
|
|
250
|
-
const core = require2(path);
|
|
251
|
-
if (typeof core.abiVersion !== "function" || core.abiVersion() !== NATIVE_CORE_ABI_VERSION) return null;
|
|
252
|
-
return core;
|
|
253
|
-
}
|
|
254
|
-
function loadNativeCore() {
|
|
255
|
-
if (loaded !== void 0) return loaded;
|
|
256
|
-
loaded = null;
|
|
257
|
-
const named = namedBinaryPath();
|
|
258
|
-
if (process.env.NARSIL_SEARCH_BACKEND === "wasm") {
|
|
259
|
-
return reportMissingCore("NARSIL_SEARCH_BACKEND asks for the WebAssembly search", false);
|
|
260
|
-
}
|
|
261
|
-
const path = named ?? publishedBinaryPath(createRequire(import.meta.url));
|
|
262
|
-
if (path === null || !existsSync(path)) {
|
|
263
|
-
return reportMissingCore(`this platform has no native search core at ${path ?? "any known path"}`, named !== null);
|
|
264
|
-
}
|
|
265
|
-
try {
|
|
266
|
-
loaded = loadedCore(path);
|
|
267
|
-
} catch (error) {
|
|
268
|
-
return reportMissingCore(
|
|
269
|
-
`loading the native search core at ${path} failed with "${error instanceof Error ? error.message : String(error)}"`,
|
|
270
|
-
named !== null
|
|
271
|
-
);
|
|
272
|
-
}
|
|
273
|
-
if (loaded === null) {
|
|
274
|
-
return reportMissingCore(`the native search core at ${path} reports another ABI version`, named !== null);
|
|
275
|
-
}
|
|
276
|
-
return loaded;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
186
|
// src/vector/shared-buffers/growable.ts
|
|
280
187
|
function sharedMemoryAvailable() {
|
|
281
188
|
return typeof SharedArrayBuffer === "function";
|
|
@@ -1998,6 +1905,7 @@ function insertNode(state, ord, holdsGraphLock = false) {
|
|
|
1998
1905
|
writeRecordBeforePlacement(state, ord);
|
|
1999
1906
|
if (placeThroughTheCore(state, ord, holdsGraphLock)) return true;
|
|
2000
1907
|
if (nodeExists(state, ord)) return false;
|
|
1908
|
+
noteFallback("place");
|
|
2001
1909
|
if (!holdsGraphLock) lockGraphShared(state.locks);
|
|
2002
1910
|
try {
|
|
2003
1911
|
clearTombstone(state, ord);
|
|
@@ -2068,6 +1976,7 @@ function markTombstone(state, ord) {
|
|
|
2068
1976
|
if (!nodeExists(state, ord) || !reachTombstone(state, ord)) return;
|
|
2069
1977
|
const field = nativeFieldFor(state);
|
|
2070
1978
|
if (field !== null && nativeRemove(state, field, ord)) return;
|
|
1979
|
+
noteFallback("remove");
|
|
2071
1980
|
if (Atomics.compareExchange(state.tombstones, ord, 0, 1) === 0) {
|
|
2072
1981
|
Atomics.add(state.header, GRAPH_TOMBSTONE_COUNT, 1);
|
|
2073
1982
|
}
|
|
@@ -2083,6 +1992,7 @@ function compactTombstones(state) {
|
|
|
2083
1992
|
if (Atomics.load(state.header, GRAPH_TOMBSTONE_COUNT) === 0) return;
|
|
2084
1993
|
const field = nativeFieldFor(state);
|
|
2085
1994
|
if (field !== null && nativeCompact(state, field, state.buildMetric)) return;
|
|
1995
|
+
noteFallback("compact");
|
|
2086
1996
|
const tombstonedOrds = [];
|
|
2087
1997
|
const slots = adjacencySlots(state.adjacency);
|
|
2088
1998
|
for (let ord = 0; ord < slots; ord++) {
|
|
@@ -2236,6 +2146,7 @@ function traverse(state, query, k, searchMetric, options) {
|
|
|
2236
2146
|
return { candidates, depth: useQuantized ? depth : 0, arenaQuery: null, qMag: 0, native };
|
|
2237
2147
|
}
|
|
2238
2148
|
}
|
|
2149
|
+
noteFallback("search");
|
|
2239
2150
|
const store = state.store;
|
|
2240
2151
|
const arenaQuery = store.prepareQueryArena(query);
|
|
2241
2152
|
const qMag = arenaQuery ? arenaQuery.magnitude : magnitude(query);
|
|
@@ -2361,6 +2272,7 @@ function collectHits(state, query, k, searchMetric, minSimilarity, options) {
|
|
|
2361
2272
|
return hits;
|
|
2362
2273
|
}
|
|
2363
2274
|
function rescoreWithFullPrecision(state, candidates, query, qMag, arenaQuery, depth, metric, minSimilarity, filter) {
|
|
2275
|
+
noteFallback("score");
|
|
2364
2276
|
const rescored = [];
|
|
2365
2277
|
const nearest = Math.min(candidates.size, depth);
|
|
2366
2278
|
for (let i = 0; i < nearest; i++) {
|
|
@@ -2632,6 +2544,7 @@ function openSharedQuantizer(store, layout, metric) {
|
|
|
2632
2544
|
function writeCodesOf(ordinals) {
|
|
2633
2545
|
if (!isCalibrated() || ordinals.length === 0) return;
|
|
2634
2546
|
if (nativeQuantise(store.handles, metric, ordinals)) return;
|
|
2547
|
+
noteFallback("quantise");
|
|
2635
2548
|
for (const ordinal of ordinals) writeRecordOf(ordinal);
|
|
2636
2549
|
}
|
|
2637
2550
|
function stageQuery(block, query) {
|
|
@@ -2728,6 +2641,7 @@ function openSharedQuantizer(store, layout, metric) {
|
|
|
2728
2641
|
writeCodesOf,
|
|
2729
2642
|
calibrateFrom(ordinals) {
|
|
2730
2643
|
if (nativeCalibrate(store.handles, metric, ordinals)) return isCalibrated();
|
|
2644
|
+
noteFallback("calibrate");
|
|
2731
2645
|
const centroid = osqCentroid(storedVectors(ordinals), dimension, metric);
|
|
2732
2646
|
if (centroid === null) return false;
|
|
2733
2647
|
writeCentroid(centroid);
|
|
@@ -4189,7 +4103,11 @@ function createHNSWIndex(dimension, store, config, quantizer, handles) {
|
|
|
4189
4103
|
throw new Error(`Cannot insert HNSW node: vector for "${docId}" not found in VectorStore`);
|
|
4190
4104
|
}
|
|
4191
4105
|
if (entry.vector.length !== dimension) {
|
|
4192
|
-
throw new
|
|
4106
|
+
throw new NarsilError(
|
|
4107
|
+
ErrorCodes.VECTOR_DIMENSION_MISMATCH,
|
|
4108
|
+
`Vector dimension mismatch: expected ${dimension}, got ${entry.vector.length}`,
|
|
4109
|
+
{ docId, expected: dimension, received: entry.vector.length }
|
|
4110
|
+
);
|
|
4193
4111
|
}
|
|
4194
4112
|
insertNode(state, ord);
|
|
4195
4113
|
}
|
|
@@ -4277,4 +4195,4 @@ function createHNSWIndex(dimension, store, config, quantizer, handles) {
|
|
|
4277
4195
|
};
|
|
4278
4196
|
}
|
|
4279
4197
|
|
|
4280
|
-
export { DISK_STORAGE_BLOCK_BYTES, GRAPH_BUILD_CHUNKS_IN_FLIGHT_PER_WORKER, GRAPH_BUILD_DISPATCH_CHUNK, MAX_WORKER_COPIES, SCRATCH_SLOTS_PER_THREAD_POOL, STORE_CALIBRATION_GENERATION, VECTOR_INSERT_TIMEOUT_MS, VECTOR_SCRATCH_SLOTS, VECTOR_SEARCH_LOAD_TIMEOUT_MS, VECTOR_SEARCH_TIMEOUT_MS, addToOrdinalFilter, cosineSimilarityWithMagnitudes, createHNSWIndex, createOrdinalFilter, createOsqQuantizer, createVectorStore, dotProduct, entryForOrd, euclideanDistance, isSimdAvailable, isTombstoned, magnitude, nativeScoresOf, nativeStoreScratchBytes,
|
|
4198
|
+
export { DISK_STORAGE_BLOCK_BYTES, GRAPH_BUILD_CHUNKS_IN_FLIGHT_PER_WORKER, GRAPH_BUILD_DISPATCH_CHUNK, MAX_WORKER_COPIES, SCRATCH_SLOTS_PER_THREAD_POOL, STORE_CALIBRATION_GENERATION, VECTOR_INSERT_TIMEOUT_MS, VECTOR_SCRATCH_SLOTS, VECTOR_SEARCH_LOAD_TIMEOUT_MS, VECTOR_SEARCH_TIMEOUT_MS, addToOrdinalFilter, cosineSimilarityWithMagnitudes, createHNSWIndex, createOrdinalFilter, createOsqQuantizer, createVectorStore, dotProduct, entryForOrd, euclideanDistance, isSimdAvailable, isTombstoned, magnitude, nativeScoresOf, nativeStoreScratchBytes, openSharedVectorField, ordinalFilterHas, ordinalFilterValues, osqBitsOf, osqRecordBytes, releaseLocksHeldBy, removeFromOrdinalFilter, requireWholeNeighbourLists, sharedMemoryAvailable, toDistance, toScore };
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { NarsilError, ErrorCodes } from './chunk-FRQVMFY7.mjs';
|
|
2
|
+
import { existsSync } from 'fs';
|
|
3
|
+
import { createRequire } from 'module';
|
|
4
|
+
import { join, dirname } from 'path';
|
|
5
|
+
|
|
6
|
+
// src/vector/hnsw/constants.ts
|
|
7
|
+
var MAX_LAYER_CAP = 32;
|
|
8
|
+
var MAX_M = 512;
|
|
9
|
+
var INITIAL_UPPER_SLOTS = 64;
|
|
10
|
+
var INITIAL_LIST_CAPACITY = 64;
|
|
11
|
+
var PLACEMENT_ROOM_REQUESTS = 8;
|
|
12
|
+
var COMPACTION_TOMBSTONE_RATIO = 0.1;
|
|
13
|
+
var COMPACTION_ABSOLUTE_THRESHOLD = 1e3;
|
|
14
|
+
var DEFAULT_EF_SEARCH = 50;
|
|
15
|
+
|
|
16
|
+
// src/vector/native/backend.ts
|
|
17
|
+
var nativeSearchCoreEnabled = true;
|
|
18
|
+
function nativeSearchCoreIsEnabled() {
|
|
19
|
+
return nativeSearchCoreEnabled;
|
|
20
|
+
}
|
|
21
|
+
function stopUsingTheNativeSearchCore(error) {
|
|
22
|
+
if (!nativeSearchCoreEnabled) return;
|
|
23
|
+
nativeSearchCoreEnabled = false;
|
|
24
|
+
console.warn(
|
|
25
|
+
"The native search core raised an error, so this thread searches through WebAssembly from now on:",
|
|
26
|
+
error instanceof Error ? error.message : String(error)
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
function noteFallback(operation) {
|
|
30
|
+
}
|
|
31
|
+
var NATIVE_CORE_ABI_VERSION = 2;
|
|
32
|
+
var BINARY_FILE_NAME = "narsil-core.node";
|
|
33
|
+
var MUSL_DIRECTORY = "musl";
|
|
34
|
+
var PLATFORMS_WITH_A_BINARY = /* @__PURE__ */ new Set([
|
|
35
|
+
"darwin-arm64",
|
|
36
|
+
"darwin-x64",
|
|
37
|
+
"linux-arm64",
|
|
38
|
+
"linux-x64",
|
|
39
|
+
"win32-arm64",
|
|
40
|
+
"win32-x64"
|
|
41
|
+
]);
|
|
42
|
+
var loaded;
|
|
43
|
+
function usesMuslLibc() {
|
|
44
|
+
try {
|
|
45
|
+
const report = process.report.getReport();
|
|
46
|
+
return report.header?.glibcVersionRuntime === void 0;
|
|
47
|
+
} catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function isUnavailable(value) {
|
|
52
|
+
return "missing" in value;
|
|
53
|
+
}
|
|
54
|
+
function binaryFileSegments() {
|
|
55
|
+
return process.platform === "linux" && usesMuslLibc() ? [MUSL_DIRECTORY, BINARY_FILE_NAME] : [BINARY_FILE_NAME];
|
|
56
|
+
}
|
|
57
|
+
function publishedCoreLocation(target) {
|
|
58
|
+
const packageName = `@delali/narsil-native-${target}`;
|
|
59
|
+
let manifest;
|
|
60
|
+
try {
|
|
61
|
+
manifest = createRequire(import.meta.url).resolve(`${packageName}/package.json`);
|
|
62
|
+
} catch {
|
|
63
|
+
return { missing: `this installation has no "${packageName}" package` };
|
|
64
|
+
}
|
|
65
|
+
const path = join(dirname(manifest), ...binaryFileSegments());
|
|
66
|
+
if (!existsSync(path)) return { missing: `the "${packageName}" package has no search core at ${path}` };
|
|
67
|
+
return { path };
|
|
68
|
+
}
|
|
69
|
+
function coreLocation() {
|
|
70
|
+
const named = process.env.NARSIL_NATIVE_CORE_PATH;
|
|
71
|
+
if (named !== void 0 && named.length > 0) {
|
|
72
|
+
if (!existsSync(named)) {
|
|
73
|
+
return { missing: `this process sets NARSIL_NATIVE_CORE_PATH to ${named}, where no file exists` };
|
|
74
|
+
}
|
|
75
|
+
return { path: named };
|
|
76
|
+
}
|
|
77
|
+
const target = `${process.platform}-${process.arch}`;
|
|
78
|
+
if (!PLATFORMS_WITH_A_BINARY.has(target)) {
|
|
79
|
+
return { missing: `the Narsil release includes no search core for ${target}` };
|
|
80
|
+
}
|
|
81
|
+
return publishedCoreLocation(target);
|
|
82
|
+
}
|
|
83
|
+
function refuseToSearchWithoutTheCore(reason) {
|
|
84
|
+
throw new NarsilError(ErrorCodes.CONFIG_INVALID, `NARSIL_REQUIRE_NATIVE_CORE is 1, yet ${reason}`, {
|
|
85
|
+
platform: `${process.platform}-${process.arch}`
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
function requestedBackend() {
|
|
89
|
+
const raw = process.env.NARSIL_SEARCH_BACKEND;
|
|
90
|
+
if (raw === void 0 || raw.trim().length === 0) return null;
|
|
91
|
+
const named = raw.trim().toLowerCase();
|
|
92
|
+
if (named === "native" || named === "wasm") return named;
|
|
93
|
+
throw new NarsilError(
|
|
94
|
+
ErrorCodes.CONFIG_INVALID,
|
|
95
|
+
`NARSIL_SEARCH_BACKEND takes either "native" or "wasm", while this environment sets it to "${raw}"`,
|
|
96
|
+
{ value: raw, backends: ["native", "wasm"] }
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
function reportMissingCore(reason, announce) {
|
|
100
|
+
if (process.env.NARSIL_REQUIRE_NATIVE_CORE === "1") refuseToSearchWithoutTheCore(reason);
|
|
101
|
+
loaded = null;
|
|
102
|
+
if (announce) console.warn(`Narsil searches through WebAssembly on this thread, because ${reason}.`);
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
function coreAt(path) {
|
|
106
|
+
let core;
|
|
107
|
+
try {
|
|
108
|
+
core = createRequire(import.meta.url)(path);
|
|
109
|
+
} catch (error) {
|
|
110
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
111
|
+
return { missing: `node raised "${message}" while loading the search core at ${path}` };
|
|
112
|
+
}
|
|
113
|
+
if (typeof core.abiVersion !== "function") return { missing: `the file at ${path} is no Narsil search core` };
|
|
114
|
+
const reported = core.abiVersion();
|
|
115
|
+
if (reported !== NATIVE_CORE_ABI_VERSION) {
|
|
116
|
+
return {
|
|
117
|
+
missing: `the search core at ${path} reports ABI version ${reported}, while this build of Narsil needs ${NATIVE_CORE_ABI_VERSION}`
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return core;
|
|
121
|
+
}
|
|
122
|
+
function loadNativeCore() {
|
|
123
|
+
if (loaded !== void 0) return loaded;
|
|
124
|
+
if (requestedBackend() === "wasm") {
|
|
125
|
+
return reportMissingCore("this process sets NARSIL_SEARCH_BACKEND to the WebAssembly search", false);
|
|
126
|
+
}
|
|
127
|
+
const location = coreLocation();
|
|
128
|
+
if (isUnavailable(location)) return reportMissingCore(location.missing, true);
|
|
129
|
+
const core = coreAt(location.path);
|
|
130
|
+
if (isUnavailable(core)) return reportMissingCore(core.missing, true);
|
|
131
|
+
loaded = core;
|
|
132
|
+
return loaded;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export { COMPACTION_ABSOLUTE_THRESHOLD, COMPACTION_TOMBSTONE_RATIO, DEFAULT_EF_SEARCH, INITIAL_LIST_CAPACITY, INITIAL_UPPER_SLOTS, MAX_LAYER_CAP, MAX_M, PLACEMENT_ROOM_REQUESTS, loadNativeCore, nativeSearchCoreIsEnabled, noteFallback, stopUsingTheNativeSearchCore };
|
|
@@ -1,21 +1,59 @@
|
|
|
1
1
|
import { detectRuntime } from './chunk-AV4IJKD2.mjs';
|
|
2
|
-
import { cloneProjected, mergeFacets, visitTokens, countsWithoutScores, fanOutMatchCount, fanOutQuery, sanitizeGlobalStats, projectionKeepsField, setNestedValue, fnv1a, bitsetHas, createBitSet, kWayMerge, boundedLevenshtein, bitsetSet, tokenize, bitsetFromSet, tokenizeIterator, bitsetAnd, bitsetOr, bitsetNot } from './chunk-
|
|
3
|
-
import { flattenSchema, validateDocument, validateDocumentStrict, isQuantizationMode, isStorageMode, extractVectorFieldsFromSchema, isTextFieldType, VECTOR_PATTERN } from './chunk-
|
|
2
|
+
import { cloneProjected, mergeFacets, visitTokens, countsWithoutScores, fanOutMatchCount, fanOutQuery, sanitizeGlobalStats, projectionKeepsField, setNestedValue, fnv1a, bitsetHas, createBitSet, kWayMerge, boundedLevenshtein, bitsetSet, tokenize, bitsetFromSet, tokenizeIterator, bitsetAnd, bitsetOr, bitsetNot } from './chunk-5T6AOR37.mjs';
|
|
3
|
+
import { flattenSchema, validateDocument, validateDocumentStrict, isQuantizationMode, isStorageMode, extractVectorFieldsFromSchema, isTextFieldType, VECTOR_PATTERN } from './chunk-L225SHNB.mjs';
|
|
4
4
|
import { english } from './chunk-TGP5M5R7.mjs';
|
|
5
|
-
import { SCRATCH_SLOTS_PER_THREAD_POOL, osqRecordBytes, openSharedVectorField, osqBitsOf, createVectorStore, DISK_STORAGE_BLOCK_BYTES, createOsqQuantizer, magnitude, createHNSWIndex, nativeStoreScratchBytes, createOrdinalFilter, addToOrdinalFilter, ordinalFilterValues, isTombstoned, nativeScoresOf, toScore, removeFromOrdinalFilter,
|
|
5
|
+
import { SCRATCH_SLOTS_PER_THREAD_POOL, osqRecordBytes, openSharedVectorField, osqBitsOf, createVectorStore, DISK_STORAGE_BLOCK_BYTES, createOsqQuantizer, magnitude, createHNSWIndex, nativeStoreScratchBytes, createOrdinalFilter, addToOrdinalFilter, ordinalFilterValues, isTombstoned, nativeScoresOf, toScore, removeFromOrdinalFilter, euclideanDistance, dotProduct, cosineSimilarityWithMagnitudes, ordinalFilterHas, requireWholeNeighbourLists, STORE_CALIBRATION_GENERATION, entryForOrd, toDistance, sharedMemoryAvailable, GRAPH_BUILD_CHUNKS_IN_FLIGHT_PER_WORKER, GRAPH_BUILD_DISPATCH_CHUNK, releaseLocksHeldBy, VECTOR_SEARCH_TIMEOUT_MS, VECTOR_SEARCH_LOAD_TIMEOUT_MS, VECTOR_INSERT_TIMEOUT_MS, VECTOR_SCRATCH_SLOTS } from './chunk-U2AL3SON.mjs';
|
|
6
|
+
import { noteFallback } from './chunk-UTOFOJOR.mjs';
|
|
6
7
|
import { VALID_HNSW_METRICS } from './chunk-IFBKLBGB.mjs';
|
|
7
8
|
import { compareCodePoints, toComparableSortValue, readSortField, compareComparableValues, SORT_VALUE_MAX_CODE_POINTS } from './chunk-2GWVQWGA.mjs';
|
|
8
|
-
import { NarsilError, ErrorCodes } from './chunk-
|
|
9
|
+
import { NarsilError, ErrorCodes } from './chunk-FRQVMFY7.mjs';
|
|
10
|
+
import { totalmem } from 'os';
|
|
9
11
|
import { getHeapStatistics } from 'v8';
|
|
10
12
|
import { encode, decode } from '@msgpack/msgpack';
|
|
11
13
|
|
|
14
|
+
var MEGABYTE_BYTES = 1048576;
|
|
15
|
+
var IN_MEGABYTES = /^--max-old-space-size=(\d+)$/;
|
|
16
|
+
var AS_PERCENTAGE = /^--max-old-space-size-percentage=(\d+(?:\.\d+)?)$/;
|
|
17
|
+
function flagEntries() {
|
|
18
|
+
const fromNodeOptions = (process.env.NODE_OPTIONS ?? "").split(/\s+/).filter((entry) => entry.length > 0);
|
|
19
|
+
return [...process.execArgv, ...fromNodeOptions];
|
|
20
|
+
}
|
|
21
|
+
function memoryTheHostAllows() {
|
|
22
|
+
const constrained = process.constrainedMemory?.() ?? 0;
|
|
23
|
+
return constrained > 0 ? constrained : totalmem();
|
|
24
|
+
}
|
|
25
|
+
function readConfiguredLimit() {
|
|
26
|
+
let megabytes = null;
|
|
27
|
+
let percentage = null;
|
|
28
|
+
for (const entry of flagEntries()) {
|
|
29
|
+
const inMegabytes = IN_MEGABYTES.exec(entry);
|
|
30
|
+
if (inMegabytes !== null) {
|
|
31
|
+
megabytes = Number(inMegabytes[1]);
|
|
32
|
+
percentage = null;
|
|
33
|
+
}
|
|
34
|
+
const asPercentage = AS_PERCENTAGE.exec(entry);
|
|
35
|
+
if (asPercentage !== null) {
|
|
36
|
+
percentage = Number(asPercentage[1]);
|
|
37
|
+
megabytes = null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const bytes = megabytes !== null && megabytes > 0 ? megabytes * MEGABYTE_BYTES : percentage !== null && percentage > 0 && percentage <= 100 ? Math.floor(memoryTheHostAllows() * percentage / 100) : null;
|
|
41
|
+
return bytes !== null && Number.isFinite(bytes) && bytes > 0 ? bytes : null;
|
|
42
|
+
}
|
|
43
|
+
var configuredLimit;
|
|
44
|
+
function configuredLimitBytes() {
|
|
45
|
+
if (configuredLimit === void 0) configuredLimit = readConfiguredLimit();
|
|
46
|
+
return configuredLimit;
|
|
47
|
+
}
|
|
12
48
|
function readHeapStatistics() {
|
|
13
49
|
try {
|
|
14
50
|
const stats = getHeapStatistics();
|
|
15
51
|
const usedBytes = stats.used_heap_size;
|
|
16
52
|
const limitBytes = stats.heap_size_limit;
|
|
17
53
|
if (!Number.isFinite(usedBytes) || !Number.isFinite(limitBytes) || limitBytes <= 0) return null;
|
|
18
|
-
|
|
54
|
+
const available = stats.total_available_size;
|
|
55
|
+
const availableBytes = Number.isFinite(available) && available >= 0 ? available : null;
|
|
56
|
+
return { usedBytes, limitBytes, availableBytes, configuredLimitBytes: configuredLimitBytes() };
|
|
19
57
|
} catch {
|
|
20
58
|
return null;
|
|
21
59
|
}
|
|
@@ -8421,8 +8459,9 @@ function completeGraph(state) {
|
|
|
8421
8459
|
}
|
|
8422
8460
|
function maintenanceStatus(state) {
|
|
8423
8461
|
const storeSize = state.store.size;
|
|
8424
|
-
const tombstoneRatio = storeSize > 0 ? state.tombstones.size / storeSize : 0;
|
|
8425
8462
|
const graphCount = state.hnsw ? 1 : 0;
|
|
8463
|
+
const graphNodes = state.hnsw === null ? storeSize : state.hnsw.size + state.hnsw.tombstoneCount;
|
|
8464
|
+
const tombstoneRatio = graphNodes > 0 ? state.tombstones.size / graphNodes : 0;
|
|
8426
8465
|
const estimatedCompactMs = Math.round(state.tombstones.size * ESTIMATED_MS_PER_TOMBSTONE * state.dimensionScale);
|
|
8427
8466
|
const optimizeVectorCount = state.hnsw === null || graphNeedsRebuild(state) ? storeSize : state.buffer.size;
|
|
8428
8467
|
const estimatedOptimizeMs = Math.round(optimizeVectorCount * ESTIMATED_MS_PER_VECTOR_REBUILD * state.dimensionScale);
|
|
@@ -8642,7 +8681,11 @@ function search(state, query, k, options) {
|
|
|
8642
8681
|
}
|
|
8643
8682
|
function searchWithFilter(state, query, k, options, filter) {
|
|
8644
8683
|
if (query.length !== state.dimension) {
|
|
8645
|
-
throw new
|
|
8684
|
+
throw new NarsilError(
|
|
8685
|
+
ErrorCodes.VECTOR_DIMENSION_MISMATCH,
|
|
8686
|
+
`Vector dimension mismatch: expected ${state.dimension}, got ${query.length}`,
|
|
8687
|
+
{ expected: state.dimension, received: query.length }
|
|
8688
|
+
);
|
|
8646
8689
|
}
|
|
8647
8690
|
const currentLiveSize = liveSize(state);
|
|
8648
8691
|
if (currentLiveSize === 0) return [];
|
|
@@ -11217,7 +11260,9 @@ function createDirectExecutor(options) {
|
|
|
11217
11260
|
}
|
|
11218
11261
|
case "memoryReport": {
|
|
11219
11262
|
const usage = typeof process !== "undefined" && process.memoryUsage ? process.memoryUsage() : {};
|
|
11220
|
-
|
|
11263
|
+
const heap = readHeapStatistics();
|
|
11264
|
+
const heapLimit = heap === null ? null : heap.configuredLimitBytes ?? heap.limitBytes;
|
|
11265
|
+
return { ...usage, heapLimit };
|
|
11221
11266
|
}
|
|
11222
11267
|
case "shutdown": {
|
|
11223
11268
|
for (const [, entry] of indexes) {
|