taladb 0.2.11 → 0.4.0
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/dist/index.d.mts +48 -1
- package/dist/index.d.ts +48 -1
- package/dist/index.js +82 -112
- package/dist/index.mjs +82 -112
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -5,6 +5,26 @@ interface VectorIndexOptions {
|
|
|
5
5
|
dimensions: number;
|
|
6
6
|
/** Similarity metric. Defaults to `"cosine"`. */
|
|
7
7
|
metric?: VectorMetric;
|
|
8
|
+
/**
|
|
9
|
+
* Index algorithm. Defaults to `"flat"` (exact brute-force).
|
|
10
|
+
* Use `"hnsw"` for approximate nearest-neighbour search — much faster on
|
|
11
|
+
* large collections at the cost of occasional missed results.
|
|
12
|
+
* Requires the `vector-hnsw` feature to be compiled in.
|
|
13
|
+
*/
|
|
14
|
+
indexType?: 'flat' | 'hnsw';
|
|
15
|
+
/** HNSW connectivity parameter M (default 16). Higher = better recall, more memory. */
|
|
16
|
+
hnswM?: number;
|
|
17
|
+
/** HNSW build-time quality parameter ef_construction (default 200). */
|
|
18
|
+
hnswEfConstruction?: number;
|
|
19
|
+
}
|
|
20
|
+
/** Describes the indexes that exist on a collection. */
|
|
21
|
+
interface CollectionIndexInfo {
|
|
22
|
+
/** B-tree indexes (created with `createIndex`). */
|
|
23
|
+
btree: string[];
|
|
24
|
+
/** Full-text search indexes (created with `createFtsIndex`). */
|
|
25
|
+
fts: string[];
|
|
26
|
+
/** Vector indexes (created with `createVectorIndex`). */
|
|
27
|
+
vector: string[];
|
|
8
28
|
}
|
|
9
29
|
/** A single result returned by `Collection.findNearest`. */
|
|
10
30
|
interface VectorSearchResult<T extends Document = Document> {
|
|
@@ -72,6 +92,25 @@ interface Collection<T extends Document = Document> {
|
|
|
72
92
|
count(filter?: Filter<T>): Promise<number>;
|
|
73
93
|
createIndex(field: keyof Omit<T, '_id'> & string): Promise<void>;
|
|
74
94
|
dropIndex(field: keyof Omit<T, '_id'> & string): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Create a full-text search index on a string field.
|
|
97
|
+
*
|
|
98
|
+
* Enables fast `{ field: { $contains: 'token' } }` queries using an
|
|
99
|
+
* inverted token index instead of a full collection scan.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* await notes.createFtsIndex('body');
|
|
103
|
+
*/
|
|
104
|
+
createFtsIndex(field: keyof Omit<T, '_id'> & string): Promise<void>;
|
|
105
|
+
/** Drop a full-text search index. */
|
|
106
|
+
dropFtsIndex(field: keyof Omit<T, '_id'> & string): Promise<void>;
|
|
107
|
+
/**
|
|
108
|
+
* Return the indexes that currently exist on this collection.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* const { btree, fts, vector } = await notes.listIndexes();
|
|
112
|
+
*/
|
|
113
|
+
listIndexes(): Promise<CollectionIndexInfo>;
|
|
75
114
|
/**
|
|
76
115
|
* Create a vector index on a numeric-array field.
|
|
77
116
|
*
|
|
@@ -84,6 +123,14 @@ interface Collection<T extends Document = Document> {
|
|
|
84
123
|
createVectorIndex(field: keyof Omit<T, '_id'> & string, options: VectorIndexOptions): Promise<void>;
|
|
85
124
|
/** Drop a vector index. */
|
|
86
125
|
dropVectorIndex(field: keyof Omit<T, '_id'> & string): Promise<void>;
|
|
126
|
+
/**
|
|
127
|
+
* Upgrade a flat vector index to HNSW in-place.
|
|
128
|
+
*
|
|
129
|
+
* After calling this, `findNearest` uses approximate nearest-neighbour
|
|
130
|
+
* search which is significantly faster on large collections.
|
|
131
|
+
* Requires the `vector-hnsw` feature to be compiled in; no-op otherwise.
|
|
132
|
+
*/
|
|
133
|
+
upgradeVectorIndex(field: keyof Omit<T, '_id'> & string): Promise<void>;
|
|
87
134
|
/**
|
|
88
135
|
* Find the `topK` most similar documents to `vector` using a vector index.
|
|
89
136
|
*
|
|
@@ -136,4 +183,4 @@ interface TalaDB {
|
|
|
136
183
|
*/
|
|
137
184
|
declare function openDB(dbName?: string): Promise<TalaDB>;
|
|
138
185
|
|
|
139
|
-
export { type Collection, type Document, type Filter, type TalaDB, type Update, type Value, type VectorIndexOptions, type VectorMetric, type VectorSearchResult, openDB };
|
|
186
|
+
export { type Collection, type CollectionIndexInfo, type Document, type Filter, type TalaDB, type Update, type Value, type VectorIndexOptions, type VectorMetric, type VectorSearchResult, openDB };
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,26 @@ interface VectorIndexOptions {
|
|
|
5
5
|
dimensions: number;
|
|
6
6
|
/** Similarity metric. Defaults to `"cosine"`. */
|
|
7
7
|
metric?: VectorMetric;
|
|
8
|
+
/**
|
|
9
|
+
* Index algorithm. Defaults to `"flat"` (exact brute-force).
|
|
10
|
+
* Use `"hnsw"` for approximate nearest-neighbour search — much faster on
|
|
11
|
+
* large collections at the cost of occasional missed results.
|
|
12
|
+
* Requires the `vector-hnsw` feature to be compiled in.
|
|
13
|
+
*/
|
|
14
|
+
indexType?: 'flat' | 'hnsw';
|
|
15
|
+
/** HNSW connectivity parameter M (default 16). Higher = better recall, more memory. */
|
|
16
|
+
hnswM?: number;
|
|
17
|
+
/** HNSW build-time quality parameter ef_construction (default 200). */
|
|
18
|
+
hnswEfConstruction?: number;
|
|
19
|
+
}
|
|
20
|
+
/** Describes the indexes that exist on a collection. */
|
|
21
|
+
interface CollectionIndexInfo {
|
|
22
|
+
/** B-tree indexes (created with `createIndex`). */
|
|
23
|
+
btree: string[];
|
|
24
|
+
/** Full-text search indexes (created with `createFtsIndex`). */
|
|
25
|
+
fts: string[];
|
|
26
|
+
/** Vector indexes (created with `createVectorIndex`). */
|
|
27
|
+
vector: string[];
|
|
8
28
|
}
|
|
9
29
|
/** A single result returned by `Collection.findNearest`. */
|
|
10
30
|
interface VectorSearchResult<T extends Document = Document> {
|
|
@@ -72,6 +92,25 @@ interface Collection<T extends Document = Document> {
|
|
|
72
92
|
count(filter?: Filter<T>): Promise<number>;
|
|
73
93
|
createIndex(field: keyof Omit<T, '_id'> & string): Promise<void>;
|
|
74
94
|
dropIndex(field: keyof Omit<T, '_id'> & string): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Create a full-text search index on a string field.
|
|
97
|
+
*
|
|
98
|
+
* Enables fast `{ field: { $contains: 'token' } }` queries using an
|
|
99
|
+
* inverted token index instead of a full collection scan.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* await notes.createFtsIndex('body');
|
|
103
|
+
*/
|
|
104
|
+
createFtsIndex(field: keyof Omit<T, '_id'> & string): Promise<void>;
|
|
105
|
+
/** Drop a full-text search index. */
|
|
106
|
+
dropFtsIndex(field: keyof Omit<T, '_id'> & string): Promise<void>;
|
|
107
|
+
/**
|
|
108
|
+
* Return the indexes that currently exist on this collection.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* const { btree, fts, vector } = await notes.listIndexes();
|
|
112
|
+
*/
|
|
113
|
+
listIndexes(): Promise<CollectionIndexInfo>;
|
|
75
114
|
/**
|
|
76
115
|
* Create a vector index on a numeric-array field.
|
|
77
116
|
*
|
|
@@ -84,6 +123,14 @@ interface Collection<T extends Document = Document> {
|
|
|
84
123
|
createVectorIndex(field: keyof Omit<T, '_id'> & string, options: VectorIndexOptions): Promise<void>;
|
|
85
124
|
/** Drop a vector index. */
|
|
86
125
|
dropVectorIndex(field: keyof Omit<T, '_id'> & string): Promise<void>;
|
|
126
|
+
/**
|
|
127
|
+
* Upgrade a flat vector index to HNSW in-place.
|
|
128
|
+
*
|
|
129
|
+
* After calling this, `findNearest` uses approximate nearest-neighbour
|
|
130
|
+
* search which is significantly faster on large collections.
|
|
131
|
+
* Requires the `vector-hnsw` feature to be compiled in; no-op otherwise.
|
|
132
|
+
*/
|
|
133
|
+
upgradeVectorIndex(field: keyof Omit<T, '_id'> & string): Promise<void>;
|
|
87
134
|
/**
|
|
88
135
|
* Find the `topK` most similar documents to `vector` using a vector index.
|
|
89
136
|
*
|
|
@@ -136,4 +183,4 @@ interface TalaDB {
|
|
|
136
183
|
*/
|
|
137
184
|
declare function openDB(dbName?: string): Promise<TalaDB>;
|
|
138
185
|
|
|
139
|
-
export { type Collection, type Document, type Filter, type TalaDB, type Update, type Value, type VectorIndexOptions, type VectorMetric, type VectorSearchResult, openDB };
|
|
186
|
+
export { type Collection, type CollectionIndexInfo, type Document, type Filter, type TalaDB, type Update, type Value, type VectorIndexOptions, type VectorMetric, type VectorSearchResult, openDB };
|
package/dist/index.js
CHANGED
|
@@ -57,7 +57,7 @@ var WorkerProxy = class {
|
|
|
57
57
|
else p.reject(new Error(error));
|
|
58
58
|
}
|
|
59
59
|
};
|
|
60
|
-
this.port.start();
|
|
60
|
+
this.port.start?.();
|
|
61
61
|
}
|
|
62
62
|
send(op, args = {}) {
|
|
63
63
|
return new Promise((resolve, reject) => {
|
|
@@ -67,71 +67,42 @@ var WorkerProxy = class {
|
|
|
67
67
|
});
|
|
68
68
|
}
|
|
69
69
|
};
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
insert: async (doc) => col.insert(doc),
|
|
82
|
-
insertMany: async (docs) => col.insertMany(docs),
|
|
83
|
-
find: async (filter) => col.find(filter ?? null),
|
|
84
|
-
findOne: async (filter) => col.findOne(filter) ?? null,
|
|
85
|
-
updateOne: async (filter, update) => col.updateOne(filter, update),
|
|
86
|
-
updateMany: async (filter, update) => col.updateMany(filter, update),
|
|
87
|
-
deleteOne: async (filter) => col.deleteOne(filter),
|
|
88
|
-
deleteMany: async (filter) => col.deleteMany(filter),
|
|
89
|
-
count: async (filter) => col.count(filter ?? null),
|
|
90
|
-
createIndex: async (field) => col.createIndex(field),
|
|
91
|
-
dropIndex: async (field) => col.dropIndex(field),
|
|
92
|
-
createVectorIndex: async (field, options) => col.createVectorIndex(field, options.dimensions, options.metric ?? null),
|
|
93
|
-
dropVectorIndex: async (field) => col.dropVectorIndex(field),
|
|
94
|
-
findNearest: async (field, vector, topK, filter) => {
|
|
95
|
-
const raw = await col.findNearest(field, vector, topK, filter ?? null);
|
|
96
|
-
return raw;
|
|
97
|
-
},
|
|
98
|
-
subscribe: (filter, callback) => {
|
|
99
|
-
let active = true;
|
|
100
|
-
let lastJson = "";
|
|
101
|
-
const poll = async () => {
|
|
102
|
-
if (!active) return;
|
|
103
|
-
try {
|
|
104
|
-
const docs = await col.find(filter ?? null);
|
|
105
|
-
const json = JSON.stringify(docs);
|
|
106
|
-
if (json !== lastJson) {
|
|
107
|
-
lastJson = json;
|
|
108
|
-
callback(docs);
|
|
109
|
-
}
|
|
110
|
-
} catch {
|
|
111
|
-
}
|
|
112
|
-
if (active) setTimeout(poll, 300);
|
|
113
|
-
};
|
|
114
|
-
poll();
|
|
115
|
-
return () => {
|
|
116
|
-
active = false;
|
|
117
|
-
};
|
|
70
|
+
function makePoller(findFn, callback) {
|
|
71
|
+
let active = true;
|
|
72
|
+
let lastJson = "";
|
|
73
|
+
const poll = async () => {
|
|
74
|
+
if (!active) return;
|
|
75
|
+
try {
|
|
76
|
+
const docs = await findFn();
|
|
77
|
+
const json = JSON.stringify(docs);
|
|
78
|
+
if (json !== lastJson) {
|
|
79
|
+
lastJson = json;
|
|
80
|
+
callback(docs);
|
|
118
81
|
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
return {
|
|
122
|
-
collection: (name) => wrapCollection(name),
|
|
123
|
-
close: async () => {
|
|
82
|
+
} catch {
|
|
124
83
|
}
|
|
84
|
+
if (active) setTimeout(poll, 300);
|
|
85
|
+
};
|
|
86
|
+
poll();
|
|
87
|
+
return () => {
|
|
88
|
+
active = false;
|
|
125
89
|
};
|
|
126
90
|
}
|
|
127
91
|
async function createBrowserDB(dbName) {
|
|
128
|
-
if (typeof SharedWorker === "undefined") {
|
|
129
|
-
return createInMemoryBrowserDB(dbName);
|
|
130
|
-
}
|
|
131
92
|
const workerUrl = new URL("@taladb/web/worker/taladb.worker.js", import_meta.url);
|
|
132
|
-
const worker = new
|
|
133
|
-
const proxy = new WorkerProxy(worker
|
|
93
|
+
const worker = new Worker(workerUrl, { type: "module", name: "taladb" });
|
|
94
|
+
const proxy = new WorkerProxy(worker);
|
|
134
95
|
await proxy.send("init", { dbName });
|
|
96
|
+
const nudgeCallbacks = /* @__PURE__ */ new Set();
|
|
97
|
+
let channel = null;
|
|
98
|
+
if (typeof BroadcastChannel !== "undefined") {
|
|
99
|
+
channel = new BroadcastChannel(`taladb:${dbName}`);
|
|
100
|
+
channel.onmessage = (e) => {
|
|
101
|
+
if (e.data === "taladb:changed") {
|
|
102
|
+
for (const nudge of nudgeCallbacks) nudge();
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
135
106
|
function wrapCollection(name) {
|
|
136
107
|
const s = JSON.stringify;
|
|
137
108
|
return {
|
|
@@ -175,13 +146,26 @@ async function createBrowserDB(dbName) {
|
|
|
175
146
|
}),
|
|
176
147
|
createIndex: (field) => proxy.send("createIndex", { collection: name, field }),
|
|
177
148
|
dropIndex: (field) => proxy.send("dropIndex", { collection: name, field }),
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
149
|
+
createFtsIndex: (field) => proxy.send("createFtsIndex", { collection: name, field }),
|
|
150
|
+
dropFtsIndex: (field) => proxy.send("dropFtsIndex", { collection: name, field }),
|
|
151
|
+
createVectorIndex: (field, options) => {
|
|
152
|
+
if (options.indexType === "hnsw") return Promise.reject(new Error("HNSW vector indexes are not available in the browser (requires native threads). Use Node.js or React Native."));
|
|
153
|
+
return proxy.send("createVectorIndex", {
|
|
154
|
+
collection: name,
|
|
155
|
+
field,
|
|
156
|
+
dimensions: options.dimensions,
|
|
157
|
+
metric: options.metric,
|
|
158
|
+
indexType: null,
|
|
159
|
+
hnswM: null,
|
|
160
|
+
hnswEfConstruction: null
|
|
161
|
+
});
|
|
162
|
+
},
|
|
184
163
|
dropVectorIndex: (field) => proxy.send("dropVectorIndex", { collection: name, field }),
|
|
164
|
+
upgradeVectorIndex: (_field) => Promise.reject(new Error("HNSW vector indexes are not available in the browser (requires native threads). Use Node.js or React Native.")),
|
|
165
|
+
listIndexes: async () => {
|
|
166
|
+
const json = await proxy.send("listIndexes", { collection: name });
|
|
167
|
+
return JSON.parse(json);
|
|
168
|
+
},
|
|
185
169
|
findNearest: async (field, vector, topK, filter) => {
|
|
186
170
|
const json = await proxy.send("findNearest", {
|
|
187
171
|
collection: name,
|
|
@@ -194,9 +178,14 @@ async function createBrowserDB(dbName) {
|
|
|
194
178
|
},
|
|
195
179
|
subscribe: (filter, callback) => {
|
|
196
180
|
let active = true;
|
|
197
|
-
let lastJson = "";
|
|
181
|
+
let lastJson = "[]";
|
|
182
|
+
let timer = null;
|
|
198
183
|
const poll = async () => {
|
|
199
184
|
if (!active) return;
|
|
185
|
+
if (timer !== null) {
|
|
186
|
+
clearTimeout(timer);
|
|
187
|
+
timer = null;
|
|
188
|
+
}
|
|
200
189
|
try {
|
|
201
190
|
const json = await proxy.send("find", {
|
|
202
191
|
collection: name,
|
|
@@ -208,18 +197,28 @@ async function createBrowserDB(dbName) {
|
|
|
208
197
|
}
|
|
209
198
|
} catch {
|
|
210
199
|
}
|
|
211
|
-
if (active) setTimeout(poll, 300);
|
|
200
|
+
if (active) timer = setTimeout(poll, 300);
|
|
212
201
|
};
|
|
202
|
+
nudgeCallbacks.add(poll);
|
|
213
203
|
poll();
|
|
214
204
|
return () => {
|
|
215
205
|
active = false;
|
|
206
|
+
nudgeCallbacks.delete(poll);
|
|
207
|
+
if (timer !== null) {
|
|
208
|
+
clearTimeout(timer);
|
|
209
|
+
timer = null;
|
|
210
|
+
}
|
|
216
211
|
};
|
|
217
212
|
}
|
|
218
213
|
};
|
|
219
214
|
}
|
|
220
215
|
return {
|
|
221
216
|
collection: (name) => wrapCollection(name),
|
|
222
|
-
close: () =>
|
|
217
|
+
close: async () => {
|
|
218
|
+
channel?.close();
|
|
219
|
+
await proxy.send("close");
|
|
220
|
+
worker.terminate();
|
|
221
|
+
}
|
|
223
222
|
};
|
|
224
223
|
}
|
|
225
224
|
async function createNodeDB(dbName) {
|
|
@@ -239,33 +238,20 @@ async function createNodeDB(dbName) {
|
|
|
239
238
|
count: async (filter) => col.count(filter ?? null),
|
|
240
239
|
createIndex: async (field) => col.createIndex(field),
|
|
241
240
|
dropIndex: async (field) => col.dropIndex(field),
|
|
242
|
-
|
|
241
|
+
createFtsIndex: async (field) => col.createFtsIndex(field),
|
|
242
|
+
dropFtsIndex: async (field) => col.dropFtsIndex(field),
|
|
243
|
+
createVectorIndex: async (field, options) => col.createVectorIndex(field, options.dimensions, options.metric ?? null, options.indexType ?? null, options.hnswM ?? null, options.hnswEfConstruction ?? null),
|
|
243
244
|
dropVectorIndex: async (field) => col.dropVectorIndex(field),
|
|
245
|
+
upgradeVectorIndex: async (field) => col.upgradeVectorIndex(field),
|
|
246
|
+
listIndexes: async () => {
|
|
247
|
+
const json = col.listIndexes();
|
|
248
|
+
return JSON.parse(json);
|
|
249
|
+
},
|
|
244
250
|
findNearest: async (field, vector, topK, filter) => {
|
|
245
251
|
const raw = await col.findNearest(field, vector, topK, filter ?? null);
|
|
246
252
|
return raw;
|
|
247
253
|
},
|
|
248
|
-
subscribe: (filter, callback) =>
|
|
249
|
-
let active = true;
|
|
250
|
-
let lastJson = "";
|
|
251
|
-
const poll = async () => {
|
|
252
|
-
if (!active) return;
|
|
253
|
-
try {
|
|
254
|
-
const docs = await col.find(filter ?? null);
|
|
255
|
-
const json = JSON.stringify(docs);
|
|
256
|
-
if (json !== lastJson) {
|
|
257
|
-
lastJson = json;
|
|
258
|
-
callback(docs);
|
|
259
|
-
}
|
|
260
|
-
} catch {
|
|
261
|
-
}
|
|
262
|
-
if (active) setTimeout(poll, 300);
|
|
263
|
-
};
|
|
264
|
-
poll();
|
|
265
|
-
return () => {
|
|
266
|
-
active = false;
|
|
267
|
-
};
|
|
268
|
-
}
|
|
254
|
+
subscribe: (filter, callback) => makePoller(async () => col.find(filter ?? null), callback)
|
|
269
255
|
};
|
|
270
256
|
}
|
|
271
257
|
return {
|
|
@@ -296,33 +282,17 @@ async function createNativeDB(_dbName) {
|
|
|
296
282
|
count: async (filter) => col.count(filter ?? {}),
|
|
297
283
|
createIndex: async (field) => col.createIndex(field),
|
|
298
284
|
dropIndex: async (field) => col.dropIndex(field),
|
|
299
|
-
|
|
285
|
+
createFtsIndex: async (field) => col.createFtsIndex(field),
|
|
286
|
+
dropFtsIndex: async (field) => col.dropFtsIndex(field),
|
|
287
|
+
createVectorIndex: async (field, options) => col.createVectorIndex(field, options.dimensions, options.metric ?? null, options.indexType ?? null, options.hnswM ?? null, options.hnswEfConstruction ?? null),
|
|
300
288
|
dropVectorIndex: async (field) => col.dropVectorIndex(field),
|
|
289
|
+
upgradeVectorIndex: async (field) => col.upgradeVectorIndex(field),
|
|
290
|
+
listIndexes: async () => JSON.parse(col.listIndexes()),
|
|
301
291
|
findNearest: async (field, vector, topK, filter) => {
|
|
302
292
|
const raw = col.findNearest(field, vector, topK, filter ?? null);
|
|
303
293
|
return raw;
|
|
304
294
|
},
|
|
305
|
-
subscribe: (filter, callback) => {
|
|
306
|
-
let active = true;
|
|
307
|
-
let lastJson = "";
|
|
308
|
-
const poll = () => {
|
|
309
|
-
if (!active) return;
|
|
310
|
-
try {
|
|
311
|
-
const docs = col.find(filter ?? {});
|
|
312
|
-
const json = JSON.stringify(docs);
|
|
313
|
-
if (json !== lastJson) {
|
|
314
|
-
lastJson = json;
|
|
315
|
-
callback(docs);
|
|
316
|
-
}
|
|
317
|
-
} catch {
|
|
318
|
-
}
|
|
319
|
-
if (active) setTimeout(poll, 300);
|
|
320
|
-
};
|
|
321
|
-
poll();
|
|
322
|
-
return () => {
|
|
323
|
-
active = false;
|
|
324
|
-
};
|
|
325
|
-
}
|
|
295
|
+
subscribe: (filter, callback) => makePoller(async () => col.find(filter ?? {}), callback)
|
|
326
296
|
};
|
|
327
297
|
}
|
|
328
298
|
return {
|
package/dist/index.mjs
CHANGED
|
@@ -22,7 +22,7 @@ var WorkerProxy = class {
|
|
|
22
22
|
else p.reject(new Error(error));
|
|
23
23
|
}
|
|
24
24
|
};
|
|
25
|
-
this.port.start();
|
|
25
|
+
this.port.start?.();
|
|
26
26
|
}
|
|
27
27
|
send(op, args = {}) {
|
|
28
28
|
return new Promise((resolve, reject) => {
|
|
@@ -32,71 +32,42 @@ var WorkerProxy = class {
|
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
34
|
};
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
insert: async (doc) => col.insert(doc),
|
|
47
|
-
insertMany: async (docs) => col.insertMany(docs),
|
|
48
|
-
find: async (filter) => col.find(filter ?? null),
|
|
49
|
-
findOne: async (filter) => col.findOne(filter) ?? null,
|
|
50
|
-
updateOne: async (filter, update) => col.updateOne(filter, update),
|
|
51
|
-
updateMany: async (filter, update) => col.updateMany(filter, update),
|
|
52
|
-
deleteOne: async (filter) => col.deleteOne(filter),
|
|
53
|
-
deleteMany: async (filter) => col.deleteMany(filter),
|
|
54
|
-
count: async (filter) => col.count(filter ?? null),
|
|
55
|
-
createIndex: async (field) => col.createIndex(field),
|
|
56
|
-
dropIndex: async (field) => col.dropIndex(field),
|
|
57
|
-
createVectorIndex: async (field, options) => col.createVectorIndex(field, options.dimensions, options.metric ?? null),
|
|
58
|
-
dropVectorIndex: async (field) => col.dropVectorIndex(field),
|
|
59
|
-
findNearest: async (field, vector, topK, filter) => {
|
|
60
|
-
const raw = await col.findNearest(field, vector, topK, filter ?? null);
|
|
61
|
-
return raw;
|
|
62
|
-
},
|
|
63
|
-
subscribe: (filter, callback) => {
|
|
64
|
-
let active = true;
|
|
65
|
-
let lastJson = "";
|
|
66
|
-
const poll = async () => {
|
|
67
|
-
if (!active) return;
|
|
68
|
-
try {
|
|
69
|
-
const docs = await col.find(filter ?? null);
|
|
70
|
-
const json = JSON.stringify(docs);
|
|
71
|
-
if (json !== lastJson) {
|
|
72
|
-
lastJson = json;
|
|
73
|
-
callback(docs);
|
|
74
|
-
}
|
|
75
|
-
} catch {
|
|
76
|
-
}
|
|
77
|
-
if (active) setTimeout(poll, 300);
|
|
78
|
-
};
|
|
79
|
-
poll();
|
|
80
|
-
return () => {
|
|
81
|
-
active = false;
|
|
82
|
-
};
|
|
35
|
+
function makePoller(findFn, callback) {
|
|
36
|
+
let active = true;
|
|
37
|
+
let lastJson = "";
|
|
38
|
+
const poll = async () => {
|
|
39
|
+
if (!active) return;
|
|
40
|
+
try {
|
|
41
|
+
const docs = await findFn();
|
|
42
|
+
const json = JSON.stringify(docs);
|
|
43
|
+
if (json !== lastJson) {
|
|
44
|
+
lastJson = json;
|
|
45
|
+
callback(docs);
|
|
83
46
|
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return {
|
|
87
|
-
collection: (name) => wrapCollection(name),
|
|
88
|
-
close: async () => {
|
|
47
|
+
} catch {
|
|
89
48
|
}
|
|
49
|
+
if (active) setTimeout(poll, 300);
|
|
50
|
+
};
|
|
51
|
+
poll();
|
|
52
|
+
return () => {
|
|
53
|
+
active = false;
|
|
90
54
|
};
|
|
91
55
|
}
|
|
92
56
|
async function createBrowserDB(dbName) {
|
|
93
|
-
if (typeof SharedWorker === "undefined") {
|
|
94
|
-
return createInMemoryBrowserDB(dbName);
|
|
95
|
-
}
|
|
96
57
|
const workerUrl = new URL("@taladb/web/worker/taladb.worker.js", import.meta.url);
|
|
97
|
-
const worker = new
|
|
98
|
-
const proxy = new WorkerProxy(worker
|
|
58
|
+
const worker = new Worker(workerUrl, { type: "module", name: "taladb" });
|
|
59
|
+
const proxy = new WorkerProxy(worker);
|
|
99
60
|
await proxy.send("init", { dbName });
|
|
61
|
+
const nudgeCallbacks = /* @__PURE__ */ new Set();
|
|
62
|
+
let channel = null;
|
|
63
|
+
if (typeof BroadcastChannel !== "undefined") {
|
|
64
|
+
channel = new BroadcastChannel(`taladb:${dbName}`);
|
|
65
|
+
channel.onmessage = (e) => {
|
|
66
|
+
if (e.data === "taladb:changed") {
|
|
67
|
+
for (const nudge of nudgeCallbacks) nudge();
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
100
71
|
function wrapCollection(name) {
|
|
101
72
|
const s = JSON.stringify;
|
|
102
73
|
return {
|
|
@@ -140,13 +111,26 @@ async function createBrowserDB(dbName) {
|
|
|
140
111
|
}),
|
|
141
112
|
createIndex: (field) => proxy.send("createIndex", { collection: name, field }),
|
|
142
113
|
dropIndex: (field) => proxy.send("dropIndex", { collection: name, field }),
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
114
|
+
createFtsIndex: (field) => proxy.send("createFtsIndex", { collection: name, field }),
|
|
115
|
+
dropFtsIndex: (field) => proxy.send("dropFtsIndex", { collection: name, field }),
|
|
116
|
+
createVectorIndex: (field, options) => {
|
|
117
|
+
if (options.indexType === "hnsw") return Promise.reject(new Error("HNSW vector indexes are not available in the browser (requires native threads). Use Node.js or React Native."));
|
|
118
|
+
return proxy.send("createVectorIndex", {
|
|
119
|
+
collection: name,
|
|
120
|
+
field,
|
|
121
|
+
dimensions: options.dimensions,
|
|
122
|
+
metric: options.metric,
|
|
123
|
+
indexType: null,
|
|
124
|
+
hnswM: null,
|
|
125
|
+
hnswEfConstruction: null
|
|
126
|
+
});
|
|
127
|
+
},
|
|
149
128
|
dropVectorIndex: (field) => proxy.send("dropVectorIndex", { collection: name, field }),
|
|
129
|
+
upgradeVectorIndex: (_field) => Promise.reject(new Error("HNSW vector indexes are not available in the browser (requires native threads). Use Node.js or React Native.")),
|
|
130
|
+
listIndexes: async () => {
|
|
131
|
+
const json = await proxy.send("listIndexes", { collection: name });
|
|
132
|
+
return JSON.parse(json);
|
|
133
|
+
},
|
|
150
134
|
findNearest: async (field, vector, topK, filter) => {
|
|
151
135
|
const json = await proxy.send("findNearest", {
|
|
152
136
|
collection: name,
|
|
@@ -159,9 +143,14 @@ async function createBrowserDB(dbName) {
|
|
|
159
143
|
},
|
|
160
144
|
subscribe: (filter, callback) => {
|
|
161
145
|
let active = true;
|
|
162
|
-
let lastJson = "";
|
|
146
|
+
let lastJson = "[]";
|
|
147
|
+
let timer = null;
|
|
163
148
|
const poll = async () => {
|
|
164
149
|
if (!active) return;
|
|
150
|
+
if (timer !== null) {
|
|
151
|
+
clearTimeout(timer);
|
|
152
|
+
timer = null;
|
|
153
|
+
}
|
|
165
154
|
try {
|
|
166
155
|
const json = await proxy.send("find", {
|
|
167
156
|
collection: name,
|
|
@@ -173,18 +162,28 @@ async function createBrowserDB(dbName) {
|
|
|
173
162
|
}
|
|
174
163
|
} catch {
|
|
175
164
|
}
|
|
176
|
-
if (active) setTimeout(poll, 300);
|
|
165
|
+
if (active) timer = setTimeout(poll, 300);
|
|
177
166
|
};
|
|
167
|
+
nudgeCallbacks.add(poll);
|
|
178
168
|
poll();
|
|
179
169
|
return () => {
|
|
180
170
|
active = false;
|
|
171
|
+
nudgeCallbacks.delete(poll);
|
|
172
|
+
if (timer !== null) {
|
|
173
|
+
clearTimeout(timer);
|
|
174
|
+
timer = null;
|
|
175
|
+
}
|
|
181
176
|
};
|
|
182
177
|
}
|
|
183
178
|
};
|
|
184
179
|
}
|
|
185
180
|
return {
|
|
186
181
|
collection: (name) => wrapCollection(name),
|
|
187
|
-
close: () =>
|
|
182
|
+
close: async () => {
|
|
183
|
+
channel?.close();
|
|
184
|
+
await proxy.send("close");
|
|
185
|
+
worker.terminate();
|
|
186
|
+
}
|
|
188
187
|
};
|
|
189
188
|
}
|
|
190
189
|
async function createNodeDB(dbName) {
|
|
@@ -204,33 +203,20 @@ async function createNodeDB(dbName) {
|
|
|
204
203
|
count: async (filter) => col.count(filter ?? null),
|
|
205
204
|
createIndex: async (field) => col.createIndex(field),
|
|
206
205
|
dropIndex: async (field) => col.dropIndex(field),
|
|
207
|
-
|
|
206
|
+
createFtsIndex: async (field) => col.createFtsIndex(field),
|
|
207
|
+
dropFtsIndex: async (field) => col.dropFtsIndex(field),
|
|
208
|
+
createVectorIndex: async (field, options) => col.createVectorIndex(field, options.dimensions, options.metric ?? null, options.indexType ?? null, options.hnswM ?? null, options.hnswEfConstruction ?? null),
|
|
208
209
|
dropVectorIndex: async (field) => col.dropVectorIndex(field),
|
|
210
|
+
upgradeVectorIndex: async (field) => col.upgradeVectorIndex(field),
|
|
211
|
+
listIndexes: async () => {
|
|
212
|
+
const json = col.listIndexes();
|
|
213
|
+
return JSON.parse(json);
|
|
214
|
+
},
|
|
209
215
|
findNearest: async (field, vector, topK, filter) => {
|
|
210
216
|
const raw = await col.findNearest(field, vector, topK, filter ?? null);
|
|
211
217
|
return raw;
|
|
212
218
|
},
|
|
213
|
-
subscribe: (filter, callback) =>
|
|
214
|
-
let active = true;
|
|
215
|
-
let lastJson = "";
|
|
216
|
-
const poll = async () => {
|
|
217
|
-
if (!active) return;
|
|
218
|
-
try {
|
|
219
|
-
const docs = await col.find(filter ?? null);
|
|
220
|
-
const json = JSON.stringify(docs);
|
|
221
|
-
if (json !== lastJson) {
|
|
222
|
-
lastJson = json;
|
|
223
|
-
callback(docs);
|
|
224
|
-
}
|
|
225
|
-
} catch {
|
|
226
|
-
}
|
|
227
|
-
if (active) setTimeout(poll, 300);
|
|
228
|
-
};
|
|
229
|
-
poll();
|
|
230
|
-
return () => {
|
|
231
|
-
active = false;
|
|
232
|
-
};
|
|
233
|
-
}
|
|
219
|
+
subscribe: (filter, callback) => makePoller(async () => col.find(filter ?? null), callback)
|
|
234
220
|
};
|
|
235
221
|
}
|
|
236
222
|
return {
|
|
@@ -261,33 +247,17 @@ async function createNativeDB(_dbName) {
|
|
|
261
247
|
count: async (filter) => col.count(filter ?? {}),
|
|
262
248
|
createIndex: async (field) => col.createIndex(field),
|
|
263
249
|
dropIndex: async (field) => col.dropIndex(field),
|
|
264
|
-
|
|
250
|
+
createFtsIndex: async (field) => col.createFtsIndex(field),
|
|
251
|
+
dropFtsIndex: async (field) => col.dropFtsIndex(field),
|
|
252
|
+
createVectorIndex: async (field, options) => col.createVectorIndex(field, options.dimensions, options.metric ?? null, options.indexType ?? null, options.hnswM ?? null, options.hnswEfConstruction ?? null),
|
|
265
253
|
dropVectorIndex: async (field) => col.dropVectorIndex(field),
|
|
254
|
+
upgradeVectorIndex: async (field) => col.upgradeVectorIndex(field),
|
|
255
|
+
listIndexes: async () => JSON.parse(col.listIndexes()),
|
|
266
256
|
findNearest: async (field, vector, topK, filter) => {
|
|
267
257
|
const raw = col.findNearest(field, vector, topK, filter ?? null);
|
|
268
258
|
return raw;
|
|
269
259
|
},
|
|
270
|
-
subscribe: (filter, callback) => {
|
|
271
|
-
let active = true;
|
|
272
|
-
let lastJson = "";
|
|
273
|
-
const poll = () => {
|
|
274
|
-
if (!active) return;
|
|
275
|
-
try {
|
|
276
|
-
const docs = col.find(filter ?? {});
|
|
277
|
-
const json = JSON.stringify(docs);
|
|
278
|
-
if (json !== lastJson) {
|
|
279
|
-
lastJson = json;
|
|
280
|
-
callback(docs);
|
|
281
|
-
}
|
|
282
|
-
} catch {
|
|
283
|
-
}
|
|
284
|
-
if (active) setTimeout(poll, 300);
|
|
285
|
-
};
|
|
286
|
-
poll();
|
|
287
|
-
return () => {
|
|
288
|
-
active = false;
|
|
289
|
-
};
|
|
290
|
-
}
|
|
260
|
+
subscribe: (filter, callback) => makePoller(async () => col.find(filter ?? {}), callback)
|
|
291
261
|
};
|
|
292
262
|
}
|
|
293
263
|
return {
|