react-native-onyx 2.0.33 → 2.0.35
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/dist/DevTools.js +2 -2
- package/dist/Onyx.js +29 -3
- package/dist/OnyxUtils.d.ts +1 -1
- package/dist/OnyxUtils.js +3 -3
- package/dist/logMessages.d.ts +4 -0
- package/dist/logMessages.js +8 -0
- package/dist/utils.d.ts +7 -0
- package/dist/utils.js +21 -1
- package/package.json +1 -1
package/dist/DevTools.js
CHANGED
|
@@ -11,8 +11,8 @@ class DevTools {
|
|
|
11
11
|
try {
|
|
12
12
|
// We don't want to augment the window type in a library code, so we use type assertion instead
|
|
13
13
|
// eslint-disable-next-line no-underscore-dangle, @typescript-eslint/no-explicit-any
|
|
14
|
-
const reduxDevtools = window.__REDUX_DEVTOOLS_EXTENSION__;
|
|
15
|
-
if ((options
|
|
14
|
+
const reduxDevtools = typeof window === 'undefined' ? undefined : window.__REDUX_DEVTOOLS_EXTENSION__;
|
|
15
|
+
if ((options === null || options === void 0 ? void 0 : options.remote) || !reduxDevtools) {
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
18
|
return reduxDevtools.connect(options);
|
package/dist/Onyx.js
CHANGED
|
@@ -36,6 +36,7 @@ const storage_1 = __importDefault(require("./storage"));
|
|
|
36
36
|
const utils_1 = __importDefault(require("./utils"));
|
|
37
37
|
const DevTools_1 = __importDefault(require("./DevTools"));
|
|
38
38
|
const OnyxUtils_1 = __importDefault(require("./OnyxUtils"));
|
|
39
|
+
const logMessages_1 = __importDefault(require("./logMessages"));
|
|
39
40
|
// Keeps track of the last connectionID that was used so we can keep incrementing it
|
|
40
41
|
let lastConnectionID = 0;
|
|
41
42
|
// Connections can be made before `Onyx.init`. They would wait for this task before resolving
|
|
@@ -191,6 +192,13 @@ function disconnect(connectionID, keyToRemoveFromEvictionBlocklist) {
|
|
|
191
192
|
* @param value value to store
|
|
192
193
|
*/
|
|
193
194
|
function set(key, value) {
|
|
195
|
+
// check if the value is compatible with the existing value in the storage
|
|
196
|
+
const existingValue = OnyxCache_1.default.getValue(key, false);
|
|
197
|
+
const { isCompatible, existingValueType, newValueType } = utils_1.default.checkCompatibilityWithExistingValue(value, existingValue);
|
|
198
|
+
if (!isCompatible) {
|
|
199
|
+
Logger.logAlert(logMessages_1.default.incompatibleUpdateAlert(key, 'set', existingValueType, newValueType));
|
|
200
|
+
return Promise.resolve();
|
|
201
|
+
}
|
|
194
202
|
// If the value is null, we remove the key from storage
|
|
195
203
|
const { value: valueAfterRemoving, wasRemoved } = OnyxUtils_1.default.removeNullValues(key, value);
|
|
196
204
|
const valueWithoutNullValues = valueAfterRemoving;
|
|
@@ -275,7 +283,17 @@ function merge(key, changes) {
|
|
|
275
283
|
try {
|
|
276
284
|
// We first only merge the changes, so we can provide these to the native implementation (SQLite uses only delta changes in "JSON_PATCH" to merge)
|
|
277
285
|
// We don't want to remove null values from the "batchedDeltaChanges", because SQLite uses them to remove keys from storage natively.
|
|
278
|
-
const
|
|
286
|
+
const validChanges = mergeQueue[key].filter((change) => {
|
|
287
|
+
const { isCompatible, existingValueType, newValueType } = utils_1.default.checkCompatibilityWithExistingValue(change, existingValue);
|
|
288
|
+
if (!isCompatible) {
|
|
289
|
+
Logger.logAlert(logMessages_1.default.incompatibleUpdateAlert(key, 'merge', existingValueType, newValueType));
|
|
290
|
+
}
|
|
291
|
+
return isCompatible;
|
|
292
|
+
});
|
|
293
|
+
if (!validChanges.length) {
|
|
294
|
+
return undefined;
|
|
295
|
+
}
|
|
296
|
+
const batchedDeltaChanges = OnyxUtils_1.default.applyMerge(undefined, validChanges, false);
|
|
279
297
|
// Case (1): When there is no existing value in storage, we want to set the value instead of merge it.
|
|
280
298
|
// Case (2): The presence of a top-level `null` in the merge queue instructs us to drop the whole existing value.
|
|
281
299
|
// In this case, we can't simply merge the batched changes with the existing value, because then the null in the merge queue would have no effect
|
|
@@ -358,8 +376,14 @@ function mergeCollection(collectionKey, collection) {
|
|
|
358
376
|
return true;
|
|
359
377
|
});
|
|
360
378
|
const existingKeys = keys.filter((key) => persistedKeys.has(key));
|
|
379
|
+
const cachedCollectionForExistingKeys = OnyxUtils_1.default.getCachedCollection(collectionKey, existingKeys);
|
|
361
380
|
const newKeys = keys.filter((key) => !persistedKeys.has(key));
|
|
362
381
|
const existingKeyCollection = existingKeys.reduce((obj, key) => {
|
|
382
|
+
const { isCompatible, existingValueType, newValueType } = utils_1.default.checkCompatibilityWithExistingValue(mergedCollection[key], cachedCollectionForExistingKeys[key]);
|
|
383
|
+
if (!isCompatible) {
|
|
384
|
+
Logger.logAlert(logMessages_1.default.incompatibleUpdateAlert(key, 'mergeCollection', existingValueType, newValueType));
|
|
385
|
+
return obj;
|
|
386
|
+
}
|
|
363
387
|
// eslint-disable-next-line no-param-reassign
|
|
364
388
|
obj[key] = mergedCollection[key];
|
|
365
389
|
return obj;
|
|
@@ -385,11 +409,13 @@ function mergeCollection(collectionKey, collection) {
|
|
|
385
409
|
if (keyValuePairsForNewCollection.length > 0) {
|
|
386
410
|
promises.push(storage_1.default.multiSet(keyValuePairsForNewCollection));
|
|
387
411
|
}
|
|
412
|
+
// finalMergedCollection contains all the keys that were merged, without the keys of incompatible updates
|
|
413
|
+
const finalMergedCollection = Object.assign(Object.assign({}, existingKeyCollection), newCollection);
|
|
388
414
|
// Prefill cache if necessary by calling get() on any existing keys and then merge original data to cache
|
|
389
415
|
// and update all subscribers
|
|
390
416
|
const promiseUpdate = Promise.all(existingKeys.map(OnyxUtils_1.default.get)).then(() => {
|
|
391
|
-
OnyxCache_1.default.merge(
|
|
392
|
-
return OnyxUtils_1.default.scheduleNotifyCollectionSubscribers(collectionKey,
|
|
417
|
+
OnyxCache_1.default.merge(finalMergedCollection);
|
|
418
|
+
return OnyxUtils_1.default.scheduleNotifyCollectionSubscribers(collectionKey, finalMergedCollection);
|
|
393
419
|
});
|
|
394
420
|
return Promise.all(promises)
|
|
395
421
|
.catch((error) => OnyxUtils_1.default.evictStorageAndRetry(error, mergeCollection, collectionKey, mergedCollection))
|
package/dist/OnyxUtils.d.ts
CHANGED
|
@@ -103,7 +103,7 @@ declare function addToEvictionBlockList(key: OnyxKey, connectionID: number): voi
|
|
|
103
103
|
* removed.
|
|
104
104
|
*/
|
|
105
105
|
declare function addAllSafeEvictionKeysToRecentlyAccessedList(): Promise<void>;
|
|
106
|
-
declare function getCachedCollection<TKey extends CollectionKeyBase>(collectionKey: TKey): NonNullable<OnyxCollection<KeyValueMapping[TKey]>>;
|
|
106
|
+
declare function getCachedCollection<TKey extends CollectionKeyBase>(collectionKey: TKey, collectionMemberKeys?: string[]): NonNullable<OnyxCollection<KeyValueMapping[TKey]>>;
|
|
107
107
|
/**
|
|
108
108
|
* When a collection of keys change, search for any callbacks matching the collection key and trigger those callbacks
|
|
109
109
|
*/
|
package/dist/OnyxUtils.js
CHANGED
|
@@ -323,9 +323,9 @@ function addAllSafeEvictionKeysToRecentlyAccessedList() {
|
|
|
323
323
|
});
|
|
324
324
|
});
|
|
325
325
|
}
|
|
326
|
-
function getCachedCollection(collectionKey) {
|
|
327
|
-
const
|
|
328
|
-
return
|
|
326
|
+
function getCachedCollection(collectionKey, collectionMemberKeys) {
|
|
327
|
+
const resolvedCollectionMemberKeys = collectionMemberKeys || Array.from(OnyxCache_1.default.getAllKeys()).filter((storedKey) => isCollectionMemberKey(collectionKey, storedKey));
|
|
328
|
+
return resolvedCollectionMemberKeys.reduce((prev, key) => {
|
|
329
329
|
const cachedValue = OnyxCache_1.default.getValue(key);
|
|
330
330
|
if (!cachedValue) {
|
|
331
331
|
return prev;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const logMessages = {
|
|
4
|
+
incompatibleUpdateAlert: (key, operation, existingValueType, newValueType) => {
|
|
5
|
+
return `Warning: Trying to apply "${operation}" with ${newValueType !== null && newValueType !== void 0 ? newValueType : 'unknown'} type to ${existingValueType !== null && existingValueType !== void 0 ? existingValueType : 'unknown'} type in the key "${key}"`;
|
|
6
|
+
},
|
|
7
|
+
};
|
|
8
|
+
exports.default = logMessages;
|
package/dist/utils.d.ts
CHANGED
|
@@ -15,10 +15,17 @@ declare function fastMerge<TObject extends Record<string, unknown>>(target: TObj
|
|
|
15
15
|
declare function removeNestedNullValues<TObject extends Record<string, unknown>>(value: unknown | unknown[] | TObject): Record<string, unknown> | unknown[] | null;
|
|
16
16
|
/** Formats the action name by uppercasing and adding the key if provided. */
|
|
17
17
|
declare function formatActionName(method: string, key?: OnyxKey): string;
|
|
18
|
+
/** validate that the update and the existing value are compatible */
|
|
19
|
+
declare function checkCompatibilityWithExistingValue(value: unknown, existingValue: unknown): {
|
|
20
|
+
isCompatible: boolean;
|
|
21
|
+
existingValueType?: string;
|
|
22
|
+
newValueType?: string;
|
|
23
|
+
};
|
|
18
24
|
declare const _default: {
|
|
19
25
|
isEmptyObject: typeof isEmptyObject;
|
|
20
26
|
fastMerge: typeof fastMerge;
|
|
21
27
|
formatActionName: typeof formatActionName;
|
|
22
28
|
removeNestedNullValues: typeof removeNestedNullValues;
|
|
29
|
+
checkCompatibilityWithExistingValue: typeof checkCompatibilityWithExistingValue;
|
|
23
30
|
};
|
|
24
31
|
export default _default;
|
package/dist/utils.js
CHANGED
|
@@ -98,4 +98,24 @@ function removeNestedNullValues(value) {
|
|
|
98
98
|
function formatActionName(method, key) {
|
|
99
99
|
return key ? `${method.toUpperCase()}/${key}` : method.toUpperCase();
|
|
100
100
|
}
|
|
101
|
-
|
|
101
|
+
/** validate that the update and the existing value are compatible */
|
|
102
|
+
function checkCompatibilityWithExistingValue(value, existingValue) {
|
|
103
|
+
if (!existingValue || !value) {
|
|
104
|
+
return {
|
|
105
|
+
isCompatible: true,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
const existingValueType = Array.isArray(existingValue) ? 'array' : 'non-array';
|
|
109
|
+
const newValueType = Array.isArray(value) ? 'array' : 'non-array';
|
|
110
|
+
if (existingValueType !== newValueType) {
|
|
111
|
+
return {
|
|
112
|
+
isCompatible: false,
|
|
113
|
+
existingValueType,
|
|
114
|
+
newValueType,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
isCompatible: true,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
exports.default = { isEmptyObject, fastMerge, formatActionName, removeNestedNullValues, checkCompatibilityWithExistingValue };
|