@taladb/web 0.3.0 → 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/package.json +1 -1
- package/pkg/package.json +1 -1
- package/pkg/taladb_web.d.ts +64 -14
- package/pkg/taladb_web.js +165 -40
- package/pkg/taladb_web_bg.wasm +0 -0
- package/pkg/taladb_web_bg.wasm.d.ts +11 -4
- package/worker/taladb.worker.js +261 -21
package/package.json
CHANGED
package/pkg/package.json
CHANGED
package/pkg/taladb_web.d.ts
CHANGED
|
@@ -16,10 +16,13 @@ export class CollectionWasm {
|
|
|
16
16
|
/**
|
|
17
17
|
* Create a vector index on `field`.
|
|
18
18
|
*
|
|
19
|
-
* `dimensions`
|
|
20
|
-
* `metric`
|
|
19
|
+
* `dimensions` — expected vector length.
|
|
20
|
+
* `metric` — optional: `"cosine"` (default), `"dot"`, or `"euclidean"`.
|
|
21
|
+
* `index_type` — optional: `"flat"` (default) or `"hnsw"`.
|
|
22
|
+
* `hnsw_m` — HNSW connectivity (default 16).
|
|
23
|
+
* `hnsw_ef_construction` — build quality (default 200).
|
|
21
24
|
*/
|
|
22
|
-
createVectorIndex(field: string, dimensions: number, metric?: string | null): void;
|
|
25
|
+
createVectorIndex(field: string, dimensions: number, metric?: string | null, index_type?: string | null, hnsw_m?: number | null, hnsw_ef_construction?: number | null): void;
|
|
23
26
|
/**
|
|
24
27
|
* Delete all matching documents. Returns the count deleted.
|
|
25
28
|
*/
|
|
@@ -33,7 +36,7 @@ export class CollectionWasm {
|
|
|
33
36
|
*/
|
|
34
37
|
dropIndex(field: string): void;
|
|
35
38
|
/**
|
|
36
|
-
* Drop a vector index.
|
|
39
|
+
* Drop a vector index (and its HNSW graph if present).
|
|
37
40
|
*/
|
|
38
41
|
dropVectorIndex(field: string): void;
|
|
39
42
|
/**
|
|
@@ -69,6 +72,10 @@ export class CollectionWasm {
|
|
|
69
72
|
* Update the first matching document. Returns true if a document was updated.
|
|
70
73
|
*/
|
|
71
74
|
updateOne(filter: any, update: any): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Rebuild the HNSW graph from the current flat vector table.
|
|
77
|
+
*/
|
|
78
|
+
upgradeVectorIndex(field: string): void;
|
|
72
79
|
}
|
|
73
80
|
|
|
74
81
|
export class TalaDBWasm {
|
|
@@ -119,9 +126,14 @@ export class WorkerDB {
|
|
|
119
126
|
createFtsIndex(collection: string, field: string): void;
|
|
120
127
|
createIndex(collection: string, field: string): void;
|
|
121
128
|
/**
|
|
122
|
-
* Create a vector index.
|
|
129
|
+
* Create a vector index.
|
|
130
|
+
*
|
|
131
|
+
* - `metric_str`: `"cosine"` (default) | `"dot"` | `"euclidean"`
|
|
132
|
+
* - `index_type`: `"flat"` (default) | `"hnsw"`
|
|
133
|
+
* - `hnsw_m`: HNSW connectivity (default 16, only used when `index_type = "hnsw"`)
|
|
134
|
+
* - `hnsw_ef_construction`: build-time quality (default 200, only used when `index_type = "hnsw"`)
|
|
123
135
|
*/
|
|
124
|
-
createVectorIndex(collection: string, field: string, dimensions: number, metric_str?: string | null): void;
|
|
136
|
+
createVectorIndex(collection: string, field: string, dimensions: number, metric_str?: string | null, index_type?: string | null, hnsw_m?: number | null, hnsw_ef_construction?: number | null): void;
|
|
125
137
|
/**
|
|
126
138
|
* Delete all matching documents. Returns the count deleted.
|
|
127
139
|
*/
|
|
@@ -133,9 +145,16 @@ export class WorkerDB {
|
|
|
133
145
|
dropFtsIndex(collection: string, field: string): void;
|
|
134
146
|
dropIndex(collection: string, field: string): void;
|
|
135
147
|
/**
|
|
136
|
-
* Drop a vector index.
|
|
148
|
+
* Drop a vector index (and its HNSW graph if present).
|
|
137
149
|
*/
|
|
138
150
|
dropVectorIndex(collection: string, field: string): void;
|
|
151
|
+
/**
|
|
152
|
+
* Serialize the entire in-memory database to bytes for persistence.
|
|
153
|
+
*
|
|
154
|
+
* Pass the returned bytes to `idbSaveSnapshot` to persist across page reloads.
|
|
155
|
+
* On next open, pass the same bytes to `openWithSnapshot` to restore all data.
|
|
156
|
+
*/
|
|
157
|
+
exportSnapshot(): Uint8Array;
|
|
139
158
|
/**
|
|
140
159
|
* Find documents. Returns a JSON array of document objects.
|
|
141
160
|
*/
|
|
@@ -156,6 +175,11 @@ export class WorkerDB {
|
|
|
156
175
|
* Insert many documents. Returns a JSON array of ULID strings.
|
|
157
176
|
*/
|
|
158
177
|
insertMany(collection: string, docs_json: string): string;
|
|
178
|
+
/**
|
|
179
|
+
* Returns a JSON string `{ btree: string[], fts: string[], vector: string[] }`
|
|
180
|
+
* listing all indexes on the given collection.
|
|
181
|
+
*/
|
|
182
|
+
listIndexes(collection: string): string;
|
|
159
183
|
/**
|
|
160
184
|
* Open an in-memory database (for tests and OPFS-unavailable fallback).
|
|
161
185
|
*/
|
|
@@ -170,6 +194,18 @@ export class WorkerDB {
|
|
|
170
194
|
* ```
|
|
171
195
|
*/
|
|
172
196
|
static openWithOpfs(sync_handle: FileSystemSyncAccessHandle): WorkerDB;
|
|
197
|
+
/**
|
|
198
|
+
* Open a database, restoring from a previously exported snapshot if provided.
|
|
199
|
+
*
|
|
200
|
+
* Pass the bytes returned by `WorkerDB.exportSnapshot()` (or `null`/`undefined`
|
|
201
|
+
* for a fresh empty database). Used by the IndexedDB fallback path.
|
|
202
|
+
*
|
|
203
|
+
* ```js
|
|
204
|
+
* const bytes = await idbLoadSnapshot(dbName); // null on first open
|
|
205
|
+
* const workerDb = WorkerDB.openWithSnapshot(bytes);
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
static openWithSnapshot(data?: Uint8Array | null): WorkerDB;
|
|
173
209
|
/**
|
|
174
210
|
* Update all matching documents. Returns the count updated.
|
|
175
211
|
*/
|
|
@@ -178,17 +214,24 @@ export class WorkerDB {
|
|
|
178
214
|
* Update the first matching document. Returns `true` / `false`.
|
|
179
215
|
*/
|
|
180
216
|
updateOne(collection: string, filter_json: string, update_json: string): boolean;
|
|
217
|
+
/**
|
|
218
|
+
* Rebuild the HNSW graph for a vector index from the current flat vector
|
|
219
|
+
* table. Use after bulk inserts or when ANN recall has degraded.
|
|
220
|
+
*
|
|
221
|
+
* No-op when the `vector-hnsw` feature is disabled or the index is flat-only.
|
|
222
|
+
*/
|
|
223
|
+
upgradeVectorIndex(collection: string, field: string): void;
|
|
181
224
|
}
|
|
182
225
|
|
|
183
226
|
/**
|
|
184
227
|
* Load a previous database snapshot from IndexedDB.
|
|
185
|
-
* Returns None if no snapshot exists yet.
|
|
228
|
+
* Returns `None` if no snapshot exists yet (first open) or IDB is unavailable.
|
|
186
229
|
*/
|
|
187
230
|
export function idb_load_snapshot(db_name: string): Promise<Uint8Array | undefined>;
|
|
188
231
|
|
|
189
232
|
/**
|
|
190
|
-
* Persist a database snapshot to IndexedDB
|
|
191
|
-
*
|
|
233
|
+
* Persist a database snapshot to IndexedDB.
|
|
234
|
+
* Returns `true` on success, `false` on any failure.
|
|
192
235
|
*/
|
|
193
236
|
export function idb_save_snapshot(db_name: string, data: Uint8Array): Promise<boolean>;
|
|
194
237
|
|
|
@@ -237,26 +280,30 @@ export interface InitOutput {
|
|
|
237
280
|
readonly workerdb_count: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
|
|
238
281
|
readonly workerdb_createFtsIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
239
282
|
readonly workerdb_createIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
240
|
-
readonly workerdb_createVectorIndex: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => [number, number];
|
|
283
|
+
readonly workerdb_createVectorIndex: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number) => [number, number];
|
|
241
284
|
readonly workerdb_deleteMany: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
|
|
242
285
|
readonly workerdb_deleteOne: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
|
|
243
286
|
readonly workerdb_dropFtsIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
244
287
|
readonly workerdb_dropIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
245
288
|
readonly workerdb_dropVectorIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
289
|
+
readonly workerdb_exportSnapshot: (a: number) => [number, number, number, number];
|
|
246
290
|
readonly workerdb_find: (a: number, b: number, c: number, d: number, e: number) => [number, number, number, number];
|
|
247
291
|
readonly workerdb_findNearest: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number) => [number, number, number, number];
|
|
248
292
|
readonly workerdb_findOne: (a: number, b: number, c: number, d: number, e: number) => [number, number, number, number];
|
|
249
293
|
readonly workerdb_insert: (a: number, b: number, c: number, d: number, e: number) => [number, number, number, number];
|
|
250
294
|
readonly workerdb_insertMany: (a: number, b: number, c: number, d: number, e: number) => [number, number, number, number];
|
|
295
|
+
readonly workerdb_listIndexes: (a: number, b: number, c: number) => [number, number, number, number];
|
|
251
296
|
readonly workerdb_openInMemory: () => [number, number, number];
|
|
252
297
|
readonly workerdb_openWithOpfs: (a: any) => [number, number, number];
|
|
298
|
+
readonly workerdb_openWithSnapshot: (a: number, b: number) => [number, number, number];
|
|
253
299
|
readonly workerdb_updateMany: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number];
|
|
254
300
|
readonly workerdb_updateOne: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number];
|
|
301
|
+
readonly workerdb_upgradeVectorIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
255
302
|
readonly __wbg_collectionwasm_free: (a: number, b: number) => void;
|
|
256
303
|
readonly __wbg_taladbwasm_free: (a: number, b: number) => void;
|
|
257
304
|
readonly collectionwasm_count: (a: number, b: any) => [number, number, number];
|
|
258
305
|
readonly collectionwasm_createIndex: (a: number, b: number, c: number) => [number, number];
|
|
259
|
-
readonly collectionwasm_createVectorIndex: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number];
|
|
306
|
+
readonly collectionwasm_createVectorIndex: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number) => [number, number];
|
|
260
307
|
readonly collectionwasm_deleteMany: (a: number, b: any) => [number, number, number];
|
|
261
308
|
readonly collectionwasm_deleteOne: (a: number, b: any) => [number, number, number];
|
|
262
309
|
readonly collectionwasm_dropIndex: (a: number, b: number, c: number) => [number, number];
|
|
@@ -268,21 +315,24 @@ export interface InitOutput {
|
|
|
268
315
|
readonly collectionwasm_insertMany: (a: number, b: any) => [number, number, number];
|
|
269
316
|
readonly collectionwasm_updateMany: (a: number, b: any, c: any) => [number, number, number];
|
|
270
317
|
readonly collectionwasm_updateOne: (a: number, b: any, c: any) => [number, number, number];
|
|
318
|
+
readonly collectionwasm_upgradeVectorIndex: (a: number, b: number, c: number) => [number, number];
|
|
271
319
|
readonly taladbwasm_collection: (a: number, b: number, c: number) => number;
|
|
272
320
|
readonly taladbwasm_exportSnapshot: (a: number) => [number, number, number, number];
|
|
273
321
|
readonly taladbwasm_openInMemory: () => [number, number, number];
|
|
274
322
|
readonly taladbwasm_openWithSnapshot: (a: number, b: number) => [number, number, number];
|
|
275
323
|
readonly init: () => void;
|
|
276
|
-
readonly idb_load_snapshot: (a: number, b: number) => any;
|
|
277
|
-
readonly idb_save_snapshot: (a: number, b: number, c: number, d: number) => any;
|
|
278
324
|
readonly is_opfs_available: () => any;
|
|
279
325
|
readonly opfs_delete_snapshot: (a: number, b: number) => any;
|
|
280
326
|
readonly opfs_flush_snapshot: (a: number, b: number, c: number, d: number) => any;
|
|
281
327
|
readonly opfs_load_snapshot: (a: number, b: number) => any;
|
|
282
328
|
readonly opfs_open_backend: (a: number, b: number) => any;
|
|
329
|
+
readonly idb_load_snapshot: (a: number, b: number) => any;
|
|
330
|
+
readonly idb_save_snapshot: (a: number, b: number, c: number, d: number) => any;
|
|
283
331
|
readonly wasm_bindgen__closure__destroy__h1411c0b1433bd547: (a: number, b: number) => void;
|
|
332
|
+
readonly wasm_bindgen__closure__destroy__h7d7554216ff39279: (a: number, b: number) => void;
|
|
284
333
|
readonly wasm_bindgen__convert__closures_____invoke__h4bd31e7387ab665d: (a: number, b: number, c: any) => [number, number];
|
|
285
334
|
readonly wasm_bindgen__convert__closures_____invoke__h675f15260128efbc: (a: number, b: number, c: any, d: any) => void;
|
|
335
|
+
readonly wasm_bindgen__convert__closures_____invoke__h98155e79a0a742d1: (a: number, b: number, c: any) => void;
|
|
286
336
|
readonly __wbindgen_malloc: (a: number, b: number) => number;
|
|
287
337
|
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
|
288
338
|
readonly __wbindgen_exn_store: (a: number) => void;
|
package/pkg/taladb_web.js
CHANGED
|
@@ -45,18 +45,26 @@ export class CollectionWasm {
|
|
|
45
45
|
/**
|
|
46
46
|
* Create a vector index on `field`.
|
|
47
47
|
*
|
|
48
|
-
* `dimensions`
|
|
49
|
-
* `metric`
|
|
48
|
+
* `dimensions` — expected vector length.
|
|
49
|
+
* `metric` — optional: `"cosine"` (default), `"dot"`, or `"euclidean"`.
|
|
50
|
+
* `index_type` — optional: `"flat"` (default) or `"hnsw"`.
|
|
51
|
+
* `hnsw_m` — HNSW connectivity (default 16).
|
|
52
|
+
* `hnsw_ef_construction` — build quality (default 200).
|
|
50
53
|
* @param {string} field
|
|
51
54
|
* @param {number} dimensions
|
|
52
55
|
* @param {string | null} [metric]
|
|
56
|
+
* @param {string | null} [index_type]
|
|
57
|
+
* @param {number | null} [hnsw_m]
|
|
58
|
+
* @param {number | null} [hnsw_ef_construction]
|
|
53
59
|
*/
|
|
54
|
-
createVectorIndex(field, dimensions, metric) {
|
|
60
|
+
createVectorIndex(field, dimensions, metric, index_type, hnsw_m, hnsw_ef_construction) {
|
|
55
61
|
const ptr0 = passStringToWasm0(field, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
56
62
|
const len0 = WASM_VECTOR_LEN;
|
|
57
63
|
var ptr1 = isLikeNone(metric) ? 0 : passStringToWasm0(metric, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
58
64
|
var len1 = WASM_VECTOR_LEN;
|
|
59
|
-
|
|
65
|
+
var ptr2 = isLikeNone(index_type) ? 0 : passStringToWasm0(index_type, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
66
|
+
var len2 = WASM_VECTOR_LEN;
|
|
67
|
+
const ret = wasm.collectionwasm_createVectorIndex(this.__wbg_ptr, ptr0, len0, dimensions, ptr1, len1, ptr2, len2, isLikeNone(hnsw_m) ? 0x100000001 : (hnsw_m) >>> 0, isLikeNone(hnsw_ef_construction) ? 0x100000001 : (hnsw_ef_construction) >>> 0);
|
|
60
68
|
if (ret[1]) {
|
|
61
69
|
throw takeFromExternrefTable0(ret[0]);
|
|
62
70
|
}
|
|
@@ -98,7 +106,7 @@ export class CollectionWasm {
|
|
|
98
106
|
}
|
|
99
107
|
}
|
|
100
108
|
/**
|
|
101
|
-
* Drop a vector index.
|
|
109
|
+
* Drop a vector index (and its HNSW graph if present).
|
|
102
110
|
* @param {string} field
|
|
103
111
|
*/
|
|
104
112
|
dropVectorIndex(field) {
|
|
@@ -218,6 +226,18 @@ export class CollectionWasm {
|
|
|
218
226
|
}
|
|
219
227
|
return ret[0] !== 0;
|
|
220
228
|
}
|
|
229
|
+
/**
|
|
230
|
+
* Rebuild the HNSW graph from the current flat vector table.
|
|
231
|
+
* @param {string} field
|
|
232
|
+
*/
|
|
233
|
+
upgradeVectorIndex(field) {
|
|
234
|
+
const ptr0 = passStringToWasm0(field, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
235
|
+
const len0 = WASM_VECTOR_LEN;
|
|
236
|
+
const ret = wasm.collectionwasm_upgradeVectorIndex(this.__wbg_ptr, ptr0, len0);
|
|
237
|
+
if (ret[1]) {
|
|
238
|
+
throw takeFromExternrefTable0(ret[0]);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
221
241
|
}
|
|
222
242
|
if (Symbol.dispose) CollectionWasm.prototype[Symbol.dispose] = CollectionWasm.prototype.free;
|
|
223
243
|
|
|
@@ -370,20 +390,30 @@ export class WorkerDB {
|
|
|
370
390
|
}
|
|
371
391
|
}
|
|
372
392
|
/**
|
|
373
|
-
* Create a vector index.
|
|
393
|
+
* Create a vector index.
|
|
394
|
+
*
|
|
395
|
+
* - `metric_str`: `"cosine"` (default) | `"dot"` | `"euclidean"`
|
|
396
|
+
* - `index_type`: `"flat"` (default) | `"hnsw"`
|
|
397
|
+
* - `hnsw_m`: HNSW connectivity (default 16, only used when `index_type = "hnsw"`)
|
|
398
|
+
* - `hnsw_ef_construction`: build-time quality (default 200, only used when `index_type = "hnsw"`)
|
|
374
399
|
* @param {string} collection
|
|
375
400
|
* @param {string} field
|
|
376
401
|
* @param {number} dimensions
|
|
377
402
|
* @param {string | null} [metric_str]
|
|
403
|
+
* @param {string | null} [index_type]
|
|
404
|
+
* @param {number | null} [hnsw_m]
|
|
405
|
+
* @param {number | null} [hnsw_ef_construction]
|
|
378
406
|
*/
|
|
379
|
-
createVectorIndex(collection, field, dimensions, metric_str) {
|
|
407
|
+
createVectorIndex(collection, field, dimensions, metric_str, index_type, hnsw_m, hnsw_ef_construction) {
|
|
380
408
|
const ptr0 = passStringToWasm0(collection, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
381
409
|
const len0 = WASM_VECTOR_LEN;
|
|
382
410
|
const ptr1 = passStringToWasm0(field, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
383
411
|
const len1 = WASM_VECTOR_LEN;
|
|
384
412
|
var ptr2 = isLikeNone(metric_str) ? 0 : passStringToWasm0(metric_str, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
385
413
|
var len2 = WASM_VECTOR_LEN;
|
|
386
|
-
|
|
414
|
+
var ptr3 = isLikeNone(index_type) ? 0 : passStringToWasm0(index_type, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
415
|
+
var len3 = WASM_VECTOR_LEN;
|
|
416
|
+
const ret = wasm.workerdb_createVectorIndex(this.__wbg_ptr, ptr0, len0, ptr1, len1, dimensions, ptr2, len2, ptr3, len3, isLikeNone(hnsw_m) ? 0x100000001 : (hnsw_m) >>> 0, isLikeNone(hnsw_ef_construction) ? 0x100000001 : (hnsw_ef_construction) >>> 0);
|
|
387
417
|
if (ret[1]) {
|
|
388
418
|
throw takeFromExternrefTable0(ret[0]);
|
|
389
419
|
}
|
|
@@ -451,7 +481,7 @@ export class WorkerDB {
|
|
|
451
481
|
}
|
|
452
482
|
}
|
|
453
483
|
/**
|
|
454
|
-
* Drop a vector index.
|
|
484
|
+
* Drop a vector index (and its HNSW graph if present).
|
|
455
485
|
* @param {string} collection
|
|
456
486
|
* @param {string} field
|
|
457
487
|
*/
|
|
@@ -465,6 +495,22 @@ export class WorkerDB {
|
|
|
465
495
|
throw takeFromExternrefTable0(ret[0]);
|
|
466
496
|
}
|
|
467
497
|
}
|
|
498
|
+
/**
|
|
499
|
+
* Serialize the entire in-memory database to bytes for persistence.
|
|
500
|
+
*
|
|
501
|
+
* Pass the returned bytes to `idbSaveSnapshot` to persist across page reloads.
|
|
502
|
+
* On next open, pass the same bytes to `openWithSnapshot` to restore all data.
|
|
503
|
+
* @returns {Uint8Array}
|
|
504
|
+
*/
|
|
505
|
+
exportSnapshot() {
|
|
506
|
+
const ret = wasm.workerdb_exportSnapshot(this.__wbg_ptr);
|
|
507
|
+
if (ret[3]) {
|
|
508
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
509
|
+
}
|
|
510
|
+
var v1 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
|
|
511
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
|
|
512
|
+
return v1;
|
|
513
|
+
}
|
|
468
514
|
/**
|
|
469
515
|
* Find documents. Returns a JSON array of document objects.
|
|
470
516
|
* @param {string} collection
|
|
@@ -612,6 +658,32 @@ export class WorkerDB {
|
|
|
612
658
|
wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
|
|
613
659
|
}
|
|
614
660
|
}
|
|
661
|
+
/**
|
|
662
|
+
* Returns a JSON string `{ btree: string[], fts: string[], vector: string[] }`
|
|
663
|
+
* listing all indexes on the given collection.
|
|
664
|
+
* @param {string} collection
|
|
665
|
+
* @returns {string}
|
|
666
|
+
*/
|
|
667
|
+
listIndexes(collection) {
|
|
668
|
+
let deferred3_0;
|
|
669
|
+
let deferred3_1;
|
|
670
|
+
try {
|
|
671
|
+
const ptr0 = passStringToWasm0(collection, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
672
|
+
const len0 = WASM_VECTOR_LEN;
|
|
673
|
+
const ret = wasm.workerdb_listIndexes(this.__wbg_ptr, ptr0, len0);
|
|
674
|
+
var ptr2 = ret[0];
|
|
675
|
+
var len2 = ret[1];
|
|
676
|
+
if (ret[3]) {
|
|
677
|
+
ptr2 = 0; len2 = 0;
|
|
678
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
679
|
+
}
|
|
680
|
+
deferred3_0 = ptr2;
|
|
681
|
+
deferred3_1 = len2;
|
|
682
|
+
return getStringFromWasm0(ptr2, len2);
|
|
683
|
+
} finally {
|
|
684
|
+
wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
615
687
|
/**
|
|
616
688
|
* Open an in-memory database (for tests and OPFS-unavailable fallback).
|
|
617
689
|
* @returns {WorkerDB}
|
|
@@ -641,6 +713,28 @@ export class WorkerDB {
|
|
|
641
713
|
}
|
|
642
714
|
return WorkerDB.__wrap(ret[0]);
|
|
643
715
|
}
|
|
716
|
+
/**
|
|
717
|
+
* Open a database, restoring from a previously exported snapshot if provided.
|
|
718
|
+
*
|
|
719
|
+
* Pass the bytes returned by `WorkerDB.exportSnapshot()` (or `null`/`undefined`
|
|
720
|
+
* for a fresh empty database). Used by the IndexedDB fallback path.
|
|
721
|
+
*
|
|
722
|
+
* ```js
|
|
723
|
+
* const bytes = await idbLoadSnapshot(dbName); // null on first open
|
|
724
|
+
* const workerDb = WorkerDB.openWithSnapshot(bytes);
|
|
725
|
+
* ```
|
|
726
|
+
* @param {Uint8Array | null} [data]
|
|
727
|
+
* @returns {WorkerDB}
|
|
728
|
+
*/
|
|
729
|
+
static openWithSnapshot(data) {
|
|
730
|
+
var ptr0 = isLikeNone(data) ? 0 : passArray8ToWasm0(data, wasm.__wbindgen_malloc);
|
|
731
|
+
var len0 = WASM_VECTOR_LEN;
|
|
732
|
+
const ret = wasm.workerdb_openWithSnapshot(ptr0, len0);
|
|
733
|
+
if (ret[2]) {
|
|
734
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
735
|
+
}
|
|
736
|
+
return WorkerDB.__wrap(ret[0]);
|
|
737
|
+
}
|
|
644
738
|
/**
|
|
645
739
|
* Update all matching documents. Returns the count updated.
|
|
646
740
|
* @param {string} collection
|
|
@@ -681,12 +775,30 @@ export class WorkerDB {
|
|
|
681
775
|
}
|
|
682
776
|
return ret[0] !== 0;
|
|
683
777
|
}
|
|
778
|
+
/**
|
|
779
|
+
* Rebuild the HNSW graph for a vector index from the current flat vector
|
|
780
|
+
* table. Use after bulk inserts or when ANN recall has degraded.
|
|
781
|
+
*
|
|
782
|
+
* No-op when the `vector-hnsw` feature is disabled or the index is flat-only.
|
|
783
|
+
* @param {string} collection
|
|
784
|
+
* @param {string} field
|
|
785
|
+
*/
|
|
786
|
+
upgradeVectorIndex(collection, field) {
|
|
787
|
+
const ptr0 = passStringToWasm0(collection, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
788
|
+
const len0 = WASM_VECTOR_LEN;
|
|
789
|
+
const ptr1 = passStringToWasm0(field, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
790
|
+
const len1 = WASM_VECTOR_LEN;
|
|
791
|
+
const ret = wasm.workerdb_upgradeVectorIndex(this.__wbg_ptr, ptr0, len0, ptr1, len1);
|
|
792
|
+
if (ret[1]) {
|
|
793
|
+
throw takeFromExternrefTable0(ret[0]);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
684
796
|
}
|
|
685
797
|
if (Symbol.dispose) WorkerDB.prototype[Symbol.dispose] = WorkerDB.prototype.free;
|
|
686
798
|
|
|
687
799
|
/**
|
|
688
800
|
* Load a previous database snapshot from IndexedDB.
|
|
689
|
-
* Returns None if no snapshot exists yet.
|
|
801
|
+
* Returns `None` if no snapshot exists yet (first open) or IDB is unavailable.
|
|
690
802
|
* @param {string} db_name
|
|
691
803
|
* @returns {Promise<Uint8Array | undefined>}
|
|
692
804
|
*/
|
|
@@ -698,8 +810,8 @@ export function idb_load_snapshot(db_name) {
|
|
|
698
810
|
}
|
|
699
811
|
|
|
700
812
|
/**
|
|
701
|
-
* Persist a database snapshot to IndexedDB
|
|
702
|
-
*
|
|
813
|
+
* Persist a database snapshot to IndexedDB.
|
|
814
|
+
* Returns `true` on success, `false` on any failure.
|
|
703
815
|
* @param {string} db_name
|
|
704
816
|
* @param {Uint8Array} data
|
|
705
817
|
* @returns {Promise<boolean>}
|
|
@@ -876,14 +988,14 @@ function __wbg_get_imports() {
|
|
|
876
988
|
__wbg__wbg_cb_unref_6b5b6b8576d35cb1: function(arg0) {
|
|
877
989
|
arg0._wbg_cb_unref();
|
|
878
990
|
},
|
|
991
|
+
__wbg_apply_ac9afb97ca32f169: function() { return handleError(function (arg0, arg1, arg2) {
|
|
992
|
+
const ret = arg0.apply(arg1, arg2);
|
|
993
|
+
return ret;
|
|
994
|
+
}, arguments); },
|
|
879
995
|
__wbg_arrayBuffer_7ff5e58aa85a64f7: function(arg0) {
|
|
880
996
|
const ret = arg0.arrayBuffer();
|
|
881
997
|
return ret;
|
|
882
998
|
},
|
|
883
|
-
__wbg_buffer_60b8043cd926067d: function(arg0) {
|
|
884
|
-
const ret = arg0.buffer;
|
|
885
|
-
return ret;
|
|
886
|
-
},
|
|
887
999
|
__wbg_call_2d781c1f4d5c0ef8: function() { return handleError(function (arg0, arg1, arg2) {
|
|
888
1000
|
const ret = arg0.call(arg1, arg2);
|
|
889
1001
|
return ret;
|
|
@@ -942,13 +1054,6 @@ function __wbg_get_imports() {
|
|
|
942
1054
|
const ret = arg0.getFile();
|
|
943
1055
|
return ret;
|
|
944
1056
|
},
|
|
945
|
-
__wbg_getItem_a7cc1d4f154f2e6f: function() { return handleError(function (arg0, arg1, arg2, arg3) {
|
|
946
|
-
const ret = arg1.getItem(getStringFromWasm0(arg2, arg3));
|
|
947
|
-
var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
948
|
-
var len1 = WASM_VECTOR_LEN;
|
|
949
|
-
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
|
950
|
-
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
|
951
|
-
}, arguments); },
|
|
952
1057
|
__wbg_getRandomValues_3f44b700395062e5: function() { return handleError(function (arg0, arg1) {
|
|
953
1058
|
globalThis.crypto.getRandomValues(getArrayU8FromWasm0(arg0, arg1));
|
|
954
1059
|
}, arguments); },
|
|
@@ -968,10 +1073,6 @@ function __wbg_get_imports() {
|
|
|
968
1073
|
const ret = arg0[arg1 >>> 0];
|
|
969
1074
|
return ret;
|
|
970
1075
|
},
|
|
971
|
-
__wbg_get_index_87179971b8d350e4: function(arg0, arg1) {
|
|
972
|
-
const ret = arg0[arg1 >>> 0];
|
|
973
|
-
return ret;
|
|
974
|
-
},
|
|
975
1076
|
__wbg_get_unchecked_329cfe50afab7352: function(arg0, arg1) {
|
|
976
1077
|
const ret = arg0[arg1 >>> 0];
|
|
977
1078
|
return ret;
|
|
@@ -1096,10 +1197,6 @@ function __wbg_get_imports() {
|
|
|
1096
1197
|
const ret = arg0.length;
|
|
1097
1198
|
return ret;
|
|
1098
1199
|
},
|
|
1099
|
-
__wbg_localStorage_51c38b3b222e1ed2: function() { return handleError(function (arg0) {
|
|
1100
|
-
const ret = arg0.localStorage;
|
|
1101
|
-
return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
|
|
1102
|
-
}, arguments); },
|
|
1103
1200
|
__wbg_navigator_9cebf56f28aa719b: function(arg0) {
|
|
1104
1201
|
const ret = arg0.navigator;
|
|
1105
1202
|
return ret;
|
|
@@ -1124,6 +1221,24 @@ function __wbg_get_imports() {
|
|
|
1124
1221
|
const ret = new Object();
|
|
1125
1222
|
return ret;
|
|
1126
1223
|
},
|
|
1224
|
+
__wbg_new_d098e265629cd10f: function(arg0, arg1) {
|
|
1225
|
+
try {
|
|
1226
|
+
var state0 = {a: arg0, b: arg1};
|
|
1227
|
+
var cb0 = (arg0, arg1) => {
|
|
1228
|
+
const a = state0.a;
|
|
1229
|
+
state0.a = 0;
|
|
1230
|
+
try {
|
|
1231
|
+
return wasm_bindgen__convert__closures_____invoke__h675f15260128efbc(a, state0.b, arg0, arg1);
|
|
1232
|
+
} finally {
|
|
1233
|
+
state0.a = a;
|
|
1234
|
+
}
|
|
1235
|
+
};
|
|
1236
|
+
const ret = new Promise(cb0);
|
|
1237
|
+
return ret;
|
|
1238
|
+
} finally {
|
|
1239
|
+
state0.a = state0.b = 0;
|
|
1240
|
+
}
|
|
1241
|
+
},
|
|
1127
1242
|
__wbg_new_from_slice_22da9388ac046e50: function(arg0, arg1) {
|
|
1128
1243
|
const ret = new Uint8Array(getArrayU8FromWasm0(arg0, arg1));
|
|
1129
1244
|
return ret;
|
|
@@ -1165,6 +1280,10 @@ function __wbg_get_imports() {
|
|
|
1165
1280
|
__wbg_prototypesetcall_d62e5099504357e6: function(arg0, arg1, arg2) {
|
|
1166
1281
|
Uint8Array.prototype.set.call(getArrayU8FromWasm0(arg0, arg1), arg2);
|
|
1167
1282
|
},
|
|
1283
|
+
__wbg_push_e87b0e732085a946: function(arg0, arg1) {
|
|
1284
|
+
const ret = arg0.push(arg1);
|
|
1285
|
+
return ret;
|
|
1286
|
+
},
|
|
1168
1287
|
__wbg_queueMicrotask_0c399741342fb10f: function(arg0) {
|
|
1169
1288
|
const ret = arg0.queueMicrotask;
|
|
1170
1289
|
return ret;
|
|
@@ -1180,9 +1299,6 @@ function __wbg_get_imports() {
|
|
|
1180
1299
|
const ret = Promise.resolve(arg0);
|
|
1181
1300
|
return ret;
|
|
1182
1301
|
},
|
|
1183
|
-
__wbg_setItem_5f84aeef0d7f3c17: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
|
|
1184
|
-
arg0.setItem(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
|
|
1185
|
-
}, arguments); },
|
|
1186
1302
|
__wbg_set_282384002438957f: function(arg0, arg1, arg2) {
|
|
1187
1303
|
arg0[arg1 >>> 0] = arg2;
|
|
1188
1304
|
},
|
|
@@ -1243,31 +1359,36 @@ function __wbg_get_imports() {
|
|
|
1243
1359
|
return ret;
|
|
1244
1360
|
},
|
|
1245
1361
|
__wbindgen_cast_0000000000000001: function(arg0, arg1) {
|
|
1246
|
-
// Cast intrinsic for `Closure(Closure { dtor_idx:
|
|
1362
|
+
// Cast intrinsic for `Closure(Closure { dtor_idx: 422, function: Function { arguments: [Externref], shim_idx: 423, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
|
|
1247
1363
|
const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen__closure__destroy__h1411c0b1433bd547, wasm_bindgen__convert__closures_____invoke__h4bd31e7387ab665d);
|
|
1248
1364
|
return ret;
|
|
1249
1365
|
},
|
|
1250
|
-
__wbindgen_cast_0000000000000002: function(arg0) {
|
|
1366
|
+
__wbindgen_cast_0000000000000002: function(arg0, arg1) {
|
|
1367
|
+
// Cast intrinsic for `Closure(Closure { dtor_idx: 63, function: Function { arguments: [Externref], shim_idx: 64, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
|
1368
|
+
const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen__closure__destroy__h7d7554216ff39279, wasm_bindgen__convert__closures_____invoke__h98155e79a0a742d1);
|
|
1369
|
+
return ret;
|
|
1370
|
+
},
|
|
1371
|
+
__wbindgen_cast_0000000000000003: function(arg0) {
|
|
1251
1372
|
// Cast intrinsic for `F64 -> Externref`.
|
|
1252
1373
|
const ret = arg0;
|
|
1253
1374
|
return ret;
|
|
1254
1375
|
},
|
|
1255
|
-
|
|
1376
|
+
__wbindgen_cast_0000000000000004: function(arg0) {
|
|
1256
1377
|
// Cast intrinsic for `I64 -> Externref`.
|
|
1257
1378
|
const ret = arg0;
|
|
1258
1379
|
return ret;
|
|
1259
1380
|
},
|
|
1260
|
-
|
|
1381
|
+
__wbindgen_cast_0000000000000005: function(arg0, arg1) {
|
|
1261
1382
|
// Cast intrinsic for `Ref(String) -> Externref`.
|
|
1262
1383
|
const ret = getStringFromWasm0(arg0, arg1);
|
|
1263
1384
|
return ret;
|
|
1264
1385
|
},
|
|
1265
|
-
|
|
1386
|
+
__wbindgen_cast_0000000000000006: function(arg0) {
|
|
1266
1387
|
// Cast intrinsic for `U64 -> Externref`.
|
|
1267
1388
|
const ret = BigInt.asUintN(64, arg0);
|
|
1268
1389
|
return ret;
|
|
1269
1390
|
},
|
|
1270
|
-
|
|
1391
|
+
__wbindgen_cast_0000000000000007: function(arg0, arg1) {
|
|
1271
1392
|
var v0 = getArrayU8FromWasm0(arg0, arg1).slice();
|
|
1272
1393
|
wasm.__wbindgen_free(arg0, arg1 * 1, 1);
|
|
1273
1394
|
// Cast intrinsic for `Vector(U8) -> Externref`.
|
|
@@ -1290,6 +1411,10 @@ function __wbg_get_imports() {
|
|
|
1290
1411
|
};
|
|
1291
1412
|
}
|
|
1292
1413
|
|
|
1414
|
+
function wasm_bindgen__convert__closures_____invoke__h98155e79a0a742d1(arg0, arg1, arg2) {
|
|
1415
|
+
wasm.wasm_bindgen__convert__closures_____invoke__h98155e79a0a742d1(arg0, arg1, arg2);
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1293
1418
|
function wasm_bindgen__convert__closures_____invoke__h4bd31e7387ab665d(arg0, arg1, arg2) {
|
|
1294
1419
|
const ret = wasm.wasm_bindgen__convert__closures_____invoke__h4bd31e7387ab665d(arg0, arg1, arg2);
|
|
1295
1420
|
if (ret[1]) {
|
package/pkg/taladb_web_bg.wasm
CHANGED
|
Binary file
|
|
@@ -5,26 +5,30 @@ export const __wbg_workerdb_free: (a: number, b: number) => void;
|
|
|
5
5
|
export const workerdb_count: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
|
|
6
6
|
export const workerdb_createFtsIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
7
7
|
export const workerdb_createIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
8
|
-
export const workerdb_createVectorIndex: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => [number, number];
|
|
8
|
+
export const workerdb_createVectorIndex: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number) => [number, number];
|
|
9
9
|
export const workerdb_deleteMany: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
|
|
10
10
|
export const workerdb_deleteOne: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
|
|
11
11
|
export const workerdb_dropFtsIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
12
12
|
export const workerdb_dropIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
13
13
|
export const workerdb_dropVectorIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
14
|
+
export const workerdb_exportSnapshot: (a: number) => [number, number, number, number];
|
|
14
15
|
export const workerdb_find: (a: number, b: number, c: number, d: number, e: number) => [number, number, number, number];
|
|
15
16
|
export const workerdb_findNearest: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number) => [number, number, number, number];
|
|
16
17
|
export const workerdb_findOne: (a: number, b: number, c: number, d: number, e: number) => [number, number, number, number];
|
|
17
18
|
export const workerdb_insert: (a: number, b: number, c: number, d: number, e: number) => [number, number, number, number];
|
|
18
19
|
export const workerdb_insertMany: (a: number, b: number, c: number, d: number, e: number) => [number, number, number, number];
|
|
20
|
+
export const workerdb_listIndexes: (a: number, b: number, c: number) => [number, number, number, number];
|
|
19
21
|
export const workerdb_openInMemory: () => [number, number, number];
|
|
20
22
|
export const workerdb_openWithOpfs: (a: any) => [number, number, number];
|
|
23
|
+
export const workerdb_openWithSnapshot: (a: number, b: number) => [number, number, number];
|
|
21
24
|
export const workerdb_updateMany: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number];
|
|
22
25
|
export const workerdb_updateOne: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number];
|
|
26
|
+
export const workerdb_upgradeVectorIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
23
27
|
export const __wbg_collectionwasm_free: (a: number, b: number) => void;
|
|
24
28
|
export const __wbg_taladbwasm_free: (a: number, b: number) => void;
|
|
25
29
|
export const collectionwasm_count: (a: number, b: any) => [number, number, number];
|
|
26
30
|
export const collectionwasm_createIndex: (a: number, b: number, c: number) => [number, number];
|
|
27
|
-
export const collectionwasm_createVectorIndex: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number];
|
|
31
|
+
export const collectionwasm_createVectorIndex: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number) => [number, number];
|
|
28
32
|
export const collectionwasm_deleteMany: (a: number, b: any) => [number, number, number];
|
|
29
33
|
export const collectionwasm_deleteOne: (a: number, b: any) => [number, number, number];
|
|
30
34
|
export const collectionwasm_dropIndex: (a: number, b: number, c: number) => [number, number];
|
|
@@ -36,21 +40,24 @@ export const collectionwasm_insert: (a: number, b: any) => [number, number, numb
|
|
|
36
40
|
export const collectionwasm_insertMany: (a: number, b: any) => [number, number, number];
|
|
37
41
|
export const collectionwasm_updateMany: (a: number, b: any, c: any) => [number, number, number];
|
|
38
42
|
export const collectionwasm_updateOne: (a: number, b: any, c: any) => [number, number, number];
|
|
43
|
+
export const collectionwasm_upgradeVectorIndex: (a: number, b: number, c: number) => [number, number];
|
|
39
44
|
export const taladbwasm_collection: (a: number, b: number, c: number) => number;
|
|
40
45
|
export const taladbwasm_exportSnapshot: (a: number) => [number, number, number, number];
|
|
41
46
|
export const taladbwasm_openInMemory: () => [number, number, number];
|
|
42
47
|
export const taladbwasm_openWithSnapshot: (a: number, b: number) => [number, number, number];
|
|
43
48
|
export const init: () => void;
|
|
44
|
-
export const idb_load_snapshot: (a: number, b: number) => any;
|
|
45
|
-
export const idb_save_snapshot: (a: number, b: number, c: number, d: number) => any;
|
|
46
49
|
export const is_opfs_available: () => any;
|
|
47
50
|
export const opfs_delete_snapshot: (a: number, b: number) => any;
|
|
48
51
|
export const opfs_flush_snapshot: (a: number, b: number, c: number, d: number) => any;
|
|
49
52
|
export const opfs_load_snapshot: (a: number, b: number) => any;
|
|
50
53
|
export const opfs_open_backend: (a: number, b: number) => any;
|
|
54
|
+
export const idb_load_snapshot: (a: number, b: number) => any;
|
|
55
|
+
export const idb_save_snapshot: (a: number, b: number, c: number, d: number) => any;
|
|
51
56
|
export const wasm_bindgen__closure__destroy__h1411c0b1433bd547: (a: number, b: number) => void;
|
|
57
|
+
export const wasm_bindgen__closure__destroy__h7d7554216ff39279: (a: number, b: number) => void;
|
|
52
58
|
export const wasm_bindgen__convert__closures_____invoke__h4bd31e7387ab665d: (a: number, b: number, c: any) => [number, number];
|
|
53
59
|
export const wasm_bindgen__convert__closures_____invoke__h675f15260128efbc: (a: number, b: number, c: any, d: any) => void;
|
|
60
|
+
export const wasm_bindgen__convert__closures_____invoke__h98155e79a0a742d1: (a: number, b: number, c: any) => void;
|
|
54
61
|
export const __wbindgen_malloc: (a: number, b: number) => number;
|
|
55
62
|
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
|
56
63
|
export const __wbindgen_exn_store: (a: number) => void;
|
package/worker/taladb.worker.js
CHANGED
|
@@ -43,10 +43,26 @@
|
|
|
43
43
|
* dropIndex { collection, field }
|
|
44
44
|
* createFtsIndex { collection, field }
|
|
45
45
|
* dropFtsIndex { collection, field }
|
|
46
|
-
*
|
|
46
|
+
* listIndexes { collection } → JSON { btree, fts, vector }
|
|
47
|
+
* createVectorIndex { collection, field, dimensions, metric?, indexType?, hnswM?, hnswEfConstruction? }
|
|
47
48
|
* dropVectorIndex { collection, field }
|
|
49
|
+
* upgradeVectorIndex { collection, field }
|
|
48
50
|
* findNearest { collection, field, queryJson, topK, filterJson? }
|
|
49
51
|
* close {}
|
|
52
|
+
*
|
|
53
|
+
* Multi-tab live queries (BroadcastChannel)
|
|
54
|
+
* -----------------------------------------
|
|
55
|
+
* When a write op (insert/insertMany/updateOne/updateMany/deleteOne/deleteMany) commits, the worker
|
|
56
|
+
* posts a `"taladb:changed"` message on a BroadcastChannel named
|
|
57
|
+
* `"taladb:<dbName>"`. Other tabs listening on the same channel re-trigger
|
|
58
|
+
* their active `subscribe()` pollers immediately, bypassing the 300 ms tick.
|
|
59
|
+
*
|
|
60
|
+
* IndexedDB fallback (no OPFS)
|
|
61
|
+
* ----------------------------
|
|
62
|
+
* When OPFS is unavailable (cross-origin iframes, Firefox without storage
|
|
63
|
+
* access) the worker opens an in-memory database seeded from the last snapshot
|
|
64
|
+
* stored in IndexedDB. After every write it flushes a new snapshot back to
|
|
65
|
+
* IndexedDB so data survives page reloads.
|
|
50
66
|
*/
|
|
51
67
|
|
|
52
68
|
// ---------------------------------------------------------------------------
|
|
@@ -56,6 +72,27 @@
|
|
|
56
72
|
/** @type {import('../pkg/taladb_web').WorkerDB | null} */
|
|
57
73
|
let db = null;
|
|
58
74
|
|
|
75
|
+
/**
|
|
76
|
+
* WorkerDB constructor — hoisted to module scope so snapshot reloads in
|
|
77
|
+
* IDB-fallback mode can call WorkerDB.openWithSnapshot without re-importing.
|
|
78
|
+
* @type {typeof import('../pkg/taladb_web').WorkerDB | null}
|
|
79
|
+
*/
|
|
80
|
+
let WorkerDB = null;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Set to true by the BroadcastChannel listener (fallback mode) when the
|
|
84
|
+
* primary tab commits a write. Cleared at the start of the next dispatch.
|
|
85
|
+
* @type {boolean}
|
|
86
|
+
*/
|
|
87
|
+
let snapshotDirty = false;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Resolve function set when a fallback tab is waiting for the primary tab to
|
|
91
|
+
* export a snapshot via BroadcastChannel. Cleared once resolved or timed out.
|
|
92
|
+
* @type {(() => void) | null}
|
|
93
|
+
*/
|
|
94
|
+
let pendingSnapshotResolve = null;
|
|
95
|
+
|
|
59
96
|
/**
|
|
60
97
|
* Deduplicates concurrent init calls for the same dbName within one worker.
|
|
61
98
|
* @type {Map<string, Promise<void>>}
|
|
@@ -76,6 +113,99 @@ const warn = isDev ? console.warn.bind(console, '[TalaDB Worker]') : () => {};
|
|
|
76
113
|
*/
|
|
77
114
|
let releaseLock = null;
|
|
78
115
|
|
|
116
|
+
/**
|
|
117
|
+
* BroadcastChannel used to notify sibling tabs of writes.
|
|
118
|
+
* Created in doInit; null until the channel name is known.
|
|
119
|
+
* @type {BroadcastChannel | null}
|
|
120
|
+
*/
|
|
121
|
+
let broadcastChannel = null;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* True when running in IDB-fallback mode (OPFS unavailable).
|
|
125
|
+
* In this mode every write flushes a snapshot back to IndexedDB.
|
|
126
|
+
* @type {boolean}
|
|
127
|
+
*/
|
|
128
|
+
let idbFallback = false;
|
|
129
|
+
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
// IndexedDB helpers (used only when OPFS is unavailable)
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
|
|
134
|
+
const IDB_DB_NAME = 'taladb';
|
|
135
|
+
const IDB_STORE = 'snapshots';
|
|
136
|
+
const IDB_VERSION = 1;
|
|
137
|
+
|
|
138
|
+
/** Open (or upgrade) the "taladb" IDB database and return the IDBDatabase. */
|
|
139
|
+
function idbOpen() {
|
|
140
|
+
return new Promise((resolve, reject) => {
|
|
141
|
+
const req = self.indexedDB.open(IDB_DB_NAME, IDB_VERSION);
|
|
142
|
+
req.onupgradeneeded = () => {
|
|
143
|
+
// Create the object store the very first time.
|
|
144
|
+
if (!req.result.objectStoreNames.contains(IDB_STORE)) {
|
|
145
|
+
req.result.createObjectStore(IDB_STORE);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
req.onsuccess = () => resolve(req.result);
|
|
149
|
+
req.onerror = () => reject(req.error);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Load a snapshot Uint8Array from IndexedDB for `dbName`.
|
|
155
|
+
* Returns null if no snapshot is stored yet.
|
|
156
|
+
* @param {string} dbName
|
|
157
|
+
* @returns {Promise<Uint8Array | null>}
|
|
158
|
+
*/
|
|
159
|
+
async function idbLoadSnapshot(dbName) {
|
|
160
|
+
if (!self.indexedDB) return null;
|
|
161
|
+
try {
|
|
162
|
+
const idb = await idbOpen();
|
|
163
|
+
return new Promise((resolve) => {
|
|
164
|
+
const tx = idb.transaction(IDB_STORE, 'readonly');
|
|
165
|
+
const store = tx.objectStore(IDB_STORE);
|
|
166
|
+
const req = store.get(dbName);
|
|
167
|
+
req.onsuccess = () => resolve(req.result ?? null);
|
|
168
|
+
req.onerror = () => resolve(null);
|
|
169
|
+
});
|
|
170
|
+
} catch {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Persist a snapshot Uint8Array to IndexedDB for `dbName` (fire-and-forget).
|
|
177
|
+
* @param {string} dbName
|
|
178
|
+
* @param {Uint8Array} bytes
|
|
179
|
+
*/
|
|
180
|
+
async function idbSaveSnapshot(dbName, bytes) {
|
|
181
|
+
if (!self.indexedDB) return;
|
|
182
|
+
try {
|
|
183
|
+
const idb = await idbOpen();
|
|
184
|
+
await new Promise((resolve, reject) => {
|
|
185
|
+
const tx = idb.transaction(IDB_STORE, 'readwrite');
|
|
186
|
+
tx.objectStore(IDB_STORE).put(bytes, dbName);
|
|
187
|
+
tx.oncomplete = resolve;
|
|
188
|
+
tx.onerror = reject;
|
|
189
|
+
});
|
|
190
|
+
} catch { /* best-effort persistence — ignore failures */ }
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Notify sibling tabs of a write and, when in IDB-fallback mode, flush the
|
|
195
|
+
* updated snapshot to IndexedDB. Must be called after every mutating op.
|
|
196
|
+
*/
|
|
197
|
+
function onWriteCommitted() {
|
|
198
|
+
broadcastChannel?.postMessage('taladb:changed');
|
|
199
|
+
// Always flush a snapshot to IDB after every write — this keeps other tabs'
|
|
200
|
+
// IDB-fallback instances in sync via BroadcastChannel + snapshotDirty reload.
|
|
201
|
+
if (db && activeDbName) {
|
|
202
|
+
try {
|
|
203
|
+
const bytes = db.exportSnapshot();
|
|
204
|
+
idbSaveSnapshot(activeDbName, bytes).catch(() => {});
|
|
205
|
+
} catch { /* ignore snapshot export errors */ }
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
79
209
|
// ---------------------------------------------------------------------------
|
|
80
210
|
// Dedicated Worker message handler
|
|
81
211
|
// ---------------------------------------------------------------------------
|
|
@@ -95,6 +225,16 @@ self.onmessage = async (e) => {
|
|
|
95
225
|
// ---------------------------------------------------------------------------
|
|
96
226
|
|
|
97
227
|
async function dispatch(op, args) {
|
|
228
|
+
// In IDB-fallback mode, reload the snapshot before each op when the primary
|
|
229
|
+
// tab has signalled a write via BroadcastChannel. This keeps reads fresh.
|
|
230
|
+
if (idbFallback && snapshotDirty && op !== 'init' && db && activeDbName && WorkerDB) {
|
|
231
|
+
snapshotDirty = false;
|
|
232
|
+
try {
|
|
233
|
+
const fresh = await idbLoadSnapshot(activeDbName);
|
|
234
|
+
if (fresh) db = WorkerDB.openWithSnapshot(fresh);
|
|
235
|
+
} catch { /* ignore reload errors — stale read is acceptable */ }
|
|
236
|
+
}
|
|
237
|
+
|
|
98
238
|
if (op === 'init') {
|
|
99
239
|
const { dbName } = args;
|
|
100
240
|
|
|
@@ -116,11 +256,17 @@ async function dispatch(op, args) {
|
|
|
116
256
|
if (!db) throw new Error('TalaDB worker not initialised — call init first');
|
|
117
257
|
|
|
118
258
|
switch (op) {
|
|
119
|
-
case 'insert':
|
|
120
|
-
|
|
259
|
+
case 'insert': {
|
|
260
|
+
const result = db.insert(args.collection, args.docJson);
|
|
261
|
+
onWriteCommitted();
|
|
262
|
+
return result;
|
|
263
|
+
}
|
|
121
264
|
|
|
122
|
-
case 'insertMany':
|
|
123
|
-
|
|
265
|
+
case 'insertMany': {
|
|
266
|
+
const result = db.insertMany(args.collection, args.docsJson);
|
|
267
|
+
onWriteCommitted();
|
|
268
|
+
return result;
|
|
269
|
+
}
|
|
124
270
|
|
|
125
271
|
case 'find':
|
|
126
272
|
return db.find(args.collection, args.filterJson ?? 'null');
|
|
@@ -128,17 +274,29 @@ async function dispatch(op, args) {
|
|
|
128
274
|
case 'findOne':
|
|
129
275
|
return db.findOne(args.collection, args.filterJson ?? 'null');
|
|
130
276
|
|
|
131
|
-
case 'updateOne':
|
|
132
|
-
|
|
277
|
+
case 'updateOne': {
|
|
278
|
+
const result = db.updateOne(args.collection, args.filterJson, args.updateJson);
|
|
279
|
+
onWriteCommitted();
|
|
280
|
+
return result;
|
|
281
|
+
}
|
|
133
282
|
|
|
134
|
-
case 'updateMany':
|
|
135
|
-
|
|
283
|
+
case 'updateMany': {
|
|
284
|
+
const result = db.updateMany(args.collection, args.filterJson, args.updateJson);
|
|
285
|
+
onWriteCommitted();
|
|
286
|
+
return result;
|
|
287
|
+
}
|
|
136
288
|
|
|
137
|
-
case 'deleteOne':
|
|
138
|
-
|
|
289
|
+
case 'deleteOne': {
|
|
290
|
+
const result = db.deleteOne(args.collection, args.filterJson);
|
|
291
|
+
onWriteCommitted();
|
|
292
|
+
return result;
|
|
293
|
+
}
|
|
139
294
|
|
|
140
|
-
case 'deleteMany':
|
|
141
|
-
|
|
295
|
+
case 'deleteMany': {
|
|
296
|
+
const result = db.deleteMany(args.collection, args.filterJson);
|
|
297
|
+
onWriteCommitted();
|
|
298
|
+
return result;
|
|
299
|
+
}
|
|
142
300
|
|
|
143
301
|
case 'count':
|
|
144
302
|
return db.count(args.collection, args.filterJson ?? 'null');
|
|
@@ -159,14 +317,29 @@ async function dispatch(op, args) {
|
|
|
159
317
|
db.dropFtsIndex(args.collection, args.field);
|
|
160
318
|
return null;
|
|
161
319
|
|
|
320
|
+
case 'listIndexes':
|
|
321
|
+
return db.listIndexes(args.collection);
|
|
322
|
+
|
|
162
323
|
case 'createVectorIndex':
|
|
163
|
-
db.createVectorIndex(
|
|
324
|
+
db.createVectorIndex(
|
|
325
|
+
args.collection,
|
|
326
|
+
args.field,
|
|
327
|
+
args.dimensions,
|
|
328
|
+
args.metric ?? null,
|
|
329
|
+
args.indexType ?? null,
|
|
330
|
+
args.hnswM ?? null,
|
|
331
|
+
args.hnswEfConstruction ?? null,
|
|
332
|
+
);
|
|
164
333
|
return null;
|
|
165
334
|
|
|
166
335
|
case 'dropVectorIndex':
|
|
167
336
|
db.dropVectorIndex(args.collection, args.field);
|
|
168
337
|
return null;
|
|
169
338
|
|
|
339
|
+
case 'upgradeVectorIndex':
|
|
340
|
+
db.upgradeVectorIndex(args.collection, args.field);
|
|
341
|
+
return null;
|
|
342
|
+
|
|
170
343
|
case 'findNearest':
|
|
171
344
|
return db.findNearest(
|
|
172
345
|
args.collection,
|
|
@@ -179,6 +352,9 @@ async function dispatch(op, args) {
|
|
|
179
352
|
case 'close':
|
|
180
353
|
// Release the Web Lock and close the sync handle gracefully.
|
|
181
354
|
if (releaseLock) { releaseLock(); releaseLock = null; }
|
|
355
|
+
broadcastChannel?.close();
|
|
356
|
+
broadcastChannel = null;
|
|
357
|
+
idbFallback = false;
|
|
182
358
|
db = null;
|
|
183
359
|
return null;
|
|
184
360
|
|
|
@@ -195,12 +371,45 @@ async function doInit(dbName) {
|
|
|
195
371
|
const wasm = await import('../pkg/taladb_web.js');
|
|
196
372
|
await wasm.default();
|
|
197
373
|
|
|
198
|
-
|
|
374
|
+
// Hoist to module scope so snapshot reloads in dispatch() can use it.
|
|
375
|
+
WorkerDB = wasm.WorkerDB;
|
|
376
|
+
|
|
377
|
+
// Open the BroadcastChannel now that we know the db name.
|
|
378
|
+
if (typeof BroadcastChannel !== 'undefined') {
|
|
379
|
+
broadcastChannel = new BroadcastChannel(`taladb:${dbName}`);
|
|
380
|
+
broadcastChannel.onmessage = async (e) => {
|
|
381
|
+
if (e.data === 'taladb:changed' && idbFallback) {
|
|
382
|
+
// Fallback tab: primary tab wrote — reload snapshot before next read.
|
|
383
|
+
snapshotDirty = true;
|
|
384
|
+
} else if (e.data === 'taladb:request-snapshot' && !idbFallback && db && activeDbName) {
|
|
385
|
+
// Primary (OPFS) tab: a new tab asked for a snapshot — export and save it.
|
|
386
|
+
try {
|
|
387
|
+
const bytes = db.exportSnapshot();
|
|
388
|
+
await idbSaveSnapshot(activeDbName, bytes);
|
|
389
|
+
broadcastChannel.postMessage('taladb:snapshot-ready');
|
|
390
|
+
log('Exported snapshot for waiting tab');
|
|
391
|
+
} catch { /* ignore */ }
|
|
392
|
+
} else if (e.data === 'taladb:snapshot-ready' && pendingSnapshotResolve) {
|
|
393
|
+
// Fallback tab: primary tab finished saving — wake up the waiting doInit.
|
|
394
|
+
const resolve = pendingSnapshotResolve;
|
|
395
|
+
pendingSnapshotResolve = null;
|
|
396
|
+
resolve();
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
log('BroadcastChannel opened:', `taladb:${dbName}`);
|
|
400
|
+
}
|
|
199
401
|
|
|
200
402
|
const opfsAvailable = await checkOpfs();
|
|
201
403
|
if (!opfsAvailable) {
|
|
202
|
-
warn('OPFS unavailable — falling back to in-memory');
|
|
203
|
-
|
|
404
|
+
warn('OPFS unavailable — falling back to IndexedDB-backed in-memory');
|
|
405
|
+
const snapshot = await idbLoadSnapshot(dbName);
|
|
406
|
+
db = WorkerDB.openWithSnapshot(snapshot);
|
|
407
|
+
idbFallback = true;
|
|
408
|
+
if (snapshot) {
|
|
409
|
+
log(`Restored from IndexedDB snapshot (${snapshot.byteLength} bytes)`);
|
|
410
|
+
} else {
|
|
411
|
+
log('New in-memory database — writes will be persisted to IndexedDB');
|
|
412
|
+
}
|
|
204
413
|
return;
|
|
205
414
|
}
|
|
206
415
|
|
|
@@ -217,12 +426,43 @@ async function doInit(dbName) {
|
|
|
217
426
|
return;
|
|
218
427
|
}
|
|
219
428
|
|
|
220
|
-
//
|
|
221
|
-
// If another tab
|
|
222
|
-
//
|
|
429
|
+
// Try to acquire the exclusive OPFS lock immediately (ifAvailable).
|
|
430
|
+
// If another tab already holds it, fall back to IDB snapshot right away so
|
|
431
|
+
// this tab is immediately usable instead of blocking until the other tab closes.
|
|
432
|
+
// The primary (OPFS) tab flushes a snapshot to IDB after every write, and
|
|
433
|
+
// this tab's BroadcastChannel listener sets snapshotDirty so dispatch()
|
|
434
|
+
// reloads the snapshot before the next read — keeping data fresh across tabs.
|
|
223
435
|
const lockName = `taladb:${fileName}`;
|
|
224
436
|
await new Promise((resolve, reject) => {
|
|
225
|
-
navigator.locks.request(lockName, async () => {
|
|
437
|
+
navigator.locks.request(lockName, { ifAvailable: true }, async (lock) => {
|
|
438
|
+
if (lock === null) {
|
|
439
|
+
// Lock is held by another tab — use IDB snapshot so this tab loads immediately.
|
|
440
|
+
warn('OPFS lock held by another tab — falling back to IndexedDB snapshot (live-sync via BroadcastChannel)');
|
|
441
|
+
let snapshot = await idbLoadSnapshot(dbName);
|
|
442
|
+
|
|
443
|
+
if (!snapshot && broadcastChannel) {
|
|
444
|
+
// No IDB snapshot yet — ask the primary tab to export one now.
|
|
445
|
+
log('No IDB snapshot — requesting one from the primary tab...');
|
|
446
|
+
const gotIt = await new Promise(res => {
|
|
447
|
+
pendingSnapshotResolve = res;
|
|
448
|
+
setTimeout(() => { pendingSnapshotResolve = null; res(false); }, 2000);
|
|
449
|
+
broadcastChannel.postMessage('taladb:request-snapshot');
|
|
450
|
+
});
|
|
451
|
+
if (gotIt !== false) snapshot = await idbLoadSnapshot(dbName);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
db = WorkerDB.openWithSnapshot(snapshot ?? null);
|
|
455
|
+
idbFallback = true;
|
|
456
|
+
if (snapshot) {
|
|
457
|
+
log(`Restored from IDB snapshot (${snapshot.byteLength} bytes)`);
|
|
458
|
+
} else {
|
|
459
|
+
log('No IDB snapshot yet — starting with empty in-memory database');
|
|
460
|
+
}
|
|
461
|
+
resolve();
|
|
462
|
+
return; // Do not hold the lock; returning releases it back to the queue.
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Acquired the lock — use OPFS.
|
|
226
466
|
try {
|
|
227
467
|
const syncHandle = await fileHandle.createSyncAccessHandle();
|
|
228
468
|
db = WorkerDB.openWithOpfs(syncHandle);
|