@nkzw/fate-indexeddb 1.5.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -7
- package/lib/index.d.mts +4 -3
- package/lib/index.mjs +16 -27
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1354,13 +1354,13 @@ Then pass `persistence` when creating the client:
|
|
|
1354
1354
|
|
|
1355
1355
|
```tsx
|
|
1356
1356
|
import { createPersistence } from '@nkzw/fate/persistence';
|
|
1357
|
-
import {
|
|
1357
|
+
import { createIndexedDBStorage } from '@nkzw/fate-indexeddb';
|
|
1358
1358
|
import { createFateClient } from 'react-fate/client';
|
|
1359
1359
|
|
|
1360
1360
|
const fate = createFateClient({
|
|
1361
1361
|
persistence: createPersistence({
|
|
1362
1362
|
key: `workspace:${workspaceId}:user:${userId}`,
|
|
1363
|
-
storage:
|
|
1363
|
+
storage: createIndexedDBStorage(),
|
|
1364
1364
|
}),
|
|
1365
1365
|
url: '/api/fate',
|
|
1366
1366
|
});
|
|
@@ -1373,7 +1373,7 @@ persistence: createPersistence({
|
|
|
1373
1373
|
key: `workspace:${workspaceId}:user:${userId}`,
|
|
1374
1374
|
maxAge: 24 * 60 * 60 * 1000,
|
|
1375
1375
|
maxBytes: 25 * 1024 * 1024,
|
|
1376
|
-
storage:
|
|
1376
|
+
storage: createIndexedDBStorage(),
|
|
1377
1377
|
}),
|
|
1378
1378
|
```
|
|
1379
1379
|
|
|
@@ -1545,7 +1545,7 @@ const durableHTTP = createHTTPTransport<MyAPI>({
|
|
|
1545
1545
|
|
|
1546
1546
|
const fate = createFateClient({
|
|
1547
1547
|
// ...your generated tRPC or GraphQL client options...
|
|
1548
|
-
persistence: createPersistence({ key: accountKey, storage:
|
|
1548
|
+
persistence: createPersistence({ key: accountKey, storage: createIndexedDBStorage() }),
|
|
1549
1549
|
mutateDurably: durableHTTP.mutateDurably,
|
|
1550
1550
|
});
|
|
1551
1551
|
```
|
|
@@ -1635,7 +1635,6 @@ The core persistence layer has no IndexedDB dependency. You can use another back
|
|
|
1635
1635
|
```ts
|
|
1636
1636
|
interface PersistenceStorage {
|
|
1637
1637
|
read(key: string): Promise<unknown>;
|
|
1638
|
-
write(key: string, value: unknown): Promise<void>;
|
|
1639
1638
|
scan(
|
|
1640
1639
|
prefix: string,
|
|
1641
1640
|
after?: string,
|
|
@@ -1650,9 +1649,8 @@ interface PersistenceStorage {
|
|
|
1650
1649
|
Values use fate's hydration codec and can be stored as JSON. The adapter handles storage and coordination:
|
|
1651
1650
|
|
|
1652
1651
|
- `read` returns the saved value for a key.
|
|
1653
|
-
- `write` replaces one value atomically and resolves after it has committed.
|
|
1654
1652
|
- `scan` returns keys under a prefix in ascending order, strictly after the optional cursor, up to the limit (64 by default). Use your backend's ordered index to keep each scan small.
|
|
1655
|
-
- `writeBatch` commits all entries atomically. An `undefined` value deletes the key.
|
|
1653
|
+
- `writeBatch` commits all entries atomically and resolves after they have committed. An `undefined` value deletes the key. Use a one-entry batch for a single write.
|
|
1656
1654
|
- `exclusive` coordinates every tab or process sharing the backend. Different lock names are independent: fate holds a delivery lock during network work and acquires a separate write lock when updating storage. Your adapter must allow that nesting.
|
|
1657
1655
|
- `subscribe` notifies other clients after a change commits, including keys changed by `writeBatch`. Without notifications, clients check saved mutations during delivery attempts and explicit `retry()` calls.
|
|
1658
1656
|
|
package/lib/index.d.mts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { PersistenceStorage } from "@nkzw/fate/persistence";
|
|
2
2
|
//#region src/index.d.ts
|
|
3
|
-
|
|
3
|
+
type IndexedDBStorageOptions = Readonly<{
|
|
4
4
|
name?: string;
|
|
5
|
-
}
|
|
5
|
+
}>;
|
|
6
|
+
declare function createIndexedDBStorage({ name }?: IndexedDBStorageOptions): PersistenceStorage;
|
|
6
7
|
//#endregion
|
|
7
|
-
export {
|
|
8
|
+
export { IndexedDBStorageOptions, createIndexedDBStorage };
|
package/lib/index.mjs
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import { openDB } from "idb";
|
|
2
2
|
//#region src/index.ts
|
|
3
|
-
function
|
|
4
|
-
let
|
|
3
|
+
function createIndexedDBStorage({ name = "fate" } = {}) {
|
|
4
|
+
let connectionLeases = 0;
|
|
5
5
|
let connection;
|
|
6
|
-
const
|
|
7
|
-
if (--
|
|
6
|
+
const releaseDatabase = () => {
|
|
7
|
+
if (--connectionLeases === 0) {
|
|
8
8
|
const previous = connection;
|
|
9
9
|
connection = void 0;
|
|
10
10
|
previous?.then((db) => db.close(), () => {});
|
|
11
11
|
}
|
|
12
12
|
};
|
|
13
|
-
const
|
|
14
|
-
|
|
13
|
+
const acquireDatabase = async () => {
|
|
14
|
+
connectionLeases++;
|
|
15
15
|
try {
|
|
16
16
|
return await (connection ??= openDB(name, 1, { upgrade(db) {
|
|
17
17
|
db.createObjectStore("fate");
|
|
18
18
|
} }));
|
|
19
19
|
} catch (error) {
|
|
20
|
-
|
|
20
|
+
releaseDatabase();
|
|
21
21
|
throw error;
|
|
22
22
|
}
|
|
23
23
|
};
|
|
@@ -43,24 +43,24 @@ function indexedDB({ name = "fate" } = {}) {
|
|
|
43
43
|
exclusive(key, run) {
|
|
44
44
|
if (typeof navigator === "undefined" || !navigator.locks) throw new Error("fate(indexeddb): Web Locks are required for safe durable writes across tabs.");
|
|
45
45
|
return navigator.locks.request(`fate:${JSON.stringify([name, key])}`, async () => {
|
|
46
|
-
|
|
46
|
+
connectionLeases++;
|
|
47
47
|
try {
|
|
48
48
|
return await run();
|
|
49
49
|
} finally {
|
|
50
|
-
|
|
50
|
+
releaseDatabase();
|
|
51
51
|
}
|
|
52
52
|
});
|
|
53
53
|
},
|
|
54
54
|
async read(key) {
|
|
55
|
-
const db = await
|
|
55
|
+
const db = await acquireDatabase();
|
|
56
56
|
try {
|
|
57
57
|
return await db.get("fate", key);
|
|
58
58
|
} finally {
|
|
59
|
-
|
|
59
|
+
releaseDatabase();
|
|
60
60
|
}
|
|
61
61
|
},
|
|
62
62
|
async scan(prefix, after, limit = 64) {
|
|
63
|
-
const db = await
|
|
63
|
+
const db = await acquireDatabase();
|
|
64
64
|
try {
|
|
65
65
|
const range = IDBKeyRange.lowerBound(after !== void 0 && after >= prefix ? after : prefix, after !== void 0 && after >= prefix);
|
|
66
66
|
const transaction = db.transaction("fate");
|
|
@@ -76,7 +76,7 @@ function indexedDB({ name = "fate" } = {}) {
|
|
|
76
76
|
await transaction.done;
|
|
77
77
|
return entries;
|
|
78
78
|
} finally {
|
|
79
|
-
|
|
79
|
+
releaseDatabase();
|
|
80
80
|
}
|
|
81
81
|
},
|
|
82
82
|
subscribe(key, listener) {
|
|
@@ -101,19 +101,8 @@ function indexedDB({ name = "fate" } = {}) {
|
|
|
101
101
|
}
|
|
102
102
|
};
|
|
103
103
|
},
|
|
104
|
-
async write(key, value) {
|
|
105
|
-
const db = await database();
|
|
106
|
-
try {
|
|
107
|
-
const transaction = db.transaction("fate", "readwrite");
|
|
108
|
-
await transaction.store.put(value, key);
|
|
109
|
-
await transaction.done;
|
|
110
|
-
} finally {
|
|
111
|
-
release();
|
|
112
|
-
}
|
|
113
|
-
broadcast([key]);
|
|
114
|
-
},
|
|
115
104
|
async writeBatch(entries) {
|
|
116
|
-
const db = await
|
|
105
|
+
const db = await acquireDatabase();
|
|
117
106
|
try {
|
|
118
107
|
const transaction = db.transaction("fate", "readwrite");
|
|
119
108
|
try {
|
|
@@ -127,11 +116,11 @@ function indexedDB({ name = "fate" } = {}) {
|
|
|
127
116
|
throw error;
|
|
128
117
|
}
|
|
129
118
|
} finally {
|
|
130
|
-
|
|
119
|
+
releaseDatabase();
|
|
131
120
|
}
|
|
132
121
|
broadcast([...new Set(entries.map(([key]) => key))]);
|
|
133
122
|
}
|
|
134
123
|
};
|
|
135
124
|
}
|
|
136
125
|
//#endregion
|
|
137
|
-
export {
|
|
126
|
+
export { createIndexedDBStorage };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nkzw/fate-indexeddb",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "Optional IndexedDB persistence adapter for fate.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
"fake-indexeddb": "^6.2.4",
|
|
23
23
|
"vite": "npm:@voidzero-dev/vite-plus-core@0.3.0",
|
|
24
24
|
"vite-plus": "0.3.0",
|
|
25
|
-
"@nkzw/fate": "1.5.
|
|
25
|
+
"@nkzw/fate": "1.5.1"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
|
-
"@nkzw/fate": "^1.
|
|
28
|
+
"@nkzw/fate": "^1.5.1"
|
|
29
29
|
},
|
|
30
30
|
"scripts": {
|
|
31
31
|
"build": "vp pack --tsconfig tsconfig.json -d lib src/index.ts"
|