@delali/narsil 0.3.1-next.72 → 0.3.1-next.74
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 +2 -2
- package/dist/adapters/filesystem.mjs +1 -1
- package/dist/adapters/indexeddb.mjs +1 -1
- package/dist/{capabilities-D6gjjQyA.d.ts → capabilities-CAMzmkAg.d.ts} +19 -4
- package/dist/{chunk-P2ZZN32C.mjs → chunk-2E35UM3G.mjs} +2 -12
- package/dist/chunk-3DDUNI6N.mjs +48 -0
- package/dist/{chunk-KZTI25D3.mjs → chunk-4MQ5F4IL.mjs} +1 -1
- package/dist/{chunk-HVJYTKK7.mjs → chunk-BVBIQQKG.mjs} +947 -1327
- package/dist/{chunk-2X2ZQOAB.mjs → chunk-CTOSGRM7.mjs} +101 -21
- package/dist/{chunk-7QMTA7AA.mjs → chunk-CUZOX6CN.mjs} +7784 -4276
- package/dist/chunk-I23G3IZC.mjs +593 -0
- package/dist/{chunk-RV77FR2F.mjs → chunk-I64LXKO3.mjs} +0 -1
- package/dist/chunk-KEHK2O6P.mjs +13 -0
- package/dist/{chunk-CVPA5Q7R.mjs → chunk-LX4JERXI.mjs} +9 -6
- package/dist/{chunk-EDMCZLSJ.mjs → chunk-NOZUQM7J.mjs} +193 -13
- package/dist/{chunk-LCCL6EEH.mjs → chunk-PO53FV4Q.mjs} +93 -94
- package/dist/chunk-T5ZWEWVD.mjs +658 -0
- package/dist/{chunk-Y52WZWAU.mjs → chunk-TVFLHM7M.mjs} +4 -4
- package/dist/{chunk-QR4OKRVY.mjs → chunk-VKX2BPXD.mjs} +147 -642
- package/dist/{chunk-3HQPUCCT.mjs → chunk-XW25X6AU.mjs} +66 -237
- package/dist/{chunk-M6XF5HDE.mjs → chunk-Z3DQPOJQ.mjs} +127 -30
- package/dist/{client-C2TiW29y.d.ts → client-C-I70ArH.d.ts} +77 -26
- package/dist/client.d.ts +9 -9
- package/dist/client.mjs +44 -22
- package/dist/{config-BLguB-om.d.ts → config-C6Iw5rCX.d.ts} +11 -4
- package/dist/{config-C7Ip8Ife.d.ts → config-DJPH3IQB.d.ts} +11 -2
- package/dist/direct-executor-KFAGILJC.mjs +17 -0
- package/dist/distribution/coordinator/etcd.d.ts +29 -16
- package/dist/distribution/coordinator/etcd.mjs +162 -75
- package/dist/distribution/coordinator/in-memory.d.ts +2 -2
- package/dist/distribution/transport/grpc.d.ts +2 -2
- package/dist/distribution/transport/grpc.mjs +22 -2
- package/dist/distribution/transport/in-memory.d.ts +2 -2
- package/dist/distribution/transport/in-memory.mjs +6 -3
- package/dist/distribution/transport/tcp.d.ts +2 -2
- package/dist/distribution/transport/tcp.mjs +40 -16
- package/dist/distribution.d.ts +9 -9
- package/dist/distribution.mjs +647 -366
- package/dist/embeddings/openai.mjs +1 -1
- package/dist/{engine-Dm4446j1.d.ts → engine-B8eRPO7m.d.ts} +97 -188
- package/dist/index.browser.mjs +12132 -8592
- package/dist/index.d.ts +27 -8
- package/dist/index.mjs +15 -14
- package/dist/{memory-CKHTU1CL.d.ts → memory-DJEwWoCi.d.ts} +1204 -968
- package/dist/partial-words-DTIHO8G4.d.ts +19 -0
- package/dist/partial-words.d.ts +22 -0
- package/dist/partial-words.mjs +11 -0
- package/dist/pattern.mjs +1 -1
- package/dist/persistence/durability/checkpoint-worker.d.ts +57 -29
- package/dist/persistence/durability/checkpoint-worker.mjs +26 -16
- package/dist/react.d.ts +7 -7
- package/dist/react.mjs +0 -1
- package/dist/{schema-BBOCdhND.d.ts → schema-DgyDijhf.d.ts} +6 -2
- package/dist/server.d.ts +11 -11
- package/dist/server.mjs +212 -32
- package/dist/{tasks-BECd0b__.d.ts → tasks-BVmAKYBh.d.ts} +3 -3
- package/dist/{thread-IBSIZZ6W.mjs → thread-W6DPKEF6.mjs} +82 -21
- package/dist/{types-BQDlIvfS.d.ts → types-B3b68nfF.d.ts} +1 -1
- package/dist/{types-D5OwhtsQ.d.ts → types-Cb9kiY5P.d.ts} +1 -1
- package/dist/{types-BiUmaiWT.d.ts → types-ChrVy4lH.d.ts} +1 -1
- package/dist/vector/search-worker.d.ts +1 -1
- package/dist/vector/search-worker.mjs +4 -3
- package/dist/workers/entry.mjs +4 -4
- package/package.json +15 -7
- package/dist/chunk-3L4U6EJQ.mjs +0 -49
- package/dist/chunk-IFBKLBGB.mjs +0 -7
- package/dist/chunk-XZ4PAREY.mjs +0 -25
- package/dist/direct-executor-SVCHXR74.mjs +0 -14
- package/dist/serialization/crc32-worker.d.ts +0 -20
- package/dist/serialization/crc32-worker.mjs +0 -62
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import { MAX_SORT_FIELDS } from './chunk-
|
|
2
|
-
import { nativeSearchCoreIsEnabled, loadNativeCore } from './chunk-
|
|
3
|
-
import { NarsilError, ServerErrorCodes, ErrorCodes } from './chunk-
|
|
1
|
+
import { MAX_SORT_FIELDS } from './chunk-3DDUNI6N.mjs';
|
|
2
|
+
import { nativeSearchCoreIsEnabled, loadNativeCore } from './chunk-2E35UM3G.mjs';
|
|
3
|
+
import { NarsilError, ServerErrorCodes, ErrorCodes } from './chunk-I64LXKO3.mjs';
|
|
4
|
+
import { mkdtemp, open, rm } from 'fs/promises';
|
|
5
|
+
import { tmpdir } from 'os';
|
|
6
|
+
import path from 'path';
|
|
4
7
|
|
|
5
8
|
// src/server/capabilities.ts
|
|
6
9
|
var ASYNC_IMPORT_CAPABILITY = "documents.import.async";
|
|
@@ -8,12 +11,14 @@ var TASK_CANCEL_CAPABILITY = "tasks.cancel";
|
|
|
8
11
|
var TASK_FILTER_CAPABILITY = "tasks.filter";
|
|
9
12
|
var REBUILD_ANALYSIS_CAPABILITY = "indexes.rebuildAnalysis";
|
|
10
13
|
var INDEX_LIFECYCLE_CAPABILITY = "indexes.lifecycle";
|
|
14
|
+
var DOCUMENT_EXPORT_CAPABILITY = "indexes.documentExport";
|
|
11
15
|
var SERVER_CAPABILITIES = [
|
|
12
16
|
ASYNC_IMPORT_CAPABILITY,
|
|
13
17
|
TASK_CANCEL_CAPABILITY,
|
|
14
18
|
TASK_FILTER_CAPABILITY,
|
|
15
19
|
REBUILD_ANALYSIS_CAPABILITY,
|
|
16
|
-
INDEX_LIFECYCLE_CAPABILITY
|
|
20
|
+
INDEX_LIFECYCLE_CAPABILITY,
|
|
21
|
+
DOCUMENT_EXPORT_CAPABILITY
|
|
17
22
|
];
|
|
18
23
|
|
|
19
24
|
// src/server/concurrency-gate.ts
|
|
@@ -171,7 +176,6 @@ var STATUS_BY_CODE = {
|
|
|
171
176
|
SNAPSHOT_SYNC_HEADER_INVALID: 400,
|
|
172
177
|
SNAPSHOT_SYNC_FRAME_INVALID: 400,
|
|
173
178
|
SNAPSHOT_SYNC_INDEX_NOT_FOUND: 404,
|
|
174
|
-
SNAPSHOT_SYNC_TOO_LARGE: 413,
|
|
175
179
|
SNAPSHOT_SYNC_CHUNK_SIZE_EXCEEDED: 413,
|
|
176
180
|
SNAPSHOT_SYNC_ABORTED: 409,
|
|
177
181
|
SNAPSHOT_SYNC_CAPACITY_EXHAUSTED: 503,
|
|
@@ -226,6 +230,11 @@ function encodeJson(value) {
|
|
|
226
230
|
var BYTES_PER_MB = 1024 * 1024;
|
|
227
231
|
var DEFAULT_MAX_BODY_BYTES = 16 * BYTES_PER_MB;
|
|
228
232
|
var DEFAULT_MAX_IMPORT_BYTES = 100 * BYTES_PER_MB;
|
|
233
|
+
var DEFAULT_MAX_RESTORE_BYTES = 64 * 1024 * BYTES_PER_MB;
|
|
234
|
+
var SPOOL_PAUSE_ABOVE_BYTES = 8 * BYTES_PER_MB;
|
|
235
|
+
var SNAPSHOT_ARCHIVE_CONTENT_TYPE = "application/x-tar";
|
|
236
|
+
var DOCUMENT_EXPORT_CONTENT_TYPE = "application/x-ndjson";
|
|
237
|
+
var RELAY_STREAM_CHUNKS_IN_FLIGHT = 4;
|
|
229
238
|
var DEFAULT_MAX_LINE_BYTES = 4 * BYTES_PER_MB;
|
|
230
239
|
var DEFAULT_IMPORT_BATCH_SIZE = 1e3;
|
|
231
240
|
var IMPORT_FLUSHES_IN_FLIGHT = 4;
|
|
@@ -300,8 +309,56 @@ function sendError(res, status, code, message, details) {
|
|
|
300
309
|
res.writeStatus(statusLine(status)).writeHeader("Content-Type", "application/json").end(payload);
|
|
301
310
|
});
|
|
302
311
|
}
|
|
303
|
-
function
|
|
304
|
-
|
|
312
|
+
async function sendStream(res, abort, source, headers) {
|
|
313
|
+
const reader = source.getReader();
|
|
314
|
+
let wake = null;
|
|
315
|
+
abort.onAbort(() => wake?.());
|
|
316
|
+
const waitUntilWritable = () => new Promise((resolve) => {
|
|
317
|
+
wake = () => {
|
|
318
|
+
wake = null;
|
|
319
|
+
resolve();
|
|
320
|
+
};
|
|
321
|
+
res.onWritable(() => {
|
|
322
|
+
wake?.();
|
|
323
|
+
return true;
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
let started = false;
|
|
327
|
+
const begin = () => {
|
|
328
|
+
if (started) return;
|
|
329
|
+
started = true;
|
|
330
|
+
res.writeStatus(statusLine(200));
|
|
331
|
+
for (const [key, value] of headers) res.writeHeader(key, value);
|
|
332
|
+
};
|
|
333
|
+
try {
|
|
334
|
+
for (; ; ) {
|
|
335
|
+
const step = await reader.read();
|
|
336
|
+
if (abort.aborted) {
|
|
337
|
+
await reader.cancel().catch(() => void 0);
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
if (step.done) {
|
|
341
|
+
res.cork(() => {
|
|
342
|
+
begin();
|
|
343
|
+
res.end();
|
|
344
|
+
});
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
let writable = true;
|
|
348
|
+
res.cork(() => {
|
|
349
|
+
begin();
|
|
350
|
+
writable = res.write(step.value);
|
|
351
|
+
});
|
|
352
|
+
if (!writable && !abort.aborted) await waitUntilWritable();
|
|
353
|
+
}
|
|
354
|
+
} catch (err) {
|
|
355
|
+
await reader.cancel().catch(() => void 0);
|
|
356
|
+
if (abort.aborted) return;
|
|
357
|
+
if (!started) throw err;
|
|
358
|
+
res.cork(() => {
|
|
359
|
+
res.close();
|
|
360
|
+
});
|
|
361
|
+
}
|
|
305
362
|
}
|
|
306
363
|
function sendRelayed(res, abort, status, headers, body) {
|
|
307
364
|
if (abort.aborted) return;
|
|
@@ -496,7 +553,14 @@ function validateRebalance(body) {
|
|
|
496
553
|
}
|
|
497
554
|
return null;
|
|
498
555
|
}
|
|
499
|
-
var TASK_TYPES = [
|
|
556
|
+
var TASK_TYPES = [
|
|
557
|
+
"optimizeVectors",
|
|
558
|
+
"rebalance",
|
|
559
|
+
"restore",
|
|
560
|
+
"import",
|
|
561
|
+
"importExport",
|
|
562
|
+
"rebuildAnalysis"
|
|
563
|
+
];
|
|
500
564
|
var TASK_STATUSES = ["running", "succeeded", "failed", "cancelled"];
|
|
501
565
|
function parseCountParam(raw, field, minimum) {
|
|
502
566
|
if (raw === null) return minimum;
|
|
@@ -631,6 +695,87 @@ function createVersionHandler(deps) {
|
|
|
631
695
|
}
|
|
632
696
|
return { report };
|
|
633
697
|
}
|
|
698
|
+
var NotAdmittedError = class extends Error {
|
|
699
|
+
};
|
|
700
|
+
async function removeDirectory(directory) {
|
|
701
|
+
if (directory !== null) await rm(directory, { recursive: true, force: true });
|
|
702
|
+
}
|
|
703
|
+
function spoolBody(res, maxBytes, abort, admitted) {
|
|
704
|
+
return new Promise((resolve, reject) => {
|
|
705
|
+
const state = {
|
|
706
|
+
directory: null,
|
|
707
|
+
handle: null,
|
|
708
|
+
chain: Promise.resolve(),
|
|
709
|
+
queued: 0,
|
|
710
|
+
total: 0,
|
|
711
|
+
paused: true,
|
|
712
|
+
done: false
|
|
713
|
+
};
|
|
714
|
+
const fail = (error, answer) => {
|
|
715
|
+
if (state.done) return;
|
|
716
|
+
state.done = true;
|
|
717
|
+
if (answer && !abort.aborted) {
|
|
718
|
+
sendError(res, 500, ServerErrorCodes.INTERNAL_ERROR, "The server could not store the request body");
|
|
719
|
+
}
|
|
720
|
+
void state.chain.catch(() => void 0).then(async () => {
|
|
721
|
+
await state.handle?.close().catch(() => void 0);
|
|
722
|
+
await removeDirectory(state.directory).catch(() => void 0);
|
|
723
|
+
}).finally(() => reject(error));
|
|
724
|
+
};
|
|
725
|
+
const failFromChain = (error) => {
|
|
726
|
+
if (error instanceof NotAdmittedError) fail(error, false);
|
|
727
|
+
else fail(error instanceof Error ? error : new Error(String(error)), true);
|
|
728
|
+
};
|
|
729
|
+
res.pause();
|
|
730
|
+
state.chain = (async () => {
|
|
731
|
+
if (!await admitted) throw new NotAdmittedError("the request was not admitted");
|
|
732
|
+
state.directory = await mkdtemp(path.join(tmpdir(), "narsil-spool-"));
|
|
733
|
+
state.handle = await open(path.join(state.directory, "body"), "w");
|
|
734
|
+
if (!abort.aborted && !state.done && state.queued <= SPOOL_PAUSE_ABOVE_BYTES) {
|
|
735
|
+
state.paused = false;
|
|
736
|
+
res.resume();
|
|
737
|
+
}
|
|
738
|
+
})();
|
|
739
|
+
state.chain.catch(failFromChain);
|
|
740
|
+
abort.onAbort(() => fail(new Error("aborted"), false));
|
|
741
|
+
res.onData((chunk, isLast) => {
|
|
742
|
+
if (state.done || abort.aborted) return;
|
|
743
|
+
state.total += chunk.byteLength;
|
|
744
|
+
if (maxBytes > 0 && state.total > maxBytes) {
|
|
745
|
+
sendError(res, 413, ServerErrorCodes.PAYLOAD_TOO_LARGE, "Request body exceeds the configured size limit");
|
|
746
|
+
fail(new Error("payload too large"), false);
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
const copy = new Uint8Array(chunk.slice(0));
|
|
750
|
+
state.queued += copy.byteLength;
|
|
751
|
+
if (!state.paused && state.queued > SPOOL_PAUSE_ABOVE_BYTES) {
|
|
752
|
+
state.paused = true;
|
|
753
|
+
res.pause();
|
|
754
|
+
}
|
|
755
|
+
state.chain = state.chain.then(async () => {
|
|
756
|
+
if (state.handle === null) throw new Error("the spool file is not open");
|
|
757
|
+
await state.handle.write(copy);
|
|
758
|
+
state.queued -= copy.byteLength;
|
|
759
|
+
if (state.paused && state.queued <= SPOOL_PAUSE_ABOVE_BYTES && !abort.aborted && !state.done) {
|
|
760
|
+
state.paused = false;
|
|
761
|
+
res.resume();
|
|
762
|
+
}
|
|
763
|
+
});
|
|
764
|
+
state.chain.catch(failFromChain);
|
|
765
|
+
if (!isLast) return;
|
|
766
|
+
state.chain.then(async () => {
|
|
767
|
+
if (state.done) return;
|
|
768
|
+
state.done = true;
|
|
769
|
+
await state.handle?.close();
|
|
770
|
+
resolve({
|
|
771
|
+
path: path.join(state.directory ?? "", "body"),
|
|
772
|
+
bytes: state.total,
|
|
773
|
+
remove: () => removeDirectory(state.directory)
|
|
774
|
+
});
|
|
775
|
+
}, failFromChain);
|
|
776
|
+
});
|
|
777
|
+
});
|
|
778
|
+
}
|
|
634
779
|
|
|
635
780
|
// src/server/request.ts
|
|
636
781
|
function initAbortHandler(res) {
|
|
@@ -732,6 +877,19 @@ function sinkWritingAfterStatus(res, headers) {
|
|
|
732
877
|
res.end(body);
|
|
733
878
|
return sink;
|
|
734
879
|
},
|
|
880
|
+
write(chunk) {
|
|
881
|
+
return res.write(chunk);
|
|
882
|
+
},
|
|
883
|
+
pause() {
|
|
884
|
+
res.pause();
|
|
885
|
+
},
|
|
886
|
+
resume() {
|
|
887
|
+
res.resume();
|
|
888
|
+
},
|
|
889
|
+
close() {
|
|
890
|
+
res.close();
|
|
891
|
+
return sink;
|
|
892
|
+
},
|
|
735
893
|
endWithoutBody() {
|
|
736
894
|
res.endWithoutBody();
|
|
737
895
|
return sink;
|
|
@@ -830,18 +988,33 @@ function createRouteRunner(deps) {
|
|
|
830
988
|
}
|
|
831
989
|
const bodyPromise = needsBody ? readBody(res, opts.maxBytes, abort, declaredBytes) : Promise.resolve(null);
|
|
832
990
|
const hookPromise = hookContext !== null && authorize !== void 0 ? authorize(hookContext) : Promise.resolve({ allowed: true });
|
|
833
|
-
|
|
834
|
-
|
|
991
|
+
const spoolPromise = opts.spoolsBody === true ? spoolBody(
|
|
992
|
+
res,
|
|
993
|
+
opts.maxBytes,
|
|
994
|
+
abort,
|
|
995
|
+
hookPromise.then((authorization) => authorization.allowed)
|
|
996
|
+
).catch(() => null) : Promise.resolve(null);
|
|
997
|
+
Promise.all([bodyPromise, spoolPromise, hookPromise]).then(async ([rawBody, spooledBody, authorization]) => {
|
|
998
|
+
const discardSpool = () => {
|
|
999
|
+
void spooledBody?.remove().catch(() => void 0);
|
|
1000
|
+
};
|
|
1001
|
+
if (abort.aborted) {
|
|
1002
|
+
discardSpool();
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
835
1005
|
if (!authorization.allowed) {
|
|
1006
|
+
discardSpool();
|
|
836
1007
|
sendDenial(res, authorization);
|
|
837
1008
|
return;
|
|
838
1009
|
}
|
|
1010
|
+
if (opts.spoolsBody === true && spooledBody === null) return;
|
|
839
1011
|
if (gated && !gate.tryAcquire()) {
|
|
1012
|
+
discardSpool();
|
|
840
1013
|
sendError(res, 429, ServerErrorCodes.TOO_MANY_REQUESTS, "The server is at capacity; retry shortly");
|
|
841
1014
|
return;
|
|
842
1015
|
}
|
|
843
1016
|
try {
|
|
844
|
-
await handler({ res, params, query, contentType, rawBody, abort, hookContext });
|
|
1017
|
+
await handler({ res, params, query, contentType, rawBody, spooledBody, abort, hookContext });
|
|
845
1018
|
} catch (err) {
|
|
846
1019
|
if (!abort.aborted) {
|
|
847
1020
|
sendError(res, 500, ServerErrorCodes.INTERNAL_ERROR, "An unexpected error occurred");
|
|
@@ -916,7 +1089,14 @@ function serverRoutes(limits) {
|
|
|
916
1089
|
method: "post",
|
|
917
1090
|
path: "/indexes/:name/restore",
|
|
918
1091
|
handler: "restore",
|
|
919
|
-
options: { paramCount: 1,
|
|
1092
|
+
options: { paramCount: 1, spoolsBody: true, maxBytes: limits.maxRestoreBytes }
|
|
1093
|
+
},
|
|
1094
|
+
{ method: "get", path: "/indexes/:name/export", handler: "exportDocuments", options: named },
|
|
1095
|
+
{
|
|
1096
|
+
method: "post",
|
|
1097
|
+
path: "/indexes/:name/import",
|
|
1098
|
+
handler: "importExport",
|
|
1099
|
+
options: { paramCount: 1, spoolsBody: true, maxBytes: limits.maxRestoreBytes }
|
|
920
1100
|
}
|
|
921
1101
|
];
|
|
922
1102
|
}
|
|
@@ -975,4 +1155,4 @@ function childAppOf(app) {
|
|
|
975
1155
|
return candidate;
|
|
976
1156
|
}
|
|
977
1157
|
|
|
978
|
-
export { ASYNC_IMPORT_CAPABILITY, DEFAULT_IMPORT_BATCH_SIZE, DEFAULT_MAX_BODY_BYTES, DEFAULT_MAX_CONCURRENT_REQUESTS, DEFAULT_MAX_CONCURRENT_TASKS, DEFAULT_MAX_FETCH_DOCUMENTS, DEFAULT_MAX_IMPORT_BYTES, DEFAULT_MAX_IMPORT_ERRORS, DEFAULT_MAX_LINE_BYTES, DEFAULT_MAX_RESULT_WINDOW, DEFAULT_MAX_RETAINED_TASKS, DEFAULT_MAX_TASK_PAGE_SIZE, DEFAULT_TASK_PAGE_SIZE, IMPORT_FLUSHES_IN_FLIGHT, INDEX_LIFECYCLE_CAPABILITY, INDEX_TOUCH_INTERVALS_PER_IDLE_TIMEOUT, MAIN_THREAD_GATE_SLOT, MAX_INDEX_TOUCH_INTERVAL_MS, MIN_COUNTED_SERVER_LIMIT, MIN_UNBOUNDED_SERVER_LIMIT, REBUILD_ANALYSIS_CAPABILITY, RUNNING_TASK_TTL_MS, SERVER_CAPABILITIES, TASK_CANCEL_CAPABILITY, TASK_FILTER_CAPABILITY, TASK_PROGRESS_WRITE_INTERVAL_MS, TERMINAL_TASK_TTL_MS, acceptorOf, authorizerFor, badRequest, childAppOf, clearGateSlot, corsHeaderReader, createDocumentReadHandlers, createRouteRunner, createSharedGateBuffer, createSharedRequestGate, createVersionHandler, gateSlotOfWorker, httpStatusForNarsilError, loadUWebSockets, parseJson, parseJsonOptional, parseTaskListQuery, registerServerRoutes, rejectInvalid, resolveCors, respondError, respondJson,
|
|
1158
|
+
export { ASYNC_IMPORT_CAPABILITY, DEFAULT_IMPORT_BATCH_SIZE, DEFAULT_MAX_BODY_BYTES, DEFAULT_MAX_CONCURRENT_REQUESTS, DEFAULT_MAX_CONCURRENT_TASKS, DEFAULT_MAX_FETCH_DOCUMENTS, DEFAULT_MAX_IMPORT_BYTES, DEFAULT_MAX_IMPORT_ERRORS, DEFAULT_MAX_LINE_BYTES, DEFAULT_MAX_RESTORE_BYTES, DEFAULT_MAX_RESULT_WINDOW, DEFAULT_MAX_RETAINED_TASKS, DEFAULT_MAX_TASK_PAGE_SIZE, DEFAULT_TASK_PAGE_SIZE, DOCUMENT_EXPORT_CAPABILITY, DOCUMENT_EXPORT_CONTENT_TYPE, IMPORT_FLUSHES_IN_FLIGHT, INDEX_LIFECYCLE_CAPABILITY, INDEX_TOUCH_INTERVALS_PER_IDLE_TIMEOUT, MAIN_THREAD_GATE_SLOT, MAX_INDEX_TOUCH_INTERVAL_MS, MIN_COUNTED_SERVER_LIMIT, MIN_UNBOUNDED_SERVER_LIMIT, REBUILD_ANALYSIS_CAPABILITY, RELAY_STREAM_CHUNKS_IN_FLIGHT, RUNNING_TASK_TTL_MS, SERVER_CAPABILITIES, SNAPSHOT_ARCHIVE_CONTENT_TYPE, TASK_CANCEL_CAPABILITY, TASK_FILTER_CAPABILITY, TASK_PROGRESS_WRITE_INTERVAL_MS, TERMINAL_TASK_TTL_MS, acceptorOf, authorizerFor, badRequest, childAppOf, clearGateSlot, corsHeaderReader, createDocumentReadHandlers, createRouteRunner, createSharedGateBuffer, createSharedRequestGate, createVersionHandler, gateSlotOfWorker, httpStatusForNarsilError, loadUWebSockets, parseJson, parseJsonOptional, parseTaskListQuery, registerServerRoutes, rejectInvalid, resolveCors, respondError, respondJson, sendError, sendRelayed, sendStream, serializeBatchResult, serializeNarsilError, serverRoutes, statusLine, toHttpError, validateBatch, validateCreateIndex, validateDocumentBody, validateQuery, validateRebalance, validateSuggest, versionReport };
|
|
@@ -1,7 +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 {
|
|
2
|
+
import { nativeSearchCoreIsEnabled, loadNativeCore, stopUsingTheNativeSearchCore, noteFallback } from './chunk-2E35UM3G.mjs';
|
|
3
|
+
import { COMPACTION_TOMBSTONE_RATIO, COMPACTION_ABSOLUTE_THRESHOLD, MAX_LAYER_CAP, PLACEMENT_ROOM_REQUESTS, INITIAL_LIST_CAPACITY, DEFAULT_EF_SEARCH, INITIAL_UPPER_SLOTS } from './chunk-KEHK2O6P.mjs';
|
|
3
4
|
import { compareCodePoints } from './chunk-LJYTW7GT.mjs';
|
|
4
|
-
import { NarsilError, ErrorCodes } from './chunk-
|
|
5
|
+
import { NarsilError, ErrorCodes } from './chunk-I64LXKO3.mjs';
|
|
5
6
|
import { readSync, closeSync, openSync } from 'fs';
|
|
6
7
|
|
|
7
8
|
// src/vector/constants.ts
|
|
@@ -3651,6 +3652,13 @@ function createVectorStore(options) {
|
|
|
3651
3652
|
yield [docId, entryAt(open, ordinal)];
|
|
3652
3653
|
}
|
|
3653
3654
|
},
|
|
3655
|
+
*docIds() {
|
|
3656
|
+
if (open === null) return;
|
|
3657
|
+
for (let ordinal = 0; ordinal < ordToDoc.length; ordinal++) {
|
|
3658
|
+
const docId = ordToDoc[ordinal];
|
|
3659
|
+
if (docId !== void 0) yield docId;
|
|
3660
|
+
}
|
|
3661
|
+
},
|
|
3654
3662
|
clear() {
|
|
3655
3663
|
forgetDocuments();
|
|
3656
3664
|
if (open === null) return;
|
|
@@ -3789,30 +3797,24 @@ function savedTopLayer(state, ordinal) {
|
|
|
3789
3797
|
if (ordinal === NO_ORDINAL || isTombstoned(state, ordinal)) return NO_LAYER;
|
|
3790
3798
|
return Math.min(nodeMaxLayer(state, ordinal), MAX_LAYER_CAP);
|
|
3791
3799
|
}
|
|
3792
|
-
function
|
|
3800
|
+
function neighbourValueCount(state, topLayers, start, end) {
|
|
3793
3801
|
let values = 0;
|
|
3794
|
-
for (let number =
|
|
3802
|
+
for (let number = start; number < end; number++) {
|
|
3795
3803
|
const top = topLayers[number];
|
|
3796
3804
|
if (top < 0) continue;
|
|
3797
3805
|
values += state.adjacency.level0Stride + top * state.adjacency.upperStride;
|
|
3798
3806
|
}
|
|
3799
3807
|
return values;
|
|
3800
3808
|
}
|
|
3801
|
-
function
|
|
3809
|
+
function serializePart(state, numbers, start, end) {
|
|
3810
|
+
const { numberOfOrdinal, ordinalOfNumber, topLayers } = numbers;
|
|
3802
3811
|
const adjacency = state.adjacency;
|
|
3803
|
-
const
|
|
3804
|
-
const
|
|
3805
|
-
const levels = new Uint8Array(ordinalOfNumber.length);
|
|
3806
|
-
for (let number = 0; number < ordinalOfNumber.length; number++) {
|
|
3807
|
-
const ordinal = ordinalOfNumber[number];
|
|
3808
|
-
if (ordinal >= slots) continue;
|
|
3809
|
-
topLayers[number] = savedTopLayer(state, ordinal);
|
|
3810
|
-
levels[number] = topLayers[number] + 1;
|
|
3811
|
-
}
|
|
3812
|
-
const values = new Uint32Array(largestNeighbourValueCount(state, topLayers));
|
|
3812
|
+
const levels = new Uint8Array(end - start);
|
|
3813
|
+
const values = new Uint32Array(neighbourValueCount(state, topLayers, start, end));
|
|
3813
3814
|
let cursor = 0;
|
|
3814
|
-
for (let number =
|
|
3815
|
+
for (let number = start; number < end; number++) {
|
|
3815
3816
|
const top = topLayers[number];
|
|
3817
|
+
levels[number - start] = top + 1;
|
|
3816
3818
|
for (let layer = 0; layer <= top; layer++) {
|
|
3817
3819
|
const base = layerBase(adjacency, ordinalOfNumber[number], layer);
|
|
3818
3820
|
const array = layerArray(adjacency, layer);
|
|
@@ -3830,18 +3832,33 @@ function serializeNumberedGraph(state, numberOfOrdinal, ordinalOfNumber) {
|
|
|
3830
3832
|
values[countAt] = cursor - countAt - 1;
|
|
3831
3833
|
}
|
|
3832
3834
|
}
|
|
3835
|
+
return { levels, neighbours: littleEndianBytesOf(values.subarray(0, cursor)) };
|
|
3836
|
+
}
|
|
3837
|
+
function serializeNumberedGraphParts(state, numberOfOrdinal, ordinalOfNumber, partSize) {
|
|
3838
|
+
const slots = adjacencySlots(state.adjacency);
|
|
3839
|
+
const topLayers = new Int8Array(ordinalOfNumber.length).fill(-1);
|
|
3840
|
+
for (let number = 0; number < ordinalOfNumber.length; number++) {
|
|
3841
|
+
const ordinal = ordinalOfNumber[number];
|
|
3842
|
+
if (ordinal >= slots) continue;
|
|
3843
|
+
topLayers[number] = savedTopLayer(state, ordinal);
|
|
3844
|
+
}
|
|
3833
3845
|
const entryOrdinal = entryPointOf(state);
|
|
3834
3846
|
const entryNumber = entryOrdinal >= 0 && entryOrdinal < numberOfOrdinal.length ? numberOfOrdinal[entryOrdinal] : NO_NUMBER;
|
|
3835
3847
|
const entryHoldsNode = entryNumber !== NO_NUMBER && topLayers[entryNumber] >= 0;
|
|
3836
|
-
|
|
3848
|
+
const header = {
|
|
3837
3849
|
entryPoint: entryHoldsNode ? entryNumber : null,
|
|
3838
3850
|
maxLayer: Math.max(0, Math.min(topLayerOf(state), MAX_LAYER_CAP)),
|
|
3839
3851
|
m: state.M,
|
|
3840
3852
|
efConstruction: state.efCons,
|
|
3841
|
-
metric: state.buildMetric
|
|
3842
|
-
levels,
|
|
3843
|
-
neighbours: littleEndianBytesOf(values.subarray(0, cursor))
|
|
3853
|
+
metric: state.buildMetric
|
|
3844
3854
|
};
|
|
3855
|
+
const numbers = { numberOfOrdinal, ordinalOfNumber, topLayers };
|
|
3856
|
+
const parts = [];
|
|
3857
|
+
for (let start = 0; start < ordinalOfNumber.length; start += partSize) {
|
|
3858
|
+
const end = Math.min(start + partSize, ordinalOfNumber.length);
|
|
3859
|
+
parts.push({ ...header, ...serializePart(state, numbers, start, end) });
|
|
3860
|
+
}
|
|
3861
|
+
return parts;
|
|
3845
3862
|
}
|
|
3846
3863
|
function endsInsideAList() {
|
|
3847
3864
|
throw new NarsilError(
|
|
@@ -3862,95 +3879,78 @@ function requireWholeNeighbourLists(graph) {
|
|
|
3862
3879
|
}
|
|
3863
3880
|
}
|
|
3864
3881
|
}
|
|
3865
|
-
function
|
|
3866
|
-
|
|
3882
|
+
function topLayerInParts(graph, number) {
|
|
3883
|
+
const part = graph.parts[Math.floor(number / graph.partSize)];
|
|
3884
|
+
if (part === void 0) return -1;
|
|
3885
|
+
const at = number % graph.partSize;
|
|
3886
|
+
return at < part.levels.length ? part.levels[at] - 1 : -1;
|
|
3887
|
+
}
|
|
3888
|
+
function highestNodeOrdinal(graph, ordinalAt) {
|
|
3889
|
+
let highest = -1;
|
|
3890
|
+
for (let p = 0; p < graph.parts.length; p++) {
|
|
3891
|
+
const levels = graph.parts[p].levels;
|
|
3892
|
+
for (let at = 0; at < levels.length; at++) {
|
|
3893
|
+
const ordinal = ordinalAt(p * graph.partSize + at);
|
|
3894
|
+
if (levels[at] > 0 && ordinal > highest) highest = ordinal;
|
|
3895
|
+
}
|
|
3896
|
+
}
|
|
3897
|
+
return highest;
|
|
3867
3898
|
}
|
|
3868
3899
|
function deserializeNumberedGraph(state, graph, ordinalOfNumber) {
|
|
3869
|
-
|
|
3900
|
+
for (const part of graph.parts) requireWholeNeighbourLists(part);
|
|
3870
3901
|
resetGraph(state);
|
|
3871
|
-
const values = valuesOf(graph.neighbours);
|
|
3872
3902
|
const ordinalAt = (number) => number < ordinalOfNumber.length ? ordinalOfNumber[number] : NO_ORDINAL;
|
|
3873
|
-
|
|
3874
|
-
for (let number = 0; number < graph.levels.length; number++) {
|
|
3875
|
-
if (graph.levels[number] > 0 && ordinalAt(number) > highestOrdinal) highestOrdinal = ordinalAt(number);
|
|
3876
|
-
}
|
|
3903
|
+
const highestOrdinal = highestNodeOrdinal(graph, ordinalAt);
|
|
3877
3904
|
if (highestOrdinal >= 0) ensureCapacity(state, highestOrdinal + 1);
|
|
3878
3905
|
const kept = [];
|
|
3879
|
-
let cursor = 0;
|
|
3880
3906
|
let highestLayer = -1;
|
|
3881
3907
|
let nodeOnHighestLayer = NO_ORDINAL;
|
|
3882
|
-
for (let
|
|
3883
|
-
const
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
for (let i = 1; i <= count && kept.length < limit; i++) {
|
|
3900
|
-
const neighbour = values[cursor + i];
|
|
3901
|
-
const neighbourOrdinal = ordinalAt(neighbour);
|
|
3902
|
-
if (neighbourOrdinal === NO_ORDINAL || neighbour === number || topLayerIn(graph, neighbour) < layer) continue;
|
|
3903
|
-
if (!kept.includes(neighbourOrdinal)) kept.push(neighbourOrdinal);
|
|
3908
|
+
for (let p = 0; p < graph.parts.length; p++) {
|
|
3909
|
+
const part = graph.parts[p];
|
|
3910
|
+
const values = valuesOf(part.neighbours);
|
|
3911
|
+
let cursor = 0;
|
|
3912
|
+
for (let at = 0; at < part.levels.length; at++) {
|
|
3913
|
+
const number = p * graph.partSize + at;
|
|
3914
|
+
const top = part.levels[at] - 1;
|
|
3915
|
+
if (top < 0) continue;
|
|
3916
|
+
const ordinal = ordinalAt(number);
|
|
3917
|
+
const keptTop = Math.min(top, MAX_LAYER_CAP);
|
|
3918
|
+
if (ordinal !== NO_ORDINAL) {
|
|
3919
|
+
createNode(state.adjacency, ordinal, keptTop);
|
|
3920
|
+
Atomics.add(state.header, GRAPH_NODE_COUNT, 1);
|
|
3921
|
+
if (keptTop > highestLayer) {
|
|
3922
|
+
highestLayer = keptTop;
|
|
3923
|
+
nodeOnHighestLayer = ordinal;
|
|
3924
|
+
}
|
|
3904
3925
|
}
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3926
|
+
for (let layer = 0; layer <= top; layer++) {
|
|
3927
|
+
const count = values[cursor];
|
|
3928
|
+
kept.length = 0;
|
|
3929
|
+
const limit = maxConns(state, layer);
|
|
3930
|
+
for (let i = 1; i <= count && kept.length < limit; i++) {
|
|
3931
|
+
const neighbour = values[cursor + i];
|
|
3932
|
+
const neighbourOrdinal = ordinalAt(neighbour);
|
|
3933
|
+
if (neighbourOrdinal === NO_ORDINAL || neighbour === number) continue;
|
|
3934
|
+
if (topLayerInParts(graph, neighbour) < layer) continue;
|
|
3935
|
+
if (!kept.includes(neighbourOrdinal)) kept.push(neighbourOrdinal);
|
|
3936
|
+
}
|
|
3937
|
+
cursor += count + 1;
|
|
3938
|
+
if (ordinal !== NO_ORDINAL && layer <= keptTop) {
|
|
3939
|
+
replaceNeighbors(state.adjacency, ordinal, layer, kept, kept.length);
|
|
3940
|
+
}
|
|
3908
3941
|
}
|
|
3909
3942
|
}
|
|
3910
3943
|
}
|
|
3911
|
-
const
|
|
3912
|
-
const
|
|
3944
|
+
const first = graph.parts[0];
|
|
3945
|
+
const entryPoint = first === void 0 ? null : first.entryPoint;
|
|
3946
|
+
const entryOrdinal = entryPoint === null ? NO_ORDINAL : ordinalAt(entryPoint);
|
|
3947
|
+
const entryTop = entryPoint === null ? -1 : Math.min(topLayerInParts(graph, entryPoint), MAX_LAYER_CAP);
|
|
3913
3948
|
const entryIsUsable = entryOrdinal !== NO_ORDINAL && entryTop >= 0;
|
|
3914
3949
|
Atomics.store(state.header, GRAPH_ENTRY_POINT, entryIsUsable ? entryOrdinal : nodeOnHighestLayer);
|
|
3915
3950
|
Atomics.store(state.header, GRAPH_TOP_LAYER, entryIsUsable ? entryTop : highestLayer);
|
|
3916
3951
|
}
|
|
3917
3952
|
|
|
3918
3953
|
// src/vector/hnsw/persistence.ts
|
|
3919
|
-
function serializeGraph(state, store) {
|
|
3920
|
-
const nodeArray = [];
|
|
3921
|
-
const slots = adjacencySlots(state.adjacency);
|
|
3922
|
-
for (let ord = 0; ord < slots; ord++) {
|
|
3923
|
-
const maxLayer = nodeMaxLayer(state, ord);
|
|
3924
|
-
if (maxLayer === -1) continue;
|
|
3925
|
-
if (isTombstoned(state, ord)) continue;
|
|
3926
|
-
const docId = store.docIdForOrdinal(ord);
|
|
3927
|
-
if (docId === void 0) continue;
|
|
3928
|
-
const layerConns = [];
|
|
3929
|
-
for (let layer = 0; layer <= maxLayer; layer++) {
|
|
3930
|
-
const liveNeighbors = [];
|
|
3931
|
-
for (const neighborOrd of collectNeighbors(state.adjacency, ord, layer)) {
|
|
3932
|
-
if (isTombstoned(state, neighborOrd)) continue;
|
|
3933
|
-
const neighborDoc = store.docIdForOrdinal(neighborOrd);
|
|
3934
|
-
if (neighborDoc === void 0) continue;
|
|
3935
|
-
liveNeighbors.push(neighborDoc);
|
|
3936
|
-
}
|
|
3937
|
-
if (liveNeighbors.length > 0) {
|
|
3938
|
-
layerConns.push([layer, liveNeighbors]);
|
|
3939
|
-
}
|
|
3940
|
-
}
|
|
3941
|
-
nodeArray.push([docId, maxLayer, layerConns]);
|
|
3942
|
-
}
|
|
3943
|
-
const entryOrd = entryPointOf(state);
|
|
3944
|
-
const entryPoint = entryOrd === -1 ? null : store.docIdForOrdinal(entryOrd) ?? null;
|
|
3945
|
-
return {
|
|
3946
|
-
entryPoint,
|
|
3947
|
-
maxLayer: topLayerOf(state),
|
|
3948
|
-
m: state.M,
|
|
3949
|
-
efConstruction: state.efCons,
|
|
3950
|
-
metric: state.buildMetric,
|
|
3951
|
-
nodes: nodeArray
|
|
3952
|
-
};
|
|
3953
|
-
}
|
|
3954
3954
|
function resolveNodes(state, store, data) {
|
|
3955
3955
|
const nodes = [];
|
|
3956
3956
|
let maxOrd = -1;
|
|
@@ -4186,13 +4186,12 @@ function createHNSWIndex(dimension, store, config, quantizer, handles) {
|
|
|
4186
4186
|
compactTombstones: () => exclusively(() => compactTombstones(state)),
|
|
4187
4187
|
rebuild: () => exclusively(() => rebuild(state)),
|
|
4188
4188
|
exclusively,
|
|
4189
|
-
serialize: () => serializeGraph(state, store),
|
|
4190
4189
|
deserialize: (data) => exclusively(() => deserializeGraph(state, store, data)),
|
|
4191
|
-
serializeNumbered: (numberOfOrdinal, ordinalOfNumber) =>
|
|
4190
|
+
serializeNumbered: (numberOfOrdinal, ordinalOfNumber, partSize) => serializeNumberedGraphParts(state, numberOfOrdinal, ordinalOfNumber, partSize),
|
|
4192
4191
|
deserializeNumbered: (graph, ordinalOfNumber) => exclusively(() => deserializeNumberedGraph(state, graph, ordinalOfNumber)),
|
|
4193
4192
|
exportSnapshot: () => exportSnapshot(state),
|
|
4194
4193
|
restoreSnapshot: (snapshot) => exclusively(() => restoreSnapshot(state, snapshot))
|
|
4195
4194
|
};
|
|
4196
4195
|
}
|
|
4197
4196
|
|
|
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 };
|
|
4197
|
+
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, topLayerInParts };
|