@delali/narsil 0.3.1-next.72 → 0.3.1-next.73
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-CYeAWYxQ.d.ts} +19 -4
- package/dist/{chunk-Y52WZWAU.mjs → chunk-2WLD2NFW.mjs} +4 -4
- package/dist/{chunk-QR4OKRVY.mjs → chunk-3YKWSO54.mjs} +8 -3
- package/dist/{chunk-KZTI25D3.mjs → chunk-4MQ5F4IL.mjs} +1 -1
- package/dist/{chunk-CVPA5Q7R.mjs → chunk-AFKH4ZK3.mjs} +9 -6
- package/dist/{chunk-M6XF5HDE.mjs → chunk-AK3BLGCI.mjs} +141 -11
- package/dist/{chunk-7QMTA7AA.mjs → chunk-CVFAFZSN.mjs} +7771 -4271
- package/dist/{chunk-RV77FR2F.mjs → chunk-I64LXKO3.mjs} +0 -1
- package/dist/{chunk-EDMCZLSJ.mjs → chunk-LPBWCHBE.mjs} +193 -13
- package/dist/{chunk-P2ZZN32C.mjs → chunk-PU43WDY4.mjs} +4 -2
- package/dist/{chunk-HVJYTKK7.mjs → chunk-THMSFOJO.mjs} +365 -774
- package/dist/{chunk-LCCL6EEH.mjs → chunk-WVDFG45M.mjs} +92 -94
- package/dist/{chunk-3HQPUCCT.mjs → chunk-XW25X6AU.mjs} +66 -237
- package/dist/{chunk-2X2ZQOAB.mjs → chunk-ZULSEZCE.mjs} +3 -4
- package/dist/{client-C2TiW29y.d.ts → client-D698E5ge.d.ts} +76 -25
- package/dist/client.d.ts +7 -7
- package/dist/client.mjs +44 -22
- package/dist/{config-BLguB-om.d.ts → config-Bv8etwUZ.d.ts} +10 -3
- package/dist/{config-C7Ip8Ife.d.ts → config-QXU3HMpq.d.ts} +10 -1
- package/dist/direct-executor-5SRDFZAS.mjs +13 -0
- package/dist/distribution/coordinator/etcd.d.ts +27 -14
- package/dist/distribution/coordinator/etcd.mjs +162 -75
- 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 +6 -6
- package/dist/distribution.mjs +637 -366
- package/dist/embeddings/openai.mjs +1 -1
- package/dist/{engine-Dm4446j1.d.ts → engine-D_OzKZ-6.d.ts} +96 -187
- package/dist/index.browser.mjs +7179 -4031
- package/dist/index.d.ts +5 -5
- package/dist/index.mjs +11 -14
- package/dist/{memory-CKHTU1CL.d.ts → memory-B4jMmygw.d.ts} +213 -2
- package/dist/pattern.mjs +1 -1
- package/dist/persistence/durability/checkpoint-worker.d.ts +24 -16
- package/dist/persistence/durability/checkpoint-worker.mjs +22 -16
- package/dist/react.d.ts +6 -6
- package/dist/react.mjs +0 -1
- package/dist/server.d.ts +9 -9
- package/dist/server.mjs +210 -32
- package/dist/{tasks-BECd0b__.d.ts → tasks-DpgCpW1x.d.ts} +3 -3
- package/dist/{thread-IBSIZZ6W.mjs → thread-3LNVA43V.mjs} +79 -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/vector/search-worker.mjs +3 -3
- package/dist/workers/entry.mjs +4 -4
- package/package.json +7 -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
package/dist/server.mjs
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
import { DEFAULT_MAX_RETAINED_TASKS, loadUWebSockets, resolveCors, authorizerFor, createSharedGateBuffer, gateSlotOfWorker, createRouteRunner, corsHeaderReader, createSharedRequestGate, MAIN_THREAD_GATE_SLOT, registerServerRoutes, DEFAULT_MAX_CONCURRENT_TASKS, DEFAULT_MAX_TASK_PAGE_SIZE, DEFAULT_MAX_IMPORT_ERRORS, DEFAULT_MAX_FETCH_DOCUMENTS, DEFAULT_MAX_RESULT_WINDOW, DEFAULT_MAX_CONCURRENT_REQUESTS, DEFAULT_IMPORT_BATCH_SIZE, DEFAULT_MAX_LINE_BYTES, DEFAULT_MAX_IMPORT_BYTES, DEFAULT_MAX_BODY_BYTES, RUNNING_TASK_TTL_MS, DEFAULT_TASK_PAGE_SIZE, TERMINAL_TASK_TTL_MS, TASK_PROGRESS_WRITE_INTERVAL_MS, serializeNarsilError, createVersionHandler, acceptorOf, createDocumentReadHandlers, sendError, respondError, respondJson, MAX_INDEX_TOUCH_INTERVAL_MS, INDEX_TOUCH_INTERVALS_PER_IDLE_TIMEOUT, clearGateSlot, parseJson, validateCreateIndex, rejectInvalid, validateBatch, serializeBatchResult, validateDocumentBody, validateSuggest, validateQuery, parseTaskListQuery, parseJsonOptional, validateRebalance,
|
|
2
|
-
export { ASYNC_IMPORT_CAPABILITY, INDEX_LIFECYCLE_CAPABILITY, REBUILD_ANALYSIS_CAPABILITY, SERVER_CAPABILITIES, TASK_CANCEL_CAPABILITY, TASK_FILTER_CAPABILITY, httpStatusForNarsilError } from './chunk-
|
|
3
|
-
import { validateIndexName } from './chunk-
|
|
4
|
-
import { engineCoreOf, providedDocId, resolveVectorText } from './chunk-
|
|
5
|
-
import './chunk-
|
|
6
|
-
import
|
|
7
|
-
import './chunk-M6XF5HDE.mjs';
|
|
1
|
+
import { DEFAULT_MAX_RETAINED_TASKS, loadUWebSockets, resolveCors, authorizerFor, createSharedGateBuffer, gateSlotOfWorker, createRouteRunner, corsHeaderReader, createSharedRequestGate, MAIN_THREAD_GATE_SLOT, registerServerRoutes, DEFAULT_MAX_CONCURRENT_TASKS, DEFAULT_MAX_TASK_PAGE_SIZE, DEFAULT_MAX_IMPORT_ERRORS, DEFAULT_MAX_FETCH_DOCUMENTS, DEFAULT_MAX_RESULT_WINDOW, DEFAULT_MAX_CONCURRENT_REQUESTS, DEFAULT_IMPORT_BATCH_SIZE, DEFAULT_MAX_LINE_BYTES, DEFAULT_MAX_RESTORE_BYTES, DEFAULT_MAX_IMPORT_BYTES, DEFAULT_MAX_BODY_BYTES, RUNNING_TASK_TTL_MS, DEFAULT_TASK_PAGE_SIZE, TERMINAL_TASK_TTL_MS, TASK_PROGRESS_WRITE_INTERVAL_MS, serializeNarsilError, createVersionHandler, acceptorOf, createDocumentReadHandlers, sendError, respondError, respondJson, MAX_INDEX_TOUCH_INTERVAL_MS, INDEX_TOUCH_INTERVALS_PER_IDLE_TIMEOUT, clearGateSlot, parseJson, validateCreateIndex, rejectInvalid, validateBatch, serializeBatchResult, validateDocumentBody, validateSuggest, validateQuery, parseTaskListQuery, parseJsonOptional, validateRebalance, sendStream, SNAPSHOT_ARCHIVE_CONTENT_TYPE, DOCUMENT_EXPORT_CONTENT_TYPE, IMPORT_FLUSHES_IN_FLIGHT, badRequest, SERVER_CAPABILITIES, toHttpError, RELAY_STREAM_CHUNKS_IN_FLIGHT, MIN_UNBOUNDED_SERVER_LIMIT, MIN_COUNTED_SERVER_LIMIT } from './chunk-LPBWCHBE.mjs';
|
|
2
|
+
export { ASYNC_IMPORT_CAPABILITY, DOCUMENT_EXPORT_CAPABILITY, INDEX_LIFECYCLE_CAPABILITY, REBUILD_ANALYSIS_CAPABILITY, SERVER_CAPABILITIES, TASK_CANCEL_CAPABILITY, TASK_FILTER_CAPABILITY, httpStatusForNarsilError } from './chunk-LPBWCHBE.mjs';
|
|
3
|
+
import { validateIndexName } from './chunk-2WLD2NFW.mjs';
|
|
4
|
+
import { engineCoreOf, providedDocId, resolveVectorText } from './chunk-AFKH4ZK3.mjs';
|
|
5
|
+
import { detectRuntime } from './chunk-4MQ5F4IL.mjs';
|
|
6
|
+
import './chunk-AK3BLGCI.mjs';
|
|
8
7
|
import './chunk-TGP5M5R7.mjs';
|
|
9
|
-
import './chunk-
|
|
8
|
+
import './chunk-PU43WDY4.mjs';
|
|
10
9
|
import './chunk-U2BKYEC7.mjs';
|
|
11
10
|
import './chunk-LJYTW7GT.mjs';
|
|
12
11
|
import { startIdleHeapCleanup } from './chunk-Y3L5MDRV.mjs';
|
|
13
|
-
import { NarsilError, ErrorCodes, ServerErrorCodes, isNarsilError } from './chunk-
|
|
14
|
-
export { ClientErrorCodes, ErrorCodes, NarsilError, ServerErrorCodes, isNarsilError } from './chunk-
|
|
12
|
+
import { NarsilError, ErrorCodes, ServerErrorCodes, isNarsilError } from './chunk-I64LXKO3.mjs';
|
|
13
|
+
export { ClientErrorCodes, ErrorCodes, NarsilError, ServerErrorCodes, isNarsilError } from './chunk-I64LXKO3.mjs';
|
|
15
14
|
import { randomUUID } from 'crypto';
|
|
15
|
+
import { createReadStream } from 'fs';
|
|
16
|
+
import { rm } from 'fs/promises';
|
|
17
|
+
import path from 'path';
|
|
16
18
|
import { MessageChannel } from 'worker_threads';
|
|
17
19
|
|
|
18
|
-
// src/server/handlers/admin.ts
|
|
19
20
|
function createAdminHandlers(deps) {
|
|
20
21
|
const { engine, tasks, limits } = deps;
|
|
21
22
|
async function checkpoint(ctx) {
|
|
@@ -28,9 +29,12 @@ function createAdminHandlers(deps) {
|
|
|
28
29
|
}
|
|
29
30
|
async function snapshot(ctx) {
|
|
30
31
|
try {
|
|
31
|
-
const
|
|
32
|
-
if (ctx.abort.aborted)
|
|
33
|
-
|
|
32
|
+
const archive = await engine.snapshot(ctx.params[0]);
|
|
33
|
+
if (ctx.abort.aborted) {
|
|
34
|
+
await archive.cancel();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
await sendStream(ctx.res, ctx.abort, archive, [["Content-Type", SNAPSHOT_ARCHIVE_CONTENT_TYPE]]);
|
|
34
38
|
} catch (err) {
|
|
35
39
|
respondError(ctx, err);
|
|
36
40
|
}
|
|
@@ -118,15 +122,26 @@ function createAdminHandlers(deps) {
|
|
|
118
122
|
respondJson(ctx, record, 202);
|
|
119
123
|
}
|
|
120
124
|
async function restore(ctx) {
|
|
121
|
-
const
|
|
122
|
-
if (
|
|
125
|
+
const spooled = ctx.spooledBody;
|
|
126
|
+
if (spooled === null || spooled.bytes === 0) {
|
|
127
|
+
await spooled?.remove();
|
|
123
128
|
sendError(ctx.res, 400, ServerErrorCodes.EMPTY_BODY, "Request body is empty");
|
|
124
129
|
return;
|
|
125
130
|
}
|
|
126
131
|
const name = ctx.params[0];
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
132
|
+
try {
|
|
133
|
+
const record = await tasks.start("restore", name, async () => {
|
|
134
|
+
try {
|
|
135
|
+
await engine.restore(name, createReadStream(spooled.path));
|
|
136
|
+
} finally {
|
|
137
|
+
await spooled.remove();
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
respondJson(ctx, record, 202);
|
|
141
|
+
} catch (err) {
|
|
142
|
+
await spooled.remove();
|
|
143
|
+
respondError(ctx, err);
|
|
144
|
+
}
|
|
130
145
|
}
|
|
131
146
|
async function getTask(ctx) {
|
|
132
147
|
const record = await tasks.get(ctx.params[0]);
|
|
@@ -270,6 +285,54 @@ function createClusterHandlers(deps) {
|
|
|
270
285
|
}
|
|
271
286
|
return { topology, allocation };
|
|
272
287
|
}
|
|
288
|
+
function importResultOf(result, maxErrors) {
|
|
289
|
+
const errors = result.refused.slice(0, maxErrors);
|
|
290
|
+
return {
|
|
291
|
+
indexed: result.imported,
|
|
292
|
+
failed: result.refusedCount,
|
|
293
|
+
errors,
|
|
294
|
+
errorsTruncated: result.refusedCount > errors.length
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
function createDocumentExportHandlers(deps) {
|
|
298
|
+
const { engine, tasks, limits } = deps;
|
|
299
|
+
async function exportDocuments(ctx) {
|
|
300
|
+
try {
|
|
301
|
+
const lines = await engine.exportDocuments(ctx.params[0]);
|
|
302
|
+
if (ctx.abort.aborted) {
|
|
303
|
+
await lines.cancel();
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
await sendStream(ctx.res, ctx.abort, lines, [["Content-Type", DOCUMENT_EXPORT_CONTENT_TYPE]]);
|
|
307
|
+
} catch (err) {
|
|
308
|
+
respondError(ctx, err);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
async function importExport(ctx) {
|
|
312
|
+
const spooled = ctx.spooledBody;
|
|
313
|
+
if (spooled === null || spooled.bytes === 0) {
|
|
314
|
+
await spooled?.remove();
|
|
315
|
+
sendError(ctx.res, 400, ServerErrorCodes.EMPTY_BODY, "Request body is empty");
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
const name = ctx.params[0];
|
|
319
|
+
try {
|
|
320
|
+
const record = await tasks.start("importExport", name, async (context) => {
|
|
321
|
+
try {
|
|
322
|
+
const result = await engine.importDocumentExport(name, createReadStream(spooled.path));
|
|
323
|
+
context.reportResult(importResultOf(result, limits.maxImportErrors));
|
|
324
|
+
} finally {
|
|
325
|
+
await spooled.remove();
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
respondJson(ctx, record, 202);
|
|
329
|
+
} catch (err) {
|
|
330
|
+
await spooled.remove();
|
|
331
|
+
respondError(ctx, err);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return { exportDocuments, importExport };
|
|
335
|
+
}
|
|
273
336
|
|
|
274
337
|
// src/server/handlers/documents.ts
|
|
275
338
|
function createDocumentHandlers(deps) {
|
|
@@ -757,6 +820,7 @@ var ENGINE_METHOD_SAMPLE = ["createIndex", "listIndexes", "insert", "query", "ge
|
|
|
757
820
|
var LIMITS_UNBOUNDED_AT_ZERO = [
|
|
758
821
|
"maxBodyBytes",
|
|
759
822
|
"maxImportBytes",
|
|
823
|
+
"maxRestoreBytes",
|
|
760
824
|
"maxLineBytes",
|
|
761
825
|
"maxImportErrors",
|
|
762
826
|
"maxConcurrentRequests",
|
|
@@ -808,10 +872,32 @@ function bodyBytes(body) {
|
|
|
808
872
|
if (typeof body === "string") return Buffer.from(body, "utf8");
|
|
809
873
|
return body;
|
|
810
874
|
}
|
|
811
|
-
function
|
|
875
|
+
function createRelayAbort() {
|
|
876
|
+
const listeners = [];
|
|
877
|
+
let aborted = false;
|
|
878
|
+
return {
|
|
879
|
+
get aborted() {
|
|
880
|
+
return aborted;
|
|
881
|
+
},
|
|
882
|
+
onAbort(fn) {
|
|
883
|
+
if (aborted) fn();
|
|
884
|
+
else listeners.push(fn);
|
|
885
|
+
},
|
|
886
|
+
trigger() {
|
|
887
|
+
if (aborted) return;
|
|
888
|
+
aborted = true;
|
|
889
|
+
for (const fn of listeners) fn();
|
|
890
|
+
}
|
|
891
|
+
};
|
|
892
|
+
}
|
|
893
|
+
function createCapturingResponse(remoteAddress, requestId, sendPart) {
|
|
812
894
|
let status = DEFAULT_STATUS;
|
|
813
895
|
const headers = [];
|
|
814
896
|
let finished = false;
|
|
897
|
+
let streaming = false;
|
|
898
|
+
let inFlight = 0;
|
|
899
|
+
let writable = null;
|
|
900
|
+
const abort = createRelayAbort();
|
|
815
901
|
let resolveDone = () => void 0;
|
|
816
902
|
const done = new Promise((resolve) => {
|
|
817
903
|
resolveDone = resolve;
|
|
@@ -819,25 +905,57 @@ function createCapturingResponse(remoteAddress) {
|
|
|
819
905
|
function finish(body) {
|
|
820
906
|
if (finished) return;
|
|
821
907
|
finished = true;
|
|
908
|
+
if (streaming) {
|
|
909
|
+
sendPart({ type: "stream-end", requestId, failed: false }, []);
|
|
910
|
+
resolveDone(null);
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
822
913
|
resolveDone({ status, headers, body });
|
|
823
914
|
}
|
|
915
|
+
function startStreaming() {
|
|
916
|
+
if (streaming) return;
|
|
917
|
+
streaming = true;
|
|
918
|
+
sendPart({ type: "stream-start", requestId, status, headers }, []);
|
|
919
|
+
}
|
|
824
920
|
const sink = {
|
|
825
921
|
cork(callback) {
|
|
826
922
|
callback();
|
|
827
923
|
return sink;
|
|
828
924
|
},
|
|
829
925
|
writeStatus(line) {
|
|
830
|
-
if (!finished) status = statusOf(line);
|
|
926
|
+
if (!finished && !streaming) status = statusOf(line);
|
|
831
927
|
return sink;
|
|
832
928
|
},
|
|
833
929
|
writeHeader(key, value) {
|
|
834
|
-
if (!finished) headers.push([key, value]);
|
|
930
|
+
if (!finished && !streaming) headers.push([key, value]);
|
|
835
931
|
return sink;
|
|
836
932
|
},
|
|
837
933
|
end(body) {
|
|
838
934
|
finish(bodyBytes(body));
|
|
839
935
|
return sink;
|
|
840
936
|
},
|
|
937
|
+
write(chunk) {
|
|
938
|
+
if (finished || abort.aborted) return true;
|
|
939
|
+
startStreaming();
|
|
940
|
+
const copy = chunk.slice();
|
|
941
|
+
inFlight += 1;
|
|
942
|
+
sendPart({ type: "stream-chunk", requestId, chunk: copy }, [copy.buffer]);
|
|
943
|
+
return inFlight < RELAY_STREAM_CHUNKS_IN_FLIGHT;
|
|
944
|
+
},
|
|
945
|
+
pause: () => void 0,
|
|
946
|
+
resume: () => void 0,
|
|
947
|
+
close() {
|
|
948
|
+
if (finished) return sink;
|
|
949
|
+
finished = true;
|
|
950
|
+
if (streaming) {
|
|
951
|
+
sendPart({ type: "stream-end", requestId, failed: true }, []);
|
|
952
|
+
resolveDone(null);
|
|
953
|
+
} else {
|
|
954
|
+
status = NO_RESPONSE_STATUS;
|
|
955
|
+
resolveDone({ status, headers, body: new Uint8Array(0) });
|
|
956
|
+
}
|
|
957
|
+
return sink;
|
|
958
|
+
},
|
|
841
959
|
endWithoutBody() {
|
|
842
960
|
finish(new Uint8Array(0));
|
|
843
961
|
return sink;
|
|
@@ -847,16 +965,45 @@ function createCapturingResponse(remoteAddress) {
|
|
|
847
965
|
return [true, true];
|
|
848
966
|
},
|
|
849
967
|
getWriteOffset: () => 0,
|
|
850
|
-
onWritable
|
|
968
|
+
onWritable(handler) {
|
|
969
|
+
writable = handler;
|
|
970
|
+
return sink;
|
|
971
|
+
},
|
|
851
972
|
onAborted: () => sink,
|
|
852
973
|
onData: () => sink,
|
|
853
974
|
getRemoteAddressAsText: () => new TextEncoder().encode(remoteAddress).buffer
|
|
854
975
|
};
|
|
855
976
|
return {
|
|
856
977
|
sink,
|
|
978
|
+
abort,
|
|
857
979
|
done,
|
|
980
|
+
credit() {
|
|
981
|
+
inFlight = Math.max(0, inFlight - 1);
|
|
982
|
+
if (inFlight >= RELAY_STREAM_CHUNKS_IN_FLIGHT || writable === null) return;
|
|
983
|
+
const handler = writable;
|
|
984
|
+
writable = null;
|
|
985
|
+
handler(0);
|
|
986
|
+
},
|
|
987
|
+
cancel() {
|
|
988
|
+
abort.trigger();
|
|
989
|
+
if (writable !== null) {
|
|
990
|
+
const handler = writable;
|
|
991
|
+
writable = null;
|
|
992
|
+
handler(0);
|
|
993
|
+
}
|
|
994
|
+
if (!finished) {
|
|
995
|
+
finished = true;
|
|
996
|
+
resolveDone(null);
|
|
997
|
+
}
|
|
998
|
+
},
|
|
858
999
|
finishUnanswered() {
|
|
859
1000
|
if (finished) return;
|
|
1001
|
+
if (streaming) {
|
|
1002
|
+
finished = true;
|
|
1003
|
+
sendPart({ type: "stream-end", requestId, failed: true }, []);
|
|
1004
|
+
resolveDone(null);
|
|
1005
|
+
return;
|
|
1006
|
+
}
|
|
860
1007
|
status = NO_RESPONSE_STATUS;
|
|
861
1008
|
finish(new Uint8Array(0));
|
|
862
1009
|
}
|
|
@@ -867,22 +1014,36 @@ function toRelayedResponse(requestId, captured) {
|
|
|
867
1014
|
}
|
|
868
1015
|
|
|
869
1016
|
// src/server/request-threads/host.ts
|
|
870
|
-
var
|
|
1017
|
+
var RELAYED_TYPES = /* @__PURE__ */ new Set(["request", "authorize", "embed", "stream-credit", "stream-cancel"]);
|
|
871
1018
|
function isRelayRequest(message) {
|
|
872
1019
|
if (typeof message !== "object" || message === null) return false;
|
|
873
1020
|
const { type, requestId } = message;
|
|
874
1021
|
if (type === "touch") return true;
|
|
875
|
-
return typeof requestId === "number" &&
|
|
1022
|
+
return typeof requestId === "number" && typeof type === "string" && RELAYED_TYPES.has(type);
|
|
876
1023
|
}
|
|
877
|
-
|
|
878
|
-
|
|
1024
|
+
function spooledBodyOf(relayed) {
|
|
1025
|
+
if (relayed === null) return null;
|
|
1026
|
+
return {
|
|
1027
|
+
path: relayed.path,
|
|
1028
|
+
bytes: relayed.bytes,
|
|
1029
|
+
remove: () => rm(path.dirname(relayed.path), { recursive: true, force: true })
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
async function answerRequest(handlers, request, port, streams) {
|
|
1033
|
+
const captured = createCapturingResponse(
|
|
1034
|
+
request.hookContext?.remoteAddress ?? "",
|
|
1035
|
+
request.requestId,
|
|
1036
|
+
(part, moved) => port.postMessage(part, moved)
|
|
1037
|
+
);
|
|
1038
|
+
streams.set(request.requestId, captured);
|
|
879
1039
|
const ctx = {
|
|
880
1040
|
res: captured.sink,
|
|
881
1041
|
params: request.params,
|
|
882
1042
|
query: new URLSearchParams(request.query),
|
|
883
1043
|
contentType: request.contentType,
|
|
884
1044
|
rawBody: request.rawBody === null ? null : Buffer.from(request.rawBody.buffer, request.rawBody.byteOffset, request.rawBody.byteLength),
|
|
885
|
-
|
|
1045
|
+
spooledBody: spooledBodyOf(request.spooledBody),
|
|
1046
|
+
abort: captured.abort,
|
|
886
1047
|
hookContext: request.hookContext
|
|
887
1048
|
};
|
|
888
1049
|
try {
|
|
@@ -891,7 +1052,9 @@ async function answerRequest(handlers, request) {
|
|
|
891
1052
|
sendError(ctx.res, 500, ServerErrorCodes.INTERNAL_ERROR, "An unexpected error occurred");
|
|
892
1053
|
}
|
|
893
1054
|
captured.finishUnanswered();
|
|
894
|
-
|
|
1055
|
+
const answered = await captured.done;
|
|
1056
|
+
streams.delete(request.requestId);
|
|
1057
|
+
return answered === null ? null : toRelayedResponse(request.requestId, answered);
|
|
895
1058
|
}
|
|
896
1059
|
async function answerAuthorize(authorize, request) {
|
|
897
1060
|
if (authorize === void 0) {
|
|
@@ -942,14 +1105,25 @@ async function startRequestThreads(options) {
|
|
|
942
1105
|
const threads = /* @__PURE__ */ new Map();
|
|
943
1106
|
let stopped = false;
|
|
944
1107
|
function relayFrom(port) {
|
|
1108
|
+
const streams = /* @__PURE__ */ new Map();
|
|
945
1109
|
port.on("message", (message) => {
|
|
946
1110
|
if (!isRelayRequest(message)) return;
|
|
947
1111
|
if (message.type === "touch") {
|
|
948
1112
|
core.orchestrator.noteAccess(message.indexName);
|
|
949
1113
|
return;
|
|
950
1114
|
}
|
|
951
|
-
|
|
952
|
-
|
|
1115
|
+
if (message.type === "stream-credit") {
|
|
1116
|
+
streams.get(message.requestId)?.credit();
|
|
1117
|
+
return;
|
|
1118
|
+
}
|
|
1119
|
+
if (message.type === "stream-cancel") {
|
|
1120
|
+
streams.get(message.requestId)?.cancel();
|
|
1121
|
+
return;
|
|
1122
|
+
}
|
|
1123
|
+
const reply = message.type === "request" ? answerRequest(handlers, message, port, streams) : message.type === "authorize" ? answerAuthorize(authorize, message) : answerEmbed(core, message);
|
|
1124
|
+
void reply.then((answer) => {
|
|
1125
|
+
if (answer !== null) port.postMessage(answer);
|
|
1126
|
+
});
|
|
953
1127
|
});
|
|
954
1128
|
}
|
|
955
1129
|
async function stopThread(workerId, thread) {
|
|
@@ -1254,6 +1428,7 @@ function resolveLimits(limits) {
|
|
|
1254
1428
|
return {
|
|
1255
1429
|
maxBodyBytes: limits?.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES,
|
|
1256
1430
|
maxImportBytes: limits?.maxImportBytes ?? DEFAULT_MAX_IMPORT_BYTES,
|
|
1431
|
+
maxRestoreBytes: limits?.maxRestoreBytes ?? DEFAULT_MAX_RESTORE_BYTES,
|
|
1257
1432
|
maxLineBytes: limits?.maxLineBytes ?? DEFAULT_MAX_LINE_BYTES,
|
|
1258
1433
|
importBatchSize: limits?.importBatchSize ?? DEFAULT_IMPORT_BATCH_SIZE,
|
|
1259
1434
|
maxConcurrentRequests: limits?.maxConcurrentRequests ?? DEFAULT_MAX_CONCURRENT_REQUESTS,
|
|
@@ -1287,6 +1462,7 @@ function mainThreadHandlers(deps) {
|
|
|
1287
1462
|
const doc = createDocumentHandlers(deps);
|
|
1288
1463
|
const search = createSearchHandlers(deps);
|
|
1289
1464
|
const admin = createAdminHandlers(deps);
|
|
1465
|
+
const documentExport = createDocumentExportHandlers(deps);
|
|
1290
1466
|
const health = createHealthHandlers(deps);
|
|
1291
1467
|
const cluster = createClusterHandlers(deps);
|
|
1292
1468
|
const version = createVersionHandler(deps);
|
|
@@ -1333,7 +1509,9 @@ function mainThreadHandlers(deps) {
|
|
|
1333
1509
|
optimize: admin.optimize,
|
|
1334
1510
|
rebalance: admin.rebalance,
|
|
1335
1511
|
partitionConfig: admin.partitionConfig,
|
|
1336
|
-
restore: admin.restore
|
|
1512
|
+
restore: admin.restore,
|
|
1513
|
+
exportDocuments: documentExport.exportDocuments,
|
|
1514
|
+
importExport: documentExport.importExport
|
|
1337
1515
|
};
|
|
1338
1516
|
}
|
|
1339
1517
|
var NarsilHttpServer = class {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { M as MemoryStats } from './memory-
|
|
1
|
+
import { M as MemoryStats } from './memory-B4jMmygw.js';
|
|
2
2
|
|
|
3
3
|
/** Declarative index configuration accepted over HTTP. Function-valued engine
|
|
4
4
|
* options (custom tokenizer, stopWords-as-function, group reducer, embedding
|
|
@@ -142,7 +142,7 @@ interface MemoryStatsResponse extends MemoryStats {
|
|
|
142
142
|
*
|
|
143
143
|
* @public
|
|
144
144
|
*/
|
|
145
|
-
type TaskType = 'optimizeVectors' | 'rebalance' | 'restore' | 'import' | 'rebuildAnalysis';
|
|
145
|
+
type TaskType = 'optimizeVectors' | 'rebalance' | 'restore' | 'import' | 'importExport' | 'rebuildAnalysis';
|
|
146
146
|
/**
|
|
147
147
|
* Where a long-running operation stands.
|
|
148
148
|
*
|
|
@@ -207,7 +207,7 @@ interface TaskRecord {
|
|
|
207
207
|
cancelRequestedAt?: number;
|
|
208
208
|
/** How far the work has gone, which an import reports and other task types omit. */
|
|
209
209
|
progress?: TaskProgress;
|
|
210
|
-
/** What the work produced, which an import reports once it finishes. */
|
|
210
|
+
/** What the work produced, which an `import` or `importExport` task reports once it finishes. */
|
|
211
211
|
result?: ImportResult;
|
|
212
212
|
/** This says why the task failed, and a failed task alone carries it. */
|
|
213
213
|
error?: {
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import { loadUWebSockets, childAppOf, createRouteRunner, corsHeaderReader, createSharedRequestGate, registerServerRoutes, sendRelayed, createDocumentReadHandlers, respondJson, SERVER_CAPABILITIES, versionReport, sendError, serverRoutes, parseJson, validateSuggest, rejectInvalid, respondError, validateQuery } from './chunk-
|
|
2
|
-
import { executeListDocuments, executeSuggest, executePreflight, queryBindingOf, executeQuery } from './chunk-
|
|
3
|
-
import './chunk-
|
|
4
|
-
import {
|
|
5
|
-
import { extractVectorFieldsFromSchema } from './chunk-M6XF5HDE.mjs';
|
|
1
|
+
import { loadUWebSockets, childAppOf, createRouteRunner, corsHeaderReader, createSharedRequestGate, registerServerRoutes, sendRelayed, createDocumentReadHandlers, respondJson, SERVER_CAPABILITIES, versionReport, statusLine, sendError, serverRoutes, parseJson, validateSuggest, rejectInvalid, respondError, validateQuery } from './chunk-LPBWCHBE.mjs';
|
|
2
|
+
import { executeListDocuments, executeSuggest, executePreflight, queryBindingOf, executeQuery } from './chunk-ZULSEZCE.mjs';
|
|
3
|
+
import { resolveProjection, projectionKeepsField, setNestedValue } from './chunk-3YKWSO54.mjs';
|
|
4
|
+
import { extractVectorFieldsFromSchema } from './chunk-AK3BLGCI.mjs';
|
|
6
5
|
import './chunk-ZJ4CSAB2.mjs';
|
|
7
|
-
import './chunk-
|
|
6
|
+
import './chunk-PU43WDY4.mjs';
|
|
8
7
|
import './chunk-ZKRV5M2P.mjs';
|
|
9
8
|
import './chunk-LJYTW7GT.mjs';
|
|
10
|
-
import { ServerErrorCodes, NarsilError, ErrorCodes } from './chunk-
|
|
9
|
+
import { ServerErrorCodes, NarsilError, ErrorCodes } from './chunk-I64LXKO3.mjs';
|
|
11
10
|
|
|
12
11
|
// src/server/request-threads/held-vectors.ts
|
|
13
12
|
function managerWithHeldVectors(manager, fieldPaths, vectorOf) {
|
|
@@ -173,6 +172,46 @@ function isRelayReply(message) {
|
|
|
173
172
|
const { type, requestId } = message;
|
|
174
173
|
return typeof requestId === "number" && (type === "response" || type === "authorized" || type === "embedded");
|
|
175
174
|
}
|
|
175
|
+
function isStreamPart(message) {
|
|
176
|
+
if (typeof message !== "object" || message === null) return false;
|
|
177
|
+
const { type, requestId } = message;
|
|
178
|
+
return typeof requestId === "number" && (type === "stream-start" || type === "stream-chunk" || type === "stream-end");
|
|
179
|
+
}
|
|
180
|
+
function writeStreamPart(port, writer, part) {
|
|
181
|
+
const { ctx } = writer;
|
|
182
|
+
if (part.type === "stream-end") {
|
|
183
|
+
if (!ctx.abort.aborted) {
|
|
184
|
+
ctx.res.cork(() => {
|
|
185
|
+
if (part.failed) ctx.res.close();
|
|
186
|
+
else ctx.res.end();
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
writer.finish();
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (ctx.abort.aborted) return;
|
|
193
|
+
if (part.type === "stream-start") {
|
|
194
|
+
writer.started = true;
|
|
195
|
+
ctx.res.cork(() => {
|
|
196
|
+
ctx.res.writeStatus(statusLine(part.status));
|
|
197
|
+
for (const [key, value] of part.headers) ctx.res.writeHeader(key, value);
|
|
198
|
+
});
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
let writable = true;
|
|
202
|
+
ctx.res.cork(() => {
|
|
203
|
+
writable = ctx.res.write(part.chunk);
|
|
204
|
+
});
|
|
205
|
+
const credit = () => port.postMessage({ type: "stream-credit", requestId: part.requestId });
|
|
206
|
+
if (writable) {
|
|
207
|
+
credit();
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
ctx.res.onWritable(() => {
|
|
211
|
+
credit();
|
|
212
|
+
return true;
|
|
213
|
+
});
|
|
214
|
+
}
|
|
176
215
|
function errorOf(reply) {
|
|
177
216
|
const error = reply.error ?? { code: ErrorCodes.EMBEDDING_FAILED, message: "The main thread returned no vector" };
|
|
178
217
|
return new NarsilError(error.code, error.message, error.details);
|
|
@@ -205,11 +244,18 @@ function createRelayClient(port, touchIntervalMs) {
|
|
|
205
244
|
pending.clear();
|
|
206
245
|
for (const entry of waiting) entry.reject(portClosedError());
|
|
207
246
|
}
|
|
247
|
+
const writers = /* @__PURE__ */ new Map();
|
|
208
248
|
port.on("message", (message) => {
|
|
249
|
+
if (isStreamPart(message)) {
|
|
250
|
+
const writer = writers.get(message.requestId);
|
|
251
|
+
if (writer !== void 0) writeStreamPart(port, writer, message);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
209
254
|
if (!isRelayReply(message)) return;
|
|
210
255
|
const waiting = pending.get(message.requestId);
|
|
211
256
|
if (waiting === void 0) return;
|
|
212
257
|
pending.delete(message.requestId);
|
|
258
|
+
writers.delete(message.requestId);
|
|
213
259
|
waiting.resolve(message);
|
|
214
260
|
});
|
|
215
261
|
port.on("close", failAll);
|
|
@@ -244,24 +290,36 @@ function createRelayClient(port, touchIntervalMs) {
|
|
|
244
290
|
let reply;
|
|
245
291
|
const body = relayedBody(ctx.rawBody);
|
|
246
292
|
try {
|
|
247
|
-
reply = await
|
|
248
|
-
(requestId) =>
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
293
|
+
reply = await new Promise((resolve, reject) => {
|
|
294
|
+
void send((requestId) => {
|
|
295
|
+
writers.set(requestId, {
|
|
296
|
+
ctx,
|
|
297
|
+
started: false,
|
|
298
|
+
finish: () => {
|
|
299
|
+
writers.delete(requestId);
|
|
300
|
+
pending.delete(requestId);
|
|
301
|
+
resolve(null);
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
ctx.abort.onAbort(() => port.postMessage({ type: "stream-cancel", requestId }));
|
|
305
|
+
return {
|
|
306
|
+
type: "request",
|
|
307
|
+
requestId,
|
|
308
|
+
route,
|
|
309
|
+
params: ctx.params,
|
|
310
|
+
query: ctx.query.toString(),
|
|
311
|
+
contentType: ctx.contentType,
|
|
312
|
+
rawBody: body.bytes,
|
|
313
|
+
spooledBody: ctx.spooledBody === null ? null : { path: ctx.spooledBody.path, bytes: ctx.spooledBody.bytes },
|
|
314
|
+
hookContext: ctx.hookContext
|
|
315
|
+
};
|
|
316
|
+
}, body.moved).then(resolve, reject);
|
|
317
|
+
});
|
|
260
318
|
} catch {
|
|
261
319
|
if (!ctx.abort.aborted) sendUnavailable(ctx.res);
|
|
262
320
|
return;
|
|
263
321
|
}
|
|
264
|
-
if (reply.type !== "response" || ctx.abort.aborted) return;
|
|
322
|
+
if (reply === null || reply.type !== "response" || ctx.abort.aborted) return;
|
|
265
323
|
sendRelayed(ctx.res, ctx.abort, reply.status, reply.headers, reply.body);
|
|
266
324
|
},
|
|
267
325
|
async embed(indexName, vector) {
|
|
@@ -31,7 +31,7 @@ interface TransportConfig {
|
|
|
31
31
|
requestTimeout: number;
|
|
32
32
|
/** A replication entry may take this long to reach a replica and come back acknowledged. */
|
|
33
33
|
replicationTimeout: number;
|
|
34
|
-
/** A
|
|
34
|
+
/** A node waits this long for each next chunk of a snapshot transfer, which moves a partition or an index between nodes, so that the node can receive a transfer of any size while the sender keeps sending. */
|
|
35
35
|
snapshotTimeout: number;
|
|
36
36
|
}
|
|
37
37
|
/**
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { openSharedVectorField, MAX_WORKER_COPIES, createVectorStore, osqBitsOf, createHNSWIndex, createOsqQuantizer, osqRecordBytes } from '../chunk-
|
|
1
|
+
import { openSharedVectorField, MAX_WORKER_COPIES, createVectorStore, osqBitsOf, createHNSWIndex, createOsqQuantizer, osqRecordBytes } from '../chunk-WVDFG45M.mjs';
|
|
2
2
|
import '../chunk-ZJ4CSAB2.mjs';
|
|
3
|
-
import '../chunk-
|
|
3
|
+
import '../chunk-PU43WDY4.mjs';
|
|
4
4
|
import '../chunk-LJYTW7GT.mjs';
|
|
5
|
-
import '../chunk-
|
|
5
|
+
import '../chunk-I64LXKO3.mjs';
|
|
6
6
|
|
|
7
7
|
// src/vector/worker-copy.ts
|
|
8
8
|
function restoreQuantizer(snapshot, store) {
|
package/dist/workers/entry.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { startIdleHeapCleanup } from '../chunk-Y3L5MDRV.mjs';
|
|
2
2
|
import { threadSlotOfWorker, isValidWorkerAction } from '../chunk-POWOTUKJ.mjs';
|
|
3
|
-
import { ErrorCodes, NarsilError, isNarsilError } from '../chunk-
|
|
3
|
+
import { ErrorCodes, NarsilError, isNarsilError } from '../chunk-I64LXKO3.mjs';
|
|
4
4
|
|
|
5
5
|
// src/workers/action-handler.ts
|
|
6
6
|
function buildErrorResponse(requestId, code, message, details) {
|
|
@@ -18,7 +18,7 @@ async function importBootstrapModule(moduleUrl) {
|
|
|
18
18
|
await import(moduleUrl);
|
|
19
19
|
}
|
|
20
20
|
async function stopServingRequests() {
|
|
21
|
-
const { closeRequestThread } = await import('../thread-
|
|
21
|
+
const { closeRequestThread } = await import('../thread-3LNVA43V.mjs');
|
|
22
22
|
closeRequestThread();
|
|
23
23
|
}
|
|
24
24
|
function holdsCopies(executor) {
|
|
@@ -49,7 +49,7 @@ function createActionHandler(executor) {
|
|
|
49
49
|
if (!holdsCopies(executor)) {
|
|
50
50
|
throw new NarsilError(ErrorCodes.CONFIG_INVALID, "This executor holds no copies to answer requests from");
|
|
51
51
|
}
|
|
52
|
-
const starting = import('../thread-
|
|
52
|
+
const starting = import('../thread-3LNVA43V.mjs').then(
|
|
53
53
|
({ serveRequests }) => serveRequests(executor, action.settings)
|
|
54
54
|
);
|
|
55
55
|
serving.start = starting.then(
|
|
@@ -102,7 +102,7 @@ async function setup() {
|
|
|
102
102
|
} catch {
|
|
103
103
|
parentPort = null;
|
|
104
104
|
}
|
|
105
|
-
const { createDirectExecutor } = await import('../direct-executor-
|
|
105
|
+
const { createDirectExecutor } = await import('../direct-executor-5SRDFZAS.mjs');
|
|
106
106
|
const handleAction = createActionHandler(createDirectExecutor({ threadSlot }));
|
|
107
107
|
if (parentPort) {
|
|
108
108
|
const port = parentPort;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@delali/narsil",
|
|
3
|
-
"version": "0.3.1-next.
|
|
3
|
+
"version": "0.3.1-next.73",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Distributed search engine with full-text, vector, hybrid, and geosearch. One engine, embedded or on a server, with a cross-language .nrsl format.",
|
|
6
6
|
"author": "Delali (https://sondelali.com)",
|
|
@@ -231,11 +231,11 @@
|
|
|
231
231
|
}
|
|
232
232
|
},
|
|
233
233
|
"optionalDependencies": {
|
|
234
|
-
"@delali/narsil-native-darwin-arm64": "0.3.1-next.
|
|
235
|
-
"@delali/narsil-native-darwin-x64": "0.3.1-next.
|
|
236
|
-
"@delali/narsil-native-linux-arm64": "0.3.1-next.
|
|
237
|
-
"@delali/narsil-native-linux-x64": "0.3.1-next.
|
|
238
|
-
"@delali/narsil-native-win32-arm64": "0.3.1-next.
|
|
239
|
-
"@delali/narsil-native-win32-x64": "0.3.1-next.
|
|
234
|
+
"@delali/narsil-native-darwin-arm64": "0.3.1-next.73",
|
|
235
|
+
"@delali/narsil-native-darwin-x64": "0.3.1-next.73",
|
|
236
|
+
"@delali/narsil-native-linux-arm64": "0.3.1-next.73",
|
|
237
|
+
"@delali/narsil-native-linux-x64": "0.3.1-next.73",
|
|
238
|
+
"@delali/narsil-native-win32-arm64": "0.3.1-next.73",
|
|
239
|
+
"@delali/narsil-native-win32-x64": "0.3.1-next.73"
|
|
240
240
|
}
|
|
241
241
|
}
|