eigen-db 3.0.0 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/README.md +33 -31
- package/dist/eigen-db.js +144 -158
- package/dist/eigen-db.js.map +1 -1
- package/dist/eigen-db.umd.cjs +1 -1
- package/dist/eigen-db.umd.cjs.map +1 -1
- package/package.json +1 -1
- package/src/lib/__tests__/result-set.test.ts +76 -51
- package/src/lib/__tests__/vector-db.test.ts +22 -19
- package/src/lib/index.ts +10 -4
- package/src/lib/result-set.ts +53 -70
- package/src/lib/types.ts +11 -0
- package/src/lib/vector-db.ts +23 -6
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -50,15 +50,27 @@ Notes:
|
|
|
50
50
|
```ts
|
|
51
51
|
const queryVector = embeddingQuery;
|
|
52
52
|
|
|
53
|
+
// Returns a plain array of { key, score } sorted by similarity
|
|
53
54
|
const results = db.query(queryVector, { topK: 10 });
|
|
54
55
|
|
|
55
|
-
for (
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
for (const { key, score } of results) {
|
|
57
|
+
console.log(key, score);
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
For lazy iteration (useful for pagination or early stopping):
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
const results = db.query(queryVector, { topK: 100, iterable: true });
|
|
65
|
+
|
|
66
|
+
// Iterate and break early — keys are resolved on demand
|
|
67
|
+
for (const { key, score } of results) {
|
|
68
|
+
if (score < 0.5) break;
|
|
69
|
+
console.log(key, score);
|
|
58
70
|
}
|
|
59
71
|
|
|
60
|
-
// Or
|
|
61
|
-
const
|
|
72
|
+
// Or spread into an array when you need all results
|
|
73
|
+
const all = [...results];
|
|
62
74
|
```
|
|
63
75
|
|
|
64
76
|
### 4) Persist and lifecycle
|
|
@@ -80,10 +92,9 @@ await db.clear();
|
|
|
80
92
|
|
|
81
93
|
```ts
|
|
82
94
|
export { DB };
|
|
83
|
-
export { ResultSet };
|
|
84
95
|
export type { ResultItem };
|
|
85
96
|
export { VectorCapacityExceededError };
|
|
86
|
-
export type { OpenOptions, OpenOptionsInternal, SetOptions, QueryOptions, VectorInput };
|
|
97
|
+
export type { OpenOptions, OpenOptionsInternal, SetOptions, QueryOptions, IterableQueryOptions, VectorInput };
|
|
87
98
|
export { InMemoryStorageProvider, OPFSStorageProvider };
|
|
88
99
|
export type { StorageProvider };
|
|
89
100
|
```
|
|
@@ -114,8 +125,12 @@ Opens (or creates) a database instance and loads persisted data.
|
|
|
114
125
|
- Batch insert/update.
|
|
115
126
|
- `getMany(keys: string[]): (number[] | undefined)[]`
|
|
116
127
|
- Batch lookup.
|
|
117
|
-
- `query(value: VectorInput, options?: QueryOptions):
|
|
118
|
-
- Returns similarity-ranked results.
|
|
128
|
+
- `query(value: VectorInput, options?: QueryOptions): ResultItem[]`
|
|
129
|
+
- Returns similarity-ranked results as a plain array.
|
|
130
|
+
- Throws on dimension mismatch.
|
|
131
|
+
- `query(value: VectorInput, options: IterableQueryOptions): Iterable<ResultItem>`
|
|
132
|
+
- With `{ iterable: true }`, returns a lazy iterable. Keys are resolved
|
|
133
|
+
only as each item is consumed, enabling early stopping and pagination.
|
|
119
134
|
- Throws on dimension mismatch.
|
|
120
135
|
- `flush(): Promise<void>`
|
|
121
136
|
- Persists in-memory state to storage.
|
|
@@ -125,27 +140,6 @@ Opens (or creates) a database instance and loads persisted data.
|
|
|
125
140
|
- `clear(): Promise<void>`
|
|
126
141
|
- Clears in-memory state and destroys storage for this DB.
|
|
127
142
|
|
|
128
|
-
### `ResultSet`
|
|
129
|
-
|
|
130
|
-
Represents a lazily resolved, score-sorted search result collection.
|
|
131
|
-
|
|
132
|
-
#### Properties
|
|
133
|
-
|
|
134
|
-
- `length: number` — number of results available (bounded by `topK`)
|
|
135
|
-
|
|
136
|
-
#### Methods
|
|
137
|
-
|
|
138
|
-
- `get(rank: number): ResultItem`
|
|
139
|
-
- Returns the item at rank (`0` is best match).
|
|
140
|
-
- Throws `RangeError` when out of bounds.
|
|
141
|
-
- `getPage(page: number, pageSize: number): ResultItem[]`
|
|
142
|
-
- Convenience pagination helper.
|
|
143
|
-
|
|
144
|
-
#### Static
|
|
145
|
-
|
|
146
|
-
- `fromScores(scores, resolveKey, topK): ResultSet`
|
|
147
|
-
- Constructs a sorted lazy result set from raw scores.
|
|
148
|
-
|
|
149
143
|
### `ResultItem`
|
|
150
144
|
|
|
151
145
|
```ts
|
|
@@ -201,6 +195,14 @@ interface QueryOptions {
|
|
|
201
195
|
}
|
|
202
196
|
```
|
|
203
197
|
|
|
198
|
+
#### `IterableQueryOptions`
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
interface IterableQueryOptions extends QueryOptions {
|
|
202
|
+
iterable: true; // returns Iterable<ResultItem> instead of ResultItem[]
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
204
206
|
### Storage
|
|
205
207
|
|
|
206
208
|
#### `StorageProvider`
|
|
@@ -239,5 +241,5 @@ Thrown when memory growth would exceed WASM 32-bit memory limits for the configu
|
|
|
239
241
|
## Practical notes
|
|
240
242
|
|
|
241
243
|
- Similarity is dot product; with normalization enabled (default), this behaves like cosine similarity.
|
|
242
|
-
- Querying an empty database returns
|
|
244
|
+
- Querying an empty database returns an empty array (`[]`).
|
|
243
245
|
- `flush()` writes deduplicated state, and reopen preserves key-to-slot mapping.
|
package/dist/eigen-db.js
CHANGED
|
@@ -3,52 +3,7 @@ class b extends Error {
|
|
|
3
3
|
super(`Capacity exceeded. Max vectors for this dimension size is ~${e}.`), this.name = "VectorCapacityExceededError";
|
|
4
4
|
}
|
|
5
5
|
}
|
|
6
|
-
class
|
|
7
|
-
/** Total number of results */
|
|
8
|
-
length;
|
|
9
|
-
/**
|
|
10
|
-
* Sorted indices into the original database (by descending score).
|
|
11
|
-
* sortedIndices[0] is the index of the best match.
|
|
12
|
-
*/
|
|
13
|
-
sortedIndices;
|
|
14
|
-
/** Raw scores array (not sorted, indexed by original DB position) */
|
|
15
|
-
scores;
|
|
16
|
-
/** Function to lazily resolve key from the slot index */
|
|
17
|
-
resolveKey;
|
|
18
|
-
constructor(e, t, r, s) {
|
|
19
|
-
this.scores = e, this.sortedIndices = t, this.resolveKey = r, this.length = Math.min(s, t.length);
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Sort scores and return a ResultSet with lazy key resolution.
|
|
23
|
-
*
|
|
24
|
-
* @param scores - Float32Array of scores (one per DB vector)
|
|
25
|
-
* @param resolveKey - Function to resolve key by original index
|
|
26
|
-
* @param topK - Maximum number of results to include
|
|
27
|
-
*/
|
|
28
|
-
static fromScores(e, t, r) {
|
|
29
|
-
const s = e.length, o = new Uint32Array(s);
|
|
30
|
-
for (let n = 0; n < s; n++) o[n] = n;
|
|
31
|
-
return o.sort((n, a) => e[a] - e[n]), new d(e, o, t, r);
|
|
32
|
-
}
|
|
33
|
-
/** Fetch a single result by its rank (0 is best match) */
|
|
34
|
-
get(e) {
|
|
35
|
-
if (e < 0 || e >= this.length)
|
|
36
|
-
throw new RangeError(`Rank ${e} out of bounds [0, ${this.length})`);
|
|
37
|
-
const t = this.sortedIndices[e];
|
|
38
|
-
return {
|
|
39
|
-
key: this.resolveKey(t),
|
|
40
|
-
score: this.scores[t]
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
/** Helper for UI pagination. Instantiates strings only for the requested page. */
|
|
44
|
-
getPage(e, t) {
|
|
45
|
-
const r = e * t, s = Math.min(r + t, this.length), o = [];
|
|
46
|
-
for (let n = r; n < s; n++)
|
|
47
|
-
o.push(this.get(n));
|
|
48
|
-
return o;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
class B {
|
|
6
|
+
class E {
|
|
52
7
|
dirHandle = null;
|
|
53
8
|
dirName;
|
|
54
9
|
constructor(e) {
|
|
@@ -63,19 +18,19 @@ class B {
|
|
|
63
18
|
}
|
|
64
19
|
async readAll(e) {
|
|
65
20
|
try {
|
|
66
|
-
const
|
|
67
|
-
return new Uint8Array(
|
|
21
|
+
const n = await (await (await (await this.getDir()).getFileHandle(e)).getFile()).arrayBuffer();
|
|
22
|
+
return new Uint8Array(n);
|
|
68
23
|
} catch {
|
|
69
24
|
return new Uint8Array(0);
|
|
70
25
|
}
|
|
71
26
|
}
|
|
72
27
|
async append(e, t) {
|
|
73
|
-
const
|
|
74
|
-
await
|
|
28
|
+
const r = await (await this.getDir()).getFileHandle(e, { create: !0 }), n = await r.createWritable({ keepExistingData: !0 }), i = await r.getFile();
|
|
29
|
+
await n.seek(i.size), await n.write(t), await n.close();
|
|
75
30
|
}
|
|
76
31
|
async write(e, t) {
|
|
77
|
-
const
|
|
78
|
-
await
|
|
32
|
+
const n = await (await (await this.getDir()).getFileHandle(e, { create: !0 })).createWritable({ keepExistingData: !1 });
|
|
33
|
+
await n.write(t), await n.close();
|
|
79
34
|
}
|
|
80
35
|
async destroy() {
|
|
81
36
|
await (await navigator.storage.getDirectory()).removeEntry(this.dirName, { recursive: !0 }), this.dirHandle = null;
|
|
@@ -86,11 +41,11 @@ class D {
|
|
|
86
41
|
async readAll(e) {
|
|
87
42
|
const t = this.files.get(e);
|
|
88
43
|
if (!t || t.length === 0) return new Uint8Array(0);
|
|
89
|
-
const
|
|
90
|
-
let
|
|
91
|
-
for (const
|
|
92
|
-
|
|
93
|
-
return
|
|
44
|
+
const s = t.reduce((i, o) => i + o.byteLength, 0), r = new Uint8Array(s);
|
|
45
|
+
let n = 0;
|
|
46
|
+
for (const i of t)
|
|
47
|
+
r.set(i, n), n += i.byteLength;
|
|
48
|
+
return r;
|
|
94
49
|
}
|
|
95
50
|
async append(e, t) {
|
|
96
51
|
this.files.has(e) || this.files.set(e, []), this.files.get(e).push(new Uint8Array(t));
|
|
@@ -102,46 +57,46 @@ class D {
|
|
|
102
57
|
this.files.clear();
|
|
103
58
|
}
|
|
104
59
|
}
|
|
105
|
-
function
|
|
60
|
+
function B(a) {
|
|
106
61
|
let e = 0;
|
|
107
|
-
for (let
|
|
108
|
-
e +=
|
|
62
|
+
for (let r = 0; r < a.length; r++)
|
|
63
|
+
e += a[r] * a[r];
|
|
109
64
|
const t = Math.sqrt(e);
|
|
110
65
|
if (t === 0) return;
|
|
111
|
-
const
|
|
112
|
-
for (let
|
|
113
|
-
|
|
66
|
+
const s = 1 / t;
|
|
67
|
+
for (let r = 0; r < a.length; r++)
|
|
68
|
+
a[r] *= s;
|
|
114
69
|
}
|
|
115
|
-
function
|
|
116
|
-
for (let
|
|
117
|
-
let
|
|
118
|
-
const
|
|
119
|
-
for (let
|
|
120
|
-
|
|
121
|
-
t[
|
|
70
|
+
function M(a, e, t, s, r) {
|
|
71
|
+
for (let n = 0; n < s; n++) {
|
|
72
|
+
let i = 0;
|
|
73
|
+
const o = n * r;
|
|
74
|
+
for (let A = 0; A < r; A++)
|
|
75
|
+
i += a[A] * e[o + A];
|
|
76
|
+
t[n] = i;
|
|
122
77
|
}
|
|
123
78
|
}
|
|
124
|
-
const
|
|
125
|
-
function
|
|
126
|
-
const e =
|
|
127
|
-
let
|
|
128
|
-
for (const
|
|
129
|
-
|
|
130
|
-
return
|
|
79
|
+
const I = new TextEncoder(), Q = new TextDecoder();
|
|
80
|
+
function S(a) {
|
|
81
|
+
const e = a.map((o) => I.encode(o)), t = e.reduce((o, A) => o + 4 + A.byteLength, 0), s = new ArrayBuffer(t), r = new DataView(s), n = new Uint8Array(s);
|
|
82
|
+
let i = 0;
|
|
83
|
+
for (const o of e)
|
|
84
|
+
r.setUint32(i, o.byteLength, !0), i += 4, n.set(o, i), i += o.byteLength;
|
|
85
|
+
return n;
|
|
131
86
|
}
|
|
132
|
-
function O(
|
|
133
|
-
const e = [], t = new DataView(
|
|
134
|
-
let
|
|
135
|
-
for (;
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
const
|
|
139
|
-
e.push(
|
|
87
|
+
function O(a) {
|
|
88
|
+
const e = [], t = new DataView(a.buffer, a.byteOffset, a.byteLength);
|
|
89
|
+
let s = 0;
|
|
90
|
+
for (; s < a.byteLength; ) {
|
|
91
|
+
const r = t.getUint32(s, !0);
|
|
92
|
+
s += 4;
|
|
93
|
+
const n = Q.decode(a.subarray(s, s + r));
|
|
94
|
+
e.push(n), s += r;
|
|
140
95
|
}
|
|
141
96
|
return e;
|
|
142
97
|
}
|
|
143
|
-
const
|
|
144
|
-
class
|
|
98
|
+
const y = 65536, d = 65536;
|
|
99
|
+
class p {
|
|
145
100
|
memory;
|
|
146
101
|
dimensions;
|
|
147
102
|
queryOffset;
|
|
@@ -149,10 +104,10 @@ class x {
|
|
|
149
104
|
_vectorCount;
|
|
150
105
|
constructor(e, t = 0) {
|
|
151
106
|
this.dimensions = e, this.queryOffset = 0;
|
|
152
|
-
const
|
|
153
|
-
this.dbOffset = Math.ceil(
|
|
154
|
-
const
|
|
155
|
-
this.memory = new WebAssembly.Memory({ initial:
|
|
107
|
+
const s = e * 4;
|
|
108
|
+
this.dbOffset = Math.ceil(s / y) * y;
|
|
109
|
+
const r = t * e * 4, n = this.dbOffset + r, i = Math.max(1, Math.ceil(n / y));
|
|
110
|
+
this.memory = new WebAssembly.Memory({ initial: i }), this._vectorCount = t;
|
|
156
111
|
}
|
|
157
112
|
/** Current number of vectors stored */
|
|
158
113
|
get vectorCount() {
|
|
@@ -171,7 +126,7 @@ class x {
|
|
|
171
126
|
* Accounts for query buffer, DB space, and scores buffer.
|
|
172
127
|
*/
|
|
173
128
|
get maxVectors() {
|
|
174
|
-
const e =
|
|
129
|
+
const e = d * y - this.dbOffset, t = this.dimensions * 4 + 4;
|
|
175
130
|
return Math.floor(e / t);
|
|
176
131
|
}
|
|
177
132
|
/**
|
|
@@ -179,12 +134,12 @@ class x {
|
|
|
179
134
|
* Calls memory.grow() if needed.
|
|
180
135
|
*/
|
|
181
136
|
ensureCapacity(e) {
|
|
182
|
-
const t = this._vectorCount + e,
|
|
183
|
-
if (
|
|
184
|
-
const
|
|
185
|
-
if (
|
|
137
|
+
const t = this._vectorCount + e, s = this.dbOffset + t * this.dimensions * 4 + t * 4, r = this.memory.buffer.byteLength;
|
|
138
|
+
if (s > r) {
|
|
139
|
+
const n = Math.ceil((s - r) / y);
|
|
140
|
+
if (r / y + n > d)
|
|
186
141
|
throw new Error("WASM memory limit exceeded");
|
|
187
|
-
this.memory.grow(
|
|
142
|
+
this.memory.grow(n);
|
|
188
143
|
}
|
|
189
144
|
}
|
|
190
145
|
/**
|
|
@@ -199,9 +154,9 @@ class x {
|
|
|
199
154
|
*/
|
|
200
155
|
appendVectors(e) {
|
|
201
156
|
const t = this.dbOffset + this._vectorCount * this.dimensions * 4;
|
|
202
|
-
let
|
|
203
|
-
for (const
|
|
204
|
-
new Float32Array(this.memory.buffer,
|
|
157
|
+
let s = t;
|
|
158
|
+
for (const r of e)
|
|
159
|
+
new Float32Array(this.memory.buffer, s, this.dimensions).set(r), s += this.dimensions * 4;
|
|
205
160
|
return this._vectorCount += e.length, t;
|
|
206
161
|
}
|
|
207
162
|
/**
|
|
@@ -228,8 +183,8 @@ class x {
|
|
|
228
183
|
* Write a vector to a specific slot in the database region.
|
|
229
184
|
*/
|
|
230
185
|
writeVector(e, t) {
|
|
231
|
-
const
|
|
232
|
-
new Float32Array(this.memory.buffer,
|
|
186
|
+
const s = this.dbOffset + e * this.dimensions * 4;
|
|
187
|
+
new Float32Array(this.memory.buffer, s, this.dimensions).set(t);
|
|
233
188
|
}
|
|
234
189
|
/**
|
|
235
190
|
* Reset the vector count to zero, logically clearing the database.
|
|
@@ -239,19 +194,55 @@ class x {
|
|
|
239
194
|
this._vectorCount = 0;
|
|
240
195
|
}
|
|
241
196
|
}
|
|
242
|
-
|
|
197
|
+
function x(a, e, t) {
|
|
198
|
+
const s = a.length;
|
|
199
|
+
if (s === 0) return [];
|
|
200
|
+
const r = new Uint32Array(s);
|
|
201
|
+
for (let o = 0; o < s; o++) r[o] = o;
|
|
202
|
+
r.sort((o, A) => a[A] - a[o]);
|
|
203
|
+
const n = Math.min(t, s), i = new Array(n);
|
|
204
|
+
for (let o = 0; o < n; o++) {
|
|
205
|
+
const A = r[o];
|
|
206
|
+
i[o] = { key: e(A), score: a[A] };
|
|
207
|
+
}
|
|
208
|
+
return i;
|
|
209
|
+
}
|
|
210
|
+
function v(a, e, t) {
|
|
211
|
+
const s = a.length;
|
|
212
|
+
if (s === 0) return [];
|
|
213
|
+
const r = new Uint32Array(s);
|
|
214
|
+
for (let i = 0; i < s; i++) r[i] = i;
|
|
215
|
+
r.sort((i, o) => a[o] - a[i]);
|
|
216
|
+
const n = Math.min(t, s);
|
|
217
|
+
return {
|
|
218
|
+
[Symbol.iterator]() {
|
|
219
|
+
let i = 0;
|
|
220
|
+
return {
|
|
221
|
+
next() {
|
|
222
|
+
if (i >= n) return { done: !0, value: void 0 };
|
|
223
|
+
const o = r[i++];
|
|
224
|
+
return {
|
|
225
|
+
done: !1,
|
|
226
|
+
value: { key: e(o), score: a[o] }
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
const k = "AGFzbQEAAAABDgJgAn9/AGAFf39/f38AAg8BA2VudgZtZW1vcnkCAAEDAwIAAQcaAglub3JtYWxpemUAAApzZWFyY2hfYWxsAAEKsgQCtQIFAX8BewN9AXsDf/0MAAAAAAAAAAAAAAAAAAAAACEDIAFBfHEhCEEAIQICQANAIAIgCE8NASAAIAJBAnRqIQogAyAK/QAEACAK/QAEAP3mAf3kASEDIAJBBGohAgwACwsgA/0fACAD/R8BkiAD/R8CIAP9HwOSkiEEIAghCQJAA0AgCSABTw0BIAAgCUECdGohCiAEIAoqAgAgCioCAJSSIQQgCUEBaiEJDAALCyAEkSEFIAVDAAAAAFsEQA8LQwAAgD8gBZUhBiAG/RMhB0EAIQICQANAIAIgCE8NASAAIAJBAnRqIQogCiAK/QAEACAH/eYB/QsEACACQQRqIQIMAAsLIAghCQJAA0AgCSABTw0BIAAgCUECdGohCiAKIAoqAgAgBpQ4AgAgCUEBaiEJDAALCwv4AQQCfwF7AX0GfyAEQXxxIQogBEECdCEOQQAhBQJAA0AgBSADTw0BIAEgBSAObGohCf0MAAAAAAAAAAAAAAAAAAAAACEHQQAhBgJAA0AgBiAKTw0BIAAgBkECdGohDCAJIAZBAnRqIQ0gByAM/QAEACAN/QAEAP3mAf3kASEHIAZBBGohBgwACwsgB/0fACAH/R8BkiAH/R8CIAf9HwOSkiEIIAohCwJAA0AgCyAETw0BIAAgC0ECdGohDCAJIAtBAnRqIQ0gCCAMKgIAIA0qAgCUkiEIIAtBAWohCwwACwsgAiAFQQJ0aiAIOAIAIAVBAWohBQwACwsL";
|
|
243
234
|
function F() {
|
|
244
|
-
const
|
|
245
|
-
for (let t = 0; t <
|
|
246
|
-
e[t] =
|
|
235
|
+
const a = atob(k), e = new Uint8Array(a.length);
|
|
236
|
+
for (let t = 0; t < a.length; t++)
|
|
237
|
+
e[t] = a.charCodeAt(t);
|
|
247
238
|
return e;
|
|
248
239
|
}
|
|
249
|
-
async function V(
|
|
240
|
+
async function V(a, e) {
|
|
250
241
|
const t = { env: { memory: e } };
|
|
251
|
-
return (await WebAssembly.instantiate(
|
|
242
|
+
return (await WebAssembly.instantiate(a, t)).instance.exports;
|
|
252
243
|
}
|
|
253
|
-
const u = "vectors.bin",
|
|
254
|
-
class
|
|
244
|
+
const u = "vectors.bin", w = "keys.bin";
|
|
245
|
+
class C {
|
|
255
246
|
memoryManager;
|
|
256
247
|
storage;
|
|
257
248
|
dimensions;
|
|
@@ -263,23 +254,23 @@ class E {
|
|
|
263
254
|
slotToKey;
|
|
264
255
|
/** Whether this instance has been closed */
|
|
265
256
|
closed = !1;
|
|
266
|
-
constructor(e, t,
|
|
267
|
-
this.memoryManager = e, this.storage = t, this.dimensions =
|
|
257
|
+
constructor(e, t, s, r, n, i, o) {
|
|
258
|
+
this.memoryManager = e, this.storage = t, this.dimensions = s, this.shouldNormalize = r, this.wasmExports = n, this.keyToSlot = i, this.slotToKey = o;
|
|
268
259
|
}
|
|
269
260
|
static async open(e) {
|
|
270
|
-
const t = e.name ?? "default",
|
|
271
|
-
for (let
|
|
272
|
-
m.set(
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
let
|
|
261
|
+
const t = e.name ?? "default", s = e.storage ?? new E(t), r = e.normalize !== !1, [n, i] = await Promise.all([s.readAll(u), s.readAll(w)]), o = i.byteLength > 0 ? O(i) : [], A = n.byteLength / (e.dimensions * 4), m = /* @__PURE__ */ new Map(), f = [];
|
|
262
|
+
for (let c = 0; c < o.length; c++)
|
|
263
|
+
m.set(o[c], c), f[c] = o[c];
|
|
264
|
+
const h = new p(e.dimensions, A);
|
|
265
|
+
n.byteLength > 0 && h.loadVectorBytes(n, A);
|
|
266
|
+
let l = null;
|
|
276
267
|
const g = e.wasmBinary !== void 0 ? e.wasmBinary : F();
|
|
277
268
|
if (g !== null)
|
|
278
269
|
try {
|
|
279
|
-
|
|
270
|
+
l = await V(g, h.memory);
|
|
280
271
|
} catch {
|
|
281
272
|
}
|
|
282
|
-
return new
|
|
273
|
+
return new C(h, s, e.dimensions, r, l, m, f);
|
|
283
274
|
}
|
|
284
275
|
/** Total number of key-value pairs in the database */
|
|
285
276
|
get size() {
|
|
@@ -289,20 +280,20 @@ class E {
|
|
|
289
280
|
* Set a key-value pair. If the key already exists, its vector is overwritten (last-write-wins).
|
|
290
281
|
* The value is a number[] or Float32Array of length equal to the configured dimensions.
|
|
291
282
|
*/
|
|
292
|
-
set(e, t,
|
|
283
|
+
set(e, t, s) {
|
|
293
284
|
if (this.assertOpen(), t.length !== this.dimensions)
|
|
294
285
|
throw new Error(`Vector dimension mismatch: expected ${this.dimensions}, got ${t.length}`);
|
|
295
|
-
const
|
|
296
|
-
(
|
|
297
|
-
const
|
|
298
|
-
if (
|
|
299
|
-
this.memoryManager.writeVector(
|
|
286
|
+
const r = new Float32Array(t);
|
|
287
|
+
(s?.normalize ?? this.shouldNormalize) && this.normalizeVector(r);
|
|
288
|
+
const i = this.keyToSlot.get(e);
|
|
289
|
+
if (i !== void 0)
|
|
290
|
+
this.memoryManager.writeVector(i, r);
|
|
300
291
|
else {
|
|
301
292
|
if (this.memoryManager.vectorCount + 1 > this.memoryManager.maxVectors)
|
|
302
293
|
throw new b(this.memoryManager.maxVectors);
|
|
303
294
|
this.memoryManager.ensureCapacity(1);
|
|
304
|
-
const
|
|
305
|
-
this.memoryManager.appendVectors([
|
|
295
|
+
const A = this.memoryManager.vectorCount;
|
|
296
|
+
this.memoryManager.appendVectors([r]), this.keyToSlot.set(e, A), this.slotToKey[A] = e;
|
|
306
297
|
}
|
|
307
298
|
}
|
|
308
299
|
/**
|
|
@@ -319,8 +310,8 @@ class E {
|
|
|
319
310
|
* Set multiple key-value pairs at once. Last-write-wins applies within the batch.
|
|
320
311
|
*/
|
|
321
312
|
setMany(e) {
|
|
322
|
-
for (const [t,
|
|
323
|
-
this.set(t,
|
|
313
|
+
for (const [t, s] of e)
|
|
314
|
+
this.set(t, s);
|
|
324
315
|
}
|
|
325
316
|
/**
|
|
326
317
|
* Get vectors for multiple keys. Returns undefined for keys that don't exist.
|
|
@@ -328,42 +319,38 @@ class E {
|
|
|
328
319
|
getMany(e) {
|
|
329
320
|
return e.map((t) => this.get(t));
|
|
330
321
|
}
|
|
331
|
-
/**
|
|
332
|
-
* Search for the most similar vectors to the given query vector.
|
|
333
|
-
* Returns a ResultSet sorted by descending similarity score.
|
|
334
|
-
*/
|
|
335
322
|
query(e, t) {
|
|
336
323
|
this.assertOpen();
|
|
337
|
-
const
|
|
324
|
+
const s = t?.topK ?? this.size, r = t && "iterable" in t && t.iterable;
|
|
338
325
|
if (this.size === 0)
|
|
339
|
-
return
|
|
326
|
+
return [];
|
|
340
327
|
if (e.length !== this.dimensions)
|
|
341
328
|
throw new Error(`Query vector dimension mismatch: expected ${this.dimensions}, got ${e.length}`);
|
|
342
|
-
const
|
|
343
|
-
(t?.normalize ?? this.shouldNormalize) && this.normalizeVector(
|
|
344
|
-
const
|
|
329
|
+
const n = new Float32Array(e);
|
|
330
|
+
(t?.normalize ?? this.shouldNormalize) && this.normalizeVector(n), this.memoryManager.writeQuery(n), this.memoryManager.ensureCapacity(0);
|
|
331
|
+
const o = this.memoryManager.vectorCount, A = this.memoryManager.scoresOffset;
|
|
345
332
|
if (this.wasmExports)
|
|
346
333
|
this.wasmExports.search_all(
|
|
347
334
|
this.memoryManager.queryOffset,
|
|
348
335
|
this.memoryManager.dbOffset,
|
|
349
|
-
|
|
350
|
-
|
|
336
|
+
A,
|
|
337
|
+
o,
|
|
351
338
|
this.dimensions
|
|
352
339
|
);
|
|
353
340
|
else {
|
|
354
|
-
const
|
|
341
|
+
const l = new Float32Array(
|
|
355
342
|
this.memoryManager.memory.buffer,
|
|
356
343
|
this.memoryManager.queryOffset,
|
|
357
344
|
this.dimensions
|
|
358
|
-
),
|
|
345
|
+
), g = new Float32Array(
|
|
359
346
|
this.memoryManager.memory.buffer,
|
|
360
347
|
this.memoryManager.dbOffset,
|
|
361
|
-
|
|
362
|
-
),
|
|
363
|
-
|
|
348
|
+
o * this.dimensions
|
|
349
|
+
), c = new Float32Array(this.memoryManager.memory.buffer, A, o);
|
|
350
|
+
M(l, g, c, o, this.dimensions);
|
|
364
351
|
}
|
|
365
|
-
const
|
|
366
|
-
return
|
|
352
|
+
const m = new Float32Array(this.memoryManager.readScores()), f = this.slotToKey, h = (l) => f[l];
|
|
353
|
+
return r ? v(m, h, s) : x(m, h, s);
|
|
367
354
|
}
|
|
368
355
|
/**
|
|
369
356
|
* Persist the current in-memory state to storage.
|
|
@@ -372,15 +359,15 @@ class E {
|
|
|
372
359
|
this.assertOpen();
|
|
373
360
|
const e = this.memoryManager.vectorCount, t = new Uint8Array(e * this.dimensions * 4);
|
|
374
361
|
if (e > 0) {
|
|
375
|
-
const
|
|
362
|
+
const r = new Uint8Array(
|
|
376
363
|
this.memoryManager.memory.buffer,
|
|
377
364
|
this.memoryManager.dbOffset,
|
|
378
365
|
e * this.dimensions * 4
|
|
379
366
|
);
|
|
380
|
-
t.set(
|
|
367
|
+
t.set(r);
|
|
381
368
|
}
|
|
382
|
-
const
|
|
383
|
-
await Promise.all([this.storage.write(u, t), this.storage.write(
|
|
369
|
+
const s = S(this.slotToKey);
|
|
370
|
+
await Promise.all([this.storage.write(u, t), this.storage.write(w, s)]);
|
|
384
371
|
}
|
|
385
372
|
/**
|
|
386
373
|
* Flush data to storage and release the instance.
|
|
@@ -402,10 +389,10 @@ class E {
|
|
|
402
389
|
if (this.wasmExports) {
|
|
403
390
|
const t = this.memoryManager.queryOffset;
|
|
404
391
|
new Float32Array(this.memoryManager.memory.buffer, t, e.length).set(e), this.wasmExports.normalize(t, e.length);
|
|
405
|
-
const
|
|
406
|
-
e.set(
|
|
392
|
+
const s = new Float32Array(this.memoryManager.memory.buffer, t, e.length);
|
|
393
|
+
e.set(s);
|
|
407
394
|
} else
|
|
408
|
-
|
|
395
|
+
B(e);
|
|
409
396
|
}
|
|
410
397
|
assertOpen() {
|
|
411
398
|
if (this.closed)
|
|
@@ -413,10 +400,9 @@ class E {
|
|
|
413
400
|
}
|
|
414
401
|
}
|
|
415
402
|
export {
|
|
416
|
-
|
|
403
|
+
C as DB,
|
|
417
404
|
D as InMemoryStorageProvider,
|
|
418
|
-
|
|
419
|
-
d as ResultSet,
|
|
405
|
+
E as OPFSStorageProvider,
|
|
420
406
|
b as VectorCapacityExceededError
|
|
421
407
|
};
|
|
422
408
|
//# sourceMappingURL=eigen-db.js.map
|