tinybase 6.4.1 → 6.5.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/@types/omni/index.d.ts +1 -0
- package/@types/omni/with-schemas/index.d.ts +1 -0
- package/@types/persisters/index.d.ts +1 -0
- package/@types/persisters/persister-react-native-mmkv/index.d.ts +118 -0
- package/@types/persisters/persister-react-native-mmkv/with-schemas/index.d.ts +132 -0
- package/@types/persisters/with-schemas/index.d.ts +1 -0
- package/min/omni/index.js +1 -1
- package/min/omni/index.js.gz +0 -0
- package/min/omni/with-schemas/index.js +1 -1
- package/min/omni/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-react-native-mmkv/index.js +1 -0
- package/min/persisters/persister-react-native-mmkv/index.js.gz +0 -0
- package/min/persisters/persister-react-native-mmkv/with-schemas/index.js +1 -0
- package/min/persisters/persister-react-native-mmkv/with-schemas/index.js.gz +0 -0
- package/omni/index.js +47 -3
- package/omni/with-schemas/index.js +47 -3
- package/package.json +44 -1
- package/persisters/persister-react-native-mmkv/index.js +459 -0
- package/persisters/persister-react-native-mmkv/with-schemas/index.js +459 -0
- package/readme.md +2 -2
|
@@ -4514,7 +4514,7 @@ const createAutomergePersister = (
|
|
|
4514
4514
|
);
|
|
4515
4515
|
};
|
|
4516
4516
|
|
|
4517
|
-
const STORAGE = 'storage';
|
|
4517
|
+
const STORAGE$1 = 'storage';
|
|
4518
4518
|
const createStoragePersister = (
|
|
4519
4519
|
store,
|
|
4520
4520
|
storageName,
|
|
@@ -4534,11 +4534,11 @@ const createStoragePersister = (
|
|
|
4534
4534
|
);
|
|
4535
4535
|
}
|
|
4536
4536
|
};
|
|
4537
|
-
WINDOW.addEventListener(STORAGE, storageListener);
|
|
4537
|
+
WINDOW.addEventListener(STORAGE$1, storageListener);
|
|
4538
4538
|
return storageListener;
|
|
4539
4539
|
};
|
|
4540
4540
|
const delPersisterListener = (storageListener) =>
|
|
4541
|
-
WINDOW.removeEventListener(STORAGE, storageListener);
|
|
4541
|
+
WINDOW.removeEventListener(STORAGE$1, storageListener);
|
|
4542
4542
|
return createCustomPersister(
|
|
4543
4543
|
store,
|
|
4544
4544
|
getPersisted,
|
|
@@ -5360,6 +5360,49 @@ const viewUpsert = async (
|
|
|
5360
5360
|
);
|
|
5361
5361
|
};
|
|
5362
5362
|
|
|
5363
|
+
const STORAGE = 'storage';
|
|
5364
|
+
const createReactNativeMmkvPersister = (
|
|
5365
|
+
store,
|
|
5366
|
+
storage,
|
|
5367
|
+
storageName = STORAGE,
|
|
5368
|
+
onIgnoredError,
|
|
5369
|
+
) => {
|
|
5370
|
+
const getPersisted = async () => {
|
|
5371
|
+
const data = storage.getString(storageName);
|
|
5372
|
+
const value = data === void 0 ? void 0 : JSON.parse(data);
|
|
5373
|
+
return Promise.resolve(value);
|
|
5374
|
+
};
|
|
5375
|
+
const setPersisted = async (getContent) => {
|
|
5376
|
+
const content = getContent();
|
|
5377
|
+
if (content !== void 0) {
|
|
5378
|
+
storage.set(storageName, JSON.stringify(content));
|
|
5379
|
+
}
|
|
5380
|
+
};
|
|
5381
|
+
const addPersisterListener = (listener) =>
|
|
5382
|
+
storage.addOnValueChangedListener((key) => {
|
|
5383
|
+
if (key === storageName) {
|
|
5384
|
+
const value = storage.getString(storageName);
|
|
5385
|
+
if (value) {
|
|
5386
|
+
listener(JSON.parse(value));
|
|
5387
|
+
}
|
|
5388
|
+
}
|
|
5389
|
+
});
|
|
5390
|
+
const delPersisterListener = (storageListener) => {
|
|
5391
|
+
storageListener.remove();
|
|
5392
|
+
};
|
|
5393
|
+
return createCustomPersister(
|
|
5394
|
+
store,
|
|
5395
|
+
getPersisted,
|
|
5396
|
+
setPersisted,
|
|
5397
|
+
addPersisterListener,
|
|
5398
|
+
delPersisterListener,
|
|
5399
|
+
onIgnoredError,
|
|
5400
|
+
3,
|
|
5401
|
+
// StoreOrMergeableStore
|
|
5402
|
+
{getStorageName: () => storageName},
|
|
5403
|
+
);
|
|
5404
|
+
};
|
|
5405
|
+
|
|
5363
5406
|
const createReactNativeSqlitePersister = (
|
|
5364
5407
|
store,
|
|
5365
5408
|
db,
|
|
@@ -10454,6 +10497,7 @@ export {
|
|
|
10454
10497
|
createPostgresPersister,
|
|
10455
10498
|
createPowerSyncPersister,
|
|
10456
10499
|
createQueries,
|
|
10500
|
+
createReactNativeMmkvPersister,
|
|
10457
10501
|
createReactNativeSqlitePersister,
|
|
10458
10502
|
createRelationships,
|
|
10459
10503
|
createRemotePersister,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tinybase",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.5.0",
|
|
4
4
|
"author": "jamesgpearce",
|
|
5
5
|
"repository": "github:tinyplex/tinybase",
|
|
6
6
|
"license": "MIT",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"postgres": "^3.4.7",
|
|
38
38
|
"react": "^19.0.0",
|
|
39
39
|
"react-dom": "^19.0.0",
|
|
40
|
+
"react-native-mmkv": "3.3.0",
|
|
40
41
|
"react-native-sqlite-storage": "^6.0.1",
|
|
41
42
|
"sqlite3": "^5.1.7",
|
|
42
43
|
"ws": "^8.18.3",
|
|
@@ -91,6 +92,12 @@
|
|
|
91
92
|
"react-dom": {
|
|
92
93
|
"optional": true
|
|
93
94
|
},
|
|
95
|
+
"react-native-sqlite-storage": {
|
|
96
|
+
"optional": true
|
|
97
|
+
},
|
|
98
|
+
"react-native-mmkv": {
|
|
99
|
+
"optional": true
|
|
100
|
+
},
|
|
94
101
|
"sqlite3": {
|
|
95
102
|
"optional": true
|
|
96
103
|
},
|
|
@@ -243,6 +250,12 @@
|
|
|
243
250
|
"persisters/persister-powersync/with-schemas": [
|
|
244
251
|
"./@types/persisters/persister-powersync/with-schemas/index.d.ts"
|
|
245
252
|
],
|
|
253
|
+
"persisters/persister-react-native-mmkv": [
|
|
254
|
+
"./@types/persisters/persister-react-native-mmkv/index.d.ts"
|
|
255
|
+
],
|
|
256
|
+
"persisters/persister-react-native-mmkv/with-schemas": [
|
|
257
|
+
"./@types/persisters/persister-react-native-mmkv/with-schemas/index.d.ts"
|
|
258
|
+
],
|
|
246
259
|
"persisters/persister-react-native-sqlite": [
|
|
247
260
|
"./@types/persisters/persister-react-native-sqlite/index.d.ts"
|
|
248
261
|
],
|
|
@@ -495,6 +508,12 @@
|
|
|
495
508
|
"min/persisters/persister-powersync/with-schemas": [
|
|
496
509
|
"./@types/persisters/persister-powersync/with-schemas/index.d.ts"
|
|
497
510
|
],
|
|
511
|
+
"min/persisters/persister-react-native-mmkv": [
|
|
512
|
+
"./@types/persisters/persister-react-native-mmkv/index.d.ts"
|
|
513
|
+
],
|
|
514
|
+
"min/persisters/persister-react-native-mmkv/with-schemas": [
|
|
515
|
+
"./@types/persisters/persister-react-native-mmkv/with-schemas/index.d.ts"
|
|
516
|
+
],
|
|
498
517
|
"min/persisters/persister-react-native-sqlite": [
|
|
499
518
|
"./@types/persisters/persister-react-native-sqlite/index.d.ts"
|
|
500
519
|
],
|
|
@@ -888,6 +907,18 @@
|
|
|
888
907
|
"default": "./persisters/persister-powersync/index.js"
|
|
889
908
|
}
|
|
890
909
|
},
|
|
910
|
+
"./persisters/persister-react-native-mmkv": {
|
|
911
|
+
"default": {
|
|
912
|
+
"types": "./@types/persisters/persister-react-native-mmkv/index.d.ts",
|
|
913
|
+
"default": "./persisters/persister-react-native-mmkv/index.js"
|
|
914
|
+
}
|
|
915
|
+
},
|
|
916
|
+
"./persisters/persister-react-native-mmkv/with-schemas": {
|
|
917
|
+
"default": {
|
|
918
|
+
"types": "./@types/persisters/persister-react-native-mmkv/with-schemas/index.d.ts",
|
|
919
|
+
"default": "./persisters/persister-react-native-mmkv/index.js"
|
|
920
|
+
}
|
|
921
|
+
},
|
|
891
922
|
"./persisters/persister-react-native-sqlite": {
|
|
892
923
|
"default": {
|
|
893
924
|
"types": "./@types/persisters/persister-react-native-sqlite/index.d.ts",
|
|
@@ -1392,6 +1423,18 @@
|
|
|
1392
1423
|
"default": "./min/persisters/persister-powersync/index.js"
|
|
1393
1424
|
}
|
|
1394
1425
|
},
|
|
1426
|
+
"./min/persisters/persister-react-native-mmkv": {
|
|
1427
|
+
"default": {
|
|
1428
|
+
"types": "./@types/persisters/persister-react-native-mmkv/index.d.ts",
|
|
1429
|
+
"default": "./min/persisters/persister-react-native-mmkv/index.js"
|
|
1430
|
+
}
|
|
1431
|
+
},
|
|
1432
|
+
"./min/persisters/persister-react-native-mmkv/with-schemas": {
|
|
1433
|
+
"default": {
|
|
1434
|
+
"types": "./@types/persisters/persister-react-native-mmkv/with-schemas/index.d.ts",
|
|
1435
|
+
"default": "./min/persisters/persister-react-native-mmkv/index.js"
|
|
1436
|
+
}
|
|
1437
|
+
},
|
|
1395
1438
|
"./min/persisters/persister-react-native-sqlite": {
|
|
1396
1439
|
"default": {
|
|
1397
1440
|
"types": "./@types/persisters/persister-react-native-sqlite/index.d.ts",
|
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
const EMPTY_STRING = '';
|
|
2
|
+
|
|
3
|
+
const isUndefined = (thing) => thing == void 0;
|
|
4
|
+
const ifNotUndefined = (value, then, otherwise) =>
|
|
5
|
+
isUndefined(value) ? otherwise?.() : then(value);
|
|
6
|
+
const isArray = (thing) => Array.isArray(thing);
|
|
7
|
+
const size = (arrayOrString) => arrayOrString.length;
|
|
8
|
+
const test = (regex, subject) => regex.test(subject);
|
|
9
|
+
const errorNew = (message) => {
|
|
10
|
+
throw new Error(message);
|
|
11
|
+
};
|
|
12
|
+
const tryCatch = async (action, then1, then2) => {
|
|
13
|
+
try {
|
|
14
|
+
return await action();
|
|
15
|
+
} catch (error) {
|
|
16
|
+
/* istanbul ignore next */
|
|
17
|
+
then1?.(error);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const arrayForEach = (array, cb) => array.forEach(cb);
|
|
22
|
+
const arrayClear = (array, to) => array.splice(0, to);
|
|
23
|
+
const arrayPush = (array, ...values) => array.push(...values);
|
|
24
|
+
const arrayShift = (array) => array.shift();
|
|
25
|
+
|
|
26
|
+
const collSize = (coll) => coll?.size ?? 0;
|
|
27
|
+
const collHas = (coll, keyOrValue) => coll?.has(keyOrValue) ?? false;
|
|
28
|
+
const collIsEmpty = (coll) => isUndefined(coll) || collSize(coll) == 0;
|
|
29
|
+
const collForEach = (coll, cb) => coll?.forEach(cb);
|
|
30
|
+
const collDel = (coll, keyOrValue) => coll?.delete(keyOrValue);
|
|
31
|
+
|
|
32
|
+
const object = Object;
|
|
33
|
+
const getPrototypeOf = (obj) => object.getPrototypeOf(obj);
|
|
34
|
+
const isObject = (obj) =>
|
|
35
|
+
!isUndefined(obj) &&
|
|
36
|
+
ifNotUndefined(
|
|
37
|
+
getPrototypeOf(obj),
|
|
38
|
+
(objPrototype) =>
|
|
39
|
+
objPrototype == object.prototype ||
|
|
40
|
+
isUndefined(getPrototypeOf(objPrototype)),
|
|
41
|
+
|
|
42
|
+
/* istanbul ignore next */
|
|
43
|
+
() => true,
|
|
44
|
+
);
|
|
45
|
+
const objIds = object.keys;
|
|
46
|
+
const objFreeze = object.freeze;
|
|
47
|
+
const objSize = (obj) => size(objIds(obj));
|
|
48
|
+
const objIsEmpty = (obj) => isObject(obj) && objSize(obj) == 0;
|
|
49
|
+
|
|
50
|
+
const mapNew = (entries) => new Map(entries);
|
|
51
|
+
const mapGet = (map, key) => map?.get(key);
|
|
52
|
+
const mapSet = (map, key, value) =>
|
|
53
|
+
isUndefined(value) ? (collDel(map, key), map) : map?.set(key, value);
|
|
54
|
+
const mapEnsure = (map, key, getDefaultValue, hadExistingValue) => {
|
|
55
|
+
if (!collHas(map, key)) {
|
|
56
|
+
mapSet(map, key, getDefaultValue());
|
|
57
|
+
} else {
|
|
58
|
+
hadExistingValue?.(mapGet(map, key));
|
|
59
|
+
}
|
|
60
|
+
return mapGet(map, key);
|
|
61
|
+
};
|
|
62
|
+
const visitTree = (node, path, ensureLeaf, pruneLeaf, p = 0) =>
|
|
63
|
+
ifNotUndefined(
|
|
64
|
+
(ensureLeaf ? mapEnsure : mapGet)(
|
|
65
|
+
node,
|
|
66
|
+
path[p],
|
|
67
|
+
p > size(path) - 2 ? ensureLeaf : mapNew,
|
|
68
|
+
),
|
|
69
|
+
(nodeOrLeaf) => {
|
|
70
|
+
if (p > size(path) - 2) {
|
|
71
|
+
if (pruneLeaf?.(nodeOrLeaf)) {
|
|
72
|
+
mapSet(node, path[p]);
|
|
73
|
+
}
|
|
74
|
+
return nodeOrLeaf;
|
|
75
|
+
}
|
|
76
|
+
const leaf = visitTree(nodeOrLeaf, path, ensureLeaf, pruneLeaf, p + 1);
|
|
77
|
+
if (collIsEmpty(nodeOrLeaf)) {
|
|
78
|
+
mapSet(node, path[p]);
|
|
79
|
+
}
|
|
80
|
+
return leaf;
|
|
81
|
+
},
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const INTEGER = /^\d+$/;
|
|
85
|
+
const getPoolFunctions = () => {
|
|
86
|
+
const pool = [];
|
|
87
|
+
let nextId = 0;
|
|
88
|
+
return [
|
|
89
|
+
(reuse) => (reuse ? arrayShift(pool) : null) ?? EMPTY_STRING + nextId++,
|
|
90
|
+
(id) => {
|
|
91
|
+
if (test(INTEGER, id) && size(pool) < 1e3) {
|
|
92
|
+
arrayPush(pool, id);
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
];
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const setNew = (entryOrEntries) =>
|
|
99
|
+
new Set(
|
|
100
|
+
isArray(entryOrEntries) || isUndefined(entryOrEntries)
|
|
101
|
+
? entryOrEntries
|
|
102
|
+
: [entryOrEntries],
|
|
103
|
+
);
|
|
104
|
+
const setAdd = (set, value) => set?.add(value);
|
|
105
|
+
|
|
106
|
+
const getWildcardedLeaves = (deepIdSet, path = [EMPTY_STRING]) => {
|
|
107
|
+
const leaves = [];
|
|
108
|
+
const deep = (node, p) =>
|
|
109
|
+
p == size(path)
|
|
110
|
+
? arrayPush(leaves, node)
|
|
111
|
+
: path[p] === null
|
|
112
|
+
? collForEach(node, (node2) => deep(node2, p + 1))
|
|
113
|
+
: arrayForEach([path[p], null], (id) => deep(mapGet(node, id), p + 1));
|
|
114
|
+
deep(deepIdSet, 0);
|
|
115
|
+
return leaves;
|
|
116
|
+
};
|
|
117
|
+
const getListenerFunctions = (getThing) => {
|
|
118
|
+
let thing;
|
|
119
|
+
const [getId, releaseId] = getPoolFunctions();
|
|
120
|
+
const allListeners = mapNew();
|
|
121
|
+
const addListener = (
|
|
122
|
+
listener,
|
|
123
|
+
idSetNode,
|
|
124
|
+
path,
|
|
125
|
+
pathGetters = [],
|
|
126
|
+
extraArgsGetter = () => [],
|
|
127
|
+
) => {
|
|
128
|
+
thing ??= getThing();
|
|
129
|
+
const id = getId(1);
|
|
130
|
+
mapSet(allListeners, id, [
|
|
131
|
+
listener,
|
|
132
|
+
idSetNode,
|
|
133
|
+
path,
|
|
134
|
+
pathGetters,
|
|
135
|
+
extraArgsGetter,
|
|
136
|
+
]);
|
|
137
|
+
setAdd(visitTree(idSetNode, path ?? [EMPTY_STRING], setNew), id);
|
|
138
|
+
return id;
|
|
139
|
+
};
|
|
140
|
+
const callListeners = (idSetNode, ids, ...extraArgs) =>
|
|
141
|
+
arrayForEach(getWildcardedLeaves(idSetNode, ids), (set) =>
|
|
142
|
+
collForEach(set, (id) =>
|
|
143
|
+
mapGet(allListeners, id)[0](thing, ...(ids ?? []), ...extraArgs),
|
|
144
|
+
),
|
|
145
|
+
);
|
|
146
|
+
const delListener = (id) =>
|
|
147
|
+
ifNotUndefined(mapGet(allListeners, id), ([, idSetNode, idOrNulls]) => {
|
|
148
|
+
visitTree(idSetNode, idOrNulls ?? [EMPTY_STRING], void 0, (idSet) => {
|
|
149
|
+
collDel(idSet, id);
|
|
150
|
+
return collIsEmpty(idSet) ? 1 : 0;
|
|
151
|
+
});
|
|
152
|
+
mapSet(allListeners, id);
|
|
153
|
+
releaseId(id);
|
|
154
|
+
return idOrNulls;
|
|
155
|
+
});
|
|
156
|
+
const callListener = (id) =>
|
|
157
|
+
ifNotUndefined(
|
|
158
|
+
mapGet(allListeners, id),
|
|
159
|
+
([listener, , path = [], pathGetters, extraArgsGetter]) => {
|
|
160
|
+
const callWithIds = (...ids) => {
|
|
161
|
+
const index = size(ids);
|
|
162
|
+
if (index == size(path)) {
|
|
163
|
+
listener(thing, ...ids, ...extraArgsGetter(ids));
|
|
164
|
+
} else if (isUndefined(path[index])) {
|
|
165
|
+
arrayForEach(pathGetters[index]?.(...ids) ?? [], (id2) =>
|
|
166
|
+
callWithIds(...ids, id2),
|
|
167
|
+
);
|
|
168
|
+
} else {
|
|
169
|
+
callWithIds(...ids, path[index]);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
callWithIds();
|
|
173
|
+
},
|
|
174
|
+
);
|
|
175
|
+
return [addListener, callListeners, delListener, callListener];
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const scheduleRunning = mapNew();
|
|
179
|
+
const scheduleActions = mapNew();
|
|
180
|
+
const getStoreFunctions = (
|
|
181
|
+
persist = 1 /* StoreOnly */,
|
|
182
|
+
store,
|
|
183
|
+
isSynchronizer,
|
|
184
|
+
) =>
|
|
185
|
+
persist != 1 /* StoreOnly */ && store.isMergeable()
|
|
186
|
+
? [
|
|
187
|
+
1,
|
|
188
|
+
store.getMergeableContent,
|
|
189
|
+
() => store.getTransactionMergeableChanges(!isSynchronizer),
|
|
190
|
+
([[changedTables], [changedValues]]) =>
|
|
191
|
+
!objIsEmpty(changedTables) || !objIsEmpty(changedValues),
|
|
192
|
+
store.setDefaultContent,
|
|
193
|
+
]
|
|
194
|
+
: persist != 2 /* MergeableStoreOnly */
|
|
195
|
+
? [
|
|
196
|
+
0,
|
|
197
|
+
store.getContent,
|
|
198
|
+
store.getTransactionChanges,
|
|
199
|
+
([changedTables, changedValues]) =>
|
|
200
|
+
!objIsEmpty(changedTables) || !objIsEmpty(changedValues),
|
|
201
|
+
store.setContent,
|
|
202
|
+
]
|
|
203
|
+
: errorNew('Store type not supported by this Persister');
|
|
204
|
+
const createCustomPersister = (
|
|
205
|
+
store,
|
|
206
|
+
getPersisted,
|
|
207
|
+
setPersisted,
|
|
208
|
+
addPersisterListener,
|
|
209
|
+
delPersisterListener,
|
|
210
|
+
onIgnoredError,
|
|
211
|
+
persist,
|
|
212
|
+
extra = {},
|
|
213
|
+
isSynchronizer = 0,
|
|
214
|
+
scheduleId = [],
|
|
215
|
+
) => {
|
|
216
|
+
let status = 0; /* Idle */
|
|
217
|
+
let loads = 0;
|
|
218
|
+
let saves = 0;
|
|
219
|
+
let action;
|
|
220
|
+
let autoLoadHandle;
|
|
221
|
+
let autoSaveListenerId;
|
|
222
|
+
mapEnsure(scheduleRunning, scheduleId, () => 0);
|
|
223
|
+
mapEnsure(scheduleActions, scheduleId, () => []);
|
|
224
|
+
const statusListeners = mapNew();
|
|
225
|
+
const [
|
|
226
|
+
isMergeableStore,
|
|
227
|
+
getContent,
|
|
228
|
+
getChanges,
|
|
229
|
+
hasChanges,
|
|
230
|
+
setDefaultContent,
|
|
231
|
+
] = getStoreFunctions(persist, store, isSynchronizer);
|
|
232
|
+
const [addListener, callListeners, delListenerImpl] = getListenerFunctions(
|
|
233
|
+
() => persister,
|
|
234
|
+
);
|
|
235
|
+
const setStatus = (newStatus) => {
|
|
236
|
+
if (newStatus != status) {
|
|
237
|
+
status = newStatus;
|
|
238
|
+
callListeners(statusListeners, void 0, status);
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
const run = async () => {
|
|
242
|
+
/* istanbul ignore else */
|
|
243
|
+
if (!mapGet(scheduleRunning, scheduleId)) {
|
|
244
|
+
mapSet(scheduleRunning, scheduleId, 1);
|
|
245
|
+
while (
|
|
246
|
+
!isUndefined((action = arrayShift(mapGet(scheduleActions, scheduleId))))
|
|
247
|
+
) {
|
|
248
|
+
await tryCatch(action, onIgnoredError);
|
|
249
|
+
}
|
|
250
|
+
mapSet(scheduleRunning, scheduleId, 0);
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
const setContentOrChanges = (contentOrChanges) => {
|
|
254
|
+
(isMergeableStore && isArray(contentOrChanges?.[0])
|
|
255
|
+
? contentOrChanges?.[2] === 1
|
|
256
|
+
? store.applyMergeableChanges
|
|
257
|
+
: store.setMergeableContent
|
|
258
|
+
: contentOrChanges?.[2] === 1
|
|
259
|
+
? store.applyChanges
|
|
260
|
+
: store.setContent)(contentOrChanges);
|
|
261
|
+
};
|
|
262
|
+
const load = async (initialContent) => {
|
|
263
|
+
/* istanbul ignore else */
|
|
264
|
+
if (status != 2 /* Saving */) {
|
|
265
|
+
setStatus(1 /* Loading */);
|
|
266
|
+
loads++;
|
|
267
|
+
await schedule(async () => {
|
|
268
|
+
await tryCatch(
|
|
269
|
+
async () => {
|
|
270
|
+
const content = await getPersisted();
|
|
271
|
+
if (isArray(content)) {
|
|
272
|
+
setContentOrChanges(content);
|
|
273
|
+
} else if (initialContent) {
|
|
274
|
+
setDefaultContent(initialContent);
|
|
275
|
+
} else {
|
|
276
|
+
errorNew(`Content is not an array: ${content}`);
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
() => {
|
|
280
|
+
if (initialContent) {
|
|
281
|
+
setDefaultContent(initialContent);
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
);
|
|
285
|
+
setStatus(0 /* Idle */);
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
return persister;
|
|
289
|
+
};
|
|
290
|
+
const startAutoLoad = async (initialContent) => {
|
|
291
|
+
stopAutoLoad();
|
|
292
|
+
await load(initialContent);
|
|
293
|
+
await tryCatch(
|
|
294
|
+
async () =>
|
|
295
|
+
(autoLoadHandle = await addPersisterListener(
|
|
296
|
+
async (content, changes) => {
|
|
297
|
+
if (changes || content) {
|
|
298
|
+
/* istanbul ignore else */
|
|
299
|
+
if (status != 2 /* Saving */) {
|
|
300
|
+
setStatus(1 /* Loading */);
|
|
301
|
+
loads++;
|
|
302
|
+
setContentOrChanges(changes ?? content);
|
|
303
|
+
setStatus(0 /* Idle */);
|
|
304
|
+
}
|
|
305
|
+
} else {
|
|
306
|
+
await load();
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
)),
|
|
310
|
+
onIgnoredError,
|
|
311
|
+
);
|
|
312
|
+
return persister;
|
|
313
|
+
};
|
|
314
|
+
const stopAutoLoad = async () => {
|
|
315
|
+
if (autoLoadHandle) {
|
|
316
|
+
await tryCatch(
|
|
317
|
+
() => delPersisterListener(autoLoadHandle),
|
|
318
|
+
onIgnoredError,
|
|
319
|
+
);
|
|
320
|
+
autoLoadHandle = void 0;
|
|
321
|
+
}
|
|
322
|
+
return persister;
|
|
323
|
+
};
|
|
324
|
+
const isAutoLoading = () => !isUndefined(autoLoadHandle);
|
|
325
|
+
const save = async (changes) => {
|
|
326
|
+
/* istanbul ignore else */
|
|
327
|
+
if (status != 1 /* Loading */) {
|
|
328
|
+
setStatus(2 /* Saving */);
|
|
329
|
+
saves++;
|
|
330
|
+
await schedule(async () => {
|
|
331
|
+
await tryCatch(() => setPersisted(getContent, changes), onIgnoredError);
|
|
332
|
+
setStatus(0 /* Idle */);
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
return persister;
|
|
336
|
+
};
|
|
337
|
+
const startAutoSave = async () => {
|
|
338
|
+
stopAutoSave();
|
|
339
|
+
await save();
|
|
340
|
+
autoSaveListenerId = store.addDidFinishTransactionListener(() => {
|
|
341
|
+
const changes = getChanges();
|
|
342
|
+
if (hasChanges(changes)) {
|
|
343
|
+
save(changes);
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
return persister;
|
|
347
|
+
};
|
|
348
|
+
const stopAutoSave = async () => {
|
|
349
|
+
if (autoSaveListenerId) {
|
|
350
|
+
store.delListener(autoSaveListenerId);
|
|
351
|
+
autoSaveListenerId = void 0;
|
|
352
|
+
}
|
|
353
|
+
return persister;
|
|
354
|
+
};
|
|
355
|
+
const isAutoSaving = () => !isUndefined(autoSaveListenerId);
|
|
356
|
+
const startAutoPersisting = async (
|
|
357
|
+
initialContent,
|
|
358
|
+
startSaveFirst = false,
|
|
359
|
+
) => {
|
|
360
|
+
const [call1, call2] = startSaveFirst
|
|
361
|
+
? [startAutoSave, startAutoLoad]
|
|
362
|
+
: [startAutoLoad, startAutoSave];
|
|
363
|
+
await call1(initialContent);
|
|
364
|
+
await call2(initialContent);
|
|
365
|
+
return persister;
|
|
366
|
+
};
|
|
367
|
+
const stopAutoPersisting = async (stopSaveFirst = false) => {
|
|
368
|
+
const [call1, call2] = stopSaveFirst
|
|
369
|
+
? [stopAutoSave, stopAutoLoad]
|
|
370
|
+
: [stopAutoLoad, stopAutoSave];
|
|
371
|
+
await call1();
|
|
372
|
+
await call2();
|
|
373
|
+
return persister;
|
|
374
|
+
};
|
|
375
|
+
const getStatus = () => status;
|
|
376
|
+
const addStatusListener = (listener) =>
|
|
377
|
+
addListener(listener, statusListeners);
|
|
378
|
+
const delListener = (listenerId) => {
|
|
379
|
+
delListenerImpl(listenerId);
|
|
380
|
+
return store;
|
|
381
|
+
};
|
|
382
|
+
const schedule = async (...actions) => {
|
|
383
|
+
arrayPush(mapGet(scheduleActions, scheduleId), ...actions);
|
|
384
|
+
await run();
|
|
385
|
+
return persister;
|
|
386
|
+
};
|
|
387
|
+
const getStore = () => store;
|
|
388
|
+
const destroy = () => {
|
|
389
|
+
arrayClear(mapGet(scheduleActions, scheduleId));
|
|
390
|
+
return stopAutoPersisting();
|
|
391
|
+
};
|
|
392
|
+
const getStats = () => ({loads, saves});
|
|
393
|
+
const persister = {
|
|
394
|
+
load,
|
|
395
|
+
startAutoLoad,
|
|
396
|
+
stopAutoLoad,
|
|
397
|
+
isAutoLoading,
|
|
398
|
+
save,
|
|
399
|
+
startAutoSave,
|
|
400
|
+
stopAutoSave,
|
|
401
|
+
isAutoSaving,
|
|
402
|
+
startAutoPersisting,
|
|
403
|
+
stopAutoPersisting,
|
|
404
|
+
getStatus,
|
|
405
|
+
addStatusListener,
|
|
406
|
+
delListener,
|
|
407
|
+
schedule,
|
|
408
|
+
getStore,
|
|
409
|
+
destroy,
|
|
410
|
+
getStats,
|
|
411
|
+
...extra,
|
|
412
|
+
};
|
|
413
|
+
return objFreeze(persister);
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
const STORAGE = 'storage';
|
|
417
|
+
const createReactNativeMmkvPersister = (
|
|
418
|
+
store,
|
|
419
|
+
storage,
|
|
420
|
+
storageName = STORAGE,
|
|
421
|
+
onIgnoredError,
|
|
422
|
+
) => {
|
|
423
|
+
const getPersisted = async () => {
|
|
424
|
+
const data = storage.getString(storageName);
|
|
425
|
+
const value = data === void 0 ? void 0 : JSON.parse(data);
|
|
426
|
+
return Promise.resolve(value);
|
|
427
|
+
};
|
|
428
|
+
const setPersisted = async (getContent) => {
|
|
429
|
+
const content = getContent();
|
|
430
|
+
if (content !== void 0) {
|
|
431
|
+
storage.set(storageName, JSON.stringify(content));
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
const addPersisterListener = (listener) =>
|
|
435
|
+
storage.addOnValueChangedListener((key) => {
|
|
436
|
+
if (key === storageName) {
|
|
437
|
+
const value = storage.getString(storageName);
|
|
438
|
+
if (value) {
|
|
439
|
+
listener(JSON.parse(value));
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
const delPersisterListener = (storageListener) => {
|
|
444
|
+
storageListener.remove();
|
|
445
|
+
};
|
|
446
|
+
return createCustomPersister(
|
|
447
|
+
store,
|
|
448
|
+
getPersisted,
|
|
449
|
+
setPersisted,
|
|
450
|
+
addPersisterListener,
|
|
451
|
+
delPersisterListener,
|
|
452
|
+
onIgnoredError,
|
|
453
|
+
3,
|
|
454
|
+
// StoreOrMergeableStore
|
|
455
|
+
{getStorageName: () => storageName},
|
|
456
|
+
);
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
export {createReactNativeMmkvPersister};
|