@delali/narsil 0.2.4-next.51 → 0.2.4-next.54

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 (64) hide show
  1. package/README.md +33 -27
  2. package/dist/adapters/filesystem.mjs +1 -1
  3. package/dist/adapters/indexeddb.mjs +1 -1
  4. package/dist/{capabilities-BWm4IITU.d.ts → capabilities-DlYw0Ov0.d.ts} +13 -2
  5. package/dist/{chunk-KMMJMDUA.mjs → chunk-3L4U6EJQ.mjs} +15 -10
  6. package/dist/chunk-4NVPQ6S5.mjs +366 -0
  7. package/dist/{chunk-CMVG2UEF.mjs → chunk-5T6AOR37.mjs} +56 -518
  8. package/dist/{chunk-ND34I3SV.mjs → chunk-BH5SYB5W.mjs} +3295 -2149
  9. package/dist/{chunk-XE6XR2OE.mjs → chunk-D2S642IV.mjs} +4 -2
  10. package/dist/{chunk-P4ELXVJQ.mjs → chunk-FRQVMFY7.mjs} +7 -1
  11. package/dist/chunk-IFBKLBGB.mjs +7 -0
  12. package/dist/chunk-L225SHNB.mjs +513 -0
  13. package/dist/{chunk-MHE7YWAU.mjs → chunk-NTZYA3SJ.mjs} +3 -3
  14. package/dist/{chunk-WYJXSLER.mjs → chunk-POWOTUKJ.mjs} +7 -1
  15. package/dist/{chunk-CV5H7XL7.mjs → chunk-RGS7FMCB.mjs} +53 -10
  16. package/dist/{chunk-ZHUQKZBE.mjs → chunk-TVT5V4E7.mjs} +101 -34
  17. package/dist/chunk-U2AL3SON.mjs +4198 -0
  18. package/dist/chunk-UTOFOJOR.mjs +135 -0
  19. package/dist/{chunk-BEIK3EOZ.mjs → chunk-XNQAIO74.mjs} +5523 -3847
  20. package/dist/chunk-Y3L5MDRV.mjs +96 -0
  21. package/dist/chunk-ZJ4CSAB2.mjs +13 -0
  22. package/dist/{client-B_X6_AbT.d.ts → client-CQUqt9Ir.d.ts} +13 -4
  23. package/dist/client.d.ts +8 -8
  24. package/dist/client.mjs +20 -14
  25. package/dist/{config-Czh2YNDi.d.ts → config-CNas6wJH.d.ts} +2 -2
  26. package/dist/{config-OON7IJ_B.d.ts → config-bXxnJrQc.d.ts} +80 -35
  27. package/dist/direct-executor-RBA5O7EN.mjs +12 -0
  28. package/dist/distribution/coordinator/etcd.d.ts +2 -2
  29. package/dist/distribution/coordinator/etcd.mjs +1 -1
  30. package/dist/distribution/coordinator/in-memory.d.ts +2 -2
  31. package/dist/distribution/transport/grpc.mjs +1 -1
  32. package/dist/distribution.d.ts +8 -8
  33. package/dist/distribution.mjs +32 -17
  34. package/dist/embeddings/openai.mjs +1 -1
  35. package/dist/{engine-9PtFY50q.d.ts → engine-Dj4I91Jv.d.ts} +21 -8
  36. package/dist/index.browser.mjs +12962 -7786
  37. package/dist/index.d.ts +9 -21
  38. package/dist/index.mjs +14 -13
  39. package/dist/{memory-Bzd5xcEW.d.ts → memory-xrXOZMbw.d.ts} +68 -13
  40. package/dist/persistence/durability/checkpoint-worker.d.ts +138 -3
  41. package/dist/persistence/durability/checkpoint-worker.mjs +32 -18
  42. package/dist/react.d.ts +11 -11
  43. package/dist/react.mjs +16 -4
  44. package/dist/{schema-BqRx9t4E.d.ts → schema-mLpXZBEh.d.ts} +43 -12
  45. package/dist/serialization/crc32-worker.mjs +2 -1
  46. package/dist/server.d.ts +13 -10
  47. package/dist/server.mjs +136 -47
  48. package/dist/simd-DW5AtJ6B.d.ts +41 -0
  49. package/dist/{tasks-DT7L1p6w.d.ts → tasks-Df73Tjgq.d.ts} +9 -5
  50. package/dist/{thread-PZLEO6JL.mjs → thread-5UP6MGED.mjs} +131 -43
  51. package/dist/{types-DXPxaXPO.d.ts → types-BTIVO8DI.d.ts} +1 -1
  52. package/dist/vector/search-worker.d.ts +292 -128
  53. package/dist/vector/search-worker.mjs +70 -54
  54. package/dist/workers/entry.mjs +30 -14
  55. package/package.json +52 -31
  56. package/dist/brute-force-DbHYCTc3.d.ts +0 -8
  57. package/dist/chunk-CBLS46IE.mjs +0 -10
  58. package/dist/chunk-PIWKZPP7.mjs +0 -64
  59. package/dist/chunk-PMBHH44R.mjs +0 -492
  60. package/dist/chunk-RP23PWMV.mjs +0 -11
  61. package/dist/chunk-X6YZO4MQ.mjs +0 -1572
  62. package/dist/direct-executor-OREXU72C.mjs +0 -12
  63. package/dist/vector/hnsw-build-worker.d.ts +0 -105
  64. package/dist/vector/hnsw-build-worker.mjs +0 -123
@@ -1,32 +1,29 @@
1
- import { openSharedWorkerCopy, createScalarQuantizer } from '../chunk-PMBHH44R.mjs';
2
- import { searchOrdinals, MAX_WORKER_COPIES, createVectorStore, createHNSWIndex } from '../chunk-X6YZO4MQ.mjs';
3
- import '../chunk-RP23PWMV.mjs';
1
+ import { openSharedVectorField, MAX_WORKER_COPIES, createVectorStore, osqBitsOf, createHNSWIndex, createOsqQuantizer, osqRecordBytes } from '../chunk-U2AL3SON.mjs';
2
+ import '../chunk-ZJ4CSAB2.mjs';
3
+ import '../chunk-UTOFOJOR.mjs';
4
4
  import '../chunk-2GWVQWGA.mjs';
5
+ import '../chunk-FRQVMFY7.mjs';
5
6
 
6
7
  // src/vector/worker-copy.ts
8
+ function restoreQuantizer(snapshot, store) {
9
+ const bits = osqBitsOf(snapshot.quantization);
10
+ if (bits === null || snapshot.codes === null) return null;
11
+ const quantizer = createOsqQuantizer(snapshot.dimension, bits, snapshot.metric, store);
12
+ quantizer.restoreCentroid(snapshot.codes.centroid);
13
+ const recordBytes = osqRecordBytes(snapshot.dimension, bits);
14
+ for (let ordinal = 0; ordinal < snapshot.codes.present.length; ordinal++) {
15
+ if (snapshot.codes.present[ordinal] !== 1) continue;
16
+ const docId = store.docIdForOrdinal(ordinal);
17
+ if (docId === void 0) continue;
18
+ quantizer.restoreRecord(docId, snapshot.codes.records.subarray(ordinal * recordBytes, (ordinal + 1) * recordBytes));
19
+ }
20
+ return quantizer;
21
+ }
7
22
  function restoreWorkerCopy(snapshot) {
8
- const store = createVectorStore();
23
+ const store = createVectorStore({ dimension: snapshot.dimension, codeBits: osqBitsOf(snapshot.quantization) });
9
24
  store.restoreSnapshot(snapshot.store);
10
25
  const tombstones = new Set(snapshot.tombstones);
11
- let quantizer = null;
12
- if (snapshot.quantization === "sq8") {
13
- const sq8 = createScalarQuantizer(snapshot.dimension, store);
14
- if (snapshot.calibration !== null) {
15
- sq8.restoreCalibration(snapshot.calibration.alpha, snapshot.calibration.offset);
16
- } else {
17
- const live = [];
18
- for (const [docId, entry] of store.entries()) {
19
- if (tombstones.has(docId)) continue;
20
- live.push(entry.vector);
21
- }
22
- sq8.calibrate(live);
23
- }
24
- for (const [docId, entry] of store.entries()) {
25
- if (tombstones.has(docId)) continue;
26
- sq8.quantize(docId, entry.vector);
27
- }
28
- quantizer = sq8;
29
- }
26
+ const quantizer = restoreQuantizer(snapshot, store);
30
27
  const graph = createHNSWIndex(
31
28
  snapshot.dimension,
32
29
  store,
@@ -34,6 +31,7 @@ function restoreWorkerCopy(snapshot) {
34
31
  quantizer ?? void 0
35
32
  );
36
33
  graph.restoreSnapshot(snapshot.graph);
34
+ for (const docId of tombstones) graph.markTombstone(docId);
37
35
  return { store, graph, tombstones };
38
36
  }
39
37
 
@@ -51,29 +49,53 @@ function handleLoad(request) {
51
49
  }
52
50
  function handleLoadShared(request) {
53
51
  ensureRoom(request.handle);
54
- copies.set(request.handle, { kind: "shared", copy: openSharedWorkerCopy(request.snapshot, request.scratchSlot) });
52
+ const existing = copies.get(request.handle);
53
+ if (existing?.kind === "shared") {
54
+ existing.view.adopt(request.handles);
55
+ } else {
56
+ copies.set(request.handle, { kind: "shared", view: openSharedVectorField(request.handles, request.scratchSlot) });
57
+ }
55
58
  return { type: "ack", requestId: request.requestId, handle: request.handle };
56
59
  }
57
60
  function handleDrop(request) {
61
+ const held = copies.get(request.handle);
62
+ if (held?.kind === "shared") held.view.close();
58
63
  copies.delete(request.handle);
59
64
  return { type: "ack", requestId: request.requestId, handle: request.handle };
60
65
  }
66
+ function yieldToEventLoop() {
67
+ return new Promise((resolve) => {
68
+ if (typeof setImmediate === "function") setImmediate(resolve);
69
+ else setTimeout(resolve, 0);
70
+ });
71
+ }
72
+ async function handleInsert(request) {
73
+ const entry = copies.get(request.handle);
74
+ if (!entry) {
75
+ throw new Error(`Search worker holds no copy for handle ${request.handle}`);
76
+ }
77
+ if (entry.kind !== "shared") {
78
+ throw new Error(`Handle ${request.handle} holds a cloned copy, which takes no insertions`);
79
+ }
80
+ for (const ordinal of request.ordinals) {
81
+ entry.view.insertOrdinal(ordinal);
82
+ await yieldToEventLoop();
83
+ }
84
+ return { type: "inserted", requestId: request.requestId, outcome: entry.view.takeOutcome() };
85
+ }
61
86
  function handleSearch(request) {
62
87
  const entry = copies.get(request.handle);
63
88
  if (!entry) {
64
89
  throw new Error(`Search worker holds no copy for handle ${request.handle}`);
65
90
  }
66
91
  if (entry.kind !== "clone") {
67
- throw new Error(`Handle ${request.handle} holds a shared copy, which answers ordinal searches alone`);
92
+ throw new Error(`Handle ${request.handle} holds a shared field, which answers ordinal searches alone`);
68
93
  }
69
- const hits = entry.copy.graph.search(
70
- request.query,
71
- request.k,
72
- request.metric,
73
- request.minSimilarity,
74
- request.filter,
75
- request.efSearch
76
- );
94
+ const hits = entry.copy.graph.search(request.query, request.k, request.metric, request.minSimilarity, {
95
+ filter: request.filter,
96
+ efSearch: request.efSearch,
97
+ oversample: request.oversample
98
+ });
77
99
  const docIds = [];
78
100
  const scores = new Float64Array(hits.length);
79
101
  for (let i = 0; i < hits.length; i++) {
@@ -90,16 +112,11 @@ function handleSearchOrdinals(request) {
90
112
  if (entry.kind !== "shared") {
91
113
  throw new Error(`Handle ${request.handle} holds a cloned copy, which answers document id searches alone`);
92
114
  }
93
- const hits = searchOrdinals(
94
- entry.copy.searchState,
95
- request.query,
96
- request.k,
97
- request.metric,
98
- request.minSimilarity,
99
- entry.copy.rankByOrdinal,
100
- request.filter,
101
- request.efSearch
102
- );
115
+ const hits = entry.view.searchOrdinals(request.query, request.k, request.metric, request.minSimilarity, {
116
+ filter: request.filter,
117
+ efSearch: request.efSearch,
118
+ oversample: request.oversample
119
+ });
103
120
  const ordinals = new Uint32Array(hits.length);
104
121
  const scores = new Float64Array(hits.length);
105
122
  for (let i = 0; i < hits.length; i++) {
@@ -108,11 +125,12 @@ function handleSearchOrdinals(request) {
108
125
  }
109
126
  return { type: "ordinalResult", requestId: request.requestId, ordinals, scores };
110
127
  }
111
- function handleAnyRequest(raw) {
128
+ async function handleAnyRequest(raw) {
112
129
  const request = raw;
113
130
  if (request.type === "load") return handleLoad(request);
114
131
  if (request.type === "loadShared") return handleLoadShared(request);
115
132
  if (request.type === "drop") return handleDrop(request);
133
+ if (request.type === "insertOrdinals") return handleInsert(request);
116
134
  if (request.type === "search") return handleSearch(request);
117
135
  if (request.type === "searchOrdinals") return handleSearchOrdinals(request);
118
136
  throw new Error(`Unknown request type: ${request.type}`);
@@ -138,11 +156,10 @@ async function setupAsync() {
138
156
  if (parentPort) {
139
157
  const port = parentPort;
140
158
  port.on("message", (raw) => {
141
- try {
142
- port.postMessage(handleAnyRequest(raw));
143
- } catch (err) {
144
- port.postMessage(errorFor(raw, err));
145
- }
159
+ handleAnyRequest(raw).then(
160
+ (reply) => port.postMessage(reply),
161
+ (err) => port.postMessage(errorFor(raw, err))
162
+ );
146
163
  });
147
164
  return;
148
165
  }
@@ -150,11 +167,10 @@ async function setupAsync() {
150
167
  if (globalSelf && typeof globalSelf.postMessage === "function") {
151
168
  const webSelf = globalSelf;
152
169
  webSelf.onmessage = (event) => {
153
- try {
154
- webSelf.postMessage(handleAnyRequest(event.data));
155
- } catch (err) {
156
- webSelf.postMessage(errorFor(event.data, err));
157
- }
170
+ handleAnyRequest(event.data).then(
171
+ (reply) => webSelf.postMessage(reply),
172
+ (err) => webSelf.postMessage(errorFor(event.data, err))
173
+ );
158
174
  };
159
175
  }
160
176
  }
@@ -1,9 +1,10 @@
1
- import { isValidWorkerAction } from '../chunk-WYJXSLER.mjs';
2
- import { NarsilError, ErrorCodes } from '../chunk-P4ELXVJQ.mjs';
1
+ import { startIdleHeapCleanup } from '../chunk-Y3L5MDRV.mjs';
2
+ import { threadSlotOfWorker, isValidWorkerAction } from '../chunk-POWOTUKJ.mjs';
3
+ import { ErrorCodes, NarsilError, isNarsilError } from '../chunk-FRQVMFY7.mjs';
3
4
 
4
5
  // src/workers/action-handler.ts
5
- function buildErrorResponse(requestId, code, message) {
6
- return { type: "error", requestId, code, message };
6
+ function buildErrorResponse(requestId, code, message, details) {
7
+ return details === void 0 || Object.keys(details).length === 0 ? { type: "error", requestId, code, message } : { type: "error", requestId, code, message, details };
7
8
  }
8
9
  function buildSuccessResponse(requestId, data) {
9
10
  return { type: "success", requestId, data };
@@ -17,7 +18,7 @@ async function importBootstrapModule(moduleUrl) {
17
18
  await import(moduleUrl);
18
19
  }
19
20
  async function stopServingRequests() {
20
- const { closeRequestThread } = await import('../thread-PZLEO6JL.mjs');
21
+ const { closeRequestThread } = await import('../thread-5UP6MGED.mjs');
21
22
  closeRequestThread();
22
23
  }
23
24
  function holdsCopies(executor) {
@@ -48,7 +49,7 @@ function createActionHandler(executor) {
48
49
  if (!holdsCopies(executor)) {
49
50
  throw new NarsilError(ErrorCodes.CONFIG_INVALID, "This executor holds no copies to answer requests from");
50
51
  }
51
- const starting = import('../thread-PZLEO6JL.mjs').then(
52
+ const starting = import('../thread-5UP6MGED.mjs').then(
52
53
  ({ serveRequests }) => serveRequests(executor, action.settings)
53
54
  );
54
55
  serving.start = starting.then(
@@ -69,9 +70,10 @@ function createActionHandler(executor) {
69
70
  const result = await executor.execute(action);
70
71
  post(buildSuccessResponse(action.requestId, result));
71
72
  } catch (err) {
72
- const code = err?.code ?? "UNKNOWN_ERROR";
73
+ const failure = isNarsilError(err) ? err : null;
74
+ const code = failure?.code ?? ErrorCodes.WORKER_ACTION_FAILED;
73
75
  const message = err instanceof Error ? err.message : String(err);
74
- post(buildErrorResponse(action.requestId, code, message));
76
+ post(buildErrorResponse(action.requestId, code, message, failure?.details));
75
77
  }
76
78
  return false;
77
79
  };
@@ -91,22 +93,30 @@ function workerIdOf(workerData) {
91
93
  }
92
94
  async function setup() {
93
95
  let parentPort = null;
94
- let scratchSlot;
96
+ let threadSlot;
95
97
  try {
96
98
  const workerThreads = await import('worker_threads');
97
99
  parentPort = workerThreads.parentPort ?? null;
98
- scratchSlot = workerIdOf(workerThreads.workerData);
100
+ const workerId = workerIdOf(workerThreads.workerData);
101
+ threadSlot = workerId === void 0 ? void 0 : threadSlotOfWorker(workerId);
99
102
  } catch {
100
103
  parentPort = null;
101
104
  }
102
- const { createDirectExecutor } = await import('../direct-executor-OREXU72C.mjs');
103
- const handleAction = createActionHandler(createDirectExecutor({ scratchSlot }));
105
+ const { createDirectExecutor } = await import('../direct-executor-RBA5O7EN.mjs');
106
+ const handleAction = createActionHandler(createDirectExecutor({ threadSlot }));
104
107
  if (parentPort) {
105
108
  const port = parentPort;
109
+ startIdleHeapCleanup();
106
110
  port.on("message", (raw) => {
107
111
  if (!isValidWorkerAction(raw)) {
108
112
  const requestId = raw?.requestId ?? "unknown";
109
- port.postMessage(buildErrorResponse(requestId, "INVALID_ACTION", "Received an invalid worker action"));
113
+ port.postMessage(
114
+ buildErrorResponse(
115
+ requestId,
116
+ ErrorCodes.WORKER_ACTION_FAILED,
117
+ "This worker received a message that is no valid action"
118
+ )
119
+ );
110
120
  return;
111
121
  }
112
122
  handleAction(raw, (msg) => port.postMessage(msg)).then((shouldClose) => {
@@ -124,7 +134,13 @@ async function setup() {
124
134
  const raw = event.data;
125
135
  if (!isValidWorkerAction(raw)) {
126
136
  const requestId = raw?.requestId ?? "unknown";
127
- webSelf.postMessage(buildErrorResponse(requestId, "INVALID_ACTION", "Received an invalid worker action"));
137
+ webSelf.postMessage(
138
+ buildErrorResponse(
139
+ requestId,
140
+ ErrorCodes.WORKER_ACTION_FAILED,
141
+ "This worker received a message that is no valid action"
142
+ )
143
+ );
128
144
  return;
129
145
  }
130
146
  handleAction(raw, (msg) => webSelf.postMessage(msg)).then((shouldClose) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@delali/narsil",
3
- "version": "0.2.4-next.51",
3
+ "version": "0.2.4-next.54",
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)",
@@ -34,6 +34,22 @@
34
34
  "#platform/heap-statistics": {
35
35
  "browser": "./src/runtime/heap-statistics.browser.ts",
36
36
  "default": "./src/runtime/heap-statistics.ts"
37
+ },
38
+ "#platform/idle-heap-cleanup": {
39
+ "browser": "./src/runtime/idle-heap-cleanup.browser.ts",
40
+ "default": "./src/runtime/idle-heap-cleanup.ts"
41
+ },
42
+ "#platform/vector-file": {
43
+ "browser": "./src/vector/vector-store/vector-file.browser.ts",
44
+ "default": "./src/vector/vector-store/vector-file.ts"
45
+ },
46
+ "#platform/native-core": {
47
+ "browser": "./src/vector/native/loader.browser.ts",
48
+ "default": "./src/vector/native/loader.ts"
49
+ },
50
+ "#platform/native-crc32": {
51
+ "browser": "./src/serialization/native-crc32.browser.ts",
52
+ "default": "./src/serialization/native-crc32.ts"
37
53
  }
38
54
  },
39
55
  "sideEffects": false,
@@ -49,6 +65,31 @@
49
65
  "engines": {
50
66
  "node": ">=22"
51
67
  },
68
+ "scripts": {
69
+ "build": "rm -rf dist && tsup && node scripts/check-browser-bundle.mjs && tsx scripts/api-surface.ts",
70
+ "test": "vitest run --exclude='**/vector/recall.test.ts'",
71
+ "test:etcd": "vitest run src/__tests__/distribution/coordinator/etcd-integration/*.test.ts",
72
+ "test:watch": "vitest",
73
+ "test:coverage": "vitest run --coverage",
74
+ "test:recall": "vitest run src/__tests__/vector/recall.test.ts",
75
+ "test:embeddings": "NARSIL_TEST_EMBEDDINGS=1 vitest run embedding-e2e",
76
+ "bench": "vitest bench",
77
+ "stemmers": "tsx snowball/build.ts",
78
+ "revisions": "tsx scripts/analysis-revisions.ts",
79
+ "revisions:write": "tsx scripts/analysis-revisions.ts --write",
80
+ "revisions:record": "tsx scripts/analysis-revisions.ts --record",
81
+ "api": "tsx scripts/api-surface.ts",
82
+ "api:write": "tsx scripts/api-surface.ts --write",
83
+ "lookalikes": "tsx scripts/lookalike-counts.ts",
84
+ "lookalikes:collect": "tsx scripts/lookalike-counts.ts --collect",
85
+ "fold-table": "tsx scripts/fold-table.ts",
86
+ "fold-table:write": "tsx scripts/fold-table.ts --write",
87
+ "lint": "biome check src/",
88
+ "typecheck:src": "tsc --noEmit",
89
+ "typecheck:tests": "tsc --noEmit -p tsconfig.test.json",
90
+ "typecheck:tooling": "tsc --noEmit -p scripts/tsconfig.json && tsc --noEmit -p benchmarks/tsconfig.json && tsc --noEmit -p wasm/tsconfig.json && tsc --noEmit -p snowball/tsconfig.json",
91
+ "typecheck": "pnpm run typecheck:src && pnpm run typecheck:tests && pnpm run typecheck:tooling"
92
+ },
52
93
  "exports": {
53
94
  ".": {
54
95
  "browser": {
@@ -82,10 +123,6 @@
82
123
  "import": "./dist/invalidation/broadcast-channel.mjs",
83
124
  "types": "./dist/invalidation/broadcast-channel.d.ts"
84
125
  },
85
- "./vector/hnsw-build-worker": {
86
- "import": "./dist/vector/hnsw-build-worker.mjs",
87
- "types": "./dist/vector/hnsw-build-worker.d.ts"
88
- },
89
126
  "./vector/search-worker": {
90
127
  "import": "./dist/vector/search-worker.mjs",
91
128
  "types": "./dist/vector/search-worker.d.ts"
@@ -145,6 +182,7 @@
145
182
  },
146
183
  "devDependencies": {
147
184
  "@biomejs/biome": "2.4.4",
185
+ "@delali/narsil-embeddings-transformers": "workspace:*",
148
186
  "@grpc/grpc-js": "1.14.4",
149
187
  "@microsoft/api-extractor": "7.58.12",
150
188
  "@types/node": "22.15.32",
@@ -162,8 +200,7 @@
162
200
  "typescript": "5.9.3",
163
201
  "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.58.0",
164
202
  "vitest": "4.0.18",
165
- "wabt": "1.0.39",
166
- "@delali/narsil-embeddings-transformers": "0.1.7"
203
+ "wabt": "1.0.39"
167
204
  },
168
205
  "peerDependencies": {
169
206
  "@grpc/grpc-js": "1.14.4",
@@ -185,28 +222,12 @@
185
222
  "optional": true
186
223
  }
187
224
  },
188
- "scripts": {
189
- "build": "rm -rf dist && tsup && node scripts/check-browser-bundle.mjs && tsx scripts/api-surface.ts",
190
- "test": "vitest run --exclude='**/vector/recall.test.ts'",
191
- "test:etcd": "vitest run src/__tests__/distribution/coordinator/etcd-integration/*.test.ts",
192
- "test:watch": "vitest",
193
- "test:coverage": "vitest run --coverage",
194
- "test:recall": "vitest run src/__tests__/vector/recall.test.ts",
195
- "test:embeddings": "NARSIL_TEST_EMBEDDINGS=1 vitest run embedding-e2e",
196
- "bench": "vitest bench",
197
- "stemmers": "tsx snowball/build.ts",
198
- "revisions": "tsx scripts/analysis-revisions.ts",
199
- "revisions:write": "tsx scripts/analysis-revisions.ts --write",
200
- "api": "tsx scripts/api-surface.ts",
201
- "api:write": "tsx scripts/api-surface.ts --write",
202
- "lookalikes": "tsx scripts/lookalike-counts.ts",
203
- "lookalikes:collect": "tsx scripts/lookalike-counts.ts --collect",
204
- "fold-table": "tsx scripts/fold-table.ts",
205
- "fold-table:write": "tsx scripts/fold-table.ts --write",
206
- "lint": "biome check src/",
207
- "typecheck:src": "tsc --noEmit",
208
- "typecheck:tests": "tsc --noEmit -p tsconfig.test.json",
209
- "typecheck:tooling": "tsc --noEmit -p scripts/tsconfig.json && tsc --noEmit -p benchmarks/tsconfig.json && tsc --noEmit -p wasm/tsconfig.json && tsc --noEmit -p snowball/tsconfig.json",
210
- "typecheck": "pnpm run typecheck:src && pnpm run typecheck:tests && pnpm run typecheck:tooling"
225
+ "optionalDependencies": {
226
+ "@delali/narsil-native-darwin-arm64": "0.2.4-next.54",
227
+ "@delali/narsil-native-darwin-x64": "0.2.4-next.54",
228
+ "@delali/narsil-native-linux-arm64": "0.2.4-next.54",
229
+ "@delali/narsil-native-linux-x64": "0.2.4-next.54",
230
+ "@delali/narsil-native-win32-arm64": "0.2.4-next.54",
231
+ "@delali/narsil-native-win32-x64": "0.2.4-next.54"
211
232
  }
212
- }
233
+ }
@@ -1,8 +0,0 @@
1
- /**
2
- * Similarity metric a vector search ranks by.
3
- *
4
- * @internal
5
- */
6
- type VectorMetric = 'cosine' | 'dotProduct' | 'euclidean';
7
-
8
- export type { VectorMetric as V };
@@ -1,10 +0,0 @@
1
- // src/search/constants.ts
2
- var RESULT_WINDOW = 1e4;
3
- var DEFAULT_PAGE_SIZE = 10;
4
- var MAX_CURSOR_LENGTH = 40960;
5
- var MAX_SORT_FIELDS = 8;
6
- var MAX_SORT_FIELD_NAME_LENGTH = 255;
7
- var MAX_CURSOR_ANCHOR_CODE_POINTS = 512;
8
- var PREFIX_MAX_EXPANSIONS = 50;
9
-
10
- export { DEFAULT_PAGE_SIZE, MAX_CURSOR_ANCHOR_CODE_POINTS, MAX_CURSOR_LENGTH, MAX_SORT_FIELDS, MAX_SORT_FIELD_NAME_LENGTH, PREFIX_MAX_EXPANSIONS, RESULT_WINDOW };
@@ -1,64 +0,0 @@
1
- import { NarsilError, ErrorCodes } from './chunk-P4ELXVJQ.mjs';
2
-
3
- // src/narsil/internals.ts
4
- var engineCores = /* @__PURE__ */ new WeakMap();
5
- function bindEngineCore(engine, core) {
6
- engineCores.set(engine, core);
7
- }
8
- function engineCoreOf(engine) {
9
- return engineCores.get(engine);
10
- }
11
-
12
- // src/distribution/constants.ts
13
- var WIRE_BATCH_BUDGET = {
14
- maxCount: 1e3,
15
- maxBytes: 8388608,
16
- overheadBytes: 256
17
- };
18
- var MAX_PARTITION_COUNT = 65536;
19
- var MAX_REPLICATION_FACTOR = 255;
20
-
21
- // src/engine/resolve-vector-text.ts
22
- async function resolveVectorText(params, embeddingAdapter, signal, embeddingAdapterName) {
23
- if (!params.vector) return params;
24
- if (params.vector.text === void 0 && params.vector.value === void 0) return params;
25
- if (params.vector.value !== void 0 && params.vector.text === void 0) return params;
26
- if (params.vector.text !== void 0 && params.vector.value !== void 0) {
27
- throw new NarsilError(ErrorCodes.EMBEDDING_CONFIG_INVALID, "Vector query cannot have both 'text' and 'value'");
28
- }
29
- if (!embeddingAdapter) {
30
- throw new NarsilError(
31
- ErrorCodes.EMBEDDING_CONFIG_INVALID,
32
- embeddingAdapterName ? `Vector query with 'text' needs embedding adapter "${embeddingAdapterName}", which is not registered on this engine. Register it with registerEmbeddingAdapter or supply a raw vector.` : "Vector query with 'text' requires an embedding adapter on the index or instance",
33
- embeddingAdapterName ? { adapter: embeddingAdapterName } : void 0
34
- );
35
- }
36
- if (typeof params.vector.text !== "string") {
37
- throw new NarsilError(
38
- ErrorCodes.DOC_VALIDATION_FAILED,
39
- `Vector query 'text' must be a string, got ${typeof params.vector.text}`
40
- );
41
- }
42
- if (params.vector.text.length === 0) {
43
- throw new NarsilError(ErrorCodes.DOC_VALIDATION_FAILED, "Vector query 'text' must not be empty");
44
- }
45
- const raw = await embeddingAdapter.embed(params.vector.text, "query", signal);
46
- if (!(raw instanceof Float32Array)) {
47
- throw new NarsilError(
48
- ErrorCodes.EMBEDDING_FAILED,
49
- `Adapter returned ${typeof raw} for query embedding, expected Float32Array`
50
- );
51
- }
52
- if (raw.length !== embeddingAdapter.dimensions) {
53
- throw new NarsilError(
54
- ErrorCodes.EMBEDDING_DIMENSION_MISMATCH,
55
- `Adapter returned ${raw.length}-dimensional vector for query, expected ${embeddingAdapter.dimensions}`,
56
- { expected: embeddingAdapter.dimensions, actual: raw.length }
57
- );
58
- }
59
- const resolved = { ...params.vector, value: Array.from(raw) };
60
- delete resolved.text;
61
- return { ...params, vector: resolved };
62
- }
63
-
64
- export { MAX_PARTITION_COUNT, MAX_REPLICATION_FACTOR, WIRE_BATCH_BUDGET, bindEngineCore, engineCoreOf, resolveVectorText };