@hashtree/dexie 0.1.0 → 0.1.3
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/README.md +49 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -10
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/test-setup.d.ts +1 -0
- package/dist/test-setup.d.ts.map +1 -0
- package/package.json +18 -13
package/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# @hashtree/dexie
|
|
2
|
+
|
|
3
|
+
IndexedDB storage adapter for hashtree using Dexie.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @hashtree/dexie
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { DexieStore } from '@hashtree/dexie';
|
|
15
|
+
import { HashTree } from '@hashtree/core';
|
|
16
|
+
|
|
17
|
+
const store = new DexieStore('my-hashtree-db');
|
|
18
|
+
const tree = new HashTree({ store });
|
|
19
|
+
|
|
20
|
+
// Store persists to IndexedDB
|
|
21
|
+
await tree.putFile(data);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Features
|
|
25
|
+
|
|
26
|
+
- Persistent browser storage
|
|
27
|
+
- LRU eviction support
|
|
28
|
+
- Automatic schema migrations
|
|
29
|
+
|
|
30
|
+
## API
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
const store = new DexieStore(dbName?: string);
|
|
34
|
+
|
|
35
|
+
await store.get(hash);
|
|
36
|
+
await store.put(hash, data);
|
|
37
|
+
await store.has(hash);
|
|
38
|
+
await store.delete(hash);
|
|
39
|
+
await store.keys();
|
|
40
|
+
await store.clear();
|
|
41
|
+
await store.count();
|
|
42
|
+
await store.totalBytes();
|
|
43
|
+
await store.evict(maxBytes);
|
|
44
|
+
store.close();
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## License
|
|
48
|
+
|
|
49
|
+
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export declare class DexieStore implements Store {
|
|
|
24
24
|
count(): Promise<number>;
|
|
25
25
|
/**
|
|
26
26
|
* Get total bytes stored
|
|
27
|
+
* Uses cursor to avoid loading all blobs into memory at once
|
|
27
28
|
*/
|
|
28
29
|
totalBytes(): Promise<number>;
|
|
29
30
|
/**
|
|
@@ -40,3 +41,4 @@ export declare class DexieStore implements Store {
|
|
|
40
41
|
*/
|
|
41
42
|
static deleteDatabase(dbName?: string): Promise<void>;
|
|
42
43
|
}
|
|
44
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAkClD;;;GAGG;AACH,qBAAa,UAAW,YAAW,KAAK;IACtC,OAAO,CAAC,EAAE,CAAa;gBAEX,MAAM,GAAE,MAAmB;IAIjC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC;IAYnD,GAAG,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAyB3C,GAAG,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC;IAYjC,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC;IAe1C;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;IAW7B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAS9B;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAanC;;;OAGG;IACG,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA4B9C;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;WACU,cAAc,CAAC,MAAM,GAAE,MAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;CAGxE"}
|
package/dist/index.js
CHANGED
|
@@ -36,7 +36,8 @@ export class DexieStore {
|
|
|
36
36
|
async put(hash, data) {
|
|
37
37
|
const hashHex = toHex(hash);
|
|
38
38
|
try {
|
|
39
|
-
|
|
39
|
+
// Store directly - IDB will clone the data internally
|
|
40
|
+
await this.db.blobs.put({ hashHex, data, lastAccess: Date.now() });
|
|
40
41
|
return true;
|
|
41
42
|
}
|
|
42
43
|
catch (e) {
|
|
@@ -55,9 +56,13 @@ export class DexieStore {
|
|
|
55
56
|
// Update lastAccess timestamp for LRU tracking (fire-and-forget)
|
|
56
57
|
// We need to re-put the entry to avoid fake-indexeddb corruption issues with partial updates
|
|
57
58
|
this.db.blobs.put({ ...entry, lastAccess: Date.now() }).catch(() => { });
|
|
58
|
-
//
|
|
59
|
-
//
|
|
59
|
+
// Return directly - IDB returns a fresh copy already
|
|
60
|
+
// Only slice if the view doesn't match the buffer (rare edge case)
|
|
60
61
|
const data = entry.data;
|
|
62
|
+
if (data.byteOffset === 0 && data.byteLength === data.buffer.byteLength) {
|
|
63
|
+
return data;
|
|
64
|
+
}
|
|
65
|
+
// Rare: view is a subset of a larger buffer, need to copy
|
|
61
66
|
return new Uint8Array(data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength));
|
|
62
67
|
}
|
|
63
68
|
catch (e) {
|
|
@@ -68,8 +73,9 @@ export class DexieStore {
|
|
|
68
73
|
async has(hash) {
|
|
69
74
|
const hashHex = toHex(hash);
|
|
70
75
|
try {
|
|
71
|
-
|
|
72
|
-
|
|
76
|
+
// Use count with where clause - doesn't load the blob data
|
|
77
|
+
const count = await this.db.blobs.where('hashHex').equals(hashHex).count();
|
|
78
|
+
return count > 0;
|
|
73
79
|
}
|
|
74
80
|
catch (e) {
|
|
75
81
|
console.error('[DexieStore] has error:', e);
|
|
@@ -96,8 +102,9 @@ export class DexieStore {
|
|
|
96
102
|
*/
|
|
97
103
|
async keys() {
|
|
98
104
|
try {
|
|
99
|
-
|
|
100
|
-
|
|
105
|
+
// Only fetch the primary keys, not the blob data
|
|
106
|
+
const hashHexes = await this.db.blobs.toCollection().primaryKeys();
|
|
107
|
+
return hashHexes.map(hex => fromHex(hex));
|
|
101
108
|
}
|
|
102
109
|
catch (e) {
|
|
103
110
|
console.error('[DexieStore] keys error:', e);
|
|
@@ -129,12 +136,13 @@ export class DexieStore {
|
|
|
129
136
|
}
|
|
130
137
|
/**
|
|
131
138
|
* Get total bytes stored
|
|
139
|
+
* Uses cursor to avoid loading all blobs into memory at once
|
|
132
140
|
*/
|
|
133
141
|
async totalBytes() {
|
|
134
142
|
try {
|
|
135
143
|
let total = 0;
|
|
136
|
-
await this.db.blobs.each(
|
|
137
|
-
total +=
|
|
144
|
+
await this.db.blobs.each(entry => {
|
|
145
|
+
total += entry.data.byteLength;
|
|
138
146
|
});
|
|
139
147
|
return total;
|
|
140
148
|
}
|
|
@@ -161,7 +169,7 @@ export class DexieStore {
|
|
|
161
169
|
if (bytesRemoved >= targetRemoval)
|
|
162
170
|
break;
|
|
163
171
|
await this.db.blobs.delete(entry.hashHex);
|
|
164
|
-
bytesRemoved += entry.data.
|
|
172
|
+
bytesRemoved += entry.data.byteLength;
|
|
165
173
|
entriesRemoved++;
|
|
166
174
|
}
|
|
167
175
|
console.log(`[DexieStore] Evicted ${entriesRemoved} entries (${bytesRemoved} bytes)`);
|
package/dist/index.test.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""}
|
package/dist/test-setup.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-setup.d.ts","sourceRoot":"","sources":["../src/test-setup.ts"],"names":[],"mappings":"AACA,OAAO,qBAAqB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hashtree/dexie",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"license": "MIT",
|
|
5
|
-
"publishConfig": {
|
|
6
|
-
"access": "public"
|
|
7
|
-
},
|
|
3
|
+
"version": "0.1.3",
|
|
8
4
|
"description": "Dexie-based IndexedDB store for hashtree",
|
|
9
5
|
"type": "module",
|
|
10
6
|
"main": "dist/index.js",
|
|
@@ -18,19 +14,28 @@
|
|
|
18
14
|
"files": [
|
|
19
15
|
"dist"
|
|
20
16
|
],
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"hashtree",
|
|
22
|
+
"dexie",
|
|
23
|
+
"indexeddb",
|
|
24
|
+
"storage"
|
|
25
|
+
],
|
|
26
|
+
"author": "Martti Malmi",
|
|
27
|
+
"license": "MIT",
|
|
21
28
|
"dependencies": {
|
|
22
|
-
"dexie": "^4.
|
|
23
|
-
"@hashtree/core": "0.1.
|
|
29
|
+
"dexie": "^4.2.1",
|
|
30
|
+
"@hashtree/core": "0.1.3"
|
|
24
31
|
},
|
|
25
32
|
"devDependencies": {
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"typescript": "^5.8.3",
|
|
29
|
-
"vitest": "^2.1.8"
|
|
33
|
+
"typescript": "^5.3.0",
|
|
34
|
+
"vitest": "^2.0.0"
|
|
30
35
|
},
|
|
31
36
|
"scripts": {
|
|
32
37
|
"build": "tsc",
|
|
33
|
-
"
|
|
34
|
-
"test": "vitest
|
|
38
|
+
"test": "vitest run",
|
|
39
|
+
"test:watch": "vitest"
|
|
35
40
|
}
|
|
36
41
|
}
|