@delali/narsil 0.2.4-next.42 → 0.2.4-next.44

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.
Files changed (36) hide show
  1. package/dist/adapters/filesystem.mjs +1 -1
  2. package/dist/adapters/indexeddb.mjs +1 -1
  3. package/dist/{chunk-GB2IIJJG.mjs → chunk-P4ELXVJQ.mjs} +2 -4
  4. package/dist/{chunk-MMSWEEZT.mjs → chunk-WASNWIEK.mjs} +1452 -373
  5. package/dist/{chunk-GRWFY2HI.mjs → chunk-XNCJFU2E.mjs} +239 -61
  6. package/dist/{chunk-WU2UZEVD.mjs → chunk-XWICBGYT.mjs} +1 -1
  7. package/dist/{client-BobVnoIK.d.ts → client-C5BkUqB8.d.ts} +26 -3
  8. package/dist/client.d.ts +8 -8
  9. package/dist/client.mjs +12 -6
  10. package/dist/{config-fLC4lbmg.d.ts → config-B-ZI-ft5.d.ts} +2 -2
  11. package/dist/{config-Byyl1QqH.d.ts → config-BZRExglL.d.ts} +20 -3
  12. package/dist/{direct-executor-MSJEVPZU.mjs → direct-executor-IMXNRS7O.mjs} +2 -2
  13. package/dist/distribution/coordinator/etcd.d.ts +2 -2
  14. package/dist/distribution/coordinator/etcd.mjs +1 -1
  15. package/dist/distribution/coordinator/in-memory.d.ts +2 -2
  16. package/dist/distribution/transport/grpc.mjs +1 -1
  17. package/dist/distribution.d.ts +24 -10
  18. package/dist/distribution.mjs +1721 -1129
  19. package/dist/embeddings/openai.mjs +1 -1
  20. package/dist/{engine-BE45D5ZG.d.ts → engine-Cjr1uBLa.d.ts} +47 -24
  21. package/dist/index.browser.mjs +1668 -416
  22. package/dist/index.d.ts +9 -9
  23. package/dist/index.mjs +4 -4
  24. package/dist/{options-EXYFcem-.d.ts → options-BC68VPoE.d.ts} +10 -3
  25. package/dist/persistence/durability/checkpoint-worker.d.ts +3 -1
  26. package/dist/persistence/durability/checkpoint-worker.mjs +4 -4
  27. package/dist/react.d.ts +6 -6
  28. package/dist/react.mjs +2 -4
  29. package/dist/{schema-ZRbk8BgH.d.ts → schema-B7juWg8Q.d.ts} +17 -6
  30. package/dist/{search-DHuXwJYk.d.ts → search-DDHjfXhJ.d.ts} +35 -11
  31. package/dist/server.d.ts +10 -10
  32. package/dist/server.mjs +30 -12
  33. package/dist/{tasks-CnMLpfk-.d.ts → tasks-Bn4R1NPN.d.ts} +1 -1
  34. package/dist/{types-B5Tsaalz.d.ts → types-DsSSjY4d.d.ts} +1 -1
  35. package/dist/workers/entry.mjs +2 -2
  36. package/package.json +1 -1
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
- import { c as StopWordOverride, C as CustomTokenizer } from './schema-ZRbk8BgH.js';
2
- export { A as AnyDocument, B as BM25Params, E as EmbeddingFieldConfig, F as FieldType, I as IndexConfig, a as InsertOptions, P as PartitionConfig, S as SchemaDefinition, b as ScoringMode, V as VectorIndexConfig, d as VectorQuantizationMode } from './schema-ZRbk8BgH.js';
1
+ import { c as StopWordOverride, C as CustomTokenizer } from './schema-B7juWg8Q.js';
2
+ export { A as AnyDocument, B as BM25Params, E as EmbeddingFieldConfig, F as FieldType, I as IndexConfig, b as InsertOptions, P as PartitionConfig, S as SchemaDefinition, a as ScoringMode, V as VectorIndexConfig, d as VectorQuantizationMode } from './schema-B7juWg8Q.js';
3
3
  import { L as LanguageModule } from './language-DB8KG1z5.js';
4
4
  export { T as TokenizerConfig } from './language-DB8KG1z5.js';
5
- export { A as ArrayFilter, B as BatchResult, C as ClientErrorCode, a as ClientErrorCodes, k as ComparisonFilter, D as DocumentProjection, E as ErrorCode, b as ErrorCodes, F as FacetConfig, l as FacetResult, m as FieldFilter, n as FilterExpression, G as GeoFilter, o as GeoPolygonFilter, p as GeoRadiusFilter, q as GroupConfig, r as GroupReducer, s as GroupResult, H as HighlightConfig, t as HighlightMatch, u as Hit, v as HybridConfig, I as IndexInfo, f as IndexStats, L as ListParams, g as ListResult, w as ListedDocument, M as MemoryStats, N as NarsilError, c as NarsilErrorCode, P as PartitionStatsResult, h as PreflightResult, x as PresenceFilter, y as ProcessMemoryReport, z as QueryCoverage, Q as QueryParams, e as QueryResult, J as ScoreComponents, K as SearchMode, S as ServerErrorCode, d as ServerErrorCodes, O as SortField, R as SortSpec, T as StringFilter, i as SuggestParams, j as SuggestResult, U as TermMatchPolicy, V as VectorMaintenanceResult, W as VectorQueryConfig } from './search-DHuXwJYk.js';
6
- import { N as NarsilConfig } from './config-Byyl1QqH.js';
7
- export { A as AnalysisConfig, D as DurabilityConfig, I as IndexContext, a as InsertContext, b as NarsilPlugin, P as PartitionContext, R as RemoveContext, S as SearchContext, c as StaleAnalysis, U as UpdateContext, W as WorkerConfig, d as WorkerContext } from './config-Byyl1QqH.js';
8
- import { a as Narsil } from './engine-BE45D5ZG.js';
9
- export { N as NarsilEventMap } from './engine-BE45D5ZG.js';
5
+ export { A as ArrayFilter, B as BatchResult, C as ClientErrorCode, a as ClientErrorCodes, k as ComparisonFilter, D as DocumentProjection, E as ErrorCode, b as ErrorCodes, F as FacetConfig, l as FacetResult, m as FieldFilter, n as FilterExpression, G as GeoFilter, o as GeoPolygonFilter, p as GeoRadiusFilter, q as GroupConfig, r as GroupReducer, s as GroupResult, H as HighlightConfig, t as HighlightMatch, u as Hit, v as HybridConfig, I as IndexInfo, f as IndexStats, L as ListParams, g as ListResult, w as ListedDocument, M as MemoryStats, N as NarsilError, c as NarsilErrorCode, P as PartitionStatsResult, h as PreflightResult, x as PresenceFilter, y as ProcessMemoryReport, z as QueryCoverage, Q as QueryParams, e as QueryResult, J as ScoreComponents, K as SearchMode, S as ServerErrorCode, d as ServerErrorCodes, O as SortField, R as SortSpec, T as StringFilter, i as SuggestParams, j as SuggestResult, U as TermMatchPolicy, V as VectorMaintenanceResult, W as VectorQueryConfig } from './search-DDHjfXhJ.js';
6
+ import { N as NarsilConfig } from './config-BZRExglL.js';
7
+ export { A as AnalysisConfig, D as DurabilityConfig, I as IndexContext, a as IndexLifecycleConfig, b as InsertContext, c as NarsilPlugin, P as PartitionContext, R as RemoveContext, S as SearchContext, d as StaleAnalysis, U as UpdateContext, W as WorkerConfig, e as WorkerContext } from './config-BZRExglL.js';
8
+ import { a as Narsil } from './engine-Cjr1uBLa.js';
9
+ export { I as IndexLifecycleOperations, N as NarsilEventMap } from './engine-Cjr1uBLa.js';
10
10
  export { E as EmbeddingAdapter, I as InvalidationAdapter, a as InvalidationEvent, b as PartitionStatistics, P as PersistenceAdapter } from './adapters-79OIa4xm.js';
11
11
 
12
12
  /**
@@ -154,8 +154,8 @@ declare function getLanguage(name: string): LanguageModule;
154
154
  *
155
155
  * The engine holds every index you create, so an application usually keeps one
156
156
  * instance for its lifetime. When you configure persistence, this recovers the
157
- * indexes already on disk before it resolves, so the engine is ready to query
158
- * as soon as you have it.
157
+ * indexes already on disk before it resolves. Lifecycle settings register
158
+ * those indexes as closed and load each one when its first request arrives.
159
159
  *
160
160
  * @param config - This carries the persistence, partitioning, and worker
161
161
  * invalidation settings. Omit it for an engine that keeps everything in memory.
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
- export { VERSION, createNarsil } from './chunk-MMSWEEZT.mjs';
1
+ export { VERSION, createNarsil } from './chunk-WASNWIEK.mjs';
2
2
  import './chunk-JQUL2T6I.mjs';
3
- import './chunk-WU2UZEVD.mjs';
4
- export { clearNormalizationCache, configureNormalizationCache, getLanguage, getNormalizationCacheSize, getStopWords, getTokenizer, hasStopWords, hasTokenizer, registerLanguage, registerStopWords, registerTokenizer, resetNormalizationCache } from './chunk-GRWFY2HI.mjs';
3
+ import './chunk-XWICBGYT.mjs';
4
+ export { clearNormalizationCache, configureNormalizationCache, getLanguage, getNormalizationCacheSize, getStopWords, getTokenizer, hasStopWords, hasTokenizer, registerLanguage, registerStopWords, registerTokenizer, resetNormalizationCache } from './chunk-XNCJFU2E.mjs';
5
5
  import './chunk-TGP5M5R7.mjs';
6
6
  import './chunk-OBXS7OZM.mjs';
7
7
  export { isSimdAvailable } from './chunk-WDL632CN.mjs';
@@ -9,4 +9,4 @@ import './chunk-KMMJMDUA.mjs';
9
9
  import './chunk-U2BKYEC7.mjs';
10
10
  import './chunk-BFIH7OV5.mjs';
11
11
  import './chunk-WTONLDU3.mjs';
12
- export { ClientErrorCodes, ErrorCodes, NarsilError, ServerErrorCodes } from './chunk-GB2IIJJG.mjs';
12
+ export { ClientErrorCodes, ErrorCodes, NarsilError, ServerErrorCodes } from './chunk-P4ELXVJQ.mjs';
@@ -1,6 +1,6 @@
1
- import { C as ClusterNamespace } from './config-fLC4lbmg.js';
1
+ import { C as ClusterNamespace } from './config-B-ZI-ft5.js';
2
2
  import { E as EmbeddingAdapter } from './adapters-79OIa4xm.js';
3
- import { h as TaskStore } from './tasks-CnMLpfk-.js';
3
+ import { h as TaskStore } from './tasks-Bn4R1NPN.js';
4
4
 
5
5
  /**
6
6
  * Marks that `POST /indexes/{name}/documents/_import` accepts `?async=true` and
@@ -29,6 +29,13 @@ declare const TASK_FILTER_CAPABILITY = "tasks.filter";
29
29
  * @public
30
30
  */
31
31
  declare const REBUILD_ANALYSIS_CAPABILITY = "indexes.rebuildAnalysis";
32
+ /**
33
+ * Marks that `POST /indexes/{name}/_open` and `POST /indexes/{name}/_close`
34
+ * load and release an index's server memory.
35
+ *
36
+ * @public
37
+ */
38
+ declare const INDEX_LIFECYCLE_CAPABILITY = "indexes.lifecycle";
32
39
  /**
33
40
  * Every capability this server announces at `/capabilities`.
34
41
  *
@@ -240,4 +247,4 @@ interface ErrorEnvelope {
240
247
  };
241
248
  }
242
249
 
243
- export { ASYNC_IMPORT_CAPABILITY as A, type CorsOptions as C, type ErrorEnvelope as E, 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 };
250
+ 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 };
@@ -1,8 +1,10 @@
1
- import { P as PartitionConfig, b as ScoringMode, V as VectorIndexConfig } from '../../schema-ZRbk8BgH.js';
1
+ import { P as PartitionConfig, a as ScoringMode, V as VectorIndexConfig } from '../../schema-B7juWg8Q.js';
2
2
  import '../../adapters-79OIa4xm.js';
3
3
 
4
4
  interface IndexMetadata {
5
5
  indexName: string;
6
+ /** Number of documents represented by the last completed checkpoint. */
7
+ documentCount?: number;
6
8
  /** The identity a cluster gave the index at creation; absent on a single engine. */
7
9
  indexUuid?: string;
8
10
  /** The partitions this copy holds, which a cluster node answers a partition-stores request from. */
@@ -1,7 +1,7 @@
1
- import { createDurableDirectory, writeSegmentedCheckpoint } from '../../chunk-MMSWEEZT.mjs';
1
+ import { createDurableDirectory, writeSegmentedCheckpoint } from '../../chunk-WASNWIEK.mjs';
2
2
  import '../../chunk-JQUL2T6I.mjs';
3
- import '../../chunk-WU2UZEVD.mjs';
4
- import '../../chunk-GRWFY2HI.mjs';
3
+ import '../../chunk-XWICBGYT.mjs';
4
+ import '../../chunk-XNCJFU2E.mjs';
5
5
  import '../../chunk-TGP5M5R7.mjs';
6
6
  import '../../chunk-OBXS7OZM.mjs';
7
7
  import '../../chunk-WDL632CN.mjs';
@@ -9,7 +9,7 @@ import '../../chunk-KMMJMDUA.mjs';
9
9
  import '../../chunk-U2BKYEC7.mjs';
10
10
  import '../../chunk-BFIH7OV5.mjs';
11
11
  import '../../chunk-WTONLDU3.mjs';
12
- import '../../chunk-GB2IIJJG.mjs';
12
+ import '../../chunk-P4ELXVJQ.mjs';
13
13
 
14
14
  // src/persistence/durability/rebuild.ts
15
15
  async function rebuildSnapshotFromDurable(root, metadata, targets, compactionThreshold) {
package/dist/react.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- import { N as NarsilError, L as ListParams, g as ListResult, I as IndexInfo, f as IndexStats, Q as QueryParams, h as PreflightResult, e as QueryResult, i as SuggestParams, j as SuggestResult } from './search-DHuXwJYk.js';
2
- export { C as ClientErrorCode, a as ClientErrorCodes, E as ErrorCode, b as ErrorCodes, c as NarsilErrorCode, S as ServerErrorCode, d as ServerErrorCodes } from './search-DHuXwJYk.js';
3
- import { e as TaskRecord, d as TaskProgress, b as ImportResult, c as TaskListQuery, T as TaskListPage } from './tasks-CnMLpfk-.js';
4
- export { I as ImportError, f as TaskStatus, g as TaskType } from './tasks-CnMLpfk-.js';
1
+ import { N as NarsilError, L as ListParams, g as ListResult, I as IndexInfo, f as IndexStats, Q as QueryParams, h as PreflightResult, e as QueryResult, i as SuggestParams, j as SuggestResult } from './search-DDHjfXhJ.js';
2
+ export { C as ClientErrorCode, a as ClientErrorCodes, E as ErrorCode, b as ErrorCodes, c as NarsilErrorCode, S as ServerErrorCode, d as ServerErrorCodes } from './search-DDHjfXhJ.js';
3
+ import { e as TaskRecord, d as TaskProgress, b as ImportResult, c as TaskListQuery, T as TaskListPage } from './tasks-Bn4R1NPN.js';
4
+ export { I as ImportError, f as TaskStatus, g as TaskType } from './tasks-Bn4R1NPN.js';
5
5
  import { ReactNode, ReactElement } from 'react';
6
- import { N as NarsilClient, I as ImportSource } from './client-BobVnoIK.js';
7
- import { A as AnyDocument } from './schema-ZRbk8BgH.js';
6
+ import { N as NarsilClient, I as ImportSource } from './client-C5BkUqB8.js';
7
+ import { A as AnyDocument } from './schema-B7juWg8Q.js';
8
8
  import './adapters-79OIa4xm.js';
9
9
 
10
10
  /**
package/dist/react.mjs CHANGED
@@ -3,7 +3,6 @@ import { createContext, useState, useEffect, createElement, useRef, useEffectEve
3
3
  // src/errors.ts
4
4
  var ErrorCodes = {
5
5
  SCHEMA_INVALID_TYPE: "SCHEMA_INVALID_TYPE",
6
- SCHEMA_MISSING_FIELD: "SCHEMA_MISSING_FIELD",
7
6
  SCHEMA_DEPTH_EXCEEDED: "SCHEMA_DEPTH_EXCEEDED",
8
7
  SCHEMA_INVALID_VECTOR_DIMENSION: "SCHEMA_INVALID_VECTOR_DIMENSION",
9
8
  SCHEMA_INVALID_GEOPOINT: "SCHEMA_INVALID_GEOPOINT",
@@ -13,6 +12,7 @@ var ErrorCodes = {
13
12
  INDEX_NOT_FOUND: "INDEX_NOT_FOUND",
14
13
  INDEX_ALREADY_EXISTS: "INDEX_ALREADY_EXISTS",
15
14
  INDEX_ORPHANED: "INDEX_ORPHANED",
15
+ INDEX_REOPEN_CAPACITY_EXHAUSTED: "INDEX_REOPEN_CAPACITY_EXHAUSTED",
16
16
  PARTITION_CORRUPTED: "PARTITION_CORRUPTED",
17
17
  PARTITION_REBALANCING_BACKPRESSURE: "PARTITION_REBALANCING_BACKPRESSURE",
18
18
  WORKER_CRASHED: "WORKER_CRASHED",
@@ -25,7 +25,6 @@ var ErrorCodes = {
25
25
  PERSISTENCE_WAL_CORRUPT: "PERSISTENCE_WAL_CORRUPT",
26
26
  PERSISTENCE_FSYNC_FAILED: "PERSISTENCE_FSYNC_FAILED",
27
27
  SEARCH_INVALID_FIELD: "SEARCH_INVALID_FIELD",
28
- SEARCH_INVALID_VECTOR_SIZE: "SEARCH_INVALID_VECTOR_SIZE",
29
28
  VECTOR_DIMENSION_MISMATCH: "VECTOR_DIMENSION_MISMATCH",
30
29
  SEARCH_INVALID_FILTER: "SEARCH_INVALID_FILTER",
31
30
  SEARCH_INVALID_MODE: "SEARCH_INVALID_MODE",
@@ -49,8 +48,6 @@ var ErrorCodes = {
49
48
  ALLOCATION_NO_DATA_NODES: "ALLOCATION_NO_DATA_NODES",
50
49
  ALLOCATION_INVALID_CONFIG: "ALLOCATION_INVALID_CONFIG",
51
50
  ALLOCATION_FAILED: "ALLOCATION_FAILED",
52
- CONTROLLER_LEASE_LOST: "CONTROLLER_LEASE_LOST",
53
- CONTROLLER_NOT_ACTIVE: "CONTROLLER_NOT_ACTIVE",
54
51
  CONTROLLER_METADATA_INVALID: "CONTROLLER_METADATA_INVALID",
55
52
  NODE_BOOTSTRAP_FAILED: "NODE_BOOTSTRAP_FAILED",
56
53
  NODE_ALREADY_JOINED: "NODE_ALREADY_JOINED",
@@ -106,6 +103,7 @@ var ServerErrorCodes = {
106
103
  TASK_NOT_FOUND: "TASK_NOT_FOUND",
107
104
  TASK_NOT_CANCELLABLE: "TASK_NOT_CANCELLABLE",
108
105
  TASK_OWNED_BY_ANOTHER_INSTANCE: "TASK_OWNED_BY_ANOTHER_INSTANCE",
106
+ TASK_INTERRUPTED: "TASK_INTERRUPTED",
109
107
  TOO_MANY_REQUESTS: "TOO_MANY_REQUESTS",
110
108
  HOOK_ERROR: "HOOK_ERROR",
111
109
  INTERNAL_ERROR: "INTERNAL_ERROR"
@@ -61,7 +61,12 @@ type VectorQuantizationMode = 'sq8' | 'none';
61
61
  interface VectorIndexConfig {
62
62
  /** The engine promotes the field to an HNSW graph once it holds this many vectors. */
63
63
  threshold?: number;
64
- /** A filtered search prefers the graph over a scan once the field holds this many vectors. */
64
+ /**
65
+ * A selectivity ratio between 0 and 1, defaulting to 0.03. A filtered search
66
+ * whose filter matches a smaller share of the graph's vectors scans just the
67
+ * matches, and one matching a larger share searches the graph. The engine
68
+ * clamps any value outside that range to it.
69
+ */
65
70
  filterThreshold?: number;
66
71
  /** These settings shape the graph: neighbours per node, build-time exploration, and the metric that ranks results. */
67
72
  hnswConfig?: {
@@ -69,7 +74,7 @@ interface VectorIndexConfig {
69
74
  efConstruction?: number;
70
75
  metric?: 'cosine' | 'dotProduct' | 'euclidean';
71
76
  };
72
- /** The engine stores the promoted vectors at this precision. It keeps full precision by default. */
77
+ /** The engine stores the promoted vectors at this precision, and it quantises to `sq8` by default. Set `none` to keep full precision. */
73
78
  quantization?: VectorQuantizationMode;
74
79
  }
75
80
  /**
@@ -117,7 +122,12 @@ interface IndexConfig {
117
122
  stopWords?: StopWordOverride | string;
118
123
  /** This replaces the language's tokeniser, either inline or by the name a tokeniser registered under. */
119
124
  tokenizer?: CustomTokenizer | string;
120
- /** Setting this records term positions, which phrase queries and highlighting need. */
125
+ /**
126
+ * Setting this records term positions in each posting, which the `.nrsl`
127
+ * format carries for readers that match phrases. This engine's highlighter
128
+ * re-analyses the stored text instead of reading them, so an index that
129
+ * opts out answers every query the same way and stores less.
130
+ */
121
131
  trackPositions?: boolean;
122
132
  /** These settings control when vector fields move to an HNSW graph, and how that graph is built. */
123
133
  vectorPromotion?: VectorIndexConfig;
@@ -170,8 +180,9 @@ interface CustomTokenizer {
170
180
  * Splits one field value into the tokens the engine indexes.
171
181
  *
172
182
  * @param text - The raw field value, before any stemming or stop word removal.
173
- * @returns Each token with the character offset it starts at, which
174
- * highlighting and phrase matching rely on.
183
+ * @returns Each token with its ordinal position in the field, which the
184
+ * engine writes into postings when `trackPositions` is on, and which a
185
+ * prefix query reads to find the last typed word.
175
186
  */
176
187
  tokenize(text: string): Array<{
177
188
  token: string;
@@ -220,4 +231,4 @@ interface InsertOptions {
220
231
  skipClone?: boolean;
221
232
  }
222
233
 
223
- export type { AnyDocument as A, BM25Params as B, CustomTokenizer as C, EmbeddingFieldConfig as E, FieldType as F, IndexConfig as I, PartitionConfig as P, SchemaDefinition as S, VectorIndexConfig as V, InsertOptions as a, ScoringMode as b, StopWordOverride as c, VectorQuantizationMode as d };
234
+ export type { AnyDocument as A, BM25Params as B, CustomTokenizer as C, EmbeddingFieldConfig as E, FieldType as F, IndexConfig as I, PartitionConfig as P, SchemaDefinition as S, VectorIndexConfig as V, ScoringMode as a, InsertOptions as b, StopWordOverride as c, VectorQuantizationMode as d };
@@ -1,4 +1,4 @@
1
- import { A as AnyDocument, S as SchemaDefinition, b as ScoringMode } from './schema-ZRbk8BgH.js';
1
+ import { A as AnyDocument, S as SchemaDefinition, a as ScoringMode } from './schema-B7juWg8Q.js';
2
2
 
3
3
  /**
4
4
  * Every code a {@link NarsilError} carries, grouped by the part of the engine
@@ -12,7 +12,6 @@ import { A as AnyDocument, S as SchemaDefinition, b as ScoringMode } from './sch
12
12
  */
13
13
  declare const ErrorCodes: {
14
14
  readonly SCHEMA_INVALID_TYPE: "SCHEMA_INVALID_TYPE";
15
- readonly SCHEMA_MISSING_FIELD: "SCHEMA_MISSING_FIELD";
16
15
  readonly SCHEMA_DEPTH_EXCEEDED: "SCHEMA_DEPTH_EXCEEDED";
17
16
  readonly SCHEMA_INVALID_VECTOR_DIMENSION: "SCHEMA_INVALID_VECTOR_DIMENSION";
18
17
  readonly SCHEMA_INVALID_GEOPOINT: "SCHEMA_INVALID_GEOPOINT";
@@ -22,6 +21,7 @@ declare const ErrorCodes: {
22
21
  readonly INDEX_NOT_FOUND: "INDEX_NOT_FOUND";
23
22
  readonly INDEX_ALREADY_EXISTS: "INDEX_ALREADY_EXISTS";
24
23
  readonly INDEX_ORPHANED: "INDEX_ORPHANED";
24
+ readonly INDEX_REOPEN_CAPACITY_EXHAUSTED: "INDEX_REOPEN_CAPACITY_EXHAUSTED";
25
25
  readonly PARTITION_CORRUPTED: "PARTITION_CORRUPTED";
26
26
  readonly PARTITION_REBALANCING_BACKPRESSURE: "PARTITION_REBALANCING_BACKPRESSURE";
27
27
  readonly WORKER_CRASHED: "WORKER_CRASHED";
@@ -34,7 +34,6 @@ declare const ErrorCodes: {
34
34
  readonly PERSISTENCE_WAL_CORRUPT: "PERSISTENCE_WAL_CORRUPT";
35
35
  readonly PERSISTENCE_FSYNC_FAILED: "PERSISTENCE_FSYNC_FAILED";
36
36
  readonly SEARCH_INVALID_FIELD: "SEARCH_INVALID_FIELD";
37
- readonly SEARCH_INVALID_VECTOR_SIZE: "SEARCH_INVALID_VECTOR_SIZE";
38
37
  readonly VECTOR_DIMENSION_MISMATCH: "VECTOR_DIMENSION_MISMATCH";
39
38
  readonly SEARCH_INVALID_FILTER: "SEARCH_INVALID_FILTER";
40
39
  readonly SEARCH_INVALID_MODE: "SEARCH_INVALID_MODE";
@@ -58,8 +57,6 @@ declare const ErrorCodes: {
58
57
  readonly ALLOCATION_NO_DATA_NODES: "ALLOCATION_NO_DATA_NODES";
59
58
  readonly ALLOCATION_INVALID_CONFIG: "ALLOCATION_INVALID_CONFIG";
60
59
  readonly ALLOCATION_FAILED: "ALLOCATION_FAILED";
61
- readonly CONTROLLER_LEASE_LOST: "CONTROLLER_LEASE_LOST";
62
- readonly CONTROLLER_NOT_ACTIVE: "CONTROLLER_NOT_ACTIVE";
63
60
  readonly CONTROLLER_METADATA_INVALID: "CONTROLLER_METADATA_INVALID";
64
61
  readonly NODE_BOOTSTRAP_FAILED: "NODE_BOOTSTRAP_FAILED";
65
62
  readonly NODE_ALREADY_JOINED: "NODE_ALREADY_JOINED";
@@ -131,6 +128,7 @@ declare const ServerErrorCodes: {
131
128
  readonly TASK_NOT_FOUND: "TASK_NOT_FOUND";
132
129
  readonly TASK_NOT_CANCELLABLE: "TASK_NOT_CANCELLABLE";
133
130
  readonly TASK_OWNED_BY_ANOTHER_INSTANCE: "TASK_OWNED_BY_ANOTHER_INSTANCE";
131
+ readonly TASK_INTERRUPTED: "TASK_INTERRUPTED";
134
132
  readonly TOO_MANY_REQUESTS: "TOO_MANY_REQUESTS";
135
133
  readonly HOOK_ERROR: "HOOK_ERROR";
136
134
  readonly INTERNAL_ERROR: "INTERNAL_ERROR";
@@ -334,6 +332,10 @@ interface GroupResult {
334
332
  values: Record<string, unknown>;
335
333
  /** These hits fall in the group, cut to the query's `maxPerGroup`. */
336
334
  hits: Array<Hit>;
335
+ /** The query's reducer produced this value for the group, and only a query that set `group.reduce` carries it. */
336
+ reduced?: unknown;
337
+ /** The reducer threw, and this holds its message, so the group carries its hits and no `reduced` value. */
338
+ reducerError?: string;
337
339
  }
338
340
  /**
339
341
  * What {@link Narsil.preflight} returns: how many documents a query matches,
@@ -370,7 +372,7 @@ interface BatchResult {
370
372
  * @public
371
373
  */
372
374
  interface IndexStats {
373
- /** The index holds this many documents. */
375
+ /** The index holds this many documents. A closed index reports its count as of the last checkpoint. */
374
376
  documentCount: number;
375
377
  /** The index is spread across this many partitions. */
376
378
  partitionCount: number;
@@ -397,7 +399,7 @@ interface IndexStats {
397
399
  interface IndexInfo {
398
400
  /** The index was created under this name. */
399
401
  name: string;
400
- /** The index holds this many documents. */
402
+ /** The index holds this many documents. A closed index reports its count as of the last checkpoint. */
401
403
  documentCount: number;
402
404
  /** The index is spread across this many partitions. */
403
405
  partitionCount: number;
@@ -405,6 +407,10 @@ interface IndexInfo {
405
407
  language: string;
406
408
  /** This turns true when the index's terms came from an older analysis than its language module produces now. */
407
409
  analysisStale?: boolean;
410
+ /** This is `open` in memory, `closed` after release, and `reopen-failed` after five recovery failures. */
411
+ state: 'open' | 'closed' | 'reopen-failed';
412
+ /** This counts successful loads since this engine started. */
413
+ reopenCount: number;
408
414
  }
409
415
  /**
410
416
  * What {@link Narsil.getPartitionStats} reports for one partition, which is
@@ -483,6 +489,12 @@ interface MemoryStats {
483
489
  * `process.heapUsed` cannot tell engines apart.
484
490
  */
485
491
  estimatedIndexBytes: number;
492
+ /** This many indexes currently occupy engine memory. */
493
+ openIndexCount: number;
494
+ /** This many indexes remain registered without occupying engine memory, including parked recovery failures. */
495
+ closedIndexCount: number;
496
+ /** This counts successful index loads since this engine started. */
497
+ reopenCount: number;
486
498
  /**
487
499
  * Per-worker V8 heap usage when the engine has been promoted to a worker
488
500
  * pool. Empty when no workers are active.
@@ -752,7 +764,11 @@ interface QueryParams {
752
764
  boost?: Record<string, number>;
753
765
  /** The query gathers term statistics this way, and follows the index's `defaultScoring` otherwise. */
754
766
  scoring?: ScoringMode;
755
- /** The engine drops any hit scoring below this value. */
767
+ /**
768
+ * The engine drops any hit scoring below this value. It ranks with BM25,
769
+ * which has no fixed upper bound, so a floor that suits one index and one
770
+ * query can reject every hit in another.
771
+ */
756
772
  minScore?: number;
757
773
  /** A document has to carry this many query terms. The engine accepts one by default. */
758
774
  termMatch?: TermMatchPolicy;
@@ -769,7 +785,12 @@ interface QueryParams {
769
785
  * Off by default.
770
786
  */
771
787
  prefix?: boolean;
772
- /** Setting this matches the term as written, skipping stemming and fuzzy matching. */
788
+ /**
789
+ * Setting this requires every query term to equal an indexed term outright,
790
+ * which turns off fuzzy matching and prefix completion. The engine still
791
+ * stems the query, because the index stores stemmed terms, so `running`
792
+ * matches a document that said `running` through their shared stem.
793
+ */
773
794
  exact?: boolean;
774
795
  /** These settings name the fields the query counts values for, and control how each count is cut and sorted. */
775
796
  facets?: FacetConfig;
@@ -931,6 +952,8 @@ interface GroupConfig {
931
952
  fields: string[];
932
953
  /** Each group keeps this many hits, and one by default, which is the collapse behaviour. */
933
954
  maxPerGroup?: number;
955
+ /** The result keeps this many groups, best first, and every group without it. */
956
+ limit?: number;
934
957
  /** This folds each group's hits into one value, such as a sum or an average. */
935
958
  reduce?: GroupReducer;
936
959
  }
@@ -957,8 +980,9 @@ type GroupReducer = {
957
980
  * Which fields a query returns highlighted snippets for, and how those
958
981
  * snippets are marked up.
959
982
  *
960
- * The index has to have been created with `trackPositions`, because
961
- * highlighting reads the positions that setting records.
983
+ * The highlighter re-analyses each returned field's text and marks the spans
984
+ * whose stems match the query, so it works whatever the index's
985
+ * `trackPositions` setting says.
962
986
  *
963
987
  * @public
964
988
  */
package/dist/server.d.ts CHANGED
@@ -1,14 +1,14 @@
1
- import { b as ServerOptions, N as NarsilServer } from './options-EXYFcem-.js';
2
- export { A as ASYNC_IMPORT_CAPABILITY, C as CorsOptions, E as ErrorEnvelope, O as OnRequestHook, R as REBUILD_ANALYSIS_CAPABILITY, c as RequestContext, d as RequestDenial, S as SERVER_CAPABILITIES, e as ServerLimits, T as TASK_CANCEL_CAPABILITY, a as TASK_FILTER_CAPABILITY } from './options-EXYFcem-.js';
3
- import { a as Narsil } from './engine-BE45D5ZG.js';
4
- import { h as TaskStore, e as TaskRecord, d as TaskProgress, b as ImportResult } from './tasks-CnMLpfk-.js';
5
- export { C as CapabilitiesResponse, a as CreateIndexEmbedding, i as CreateIndexRequest, H as HttpIndexConfig, I as ImportError, T as TaskListPage, c as TaskListQuery, f as TaskStatus, g as TaskType } from './tasks-CnMLpfk-.js';
6
- export { d as ServerErrorCodes } from './search-DHuXwJYk.js';
7
- import './config-fLC4lbmg.js';
8
- import './config-Byyl1QqH.js';
1
+ import { b as ServerOptions, N as NarsilServer } from './options-BC68VPoE.js';
2
+ export { A as ASYNC_IMPORT_CAPABILITY, C as CorsOptions, E as ErrorEnvelope, I as INDEX_LIFECYCLE_CAPABILITY, O as OnRequestHook, R as REBUILD_ANALYSIS_CAPABILITY, c as RequestContext, d as RequestDenial, S as SERVER_CAPABILITIES, e as ServerLimits, T as TASK_CANCEL_CAPABILITY, a as TASK_FILTER_CAPABILITY } from './options-BC68VPoE.js';
3
+ import { a as Narsil } from './engine-Cjr1uBLa.js';
4
+ import { h as TaskStore, e as TaskRecord, d as TaskProgress, b as ImportResult } from './tasks-Bn4R1NPN.js';
5
+ export { C as CapabilitiesResponse, a as CreateIndexEmbedding, i as CreateIndexRequest, H as HttpIndexConfig, I as ImportError, T as TaskListPage, c as TaskListQuery, f as TaskStatus, g as TaskType } from './tasks-Bn4R1NPN.js';
6
+ export { d as ServerErrorCodes } from './search-DDHjfXhJ.js';
7
+ import './config-B-ZI-ft5.js';
8
+ import './config-BZRExglL.js';
9
9
  import './adapters-79OIa4xm.js';
10
- import './schema-ZRbk8BgH.js';
11
- import './types-B5Tsaalz.js';
10
+ import './schema-B7juWg8Q.js';
11
+ import './types-DsSSjY4d.js';
12
12
  import './types-D5OwhtsQ.js';
13
13
 
14
14
  /**
package/dist/server.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { validateIndexName } from './chunk-WU2UZEVD.mjs';
2
- import { ServerErrorCodes, NarsilError, ErrorCodes } from './chunk-GB2IIJJG.mjs';
3
- export { ServerErrorCodes } from './chunk-GB2IIJJG.mjs';
1
+ import { validateIndexName } from './chunk-XWICBGYT.mjs';
2
+ import { ServerErrorCodes, NarsilError, ErrorCodes } from './chunk-P4ELXVJQ.mjs';
3
+ export { ServerErrorCodes } from './chunk-P4ELXVJQ.mjs';
4
4
  import { randomUUID } from 'crypto';
5
5
 
6
6
  // src/server/capabilities.ts
@@ -8,11 +8,13 @@ var ASYNC_IMPORT_CAPABILITY = "documents.import.async";
8
8
  var TASK_CANCEL_CAPABILITY = "tasks.cancel";
9
9
  var TASK_FILTER_CAPABILITY = "tasks.filter";
10
10
  var REBUILD_ANALYSIS_CAPABILITY = "indexes.rebuildAnalysis";
11
+ var INDEX_LIFECYCLE_CAPABILITY = "indexes.lifecycle";
11
12
  var SERVER_CAPABILITIES = [
12
13
  ASYNC_IMPORT_CAPABILITY,
13
14
  TASK_CANCEL_CAPABILITY,
14
15
  TASK_FILTER_CAPABILITY,
15
- REBUILD_ANALYSIS_CAPABILITY
16
+ REBUILD_ANALYSIS_CAPABILITY,
17
+ INDEX_LIFECYCLE_CAPABILITY
16
18
  ];
17
19
 
18
20
  // src/server/cors.ts
@@ -52,20 +54,19 @@ var STATUS_BY_CODE = {
52
54
  TASK_NOT_FOUND: 404,
53
55
  TASK_NOT_CANCELLABLE: 409,
54
56
  TASK_OWNED_BY_ANOTHER_INSTANCE: 409,
57
+ TASK_INTERRUPTED: 503,
55
58
  TOO_MANY_REQUESTS: 429,
56
59
  HOOK_ERROR: 500,
57
60
  INTERNAL_ERROR: 500,
58
61
  ENVELOPE_INVALID_MAGIC: 400,
59
62
  ENVELOPE_VERSION_MISMATCH: 400,
60
63
  SCHEMA_INVALID_TYPE: 400,
61
- SCHEMA_MISSING_FIELD: 400,
62
64
  SCHEMA_DEPTH_EXCEEDED: 400,
63
65
  SCHEMA_INVALID_VECTOR_DIMENSION: 400,
64
66
  SCHEMA_INVALID_GEOPOINT: 400,
65
67
  DOC_VALIDATION_FAILED: 400,
66
68
  DOC_MISSING_REQUIRED_FIELD: 400,
67
69
  SEARCH_INVALID_FIELD: 400,
68
- SEARCH_INVALID_VECTOR_SIZE: 400,
69
70
  VECTOR_DIMENSION_MISMATCH: 400,
70
71
  SEARCH_INVALID_FILTER: 400,
71
72
  SEARCH_INVALID_MODE: 400,
@@ -80,6 +81,7 @@ var STATUS_BY_CODE = {
80
81
  DOC_NOT_FOUND: 404,
81
82
  INDEX_ALREADY_EXISTS: 409,
82
83
  INDEX_ORPHANED: 409,
84
+ INDEX_REOPEN_CAPACITY_EXHAUSTED: 503,
83
85
  DOC_ALREADY_EXISTS: 409,
84
86
  PARTITION_REBALANCING_BACKPRESSURE: 409,
85
87
  PARTITION_CAPACITY_EXCEEDED: 409,
@@ -114,8 +116,6 @@ var STATUS_BY_CODE = {
114
116
  ALLOCATION_INVALID_CONFIG: 400,
115
117
  ALLOCATION_NO_DATA_NODES: 503,
116
118
  ALLOCATION_FAILED: 503,
117
- CONTROLLER_LEASE_LOST: 503,
118
- CONTROLLER_NOT_ACTIVE: 503,
119
119
  NODE_ALREADY_JOINED: 409,
120
120
  NODE_NOT_JOINED: 503,
121
121
  NODE_NOT_READY: 503,
@@ -309,7 +309,7 @@ function validateQuery(params, maxWindow) {
309
309
  const rowBound = overWindow("limit", params.limit, maxWindow) ?? overWindow("offset", params.offset, maxWindow);
310
310
  if (rowBound) return rowBound;
311
311
  if (params.group && typeof params.group === "object") {
312
- const grouped = overWindow("group.maxPerGroup", params.group.maxPerGroup, maxWindow);
312
+ const grouped = overWindow("group.maxPerGroup", params.group.maxPerGroup, maxWindow) ?? overWindow("group.limit", params.group.limit, maxWindow);
313
313
  if (grouped) return grouped;
314
314
  }
315
315
  if (params.facets && typeof params.facets === "object") {
@@ -1151,7 +1151,23 @@ function createIndexHandlers(deps) {
1151
1151
  respondError(ctx, err);
1152
1152
  }
1153
1153
  }
1154
- return { create, list, drop, stats, partitions, clear };
1154
+ async function open(ctx) {
1155
+ try {
1156
+ await engine.open(ctx.params[0]);
1157
+ respondJson(ctx, { name: ctx.params[0], state: "open" });
1158
+ } catch (err) {
1159
+ respondError(ctx, err);
1160
+ }
1161
+ }
1162
+ async function close(ctx) {
1163
+ try {
1164
+ await engine.close(ctx.params[0]);
1165
+ respondJson(ctx, { name: ctx.params[0], state: "closed" });
1166
+ } catch (err) {
1167
+ respondError(ctx, err);
1168
+ }
1169
+ }
1170
+ return { create, list, drop, stats, partitions, clear, open, close };
1155
1171
  }
1156
1172
 
1157
1173
  // src/server/handlers/search.ts
@@ -1559,7 +1575,7 @@ var TaskRegistry = class {
1559
1575
  ...record,
1560
1576
  status: "failed",
1561
1577
  completedAt: Date.now(),
1562
- error: { code: "TASK_INTERRUPTED", message: "The server restarted while this task was running" }
1578
+ error: { code: ServerErrorCodes.TASK_INTERRUPTED, message: "The server restarted while this task was running" }
1563
1579
  };
1564
1580
  try {
1565
1581
  await this.store.set(failed, TERMINAL_TTL_MS);
@@ -1745,6 +1761,8 @@ var NarsilHttpServer = class {
1745
1761
  app.get("/indexes/:name/partitions", json(idx.partitions, { paramCount: 1, maxBytes: 0 }));
1746
1762
  app.get("/indexes/:name/cluster", json(cluster.allocation, { paramCount: 1, maxBytes: 0 }));
1747
1763
  app.post("/indexes/:name/_clear", json(idx.clear, { paramCount: 1, maxBytes: 0 }));
1764
+ app.post("/indexes/:name/_open", json(idx.open, { paramCount: 1, maxBytes: 0 }));
1765
+ app.post("/indexes/:name/_close", json(idx.close, { paramCount: 1, maxBytes: 0 }));
1748
1766
  app.get("/indexes/:name/count", json(doc.count, { paramCount: 1, maxBytes: 0 }));
1749
1767
  app.post("/indexes/:name/documents", json(doc.insert, { paramCount: 1, needsBody: true, maxBytes: maxBodyBytes }));
1750
1768
  app.post(
@@ -1810,4 +1828,4 @@ function createServer(engine, options) {
1810
1828
  return new NarsilHttpServer(engine, options);
1811
1829
  }
1812
1830
 
1813
- export { ASYNC_IMPORT_CAPABILITY, InMemoryTaskStore, REBUILD_ANALYSIS_CAPABILITY, SERVER_CAPABILITIES, TASK_CANCEL_CAPABILITY, TASK_FILTER_CAPABILITY, createServer, httpStatusForNarsilError };
1831
+ export { ASYNC_IMPORT_CAPABILITY, INDEX_LIFECYCLE_CAPABILITY, InMemoryTaskStore, REBUILD_ANALYSIS_CAPABILITY, SERVER_CAPABILITIES, TASK_CANCEL_CAPABILITY, TASK_FILTER_CAPABILITY, createServer, httpStatusForNarsilError };
@@ -54,7 +54,7 @@ interface HttpIndexConfig {
54
54
  };
55
55
  /** This list replaces the language's stop words. */
56
56
  stopWords?: string[];
57
- /** Setting this records term positions, which phrase queries and highlighting need. */
57
+ /** Setting this records term positions in each posting, which the `.nrsl` format carries for readers that match phrases. Highlighting works without it. */
58
58
  trackPositions?: boolean;
59
59
  /** Setting this to false returns index stems from suggestions and prefix expansion, instead of the words users typed. */
60
60
  surfaceForms?: boolean;
@@ -1,4 +1,4 @@
1
- import { S as SchemaDefinition } from './schema-ZRbk8BgH.js';
1
+ import { S as SchemaDefinition } from './schema-B7juWg8Q.js';
2
2
 
3
3
  /**
4
4
  * What a node does in a cluster. A node may hold several roles at once.
@@ -1,5 +1,5 @@
1
1
  import { isValidWorkerAction } from '../chunk-WTONLDU3.mjs';
2
- import { NarsilError, ErrorCodes } from '../chunk-GB2IIJJG.mjs';
2
+ import { NarsilError, ErrorCodes } from '../chunk-P4ELXVJQ.mjs';
3
3
 
4
4
  // src/workers/action-handler.ts
5
5
  function buildErrorResponse(requestId, code, message) {
@@ -55,7 +55,7 @@ async function setup() {
55
55
  } catch {
56
56
  parentPort = null;
57
57
  }
58
- const { createDirectExecutor } = await import('../direct-executor-MSJEVPZU.mjs');
58
+ const { createDirectExecutor } = await import('../direct-executor-IMXNRS7O.mjs');
59
59
  const handleAction = createActionHandler(createDirectExecutor());
60
60
  if (parentPort) {
61
61
  const port = parentPort;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@delali/narsil",
3
- "version": "0.2.4-next.42",
3
+ "version": "0.2.4-next.44",
4
4
  "type": "module",
5
5
  "description": "A distributed full-text search engine with cross-language portable binary format.",
6
6
  "author": "Delali (https://sondelali.com)",