@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/README.md
CHANGED
|
@@ -106,7 +106,7 @@ Every hit holds the document, its id, and its BM25 score. Beside the hits, `resu
|
|
|
106
106
|
|
|
107
107
|
**Geosearch.** [Geo filters](https://github.com/assetcorp/narsil/blob/main/docs/geosearch.md) match documents by radius, using Haversine or Vincenty distance, or by polygon containment. You can combine a geo filter with every other query feature.
|
|
108
108
|
|
|
109
|
-
**Storage.** [Persistence adapters](https://github.com/assetcorp/narsil/blob/main/docs/persistence-and-durability.md) store indexes on the filesystem, in IndexedDB, in memory, or in a backend of your own. With durability on, the engine keeps a write-ahead log with periodic checkpoints and recovers on its own after a crash.
|
|
109
|
+
**Storage.** [Persistence adapters](https://github.com/assetcorp/narsil/blob/main/docs/persistence-and-durability.md) store indexes on the filesystem, in IndexedDB, in memory, or in a backend of your own. With durability on, the engine keeps a write-ahead log with periodic checkpoints and recovers on its own after a crash. You can stream a whole index into a portable snapshot archive, or export its documents as JSON Lines to move the index across releases.
|
|
110
110
|
|
|
111
111
|
**Scale.** The engine routes each document to a [partition](https://github.com/assetcorp/narsil/blob/main/docs/partitions-and-workers.md) by a deterministic hash. When you call `rebalance()`, the engine reshapes the partitions online and buffers incoming writes in a write-ahead queue. Once an index holds 1,000 documents, the engine serves keyword queries from worker copies on half its worker threads, while the HTTP server receives requests on the threads that hold those copies.
|
|
112
112
|
|
|
@@ -124,7 +124,7 @@ Every hit holds the document, its id, and its BM25 score. Beside the hits, `resu
|
|
|
124
124
|
| [Hybrid search](https://github.com/assetcorp/narsil/blob/main/docs/hybrid-search.md) | Reciprocal rank fusion and linear blending of text and vector rankings |
|
|
125
125
|
| [Geosearch](https://github.com/assetcorp/narsil/blob/main/docs/geosearch.md) | Radius and polygon filters, and the two distance formulas |
|
|
126
126
|
| [Embedding adapters](https://github.com/assetcorp/narsil/blob/main/docs/embedding-adapters.md) | Automatic embedding on insert and query, named adapters, the bundled ones, and custom ones |
|
|
127
|
-
| [Persistence and durability](https://github.com/assetcorp/narsil/blob/main/docs/persistence-and-durability.md) | Storage backends, the write-ahead log, checkpoints, recovery, and
|
|
127
|
+
| [Persistence and durability](https://github.com/assetcorp/narsil/blob/main/docs/persistence-and-durability.md) | Storage backends, the write-ahead log, checkpoints, recovery, snapshots, document exports, and indexes from an earlier release |
|
|
128
128
|
| [Partitions and workers](https://github.com/assetcorp/narsil/blob/main/docs/partitions-and-workers.md) | Partition routing, online rebalancing, worker copies, and multi-instance invalidation |
|
|
129
129
|
| [Language support](https://github.com/assetcorp/narsil/blob/main/docs/language-support.md) | The 107 language modules, analysis revisions and rebuilds, and named tokenizers and stop words |
|
|
130
130
|
| [HTTP server](https://github.com/assetcorp/narsil/blob/main/docs/http-server.md) | Wrapping an engine in a REST API, every route it serves, and long-running tasks |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { E as EmbeddingAdapter } from './adapters-79OIa4xm.js';
|
|
2
|
-
import { C as ClusterNamespace } from './config-
|
|
3
|
-
import { h as TaskStore } from './tasks-
|
|
2
|
+
import { C as ClusterNamespace } from './config-Bv8etwUZ.js';
|
|
3
|
+
import { h as TaskStore } from './tasks-DpgCpW1x.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Context handed to {@link OnRequestHook} for every inbound request, captured
|
|
@@ -70,8 +70,15 @@ interface CorsOptions {
|
|
|
70
70
|
interface ServerLimits {
|
|
71
71
|
/** Cap for JSON request bodies (single doc, batch, search). Excess → 413. */
|
|
72
72
|
maxBodyBytes?: number;
|
|
73
|
-
/** Cap for the NDJSON import stream
|
|
73
|
+
/** Cap for the NDJSON import stream. Excess → 413. */
|
|
74
74
|
maxImportBytes?: number;
|
|
75
|
+
/** The server accepts a snapshot archive for `POST /indexes/{name}/restore`
|
|
76
|
+
* and a document export for `POST /indexes/{name}/import` of up to this many
|
|
77
|
+
* bytes, and it answers a larger upload with 413. The server writes each
|
|
78
|
+
* upload to a temporary file as the upload arrives, so it needs the same
|
|
79
|
+
* memory for an upload of any size. The default is 64 GiB, and 0 accepts an
|
|
80
|
+
* upload of any size. */
|
|
81
|
+
maxRestoreBytes?: number;
|
|
75
82
|
/** Cap for a single NDJSON line, so one unterminated line cannot exhaust memory. Excess → 413. */
|
|
76
83
|
maxLineBytes?: number;
|
|
77
84
|
/** Documents handed to the engine per batch during NDJSON import; the loop yields between batches. */
|
|
@@ -255,6 +262,14 @@ declare const REBUILD_ANALYSIS_CAPABILITY = "indexes.rebuildAnalysis";
|
|
|
255
262
|
* @public
|
|
256
263
|
*/
|
|
257
264
|
declare const INDEX_LIFECYCLE_CAPABILITY = "indexes.lifecycle";
|
|
265
|
+
/**
|
|
266
|
+
* Marks a server that answers `GET /indexes/{name}/export` with a stream of a
|
|
267
|
+
* document export and imports an export sent to `POST /indexes/{name}/import`
|
|
268
|
+
* in a task.
|
|
269
|
+
*
|
|
270
|
+
* @public
|
|
271
|
+
*/
|
|
272
|
+
declare const DOCUMENT_EXPORT_CAPABILITY = "indexes.documentExport";
|
|
258
273
|
/**
|
|
259
274
|
* Every capability this server announces at `/capabilities`.
|
|
260
275
|
*
|
|
@@ -266,4 +281,4 @@ declare const INDEX_LIFECYCLE_CAPABILITY = "indexes.lifecycle";
|
|
|
266
281
|
*/
|
|
267
282
|
declare const SERVER_CAPABILITIES: readonly string[];
|
|
268
283
|
|
|
269
|
-
export { ASYNC_IMPORT_CAPABILITY as A, type CorsOptions as C, type ErrorEnvelope as E, INDEX_LIFECYCLE_CAPABILITY as I, type NarsilServer as N, type OnRequestHook as O, REBUILD_ANALYSIS_CAPABILITY as R, SERVER_CAPABILITIES as S, TASK_CANCEL_CAPABILITY as T, TASK_FILTER_CAPABILITY as a, type ServerOptions as b, type RequestContext as c, type RequestDenial as d, type ServerLimits as e };
|
|
284
|
+
export { ASYNC_IMPORT_CAPABILITY as A, type CorsOptions as C, DOCUMENT_EXPORT_CAPABILITY as D, type ErrorEnvelope as E, INDEX_LIFECYCLE_CAPABILITY as I, type NarsilServer as N, type OnRequestHook as O, REBUILD_ANALYSIS_CAPABILITY as R, SERVER_CAPABILITIES as S, TASK_CANCEL_CAPABILITY as T, TASK_FILTER_CAPABILITY as a, type ServerOptions as b, type RequestContext as c, type RequestDenial as d, type ServerLimits as e };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { readSharedConfigFields, restoredEmbedding, restoredPartitionConfig, MAX_PARTITION_COUNT, MAX_REPLICATION_FACTOR } from './chunk-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { readSharedConfigFields, restoredEmbedding, restoredPartitionConfig, MAX_PARTITION_COUNT, MAX_REPLICATION_FACTOR } from './chunk-AFKH4ZK3.mjs';
|
|
2
|
+
import { getLanguage } from './chunk-4MQ5F4IL.mjs';
|
|
3
|
+
import { MAX_INDEX_NAME_LENGTH, INDEX_NAME_PATTERN } from './chunk-AK3BLGCI.mjs';
|
|
4
4
|
import { compareCodePoints } from './chunk-LJYTW7GT.mjs';
|
|
5
|
-
import { NarsilError, ErrorCodes } from './chunk-
|
|
5
|
+
import { NarsilError, ErrorCodes } from './chunk-I64LXKO3.mjs';
|
|
6
6
|
import { encode, decode } from '@msgpack/msgpack';
|
|
7
7
|
|
|
8
8
|
// src/distribution/cluster/index-settings.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { isWordIndexedBase, flattenSchema, MAX_LATITUDE_DEGREES, MAX_LONGITUDE_DEGREES, MIN_POLYGON_POINTS, parsedTypeOf, isStringValuedBase, withSortableOption, isGeopointOrVectorType, MAX_SORT_FIELDS, MAX_SORT_FIELD_NAME_LENGTH, MAX_CURSOR_LENGTH, MAX_CURSOR_ANCHOR_CODE_POINTS, RESULT_WINDOW, DEFAULT_FUZZY_PREFIX_LENGTH, EARTH_RADIUS_METERS, RADIUS_BOX_MARGIN_RATIO, RADIUS_BOX_MARGIN_RADIANS, FULL_TURN_DEGREES, ANTIMERIDIAN_SPAN_DEGREES, DEFAULT_PAGE_SIZE, PROTOTYPE_POLLUTION_KEYS, DEG_TO_RAD, LOCATION_CODE_BITS_PER_AXIS, isLatitude, isLongitude, isWordIndexedFieldType, PREFIX_MAX_EXPANSIONS, MAX_COVERING_CELLS } from './chunk-
|
|
1
|
+
import { isWordIndexedBase, flattenSchema, MAX_LATITUDE_DEGREES, MAX_LONGITUDE_DEGREES, MIN_POLYGON_POINTS, parsedTypeOf, isStringValuedBase, withSortableOption, isGeopointOrVectorType, MAX_SORT_FIELDS, MAX_SORT_FIELD_NAME_LENGTH, MAX_CURSOR_LENGTH, MAX_CURSOR_ANCHOR_CODE_POINTS, RESULT_WINDOW, DEFAULT_FUZZY_PREFIX_LENGTH, EARTH_RADIUS_METERS, RADIUS_BOX_MARGIN_RATIO, RADIUS_BOX_MARGIN_RADIANS, FULL_TURN_DEGREES, ANTIMERIDIAN_SPAN_DEGREES, DEFAULT_PAGE_SIZE, PROTOTYPE_POLLUTION_KEYS, DEG_TO_RAD, LOCATION_CODE_BITS_PER_AXIS, isLatitude, isLongitude, isWordIndexedFieldType, PREFIX_MAX_EXPANSIONS, MAX_COVERING_CELLS } from './chunk-AK3BLGCI.mjs';
|
|
2
2
|
import { DEFAULT_PATTERN_WORK_CAP, PATTERN_TEST_OPERATORS, bitsetIsEmpty, MAX_PATTERN_TEXT_CODE_POINTS, MAX_PATTERN_POSITIONS, createBitSet, bitsetSet, PATTERN_WORK_FLUSH_UNITS, MATCHER_STATE_BUDGET_BYTES } from './chunk-ZKRV5M2P.mjs';
|
|
3
3
|
import { compareCodePoints, sortModeOf, defaultSortMode, SORT_VALUE_MAX_CODE_POINTS, toReducedSortValue, readSortField, compareComparableKeys, toComparableSortValue, exceedsCodePoints, holdsUnpairedSurrogate, isSortMode, SORT_MODES, compareSortValues, foldedCodePointCount } from './chunk-LJYTW7GT.mjs';
|
|
4
|
-
import { createNarsilError, ErrorCodes, NarsilError } from './chunk-
|
|
4
|
+
import { createNarsilError, ErrorCodes, NarsilError } from './chunk-I64LXKO3.mjs';
|
|
5
5
|
|
|
6
6
|
// src/core/tokenizer/constants.ts
|
|
7
7
|
var TOKEN_CACHE_SIZE_FLOOR = 5e4;
|
|
@@ -777,6 +777,7 @@ function getOrCreateFieldNameIndex(table, fieldName) {
|
|
|
777
777
|
table.indexMap.set(fieldName, idx);
|
|
778
778
|
return idx;
|
|
779
779
|
}
|
|
780
|
+
var VECTOR_PATTERN = /^vector\[(\d+)]$/;
|
|
780
781
|
function getNestedValue(obj, path) {
|
|
781
782
|
const parts = path.split(".");
|
|
782
783
|
let current = obj;
|
|
@@ -809,6 +810,10 @@ function textFieldsChanged(oldDoc, newDoc, fields) {
|
|
|
809
810
|
}
|
|
810
811
|
return false;
|
|
811
812
|
}
|
|
813
|
+
function parseVectorDimension(fieldType) {
|
|
814
|
+
const match = VECTOR_PATTERN.exec(fieldType);
|
|
815
|
+
return match ? Number.parseInt(match[1], 10) : null;
|
|
816
|
+
}
|
|
812
817
|
function tokenizeOptions(options) {
|
|
813
818
|
return {
|
|
814
819
|
stem: true,
|
|
@@ -2573,4 +2578,4 @@ function setNestedValue(obj, path, value) {
|
|
|
2573
2578
|
current[segments[segments.length - 1]] = value;
|
|
2574
2579
|
}
|
|
2575
2580
|
|
|
2576
|
-
export { GEO_UNIT_METRES, MAX_FILTER_ARRAY_SIZE, MAX_FILTER_DEPTH, MAX_FILTER_TESTS, applyPagination, applyProjection, applySorting, boundedLevenshtein, clampRowCount, clearNormalizationCache, cloneProjected, collectQueryTermStats, computeFacets, configureNormalizationCache, countsWithoutScores, coveringRanges, createPatternWorkMeter, decodePageCursor, encodePageCursor, everyValueFacetConfig, fanOutMatchCount, fanOutQuery, filterTestCount, fnv1a, fnv1aBytes, fnv1aUint32s, fulltextMatches, fuzzyPrefixOf, fuzzyTermMatches, getFieldValueByInternalId, getFlatSchema, getNestedValue, getNormalizationCacheSize, getOrCreateFieldNameIndex, joinPatternWorkMeter, kWayMerge, locationCode, mergeFacets, mergePartitionStats, normalizeSort, oversampledFacetConfig, oversampledShardSize, partitionsIn, polygonBoxes, polygonContainment, projectionKeepsField, pruneStatsToQueryTerms, radiusBoxes, readSortValues, requireMatchingCursor, requireSortableFields, requireValidFilter, requireValidOperands, requireWithinResultWindow, resetNormalizationCache, resolveProjection, sanitizeGlobalStats, setNestedValue, sortModesOf, sortSignatureEntry, sortSignatureOf, textFieldsChanged, tokenize, tokenizeIterator, tokenizeOptions, undeclaredFieldOnStrictIndex, undeclaredFilterField, visitTokens };
|
|
2581
|
+
export { GEO_UNIT_METRES, MAX_FILTER_ARRAY_SIZE, MAX_FILTER_DEPTH, MAX_FILTER_TESTS, applyPagination, applyProjection, applySorting, boundedLevenshtein, clampRowCount, clearNormalizationCache, cloneProjected, collectQueryTermStats, computeFacets, configureNormalizationCache, countsWithoutScores, coveringRanges, createPatternWorkMeter, decodePageCursor, encodePageCursor, everyValueFacetConfig, fanOutMatchCount, fanOutQuery, filterTestCount, fnv1a, fnv1aBytes, fnv1aUint32s, fulltextMatches, fuzzyPrefixOf, fuzzyTermMatches, getFieldValueByInternalId, getFlatSchema, getNestedValue, getNormalizationCacheSize, getOrCreateFieldNameIndex, joinPatternWorkMeter, kWayMerge, locationCode, mergeFacets, mergePartitionStats, normalizeSort, oversampledFacetConfig, oversampledShardSize, parseVectorDimension, partitionsIn, polygonBoxes, polygonContainment, projectionKeepsField, pruneStatsToQueryTerms, radiusBoxes, readSortValues, requireMatchingCursor, requireSortableFields, requireValidFilter, requireValidOperands, requireWithinResultWindow, resetNormalizationCache, resolveProjection, sanitizeGlobalStats, setNestedValue, sortModesOf, sortSignatureEntry, sortSignatureOf, textFieldsChanged, tokenize, tokenizeIterator, tokenizeOptions, undeclaredFieldOnStrictIndex, undeclaredFilterField, visitTokens };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { validateRequiredFields } from './chunk-
|
|
2
|
-
import { ErrorCodes, NarsilError } from './chunk-
|
|
1
|
+
import { requireDocumentWithinSizeLimit, validateRequiredFields } from './chunk-AK3BLGCI.mjs';
|
|
2
|
+
import { ErrorCodes, NarsilError } from './chunk-I64LXKO3.mjs';
|
|
3
3
|
|
|
4
4
|
// src/narsil/internals.ts
|
|
5
5
|
var engineCores = /* @__PURE__ */ new WeakMap();
|
|
@@ -244,7 +244,10 @@ function providedDocId(document) {
|
|
|
244
244
|
return typeof id === "string" && id.length > 0 ? id : void 0;
|
|
245
245
|
}
|
|
246
246
|
function requireDocumentObject(document) {
|
|
247
|
-
if (document !== null && typeof document === "object" && !Array.isArray(document))
|
|
247
|
+
if (document !== null && typeof document === "object" && !Array.isArray(document)) {
|
|
248
|
+
requireDocumentWithinSizeLimit(document);
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
248
251
|
const received = Array.isArray(document) ? "a list" : document === null ? "null" : `a ${typeof document}`;
|
|
249
252
|
throw new NarsilError(
|
|
250
253
|
ErrorCodes.DOC_VALIDATION_FAILED,
|
|
@@ -578,9 +581,9 @@ function readSharedConfigFields(source, reject) {
|
|
|
578
581
|
...typeof source.patternValueLimit === "number" ? { patternValueLimit: source.patternValueLimit } : {}
|
|
579
582
|
};
|
|
580
583
|
}
|
|
581
|
-
function restoredConfigFields(envelope) {
|
|
582
|
-
const shared = readSharedConfigFields(envelope,
|
|
583
|
-
const partitions = restoredPartitionConfig(envelope.partitionConfig);
|
|
584
|
+
function restoredConfigFields(envelope, reject = rejectSnapshot) {
|
|
585
|
+
const shared = readSharedConfigFields(envelope, reject);
|
|
586
|
+
const partitions = restoredPartitionConfig(envelope.partitionConfig, reject);
|
|
584
587
|
return {
|
|
585
588
|
...shared,
|
|
586
589
|
...partitions !== void 0 ? { partitions } : {}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { MAX_M } from './chunk-
|
|
1
|
+
import { EARLIER_RELEASE_MIN_M, MIN_M, MAX_M } from './chunk-PU43WDY4.mjs';
|
|
2
2
|
import { holdsUnpairedSurrogate, exceedsCodePoints } from './chunk-LJYTW7GT.mjs';
|
|
3
|
-
import { NarsilError, ErrorCodes } from './chunk-
|
|
3
|
+
import { NarsilError, ErrorCodes } from './chunk-I64LXKO3.mjs';
|
|
4
|
+
import { encode } from '@msgpack/msgpack';
|
|
4
5
|
|
|
5
6
|
// src/schema/constants.ts
|
|
6
7
|
var MAX_NESTING_DEPTH = 4;
|
|
@@ -8,6 +9,10 @@ var MAX_DOCUMENT_NESTING_DEPTH = 32;
|
|
|
8
9
|
var DEFAULT_PATTERN_VALUE_LIMIT = 8192;
|
|
9
10
|
var MIN_PATTERN_VALUE_LIMIT = 1;
|
|
10
11
|
var MAX_PATTERN_VALUE_LIMIT = 65536;
|
|
12
|
+
var MAX_VECTOR_DIMENSION = 4096;
|
|
13
|
+
var MAX_STORED_VECTOR_DIMENSION = 65535;
|
|
14
|
+
var MAX_TEXT_FIELDS = 65536;
|
|
15
|
+
var MAX_DOCUMENT_BYTES = 16777216;
|
|
11
16
|
|
|
12
17
|
// src/schema/validator/shared.ts
|
|
13
18
|
var VECTOR_PATTERN = /^vector\[(\d+)]$/;
|
|
@@ -57,11 +62,11 @@ function parseBase(baseName, path, type) {
|
|
|
57
62
|
invalidType(path, type, `Field "${path}" has an unsupported type: "${type}"`);
|
|
58
63
|
}
|
|
59
64
|
const dimension = Number.parseInt(vectorMatch[1], 10);
|
|
60
|
-
if (dimension <= 0) {
|
|
65
|
+
if (dimension <= 0 || dimension > MAX_STORED_VECTOR_DIMENSION) {
|
|
61
66
|
throw new NarsilError(
|
|
62
67
|
ErrorCodes.SCHEMA_INVALID_VECTOR_DIMENSION,
|
|
63
|
-
`Vector field "${path}"
|
|
64
|
-
{ field: path, dimension }
|
|
68
|
+
`Vector field "${path}" has ${dimension} dimensions, but a vector field holds from 1 to ${MAX_STORED_VECTOR_DIMENSION}`,
|
|
69
|
+
{ field: path, dimension, maximum: MAX_STORED_VECTOR_DIMENSION }
|
|
65
70
|
);
|
|
66
71
|
}
|
|
67
72
|
return { base: "vector", dimension };
|
|
@@ -194,9 +199,30 @@ function validateSchema(schema) {
|
|
|
194
199
|
if (Object.keys(schema).length === 0) {
|
|
195
200
|
throw new NarsilError(ErrorCodes.SCHEMA_INVALID_TYPE, "Schema must define at least one field");
|
|
196
201
|
}
|
|
197
|
-
|
|
202
|
+
const validated = validateSchemaFields(schema, 1, "");
|
|
203
|
+
requireTextFieldCount(schemaFieldsOf(validated).filter((field) => isWordIndexedBase(field.base)).length);
|
|
204
|
+
return validated;
|
|
205
|
+
}
|
|
206
|
+
function requireTextFieldCount(count) {
|
|
207
|
+
if (count <= MAX_TEXT_FIELDS) return;
|
|
208
|
+
throw new NarsilError(
|
|
209
|
+
ErrorCodes.SCHEMA_INVALID_TYPE,
|
|
210
|
+
`The schema declares ${count} string and string[] fields, but a schema holds at most ${MAX_TEXT_FIELDS}`,
|
|
211
|
+
{ textFields: count, maximum: MAX_TEXT_FIELDS }
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
function requireCreatableSchema(schema) {
|
|
215
|
+
for (const field of schemaFieldsOf(schema)) {
|
|
216
|
+
if (field.base !== "vector" || field.dimension <= MAX_VECTOR_DIMENSION) continue;
|
|
217
|
+
throw new NarsilError(
|
|
218
|
+
ErrorCodes.SCHEMA_INVALID_VECTOR_DIMENSION,
|
|
219
|
+
`Vector field "${field.path}" has ${field.dimension} dimensions, but a new index takes at most ${MAX_VECTOR_DIMENSION}`,
|
|
220
|
+
{ field: field.path, dimension: field.dimension, maximum: MAX_VECTOR_DIMENSION }
|
|
221
|
+
);
|
|
222
|
+
}
|
|
198
223
|
}
|
|
199
224
|
function requireValidFieldTypes(flatSchema) {
|
|
225
|
+
let textFields = 0;
|
|
200
226
|
for (const [path, type] of Object.entries(flatSchema)) {
|
|
201
227
|
if (typeof type !== "string") {
|
|
202
228
|
throw new NarsilError(
|
|
@@ -205,8 +231,9 @@ function requireValidFieldTypes(flatSchema) {
|
|
|
205
231
|
{ field: path, type: String(type) }
|
|
206
232
|
);
|
|
207
233
|
}
|
|
208
|
-
parseFieldType(type, path);
|
|
234
|
+
if (isWordIndexedBase(parseFieldType(type, path).base)) textFields += 1;
|
|
209
235
|
}
|
|
236
|
+
requireTextFieldCount(textFields);
|
|
210
237
|
}
|
|
211
238
|
function flattenRecursive(schema, prefix, result) {
|
|
212
239
|
for (const [field, type] of Object.entries(schema)) {
|
|
@@ -474,7 +501,11 @@ function walkStorable(value, path, depth, ancestors, skip) {
|
|
|
474
501
|
reject(path, `holds a ${kind}, which cannot be stored or recovered`);
|
|
475
502
|
}
|
|
476
503
|
const container = value;
|
|
477
|
-
if (container instanceof Date
|
|
504
|
+
if (container instanceof Date) {
|
|
505
|
+
if (Number.isNaN(container.getTime())) reject(path, "holds an invalid date, which the engine cannot store");
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
if (container instanceof Uint8Array) return;
|
|
478
509
|
const isArray = Array.isArray(container);
|
|
479
510
|
if (!isArray && !isPlainObject2(container)) {
|
|
480
511
|
reject(
|
|
@@ -628,6 +659,71 @@ function validateRequiredFields(document, required) {
|
|
|
628
659
|
}
|
|
629
660
|
}
|
|
630
661
|
}
|
|
662
|
+
function holdsNegativeZero(value) {
|
|
663
|
+
const pending = [value];
|
|
664
|
+
while (pending.length > 0) {
|
|
665
|
+
const next = pending.pop();
|
|
666
|
+
if (typeof next === "number") {
|
|
667
|
+
if (Object.is(next, -0)) return true;
|
|
668
|
+
continue;
|
|
669
|
+
}
|
|
670
|
+
if (next === null || typeof next !== "object" || ArrayBuffer.isView(next)) continue;
|
|
671
|
+
for (const child of Array.isArray(next) ? next : Object.values(next)) pending.push(child);
|
|
672
|
+
}
|
|
673
|
+
return false;
|
|
674
|
+
}
|
|
675
|
+
function encodeDocument(document) {
|
|
676
|
+
return encode(document, holdsNegativeZero(document) ? { forceIntegerToFloat: true } : void 0);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// src/schema/validator/document-size.ts
|
|
680
|
+
var LARGEST_HEADER_BYTES = 5;
|
|
681
|
+
var LARGEST_NUMBER_BYTES = 9;
|
|
682
|
+
var LARGEST_TIMESTAMP_BYTES = 15;
|
|
683
|
+
var LARGEST_UTF8_BYTES_PER_UNIT = 3;
|
|
684
|
+
function upperBoundBytes(value, budget, depth) {
|
|
685
|
+
if (value === null || value === void 0 || typeof value === "boolean") return 1;
|
|
686
|
+
if (typeof value === "number") return LARGEST_NUMBER_BYTES;
|
|
687
|
+
if (typeof value === "string") return LARGEST_HEADER_BYTES + value.length * LARGEST_UTF8_BYTES_PER_UNIT;
|
|
688
|
+
if (value instanceof Date) return LARGEST_TIMESTAMP_BYTES;
|
|
689
|
+
if (ArrayBuffer.isView(value)) return LARGEST_HEADER_BYTES + value.byteLength;
|
|
690
|
+
if (typeof value !== "object" || depth > MAX_DOCUMENT_NESTING_DEPTH) return LARGEST_NUMBER_BYTES;
|
|
691
|
+
let total = LARGEST_HEADER_BYTES;
|
|
692
|
+
if (Array.isArray(value)) {
|
|
693
|
+
for (const item of value) {
|
|
694
|
+
total += upperBoundBytes(item, budget - total, depth + 1);
|
|
695
|
+
if (total > budget) return total;
|
|
696
|
+
}
|
|
697
|
+
return total;
|
|
698
|
+
}
|
|
699
|
+
const record = value;
|
|
700
|
+
for (const key of Object.keys(record)) {
|
|
701
|
+
total += LARGEST_HEADER_BYTES + key.length * LARGEST_UTF8_BYTES_PER_UNIT;
|
|
702
|
+
total += upperBoundBytes(record[key], budget - total, depth + 1);
|
|
703
|
+
if (total > budget) return total;
|
|
704
|
+
}
|
|
705
|
+
return total;
|
|
706
|
+
}
|
|
707
|
+
function messagePackUpperBoundBytes(value) {
|
|
708
|
+
return upperBoundBytes(value, Number.POSITIVE_INFINITY, 0);
|
|
709
|
+
}
|
|
710
|
+
function encodedBytesOf(document) {
|
|
711
|
+
try {
|
|
712
|
+
return encodeDocument(document).byteLength;
|
|
713
|
+
} catch {
|
|
714
|
+
return null;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
function requireDocumentWithinSizeLimit(document) {
|
|
718
|
+
if (upperBoundBytes(document, MAX_DOCUMENT_BYTES, 0) <= MAX_DOCUMENT_BYTES) return;
|
|
719
|
+
const encodedBytes = encodedBytesOf(document);
|
|
720
|
+
if (encodedBytes === null || encodedBytes <= MAX_DOCUMENT_BYTES) return;
|
|
721
|
+
throw new NarsilError(
|
|
722
|
+
ErrorCodes.DOC_VALIDATION_FAILED,
|
|
723
|
+
`The document takes ${encodedBytes} bytes as MessagePack, vector values included, but a document may take at most ${MAX_DOCUMENT_BYTES}`,
|
|
724
|
+
{ bytes: encodedBytes, maximum: MAX_DOCUMENT_BYTES }
|
|
725
|
+
);
|
|
726
|
+
}
|
|
631
727
|
|
|
632
728
|
// src/schema/validator/vector-promotion.ts
|
|
633
729
|
var QUANTIZATION_MODES = /* @__PURE__ */ new Set(["osq8", "osq4", "osq2", "osq1", "none"]);
|
|
@@ -651,6 +747,13 @@ function validateVectorStorage(config, filesystemDurability) {
|
|
|
651
747
|
});
|
|
652
748
|
}
|
|
653
749
|
}
|
|
750
|
+
function raiseEarlierReleaseGraphSetting(config) {
|
|
751
|
+
if (typeof config !== "object" || config === null) return config;
|
|
752
|
+
const hnsw = config.hnswConfig;
|
|
753
|
+
if (typeof hnsw !== "object" || hnsw === null) return config;
|
|
754
|
+
if (hnsw.m !== EARLIER_RELEASE_MIN_M) return config;
|
|
755
|
+
return { ...config, hnswConfig: { ...hnsw, m: MIN_M } };
|
|
756
|
+
}
|
|
654
757
|
function validateVectorPromotion(config) {
|
|
655
758
|
if (config === void 0) return;
|
|
656
759
|
if (config.threshold !== void 0 && !isPositiveInteger(config.threshold)) {
|
|
@@ -666,8 +769,8 @@ function validateVectorPromotion(config) {
|
|
|
666
769
|
}
|
|
667
770
|
const hnsw = config.hnswConfig;
|
|
668
771
|
if (hnsw === void 0) return;
|
|
669
|
-
if (hnsw.m !== void 0 && (!
|
|
670
|
-
fail(`vectorPromotion.hnswConfig.m must be a
|
|
772
|
+
if (hnsw.m !== void 0 && (!Number.isInteger(hnsw.m) || hnsw.m < MIN_M || hnsw.m > MAX_M)) {
|
|
773
|
+
fail(`vectorPromotion.hnswConfig.m must be a whole number from ${MIN_M} to ${MAX_M}`, { m: hnsw.m });
|
|
671
774
|
}
|
|
672
775
|
if (hnsw.efConstruction !== void 0 && !isPositiveInteger(hnsw.efConstruction)) {
|
|
673
776
|
fail("vectorPromotion.hnswConfig.efConstruction must be a positive integer", {
|
|
@@ -698,4 +801,31 @@ var DEFAULT_LINEAR_ALPHA = 0.5;
|
|
|
698
801
|
var MIN_LINEAR_ALPHA = 0;
|
|
699
802
|
var MAX_LINEAR_ALPHA = 1;
|
|
700
803
|
|
|
701
|
-
|
|
804
|
+
// src/engine/constants.ts
|
|
805
|
+
var MIN_DOCUMENTS_FOR_SEGMENTS = 64;
|
|
806
|
+
var BATCH_CHUNK_SIZE = 1e3;
|
|
807
|
+
var DEFAULT_LIMIT = DEFAULT_PAGE_SIZE;
|
|
808
|
+
var DEFAULT_OFFSET = 0;
|
|
809
|
+
var INDEX_NAME_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
|
|
810
|
+
var ABSOLUTE_WINDOWS_PATH_PATTERN = /^[a-zA-Z]:[\\/]/;
|
|
811
|
+
var MODULE_URL_SCHEME_PATTERN = /^(file|https?|data|node):/;
|
|
812
|
+
var MAX_INDEX_NAME_LENGTH = 255;
|
|
813
|
+
var MAX_DOC_ID_LENGTH = 512;
|
|
814
|
+
var EXPORT_CHUNK_BYTES = 1048576;
|
|
815
|
+
var MAX_EXPORT_LINE_BYTES = 117443592;
|
|
816
|
+
var MAX_INDEX_CONFIGURATION_BYTES = 16777216;
|
|
817
|
+
var IMPORT_BATCH_DOCUMENTS = 1e3;
|
|
818
|
+
var MAX_IMPORT_REFUSALS_REPORTED = 1e3;
|
|
819
|
+
var MIN_SWEEP_INTERVAL_MS = 100;
|
|
820
|
+
var MAX_SWEEP_INTERVAL_MS = 6e4;
|
|
821
|
+
var HEAP_PRESSURE_WARNING_FRACTION = 0.9;
|
|
822
|
+
var HEAP_PRESSURE_REARM_FRACTION = 0.8;
|
|
823
|
+
var STATISTICS_BROADCAST_INTERVAL_MS = 5e3;
|
|
824
|
+
var FOREIGN_STATS_TTL_MS = 6e4;
|
|
825
|
+
var DEFAULT_SUGGEST_LIMIT = 10;
|
|
826
|
+
var MAX_SUGGEST_LIMIT = 100;
|
|
827
|
+
var SUGGEST_OVERSAMPLE_FACTOR = 1.5;
|
|
828
|
+
var SUGGEST_OVERSAMPLE_PADDING = 10;
|
|
829
|
+
var MAX_SUGGEST_SCATTER_LIMIT = Math.ceil(MAX_SUGGEST_LIMIT * SUGGEST_OVERSAMPLE_FACTOR) + SUGGEST_OVERSAMPLE_PADDING;
|
|
830
|
+
|
|
831
|
+
export { ABSOLUTE_WINDOWS_PATH_PATTERN, ANTIMERIDIAN_SPAN_DEGREES, BATCH_CHUNK_SIZE, DEFAULT_FUZZY_PREFIX_LENGTH, DEFAULT_LIMIT, DEFAULT_LINEAR_ALPHA, DEFAULT_MAX_PER_GROUP, DEFAULT_OFFSET, DEFAULT_PAGE_SIZE, DEFAULT_RANK_CONSTANT, DEFAULT_SUGGEST_LIMIT, DEG_TO_RAD, EARTH_RADIUS_METERS, EXPORT_CHUNK_BYTES, FOREIGN_STATS_TTL_MS, FULL_TURN_DEGREES, HEAP_PRESSURE_REARM_FRACTION, HEAP_PRESSURE_WARNING_FRACTION, IMPORT_BATCH_DOCUMENTS, INDEX_NAME_PATTERN, LOCATION_CODE_BITS_PER_AXIS, MAX_COVERING_CELLS, MAX_CURSOR_ANCHOR_CODE_POINTS, MAX_CURSOR_LENGTH, MAX_DOCUMENT_NESTING_DEPTH, MAX_DOC_ID_LENGTH, MAX_EXPORT_LINE_BYTES, MAX_IMPORT_REFUSALS_REPORTED, MAX_INDEX_CONFIGURATION_BYTES, MAX_INDEX_NAME_LENGTH, MAX_LATITUDE_DEGREES, MAX_LINEAR_ALPHA, MAX_LONGITUDE_DEGREES, MAX_NESTING_DEPTH, MAX_PATTERN_VALUE_LIMIT, MAX_PREFIX_LENGTH, MAX_SORT_FIELDS, MAX_SORT_FIELD_NAME_LENGTH, MAX_STORED_VECTOR_DIMENSION, MAX_SUGGEST_LIMIT, MAX_SUGGEST_SCATTER_LIMIT, MAX_SWEEP_INTERVAL_MS, MAX_TOLERANCE, MIN_DOCUMENTS_FOR_SEGMENTS, MIN_LINEAR_ALPHA, MIN_PATTERN_VALUE_LIMIT, MIN_POLYGON_POINTS, MIN_RANK_CONSTANT, MIN_SWEEP_INTERVAL_MS, MODULE_URL_SCHEME_PATTERN, PREFIX_MAX_EXPANSIONS, PROTOTYPE_POLLUTION_KEYS, RADIUS_BOX_MARGIN_RADIANS, RADIUS_BOX_MARGIN_RATIO, RESULT_WINDOW, STATISTICS_BROADCAST_INTERVAL_MS, SUGGEST_OVERSAMPLE_FACTOR, SUGGEST_OVERSAMPLE_PADDING, VECTOR_PATTERN, VINCENTY_CONVERGENCE_THRESHOLD, VINCENTY_MAX_ITERATIONS, encodeDocument, extractVectorFieldsFromSchema, flattenSchema, isGeopointOrVectorType, isLatitude, isListBase, isLongitude, isQuantizationMode, isSingleStringFieldType, isStorageMode, isStringValuedBase, isWordIndexedBase, isWordIndexedFieldType, messagePackUpperBoundBytes, parsedTypeOf, raiseEarlierReleaseGraphSetting, requireCreatableSchema, requireDocumentWithinSizeLimit, requireValidFieldTypes, schemaFieldsOf, validateDocument, validateDocumentStrict, validateRequiredFields, validateSchema, validateVectorPromotion, validateVectorStorage, withSortableOption };
|