@taladb/web 0.8.3 → 0.9.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 +2 -2
- package/pkg/package.json +1 -1
- package/pkg/taladb_web.d.ts +65 -10
- package/pkg/taladb_web.js +260 -20
- package/pkg/taladb_web_bg.wasm +0 -0
- package/pkg/taladb_web_bg.wasm.d.ts +21 -9
- package/worker/taladb.worker.js +151 -19
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taladb/web",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "TalaDB WASM bindings — document queries and vector search in the browser",
|
|
5
5
|
"main": "pkg/taladb_web.js",
|
|
6
6
|
"types": "pkg/taladb_web.d.ts",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"repository": {
|
|
20
20
|
"type": "git",
|
|
21
21
|
"url": "https://github.com/thinkgrid-labs/taladb.git",
|
|
22
|
-
"directory": "packages/
|
|
22
|
+
"directory": "packages/bindings/web"
|
|
23
23
|
},
|
|
24
24
|
"homepage": "https://thinkgrid-labs.github.io/taladb/guide/web",
|
|
25
25
|
"bugs": {
|
package/pkg/package.json
CHANGED
package/pkg/taladb_web.d.ts
CHANGED
|
@@ -5,10 +5,19 @@ export class CollectionWasm {
|
|
|
5
5
|
private constructor();
|
|
6
6
|
free(): void;
|
|
7
7
|
[Symbol.dispose](): void;
|
|
8
|
+
/**
|
|
9
|
+
* Run a MongoDB-style aggregation pipeline (`$match`, `$group`, `$sort`,
|
|
10
|
+
* `$skip`, `$limit`, `$project`). Returns the resulting documents.
|
|
11
|
+
*/
|
|
12
|
+
aggregate(pipeline: any): any;
|
|
8
13
|
/**
|
|
9
14
|
* Count documents matching the filter.
|
|
10
15
|
*/
|
|
11
16
|
count(filter: any): number;
|
|
17
|
+
/**
|
|
18
|
+
* Create a compound index. `fields_json` is a JSON array of field names.
|
|
19
|
+
*/
|
|
20
|
+
createCompoundIndex(fields_json: string): void;
|
|
12
21
|
/**
|
|
13
22
|
* Create a secondary index on a field.
|
|
14
23
|
*/
|
|
@@ -31,6 +40,10 @@ export class CollectionWasm {
|
|
|
31
40
|
* Delete the first matching document. Returns true if deleted.
|
|
32
41
|
*/
|
|
33
42
|
deleteOne(filter: any): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Drop a compound index by its ordered field list (`fields_json`).
|
|
45
|
+
*/
|
|
46
|
+
dropCompoundIndex(fields_json: string): void;
|
|
34
47
|
/**
|
|
35
48
|
* Drop a secondary index.
|
|
36
49
|
*/
|
|
@@ -86,6 +99,12 @@ export class TalaDBWasm {
|
|
|
86
99
|
* Get a collection handle by name.
|
|
87
100
|
*/
|
|
88
101
|
collection(name: string): CollectionWasm;
|
|
102
|
+
/**
|
|
103
|
+
* Export changes to `collections` after `sinceMs` (exclusive) as a JSON
|
|
104
|
+
* changeset string, for bidirectional sync. `sinceMs` is a millisecond
|
|
105
|
+
* epoch timestamp (the persisted sync cursor).
|
|
106
|
+
*/
|
|
107
|
+
exportChanges(since_ms: number, collections: string[]): string;
|
|
89
108
|
/**
|
|
90
109
|
* Serialize the entire in-memory database to bytes.
|
|
91
110
|
*
|
|
@@ -94,6 +113,16 @@ export class TalaDBWasm {
|
|
|
94
113
|
* `openWithSnapshot` to restore all data.
|
|
95
114
|
*/
|
|
96
115
|
exportSnapshot(): Uint8Array;
|
|
116
|
+
/**
|
|
117
|
+
* Merge a JSON changeset string (from a remote peer) into the local
|
|
118
|
+
* database via Last-Write-Wins. Returns the number of documents changed.
|
|
119
|
+
*/
|
|
120
|
+
importChanges(changeset_json: string): number;
|
|
121
|
+
/**
|
|
122
|
+
* User collection names (reserved `_`-prefixed collections excluded).
|
|
123
|
+
* Backs the sync orchestration's "sync all collections" default.
|
|
124
|
+
*/
|
|
125
|
+
listCollectionNames(): string[];
|
|
97
126
|
/**
|
|
98
127
|
* Open an in-memory database (suitable for tests and environments without OPFS).
|
|
99
128
|
*/
|
|
@@ -119,6 +148,10 @@ export class WorkerDB {
|
|
|
119
148
|
private constructor();
|
|
120
149
|
free(): void;
|
|
121
150
|
[Symbol.dispose](): void;
|
|
151
|
+
/**
|
|
152
|
+
* Run an aggregation pipeline. Returns a JSON array of result documents.
|
|
153
|
+
*/
|
|
154
|
+
aggregate(collection: string, pipeline_json: string): string;
|
|
122
155
|
/**
|
|
123
156
|
* Compact the underlying OPFS / redb storage file, reclaiming space freed
|
|
124
157
|
* by deletes and updates.
|
|
@@ -149,6 +182,10 @@ export class WorkerDB {
|
|
|
149
182
|
* Count matching documents.
|
|
150
183
|
*/
|
|
151
184
|
count(collection: string, filter_json: string): number;
|
|
185
|
+
/**
|
|
186
|
+
* Create a compound index. `fields_json` is a JSON array of field names.
|
|
187
|
+
*/
|
|
188
|
+
createCompoundIndex(collection: string, fields_json: string): void;
|
|
152
189
|
createFtsIndex(collection: string, field: string): void;
|
|
153
190
|
createIndex(collection: string, field: string): void;
|
|
154
191
|
/**
|
|
@@ -168,6 +205,10 @@ export class WorkerDB {
|
|
|
168
205
|
* Delete the first matching document. Returns `true` / `false`.
|
|
169
206
|
*/
|
|
170
207
|
deleteOne(collection: string, filter_json: string): boolean;
|
|
208
|
+
/**
|
|
209
|
+
* Drop a compound index by its ordered field list (`fields_json`).
|
|
210
|
+
*/
|
|
211
|
+
dropCompoundIndex(collection: string, fields_json: string): void;
|
|
171
212
|
dropFtsIndex(collection: string, field: string): void;
|
|
172
213
|
dropIndex(collection: string, field: string): void;
|
|
173
214
|
/**
|
|
@@ -252,7 +293,7 @@ export class WorkerDB {
|
|
|
252
293
|
* const db = WorkerDB.openWithConfigAndOpfs(handle, JSON.stringify(config));
|
|
253
294
|
* ```
|
|
254
295
|
*/
|
|
255
|
-
static openWithConfigAndOpfs(sync_handle: FileSystemSyncAccessHandle, config_json?: string | null): WorkerDB;
|
|
296
|
+
static openWithConfigAndOpfs(sync_handle: FileSystemSyncAccessHandle, config_json?: string | null, passphrase?: string | null, salt?: Uint8Array | null): WorkerDB;
|
|
256
297
|
/**
|
|
257
298
|
* Open a database from an optional snapshot with HTTP push sync config.
|
|
258
299
|
*
|
|
@@ -287,6 +328,8 @@ export class WorkerDB {
|
|
|
287
328
|
* ```
|
|
288
329
|
*/
|
|
289
330
|
static openWithSnapshot(data?: Uint8Array | null): WorkerDB;
|
|
331
|
+
syncPending(): bigint;
|
|
332
|
+
syncStatus(): string;
|
|
290
333
|
/**
|
|
291
334
|
* Update all matching documents. Returns the count updated.
|
|
292
335
|
*/
|
|
@@ -358,14 +401,17 @@ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembl
|
|
|
358
401
|
export interface InitOutput {
|
|
359
402
|
readonly memory: WebAssembly.Memory;
|
|
360
403
|
readonly __wbg_workerdb_free: (a: number, b: number) => void;
|
|
404
|
+
readonly workerdb_aggregate: (a: number, b: number, c: number, d: number, e: number) => [number, number, number, number];
|
|
361
405
|
readonly workerdb_compact: (a: number) => [number, number];
|
|
362
406
|
readonly workerdb_compactTombstones: (a: number, b: number, c: number, d: number) => [number, number, number];
|
|
363
407
|
readonly workerdb_count: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
|
|
408
|
+
readonly workerdb_createCompoundIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
364
409
|
readonly workerdb_createFtsIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
365
410
|
readonly workerdb_createIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
366
411
|
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];
|
|
367
412
|
readonly workerdb_deleteMany: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
|
|
368
413
|
readonly workerdb_deleteOne: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
|
|
414
|
+
readonly workerdb_dropCompoundIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
369
415
|
readonly workerdb_dropFtsIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
370
416
|
readonly workerdb_dropIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
371
417
|
readonly workerdb_dropVectorIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
@@ -380,20 +426,25 @@ export interface InitOutput {
|
|
|
380
426
|
readonly workerdb_listCollections: (a: number) => [number, number, number, number];
|
|
381
427
|
readonly workerdb_listIndexes: (a: number, b: number, c: number) => [number, number, number, number];
|
|
382
428
|
readonly workerdb_openInMemory: () => [number, number, number];
|
|
383
|
-
readonly workerdb_openWithConfigAndOpfs: (a: any, b: number, c: number) => [number, number, number];
|
|
429
|
+
readonly workerdb_openWithConfigAndOpfs: (a: any, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number];
|
|
384
430
|
readonly workerdb_openWithConfigAndSnapshot: (a: number, b: number, c: number, d: number) => [number, number, number];
|
|
385
431
|
readonly workerdb_openWithOpfs: (a: any) => [number, number, number];
|
|
386
432
|
readonly workerdb_openWithSnapshot: (a: number, b: number) => [number, number, number];
|
|
433
|
+
readonly workerdb_syncPending: (a: number) => bigint;
|
|
434
|
+
readonly workerdb_syncStatus: (a: number) => [number, number];
|
|
387
435
|
readonly workerdb_updateMany: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number];
|
|
388
436
|
readonly workerdb_updateOne: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number];
|
|
389
437
|
readonly workerdb_upgradeVectorIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
390
438
|
readonly __wbg_collectionwasm_free: (a: number, b: number) => void;
|
|
391
439
|
readonly __wbg_taladbwasm_free: (a: number, b: number) => void;
|
|
440
|
+
readonly collectionwasm_aggregate: (a: number, b: any) => [number, number, number];
|
|
392
441
|
readonly collectionwasm_count: (a: number, b: any) => [number, number, number];
|
|
442
|
+
readonly collectionwasm_createCompoundIndex: (a: number, b: number, c: number) => [number, number];
|
|
393
443
|
readonly collectionwasm_createIndex: (a: number, b: number, c: number) => [number, number];
|
|
394
444
|
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];
|
|
395
445
|
readonly collectionwasm_deleteMany: (a: number, b: any) => [number, number, number];
|
|
396
446
|
readonly collectionwasm_deleteOne: (a: number, b: any) => [number, number, number];
|
|
447
|
+
readonly collectionwasm_dropCompoundIndex: (a: number, b: number, c: number) => [number, number];
|
|
397
448
|
readonly collectionwasm_dropIndex: (a: number, b: number, c: number) => [number, number];
|
|
398
449
|
readonly collectionwasm_dropVectorIndex: (a: number, b: number, c: number) => [number, number];
|
|
399
450
|
readonly collectionwasm_find: (a: number, b: any) => [number, number, number];
|
|
@@ -405,24 +456,27 @@ export interface InitOutput {
|
|
|
405
456
|
readonly collectionwasm_updateOne: (a: number, b: any, c: any) => [number, number, number];
|
|
406
457
|
readonly collectionwasm_upgradeVectorIndex: (a: number, b: number, c: number) => [number, number];
|
|
407
458
|
readonly taladbwasm_collection: (a: number, b: number, c: number) => [number, number, number];
|
|
459
|
+
readonly taladbwasm_exportChanges: (a: number, b: number, c: number, d: number) => [number, number, number, number];
|
|
408
460
|
readonly taladbwasm_exportSnapshot: (a: number) => [number, number, number, number];
|
|
461
|
+
readonly taladbwasm_importChanges: (a: number, b: number, c: number) => [number, number, number];
|
|
462
|
+
readonly taladbwasm_listCollectionNames: (a: number) => [number, number, number, number];
|
|
409
463
|
readonly taladbwasm_openInMemory: () => [number, number, number];
|
|
410
464
|
readonly taladbwasm_openWithSnapshot: (a: number, b: number) => [number, number, number];
|
|
411
465
|
readonly init: () => void;
|
|
466
|
+
readonly opfs_open_backend: (a: number, b: number) => any;
|
|
412
467
|
readonly is_opfs_available: () => any;
|
|
413
468
|
readonly opfs_delete_snapshot: (a: number, b: number) => any;
|
|
414
469
|
readonly opfs_flush_snapshot: (a: number, b: number, c: number, d: number) => any;
|
|
415
470
|
readonly opfs_load_snapshot: (a: number, b: number) => any;
|
|
416
471
|
readonly idb_load_snapshot: (a: number, b: number) => any;
|
|
417
472
|
readonly idb_save_snapshot: (a: number, b: number, c: number, d: number) => any;
|
|
418
|
-
readonly
|
|
419
|
-
readonly
|
|
420
|
-
readonly
|
|
421
|
-
readonly
|
|
422
|
-
readonly
|
|
423
|
-
readonly
|
|
424
|
-
readonly
|
|
425
|
-
readonly wasm_bindgen__convert__closures_____invoke__h88d126a9c69f3dfa: (a: number, b: number) => void;
|
|
473
|
+
readonly wasm_bindgen_60ce93de3f474933___closure__destroy___dyn_core_7d5f0a2ba6a62c33___ops__function__FnMut_____Output_______: (a: number, b: number) => void;
|
|
474
|
+
readonly wasm_bindgen_60ce93de3f474933___closure__destroy___dyn_core_7d5f0a2ba6a62c33___ops__function__FnMut__wasm_bindgen_60ce93de3f474933___JsValue____Output___core_7d5f0a2ba6a62c33___result__Result_____wasm_bindgen_60ce93de3f474933___JsError___: (a: number, b: number) => void;
|
|
475
|
+
readonly wasm_bindgen_60ce93de3f474933___closure__destroy___dyn_core_7d5f0a2ba6a62c33___ops__function__FnMut__wasm_bindgen_60ce93de3f474933___JsValue____Output_______: (a: number, b: number) => void;
|
|
476
|
+
readonly wasm_bindgen_60ce93de3f474933___convert__closures_____invoke___wasm_bindgen_60ce93de3f474933___JsValue__core_7d5f0a2ba6a62c33___result__Result_____wasm_bindgen_60ce93de3f474933___JsError___true_: (a: number, b: number, c: any) => [number, number];
|
|
477
|
+
readonly wasm_bindgen_60ce93de3f474933___convert__closures_____invoke___js_sys_517e1093b71f55ec___Function_fn_wasm_bindgen_60ce93de3f474933___JsValue_____wasm_bindgen_60ce93de3f474933___sys__Undefined___js_sys_517e1093b71f55ec___Function_fn_wasm_bindgen_60ce93de3f474933___JsValue_____wasm_bindgen_60ce93de3f474933___sys__Undefined_______true_: (a: number, b: number, c: any, d: any) => void;
|
|
478
|
+
readonly wasm_bindgen_60ce93de3f474933___convert__closures_____invoke___wasm_bindgen_60ce93de3f474933___JsValue______true_: (a: number, b: number, c: any) => void;
|
|
479
|
+
readonly wasm_bindgen_60ce93de3f474933___convert__closures_____invoke_______true_: (a: number, b: number) => void;
|
|
426
480
|
readonly __wbindgen_malloc: (a: number, b: number) => number;
|
|
427
481
|
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
|
428
482
|
readonly __wbindgen_exn_store: (a: number) => void;
|
|
@@ -430,6 +484,7 @@ export interface InitOutput {
|
|
|
430
484
|
readonly __wbindgen_externrefs: WebAssembly.Table;
|
|
431
485
|
readonly __wbindgen_free: (a: number, b: number, c: number) => void;
|
|
432
486
|
readonly __externref_table_dealloc: (a: number) => void;
|
|
487
|
+
readonly __externref_drop_slice: (a: number, b: number) => void;
|
|
433
488
|
readonly __wbindgen_start: () => void;
|
|
434
489
|
}
|
|
435
490
|
|
package/pkg/taladb_web.js
CHANGED
|
@@ -18,6 +18,19 @@ export class CollectionWasm {
|
|
|
18
18
|
const ptr = this.__destroy_into_raw();
|
|
19
19
|
wasm.__wbg_collectionwasm_free(ptr, 0);
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Run a MongoDB-style aggregation pipeline (`$match`, `$group`, `$sort`,
|
|
23
|
+
* `$skip`, `$limit`, `$project`). Returns the resulting documents.
|
|
24
|
+
* @param {any} pipeline
|
|
25
|
+
* @returns {any}
|
|
26
|
+
*/
|
|
27
|
+
aggregate(pipeline) {
|
|
28
|
+
const ret = wasm.collectionwasm_aggregate(this.__wbg_ptr, pipeline);
|
|
29
|
+
if (ret[2]) {
|
|
30
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
31
|
+
}
|
|
32
|
+
return takeFromExternrefTable0(ret[0]);
|
|
33
|
+
}
|
|
21
34
|
/**
|
|
22
35
|
* Count documents matching the filter.
|
|
23
36
|
* @param {any} filter
|
|
@@ -30,6 +43,18 @@ export class CollectionWasm {
|
|
|
30
43
|
}
|
|
31
44
|
return ret[0] >>> 0;
|
|
32
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Create a compound index. `fields_json` is a JSON array of field names.
|
|
48
|
+
* @param {string} fields_json
|
|
49
|
+
*/
|
|
50
|
+
createCompoundIndex(fields_json) {
|
|
51
|
+
const ptr0 = passStringToWasm0(fields_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
52
|
+
const len0 = WASM_VECTOR_LEN;
|
|
53
|
+
const ret = wasm.collectionwasm_createCompoundIndex(this.__wbg_ptr, ptr0, len0);
|
|
54
|
+
if (ret[1]) {
|
|
55
|
+
throw takeFromExternrefTable0(ret[0]);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
33
58
|
/**
|
|
34
59
|
* Create a secondary index on a field.
|
|
35
60
|
* @param {string} field
|
|
@@ -93,6 +118,18 @@ export class CollectionWasm {
|
|
|
93
118
|
}
|
|
94
119
|
return ret[0] !== 0;
|
|
95
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Drop a compound index by its ordered field list (`fields_json`).
|
|
123
|
+
* @param {string} fields_json
|
|
124
|
+
*/
|
|
125
|
+
dropCompoundIndex(fields_json) {
|
|
126
|
+
const ptr0 = passStringToWasm0(fields_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
127
|
+
const len0 = WASM_VECTOR_LEN;
|
|
128
|
+
const ret = wasm.collectionwasm_dropCompoundIndex(this.__wbg_ptr, ptr0, len0);
|
|
129
|
+
if (ret[1]) {
|
|
130
|
+
throw takeFromExternrefTable0(ret[0]);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
96
133
|
/**
|
|
97
134
|
* Drop a secondary index.
|
|
98
135
|
* @param {string} field
|
|
@@ -273,6 +310,34 @@ export class TalaDBWasm {
|
|
|
273
310
|
}
|
|
274
311
|
return CollectionWasm.__wrap(ret[0]);
|
|
275
312
|
}
|
|
313
|
+
/**
|
|
314
|
+
* Export changes to `collections` after `sinceMs` (exclusive) as a JSON
|
|
315
|
+
* changeset string, for bidirectional sync. `sinceMs` is a millisecond
|
|
316
|
+
* epoch timestamp (the persisted sync cursor).
|
|
317
|
+
* @param {number} since_ms
|
|
318
|
+
* @param {string[]} collections
|
|
319
|
+
* @returns {string}
|
|
320
|
+
*/
|
|
321
|
+
exportChanges(since_ms, collections) {
|
|
322
|
+
let deferred3_0;
|
|
323
|
+
let deferred3_1;
|
|
324
|
+
try {
|
|
325
|
+
const ptr0 = passArrayJsValueToWasm0(collections, wasm.__wbindgen_malloc);
|
|
326
|
+
const len0 = WASM_VECTOR_LEN;
|
|
327
|
+
const ret = wasm.taladbwasm_exportChanges(this.__wbg_ptr, since_ms, ptr0, len0);
|
|
328
|
+
var ptr2 = ret[0];
|
|
329
|
+
var len2 = ret[1];
|
|
330
|
+
if (ret[3]) {
|
|
331
|
+
ptr2 = 0; len2 = 0;
|
|
332
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
333
|
+
}
|
|
334
|
+
deferred3_0 = ptr2;
|
|
335
|
+
deferred3_1 = len2;
|
|
336
|
+
return getStringFromWasm0(ptr2, len2);
|
|
337
|
+
} finally {
|
|
338
|
+
wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
276
341
|
/**
|
|
277
342
|
* Serialize the entire in-memory database to bytes.
|
|
278
343
|
*
|
|
@@ -290,6 +355,35 @@ export class TalaDBWasm {
|
|
|
290
355
|
wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
|
|
291
356
|
return v1;
|
|
292
357
|
}
|
|
358
|
+
/**
|
|
359
|
+
* Merge a JSON changeset string (from a remote peer) into the local
|
|
360
|
+
* database via Last-Write-Wins. Returns the number of documents changed.
|
|
361
|
+
* @param {string} changeset_json
|
|
362
|
+
* @returns {number}
|
|
363
|
+
*/
|
|
364
|
+
importChanges(changeset_json) {
|
|
365
|
+
const ptr0 = passStringToWasm0(changeset_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
366
|
+
const len0 = WASM_VECTOR_LEN;
|
|
367
|
+
const ret = wasm.taladbwasm_importChanges(this.__wbg_ptr, ptr0, len0);
|
|
368
|
+
if (ret[2]) {
|
|
369
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
370
|
+
}
|
|
371
|
+
return ret[0] >>> 0;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* User collection names (reserved `_`-prefixed collections excluded).
|
|
375
|
+
* Backs the sync orchestration's "sync all collections" default.
|
|
376
|
+
* @returns {string[]}
|
|
377
|
+
*/
|
|
378
|
+
listCollectionNames() {
|
|
379
|
+
const ret = wasm.taladbwasm_listCollectionNames(this.__wbg_ptr);
|
|
380
|
+
if (ret[3]) {
|
|
381
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
382
|
+
}
|
|
383
|
+
var v1 = getArrayJsValueFromWasm0(ret[0], ret[1]).slice();
|
|
384
|
+
wasm.__wbindgen_free(ret[0], ret[1] * 4, 4);
|
|
385
|
+
return v1;
|
|
386
|
+
}
|
|
293
387
|
/**
|
|
294
388
|
* Open an in-memory database (suitable for tests and environments without OPFS).
|
|
295
389
|
* @returns {TalaDBWasm}
|
|
@@ -347,6 +441,34 @@ export class WorkerDB {
|
|
|
347
441
|
const ptr = this.__destroy_into_raw();
|
|
348
442
|
wasm.__wbg_workerdb_free(ptr, 0);
|
|
349
443
|
}
|
|
444
|
+
/**
|
|
445
|
+
* Run an aggregation pipeline. Returns a JSON array of result documents.
|
|
446
|
+
* @param {string} collection
|
|
447
|
+
* @param {string} pipeline_json
|
|
448
|
+
* @returns {string}
|
|
449
|
+
*/
|
|
450
|
+
aggregate(collection, pipeline_json) {
|
|
451
|
+
let deferred4_0;
|
|
452
|
+
let deferred4_1;
|
|
453
|
+
try {
|
|
454
|
+
const ptr0 = passStringToWasm0(collection, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
455
|
+
const len0 = WASM_VECTOR_LEN;
|
|
456
|
+
const ptr1 = passStringToWasm0(pipeline_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
457
|
+
const len1 = WASM_VECTOR_LEN;
|
|
458
|
+
const ret = wasm.workerdb_aggregate(this.__wbg_ptr, ptr0, len0, ptr1, len1);
|
|
459
|
+
var ptr3 = ret[0];
|
|
460
|
+
var len3 = ret[1];
|
|
461
|
+
if (ret[3]) {
|
|
462
|
+
ptr3 = 0; len3 = 0;
|
|
463
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
464
|
+
}
|
|
465
|
+
deferred4_0 = ptr3;
|
|
466
|
+
deferred4_1 = len3;
|
|
467
|
+
return getStringFromWasm0(ptr3, len3);
|
|
468
|
+
} finally {
|
|
469
|
+
wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
350
472
|
/**
|
|
351
473
|
* Compact the underlying OPFS / redb storage file, reclaiming space freed
|
|
352
474
|
* by deletes and updates.
|
|
@@ -406,6 +528,21 @@ export class WorkerDB {
|
|
|
406
528
|
}
|
|
407
529
|
return ret[0] >>> 0;
|
|
408
530
|
}
|
|
531
|
+
/**
|
|
532
|
+
* Create a compound index. `fields_json` is a JSON array of field names.
|
|
533
|
+
* @param {string} collection
|
|
534
|
+
* @param {string} fields_json
|
|
535
|
+
*/
|
|
536
|
+
createCompoundIndex(collection, fields_json) {
|
|
537
|
+
const ptr0 = passStringToWasm0(collection, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
538
|
+
const len0 = WASM_VECTOR_LEN;
|
|
539
|
+
const ptr1 = passStringToWasm0(fields_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
540
|
+
const len1 = WASM_VECTOR_LEN;
|
|
541
|
+
const ret = wasm.workerdb_createCompoundIndex(this.__wbg_ptr, ptr0, len0, ptr1, len1);
|
|
542
|
+
if (ret[1]) {
|
|
543
|
+
throw takeFromExternrefTable0(ret[0]);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
409
546
|
/**
|
|
410
547
|
* @param {string} collection
|
|
411
548
|
* @param {string} field
|
|
@@ -497,6 +634,21 @@ export class WorkerDB {
|
|
|
497
634
|
}
|
|
498
635
|
return ret[0] !== 0;
|
|
499
636
|
}
|
|
637
|
+
/**
|
|
638
|
+
* Drop a compound index by its ordered field list (`fields_json`).
|
|
639
|
+
* @param {string} collection
|
|
640
|
+
* @param {string} fields_json
|
|
641
|
+
*/
|
|
642
|
+
dropCompoundIndex(collection, fields_json) {
|
|
643
|
+
const ptr0 = passStringToWasm0(collection, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
644
|
+
const len0 = WASM_VECTOR_LEN;
|
|
645
|
+
const ptr1 = passStringToWasm0(fields_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
646
|
+
const len1 = WASM_VECTOR_LEN;
|
|
647
|
+
const ret = wasm.workerdb_dropCompoundIndex(this.__wbg_ptr, ptr0, len0, ptr1, len1);
|
|
648
|
+
if (ret[1]) {
|
|
649
|
+
throw takeFromExternrefTable0(ret[0]);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
500
652
|
/**
|
|
501
653
|
* @param {string} collection
|
|
502
654
|
* @param {string} field
|
|
@@ -833,12 +985,18 @@ export class WorkerDB {
|
|
|
833
985
|
* ```
|
|
834
986
|
* @param {FileSystemSyncAccessHandle} sync_handle
|
|
835
987
|
* @param {string | null} [config_json]
|
|
988
|
+
* @param {string | null} [passphrase]
|
|
989
|
+
* @param {Uint8Array | null} [salt]
|
|
836
990
|
* @returns {WorkerDB}
|
|
837
991
|
*/
|
|
838
|
-
static openWithConfigAndOpfs(sync_handle, config_json) {
|
|
992
|
+
static openWithConfigAndOpfs(sync_handle, config_json, passphrase, salt) {
|
|
839
993
|
var ptr0 = isLikeNone(config_json) ? 0 : passStringToWasm0(config_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
840
994
|
var len0 = WASM_VECTOR_LEN;
|
|
841
|
-
|
|
995
|
+
var ptr1 = isLikeNone(passphrase) ? 0 : passStringToWasm0(passphrase, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
996
|
+
var len1 = WASM_VECTOR_LEN;
|
|
997
|
+
var ptr2 = isLikeNone(salt) ? 0 : passArray8ToWasm0(salt, wasm.__wbindgen_malloc);
|
|
998
|
+
var len2 = WASM_VECTOR_LEN;
|
|
999
|
+
const ret = wasm.workerdb_openWithConfigAndOpfs(sync_handle, ptr0, len0, ptr1, len1, ptr2, len2);
|
|
842
1000
|
if (ret[2]) {
|
|
843
1001
|
throw takeFromExternrefTable0(ret[1]);
|
|
844
1002
|
}
|
|
@@ -909,6 +1067,28 @@ export class WorkerDB {
|
|
|
909
1067
|
}
|
|
910
1068
|
return WorkerDB.__wrap(ret[0]);
|
|
911
1069
|
}
|
|
1070
|
+
/**
|
|
1071
|
+
* @returns {bigint}
|
|
1072
|
+
*/
|
|
1073
|
+
syncPending() {
|
|
1074
|
+
const ret = wasm.workerdb_syncPending(this.__wbg_ptr);
|
|
1075
|
+
return BigInt.asUintN(64, ret);
|
|
1076
|
+
}
|
|
1077
|
+
/**
|
|
1078
|
+
* @returns {string}
|
|
1079
|
+
*/
|
|
1080
|
+
syncStatus() {
|
|
1081
|
+
let deferred1_0;
|
|
1082
|
+
let deferred1_1;
|
|
1083
|
+
try {
|
|
1084
|
+
const ret = wasm.workerdb_syncStatus(this.__wbg_ptr);
|
|
1085
|
+
deferred1_0 = ret[0];
|
|
1086
|
+
deferred1_1 = ret[1];
|
|
1087
|
+
return getStringFromWasm0(ret[0], ret[1]);
|
|
1088
|
+
} finally {
|
|
1089
|
+
wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
912
1092
|
/**
|
|
913
1093
|
* Update all matching documents. Returns the count updated.
|
|
914
1094
|
* @param {string} collection
|
|
@@ -1207,6 +1387,10 @@ function __wbg_get_imports() {
|
|
|
1207
1387
|
const ret = arg0.createWritable();
|
|
1208
1388
|
return ret;
|
|
1209
1389
|
},
|
|
1390
|
+
__wbg_crypto_38df2bab126b63dc: function(arg0) {
|
|
1391
|
+
const ret = arg0.crypto;
|
|
1392
|
+
return ret;
|
|
1393
|
+
},
|
|
1210
1394
|
__wbg_done_08ce71ee07e3bd17: function(arg0) {
|
|
1211
1395
|
const ret = arg0.done;
|
|
1212
1396
|
return ret;
|
|
@@ -1256,6 +1440,9 @@ function __wbg_get_imports() {
|
|
|
1256
1440
|
__wbg_getRandomValues_3f44b700395062e5: function() { return handleError(function (arg0, arg1) {
|
|
1257
1441
|
globalThis.crypto.getRandomValues(getArrayU8FromWasm0(arg0, arg1));
|
|
1258
1442
|
}, arguments); },
|
|
1443
|
+
__wbg_getRandomValues_c44a50d8cfdaebeb: function() { return handleError(function (arg0, arg1) {
|
|
1444
|
+
arg0.getRandomValues(arg1);
|
|
1445
|
+
}, arguments); },
|
|
1259
1446
|
__wbg_getSize_0a16c5e2524d34aa: function() { return handleError(function (arg0) {
|
|
1260
1447
|
const ret = arg0.getSize();
|
|
1261
1448
|
return ret;
|
|
@@ -1414,6 +1601,10 @@ function __wbg_get_imports() {
|
|
|
1414
1601
|
const ret = arg0.length;
|
|
1415
1602
|
return ret;
|
|
1416
1603
|
},
|
|
1604
|
+
__wbg_msCrypto_bd5a034af96bcba6: function(arg0) {
|
|
1605
|
+
const ret = arg0.msCrypto;
|
|
1606
|
+
return ret;
|
|
1607
|
+
},
|
|
1417
1608
|
__wbg_navigator_9cebf56f28aa719b: function(arg0) {
|
|
1418
1609
|
const ret = arg0.navigator;
|
|
1419
1610
|
return ret;
|
|
@@ -1453,7 +1644,7 @@ function __wbg_get_imports() {
|
|
|
1453
1644
|
const a = state0.a;
|
|
1454
1645
|
state0.a = 0;
|
|
1455
1646
|
try {
|
|
1456
|
-
return
|
|
1647
|
+
return wasm_bindgen_60ce93de3f474933___convert__closures_____invoke___js_sys_517e1093b71f55ec___Function_fn_wasm_bindgen_60ce93de3f474933___JsValue_____wasm_bindgen_60ce93de3f474933___sys__Undefined___js_sys_517e1093b71f55ec___Function_fn_wasm_bindgen_60ce93de3f474933___JsValue_____wasm_bindgen_60ce93de3f474933___sys__Undefined_______true_(a, state0.b, arg0, arg1);
|
|
1457
1648
|
} finally {
|
|
1458
1649
|
state0.a = a;
|
|
1459
1650
|
}
|
|
@@ -1475,7 +1666,7 @@ function __wbg_get_imports() {
|
|
|
1475
1666
|
const a = state0.a;
|
|
1476
1667
|
state0.a = 0;
|
|
1477
1668
|
try {
|
|
1478
|
-
return
|
|
1669
|
+
return wasm_bindgen_60ce93de3f474933___convert__closures_____invoke___js_sys_517e1093b71f55ec___Function_fn_wasm_bindgen_60ce93de3f474933___JsValue_____wasm_bindgen_60ce93de3f474933___sys__Undefined___js_sys_517e1093b71f55ec___Function_fn_wasm_bindgen_60ce93de3f474933___JsValue_____wasm_bindgen_60ce93de3f474933___sys__Undefined_______true_(a, state0.b, arg0, arg1);
|
|
1479
1670
|
} finally {
|
|
1480
1671
|
state0.a = a;
|
|
1481
1672
|
}
|
|
@@ -1502,6 +1693,10 @@ function __wbg_get_imports() {
|
|
|
1502
1693
|
const ret = arg0.next;
|
|
1503
1694
|
return ret;
|
|
1504
1695
|
},
|
|
1696
|
+
__wbg_node_84ea875411254db1: function(arg0) {
|
|
1697
|
+
const ret = arg0.node;
|
|
1698
|
+
return ret;
|
|
1699
|
+
},
|
|
1505
1700
|
__wbg_now_16f0c993d5dd6c27: function() {
|
|
1506
1701
|
const ret = Date.now();
|
|
1507
1702
|
return ret;
|
|
@@ -1510,6 +1705,10 @@ function __wbg_get_imports() {
|
|
|
1510
1705
|
const ret = Array.of(arg0, arg1);
|
|
1511
1706
|
return ret;
|
|
1512
1707
|
},
|
|
1708
|
+
__wbg_process_44c7a14e11e9f69e: function(arg0) {
|
|
1709
|
+
const ret = arg0.process;
|
|
1710
|
+
return ret;
|
|
1711
|
+
},
|
|
1513
1712
|
__wbg_prototypesetcall_d62e5099504357e6: function(arg0, arg1, arg2) {
|
|
1514
1713
|
Uint8Array.prototype.set.call(getArrayU8FromWasm0(arg0, arg1), arg2);
|
|
1515
1714
|
},
|
|
@@ -1524,10 +1723,17 @@ function __wbg_get_imports() {
|
|
|
1524
1723
|
__wbg_queueMicrotask_a082d78ce798393e: function(arg0) {
|
|
1525
1724
|
queueMicrotask(arg0);
|
|
1526
1725
|
},
|
|
1726
|
+
__wbg_randomFillSync_6c25eac9869eb53c: function() { return handleError(function (arg0, arg1) {
|
|
1727
|
+
arg0.randomFillSync(arg1);
|
|
1728
|
+
}, arguments); },
|
|
1527
1729
|
__wbg_removeEntry_b2a4d6d0ee2040c5: function(arg0, arg1, arg2) {
|
|
1528
1730
|
const ret = arg0.removeEntry(getStringFromWasm0(arg1, arg2));
|
|
1529
1731
|
return ret;
|
|
1530
1732
|
},
|
|
1733
|
+
__wbg_require_b4edbdcf3e2a1ef0: function() { return handleError(function () {
|
|
1734
|
+
const ret = module.require;
|
|
1735
|
+
return ret;
|
|
1736
|
+
}, arguments); },
|
|
1531
1737
|
__wbg_resolve_ae8d83246e5bcc12: function(arg0) {
|
|
1532
1738
|
const ret = Promise.resolve(arg0);
|
|
1533
1739
|
return ret;
|
|
@@ -1613,6 +1819,10 @@ function __wbg_get_imports() {
|
|
|
1613
1819
|
const ret = JSON.stringify(arg0);
|
|
1614
1820
|
return ret;
|
|
1615
1821
|
}, arguments); },
|
|
1822
|
+
__wbg_subarray_a068d24e39478a8a: function(arg0, arg1, arg2) {
|
|
1823
|
+
const ret = arg0.subarray(arg1 >>> 0, arg2 >>> 0);
|
|
1824
|
+
return ret;
|
|
1825
|
+
},
|
|
1616
1826
|
__wbg_then_098abe61755d12f6: function(arg0, arg1) {
|
|
1617
1827
|
const ret = arg0.then(arg1);
|
|
1618
1828
|
return ret;
|
|
@@ -1635,19 +1845,23 @@ function __wbg_get_imports() {
|
|
|
1635
1845
|
const ret = arg0.value;
|
|
1636
1846
|
return ret;
|
|
1637
1847
|
},
|
|
1848
|
+
__wbg_versions_276b2795b1c6a219: function(arg0) {
|
|
1849
|
+
const ret = arg0.versions;
|
|
1850
|
+
return ret;
|
|
1851
|
+
},
|
|
1638
1852
|
__wbindgen_cast_0000000000000001: function(arg0, arg1) {
|
|
1639
|
-
// Cast intrinsic for `Closure(Closure { dtor_idx:
|
|
1640
|
-
const ret = makeMutClosure(arg0, arg1, wasm.
|
|
1853
|
+
// Cast intrinsic for `Closure(Closure { dtor_idx: 215, function: Function { arguments: [], shim_idx: 216, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
|
1854
|
+
const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen_60ce93de3f474933___closure__destroy___dyn_core_7d5f0a2ba6a62c33___ops__function__FnMut_____Output_______, wasm_bindgen_60ce93de3f474933___convert__closures_____invoke_______true_);
|
|
1641
1855
|
return ret;
|
|
1642
1856
|
},
|
|
1643
1857
|
__wbindgen_cast_0000000000000002: function(arg0, arg1) {
|
|
1644
|
-
// Cast intrinsic for `Closure(Closure { dtor_idx:
|
|
1645
|
-
const ret = makeMutClosure(arg0, arg1, wasm.
|
|
1858
|
+
// Cast intrinsic for `Closure(Closure { dtor_idx: 692, function: Function { arguments: [Externref], shim_idx: 693, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
|
|
1859
|
+
const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen_60ce93de3f474933___closure__destroy___dyn_core_7d5f0a2ba6a62c33___ops__function__FnMut__wasm_bindgen_60ce93de3f474933___JsValue____Output___core_7d5f0a2ba6a62c33___result__Result_____wasm_bindgen_60ce93de3f474933___JsError___, wasm_bindgen_60ce93de3f474933___convert__closures_____invoke___wasm_bindgen_60ce93de3f474933___JsValue__core_7d5f0a2ba6a62c33___result__Result_____wasm_bindgen_60ce93de3f474933___JsError___true_);
|
|
1646
1860
|
return ret;
|
|
1647
1861
|
},
|
|
1648
1862
|
__wbindgen_cast_0000000000000003: function(arg0, arg1) {
|
|
1649
|
-
// Cast intrinsic for `Closure(Closure { dtor_idx:
|
|
1650
|
-
const ret = makeMutClosure(arg0, arg1, wasm.
|
|
1863
|
+
// Cast intrinsic for `Closure(Closure { dtor_idx: 71, function: Function { arguments: [Externref], shim_idx: 72, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
|
1864
|
+
const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen_60ce93de3f474933___closure__destroy___dyn_core_7d5f0a2ba6a62c33___ops__function__FnMut__wasm_bindgen_60ce93de3f474933___JsValue____Output_______, wasm_bindgen_60ce93de3f474933___convert__closures_____invoke___wasm_bindgen_60ce93de3f474933___JsValue______true_);
|
|
1651
1865
|
return ret;
|
|
1652
1866
|
},
|
|
1653
1867
|
__wbindgen_cast_0000000000000004: function(arg0) {
|
|
@@ -1661,16 +1875,21 @@ function __wbg_get_imports() {
|
|
|
1661
1875
|
return ret;
|
|
1662
1876
|
},
|
|
1663
1877
|
__wbindgen_cast_0000000000000006: function(arg0, arg1) {
|
|
1878
|
+
// Cast intrinsic for `Ref(Slice(U8)) -> NamedExternref("Uint8Array")`.
|
|
1879
|
+
const ret = getArrayU8FromWasm0(arg0, arg1);
|
|
1880
|
+
return ret;
|
|
1881
|
+
},
|
|
1882
|
+
__wbindgen_cast_0000000000000007: function(arg0, arg1) {
|
|
1664
1883
|
// Cast intrinsic for `Ref(String) -> Externref`.
|
|
1665
1884
|
const ret = getStringFromWasm0(arg0, arg1);
|
|
1666
1885
|
return ret;
|
|
1667
1886
|
},
|
|
1668
|
-
|
|
1887
|
+
__wbindgen_cast_0000000000000008: function(arg0) {
|
|
1669
1888
|
// Cast intrinsic for `U64 -> Externref`.
|
|
1670
1889
|
const ret = BigInt.asUintN(64, arg0);
|
|
1671
1890
|
return ret;
|
|
1672
1891
|
},
|
|
1673
|
-
|
|
1892
|
+
__wbindgen_cast_0000000000000009: function(arg0, arg1) {
|
|
1674
1893
|
var v0 = getArrayU8FromWasm0(arg0, arg1).slice();
|
|
1675
1894
|
wasm.__wbindgen_free(arg0, arg1 * 1, 1);
|
|
1676
1895
|
// Cast intrinsic for `Vector(U8) -> Externref`.
|
|
@@ -1693,23 +1912,23 @@ function __wbg_get_imports() {
|
|
|
1693
1912
|
};
|
|
1694
1913
|
}
|
|
1695
1914
|
|
|
1696
|
-
function
|
|
1697
|
-
wasm.
|
|
1915
|
+
function wasm_bindgen_60ce93de3f474933___convert__closures_____invoke_______true_(arg0, arg1) {
|
|
1916
|
+
wasm.wasm_bindgen_60ce93de3f474933___convert__closures_____invoke_______true_(arg0, arg1);
|
|
1698
1917
|
}
|
|
1699
1918
|
|
|
1700
|
-
function
|
|
1701
|
-
wasm.
|
|
1919
|
+
function wasm_bindgen_60ce93de3f474933___convert__closures_____invoke___wasm_bindgen_60ce93de3f474933___JsValue______true_(arg0, arg1, arg2) {
|
|
1920
|
+
wasm.wasm_bindgen_60ce93de3f474933___convert__closures_____invoke___wasm_bindgen_60ce93de3f474933___JsValue______true_(arg0, arg1, arg2);
|
|
1702
1921
|
}
|
|
1703
1922
|
|
|
1704
|
-
function
|
|
1705
|
-
const ret = wasm.
|
|
1923
|
+
function wasm_bindgen_60ce93de3f474933___convert__closures_____invoke___wasm_bindgen_60ce93de3f474933___JsValue__core_7d5f0a2ba6a62c33___result__Result_____wasm_bindgen_60ce93de3f474933___JsError___true_(arg0, arg1, arg2) {
|
|
1924
|
+
const ret = wasm.wasm_bindgen_60ce93de3f474933___convert__closures_____invoke___wasm_bindgen_60ce93de3f474933___JsValue__core_7d5f0a2ba6a62c33___result__Result_____wasm_bindgen_60ce93de3f474933___JsError___true_(arg0, arg1, arg2);
|
|
1706
1925
|
if (ret[1]) {
|
|
1707
1926
|
throw takeFromExternrefTable0(ret[0]);
|
|
1708
1927
|
}
|
|
1709
1928
|
}
|
|
1710
1929
|
|
|
1711
|
-
function
|
|
1712
|
-
wasm.
|
|
1930
|
+
function wasm_bindgen_60ce93de3f474933___convert__closures_____invoke___js_sys_517e1093b71f55ec___Function_fn_wasm_bindgen_60ce93de3f474933___JsValue_____wasm_bindgen_60ce93de3f474933___sys__Undefined___js_sys_517e1093b71f55ec___Function_fn_wasm_bindgen_60ce93de3f474933___JsValue_____wasm_bindgen_60ce93de3f474933___sys__Undefined_______true_(arg0, arg1, arg2, arg3) {
|
|
1931
|
+
wasm.wasm_bindgen_60ce93de3f474933___convert__closures_____invoke___js_sys_517e1093b71f55ec___Function_fn_wasm_bindgen_60ce93de3f474933___JsValue_____wasm_bindgen_60ce93de3f474933___sys__Undefined___js_sys_517e1093b71f55ec___Function_fn_wasm_bindgen_60ce93de3f474933___JsValue_____wasm_bindgen_60ce93de3f474933___sys__Undefined_______true_(arg0, arg1, arg2, arg3);
|
|
1713
1932
|
}
|
|
1714
1933
|
|
|
1715
1934
|
|
|
@@ -1805,6 +2024,17 @@ function debugString(val) {
|
|
|
1805
2024
|
return className;
|
|
1806
2025
|
}
|
|
1807
2026
|
|
|
2027
|
+
function getArrayJsValueFromWasm0(ptr, len) {
|
|
2028
|
+
ptr = ptr >>> 0;
|
|
2029
|
+
const mem = getDataViewMemory0();
|
|
2030
|
+
const result = [];
|
|
2031
|
+
for (let i = ptr; i < ptr + 4 * len; i += 4) {
|
|
2032
|
+
result.push(wasm.__wbindgen_externrefs.get(mem.getUint32(i, true)));
|
|
2033
|
+
}
|
|
2034
|
+
wasm.__externref_drop_slice(ptr, len);
|
|
2035
|
+
return result;
|
|
2036
|
+
}
|
|
2037
|
+
|
|
1808
2038
|
function getArrayU8FromWasm0(ptr, len) {
|
|
1809
2039
|
ptr = ptr >>> 0;
|
|
1810
2040
|
return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
|
|
@@ -1894,6 +2124,16 @@ function passArrayF32ToWasm0(arg, malloc) {
|
|
|
1894
2124
|
return ptr;
|
|
1895
2125
|
}
|
|
1896
2126
|
|
|
2127
|
+
function passArrayJsValueToWasm0(array, malloc) {
|
|
2128
|
+
const ptr = malloc(array.length * 4, 4) >>> 0;
|
|
2129
|
+
for (let i = 0; i < array.length; i++) {
|
|
2130
|
+
const add = addToExternrefTable0(array[i]);
|
|
2131
|
+
getDataViewMemory0().setUint32(ptr + 4 * i, add, true);
|
|
2132
|
+
}
|
|
2133
|
+
WASM_VECTOR_LEN = array.length;
|
|
2134
|
+
return ptr;
|
|
2135
|
+
}
|
|
2136
|
+
|
|
1897
2137
|
function passStringToWasm0(arg, malloc, realloc) {
|
|
1898
2138
|
if (realloc === undefined) {
|
|
1899
2139
|
const buf = cachedTextEncoder.encode(arg);
|
package/pkg/taladb_web_bg.wasm
CHANGED
|
Binary file
|
|
@@ -2,14 +2,17 @@
|
|
|
2
2
|
/* eslint-disable */
|
|
3
3
|
export const memory: WebAssembly.Memory;
|
|
4
4
|
export const __wbg_workerdb_free: (a: number, b: number) => void;
|
|
5
|
+
export const workerdb_aggregate: (a: number, b: number, c: number, d: number, e: number) => [number, number, number, number];
|
|
5
6
|
export const workerdb_compact: (a: number) => [number, number];
|
|
6
7
|
export const workerdb_compactTombstones: (a: number, b: number, c: number, d: number) => [number, number, number];
|
|
7
8
|
export const workerdb_count: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
|
|
9
|
+
export const workerdb_createCompoundIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
8
10
|
export const workerdb_createFtsIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
9
11
|
export const workerdb_createIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
10
12
|
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];
|
|
11
13
|
export const workerdb_deleteMany: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
|
|
12
14
|
export const workerdb_deleteOne: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
|
|
15
|
+
export const workerdb_dropCompoundIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
13
16
|
export const workerdb_dropFtsIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
14
17
|
export const workerdb_dropIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
15
18
|
export const workerdb_dropVectorIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
@@ -24,20 +27,25 @@ export const workerdb_insertMany: (a: number, b: number, c: number, d: number, e
|
|
|
24
27
|
export const workerdb_listCollections: (a: number) => [number, number, number, number];
|
|
25
28
|
export const workerdb_listIndexes: (a: number, b: number, c: number) => [number, number, number, number];
|
|
26
29
|
export const workerdb_openInMemory: () => [number, number, number];
|
|
27
|
-
export const workerdb_openWithConfigAndOpfs: (a: any, b: number, c: number) => [number, number, number];
|
|
30
|
+
export const workerdb_openWithConfigAndOpfs: (a: any, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number];
|
|
28
31
|
export const workerdb_openWithConfigAndSnapshot: (a: number, b: number, c: number, d: number) => [number, number, number];
|
|
29
32
|
export const workerdb_openWithOpfs: (a: any) => [number, number, number];
|
|
30
33
|
export const workerdb_openWithSnapshot: (a: number, b: number) => [number, number, number];
|
|
34
|
+
export const workerdb_syncPending: (a: number) => bigint;
|
|
35
|
+
export const workerdb_syncStatus: (a: number) => [number, number];
|
|
31
36
|
export const workerdb_updateMany: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number];
|
|
32
37
|
export const workerdb_updateOne: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number];
|
|
33
38
|
export const workerdb_upgradeVectorIndex: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
|
34
39
|
export const __wbg_collectionwasm_free: (a: number, b: number) => void;
|
|
35
40
|
export const __wbg_taladbwasm_free: (a: number, b: number) => void;
|
|
41
|
+
export const collectionwasm_aggregate: (a: number, b: any) => [number, number, number];
|
|
36
42
|
export const collectionwasm_count: (a: number, b: any) => [number, number, number];
|
|
43
|
+
export const collectionwasm_createCompoundIndex: (a: number, b: number, c: number) => [number, number];
|
|
37
44
|
export const collectionwasm_createIndex: (a: number, b: number, c: number) => [number, number];
|
|
38
45
|
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];
|
|
39
46
|
export const collectionwasm_deleteMany: (a: number, b: any) => [number, number, number];
|
|
40
47
|
export const collectionwasm_deleteOne: (a: number, b: any) => [number, number, number];
|
|
48
|
+
export const collectionwasm_dropCompoundIndex: (a: number, b: number, c: number) => [number, number];
|
|
41
49
|
export const collectionwasm_dropIndex: (a: number, b: number, c: number) => [number, number];
|
|
42
50
|
export const collectionwasm_dropVectorIndex: (a: number, b: number, c: number) => [number, number];
|
|
43
51
|
export const collectionwasm_find: (a: number, b: any) => [number, number, number];
|
|
@@ -49,24 +57,27 @@ export const collectionwasm_updateMany: (a: number, b: any, c: any) => [number,
|
|
|
49
57
|
export const collectionwasm_updateOne: (a: number, b: any, c: any) => [number, number, number];
|
|
50
58
|
export const collectionwasm_upgradeVectorIndex: (a: number, b: number, c: number) => [number, number];
|
|
51
59
|
export const taladbwasm_collection: (a: number, b: number, c: number) => [number, number, number];
|
|
60
|
+
export const taladbwasm_exportChanges: (a: number, b: number, c: number, d: number) => [number, number, number, number];
|
|
52
61
|
export const taladbwasm_exportSnapshot: (a: number) => [number, number, number, number];
|
|
62
|
+
export const taladbwasm_importChanges: (a: number, b: number, c: number) => [number, number, number];
|
|
63
|
+
export const taladbwasm_listCollectionNames: (a: number) => [number, number, number, number];
|
|
53
64
|
export const taladbwasm_openInMemory: () => [number, number, number];
|
|
54
65
|
export const taladbwasm_openWithSnapshot: (a: number, b: number) => [number, number, number];
|
|
55
66
|
export const init: () => void;
|
|
67
|
+
export const opfs_open_backend: (a: number, b: number) => any;
|
|
56
68
|
export const is_opfs_available: () => any;
|
|
57
69
|
export const opfs_delete_snapshot: (a: number, b: number) => any;
|
|
58
70
|
export const opfs_flush_snapshot: (a: number, b: number, c: number, d: number) => any;
|
|
59
71
|
export const opfs_load_snapshot: (a: number, b: number) => any;
|
|
60
72
|
export const idb_load_snapshot: (a: number, b: number) => any;
|
|
61
73
|
export const idb_save_snapshot: (a: number, b: number, c: number, d: number) => any;
|
|
62
|
-
export const
|
|
63
|
-
export const
|
|
64
|
-
export const
|
|
65
|
-
export const
|
|
66
|
-
export const
|
|
67
|
-
export const
|
|
68
|
-
export const
|
|
69
|
-
export const wasm_bindgen__convert__closures_____invoke__h88d126a9c69f3dfa: (a: number, b: number) => void;
|
|
74
|
+
export const wasm_bindgen_60ce93de3f474933___closure__destroy___dyn_core_7d5f0a2ba6a62c33___ops__function__FnMut_____Output_______: (a: number, b: number) => void;
|
|
75
|
+
export const wasm_bindgen_60ce93de3f474933___closure__destroy___dyn_core_7d5f0a2ba6a62c33___ops__function__FnMut__wasm_bindgen_60ce93de3f474933___JsValue____Output___core_7d5f0a2ba6a62c33___result__Result_____wasm_bindgen_60ce93de3f474933___JsError___: (a: number, b: number) => void;
|
|
76
|
+
export const wasm_bindgen_60ce93de3f474933___closure__destroy___dyn_core_7d5f0a2ba6a62c33___ops__function__FnMut__wasm_bindgen_60ce93de3f474933___JsValue____Output_______: (a: number, b: number) => void;
|
|
77
|
+
export const wasm_bindgen_60ce93de3f474933___convert__closures_____invoke___wasm_bindgen_60ce93de3f474933___JsValue__core_7d5f0a2ba6a62c33___result__Result_____wasm_bindgen_60ce93de3f474933___JsError___true_: (a: number, b: number, c: any) => [number, number];
|
|
78
|
+
export const wasm_bindgen_60ce93de3f474933___convert__closures_____invoke___js_sys_517e1093b71f55ec___Function_fn_wasm_bindgen_60ce93de3f474933___JsValue_____wasm_bindgen_60ce93de3f474933___sys__Undefined___js_sys_517e1093b71f55ec___Function_fn_wasm_bindgen_60ce93de3f474933___JsValue_____wasm_bindgen_60ce93de3f474933___sys__Undefined_______true_: (a: number, b: number, c: any, d: any) => void;
|
|
79
|
+
export const wasm_bindgen_60ce93de3f474933___convert__closures_____invoke___wasm_bindgen_60ce93de3f474933___JsValue______true_: (a: number, b: number, c: any) => void;
|
|
80
|
+
export const wasm_bindgen_60ce93de3f474933___convert__closures_____invoke_______true_: (a: number, b: number) => void;
|
|
70
81
|
export const __wbindgen_malloc: (a: number, b: number) => number;
|
|
71
82
|
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
|
72
83
|
export const __wbindgen_exn_store: (a: number) => void;
|
|
@@ -74,4 +85,5 @@ export const __externref_table_alloc: () => number;
|
|
|
74
85
|
export const __wbindgen_externrefs: WebAssembly.Table;
|
|
75
86
|
export const __wbindgen_free: (a: number, b: number, c: number) => void;
|
|
76
87
|
export const __externref_table_dealloc: (a: number) => void;
|
|
88
|
+
export const __externref_drop_slice: (a: number, b: number) => void;
|
|
77
89
|
export const __wbindgen_start: () => void;
|
package/worker/taladb.worker.js
CHANGED
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
* deleteOne { collection, filterJson }
|
|
40
40
|
* deleteMany { collection, filterJson }
|
|
41
41
|
* count { collection, filterJson }
|
|
42
|
+
* aggregate { collection, pipelineJson } → JSON array of result docs
|
|
42
43
|
* createIndex { collection, field }
|
|
43
44
|
* dropIndex { collection, field }
|
|
44
45
|
* createFtsIndex { collection, field }
|
|
@@ -161,14 +162,26 @@ let broadcastChannel = null;
|
|
|
161
162
|
*/
|
|
162
163
|
let idbFallback = false;
|
|
163
164
|
|
|
165
|
+
/** Whether this worker is allowed to publish the authoritative IDB snapshot. */
|
|
166
|
+
let snapshotWriter = false;
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* True when the database is opened with a passphrase (encrypted at rest in the
|
|
170
|
+
* OPFS file). Encrypted databases NEVER write a snapshot to IndexedDB — an
|
|
171
|
+
* exported snapshot is decrypted plaintext, so persisting it would defeat
|
|
172
|
+
* encryption. Encrypted mode therefore requires exclusive OPFS and is
|
|
173
|
+
* single-tab: the multi-tab IDB-snapshot fallback is refused, not silently
|
|
174
|
+
* downgraded to plaintext.
|
|
175
|
+
* @type {boolean}
|
|
176
|
+
*/
|
|
177
|
+
let encrypted = false;
|
|
178
|
+
|
|
164
179
|
/**
|
|
165
180
|
* Timestamp (ms) of the last changeset we exported and broadcast to the
|
|
166
181
|
* primary tab. Used as `sinceMs` for the next export so we only send the
|
|
167
182
|
* delta, not the entire database on every write.
|
|
168
183
|
* @type {number}
|
|
169
184
|
*/
|
|
170
|
-
let lastSecondaryPushMs = 0;
|
|
171
|
-
|
|
172
185
|
// ---------------------------------------------------------------------------
|
|
173
186
|
// IndexedDB helpers (used only when OPFS is unavailable)
|
|
174
187
|
// ---------------------------------------------------------------------------
|
|
@@ -259,10 +272,11 @@ async function flushSnapshot() {
|
|
|
259
272
|
clearTimeout(snapshotTimer);
|
|
260
273
|
snapshotTimer = null;
|
|
261
274
|
lastSnapshotMs = Date.now();
|
|
262
|
-
if (db && activeDbName) {
|
|
275
|
+
if (db && activeDbName && snapshotWriter) {
|
|
263
276
|
try {
|
|
264
277
|
const bytes = db.exportSnapshot();
|
|
265
278
|
await idbSaveSnapshot(activeDbName, bytes);
|
|
279
|
+
broadcastChannel?.postMessage('taladb:snapshot-ready');
|
|
266
280
|
} catch { /* best-effort — ignore failures */ }
|
|
267
281
|
}
|
|
268
282
|
}
|
|
@@ -299,11 +313,13 @@ function pushChangesetToPrimary() {
|
|
|
299
313
|
// Collect all collection names from the current in-memory state.
|
|
300
314
|
// exportChangeset accepts a JSON array of collection names.
|
|
301
315
|
const collections = db.listCollections();
|
|
302
|
-
|
|
316
|
+
// Wall-clock timestamps are not safe incremental cursors: a write can be
|
|
317
|
+
// stamped before an export but commit after its snapshot. Replay is
|
|
318
|
+
// idempotent under LWW and cannot skip such a write.
|
|
319
|
+
const changeset = db.exportChangeset(collections, 0);
|
|
303
320
|
// Only broadcast if there is actually something to send.
|
|
304
321
|
const parsed = JSON.parse(changeset);
|
|
305
322
|
if (parsed.length === 0) return;
|
|
306
|
-
lastSecondaryPushMs = Date.now();
|
|
307
323
|
broadcastChannel.postMessage({ type: 'taladb:secondary-write', token: SESSION_TOKEN, changeset });
|
|
308
324
|
log(`Broadcast ${parsed.length} change(s) to primary tab`);
|
|
309
325
|
} catch (err) {
|
|
@@ -322,7 +338,7 @@ function onWriteCommitted() {
|
|
|
322
338
|
pushChangesetToPrimary();
|
|
323
339
|
// Debounced IDB flush — keeps other tabs' fallback instances in sync via
|
|
324
340
|
// BroadcastChannel + snapshotDirty reload without writing to IDB on every op.
|
|
325
|
-
scheduleSnapshot();
|
|
341
|
+
if (snapshotWriter) scheduleSnapshot();
|
|
326
342
|
}
|
|
327
343
|
|
|
328
344
|
// ---------------------------------------------------------------------------
|
|
@@ -365,7 +381,7 @@ async function dispatch(op, args) {
|
|
|
365
381
|
}
|
|
366
382
|
|
|
367
383
|
if (op === 'init') {
|
|
368
|
-
const { dbName, configJson } = args;
|
|
384
|
+
const { dbName, configJson, passphrase } = args;
|
|
369
385
|
|
|
370
386
|
if (activeDbName !== null && activeDbName !== dbName) {
|
|
371
387
|
throw new Error(
|
|
@@ -377,7 +393,7 @@ async function dispatch(op, args) {
|
|
|
377
393
|
if (!initPromises.has(dbName)) {
|
|
378
394
|
activeDbName = dbName;
|
|
379
395
|
activeConfigJson = configJson ?? null;
|
|
380
|
-
initPromises.set(dbName, doInit(dbName, configJson ?? null));
|
|
396
|
+
initPromises.set(dbName, doInit(dbName, configJson ?? null, passphrase ?? null));
|
|
381
397
|
}
|
|
382
398
|
await initPromises.get(dbName);
|
|
383
399
|
return null;
|
|
@@ -431,6 +447,9 @@ async function dispatch(op, args) {
|
|
|
431
447
|
case 'count':
|
|
432
448
|
return db.count(args.collection, args.filterJson ?? 'null');
|
|
433
449
|
|
|
450
|
+
case 'aggregate':
|
|
451
|
+
return db.aggregate(args.collection, args.pipelineJson ?? '[]');
|
|
452
|
+
|
|
434
453
|
case 'createIndex':
|
|
435
454
|
db.createIndex(args.collection, args.field);
|
|
436
455
|
return null;
|
|
@@ -439,6 +458,14 @@ async function dispatch(op, args) {
|
|
|
439
458
|
db.dropIndex(args.collection, args.field);
|
|
440
459
|
return null;
|
|
441
460
|
|
|
461
|
+
case 'createCompoundIndex':
|
|
462
|
+
db.createCompoundIndex(args.collection, args.fieldsJson);
|
|
463
|
+
return null;
|
|
464
|
+
|
|
465
|
+
case 'dropCompoundIndex':
|
|
466
|
+
db.dropCompoundIndex(args.collection, args.fieldsJson);
|
|
467
|
+
return null;
|
|
468
|
+
|
|
442
469
|
case 'createFtsIndex':
|
|
443
470
|
db.createFtsIndex(args.collection, args.field);
|
|
444
471
|
return null;
|
|
@@ -487,6 +514,17 @@ async function dispatch(op, args) {
|
|
|
487
514
|
db.compact();
|
|
488
515
|
return null;
|
|
489
516
|
|
|
517
|
+
case 'syncStatus':
|
|
518
|
+
return db.syncStatus();
|
|
519
|
+
|
|
520
|
+
case 'flushSync': {
|
|
521
|
+
const deadline = Date.now() + (args.timeoutMs ?? 5000);
|
|
522
|
+
while (db.syncPending() > 0 && Date.now() < deadline) {
|
|
523
|
+
await new Promise(resolve => setTimeout(resolve, 20));
|
|
524
|
+
}
|
|
525
|
+
return db.syncPending() === 0;
|
|
526
|
+
}
|
|
527
|
+
|
|
490
528
|
case 'compactTombstones':
|
|
491
529
|
// Prune tombstones older than beforeMs from a collection.
|
|
492
530
|
// Returns the count of tombstones removed.
|
|
@@ -506,6 +544,13 @@ async function dispatch(op, args) {
|
|
|
506
544
|
}
|
|
507
545
|
|
|
508
546
|
case 'close':
|
|
547
|
+
// Give accepted HTTP push events a bounded opportunity to finish.
|
|
548
|
+
{
|
|
549
|
+
const deadline = Date.now() + 5000;
|
|
550
|
+
while (db.syncPending() > 0 && Date.now() < deadline) {
|
|
551
|
+
await new Promise(resolve => setTimeout(resolve, 20));
|
|
552
|
+
}
|
|
553
|
+
}
|
|
509
554
|
// Flush any pending debounced snapshot before releasing the lock so
|
|
510
555
|
// no writes are lost when the tab closes or navigates away.
|
|
511
556
|
await flushSnapshot();
|
|
@@ -514,6 +559,7 @@ async function dispatch(op, args) {
|
|
|
514
559
|
broadcastChannel?.close();
|
|
515
560
|
broadcastChannel = null;
|
|
516
561
|
idbFallback = false;
|
|
562
|
+
snapshotWriter = false;
|
|
517
563
|
db = null;
|
|
518
564
|
return null;
|
|
519
565
|
|
|
@@ -522,26 +568,58 @@ async function dispatch(op, args) {
|
|
|
522
568
|
}
|
|
523
569
|
}
|
|
524
570
|
|
|
571
|
+
/**
|
|
572
|
+
* Load the 16-byte key-derivation salt from an OPFS sidecar file, or create it
|
|
573
|
+
* on first open. The salt is not secret (it defends against precomputed-hash
|
|
574
|
+
* attacks) but must be stable across opens, so it lives beside the DB file.
|
|
575
|
+
* @returns {Promise<Uint8Array>} the 16-byte salt
|
|
576
|
+
*/
|
|
577
|
+
async function loadOrCreateSalt(root, saltFileName) {
|
|
578
|
+
const fh = await root.getFileHandle(saltFileName, { create: true });
|
|
579
|
+
const h = await fh.createSyncAccessHandle();
|
|
580
|
+
try {
|
|
581
|
+
const size = h.getSize();
|
|
582
|
+
if (size === 16) {
|
|
583
|
+
const salt = new Uint8Array(16);
|
|
584
|
+
h.read(salt, { at: 0 });
|
|
585
|
+
return salt;
|
|
586
|
+
}
|
|
587
|
+
if (size === 0) {
|
|
588
|
+
const salt = new Uint8Array(16);
|
|
589
|
+
self.crypto.getRandomValues(salt);
|
|
590
|
+
h.write(salt, { at: 0 });
|
|
591
|
+
h.flush();
|
|
592
|
+
return salt;
|
|
593
|
+
}
|
|
594
|
+
throw new Error(`invalid TalaDB salt file (${size} bytes, expected 16)`);
|
|
595
|
+
} finally {
|
|
596
|
+
h.close();
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
525
600
|
// ---------------------------------------------------------------------------
|
|
526
601
|
// Initialisation — load WASM, acquire lock, open OPFS file
|
|
527
602
|
// ---------------------------------------------------------------------------
|
|
528
603
|
|
|
529
|
-
async function doInit(dbName, configJson) {
|
|
604
|
+
async function doInit(dbName, configJson, passphrase = null) {
|
|
530
605
|
const wasm = await import(/* @vite-ignore */ '../pkg/taladb_web.js');
|
|
531
606
|
await wasm.default();
|
|
532
607
|
|
|
533
608
|
// Hoist to module scope so snapshot reloads in dispatch() can use it.
|
|
534
609
|
WorkerDB = wasm.WorkerDB;
|
|
535
610
|
|
|
611
|
+
encrypted = typeof passphrase === 'string' && passphrase.length > 0;
|
|
612
|
+
|
|
536
613
|
// Open the BroadcastChannel now that we know the db name.
|
|
537
614
|
if (typeof BroadcastChannel !== 'undefined') {
|
|
538
615
|
broadcastChannel = new BroadcastChannel(`taladb:${dbName}`);
|
|
539
616
|
broadcastChannel.onmessage = async (e) => {
|
|
540
617
|
if (e.data === 'taladb:changed' && idbFallback) {
|
|
541
|
-
//
|
|
542
|
-
|
|
543
|
-
} else if (e.data === 'taladb:request-snapshot' && !idbFallback && db && activeDbName) {
|
|
618
|
+
// Wait for snapshot-ready: changed is emitted before the primary's
|
|
619
|
+
// asynchronous IDB transaction has committed.
|
|
620
|
+
} else if (e.data === 'taladb:request-snapshot' && !idbFallback && !encrypted && db && activeDbName) {
|
|
544
621
|
// Primary (OPFS) tab: a new tab asked for a snapshot — export and save it.
|
|
622
|
+
// Never for encrypted DBs: an exported snapshot is decrypted plaintext.
|
|
545
623
|
try {
|
|
546
624
|
const bytes = db.exportSnapshot();
|
|
547
625
|
await idbSaveSnapshot(activeDbName, bytes);
|
|
@@ -553,8 +631,15 @@ async function doInit(dbName, configJson) {
|
|
|
553
631
|
const resolve = pendingSnapshotResolve;
|
|
554
632
|
pendingSnapshotResolve = null;
|
|
555
633
|
resolve();
|
|
556
|
-
} else if (e.data
|
|
557
|
-
|
|
634
|
+
} else if (e.data === 'taladb:snapshot-ready' && idbFallback) {
|
|
635
|
+
snapshotDirty = true;
|
|
636
|
+
} else if (e.data?.type === 'taladb:secondary-write' && typeof e.data.token === 'string' && e.data.token.length > 0 && db && !encrypted) {
|
|
637
|
+
// `!encrypted`: encrypted databases are single-tab, so there are no
|
|
638
|
+
// legitimate secondary-tab writes — accepting them would let any
|
|
639
|
+
// same-origin script inject documents into an encrypted DB without
|
|
640
|
+
// knowing the passphrase.
|
|
641
|
+
// Merge peer writes in every mode. This also makes multiple tabs
|
|
642
|
+
// converge when OPFS is entirely unavailable and every tab uses IDB.
|
|
558
643
|
// The token requirement rejects unauthenticated injection attempts that
|
|
559
644
|
// omit the SESSION_TOKEN field (not a guarantee against same-origin attackers
|
|
560
645
|
// who observe the token, but defence-in-depth against naive injection).
|
|
@@ -579,17 +664,27 @@ async function doInit(dbName, configJson) {
|
|
|
579
664
|
if (configJson) return WorkerDB.openWithConfigAndSnapshot(snapshot, configJson);
|
|
580
665
|
return WorkerDB.openWithSnapshot(snapshot);
|
|
581
666
|
}
|
|
667
|
+
// Salt for key derivation, loaded/created in an OPFS sidecar (encrypted mode
|
|
668
|
+
// only). Passed to the WASM open so the derived key is stable across opens.
|
|
669
|
+
let salt = null;
|
|
582
670
|
function openWithOpfs(syncHandle) {
|
|
583
|
-
|
|
584
|
-
return WorkerDB.
|
|
671
|
+
// openWithConfigAndOpfs(handle, configJson, passphrase?, salt?)
|
|
672
|
+
return WorkerDB.openWithConfigAndOpfs(syncHandle, configJson ?? null, passphrase, salt);
|
|
585
673
|
}
|
|
586
674
|
|
|
587
675
|
const opfsAvailable = await checkOpfs();
|
|
588
676
|
if (!opfsAvailable) {
|
|
677
|
+
if (encrypted) {
|
|
678
|
+
throw new Error(
|
|
679
|
+
'TalaDB encryption requires OPFS, which is unavailable in this browser context. ' +
|
|
680
|
+
'Refusing to open — the in-memory/IndexedDB fallback cannot encrypt at rest.'
|
|
681
|
+
);
|
|
682
|
+
}
|
|
589
683
|
warn('OPFS unavailable — falling back to IndexedDB-backed in-memory');
|
|
590
684
|
const snapshot = await idbLoadSnapshot(dbName);
|
|
591
685
|
db = openWithSnapshot(snapshot);
|
|
592
686
|
idbFallback = true;
|
|
687
|
+
snapshotWriter = true;
|
|
593
688
|
if (snapshot) {
|
|
594
689
|
log(`Restored from IndexedDB snapshot (${snapshot.byteLength} bytes)`);
|
|
595
690
|
} else {
|
|
@@ -602,11 +697,26 @@ async function doInit(dbName, configJson) {
|
|
|
602
697
|
const fileName = `taladb_${dbName.replaceAll(/[/\\:]/g, '_')}.redb`;
|
|
603
698
|
const fileHandle = await root.getFileHandle(fileName, { create: true });
|
|
604
699
|
|
|
700
|
+
// Encrypted mode: the 16-byte key-derivation salt lives in an OPFS sidecar
|
|
701
|
+
// file next to the DB. It is loaded/created only AFTER this tab has won the
|
|
702
|
+
// exclusive lock (or determined no locking applies), so two tabs racing to
|
|
703
|
+
// open never collide on the salt file's exclusive access handle.
|
|
704
|
+
|
|
605
705
|
if (!('locks' in navigator)) {
|
|
606
706
|
// Web Locks not available — open directly (single-tab safe only).
|
|
607
707
|
warn('Web Locks unavailable — multi-tab write safety disabled');
|
|
708
|
+
if (encrypted) salt = await loadOrCreateSalt(root, `${fileName}.salt`);
|
|
608
709
|
const syncHandle = await fileHandle.createSyncAccessHandle();
|
|
609
|
-
|
|
710
|
+
try {
|
|
711
|
+
db = openWithOpfs(syncHandle);
|
|
712
|
+
} catch (e) {
|
|
713
|
+
// A failed open (e.g. wrong passphrase) must release the exclusive OPFS
|
|
714
|
+
// access handle, or every retry fails with "Access Handles cannot be
|
|
715
|
+
// created" until the page reloads.
|
|
716
|
+
try { syncHandle.close(); } catch { /* best-effort */ }
|
|
717
|
+
throw e;
|
|
718
|
+
}
|
|
719
|
+
snapshotWriter = !encrypted; // encrypted DBs never write a plaintext IDB snapshot
|
|
610
720
|
log(`Opened "${fileName}" via OPFS`);
|
|
611
721
|
return;
|
|
612
722
|
}
|
|
@@ -621,7 +731,18 @@ async function doInit(dbName, configJson) {
|
|
|
621
731
|
await new Promise((resolve, reject) => {
|
|
622
732
|
navigator.locks.request(lockName, { ifAvailable: true }, async (lock) => {
|
|
623
733
|
if (lock === null) {
|
|
624
|
-
// Lock is held by another tab
|
|
734
|
+
// Lock is held by another tab.
|
|
735
|
+
if (encrypted) {
|
|
736
|
+
// The IDB-snapshot fallback stores decrypted plaintext, so it's
|
|
737
|
+
// refused for encrypted databases — they're single-tab. Reject
|
|
738
|
+
// rather than downgrade.
|
|
739
|
+
reject(new Error(
|
|
740
|
+
'This encrypted TalaDB database is already open in another tab. ' +
|
|
741
|
+
'Encrypted browser databases are single-tab (the multi-tab fallback would store plaintext).'
|
|
742
|
+
));
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
// Unencrypted: use IDB snapshot so this tab loads immediately.
|
|
625
746
|
warn('OPFS lock held by another tab — falling back to IndexedDB snapshot (live-sync via BroadcastChannel)');
|
|
626
747
|
let snapshot = await idbLoadSnapshot(dbName);
|
|
627
748
|
|
|
@@ -638,6 +759,7 @@ async function doInit(dbName, configJson) {
|
|
|
638
759
|
|
|
639
760
|
db = openWithSnapshot(snapshot ?? null);
|
|
640
761
|
idbFallback = true;
|
|
762
|
+
snapshotWriter = false;
|
|
641
763
|
if (snapshot) {
|
|
642
764
|
log(`Restored from IDB snapshot (${snapshot.byteLength} bytes)`);
|
|
643
765
|
} else {
|
|
@@ -648,9 +770,12 @@ async function doInit(dbName, configJson) {
|
|
|
648
770
|
}
|
|
649
771
|
|
|
650
772
|
// Acquired the lock — use OPFS.
|
|
773
|
+
let syncHandle = null;
|
|
651
774
|
try {
|
|
652
|
-
|
|
775
|
+
if (encrypted) salt = await loadOrCreateSalt(root, `${fileName}.salt`);
|
|
776
|
+
syncHandle = await fileHandle.createSyncAccessHandle();
|
|
653
777
|
db = openWithOpfs(syncHandle);
|
|
778
|
+
snapshotWriter = !encrypted; // encrypted DBs never write a plaintext IDB snapshot
|
|
654
779
|
log(`Opened "${fileName}" via OPFS (Web Locks)`);
|
|
655
780
|
resolve(); // signal doInit complete — caller can proceed
|
|
656
781
|
|
|
@@ -661,6 +786,13 @@ async function doInit(dbName, configJson) {
|
|
|
661
786
|
syncHandle.close();
|
|
662
787
|
db = null;
|
|
663
788
|
} catch (e) {
|
|
789
|
+
// A failed open (e.g. wrong passphrase) must release the exclusive
|
|
790
|
+
// OPFS access handle, or every retry fails with "Access Handles
|
|
791
|
+
// cannot be created" until the page reloads. Returning from this
|
|
792
|
+
// callback also releases the Web Lock.
|
|
793
|
+
if (syncHandle) {
|
|
794
|
+
try { syncHandle.close(); } catch { /* best-effort */ }
|
|
795
|
+
}
|
|
664
796
|
reject(e);
|
|
665
797
|
}
|
|
666
798
|
});
|