@delali/narsil 0.1.6 → 0.1.8

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 (88) hide show
  1. package/README.md +174 -4
  2. package/dist/adapters/filesystem.d.ts +1 -1
  3. package/dist/adapters/filesystem.mjs +46 -2
  4. package/dist/adapters/indexeddb.d.ts +1 -1
  5. package/dist/adapters/indexeddb.mjs +1 -1
  6. package/dist/adapters/memory.d.ts +1 -1
  7. package/dist/{adapters-XODT2F3h.d.ts → adapters-Bo2JQg8b.d.ts} +8 -1
  8. package/dist/chunk-ALB35PRQ.mjs +98 -0
  9. package/dist/{chunk-TFWBALU4.mjs → chunk-FS7XLIUS.mjs} +3219 -2063
  10. package/dist/chunk-GQEHCZG7.mjs +6825 -0
  11. package/dist/chunk-KMMJMDUA.mjs +44 -0
  12. package/dist/chunk-RQLXC2YS.mjs +269 -0
  13. package/dist/chunk-S7RJJMHI.mjs +1086 -0
  14. package/dist/{chunk-WYC635GI.mjs → chunk-TW6BXTOL.mjs} +10 -7
  15. package/dist/chunk-WISGW24C.mjs +455 -0
  16. package/dist/config-cQLlYR3U.d.ts +470 -0
  17. package/dist/direct-executor-FX56DYD3.mjs +4 -0
  18. package/dist/distribution/coordinator/etcd.d.ts +16 -0
  19. package/dist/distribution/coordinator/etcd.mjs +2 -0
  20. package/dist/distribution/coordinator/in-memory.d.ts +7 -0
  21. package/dist/distribution/coordinator/in-memory.mjs +1 -0
  22. package/dist/distribution.d.ts +122 -0
  23. package/dist/distribution.mjs +7410 -0
  24. package/dist/embeddings/openai.d.ts +13 -0
  25. package/dist/embeddings/openai.mjs +248 -0
  26. package/dist/index.browser.mjs +12111 -5793
  27. package/dist/index.d.ts +10 -420
  28. package/dist/index.mjs +7 -2052
  29. package/dist/invalidation/broadcast-channel.d.ts +1 -1
  30. package/dist/invalidation/filesystem.d.ts +1 -1
  31. package/dist/invalidation/noop.d.ts +1 -1
  32. package/dist/{language-ClUGLuoC.d.ts → language-ONQ3iVDf.d.ts} +1 -0
  33. package/dist/languages/arabic.d.ts +1 -1
  34. package/dist/languages/armenian.d.ts +1 -1
  35. package/dist/languages/bulgarian.d.ts +1 -1
  36. package/dist/languages/chinese.d.ts +1 -1
  37. package/dist/languages/dagbani.d.ts +1 -1
  38. package/dist/languages/danish.d.ts +1 -1
  39. package/dist/languages/dutch.d.ts +1 -1
  40. package/dist/languages/english.d.ts +1 -1
  41. package/dist/languages/english.mjs +1 -1
  42. package/dist/languages/ewe.d.ts +1 -1
  43. package/dist/languages/finnish.d.ts +1 -1
  44. package/dist/languages/french.d.ts +1 -1
  45. package/dist/languages/ga.d.ts +1 -1
  46. package/dist/languages/german.d.ts +1 -1
  47. package/dist/languages/greek.d.ts +1 -1
  48. package/dist/languages/hausa.d.ts +1 -1
  49. package/dist/languages/hindi.d.ts +1 -1
  50. package/dist/languages/hungarian.d.ts +1 -1
  51. package/dist/languages/igbo.d.ts +1 -1
  52. package/dist/languages/indonesian.d.ts +1 -1
  53. package/dist/languages/irish.d.ts +1 -1
  54. package/dist/languages/italian.d.ts +1 -1
  55. package/dist/languages/japanese.d.ts +1 -1
  56. package/dist/languages/nepali.d.ts +1 -1
  57. package/dist/languages/norwegian.d.ts +1 -1
  58. package/dist/languages/portuguese.d.ts +1 -1
  59. package/dist/languages/romanian.d.ts +1 -1
  60. package/dist/languages/russian.d.ts +1 -1
  61. package/dist/languages/sanskrit.d.ts +1 -1
  62. package/dist/languages/serbian.d.ts +1 -1
  63. package/dist/languages/slovenian.d.ts +1 -1
  64. package/dist/languages/spanish.d.ts +1 -1
  65. package/dist/languages/swahili.d.ts +1 -1
  66. package/dist/languages/swedish.d.ts +1 -1
  67. package/dist/languages/tamil.d.ts +1 -1
  68. package/dist/languages/turkish.d.ts +1 -1
  69. package/dist/languages/twi.d.ts +1 -1
  70. package/dist/languages/ukrainian.d.ts +1 -1
  71. package/dist/languages/yoruba.d.ts +1 -1
  72. package/dist/languages/zulu.d.ts +1 -1
  73. package/dist/narsil-ChTdkwPu.d.ts +68 -0
  74. package/dist/persistence/durability/checkpoint-worker.d.ts +41 -0
  75. package/dist/persistence/durability/checkpoint-worker.mjs +59 -0
  76. package/dist/schema-BVaw7nqz.d.ts +58 -0
  77. package/dist/serialization/crc32-worker.d.ts +20 -0
  78. package/dist/serialization/crc32-worker.mjs +61 -0
  79. package/dist/server.d.ts +218 -0
  80. package/dist/server.mjs +1185 -0
  81. package/dist/types-Bt7c4hDF.d.ts +73 -0
  82. package/dist/vector/hnsw-build-worker.d.ts +9 -2
  83. package/dist/vector/hnsw-build-worker.mjs +54 -10
  84. package/dist/workers/entry.mjs +1 -1
  85. package/package.json +46 -4
  86. package/dist/chunk-7GKPWGCN.mjs +0 -43
  87. package/dist/chunk-GVN2W4VA.mjs +0 -570
  88. package/dist/direct-executor-6TSG7GWH.mjs +0 -4
@@ -0,0 +1,73 @@
1
+ import { S as SchemaDefinition } from './schema-BVaw7nqz.js';
2
+
3
+ type NodeRole = 'data' | 'coordinator' | 'controller';
4
+ type PartitionState = 'UNASSIGNED' | 'INITIALISING' | 'ACTIVE' | 'MIGRATING' | 'DECOMMISSIONING';
5
+ interface NodeCapacity {
6
+ memoryBytes: number;
7
+ cpuCores: number;
8
+ diskBytes: number | null;
9
+ }
10
+ interface NodeRegistration {
11
+ nodeId: string;
12
+ address: string;
13
+ roles: NodeRole[];
14
+ capacity: NodeCapacity;
15
+ startedAt: string;
16
+ version: string;
17
+ metadata?: Record<string, string>;
18
+ }
19
+ interface PartitionAssignment {
20
+ primary: string | null;
21
+ replicas: string[];
22
+ inSyncSet: string[];
23
+ state: PartitionState;
24
+ primaryTerm: number;
25
+ }
26
+ interface AllocationTable {
27
+ indexName: string;
28
+ version: number;
29
+ replicationFactor: number;
30
+ assignments: Map<number, PartitionAssignment>;
31
+ }
32
+ interface NodeEvent {
33
+ type: 'node_joined' | 'node_left';
34
+ nodeId: string;
35
+ registration: NodeRegistration | null;
36
+ }
37
+ interface AllocationEvent {
38
+ indexName: string;
39
+ table: AllocationTable;
40
+ }
41
+ interface SchemaEvent {
42
+ type: 'schema_created' | 'schema_dropped';
43
+ indexName: string;
44
+ schema: SchemaDefinition | null;
45
+ }
46
+ interface AllocationConstraints {
47
+ zoneAwareness: boolean;
48
+ zoneAttribute: string;
49
+ maxShardsPerNode: number | null;
50
+ }
51
+ interface ClusterCoordinator {
52
+ registerNode(registration: NodeRegistration): Promise<void>;
53
+ deregisterNode(nodeId: string): Promise<void>;
54
+ listNodes(): Promise<NodeRegistration[]>;
55
+ watchNodes(handler: (event: NodeEvent) => void): Promise<() => void>;
56
+ getAllocation(indexName: string): Promise<AllocationTable | null>;
57
+ putAllocation(indexName: string, table: AllocationTable, expectedVersion?: number | null): Promise<boolean>;
58
+ watchAllocation(handler: (event: AllocationEvent) => void): Promise<() => void>;
59
+ getPartitionState(indexName: string, partitionId: number): Promise<PartitionState>;
60
+ putPartitionState(indexName: string, partitionId: number, state: PartitionState): Promise<void>;
61
+ acquireLease(key: string, nodeId: string, ttlMs: number): Promise<boolean>;
62
+ renewLease(key: string, nodeId: string, ttlMs: number): Promise<boolean>;
63
+ releaseLease(key: string): Promise<void>;
64
+ get(key: string): Promise<Uint8Array | null>;
65
+ compareAndSet(key: string, expected: Uint8Array | null, value: Uint8Array): Promise<boolean>;
66
+ getSchema(indexName: string): Promise<SchemaDefinition | null>;
67
+ putSchema(indexName: string, schema: SchemaDefinition): Promise<void>;
68
+ watchSchemas(handler: (event: SchemaEvent) => void): Promise<() => void>;
69
+ getLeaseHolder(key: string): Promise<string | null>;
70
+ shutdown(): Promise<void>;
71
+ }
72
+
73
+ export type { AllocationTable as A, ClusterCoordinator as C, NodeRegistration as N, PartitionAssignment as P, SchemaEvent as S, NodeRole as a, NodeCapacity as b, AllocationConstraints as c, AllocationEvent as d, NodeEvent as e, PartitionState as f };
@@ -6,7 +6,7 @@ interface HNSWConfig {
6
6
  metric?: VectorMetric;
7
7
  }
8
8
  interface SerializedHNSWGraph {
9
- entryPoint: string;
9
+ entryPoint: string | null;
10
10
  maxLayer: number;
11
11
  m: number;
12
12
  efConstruction: number;
@@ -23,6 +23,13 @@ interface HNSWBuildRequest {
23
23
  dimension: number;
24
24
  config: HNSWConfig;
25
25
  }
26
+ interface HNSWBuildRequestBinary {
27
+ type: 'build-binary';
28
+ docIds: string[];
29
+ vectorData: Float32Array;
30
+ dimension: number;
31
+ config: HNSWConfig;
32
+ }
26
33
  interface HNSWBuildResponse {
27
34
  type: 'success';
28
35
  graph: SerializedHNSWGraph;
@@ -34,4 +41,4 @@ interface HNSWBuildError {
34
41
  type HNSWWorkerMessage = HNSWBuildResponse | HNSWBuildError;
35
42
  declare function handleBuildRequest(request: HNSWBuildRequest): SerializedHNSWGraph;
36
43
 
37
- export { type HNSWBuildError, type HNSWBuildRequest, type HNSWBuildResponse, type HNSWWorkerMessage, handleBuildRequest };
44
+ export { type HNSWBuildError, type HNSWBuildRequest, type HNSWBuildRequestBinary, type HNSWBuildResponse, type HNSWWorkerMessage, handleBuildRequest };
@@ -1,4 +1,4 @@
1
- import { createHNSWIndex } from '../chunk-GVN2W4VA.mjs';
1
+ import { createVectorStore, createHNSWIndex } from '../chunk-S7RJJMHI.mjs';
2
2
 
3
3
  // src/vector/hnsw-build-worker.ts
4
4
  var MAX_WORKER_DIMENSION = 8192;
@@ -23,15 +23,63 @@ function validateBuildRequest(request) {
23
23
  }
24
24
  }
25
25
  }
26
+ function clampHNSWConfig(config) {
27
+ return {
28
+ ...config,
29
+ m: config.m != null ? Math.max(2, Math.min(64, config.m)) : void 0,
30
+ efConstruction: config.efConstruction != null ? Math.max(10, Math.min(1e3, config.efConstruction)) : void 0
31
+ };
32
+ }
26
33
  function handleBuildRequest(request) {
27
34
  validateBuildRequest(request);
28
- const hnsw = createHNSWIndex(request.dimension, request.config);
35
+ const safeConfig = clampHNSWConfig(request.config);
36
+ const store = createVectorStore();
37
+ for (const entry of request.vectors) {
38
+ store.insert(entry.docId, new Float32Array(entry.values));
39
+ }
40
+ const hnsw = createHNSWIndex(request.dimension, store, safeConfig);
29
41
  for (const entry of request.vectors) {
30
- const vec = new Float32Array(entry.values);
31
- hnsw.insert(entry.docId, vec);
42
+ hnsw.insertNode(entry.docId);
32
43
  }
33
44
  return hnsw.serialize();
34
45
  }
46
+ function handleBuildRequestBinary(request) {
47
+ const { docIds, vectorData, dimension, config } = request;
48
+ if (!Number.isInteger(dimension) || dimension <= 0 || dimension > MAX_WORKER_DIMENSION) {
49
+ throw new Error(`Invalid dimension: ${dimension} (must be 1..${MAX_WORKER_DIMENSION})`);
50
+ }
51
+ if (docIds.length > MAX_WORKER_VECTORS) {
52
+ throw new Error(`Too many vectors: ${docIds.length} (max ${MAX_WORKER_VECTORS})`);
53
+ }
54
+ const expectedLength = docIds.length * dimension;
55
+ if (vectorData.length !== expectedLength) {
56
+ throw new Error(
57
+ `vectorData length ${vectorData.length} does not match ${docIds.length} * ${dimension} = ${expectedLength}`
58
+ );
59
+ }
60
+ const safeConfig = clampHNSWConfig(config);
61
+ const store = createVectorStore();
62
+ for (let i = 0; i < docIds.length; i++) {
63
+ const offset = i * dimension;
64
+ const vec = vectorData.subarray(offset, offset + dimension);
65
+ store.insert(docIds[i], new Float32Array(vec));
66
+ }
67
+ const hnsw = createHNSWIndex(dimension, store, safeConfig);
68
+ for (const docId of docIds) {
69
+ hnsw.insertNode(docId);
70
+ }
71
+ return hnsw.serialize();
72
+ }
73
+ function handleAnyRequest(raw) {
74
+ const request = raw;
75
+ if (request.type === "build") {
76
+ return handleBuildRequest(raw);
77
+ }
78
+ if (request.type === "build-binary") {
79
+ return handleBuildRequestBinary(raw);
80
+ }
81
+ throw new Error(`Unknown request type: ${request.type}`);
82
+ }
35
83
  function setupWorker() {
36
84
  setupAsync().catch((err) => {
37
85
  console.error("HNSW build worker setup failed:", err);
@@ -48,10 +96,8 @@ async function setupAsync() {
48
96
  if (parentPort) {
49
97
  const port = parentPort;
50
98
  port.on("message", (raw) => {
51
- const request = raw;
52
- if (request.type !== "build") return;
53
99
  try {
54
- const graph = handleBuildRequest(request);
100
+ const graph = handleAnyRequest(raw);
55
101
  port.postMessage({ type: "success", graph });
56
102
  } catch (err) {
57
103
  const message = err instanceof Error ? err.message : String(err);
@@ -64,10 +110,8 @@ async function setupAsync() {
64
110
  if (globalSelf && typeof globalSelf.postMessage === "function") {
65
111
  const webSelf = globalSelf;
66
112
  webSelf.onmessage = (event) => {
67
- const request = event.data;
68
- if (request.type !== "build") return;
69
113
  try {
70
- const graph = handleBuildRequest(request);
114
+ const graph = handleAnyRequest(event.data);
71
115
  webSelf.postMessage({ type: "success", graph });
72
116
  } catch (err) {
73
117
  const message = err instanceof Error ? err.message : String(err);
@@ -15,7 +15,7 @@ async function setup() {
15
15
  } catch {
16
16
  parentPort = null;
17
17
  }
18
- const { createDirectExecutor } = await import('../direct-executor-6TSG7GWH.mjs');
18
+ const { createDirectExecutor } = await import('../direct-executor-FX56DYD3.mjs');
19
19
  const executor = createDirectExecutor();
20
20
  function buildErrorResponse(requestId, code, message) {
21
21
  return { type: "error", requestId, code, message };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@delali/narsil",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
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)",
@@ -74,9 +74,29 @@
74
74
  "import": "./dist/vector/hnsw-build-worker.mjs",
75
75
  "types": "./dist/vector/hnsw-build-worker.d.ts"
76
76
  },
77
+ "./embeddings/openai": {
78
+ "import": "./dist/embeddings/openai.mjs",
79
+ "types": "./dist/embeddings/openai.d.ts"
80
+ },
77
81
  "./languages/*": {
78
82
  "import": "./dist/languages/*.mjs",
79
83
  "types": "./dist/languages/*.d.ts"
84
+ },
85
+ "./distribution": {
86
+ "import": "./dist/distribution.mjs",
87
+ "types": "./dist/distribution.d.ts"
88
+ },
89
+ "./distribution/coordinator/in-memory": {
90
+ "import": "./dist/distribution/coordinator/in-memory.mjs",
91
+ "types": "./dist/distribution/coordinator/in-memory.d.ts"
92
+ },
93
+ "./distribution/coordinator/etcd": {
94
+ "import": "./dist/distribution/coordinator/etcd.mjs",
95
+ "types": "./dist/distribution/coordinator/etcd.d.ts"
96
+ },
97
+ "./server": {
98
+ "import": "./dist/server.mjs",
99
+ "types": "./dist/server.d.ts"
80
100
  }
81
101
  },
82
102
  "files": [
@@ -90,18 +110,40 @@
90
110
  "@biomejs/biome": "2.4.4",
91
111
  "@types/node": "22.15.32",
92
112
  "@vitest/coverage-v8": "4.0.18",
113
+ "etcd3": "1.1.2",
114
+ "selfsigned": "5.5.0",
93
115
  "tsup": "8.5.1",
94
116
  "typescript": "5.9.3",
117
+ "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.58.0",
95
118
  "vitest": "4.0.18",
96
- "wabt": "1.0.39"
119
+ "wabt": "1.0.39",
120
+ "@delali/narsil-embeddings-transformers": "0.1.6"
121
+ },
122
+ "peerDependencies": {
123
+ "etcd3": "1.1.2",
124
+ "uWebSockets.js": ">=20.0.0"
125
+ },
126
+ "peerDependenciesMeta": {
127
+ "etcd3": {
128
+ "optional": true
129
+ },
130
+ "uWebSockets.js": {
131
+ "optional": true
132
+ }
97
133
  },
98
134
  "scripts": {
99
135
  "build": "tsup",
100
- "test": "vitest run",
136
+ "test": "vitest run --exclude='**/vector/recall.test.ts'",
137
+ "test:etcd": "vitest run src/__tests__/distribution/coordinator/etcd-integration/*.test.ts",
101
138
  "test:watch": "vitest",
102
139
  "test:coverage": "vitest run --coverage",
140
+ "test:recall": "vitest run src/__tests__/vector/recall.test.ts",
141
+ "test:embeddings": "NARSIL_TEST_EMBEDDINGS=1 vitest run embedding-e2e",
103
142
  "bench": "vitest bench",
104
143
  "lint": "biome check src/",
105
- "typecheck": "tsc --noEmit"
144
+ "typecheck:src": "tsc --noEmit",
145
+ "typecheck:tests": "tsc --noEmit -p tsconfig.test.json",
146
+ "typecheck:tooling": "tsc --noEmit -p scripts/tsconfig.json && tsc --noEmit -p benchmarks/tsconfig.json && tsc --noEmit -p wasm/tsconfig.json",
147
+ "typecheck": "pnpm run typecheck:src && pnpm run typecheck:tests && pnpm run typecheck:tooling"
106
148
  }
107
149
  }
@@ -1,43 +0,0 @@
1
- // src/errors.ts
2
- var ErrorCodes = {
3
- SCHEMA_INVALID_TYPE: "SCHEMA_INVALID_TYPE",
4
- SCHEMA_MISSING_FIELD: "SCHEMA_MISSING_FIELD",
5
- SCHEMA_DEPTH_EXCEEDED: "SCHEMA_DEPTH_EXCEEDED",
6
- SCHEMA_INVALID_VECTOR_DIMENSION: "SCHEMA_INVALID_VECTOR_DIMENSION",
7
- SCHEMA_INVALID_GEOPOINT: "SCHEMA_INVALID_GEOPOINT",
8
- DOC_NOT_FOUND: "DOC_NOT_FOUND",
9
- DOC_ALREADY_EXISTS: "DOC_ALREADY_EXISTS",
10
- DOC_VALIDATION_FAILED: "DOC_VALIDATION_FAILED",
11
- INDEX_NOT_FOUND: "INDEX_NOT_FOUND",
12
- INDEX_ALREADY_EXISTS: "INDEX_ALREADY_EXISTS",
13
- PARTITION_CORRUPTED: "PARTITION_CORRUPTED",
14
- PARTITION_REBALANCING_BACKPRESSURE: "PARTITION_REBALANCING_BACKPRESSURE",
15
- WORKER_CRASHED: "WORKER_CRASHED",
16
- WORKER_BUSY: "WORKER_BUSY",
17
- WORKER_TIMEOUT: "WORKER_TIMEOUT",
18
- PERSISTENCE_SAVE_FAILED: "PERSISTENCE_SAVE_FAILED",
19
- PERSISTENCE_LOAD_FAILED: "PERSISTENCE_LOAD_FAILED",
20
- PERSISTENCE_DELETE_FAILED: "PERSISTENCE_DELETE_FAILED",
21
- PERSISTENCE_CRC_MISMATCH: "PERSISTENCE_CRC_MISMATCH",
22
- SEARCH_INVALID_FIELD: "SEARCH_INVALID_FIELD",
23
- SEARCH_INVALID_VECTOR_SIZE: "SEARCH_INVALID_VECTOR_SIZE",
24
- SEARCH_INVALID_FILTER: "SEARCH_INVALID_FILTER",
25
- SEARCH_INVALID_MODE: "SEARCH_INVALID_MODE",
26
- SEARCH_INVALID_CURSOR: "SEARCH_INVALID_CURSOR",
27
- LANGUAGE_NOT_SUPPORTED: "LANGUAGE_NOT_SUPPORTED",
28
- ENVELOPE_VERSION_MISMATCH: "ENVELOPE_VERSION_MISMATCH",
29
- ENVELOPE_INVALID_MAGIC: "ENVELOPE_INVALID_MAGIC",
30
- PARTITION_CAPACITY_EXCEEDED: "PARTITION_CAPACITY_EXCEEDED"
31
- };
32
- var NarsilError = class extends Error {
33
- code;
34
- details;
35
- constructor(code, message, details) {
36
- super(message);
37
- this.name = "NarsilError";
38
- this.code = code;
39
- this.details = details ?? {};
40
- }
41
- };
42
-
43
- export { ErrorCodes, NarsilError };