@delali/narsil 0.3.1-next.72 → 0.3.1-next.74

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +2 -2
  2. package/dist/adapters/filesystem.mjs +1 -1
  3. package/dist/adapters/indexeddb.mjs +1 -1
  4. package/dist/{capabilities-D6gjjQyA.d.ts → capabilities-CAMzmkAg.d.ts} +19 -4
  5. package/dist/{chunk-P2ZZN32C.mjs → chunk-2E35UM3G.mjs} +2 -12
  6. package/dist/chunk-3DDUNI6N.mjs +48 -0
  7. package/dist/{chunk-KZTI25D3.mjs → chunk-4MQ5F4IL.mjs} +1 -1
  8. package/dist/{chunk-HVJYTKK7.mjs → chunk-BVBIQQKG.mjs} +947 -1327
  9. package/dist/{chunk-2X2ZQOAB.mjs → chunk-CTOSGRM7.mjs} +101 -21
  10. package/dist/{chunk-7QMTA7AA.mjs → chunk-CUZOX6CN.mjs} +7784 -4276
  11. package/dist/chunk-I23G3IZC.mjs +593 -0
  12. package/dist/{chunk-RV77FR2F.mjs → chunk-I64LXKO3.mjs} +0 -1
  13. package/dist/chunk-KEHK2O6P.mjs +13 -0
  14. package/dist/{chunk-CVPA5Q7R.mjs → chunk-LX4JERXI.mjs} +9 -6
  15. package/dist/{chunk-EDMCZLSJ.mjs → chunk-NOZUQM7J.mjs} +193 -13
  16. package/dist/{chunk-LCCL6EEH.mjs → chunk-PO53FV4Q.mjs} +93 -94
  17. package/dist/chunk-T5ZWEWVD.mjs +658 -0
  18. package/dist/{chunk-Y52WZWAU.mjs → chunk-TVFLHM7M.mjs} +4 -4
  19. package/dist/{chunk-QR4OKRVY.mjs → chunk-VKX2BPXD.mjs} +147 -642
  20. package/dist/{chunk-3HQPUCCT.mjs → chunk-XW25X6AU.mjs} +66 -237
  21. package/dist/{chunk-M6XF5HDE.mjs → chunk-Z3DQPOJQ.mjs} +127 -30
  22. package/dist/{client-C2TiW29y.d.ts → client-C-I70ArH.d.ts} +77 -26
  23. package/dist/client.d.ts +9 -9
  24. package/dist/client.mjs +44 -22
  25. package/dist/{config-BLguB-om.d.ts → config-C6Iw5rCX.d.ts} +11 -4
  26. package/dist/{config-C7Ip8Ife.d.ts → config-DJPH3IQB.d.ts} +11 -2
  27. package/dist/direct-executor-KFAGILJC.mjs +17 -0
  28. package/dist/distribution/coordinator/etcd.d.ts +29 -16
  29. package/dist/distribution/coordinator/etcd.mjs +162 -75
  30. package/dist/distribution/coordinator/in-memory.d.ts +2 -2
  31. package/dist/distribution/transport/grpc.d.ts +2 -2
  32. package/dist/distribution/transport/grpc.mjs +22 -2
  33. package/dist/distribution/transport/in-memory.d.ts +2 -2
  34. package/dist/distribution/transport/in-memory.mjs +6 -3
  35. package/dist/distribution/transport/tcp.d.ts +2 -2
  36. package/dist/distribution/transport/tcp.mjs +40 -16
  37. package/dist/distribution.d.ts +9 -9
  38. package/dist/distribution.mjs +647 -366
  39. package/dist/embeddings/openai.mjs +1 -1
  40. package/dist/{engine-Dm4446j1.d.ts → engine-B8eRPO7m.d.ts} +97 -188
  41. package/dist/index.browser.mjs +12132 -8592
  42. package/dist/index.d.ts +27 -8
  43. package/dist/index.mjs +15 -14
  44. package/dist/{memory-CKHTU1CL.d.ts → memory-DJEwWoCi.d.ts} +1204 -968
  45. package/dist/partial-words-DTIHO8G4.d.ts +19 -0
  46. package/dist/partial-words.d.ts +22 -0
  47. package/dist/partial-words.mjs +11 -0
  48. package/dist/pattern.mjs +1 -1
  49. package/dist/persistence/durability/checkpoint-worker.d.ts +57 -29
  50. package/dist/persistence/durability/checkpoint-worker.mjs +26 -16
  51. package/dist/react.d.ts +7 -7
  52. package/dist/react.mjs +0 -1
  53. package/dist/{schema-BBOCdhND.d.ts → schema-DgyDijhf.d.ts} +6 -2
  54. package/dist/server.d.ts +11 -11
  55. package/dist/server.mjs +212 -32
  56. package/dist/{tasks-BECd0b__.d.ts → tasks-BVmAKYBh.d.ts} +3 -3
  57. package/dist/{thread-IBSIZZ6W.mjs → thread-W6DPKEF6.mjs} +82 -21
  58. package/dist/{types-BQDlIvfS.d.ts → types-B3b68nfF.d.ts} +1 -1
  59. package/dist/{types-D5OwhtsQ.d.ts → types-Cb9kiY5P.d.ts} +1 -1
  60. package/dist/{types-BiUmaiWT.d.ts → types-ChrVy4lH.d.ts} +1 -1
  61. package/dist/vector/search-worker.d.ts +1 -1
  62. package/dist/vector/search-worker.mjs +4 -3
  63. package/dist/workers/entry.mjs +4 -4
  64. package/package.json +15 -7
  65. package/dist/chunk-3L4U6EJQ.mjs +0 -49
  66. package/dist/chunk-IFBKLBGB.mjs +0 -7
  67. package/dist/chunk-XZ4PAREY.mjs +0 -25
  68. package/dist/direct-executor-SVCHXR74.mjs +0 -14
  69. package/dist/serialization/crc32-worker.d.ts +0 -20
  70. package/dist/serialization/crc32-worker.mjs +0 -62
@@ -1,9 +1,10 @@
1
- import { MAX_INDEX_NAME_LENGTH, INDEX_NAME_PATTERN, MAX_DOC_ID_LENGTH, DEFAULT_LIMIT, DEFAULT_SUGGEST_LIMIT, MAX_SUGGEST_LIMIT, MAX_SUGGEST_SCATTER_LIMIT, ABSOLUTE_WINDOWS_PATH_PATTERN, MODULE_URL_SCHEME_PATTERN, DEFAULT_OFFSET } from './chunk-XZ4PAREY.mjs';
2
- import { clampRowCount, sortSignatureOf, requireSortableFields, decodePageCursor, requireMatchingCursor, resolveProjection, encodePageCursor, requireWithinResultWindow, normalizeSort, fanOutQuery, sortModesOf, applySorting, applyPagination, projectionKeepsField, countsWithoutScores, fanOutMatchCount, tokenize, fnv1aBytes, requireValidFilter, createPatternWorkMeter, everyValueFacetConfig, fulltextMatches, mergeFacets, pruneStatsToQueryTerms, partitionsIn, undeclaredFieldOnStrictIndex, fuzzyTermMatches } from './chunk-QR4OKRVY.mjs';
3
- import { MIN_PATTERN_VALUE_LIMIT, MAX_PATTERN_VALUE_LIMIT, DEFAULT_MAX_PER_GROUP, flattenSchema, DEFAULT_LINEAR_ALPHA, MIN_LINEAR_ALPHA, MAX_LINEAR_ALPHA, DEFAULT_RANK_CONSTANT, MIN_RANK_CONSTANT, DEFAULT_FUZZY_PREFIX_LENGTH, RESULT_WINDOW, isWordIndexedFieldType, isGeopointOrVectorType, MAX_TOLERANCE, MAX_PREFIX_LENGTH } from './chunk-M6XF5HDE.mjs';
1
+ import { clampRowCount, sortSignatureOf, requireSortableFields, decodePageCursor, requireMatchingCursor, resolveProjection, encodePageCursor, requireWithinResultWindow, normalizeSort, fanOutQuery, sortModesOf, applySorting, applyPagination, projectionKeepsField, countsWithoutScores, fanOutMatchCount, fnv1aBytes, requireValidFilter, createPatternWorkMeter, everyValueFacetConfig, fulltextMatches, mergeFacets, pruneStatsToQueryTerms, partitionsIn, undeclaredFieldOnStrictIndex } from './chunk-VKX2BPXD.mjs';
2
+ import { MAX_INDEX_NAME_LENGTH, INDEX_NAME_PATTERN, MAX_DOC_ID_LENGTH, DEFAULT_LIMIT, DEFAULT_MAX_PER_GROUP, DEFAULT_SUGGEST_LIMIT, MAX_SUGGEST_LIMIT, MAX_SUGGEST_SCATTER_LIMIT, ABSOLUTE_WINDOWS_PATH_PATTERN, MODULE_URL_SCHEME_PATTERN, DEFAULT_LINEAR_ALPHA, MIN_LINEAR_ALPHA, MAX_LINEAR_ALPHA, DEFAULT_RANK_CONSTANT, MIN_RANK_CONSTANT, DEFAULT_OFFSET, DEFAULT_FUZZY_PREFIX_LENGTH, RESULT_WINDOW, PARTIAL_WORD_MIN_CODE_POINTS, PARTIAL_WORDS_ADDED_PER_QUERY, MAX_TOLERANCE, MAX_PREFIX_LENGTH } from './chunk-3DDUNI6N.mjs';
4
3
  import { MIN_OVERSAMPLE } from './chunk-ZJ4CSAB2.mjs';
5
- import { holdsUnpairedSurrogate, compareCodePoints, compareComparableKeys } from './chunk-LJYTW7GT.mjs';
6
- import { NarsilError, ErrorCodes } from './chunk-RV77FR2F.mjs';
4
+ import { tokenize, fuzzyTermMatches } from './chunk-I23G3IZC.mjs';
5
+ import { partialFieldsOf, MIN_PATTERN_VALUE_LIMIT, MAX_PATTERN_VALUE_LIMIT, flattenSchema, isWordIndexedFieldType, isGeopointOrVectorType } from './chunk-Z3DQPOJQ.mjs';
6
+ import { holdsUnpairedSurrogate, compareCodePoints, compareComparableKeys, codePointCount } from './chunk-LJYTW7GT.mjs';
7
+ import { NarsilError, ErrorCodes } from './chunk-I64LXKO3.mjs';
7
8
 
8
9
  // src/search/cursor-binding.ts
9
10
  var ABSENT_TAG = 0;
@@ -130,7 +131,7 @@ function boundVectorOf(vector) {
130
131
  return bound;
131
132
  }
132
133
  var FILTERS_SLOT = 2;
133
- var BOUND_SLOT_COUNT = 15;
134
+ var BOUND_SLOT_COUNT = 16;
134
135
  function bindingOf(values) {
135
136
  const stream = { bytes: new Uint8Array(256), length: 0 };
136
137
  for (const value of values) {
@@ -149,6 +150,7 @@ function queryBindingOf(params) {
149
150
  params.tolerance,
150
151
  params.prefixLength,
151
152
  params.prefix,
153
+ params.partialWords,
152
154
  params.exact,
153
155
  params.pinned,
154
156
  params.mode,
@@ -317,9 +319,18 @@ function requireKnownMode(params) {
317
319
  { mode: String(params.mode), modes: [...SEARCH_MODES] }
318
320
  );
319
321
  }
322
+ function requireBooleanPartialWords(params) {
323
+ const setting = params.partialWords;
324
+ if (setting === void 0 || typeof setting === "boolean") return;
325
+ throw new NarsilError(ErrorCodes.CONFIG_INVALID, 'The "partialWords" query option takes true or false', {
326
+ option: "partialWords",
327
+ received: setting === null ? "null" : typeof setting
328
+ });
329
+ }
320
330
  function requireValidQueryOptions(params, config) {
321
331
  const strict = config.strict === true;
322
332
  requireValidTypoTolerance(params);
333
+ requireBooleanPartialWords(params);
323
334
  requireSortableFields(params.sort, config.schema, strict);
324
335
  requireValidQueryFilter(params.filters, config.schema);
325
336
  requireUsableQueryFields(params, config.schema, strict);
@@ -425,6 +436,16 @@ function validatePartitionConfig(partitions) {
425
436
  });
426
437
  }
427
438
  }
439
+ function requireSurfaceFormsForPartialFields(schema, surfaceForms) {
440
+ if (surfaceForms !== false) return;
441
+ const partialFields = partialFieldsOf(schema);
442
+ if (partialFields.length === 0) return;
443
+ throw new NarsilError(
444
+ ErrorCodes.CONFIG_INVALID,
445
+ `Field "${partialFields[0]}" declares "partial", which compares words as the documents wrote them, so its index needs surfaceForms left on`,
446
+ { fields: [...partialFields], surfaceForms: false }
447
+ );
448
+ }
428
449
  function validatePatternValueLimit(limit) {
429
450
  if (limit === void 0) return;
430
451
  if (typeof limit !== "number" || !Number.isInteger(limit) || limit < MIN_PATTERN_VALUE_LIMIT || limit > MAX_PATTERN_VALUE_LIMIT) {
@@ -814,6 +835,31 @@ function applySnippetTruncation(taggedText, originalText, positions, maxLen, pre
814
835
  if (needsTrailingEllipsis) snippet = `${snippet}...`;
815
836
  return { snippet, visiblePositions };
816
837
  }
838
+ function containsPartialWord(spelling, words) {
839
+ for (const word of words) {
840
+ if (spelling.length > word.length && spelling.includes(word)) return true;
841
+ }
842
+ return false;
843
+ }
844
+ function partialWordMatcher(text, language, partial) {
845
+ const indexed = tokenize(text, language, {
846
+ stem: true,
847
+ removeStopWords: true,
848
+ collectSurfaces: true,
849
+ customTokenizer: partial.customTokenizer,
850
+ stopWordOverride: partial.stopWordOverride
851
+ });
852
+ const positions = /* @__PURE__ */ new Set();
853
+ const spellings = /* @__PURE__ */ new Set();
854
+ for (let at = 0; at < indexed.tokens.length; at++) {
855
+ const spelling = indexed.surfaces?.[at] ?? indexed.tokens[at].token;
856
+ if (!containsPartialWord(spelling, partial.words)) continue;
857
+ positions.add(indexed.tokens[at].position);
858
+ spellings.add(spelling);
859
+ }
860
+ if (partial.customTokenizer !== void 0) return (_position, fieldToken) => spellings.has(fieldToken);
861
+ return (position) => positions.has(position);
862
+ }
817
863
  function highlightField(text, queryTokens, language, options) {
818
864
  const preTag = options?.preTag ?? "<mark>";
819
865
  const postTag = options?.postTag ?? "</mark>";
@@ -850,11 +896,13 @@ function highlightField(text, queryTokens, language, options) {
850
896
  matchByFieldToken.set(fieldToken, matches);
851
897
  return matches;
852
898
  };
899
+ const matchesInside = options?.partialWords === void 0 ? null : partialWordMatcher(text, language, options.partialWords);
853
900
  for (let i = 0; i < fieldResult.tokens.length; i++) {
854
901
  if (i >= charOffsets.length) break;
855
902
  const fieldToken = fieldResult.tokens[i].token;
856
903
  const prefixMatch = prefixToken !== void 0 && fieldToken.startsWith(prefixToken);
857
- if (prefixMatch || matchesQuery(fieldToken)) {
904
+ const insideMatch = matchesInside?.(fieldResult.tokens[i].position, fieldToken) === true;
905
+ if (prefixMatch || insideMatch || matchesQuery(fieldToken)) {
858
906
  matchedRanges.push({ start: charOffsets[i].start, end: charOffsets[i].end });
859
907
  }
860
908
  }
@@ -886,7 +934,39 @@ function highlightField(text, queryTokens, language, options) {
886
934
  }
887
935
 
888
936
  // src/engine/query/highlight.ts
889
- function applyHighlights(hits, params, language, analysis, readStoredDocument) {
937
+ function writtenWordsOf(params, language, analysis) {
938
+ return tokenize(params.term ?? "", language, {
939
+ stem: false,
940
+ removeStopWords: true,
941
+ customTokenizer: analysis.customTokenizer,
942
+ stopWordOverride: analysis.stopWords
943
+ }).tokens;
944
+ }
945
+ function partialWordTagging(params, schema, queryTokens, written, analysis) {
946
+ if (params.partialWords !== true || params.exact === true) return null;
947
+ const fields = partialFieldsOf(schema).filter((field) => params.fields === void 0 || params.fields.includes(field));
948
+ if (fields.length === 0) return null;
949
+ const writtenAt = /* @__PURE__ */ new Map();
950
+ for (const word of written) {
951
+ if (!writtenAt.has(word.position)) writtenAt.set(word.position, word.token);
952
+ }
953
+ const seenTokens = /* @__PURE__ */ new Set();
954
+ const words = [];
955
+ for (const queryToken of queryTokens) {
956
+ if (seenTokens.has(queryToken.token)) continue;
957
+ seenTokens.add(queryToken.token);
958
+ const word = writtenAt.get(queryToken.position);
959
+ if (word === void 0 || codePointCount(word) < PARTIAL_WORD_MIN_CODE_POINTS) continue;
960
+ words.push(word);
961
+ if (words.length === PARTIAL_WORDS_ADDED_PER_QUERY) break;
962
+ }
963
+ if (words.length === 0) return null;
964
+ return {
965
+ fields: new Set(fields),
966
+ highlight: { words, customTokenizer: analysis.customTokenizer, stopWordOverride: analysis.stopWords }
967
+ };
968
+ }
969
+ function applyHighlights(hits, params, language, analysis, schema, readStoredDocument) {
890
970
  if (!params.highlight) return;
891
971
  const queryTokenResult = tokenize(params.term ?? "", language, {
892
972
  stem: true,
@@ -894,17 +974,15 @@ function applyHighlights(hits, params, language, analysis, readStoredDocument) {
894
974
  customTokenizer: analysis.customTokenizer,
895
975
  stopWordOverride: analysis.stopWords
896
976
  });
977
+ const queryTokens = queryTokenResult.tokens;
978
+ const usesPrefix = params.prefix === true && params.exact !== true && queryTokens.length > 0;
979
+ const usesPartialWords = params.partialWords === true && params.exact !== true && queryTokens.length > 0;
980
+ const written = usesPrefix || usesPartialWords ? writtenWordsOf(params, language, analysis) : [];
897
981
  let prefixToken;
898
982
  let completedToken;
899
- if (params.prefix === true && params.exact !== true && queryTokenResult.tokens.length > 0) {
900
- const lastToken = queryTokenResult.tokens[queryTokenResult.tokens.length - 1];
901
- const unstemmed = tokenize(params.term ?? "", language, {
902
- stem: false,
903
- removeStopWords: true,
904
- customTokenizer: analysis.customTokenizer,
905
- stopWordOverride: analysis.stopWords
906
- });
907
- for (const t of unstemmed.tokens) {
983
+ if (usesPrefix) {
984
+ const lastToken = queryTokens[queryTokens.length - 1];
985
+ for (const t of written) {
908
986
  if (t.position === lastToken.position) {
909
987
  prefixToken = t.token;
910
988
  completedToken = lastToken.token;
@@ -912,6 +990,7 @@ function applyHighlights(hits, params, language, analysis, readStoredDocument) {
912
990
  }
913
991
  }
914
992
  }
993
+ const partialWords = usesPartialWords ? partialWordTagging(params, schema, queryTokens, written, analysis) : null;
915
994
  for (const hit of hits) {
916
995
  const highlights = {};
917
996
  const projected = hit.document;
@@ -923,14 +1002,15 @@ function applyHighlights(hits, params, language, analysis, readStoredDocument) {
923
1002
  fieldValue = stored?.[field];
924
1003
  }
925
1004
  if (typeof fieldValue === "string") {
926
- highlights[field] = highlightField(fieldValue, queryTokenResult.tokens, language, {
1005
+ highlights[field] = highlightField(fieldValue, queryTokens, language, {
927
1006
  preTag: params.highlight.preTag,
928
1007
  postTag: params.highlight.postTag,
929
1008
  maxSnippetLength: params.highlight.maxSnippetLength,
930
1009
  prefixToken,
931
1010
  completedToken,
932
1011
  tolerance: params.exact === true ? 0 : params.tolerance ?? 0,
933
- prefixLength: params.prefixLength ?? DEFAULT_FUZZY_PREFIX_LENGTH
1012
+ prefixLength: params.prefixLength ?? DEFAULT_FUZZY_PREFIX_LENGTH,
1013
+ partialWords: partialWords?.fields.has(field) === true ? partialWords.highlight : void 0
934
1014
  });
935
1015
  }
936
1016
  }
@@ -1440,7 +1520,7 @@ async function executeQuery(params, callerContext) {
1440
1520
  if (params.highlight) {
1441
1521
  const dropped = params.highlight.fields.some((field) => !projectionKeepsField(projection, field));
1442
1522
  const readStoredDocument = dropped ? (docId) => manager.get(docId, { kind: "full" }) : void 0;
1443
- applyHighlights(paginated, params, language, manager.analysis, readStoredDocument);
1523
+ applyHighlights(paginated, params, language, manager.analysis, manager.schema, readStoredDocument);
1444
1524
  }
1445
1525
  const elapsed = now() - startTime;
1446
1526
  return {
@@ -1558,4 +1638,4 @@ function pickDisplaySurface(surfaceOccurrences) {
1558
1638
  return best;
1559
1639
  }
1560
1640
 
1561
- export { clampLimit, dedupePinnedEntries, executeListDocuments, executePreflight, executeQuery, executeSuggest, foldGroupReducer, hitsKeptPerGroup, listBindingOf, now, queryBindingOf, resolveHybridFusion, validateBM25Params, validateDocId, validateIndexName, validatePartitionConfig, validatePatternValueLimit, validateWorkerConfig };
1641
+ export { clampLimit, dedupePinnedEntries, executeListDocuments, executePreflight, executeQuery, executeSuggest, foldGroupReducer, hitsKeptPerGroup, listBindingOf, now, queryBindingOf, requireSurfaceFormsForPartialFields, resolveHybridFusion, validateBM25Params, validateDocId, validateIndexName, validatePartitionConfig, validatePatternValueLimit, validateWorkerConfig };