@delali/narsil 0.2.3 → 0.2.4-next.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/filesystem.mjs +1 -1
- package/dist/adapters/indexeddb.mjs +1 -1
- package/dist/{chunk-MMSWEEZT.mjs → chunk-KEDL6FFZ.mjs} +315 -51
- package/dist/{chunk-WU2UZEVD.mjs → chunk-O4Q5JYNK.mjs} +1 -1
- package/dist/{chunk-GB2IIJJG.mjs → chunk-TLRUUMVE.mjs} +1 -4
- package/dist/{chunk-GRWFY2HI.mjs → chunk-YGQMKTKG.mjs} +120 -36
- package/dist/{client-BobVnoIK.d.ts → client-B5uO5jL1.d.ts} +3 -3
- package/dist/client.d.ts +8 -8
- package/dist/client.mjs +1 -4
- package/dist/{config-Byyl1QqH.d.ts → config-B09-cud9.d.ts} +2 -2
- package/dist/{config-fLC4lbmg.d.ts → config-NgUCkc6a.d.ts} +2 -2
- package/dist/{direct-executor-MSJEVPZU.mjs → direct-executor-7O23GEHE.mjs} +2 -2
- 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 +705 -272
- package/dist/embeddings/openai.mjs +1 -1
- package/dist/{engine-BE45D5ZG.d.ts → engine-CjLhdDIm.d.ts} +21 -20
- package/dist/index.browser.mjs +436 -91
- package/dist/index.d.ts +7 -7
- package/dist/index.mjs +4 -4
- package/dist/{options-EXYFcem-.d.ts → options-BakECW-r.d.ts} +2 -2
- package/dist/persistence/durability/checkpoint-worker.d.ts +1 -1
- package/dist/persistence/durability/checkpoint-worker.mjs +4 -4
- package/dist/react.d.ts +6 -6
- package/dist/react.mjs +1 -4
- package/dist/{schema-ZRbk8BgH.d.ts → schema-DXOd96kx.d.ts} +16 -5
- package/dist/{search-DHuXwJYk.d.ts → search-BGouJxH4.d.ts} +22 -9
- package/dist/server.d.ts +10 -10
- package/dist/server.mjs +6 -9
- package/dist/{tasks-CnMLpfk-.d.ts → tasks-Bn4R1NPN.d.ts} +1 -1
- package/dist/{types-B5Tsaalz.d.ts → types-BTE33VZS.d.ts} +1 -1
- package/dist/workers/entry.mjs +2 -2
- package/package.json +2 -2
package/dist/index.browser.mjs
CHANGED
|
@@ -3,7 +3,6 @@ import { encode, decode } from '@msgpack/msgpack';
|
|
|
3
3
|
// src/errors.ts
|
|
4
4
|
var ErrorCodes = {
|
|
5
5
|
SCHEMA_INVALID_TYPE: "SCHEMA_INVALID_TYPE",
|
|
6
|
-
SCHEMA_MISSING_FIELD: "SCHEMA_MISSING_FIELD",
|
|
7
6
|
SCHEMA_DEPTH_EXCEEDED: "SCHEMA_DEPTH_EXCEEDED",
|
|
8
7
|
SCHEMA_INVALID_VECTOR_DIMENSION: "SCHEMA_INVALID_VECTOR_DIMENSION",
|
|
9
8
|
SCHEMA_INVALID_GEOPOINT: "SCHEMA_INVALID_GEOPOINT",
|
|
@@ -25,7 +24,6 @@ var ErrorCodes = {
|
|
|
25
24
|
PERSISTENCE_WAL_CORRUPT: "PERSISTENCE_WAL_CORRUPT",
|
|
26
25
|
PERSISTENCE_FSYNC_FAILED: "PERSISTENCE_FSYNC_FAILED",
|
|
27
26
|
SEARCH_INVALID_FIELD: "SEARCH_INVALID_FIELD",
|
|
28
|
-
SEARCH_INVALID_VECTOR_SIZE: "SEARCH_INVALID_VECTOR_SIZE",
|
|
29
27
|
VECTOR_DIMENSION_MISMATCH: "VECTOR_DIMENSION_MISMATCH",
|
|
30
28
|
SEARCH_INVALID_FILTER: "SEARCH_INVALID_FILTER",
|
|
31
29
|
SEARCH_INVALID_MODE: "SEARCH_INVALID_MODE",
|
|
@@ -49,8 +47,6 @@ var ErrorCodes = {
|
|
|
49
47
|
ALLOCATION_NO_DATA_NODES: "ALLOCATION_NO_DATA_NODES",
|
|
50
48
|
ALLOCATION_INVALID_CONFIG: "ALLOCATION_INVALID_CONFIG",
|
|
51
49
|
ALLOCATION_FAILED: "ALLOCATION_FAILED",
|
|
52
|
-
CONTROLLER_LEASE_LOST: "CONTROLLER_LEASE_LOST",
|
|
53
|
-
CONTROLLER_NOT_ACTIVE: "CONTROLLER_NOT_ACTIVE",
|
|
54
50
|
CONTROLLER_METADATA_INVALID: "CONTROLLER_METADATA_INVALID",
|
|
55
51
|
NODE_BOOTSTRAP_FAILED: "NODE_BOOTSTRAP_FAILED",
|
|
56
52
|
NODE_ALREADY_JOINED: "NODE_ALREADY_JOINED",
|
|
@@ -106,6 +102,7 @@ var ServerErrorCodes = {
|
|
|
106
102
|
TASK_NOT_FOUND: "TASK_NOT_FOUND",
|
|
107
103
|
TASK_NOT_CANCELLABLE: "TASK_NOT_CANCELLABLE",
|
|
108
104
|
TASK_OWNED_BY_ANOTHER_INSTANCE: "TASK_OWNED_BY_ANOTHER_INSTANCE",
|
|
105
|
+
TASK_INTERRUPTED: "TASK_INTERRUPTED",
|
|
109
106
|
TOO_MANY_REQUESTS: "TOO_MANY_REQUESTS",
|
|
110
107
|
HOOK_ERROR: "HOOK_ERROR",
|
|
111
108
|
INTERNAL_ERROR: "INTERNAL_ERROR"
|
|
@@ -2622,7 +2619,7 @@ function wireToMetadata(raw) {
|
|
|
2622
2619
|
if (isPositiveInteger2(promotion.threshold)) {
|
|
2623
2620
|
restored.threshold = promotion.threshold;
|
|
2624
2621
|
}
|
|
2625
|
-
if (
|
|
2622
|
+
if (isSelectivityRatio(promotion.filter_threshold)) {
|
|
2626
2623
|
restored.filterThreshold = promotion.filter_threshold;
|
|
2627
2624
|
}
|
|
2628
2625
|
if (Object.keys(hnswConfig).length > 0) {
|
|
@@ -2649,6 +2646,9 @@ function isNonNegativeInteger(value) {
|
|
|
2649
2646
|
function isPositiveInteger2(value) {
|
|
2650
2647
|
return typeof value === "number" && Number.isInteger(value) && value >= 1;
|
|
2651
2648
|
}
|
|
2649
|
+
function isSelectivityRatio(value) {
|
|
2650
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= 1;
|
|
2651
|
+
}
|
|
2652
2652
|
function isWatermarkFraction(value) {
|
|
2653
2653
|
return typeof value === "number" && value > 0 && value <= 1;
|
|
2654
2654
|
}
|
|
@@ -8079,7 +8079,7 @@ function createRebalancer() {
|
|
|
8079
8079
|
skipClone: true,
|
|
8080
8080
|
stopWordOverride: manager.analysis.stopWords,
|
|
8081
8081
|
customTokenizer: manager.analysis.customTokenizer,
|
|
8082
|
-
collectSurfaces: manager.config.surfaceForms
|
|
8082
|
+
collectSurfaces: manager.config.surfaceForms !== false
|
|
8083
8083
|
};
|
|
8084
8084
|
for (const partition of currentPartitions) {
|
|
8085
8085
|
const docIds = [...partition.docIds()];
|
|
@@ -8140,8 +8140,7 @@ function createRebalancer() {
|
|
|
8140
8140
|
var FNV_OFFSET_BASIS = 2166136261;
|
|
8141
8141
|
var FNV_PRIME = 16777619;
|
|
8142
8142
|
var encoder = new TextEncoder();
|
|
8143
|
-
function
|
|
8144
|
-
const bytes = encoder.encode(input);
|
|
8143
|
+
function fnv1aBytes(bytes) {
|
|
8145
8144
|
let hash = FNV_OFFSET_BASIS;
|
|
8146
8145
|
for (let i = 0; i < bytes.length; i++) {
|
|
8147
8146
|
hash ^= bytes[i];
|
|
@@ -8149,6 +8148,9 @@ function fnv1a(input) {
|
|
|
8149
8148
|
}
|
|
8150
8149
|
return hash >>> 0;
|
|
8151
8150
|
}
|
|
8151
|
+
function fnv1a(input) {
|
|
8152
|
+
return fnv1aBytes(encoder.encode(input));
|
|
8153
|
+
}
|
|
8152
8154
|
|
|
8153
8155
|
// src/partitioning/router.ts
|
|
8154
8156
|
function createPartitionRouter() {
|
|
@@ -10189,7 +10191,7 @@ function applySorting(hits, sort, sortKeyOf) {
|
|
|
10189
10191
|
}
|
|
10190
10192
|
|
|
10191
10193
|
// src/search/cursor.ts
|
|
10192
|
-
var CURSOR_VERSION =
|
|
10194
|
+
var CURSOR_VERSION = 3;
|
|
10193
10195
|
var MAX_CURSOR_LENGTH = 40960;
|
|
10194
10196
|
var MAX_SORT_FIELDS = 8;
|
|
10195
10197
|
var MAX_SORT_FIELD_NAME_LENGTH = 255;
|
|
@@ -10244,6 +10246,7 @@ function encodePageCursor(cursor) {
|
|
|
10244
10246
|
} else if (cursor.score !== null) {
|
|
10245
10247
|
payload.s = cursor.score;
|
|
10246
10248
|
}
|
|
10249
|
+
payload.q = cursor.binding;
|
|
10247
10250
|
return encodeCursorText(JSON.stringify(payload));
|
|
10248
10251
|
}
|
|
10249
10252
|
function decodeSortKey(value, cursor) {
|
|
@@ -10288,8 +10291,11 @@ function decodePageCursor(cursor) {
|
|
|
10288
10291
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
10289
10292
|
throw invalidCursor(cursor, "expected an object");
|
|
10290
10293
|
}
|
|
10291
|
-
const { v, a, s, k, o } = parsed;
|
|
10294
|
+
const { v, a, s, k, o, q } = parsed;
|
|
10292
10295
|
if (v !== CURSOR_VERSION) throw invalidCursor(cursor, `unsupported cursor version ${String(v)}`);
|
|
10296
|
+
if (typeof q !== "string" || !/^[0-9a-f]{8}$/.test(q)) {
|
|
10297
|
+
throw invalidCursor(cursor, '"q" must be 8 lowercase hex digits');
|
|
10298
|
+
}
|
|
10293
10299
|
if (typeof a !== "string" || a.length === 0) throw invalidCursor(cursor, '"a" must be a non-empty string');
|
|
10294
10300
|
if (exceedsCodePoints(a, MAX_ANCHOR_CODE_POINTS)) {
|
|
10295
10301
|
throw invalidCursor(cursor, '"a" is too long to be a document id');
|
|
@@ -10307,10 +10313,14 @@ function decodePageCursor(cursor) {
|
|
|
10307
10313
|
anchor: a,
|
|
10308
10314
|
score: typeof s === "number" ? s : null,
|
|
10309
10315
|
sortKey,
|
|
10310
|
-
sortSignature: typeof o === "string" ? o : null
|
|
10316
|
+
sortSignature: typeof o === "string" ? o : null,
|
|
10317
|
+
binding: q
|
|
10311
10318
|
};
|
|
10312
10319
|
}
|
|
10313
|
-
function requireMatchingCursor(cursor, encoded, signature, scoreAnchored) {
|
|
10320
|
+
function requireMatchingCursor(cursor, encoded, signature, scoreAnchored, binding) {
|
|
10321
|
+
if (cursor.binding !== binding) {
|
|
10322
|
+
throw invalidCursor(encoded, "the cursor belongs to a different query");
|
|
10323
|
+
}
|
|
10314
10324
|
if (signature !== null) {
|
|
10315
10325
|
if (cursor.sortSignature !== signature) {
|
|
10316
10326
|
throw invalidCursor(encoded, "the cursor belongs to a different sort order");
|
|
@@ -10344,6 +10354,12 @@ function requireWithinResultWindow(limit, offset) {
|
|
|
10344
10354
|
{ limit, offset, window: RESULT_WINDOW }
|
|
10345
10355
|
);
|
|
10346
10356
|
}
|
|
10357
|
+
function lastOrganicResult(sliced, pinnedIds) {
|
|
10358
|
+
for (let i = sliced.length - 1; i >= 0; i--) {
|
|
10359
|
+
if (pinnedIds === void 0 || !pinnedIds.has(sliced[i].id)) return sliced[i];
|
|
10360
|
+
}
|
|
10361
|
+
return void 0;
|
|
10362
|
+
}
|
|
10347
10363
|
function ordersAfterAnchor(result, anchor, sort) {
|
|
10348
10364
|
if (sort !== void 0 && anchor.sortKey !== null) {
|
|
10349
10365
|
const comparison = compareSortValues(sort.sortKeyOf(result.id), anchor.sortKey, sort.directions) || compareCodePoints(result.id, anchor.anchor);
|
|
@@ -10354,10 +10370,10 @@ function ordersAfterAnchor(result, anchor, sort) {
|
|
|
10354
10370
|
if (result.score < anchor.score) return true;
|
|
10355
10371
|
return result.score === anchor.score && compareCodePoints(result.id, anchor.anchor) > 0;
|
|
10356
10372
|
}
|
|
10357
|
-
function applyPagination(results, limit, offset, cursor, sort) {
|
|
10373
|
+
function applyPagination(results, limit, offset, binding, cursor, sort, pinnedIds) {
|
|
10358
10374
|
const decoded = cursor ? decodePageCursor(cursor) : null;
|
|
10359
10375
|
if (decoded !== null && cursor !== void 0) {
|
|
10360
|
-
requireMatchingCursor(decoded, cursor, sort?.signature ?? null, true);
|
|
10376
|
+
requireMatchingCursor(decoded, cursor, sort?.signature ?? null, true, binding);
|
|
10361
10377
|
}
|
|
10362
10378
|
if (limit <= 0) {
|
|
10363
10379
|
return { paginated: [] };
|
|
@@ -10376,18 +10392,20 @@ function applyPagination(results, limit, offset, cursor, sort) {
|
|
|
10376
10392
|
const sliced = results.slice(afterOffset, afterOffset + limit);
|
|
10377
10393
|
let nextCursor;
|
|
10378
10394
|
const hasMore = afterOffset + limit < results.length;
|
|
10379
|
-
|
|
10380
|
-
|
|
10395
|
+
const lastResult = lastOrganicResult(sliced, pinnedIds);
|
|
10396
|
+
if (hasMore && lastResult !== void 0) {
|
|
10381
10397
|
nextCursor = sort !== void 0 ? encodePageCursor({
|
|
10382
10398
|
anchor: lastResult.id,
|
|
10383
10399
|
score: null,
|
|
10384
10400
|
sortKey: sort.sortKeyOf(lastResult.id).map(toComparableSortValue),
|
|
10385
|
-
sortSignature: sort.signature
|
|
10401
|
+
sortSignature: sort.signature,
|
|
10402
|
+
binding
|
|
10386
10403
|
}) : encodePageCursor({
|
|
10387
10404
|
anchor: lastResult.id,
|
|
10388
10405
|
score: lastResult.score ?? null,
|
|
10389
10406
|
sortKey: null,
|
|
10390
|
-
sortSignature: null
|
|
10407
|
+
sortSignature: null,
|
|
10408
|
+
binding
|
|
10391
10409
|
});
|
|
10392
10410
|
}
|
|
10393
10411
|
return { paginated: sliced, nextCursor };
|
|
@@ -10587,9 +10605,24 @@ function queryTermSatisfied(queryToken, indexTokens, tolerance, exact) {
|
|
|
10587
10605
|
return false;
|
|
10588
10606
|
}
|
|
10589
10607
|
|
|
10608
|
+
// src/partitioning/partition-selection.ts
|
|
10609
|
+
function partitionsIn(manager, partitionIds) {
|
|
10610
|
+
if (partitionIds === void 0) {
|
|
10611
|
+
return manager.getAllPartitions();
|
|
10612
|
+
}
|
|
10613
|
+
const partitions = [];
|
|
10614
|
+
for (const partitionId of partitionIds) {
|
|
10615
|
+
const partition = manager.partitionAt(partitionId);
|
|
10616
|
+
if (partition !== void 0) {
|
|
10617
|
+
partitions.push(partition);
|
|
10618
|
+
}
|
|
10619
|
+
}
|
|
10620
|
+
return partitions;
|
|
10621
|
+
}
|
|
10622
|
+
|
|
10590
10623
|
// src/partitioning/fan-out.ts
|
|
10591
10624
|
async function fanOutQuery(manager, params, language, schema, config, searchOptions) {
|
|
10592
|
-
const partitions =
|
|
10625
|
+
const partitions = partitionsIn(manager, config.partitionIds);
|
|
10593
10626
|
if (partitions.length === 0) {
|
|
10594
10627
|
return { scored: [], totalMatched: 0 };
|
|
10595
10628
|
}
|
|
@@ -11018,6 +11051,19 @@ function createPartitionManager(indexName, config, language, router, initialPart
|
|
|
11018
11051
|
return manager;
|
|
11019
11052
|
}
|
|
11020
11053
|
|
|
11054
|
+
// src/partitioning/match-count.ts
|
|
11055
|
+
function countsWithoutScores(params) {
|
|
11056
|
+
return params.minScore === void 0 && (params.termMatch === void 0 || params.termMatch === "any");
|
|
11057
|
+
}
|
|
11058
|
+
function fanOutMatchCount(manager, params, language, schema, options) {
|
|
11059
|
+
let count = 0;
|
|
11060
|
+
for (const partition of partitionsIn(manager, options?.partitionIds)) {
|
|
11061
|
+
const matches = fulltextMatches(partition, params, language, schema, options?.searchOptions);
|
|
11062
|
+
if (matches !== null) count += matches.count;
|
|
11063
|
+
}
|
|
11064
|
+
return count;
|
|
11065
|
+
}
|
|
11066
|
+
|
|
11021
11067
|
// src/vector/scalar-quantization-calibration.ts
|
|
11022
11068
|
var PADDING_FACTOR = 0.01;
|
|
11023
11069
|
function computeCalibrationBounds(vectors, dimensions) {
|
|
@@ -11247,7 +11293,7 @@ function createScalarQuantizer(dimensions, ordinalSource) {
|
|
|
11247
11293
|
let liveCount = 0;
|
|
11248
11294
|
let constants = deriveSq8Constants(0, 0, dimensions);
|
|
11249
11295
|
let calibrated = false;
|
|
11250
|
-
function
|
|
11296
|
+
function ensureCapacity3(needed) {
|
|
11251
11297
|
if (needed <= capacity) return;
|
|
11252
11298
|
let newCap = capacity === 0 ? INITIAL_CAPACITY2 : capacity;
|
|
11253
11299
|
while (newCap < needed) newCap *= 2;
|
|
@@ -11377,7 +11423,7 @@ function createScalarQuantizer(dimensions, ordinalSource) {
|
|
|
11377
11423
|
liveCount = 0;
|
|
11378
11424
|
for (const [docId, vec] of collected) {
|
|
11379
11425
|
const ord = resolveOrdinal(docId);
|
|
11380
|
-
|
|
11426
|
+
ensureCapacity3(ord + 1);
|
|
11381
11427
|
quantizeInto(ord, vec);
|
|
11382
11428
|
storeEntry(docId, ord);
|
|
11383
11429
|
}
|
|
@@ -11387,7 +11433,7 @@ function createScalarQuantizer(dimensions, ordinalSource) {
|
|
|
11387
11433
|
calibrateFromVectors([vector]);
|
|
11388
11434
|
}
|
|
11389
11435
|
const ord = resolveOrdinal(docId);
|
|
11390
|
-
|
|
11436
|
+
ensureCapacity3(ord + 1);
|
|
11391
11437
|
quantizeInto(ord, vector);
|
|
11392
11438
|
storeEntry(docId, ord);
|
|
11393
11439
|
},
|
|
@@ -11454,7 +11500,7 @@ function createScalarQuantizer(dimensions, ordinalSource) {
|
|
|
11454
11500
|
},
|
|
11455
11501
|
restoreEntry(docId, quantized, sum, sumSq) {
|
|
11456
11502
|
const ord = resolveOrdinal(docId);
|
|
11457
|
-
|
|
11503
|
+
ensureCapacity3(ord + 1);
|
|
11458
11504
|
const base = ord * dimensions;
|
|
11459
11505
|
quantizedArena.set(quantized.subarray(0, dimensions), base);
|
|
11460
11506
|
sums[ord] = sum;
|
|
@@ -11605,7 +11651,7 @@ function createVectorStore() {
|
|
|
11605
11651
|
arena = new Float32Array(simd.memory.buffer);
|
|
11606
11652
|
}
|
|
11607
11653
|
}
|
|
11608
|
-
function
|
|
11654
|
+
function ensureCapacity3(needed) {
|
|
11609
11655
|
if (needed <= capacity) return;
|
|
11610
11656
|
let newCap = capacity === 0 ? INITIAL_CAPACITY3 : capacity;
|
|
11611
11657
|
while (newCap < needed) newCap *= 2;
|
|
@@ -11687,7 +11733,7 @@ function createVectorStore() {
|
|
|
11687
11733
|
recycledOrds.delete(docId);
|
|
11688
11734
|
docToOrd.set(docId, recycled);
|
|
11689
11735
|
ordToDoc[recycled] = docId;
|
|
11690
|
-
|
|
11736
|
+
ensureCapacity3(recycled + 1);
|
|
11691
11737
|
writeVector(recycled, vector);
|
|
11692
11738
|
recordPartition(recycled, partitionId, false);
|
|
11693
11739
|
liveCount++;
|
|
@@ -11696,7 +11742,7 @@ function createVectorStore() {
|
|
|
11696
11742
|
const ord = ordToDoc.length;
|
|
11697
11743
|
docToOrd.set(docId, ord);
|
|
11698
11744
|
ordToDoc.push(docId);
|
|
11699
|
-
|
|
11745
|
+
ensureCapacity3(ord + 1);
|
|
11700
11746
|
writeVector(ord, vector);
|
|
11701
11747
|
recordPartition(ord, partitionId, false);
|
|
11702
11748
|
liveCount++;
|
|
@@ -11862,7 +11908,7 @@ function createVectorStore() {
|
|
|
11862
11908
|
}
|
|
11863
11909
|
if (snapshot.dimension === 0 || snapshot.slots === 0) return;
|
|
11864
11910
|
initStorage(snapshot.dimension);
|
|
11865
|
-
|
|
11911
|
+
ensureCapacity3(snapshot.slots);
|
|
11866
11912
|
arena.set(snapshot.vectors.subarray(0, snapshot.slots * snapshot.dimension), scratchFloatLength);
|
|
11867
11913
|
mags.set(snapshot.magnitudes.subarray(0, Math.min(snapshot.slots, mags.length)));
|
|
11868
11914
|
ensurePartitionSlots(snapshot.slots);
|
|
@@ -13015,20 +13061,43 @@ function resolveWorkerCount(requested) {
|
|
|
13015
13061
|
}
|
|
13016
13062
|
function createWorkerPool(config) {
|
|
13017
13063
|
const workerCount = resolveWorkerCount(config.count);
|
|
13018
|
-
const workers =
|
|
13064
|
+
const workers = /* @__PURE__ */ new Map();
|
|
13065
|
+
const deadSlots = /* @__PURE__ */ new Set();
|
|
13019
13066
|
const indexAssignment = /* @__PURE__ */ new Map();
|
|
13020
13067
|
let isShutdown = false;
|
|
13068
|
+
function handleWorkerDeath(slotIndex, error) {
|
|
13069
|
+
if (isShutdown || deadSlots.has(slotIndex)) {
|
|
13070
|
+
return;
|
|
13071
|
+
}
|
|
13072
|
+
deadSlots.add(slotIndex);
|
|
13073
|
+
const slot = workers.get(slotIndex);
|
|
13074
|
+
const indexNames = slot ? [...slot.indexes].sort() : [];
|
|
13075
|
+
workers.delete(slotIndex);
|
|
13076
|
+
config.onWorkerCrash?.(slotIndex, indexNames, error);
|
|
13077
|
+
}
|
|
13021
13078
|
function ensureWorker(slotIndex) {
|
|
13022
|
-
if (
|
|
13023
|
-
|
|
13024
|
-
|
|
13079
|
+
if (deadSlots.has(slotIndex)) {
|
|
13080
|
+
return void 0;
|
|
13081
|
+
}
|
|
13082
|
+
let slot = workers.get(slotIndex);
|
|
13083
|
+
if (!slot) {
|
|
13084
|
+
slot = {
|
|
13085
|
+
executor: config.workerFactory(slotIndex, (error) => handleWorkerDeath(slotIndex, error)),
|
|
13025
13086
|
indexes: /* @__PURE__ */ new Set()
|
|
13026
13087
|
};
|
|
13088
|
+
workers.set(slotIndex, slot);
|
|
13027
13089
|
}
|
|
13028
|
-
return
|
|
13090
|
+
return slot;
|
|
13029
13091
|
}
|
|
13030
13092
|
function assignSlot(indexName) {
|
|
13031
|
-
|
|
13093
|
+
const preferred = fnv1a(indexName) % workerCount;
|
|
13094
|
+
for (let probe = 0; probe < workerCount; probe++) {
|
|
13095
|
+
const candidate = (preferred + probe) % workerCount;
|
|
13096
|
+
if (!deadSlots.has(candidate)) {
|
|
13097
|
+
return candidate;
|
|
13098
|
+
}
|
|
13099
|
+
}
|
|
13100
|
+
throw new NarsilError(ErrorCodes.WORKER_CRASHED, `Every worker in the pool has crashed`);
|
|
13032
13101
|
}
|
|
13033
13102
|
function addIndex(indexName) {
|
|
13034
13103
|
if (isShutdown) {
|
|
@@ -13039,6 +13108,9 @@ function createWorkerPool(config) {
|
|
|
13039
13108
|
}
|
|
13040
13109
|
const slotIndex = assignSlot(indexName);
|
|
13041
13110
|
const slot = ensureWorker(slotIndex);
|
|
13111
|
+
if (!slot) {
|
|
13112
|
+
throw new NarsilError(ErrorCodes.WORKER_CRASHED, `Worker ${slotIndex} for index "${indexName}" has crashed`);
|
|
13113
|
+
}
|
|
13042
13114
|
slot.indexes.add(indexName);
|
|
13043
13115
|
indexAssignment.set(indexName, slotIndex);
|
|
13044
13116
|
}
|
|
@@ -13047,10 +13119,7 @@ function createWorkerPool(config) {
|
|
|
13047
13119
|
if (slotIndex === void 0) {
|
|
13048
13120
|
return;
|
|
13049
13121
|
}
|
|
13050
|
-
|
|
13051
|
-
if (slot) {
|
|
13052
|
-
slot.indexes.delete(indexName);
|
|
13053
|
-
}
|
|
13122
|
+
workers.get(slotIndex)?.indexes.delete(indexName);
|
|
13054
13123
|
indexAssignment.delete(indexName);
|
|
13055
13124
|
}
|
|
13056
13125
|
function getExecutor(indexName) {
|
|
@@ -13061,15 +13130,22 @@ function createWorkerPool(config) {
|
|
|
13061
13130
|
if (slotIndex === void 0) {
|
|
13062
13131
|
throw new NarsilError(ErrorCodes.INDEX_NOT_FOUND, `Index "${indexName}" is not registered in the worker pool`);
|
|
13063
13132
|
}
|
|
13064
|
-
|
|
13133
|
+
const slot = workers.get(slotIndex);
|
|
13134
|
+
if (slot) {
|
|
13135
|
+
return slot.executor;
|
|
13136
|
+
}
|
|
13137
|
+
for (const survivor of workers.values()) {
|
|
13138
|
+
if (survivor.indexes.has(indexName)) {
|
|
13139
|
+
return survivor.executor;
|
|
13140
|
+
}
|
|
13141
|
+
}
|
|
13142
|
+
throw new NarsilError(ErrorCodes.WORKER_CRASHED, `Every worker holding index "${indexName}" has crashed`);
|
|
13065
13143
|
}
|
|
13066
13144
|
async function getMemoryStats() {
|
|
13067
13145
|
const indices = [];
|
|
13068
13146
|
const pending = [];
|
|
13069
|
-
for (
|
|
13070
|
-
|
|
13071
|
-
if (!slot) continue;
|
|
13072
|
-
indices.push(i);
|
|
13147
|
+
for (const [slotIndex, slot] of workers) {
|
|
13148
|
+
indices.push(slotIndex);
|
|
13073
13149
|
pending.push(
|
|
13074
13150
|
slot.executor.execute({ type: "memoryReport", requestId: createRequestId() }).catch(() => null)
|
|
13075
13151
|
);
|
|
@@ -13092,7 +13168,7 @@ function createWorkerPool(config) {
|
|
|
13092
13168
|
return;
|
|
13093
13169
|
}
|
|
13094
13170
|
isShutdown = true;
|
|
13095
|
-
const shutdownPromises = workers.
|
|
13171
|
+
const shutdownPromises = [...workers.values()].map((slot) => {
|
|
13096
13172
|
const timeoutPromise = new Promise((resolve) => {
|
|
13097
13173
|
setTimeout(resolve, 5e3);
|
|
13098
13174
|
});
|
|
@@ -13102,17 +13178,16 @@ function createWorkerPool(config) {
|
|
|
13102
13178
|
indexAssignment.clear();
|
|
13103
13179
|
}
|
|
13104
13180
|
function getAllExecutors() {
|
|
13105
|
-
return workers.
|
|
13181
|
+
return [...workers.values()].map((slot) => slot.executor);
|
|
13106
13182
|
}
|
|
13107
13183
|
function addIndexToAll(indexName) {
|
|
13108
13184
|
if (isShutdown) {
|
|
13109
13185
|
throw new NarsilError(ErrorCodes.WORKER_CRASHED, "Worker pool has been shut down");
|
|
13110
13186
|
}
|
|
13111
13187
|
for (let i = 0; i < workerCount; i++) {
|
|
13112
|
-
|
|
13113
|
-
slot.indexes.add(indexName);
|
|
13188
|
+
ensureWorker(i)?.indexes.add(indexName);
|
|
13114
13189
|
}
|
|
13115
|
-
indexAssignment.set(indexName,
|
|
13190
|
+
indexAssignment.set(indexName, assignSlot(indexName));
|
|
13116
13191
|
}
|
|
13117
13192
|
return {
|
|
13118
13193
|
getExecutor,
|
|
@@ -14365,6 +14440,12 @@ function createDirectExecutor() {
|
|
|
14365
14440
|
}
|
|
14366
14441
|
case "preflight": {
|
|
14367
14442
|
const entry = requireIndex(action.indexName);
|
|
14443
|
+
if (countsWithoutScores(action.params)) {
|
|
14444
|
+
const count = fanOutMatchCount(entry.manager, action.params, entry.language, entry.config.schema, {
|
|
14445
|
+
searchOptions: entry.searchOptions
|
|
14446
|
+
});
|
|
14447
|
+
return { count };
|
|
14448
|
+
}
|
|
14368
14449
|
const result = await fanOutQuery(
|
|
14369
14450
|
entry.manager,
|
|
14370
14451
|
action.params,
|
|
@@ -15178,6 +15259,9 @@ function writeHeader(header) {
|
|
|
15178
15259
|
}
|
|
15179
15260
|
return buffer;
|
|
15180
15261
|
}
|
|
15262
|
+
function hasNrslMagic(data) {
|
|
15263
|
+
return data.length >= MAGIC_BYTES.length && data[0] === MAGIC_BYTES[0] && data[1] === MAGIC_BYTES[1] && data[2] === MAGIC_BYTES[2] && data[3] === MAGIC_BYTES[3];
|
|
15264
|
+
}
|
|
15181
15265
|
function readHeader(data) {
|
|
15182
15266
|
if (data.length < HEADER_SIZE) {
|
|
15183
15267
|
throw new NarsilError(
|
|
@@ -15213,6 +15297,7 @@ function readHeader(data) {
|
|
|
15213
15297
|
// src/serialization/envelope.ts
|
|
15214
15298
|
var CURRENT_ENVELOPE_VERSION = 1;
|
|
15215
15299
|
var SNAPSHOT_ENVELOPE_VERSION = 2;
|
|
15300
|
+
var INDEX_SNAPSHOT_ENVELOPE_VERSION = 3;
|
|
15216
15301
|
function parseEngineVersion(version) {
|
|
15217
15302
|
const parts = version.split(".");
|
|
15218
15303
|
return [parseInt(parts[0] ?? "0", 10), parseInt(parts[1] ?? "0", 10), parseInt(parts[2] ?? "0", 10)];
|
|
@@ -15357,6 +15442,19 @@ function concatEnvelopeParts(parts) {
|
|
|
15357
15442
|
async function unpackEnvelopeBytes(data) {
|
|
15358
15443
|
return unpackEnvelope(data, SNAPSHOT_ENVELOPE_VERSION);
|
|
15359
15444
|
}
|
|
15445
|
+
async function packIndexSnapshotEnvelope(payloadBytes) {
|
|
15446
|
+
return packEnvelope(payloadBytes, { checksum: true, envelopeFormatVersion: INDEX_SNAPSHOT_ENVELOPE_VERSION });
|
|
15447
|
+
}
|
|
15448
|
+
async function unpackIndexSnapshotEnvelope(data) {
|
|
15449
|
+
const { header, payloadBytes } = await unpackEnvelope(data, INDEX_SNAPSHOT_ENVELOPE_VERSION);
|
|
15450
|
+
if (header.envelopeFormatVersion !== INDEX_SNAPSHOT_ENVELOPE_VERSION) {
|
|
15451
|
+
throw new NarsilError(
|
|
15452
|
+
ErrorCodes.ENVELOPE_VERSION_MISMATCH,
|
|
15453
|
+
`Expected an index snapshot envelope of format v${INDEX_SNAPSHOT_ENVELOPE_VERSION}, received format v${header.envelopeFormatVersion}`
|
|
15454
|
+
);
|
|
15455
|
+
}
|
|
15456
|
+
return payloadBytes;
|
|
15457
|
+
}
|
|
15360
15458
|
async function writeMetadataEnvelope(meta, options = {}) {
|
|
15361
15459
|
const payloadBytes = serializeMetadata(meta);
|
|
15362
15460
|
return packEnvelope(payloadBytes, options);
|
|
@@ -18933,14 +19031,34 @@ async function awaitCompactions(state) {
|
|
|
18933
19031
|
var DEFAULT_BACKPRESSURE_LIMIT = 100;
|
|
18934
19032
|
var DEFAULT_REQUEST_TIMEOUT = 3e4;
|
|
18935
19033
|
var SHUTDOWN_TIMEOUT = 5e3;
|
|
19034
|
+
var CONSECUTIVE_TIMEOUTS_BEFORE_DEATH = 3;
|
|
19035
|
+
function errorFromEventLike(event) {
|
|
19036
|
+
if (event instanceof Error) {
|
|
19037
|
+
return event;
|
|
19038
|
+
}
|
|
19039
|
+
if (typeof event === "object" && event !== null) {
|
|
19040
|
+
const detail = event;
|
|
19041
|
+
if (detail.error instanceof Error) {
|
|
19042
|
+
return detail.error;
|
|
19043
|
+
}
|
|
19044
|
+
if (typeof detail.message === "string" && detail.message.length > 0) {
|
|
19045
|
+
return new Error(detail.message);
|
|
19046
|
+
}
|
|
19047
|
+
}
|
|
19048
|
+
return new Error("The worker reported an error event carrying no detail");
|
|
19049
|
+
}
|
|
18936
19050
|
function createWorkerExecutor(worker, config) {
|
|
18937
|
-
const backpressureLimit = DEFAULT_BACKPRESSURE_LIMIT;
|
|
18938
|
-
const requestTimeout = DEFAULT_REQUEST_TIMEOUT;
|
|
19051
|
+
const backpressureLimit = config?.backpressureLimit ?? DEFAULT_BACKPRESSURE_LIMIT;
|
|
19052
|
+
const requestTimeout = config?.requestTimeout ?? DEFAULT_REQUEST_TIMEOUT;
|
|
18939
19053
|
const pending = /* @__PURE__ */ new Map();
|
|
19054
|
+
let deathError = null;
|
|
19055
|
+
let shutdownRequested = false;
|
|
19056
|
+
let consecutiveTimeouts = 0;
|
|
18940
19057
|
function processResponse(msg) {
|
|
18941
19058
|
if (!isValidWorkerResponse(msg)) {
|
|
18942
19059
|
return;
|
|
18943
19060
|
}
|
|
19061
|
+
consecutiveTimeouts = 0;
|
|
18944
19062
|
const response = msg;
|
|
18945
19063
|
const entry = pending.get(response.requestId);
|
|
18946
19064
|
if (!entry) {
|
|
@@ -18954,15 +19072,36 @@ function createWorkerExecutor(worker, config) {
|
|
|
18954
19072
|
entry.resolve(response.data);
|
|
18955
19073
|
}
|
|
18956
19074
|
}
|
|
19075
|
+
function handleDeath(cause) {
|
|
19076
|
+
if (deathError !== null) {
|
|
19077
|
+
return;
|
|
19078
|
+
}
|
|
19079
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
19080
|
+
deathError = new NarsilError(ErrorCodes.WORKER_CRASHED, `Worker died: ${message}`);
|
|
19081
|
+
for (const [id, entry] of pending) {
|
|
19082
|
+
clearTimeout(entry.timeoutId);
|
|
19083
|
+
entry.reject(deathError);
|
|
19084
|
+
pending.delete(id);
|
|
19085
|
+
}
|
|
19086
|
+
if (!shutdownRequested) {
|
|
19087
|
+
config?.onDeath?.(cause instanceof Error ? cause : new Error(message));
|
|
19088
|
+
}
|
|
19089
|
+
}
|
|
18957
19090
|
if (typeof worker.on === "function") {
|
|
18958
19091
|
worker.on("message", (msg) => processResponse(msg));
|
|
19092
|
+
worker.on("error", (cause) => handleDeath(cause));
|
|
19093
|
+
worker.on("exit", (code) => handleDeath(new Error(`Worker exited with code ${String(code)}`)));
|
|
18959
19094
|
} else if (typeof worker.addEventListener === "function") {
|
|
18960
19095
|
worker.addEventListener("message", (event) => {
|
|
18961
19096
|
const msg = event.data;
|
|
18962
19097
|
processResponse(msg);
|
|
18963
19098
|
});
|
|
19099
|
+
worker.addEventListener("error", (event) => handleDeath(errorFromEventLike(event)));
|
|
18964
19100
|
}
|
|
18965
19101
|
function execute(action) {
|
|
19102
|
+
if (deathError !== null) {
|
|
19103
|
+
return Promise.reject(deathError);
|
|
19104
|
+
}
|
|
18966
19105
|
if (pending.size >= backpressureLimit) {
|
|
18967
19106
|
return Promise.reject(
|
|
18968
19107
|
new NarsilError(ErrorCodes.WORKER_BUSY, `Backpressure limit of ${backpressureLimit} pending requests reached`)
|
|
@@ -18974,6 +19113,10 @@ function createWorkerExecutor(worker, config) {
|
|
|
18974
19113
|
const timeoutId = setTimeout(() => {
|
|
18975
19114
|
pending.delete(requestId);
|
|
18976
19115
|
reject2(new NarsilError(ErrorCodes.WORKER_TIMEOUT, `Request ${requestId} timed out after ${requestTimeout}ms`));
|
|
19116
|
+
consecutiveTimeouts += 1;
|
|
19117
|
+
if (consecutiveTimeouts >= CONSECUTIVE_TIMEOUTS_BEFORE_DEATH) {
|
|
19118
|
+
handleDeath(new Error(`no answer to ${CONSECUTIVE_TIMEOUTS_BEFORE_DEATH} consecutive requests`));
|
|
19119
|
+
}
|
|
18977
19120
|
}, requestTimeout);
|
|
18978
19121
|
pending.set(requestId, {
|
|
18979
19122
|
resolve,
|
|
@@ -18984,6 +19127,10 @@ function createWorkerExecutor(worker, config) {
|
|
|
18984
19127
|
});
|
|
18985
19128
|
}
|
|
18986
19129
|
async function shutdown() {
|
|
19130
|
+
shutdownRequested = true;
|
|
19131
|
+
if (deathError !== null) {
|
|
19132
|
+
return;
|
|
19133
|
+
}
|
|
18987
19134
|
const requestId = createRequestId();
|
|
18988
19135
|
const shutdownAction = { type: "shutdown", requestId };
|
|
18989
19136
|
const shutdownPromise = new Promise((resolve, reject2) => {
|
|
@@ -19024,9 +19171,9 @@ async function createWorkerFactory(entryPoint) {
|
|
|
19024
19171
|
const runtime = detectRuntime();
|
|
19025
19172
|
const resolvedEntry = resolveEntryPoint();
|
|
19026
19173
|
if (runtime.supportsWebWorkers) {
|
|
19027
|
-
return function webFactory(_workerId) {
|
|
19174
|
+
return function webFactory(_workerId, onDeath) {
|
|
19028
19175
|
const instance = new Worker(resolvedEntry, { type: "module" });
|
|
19029
|
-
return createWorkerExecutor(instance);
|
|
19176
|
+
return createWorkerExecutor(instance, { onDeath });
|
|
19030
19177
|
};
|
|
19031
19178
|
}
|
|
19032
19179
|
throw new NarsilError(ErrorCodes.WORKER_CRASHED, `No worker support available on runtime "${runtime.runtime}"`);
|
|
@@ -19082,7 +19229,13 @@ async function runPromotion(state, reason) {
|
|
|
19082
19229
|
return;
|
|
19083
19230
|
}
|
|
19084
19231
|
const factory = await createWorkerFactory();
|
|
19085
|
-
const pool = createWorkerPool({
|
|
19232
|
+
const pool = createWorkerPool({
|
|
19233
|
+
count: state.config?.workers?.count,
|
|
19234
|
+
workerFactory: factory,
|
|
19235
|
+
onWorkerCrash(workerId, indexNames, error) {
|
|
19236
|
+
state.callbacks?.onWorkerCrash?.(workerId, indexNames, error);
|
|
19237
|
+
}
|
|
19238
|
+
});
|
|
19086
19239
|
for (const name of promotable) {
|
|
19087
19240
|
pool.addIndexToAll(name);
|
|
19088
19241
|
}
|
|
@@ -19403,6 +19556,9 @@ function createEngineCore(config) {
|
|
|
19403
19556
|
if (handlers) {
|
|
19404
19557
|
for (const handler of handlers) handler({ workerCount, reason });
|
|
19405
19558
|
}
|
|
19559
|
+
void Promise.resolve(pluginRegistry.runHook("onWorkerPromote", { workerCount, reason })).catch((err) => {
|
|
19560
|
+
console.warn("onWorkerPromote plugin hook failed:", err instanceof Error ? err.message : String(err));
|
|
19561
|
+
});
|
|
19406
19562
|
},
|
|
19407
19563
|
onPromotionFailure(reason, error, retryable) {
|
|
19408
19564
|
const handlers = eventHandlers.get("workerPromoteFailure");
|
|
@@ -19411,6 +19567,14 @@ function createEngineCore(config) {
|
|
|
19411
19567
|
return;
|
|
19412
19568
|
}
|
|
19413
19569
|
for (const handler of handlers) handler({ reason, error, retryable });
|
|
19570
|
+
},
|
|
19571
|
+
onWorkerCrash(workerId, indexNames, error) {
|
|
19572
|
+
const handlers = eventHandlers.get("workerCrash");
|
|
19573
|
+
if (!handlers || handlers.size === 0) {
|
|
19574
|
+
console.warn(`Worker ${workerId} crashed:`, error);
|
|
19575
|
+
return;
|
|
19576
|
+
}
|
|
19577
|
+
for (const handler of handlers) handler({ workerId, indexNames, error });
|
|
19414
19578
|
}
|
|
19415
19579
|
});
|
|
19416
19580
|
const rebalancer = createRebalancer();
|
|
@@ -21370,6 +21534,15 @@ async function executeRebalance(manager, indexName, targetPartitionCount, ctx) {
|
|
|
21370
21534
|
}
|
|
21371
21535
|
}
|
|
21372
21536
|
});
|
|
21537
|
+
try {
|
|
21538
|
+
await ctx.pluginRegistry.runHook("onPartitionSplit", {
|
|
21539
|
+
indexName,
|
|
21540
|
+
oldPartitionCount: oldCount,
|
|
21541
|
+
newPartitionCount: targetPartitionCount
|
|
21542
|
+
});
|
|
21543
|
+
} catch (hookErr) {
|
|
21544
|
+
console.warn("onPartitionSplit plugin hook failed:", hookErr instanceof Error ? hookErr.message : String(hookErr));
|
|
21545
|
+
}
|
|
21373
21546
|
await replayQueued(manager, indexName, waq, ctx);
|
|
21374
21547
|
if (ctx.durabilityManager) {
|
|
21375
21548
|
await ctx.durabilityManager.persistMetadata(indexName);
|
|
@@ -21584,7 +21757,7 @@ async function createSnapshot(manager, entry) {
|
|
|
21584
21757
|
const config = entry.config;
|
|
21585
21758
|
const bm25 = config.bm25;
|
|
21586
21759
|
const { encode: encode14 } = await import('@msgpack/msgpack');
|
|
21587
|
-
|
|
21760
|
+
const payload = encode14({
|
|
21588
21761
|
version: 2,
|
|
21589
21762
|
schema: config.schema,
|
|
21590
21763
|
language: entry.language.name,
|
|
@@ -21614,15 +21787,17 @@ async function createSnapshot(manager, entry) {
|
|
|
21614
21787
|
partitions: partitionBuffers,
|
|
21615
21788
|
vectorIndexes: vectorPayloads
|
|
21616
21789
|
});
|
|
21790
|
+
return packIndexSnapshotEnvelope(payload);
|
|
21617
21791
|
}
|
|
21618
21792
|
async function restoreFromSnapshot(indexName, data, deps) {
|
|
21619
21793
|
if (!(data instanceof Uint8Array)) {
|
|
21620
21794
|
throw new NarsilError(ErrorCodes.DOC_VALIDATION_FAILED, "Snapshot data must be a Uint8Array");
|
|
21621
21795
|
}
|
|
21796
|
+
const payloadBytes = hasNrslMagic(data) ? await unpackIndexSnapshotEnvelope(data) : data;
|
|
21622
21797
|
const { decode: decode14 } = await import('@msgpack/msgpack');
|
|
21623
21798
|
let decoded;
|
|
21624
21799
|
try {
|
|
21625
|
-
decoded = decode14(
|
|
21800
|
+
decoded = decode14(payloadBytes);
|
|
21626
21801
|
} catch (err) {
|
|
21627
21802
|
throw new NarsilError(
|
|
21628
21803
|
ErrorCodes.DOC_VALIDATION_FAILED,
|
|
@@ -21817,6 +21992,137 @@ function readProcessMemory() {
|
|
|
21817
21992
|
}
|
|
21818
21993
|
}
|
|
21819
21994
|
|
|
21995
|
+
// src/search/cursor-binding.ts
|
|
21996
|
+
var ABSENT_TAG = 0;
|
|
21997
|
+
var NULL_TAG = 1;
|
|
21998
|
+
var FALSE_TAG = 2;
|
|
21999
|
+
var TRUE_TAG = 3;
|
|
22000
|
+
var NUMBER_TAG = 4;
|
|
22001
|
+
var STRING_TAG = 5;
|
|
22002
|
+
var LIST_TAG = 6;
|
|
22003
|
+
var MAP_TAG = 7;
|
|
22004
|
+
var encoder4 = new TextEncoder();
|
|
22005
|
+
function ensureCapacity2(stream, extra) {
|
|
22006
|
+
if (stream.length + extra <= stream.bytes.length) return;
|
|
22007
|
+
const grown = new Uint8Array(Math.max(stream.bytes.length * 2, stream.length + extra));
|
|
22008
|
+
grown.set(stream.bytes.subarray(0, stream.length));
|
|
22009
|
+
stream.bytes = grown;
|
|
22010
|
+
}
|
|
22011
|
+
function writeByte(stream, value) {
|
|
22012
|
+
ensureCapacity2(stream, 1);
|
|
22013
|
+
stream.bytes[stream.length] = value;
|
|
22014
|
+
stream.length += 1;
|
|
22015
|
+
}
|
|
22016
|
+
function writeUint32(stream, value) {
|
|
22017
|
+
ensureCapacity2(stream, 4);
|
|
22018
|
+
stream.bytes[stream.length] = value >>> 24 & 255;
|
|
22019
|
+
stream.bytes[stream.length + 1] = value >>> 16 & 255;
|
|
22020
|
+
stream.bytes[stream.length + 2] = value >>> 8 & 255;
|
|
22021
|
+
stream.bytes[stream.length + 3] = value & 255;
|
|
22022
|
+
stream.length += 4;
|
|
22023
|
+
}
|
|
22024
|
+
var numberBytes = new DataView(new ArrayBuffer(8));
|
|
22025
|
+
function writeNumber(stream, value) {
|
|
22026
|
+
numberBytes.setFloat64(0, value, false);
|
|
22027
|
+
ensureCapacity2(stream, 8);
|
|
22028
|
+
for (let i = 0; i < 8; i++) {
|
|
22029
|
+
stream.bytes[stream.length + i] = numberBytes.getUint8(i);
|
|
22030
|
+
}
|
|
22031
|
+
stream.length += 8;
|
|
22032
|
+
}
|
|
22033
|
+
function writeString(stream, value) {
|
|
22034
|
+
const encoded = encoder4.encode(value);
|
|
22035
|
+
writeUint32(stream, encoded.length);
|
|
22036
|
+
ensureCapacity2(stream, encoded.length);
|
|
22037
|
+
stream.bytes.set(encoded, stream.length);
|
|
22038
|
+
stream.length += encoded.length;
|
|
22039
|
+
}
|
|
22040
|
+
function writeValue(stream, value) {
|
|
22041
|
+
if (value === void 0) {
|
|
22042
|
+
writeByte(stream, ABSENT_TAG);
|
|
22043
|
+
return;
|
|
22044
|
+
}
|
|
22045
|
+
if (value === null) {
|
|
22046
|
+
writeByte(stream, NULL_TAG);
|
|
22047
|
+
return;
|
|
22048
|
+
}
|
|
22049
|
+
if (typeof value === "boolean") {
|
|
22050
|
+
writeByte(stream, value ? TRUE_TAG : FALSE_TAG);
|
|
22051
|
+
return;
|
|
22052
|
+
}
|
|
22053
|
+
if (typeof value === "number") {
|
|
22054
|
+
writeByte(stream, NUMBER_TAG);
|
|
22055
|
+
writeNumber(stream, value);
|
|
22056
|
+
return;
|
|
22057
|
+
}
|
|
22058
|
+
if (typeof value === "string") {
|
|
22059
|
+
writeByte(stream, STRING_TAG);
|
|
22060
|
+
writeString(stream, value);
|
|
22061
|
+
return;
|
|
22062
|
+
}
|
|
22063
|
+
if (Array.isArray(value)) {
|
|
22064
|
+
writeByte(stream, LIST_TAG);
|
|
22065
|
+
writeUint32(stream, value.length);
|
|
22066
|
+
for (const member of value) {
|
|
22067
|
+
writeValue(stream, member ?? null);
|
|
22068
|
+
}
|
|
22069
|
+
return;
|
|
22070
|
+
}
|
|
22071
|
+
const record = value;
|
|
22072
|
+
const keys = Object.keys(record).sort(compareCodePoints);
|
|
22073
|
+
writeByte(stream, MAP_TAG);
|
|
22074
|
+
writeUint32(stream, keys.length);
|
|
22075
|
+
for (const key of keys) {
|
|
22076
|
+
writeByte(stream, STRING_TAG);
|
|
22077
|
+
writeString(stream, key);
|
|
22078
|
+
writeValue(stream, record[key] ?? null);
|
|
22079
|
+
}
|
|
22080
|
+
}
|
|
22081
|
+
function boundVectorOf(vector) {
|
|
22082
|
+
if (vector === void 0) return void 0;
|
|
22083
|
+
const bound = { ...vector };
|
|
22084
|
+
if (vector.value !== void 0) {
|
|
22085
|
+
bound.value = Array.from(vector.value, Math.fround);
|
|
22086
|
+
}
|
|
22087
|
+
if (vector.text !== void 0) {
|
|
22088
|
+
delete bound.value;
|
|
22089
|
+
}
|
|
22090
|
+
return bound;
|
|
22091
|
+
}
|
|
22092
|
+
var FILTERS_SLOT = 2;
|
|
22093
|
+
var BOUND_SLOT_COUNT = 15;
|
|
22094
|
+
function bindingOf(values) {
|
|
22095
|
+
const stream = { bytes: new Uint8Array(256), length: 0 };
|
|
22096
|
+
for (const value of values) {
|
|
22097
|
+
writeValue(stream, value);
|
|
22098
|
+
}
|
|
22099
|
+
return fnv1aBytes(stream.bytes.subarray(0, stream.length)).toString(16).padStart(8, "0");
|
|
22100
|
+
}
|
|
22101
|
+
function queryBindingOf(params) {
|
|
22102
|
+
return bindingOf([
|
|
22103
|
+
params.term,
|
|
22104
|
+
params.fields,
|
|
22105
|
+
params.filters,
|
|
22106
|
+
params.boost,
|
|
22107
|
+
params.minScore,
|
|
22108
|
+
params.termMatch,
|
|
22109
|
+
params.tolerance,
|
|
22110
|
+
params.prefixLength,
|
|
22111
|
+
params.prefix,
|
|
22112
|
+
params.exact,
|
|
22113
|
+
params.pinned,
|
|
22114
|
+
params.mode,
|
|
22115
|
+
params.hybrid,
|
|
22116
|
+
boundVectorOf(params.vector),
|
|
22117
|
+
params.scoring ?? "local"
|
|
22118
|
+
]);
|
|
22119
|
+
}
|
|
22120
|
+
function listBindingOf(filters) {
|
|
22121
|
+
const values = new Array(BOUND_SLOT_COUNT).fill(void 0);
|
|
22122
|
+
values[FILTERS_SLOT] = filters;
|
|
22123
|
+
return bindingOf(values);
|
|
22124
|
+
}
|
|
22125
|
+
|
|
21820
22126
|
// src/engine/list-documents/index.ts
|
|
21821
22127
|
function clampListLimit(limit) {
|
|
21822
22128
|
const clamped = Math.max(1, clampLimit(limit));
|
|
@@ -21851,7 +22157,7 @@ function collectCandidates(partition, anchor, matches, wanted, out) {
|
|
|
21851
22157
|
taken++;
|
|
21852
22158
|
}
|
|
21853
22159
|
}
|
|
21854
|
-
function pageInIdOrder(partitions, cursor, filtered, limit) {
|
|
22160
|
+
function pageInIdOrder(partitions, cursor, filtered, limit, binding) {
|
|
21855
22161
|
const anchor = cursor === null ? null : cursor.anchor;
|
|
21856
22162
|
const candidates = [];
|
|
21857
22163
|
for (let index = 0; index < partitions.length; index++) {
|
|
@@ -21866,10 +22172,10 @@ function pageInIdOrder(partitions, cursor, filtered, limit) {
|
|
|
21866
22172
|
candidates.sort(compareCodePoints);
|
|
21867
22173
|
const hasMore = candidates.length > limit;
|
|
21868
22174
|
const ids = hasMore ? candidates.slice(0, limit) : candidates;
|
|
21869
|
-
const nextCursor = hasMore && ids.length > 0 ? { anchor: ids[ids.length - 1], score: null, sortKey: null, sortSignature: null } : null;
|
|
22175
|
+
const nextCursor = hasMore && ids.length > 0 ? { anchor: ids[ids.length - 1], score: null, sortKey: null, sortSignature: null, binding } : null;
|
|
21870
22176
|
return { ids, nextCursor };
|
|
21871
22177
|
}
|
|
21872
|
-
function pageInSortOrder(partitions, cursor, filtered, limit, sort, signature, schema) {
|
|
22178
|
+
function pageInSortOrder(partitions, cursor, filtered, limit, sort, signature, schema, binding) {
|
|
21873
22179
|
const normalized = normalizeSort(sort);
|
|
21874
22180
|
const fields = normalized.map((entry) => entry.field);
|
|
21875
22181
|
const directions = normalized.map((entry) => entry.direction);
|
|
@@ -21892,7 +22198,7 @@ function pageInSortOrder(partitions, cursor, filtered, limit, sort, signature, s
|
|
|
21892
22198
|
const hasMore = merged.length > limit;
|
|
21893
22199
|
const page = hasMore ? merged.slice(0, limit) : merged;
|
|
21894
22200
|
const last = page[page.length - 1];
|
|
21895
|
-
const nextCursor = hasMore && last !== void 0 ? { anchor: last.id, score: null, sortKey: last.key, sortSignature: signature } : null;
|
|
22201
|
+
const nextCursor = hasMore && last !== void 0 ? { anchor: last.id, score: null, sortKey: last.key, sortSignature: signature, binding } : null;
|
|
21896
22202
|
return { ids: page.map((entry) => entry.id), nextCursor };
|
|
21897
22203
|
}
|
|
21898
22204
|
function countAcrossPartitions(manager, partitionIds, partitions) {
|
|
@@ -21911,15 +22217,16 @@ function executeListDocuments(params, context) {
|
|
|
21911
22217
|
const limit = clampListLimit(params.limit);
|
|
21912
22218
|
const signature = sortSignatureOf(params.sort);
|
|
21913
22219
|
requireSortableFields(params.sort, schema);
|
|
22220
|
+
const binding = listBindingOf(params.filters);
|
|
21914
22221
|
let cursor = null;
|
|
21915
22222
|
if (params.cursor !== void 0) {
|
|
21916
22223
|
cursor = decodePageCursor(params.cursor);
|
|
21917
|
-
requireMatchingCursor(cursor, params.cursor, signature, false);
|
|
22224
|
+
requireMatchingCursor(cursor, params.cursor, signature, false, binding);
|
|
21918
22225
|
}
|
|
21919
22226
|
const partitions = context.partitionIds === void 0 ? manager.getAllPartitions() : context.partitionIds.map((partitionId) => manager.partitionAt(partitionId)).filter((partition) => partition !== void 0);
|
|
21920
22227
|
const filtered = params.filters === void 0 ? null : collectFilterMatches(partitions, params.filters, schema);
|
|
21921
22228
|
const total = filtered === null ? countAcrossPartitions(manager, context.partitionIds, partitions) : filtered.total;
|
|
21922
|
-
const page = params.sort === void 0 || signature === null ? pageInIdOrder(partitions, cursor, filtered, limit) : pageInSortOrder(partitions, cursor, filtered, limit, params.sort, signature, schema);
|
|
22229
|
+
const page = params.sort === void 0 || signature === null ? pageInIdOrder(partitions, cursor, filtered, limit, binding) : pageInSortOrder(partitions, cursor, filtered, limit, params.sort, signature, schema, binding);
|
|
21923
22230
|
const projection = resolveProjection(params.document);
|
|
21924
22231
|
const documents = [];
|
|
21925
22232
|
for (const docId of page.ids) {
|
|
@@ -21987,18 +22294,14 @@ function applyGrouping(hits, group, getDocument) {
|
|
|
21987
22294
|
}
|
|
21988
22295
|
const result = { values: entry.values, hits: groupHits };
|
|
21989
22296
|
if (group.reduce) {
|
|
21990
|
-
|
|
21991
|
-
|
|
21992
|
-
|
|
21993
|
-
|
|
21994
|
-
|
|
21995
|
-
|
|
21996
|
-
|
|
21997
|
-
|
|
21998
|
-
;
|
|
21999
|
-
result.reduced = accumulator;
|
|
22000
|
-
} catch (err) {
|
|
22001
|
-
result.reducerError = err instanceof Error ? err.message : String(err);
|
|
22297
|
+
const folded = foldGroupReducer(
|
|
22298
|
+
group.reduce,
|
|
22299
|
+
groupHits.map((hit) => ({ document: getDocument(hit.id), score: hit.score ?? 0 }))
|
|
22300
|
+
);
|
|
22301
|
+
if (folded.reducerError !== void 0) {
|
|
22302
|
+
result.reducerError = folded.reducerError;
|
|
22303
|
+
} else {
|
|
22304
|
+
result.reduced = folded.reduced;
|
|
22002
22305
|
}
|
|
22003
22306
|
}
|
|
22004
22307
|
groups.push(result);
|
|
@@ -22011,19 +22314,49 @@ function applyGrouping(hits, group, getDocument) {
|
|
|
22011
22314
|
const bId = b.hits.length > 0 ? b.hits[0].id : "";
|
|
22012
22315
|
return compareCodePoints(aId, bId);
|
|
22013
22316
|
});
|
|
22317
|
+
if (group.limit !== void 0 && Number.isFinite(group.limit) && group.limit >= 0) {
|
|
22318
|
+
const cap = Math.floor(group.limit);
|
|
22319
|
+
if (groups.length > cap) {
|
|
22320
|
+
groups.length = cap;
|
|
22321
|
+
}
|
|
22322
|
+
}
|
|
22014
22323
|
return groups;
|
|
22015
22324
|
}
|
|
22325
|
+
function foldGroupReducer(reduce, rows) {
|
|
22326
|
+
try {
|
|
22327
|
+
let accumulator = reduce.initialValue();
|
|
22328
|
+
for (const row of rows) {
|
|
22329
|
+
if (row.document !== void 0) {
|
|
22330
|
+
accumulator = reduce.reducer(accumulator, row.document, row.score);
|
|
22331
|
+
}
|
|
22332
|
+
}
|
|
22333
|
+
return { reduced: accumulator };
|
|
22334
|
+
} catch (err) {
|
|
22335
|
+
return { reducerError: err instanceof Error ? err.message : String(err) };
|
|
22336
|
+
}
|
|
22337
|
+
}
|
|
22016
22338
|
|
|
22017
22339
|
// src/search/pinning.ts
|
|
22340
|
+
function dedupePinnedEntries(pinned) {
|
|
22341
|
+
const deduped = [];
|
|
22342
|
+
const seen = /* @__PURE__ */ new Set();
|
|
22343
|
+
for (const entry of pinned) {
|
|
22344
|
+
if (seen.has(entry.docId)) continue;
|
|
22345
|
+
seen.add(entry.docId);
|
|
22346
|
+
deduped.push(entry);
|
|
22347
|
+
}
|
|
22348
|
+
return deduped;
|
|
22349
|
+
}
|
|
22018
22350
|
function applyPinning(hits, pinned, resolveDoc) {
|
|
22019
22351
|
const result = hits.slice();
|
|
22020
|
-
const
|
|
22352
|
+
const deduped = dedupePinnedEntries(pinned);
|
|
22353
|
+
const pinnedDocIds = new Set(deduped.map((entry) => entry.docId));
|
|
22021
22354
|
for (let i = result.length - 1; i >= 0; i--) {
|
|
22022
22355
|
if (pinnedDocIds.has(result[i].id)) {
|
|
22023
22356
|
result.splice(i, 1);
|
|
22024
22357
|
}
|
|
22025
22358
|
}
|
|
22026
|
-
const sorted =
|
|
22359
|
+
const sorted = deduped.sort((a, b) => a.position - b.position);
|
|
22027
22360
|
for (const entry of sorted) {
|
|
22028
22361
|
const doc = resolveDoc(entry.docId);
|
|
22029
22362
|
if (!doc) continue;
|
|
@@ -22217,17 +22550,7 @@ function applyHighlights(hits, params, language, analysis) {
|
|
|
22217
22550
|
|
|
22218
22551
|
// src/engine/query/shared.ts
|
|
22219
22552
|
function partitionsFor(manager, partitionIds) {
|
|
22220
|
-
|
|
22221
|
-
return manager.getAllPartitions();
|
|
22222
|
-
}
|
|
22223
|
-
const partitions = [];
|
|
22224
|
-
for (const partitionId of partitionIds) {
|
|
22225
|
-
const partition = manager.partitionAt(partitionId);
|
|
22226
|
-
if (partition !== void 0) {
|
|
22227
|
-
partitions.push(partition);
|
|
22228
|
-
}
|
|
22229
|
-
}
|
|
22230
|
-
return partitions;
|
|
22553
|
+
return partitionsIn(manager, partitionIds);
|
|
22231
22554
|
}
|
|
22232
22555
|
function coverageFor(manager, partitionIds) {
|
|
22233
22556
|
if (partitionIds === void 0) {
|
|
@@ -22321,7 +22644,7 @@ function executeSortedQueryPage(params, context, limit, offset, sortSignature) {
|
|
|
22321
22644
|
let anchorId = null;
|
|
22322
22645
|
if (params.searchAfter !== void 0) {
|
|
22323
22646
|
const decoded = decodePageCursor(params.searchAfter);
|
|
22324
|
-
requireMatchingCursor(decoded, params.searchAfter, sortSignature, true);
|
|
22647
|
+
requireMatchingCursor(decoded, params.searchAfter, sortSignature, true, context.cursorBinding);
|
|
22325
22648
|
anchorKey = decoded.sortKey;
|
|
22326
22649
|
anchorId = decoded.anchor;
|
|
22327
22650
|
}
|
|
@@ -22366,7 +22689,13 @@ function executeSortedQueryPage(params, context, limit, offset, sortSignature) {
|
|
|
22366
22689
|
const last = page[page.length - 1];
|
|
22367
22690
|
let cursor;
|
|
22368
22691
|
if (hasMore && last !== void 0) {
|
|
22369
|
-
cursor = encodePageCursor({
|
|
22692
|
+
cursor = encodePageCursor({
|
|
22693
|
+
anchor: last.id,
|
|
22694
|
+
score: null,
|
|
22695
|
+
sortKey: last.key,
|
|
22696
|
+
sortSignature,
|
|
22697
|
+
binding: context.cursorBinding
|
|
22698
|
+
});
|
|
22370
22699
|
}
|
|
22371
22700
|
return {
|
|
22372
22701
|
hits: page.map((entry) => ({ id: entry.id, document: void 0 })),
|
|
@@ -22652,7 +22981,7 @@ async function executeQuery(params, context) {
|
|
|
22652
22981
|
if (params.group) {
|
|
22653
22982
|
groups = applyGrouping(hits, params.group, (docId) => manager.getRef(docId));
|
|
22654
22983
|
}
|
|
22655
|
-
if (params.pinned) {
|
|
22984
|
+
if (params.pinned && params.searchAfter === void 0 && context.partitionIds === void 0) {
|
|
22656
22985
|
hits = applyPinning(hits, params.pinned, (docId) => {
|
|
22657
22986
|
const doc = manager.getRef(docId);
|
|
22658
22987
|
if (!doc) return void 0;
|
|
@@ -22667,7 +22996,16 @@ async function executeQuery(params, context) {
|
|
|
22667
22996
|
sortKeyOf
|
|
22668
22997
|
};
|
|
22669
22998
|
}
|
|
22670
|
-
const
|
|
22999
|
+
const pinnedIds = params.pinned !== void 0 && params.searchAfter === void 0 ? new Set(params.pinned.map((entry) => entry.docId)) : void 0;
|
|
23000
|
+
const paged = applyPagination(
|
|
23001
|
+
hits,
|
|
23002
|
+
limit,
|
|
23003
|
+
offset,
|
|
23004
|
+
context.cursorBinding,
|
|
23005
|
+
params.searchAfter,
|
|
23006
|
+
sortContext,
|
|
23007
|
+
pinnedIds
|
|
23008
|
+
);
|
|
22671
23009
|
paginated = paged.paginated;
|
|
22672
23010
|
nextCursor = paged.nextCursor;
|
|
22673
23011
|
count = fanOutResult.totalMatched;
|
|
@@ -22736,6 +23074,11 @@ async function executePreflight(params, context) {
|
|
|
22736
23074
|
} else if (isHybridMode && hasGlobalVectorIndex) {
|
|
22737
23075
|
const result = await executeHybridSearch(params, context, preflightLimit, preflightOffset);
|
|
22738
23076
|
totalMatched = result.totalMatched;
|
|
23077
|
+
} else if (countsWithoutScores(params)) {
|
|
23078
|
+
totalMatched = fanOutMatchCount(manager, params, language, config.schema, {
|
|
23079
|
+
searchOptions: searchOptionsFor(manager),
|
|
23080
|
+
partitionIds: context.partitionIds
|
|
23081
|
+
});
|
|
22739
23082
|
} else {
|
|
22740
23083
|
const scoring = scoringConfigFor(params, context);
|
|
22741
23084
|
const workerResult = workerSearch ? await workerSearch(indexName, params, broadcastStatsForWorker(params, context, scoring), context.partitionIds) : null;
|
|
@@ -22881,7 +23224,8 @@ async function runEngineQuery(core, indexName, params, options) {
|
|
|
22881
23224
|
workerSearch,
|
|
22882
23225
|
indexName,
|
|
22883
23226
|
broadcastStats: broadcastStatsFor(core),
|
|
22884
|
-
partitionIds: options?.partitionIds
|
|
23227
|
+
partitionIds: options?.partitionIds,
|
|
23228
|
+
cursorBinding: queryBindingOf(params)
|
|
22885
23229
|
});
|
|
22886
23230
|
try {
|
|
22887
23231
|
await core.pluginRegistry.runHook("afterSearch", {
|
|
@@ -22915,7 +23259,8 @@ async function runEnginePreflight(core, indexName, params, options) {
|
|
|
22915
23259
|
workerSearch,
|
|
22916
23260
|
indexName,
|
|
22917
23261
|
broadcastStats: broadcastStatsFor(core),
|
|
22918
|
-
partitionIds: options?.partitionIds
|
|
23262
|
+
partitionIds: options?.partitionIds,
|
|
23263
|
+
cursorBinding: queryBindingOf(params)
|
|
22919
23264
|
});
|
|
22920
23265
|
if (core.analysisRebuild.isStale(indexName)) {
|
|
22921
23266
|
result.analysisStale = true;
|