react-native-onyx 3.0.32 → 3.0.34
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 +19 -0
- package/dist/Onyx.d.ts +1 -1
- package/dist/Onyx.js +5 -2
- package/dist/OnyxCache.d.ts +10 -0
- package/dist/OnyxCache.js +15 -1
- package/dist/OnyxMerge/index.js +3 -1
- package/dist/OnyxMerge/index.native.js +3 -1
- package/dist/OnyxUtils.d.ts +29 -0
- package/dist/OnyxUtils.js +80 -5
- package/dist/types.d.ts +12 -0
- package/dist/useOnyx.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -460,6 +460,25 @@ Onyx.init({
|
|
|
460
460
|
});
|
|
461
461
|
```
|
|
462
462
|
|
|
463
|
+
### Using RAM-only keys
|
|
464
|
+
|
|
465
|
+
You can choose not to save certain keys on disk and keep them RAM-only, that way their values will reset with each session. You just have to pass an array of `ramOnlyKeys` to the `Onyx.init` method. You can mark entire collections as RAM-only by including the collection key (e.g., `ONYXKEYS.COLLECTION.TEMP_DATA`). This will make all members of that collection RAM-only. Individual collection member keys cannot be selectively marked as RAM-only.
|
|
466
|
+
|
|
467
|
+
```javascript
|
|
468
|
+
import Onyx from 'react-native-onyx';
|
|
469
|
+
|
|
470
|
+
Onyx.init({
|
|
471
|
+
keys: ONYXKEYS,
|
|
472
|
+
ramOnlyKeys: [
|
|
473
|
+
ONYXKEYS.RAM_ONLY_KEY_1,
|
|
474
|
+
ONYXKEYS.RAM_ONLY_KEY_2,
|
|
475
|
+
ONYXKEYS.COLLECTION.TEMP_DATA,
|
|
476
|
+
],
|
|
477
|
+
});
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
> Note: RAM-only keys still consume memory and will remain in cache until explicitly cleared or until Onyx.clear() is called. Use them judiciously for truly ephemeral data.
|
|
481
|
+
|
|
463
482
|
### Usage
|
|
464
483
|
|
|
465
484
|
The extension interface is pretty simple, on the left sidebar you can see all the updates made to the local storage, in ascending order, and on the right pane you can see the whole the current state, payload of an action and the diff between the previous state and the current state after the action was triggered.
|
package/dist/Onyx.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as Logger from './Logger';
|
|
|
2
2
|
import type { CollectionKeyBase, ConnectOptions, InitOptions, OnyxKey, OnyxMergeCollectionInput, OnyxSetCollectionInput, OnyxMergeInput, OnyxMultiSetInput, OnyxSetInput, OnyxUpdate, SetOptions } from './types';
|
|
3
3
|
import type { Connection } from './OnyxConnectionManager';
|
|
4
4
|
/** Initialize the store with actions and listening for storage events */
|
|
5
|
-
declare function init({ keys, initialKeyStates, evictableKeys, maxCachedKeysCount, shouldSyncMultipleInstances, enablePerformanceMetrics, enableDevTools, skippableCollectionMemberIDs, }: InitOptions): void;
|
|
5
|
+
declare function init({ keys, initialKeyStates, evictableKeys, maxCachedKeysCount, shouldSyncMultipleInstances, enablePerformanceMetrics, enableDevTools, skippableCollectionMemberIDs, ramOnlyKeys, snapshotMergeKeys, }: InitOptions): void;
|
|
6
6
|
/**
|
|
7
7
|
* Connects to an Onyx key given the options passed and listens to its changes.
|
|
8
8
|
* This method will be deprecated soon. Please use `Onyx.connectWithoutView()` instead.
|
package/dist/Onyx.js
CHANGED
|
@@ -48,7 +48,7 @@ const GlobalSettings = __importStar(require("./GlobalSettings"));
|
|
|
48
48
|
const metrics_1 = __importDefault(require("./metrics"));
|
|
49
49
|
const OnyxMerge_1 = __importDefault(require("./OnyxMerge"));
|
|
50
50
|
/** Initialize the store with actions and listening for storage events */
|
|
51
|
-
function init({ keys = {}, initialKeyStates = {}, evictableKeys = [], maxCachedKeysCount = 1000, shouldSyncMultipleInstances = !!global.localStorage, enablePerformanceMetrics = false, enableDevTools = true, skippableCollectionMemberIDs = [], }) {
|
|
51
|
+
function init({ keys = {}, initialKeyStates = {}, evictableKeys = [], maxCachedKeysCount = 1000, shouldSyncMultipleInstances = !!global.localStorage, enablePerformanceMetrics = false, enableDevTools = true, skippableCollectionMemberIDs = [], ramOnlyKeys = [], snapshotMergeKeys = [], }) {
|
|
52
52
|
var _a;
|
|
53
53
|
if (enablePerformanceMetrics) {
|
|
54
54
|
GlobalSettings.setPerformanceMetricsEnabled(true);
|
|
@@ -57,6 +57,8 @@ function init({ keys = {}, initialKeyStates = {}, evictableKeys = [], maxCachedK
|
|
|
57
57
|
(0, DevTools_1.initDevTools)(enableDevTools);
|
|
58
58
|
storage_1.default.init();
|
|
59
59
|
OnyxUtils_1.default.setSkippableCollectionMemberIDs(new Set(skippableCollectionMemberIDs));
|
|
60
|
+
OnyxUtils_1.default.setSnapshotMergeKeys(new Set(snapshotMergeKeys));
|
|
61
|
+
OnyxCache_1.default.setRamOnlyKeys(new Set(ramOnlyKeys));
|
|
60
62
|
if (shouldSyncMultipleInstances) {
|
|
61
63
|
(_a = storage_1.default.keepInstancesSync) === null || _a === void 0 ? void 0 : _a.call(storage_1.default, (key, value) => {
|
|
62
64
|
OnyxCache_1.default.set(key, value);
|
|
@@ -346,8 +348,9 @@ function clear(keysToPreserve = []) {
|
|
|
346
348
|
for (const [key, value] of Object.entries(keyValuesToResetAsCollection)) {
|
|
347
349
|
updatePromises.push(OnyxUtils_1.default.scheduleNotifyCollectionSubscribers(key, value.newValues, value.oldValues));
|
|
348
350
|
}
|
|
351
|
+
// Exclude RAM-only keys to prevent them from being saved to storage
|
|
349
352
|
const defaultKeyValuePairs = Object.entries(Object.keys(defaultKeyStates)
|
|
350
|
-
.filter((key) => !keysToPreserve.includes(key))
|
|
353
|
+
.filter((key) => !keysToPreserve.includes(key) && !OnyxUtils_1.default.isRamOnlyKey(key))
|
|
351
354
|
.reduce((obj, key) => {
|
|
352
355
|
// eslint-disable-next-line no-param-reassign
|
|
353
356
|
obj[key] = defaultKeyStates[key];
|
package/dist/OnyxCache.d.ts
CHANGED
|
@@ -36,6 +36,8 @@ declare class OnyxCache {
|
|
|
36
36
|
private recentlyAccessedKeys;
|
|
37
37
|
/** Set of collection keys for fast lookup */
|
|
38
38
|
private collectionKeys;
|
|
39
|
+
/** Set of RAM-only keys for fast lookup */
|
|
40
|
+
private ramOnlyKeys;
|
|
39
41
|
constructor();
|
|
40
42
|
/** Get all the storage keys */
|
|
41
43
|
getAllKeys(): Set<OnyxKey>;
|
|
@@ -165,6 +167,14 @@ declare class OnyxCache {
|
|
|
165
167
|
* Get all data for a collection key
|
|
166
168
|
*/
|
|
167
169
|
getCollectionData(collectionKey: OnyxKey): Record<OnyxKey, OnyxValue<OnyxKey>> | undefined;
|
|
170
|
+
/**
|
|
171
|
+
* Set the RAM-only keys for optimized storage
|
|
172
|
+
*/
|
|
173
|
+
setRamOnlyKeys(ramOnlyKeys: Set<OnyxKey>): void;
|
|
174
|
+
/**
|
|
175
|
+
* Check if a key is a RAM-only key
|
|
176
|
+
*/
|
|
177
|
+
isRamOnlyKey(key: OnyxKey): boolean;
|
|
168
178
|
}
|
|
169
179
|
declare const instance: OnyxCache;
|
|
170
180
|
export default instance;
|
package/dist/OnyxCache.js
CHANGED
|
@@ -64,6 +64,8 @@ class OnyxCache {
|
|
|
64
64
|
this.recentlyAccessedKeys = new Set();
|
|
65
65
|
/** Set of collection keys for fast lookup */
|
|
66
66
|
this.collectionKeys = new Set();
|
|
67
|
+
/** Set of RAM-only keys for fast lookup */
|
|
68
|
+
this.ramOnlyKeys = new Set();
|
|
67
69
|
this.storageKeys = new Set();
|
|
68
70
|
this.nullishStorageKeys = new Set();
|
|
69
71
|
this.recentKeys = new Set();
|
|
@@ -71,7 +73,7 @@ class OnyxCache {
|
|
|
71
73
|
this.collectionData = {};
|
|
72
74
|
this.pendingPromises = new Map();
|
|
73
75
|
// bind all public methods to prevent problems with `this`
|
|
74
|
-
(0, bindAll_1.default)(this, 'getAllKeys', 'get', 'hasCacheForKey', 'addKey', 'addNullishStorageKey', 'hasNullishStorageKey', 'clearNullishStorageKeys', 'set', 'drop', 'merge', 'hasPendingTask', 'getTaskPromise', 'captureTask', 'addToAccessedKeys', 'removeLeastRecentlyUsedKeys', 'setRecentKeysLimit', 'setAllKeys', 'setEvictionAllowList', 'getEvictionBlocklist', 'isEvictableKey', 'removeLastAccessedKey', 'addLastAccessedKey', 'addEvictableKeysToRecentlyAccessedList', 'getKeyForEviction', 'setCollectionKeys', 'isCollectionKey', 'getCollectionKey', 'getCollectionData');
|
|
76
|
+
(0, bindAll_1.default)(this, 'getAllKeys', 'get', 'hasCacheForKey', 'addKey', 'addNullishStorageKey', 'hasNullishStorageKey', 'clearNullishStorageKeys', 'set', 'drop', 'merge', 'hasPendingTask', 'getTaskPromise', 'captureTask', 'addToAccessedKeys', 'removeLeastRecentlyUsedKeys', 'setRecentKeysLimit', 'setAllKeys', 'setEvictionAllowList', 'getEvictionBlocklist', 'isEvictableKey', 'removeLastAccessedKey', 'addLastAccessedKey', 'addEvictableKeysToRecentlyAccessedList', 'getKeyForEviction', 'setCollectionKeys', 'isCollectionKey', 'getCollectionKey', 'getCollectionData', 'setRamOnlyKeys', 'isRamOnlyKey');
|
|
75
77
|
}
|
|
76
78
|
/** Get all the storage keys */
|
|
77
79
|
getAllKeys() {
|
|
@@ -394,6 +396,18 @@ class OnyxCache {
|
|
|
394
396
|
// Return a shallow copy to ensure React detects changes when items are added/removed
|
|
395
397
|
return Object.assign({}, cachedCollection);
|
|
396
398
|
}
|
|
399
|
+
/**
|
|
400
|
+
* Set the RAM-only keys for optimized storage
|
|
401
|
+
*/
|
|
402
|
+
setRamOnlyKeys(ramOnlyKeys) {
|
|
403
|
+
this.ramOnlyKeys = ramOnlyKeys;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Check if a key is a RAM-only key
|
|
407
|
+
*/
|
|
408
|
+
isRamOnlyKey(key) {
|
|
409
|
+
return this.ramOnlyKeys.has(key);
|
|
410
|
+
}
|
|
397
411
|
}
|
|
398
412
|
const instance = new OnyxCache();
|
|
399
413
|
exports.default = instance;
|
package/dist/OnyxMerge/index.js
CHANGED
|
@@ -14,8 +14,10 @@ const applyMerge = (key, existingValue, validChanges) => {
|
|
|
14
14
|
OnyxUtils_1.default.logKeyChanged(OnyxUtils_1.default.METHOD.MERGE, key, mergedValue, hasChanged);
|
|
15
15
|
// This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
|
|
16
16
|
const updatePromise = OnyxUtils_1.default.broadcastUpdate(key, mergedValue, hasChanged);
|
|
17
|
+
const shouldSkipStorageOperations = !hasChanged || OnyxUtils_1.default.isRamOnlyKey(key);
|
|
17
18
|
// If the value has not changed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
|
|
18
|
-
|
|
19
|
+
// If the key is marked as RAM-only, it should not be saved nor updated in the storage.
|
|
20
|
+
if (shouldSkipStorageOperations) {
|
|
19
21
|
return Promise.resolve({ mergedValue, updatePromise });
|
|
20
22
|
}
|
|
21
23
|
// For web platforms we use `setItem` since the object was already merged with its changes before.
|
|
@@ -20,8 +20,10 @@ const applyMerge = (key, existingValue, validChanges) => {
|
|
|
20
20
|
OnyxUtils_1.default.logKeyChanged(OnyxUtils_1.default.METHOD.MERGE, key, mergedValue, hasChanged);
|
|
21
21
|
// This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
|
|
22
22
|
const updatePromise = OnyxUtils_1.default.broadcastUpdate(key, mergedValue, hasChanged);
|
|
23
|
+
const shouldSkipStorageOperations = !hasChanged || OnyxUtils_1.default.isRamOnlyKey(key);
|
|
23
24
|
// If the value has not changed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
|
|
24
|
-
|
|
25
|
+
// If the key is marked as RAM-only, it should not be saved nor updated in the storage.
|
|
26
|
+
if (shouldSkipStorageOperations) {
|
|
25
27
|
return Promise.resolve({ mergedValue, updatePromise });
|
|
26
28
|
}
|
|
27
29
|
// For native platforms we use `mergeItem` that will take advantage of JSON_PATCH and JSON_REPLACE SQL operations to
|
package/dist/OnyxUtils.d.ts
CHANGED
|
@@ -34,10 +34,18 @@ declare function getDeferredInitTask(): DeferredTask;
|
|
|
34
34
|
* Getter - returns the skippable collection member IDs.
|
|
35
35
|
*/
|
|
36
36
|
declare function getSkippableCollectionMemberIDs(): Set<string>;
|
|
37
|
+
/**
|
|
38
|
+
* Getter - returns the snapshot merge keys allowlist.
|
|
39
|
+
*/
|
|
40
|
+
declare function getSnapshotMergeKeys(): Set<string>;
|
|
37
41
|
/**
|
|
38
42
|
* Setter - sets the skippable collection member IDs.
|
|
39
43
|
*/
|
|
40
44
|
declare function setSkippableCollectionMemberIDs(ids: Set<string>): void;
|
|
45
|
+
/**
|
|
46
|
+
* Setter - sets the snapshot merge keys allowlist.
|
|
47
|
+
*/
|
|
48
|
+
declare function setSnapshotMergeKeys(keys: Set<string>): void;
|
|
41
49
|
/**
|
|
42
50
|
* Sets the initial values for the Onyx store
|
|
43
51
|
*
|
|
@@ -105,6 +113,24 @@ declare function isCollectionMemberKey<TCollectionKey extends CollectionKeyBase>
|
|
|
105
113
|
* @returns true if the key is a collection member, false otherwise
|
|
106
114
|
*/
|
|
107
115
|
declare function isCollectionMember(key: OnyxKey): boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Checks if a given key is a RAM-only key, RAM-only collection key, or a RAM-only collection member
|
|
118
|
+
*
|
|
119
|
+
* For example:
|
|
120
|
+
*
|
|
121
|
+
* For the following Onyx setup
|
|
122
|
+
*
|
|
123
|
+
* ramOnlyKeys: ["ramOnlyKey", "ramOnlyCollection_"]
|
|
124
|
+
*
|
|
125
|
+
* - `isRamOnlyKey("ramOnlyKey")` would return true
|
|
126
|
+
* - `isRamOnlyKey("ramOnlyCollection_")` would return true
|
|
127
|
+
* - `isRamOnlyKey("ramOnlyCollection_1")` would return true
|
|
128
|
+
* - `isRamOnlyKey("someOtherKey")` would return false
|
|
129
|
+
*
|
|
130
|
+
* @param key - The key to check
|
|
131
|
+
* @returns true if key is a RAM-only key, RAM-only collection key, or a RAM-only collection member
|
|
132
|
+
*/
|
|
133
|
+
declare function isRamOnlyKey(key: OnyxKey): boolean;
|
|
108
134
|
/**
|
|
109
135
|
* Splits a collection member key into the collection key part and the ID part.
|
|
110
136
|
* @param key - The collection member key to split.
|
|
@@ -354,6 +380,8 @@ declare const OnyxUtils: {
|
|
|
354
380
|
unsubscribeFromKey: typeof unsubscribeFromKey;
|
|
355
381
|
getSkippableCollectionMemberIDs: typeof getSkippableCollectionMemberIDs;
|
|
356
382
|
setSkippableCollectionMemberIDs: typeof setSkippableCollectionMemberIDs;
|
|
383
|
+
getSnapshotMergeKeys: typeof getSnapshotMergeKeys;
|
|
384
|
+
setSnapshotMergeKeys: typeof setSnapshotMergeKeys;
|
|
357
385
|
storeKeyBySubscriptions: typeof storeKeyBySubscriptions;
|
|
358
386
|
deleteKeyBySubscriptions: typeof deleteKeyBySubscriptions;
|
|
359
387
|
addKeyToRecentlyAccessedIfNeeded: typeof addKeyToRecentlyAccessedIfNeeded;
|
|
@@ -366,6 +394,7 @@ declare const OnyxUtils: {
|
|
|
366
394
|
setWithRetry: typeof setWithRetry;
|
|
367
395
|
multiSetWithRetry: typeof multiSetWithRetry;
|
|
368
396
|
setCollectionWithRetry: typeof setCollectionWithRetry;
|
|
397
|
+
isRamOnlyKey: typeof isRamOnlyKey;
|
|
369
398
|
};
|
|
370
399
|
export type { OnyxMethod };
|
|
371
400
|
export default OnyxUtils;
|
package/dist/OnyxUtils.js
CHANGED
|
@@ -38,7 +38,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.clearOnyxUtilsInternals = clearOnyxUtilsInternals;
|
|
40
40
|
const fast_equals_1 = require("fast-equals");
|
|
41
|
-
const pick_1 = __importDefault(require("lodash/pick"));
|
|
42
41
|
const underscore_1 = __importDefault(require("underscore"));
|
|
43
42
|
const DevTools_1 = __importDefault(require("./DevTools"));
|
|
44
43
|
const Logger = __importStar(require("./Logger"));
|
|
@@ -94,6 +93,8 @@ let lastSubscriptionID = 0;
|
|
|
94
93
|
const deferredInitTask = (0, createDeferredTask_1.default)();
|
|
95
94
|
// Holds a set of collection member IDs which updates will be ignored when using Onyx methods.
|
|
96
95
|
let skippableCollectionMemberIDs = new Set();
|
|
96
|
+
// Holds a set of keys that should always be merged into snapshot entries.
|
|
97
|
+
let snapshotMergeKeys = new Set();
|
|
97
98
|
function getSnapshotKey() {
|
|
98
99
|
return snapshotKey;
|
|
99
100
|
}
|
|
@@ -127,12 +128,24 @@ function getDeferredInitTask() {
|
|
|
127
128
|
function getSkippableCollectionMemberIDs() {
|
|
128
129
|
return skippableCollectionMemberIDs;
|
|
129
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Getter - returns the snapshot merge keys allowlist.
|
|
133
|
+
*/
|
|
134
|
+
function getSnapshotMergeKeys() {
|
|
135
|
+
return snapshotMergeKeys;
|
|
136
|
+
}
|
|
130
137
|
/**
|
|
131
138
|
* Setter - sets the skippable collection member IDs.
|
|
132
139
|
*/
|
|
133
140
|
function setSkippableCollectionMemberIDs(ids) {
|
|
134
141
|
skippableCollectionMemberIDs = ids;
|
|
135
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* Setter - sets the snapshot merge keys allowlist.
|
|
145
|
+
*/
|
|
146
|
+
function setSnapshotMergeKeys(keys) {
|
|
147
|
+
snapshotMergeKeys = keys;
|
|
148
|
+
}
|
|
136
149
|
/**
|
|
137
150
|
* Sets the initial values for the Onyx store
|
|
138
151
|
*
|
|
@@ -372,6 +385,34 @@ function isCollectionMember(key) {
|
|
|
372
385
|
return false;
|
|
373
386
|
}
|
|
374
387
|
}
|
|
388
|
+
/**
|
|
389
|
+
* Checks if a given key is a RAM-only key, RAM-only collection key, or a RAM-only collection member
|
|
390
|
+
*
|
|
391
|
+
* For example:
|
|
392
|
+
*
|
|
393
|
+
* For the following Onyx setup
|
|
394
|
+
*
|
|
395
|
+
* ramOnlyKeys: ["ramOnlyKey", "ramOnlyCollection_"]
|
|
396
|
+
*
|
|
397
|
+
* - `isRamOnlyKey("ramOnlyKey")` would return true
|
|
398
|
+
* - `isRamOnlyKey("ramOnlyCollection_")` would return true
|
|
399
|
+
* - `isRamOnlyKey("ramOnlyCollection_1")` would return true
|
|
400
|
+
* - `isRamOnlyKey("someOtherKey")` would return false
|
|
401
|
+
*
|
|
402
|
+
* @param key - The key to check
|
|
403
|
+
* @returns true if key is a RAM-only key, RAM-only collection key, or a RAM-only collection member
|
|
404
|
+
*/
|
|
405
|
+
function isRamOnlyKey(key) {
|
|
406
|
+
try {
|
|
407
|
+
const collectionKey = getCollectionKey(key);
|
|
408
|
+
// If collectionKey exists for a given key, check if it's a RAM-only key
|
|
409
|
+
return OnyxCache_1.default.isRamOnlyKey(collectionKey);
|
|
410
|
+
}
|
|
411
|
+
catch (_a) {
|
|
412
|
+
// If getCollectionKey throws, the key is not a collection member
|
|
413
|
+
}
|
|
414
|
+
return OnyxCache_1.default.isRamOnlyKey(key);
|
|
415
|
+
}
|
|
375
416
|
/**
|
|
376
417
|
* Splits a collection member key into the collection key part and the ID part.
|
|
377
418
|
* @param key - The collection member key to split.
|
|
@@ -700,6 +741,9 @@ function scheduleNotifyCollectionSubscribers(key, value, previousValue) {
|
|
|
700
741
|
function remove(key, isProcessingCollectionUpdate) {
|
|
701
742
|
OnyxCache_1.default.drop(key);
|
|
702
743
|
scheduleSubscriberUpdate(key, undefined, undefined, isProcessingCollectionUpdate);
|
|
744
|
+
if (isRamOnlyKey(key)) {
|
|
745
|
+
return Promise.resolve();
|
|
746
|
+
}
|
|
703
747
|
return storage_1.default.removeItem(key).then(() => undefined);
|
|
704
748
|
}
|
|
705
749
|
function reportStorageQuota() {
|
|
@@ -1011,7 +1055,14 @@ function updateSnapshots(data, mergeFn) {
|
|
|
1011
1055
|
continue;
|
|
1012
1056
|
}
|
|
1013
1057
|
const oldValue = updatedData[key] || {};
|
|
1014
|
-
|
|
1058
|
+
// Snapshot entries are stored as a "shape" of the last known data per key, so by default we only
|
|
1059
|
+
// merge fields that already exist in the snapshot to avoid unintentionally bloating snapshot data.
|
|
1060
|
+
// Some clients need specific fields (like pending status) even when they are missing in the snapshot,
|
|
1061
|
+
// so we allow an explicit, opt-in list of keys to always include during snapshot merges.
|
|
1062
|
+
const snapshotExistingKeys = Object.keys(snapshotData[key] || {});
|
|
1063
|
+
const allowedNewKeys = getSnapshotMergeKeys();
|
|
1064
|
+
const keysToCopy = new Set([...snapshotExistingKeys, ...allowedNewKeys]);
|
|
1065
|
+
const newValue = typeof value === 'object' && value !== null ? utils_1.default.pick(value, [...keysToCopy]) : {};
|
|
1015
1066
|
updatedData = Object.assign(Object.assign({}, updatedData), { [key]: Object.assign(oldValue, newValue) });
|
|
1016
1067
|
}
|
|
1017
1068
|
// Skip the update if there's no data to be merged
|
|
@@ -1083,6 +1134,11 @@ function setWithRetry({ key, value, options }, retryAttempt) {
|
|
|
1083
1134
|
if (!hasChanged && !retryAttempt) {
|
|
1084
1135
|
return updatePromise;
|
|
1085
1136
|
}
|
|
1137
|
+
// If a key is a RAM-only key or a member of RAM-only collection, we skip the step that modifies the storage
|
|
1138
|
+
if (isRamOnlyKey(key)) {
|
|
1139
|
+
OnyxUtils.sendActionToDevTools(OnyxUtils.METHOD.SET, key, valueWithoutNestedNullValues);
|
|
1140
|
+
return updatePromise;
|
|
1141
|
+
}
|
|
1086
1142
|
return storage_1.default.setItem(key, valueWithoutNestedNullValues)
|
|
1087
1143
|
.catch((error) => OnyxUtils.retryOperation(error, setWithRetry, { key, value: valueWithoutNestedNullValues, options }, retryAttempt))
|
|
1088
1144
|
.then(() => {
|
|
@@ -1127,7 +1183,12 @@ function multiSetWithRetry(data, retryAttempt) {
|
|
|
1127
1183
|
OnyxCache_1.default.set(key, value);
|
|
1128
1184
|
return OnyxUtils.scheduleSubscriberUpdate(key, value);
|
|
1129
1185
|
});
|
|
1130
|
-
|
|
1186
|
+
const keyValuePairsToStore = keyValuePairsToSet.filter((keyValuePair) => {
|
|
1187
|
+
const [key] = keyValuePair;
|
|
1188
|
+
// Filter out the RAM-only key value pairs, as they should not be saved to storage
|
|
1189
|
+
return !isRamOnlyKey(key);
|
|
1190
|
+
});
|
|
1191
|
+
return storage_1.default.multiSet(keyValuePairsToStore)
|
|
1131
1192
|
.catch((error) => OnyxUtils.retryOperation(error, multiSetWithRetry, newData, retryAttempt))
|
|
1132
1193
|
.then(() => {
|
|
1133
1194
|
OnyxUtils.sendActionToDevTools(OnyxUtils.METHOD.MULTI_SET, undefined, newData);
|
|
@@ -1187,6 +1248,11 @@ function setCollectionWithRetry({ collectionKey, collection }, retryAttempt) {
|
|
|
1187
1248
|
for (const [key, value] of keyValuePairs)
|
|
1188
1249
|
OnyxCache_1.default.set(key, value);
|
|
1189
1250
|
const updatePromise = OnyxUtils.scheduleNotifyCollectionSubscribers(collectionKey, mutableCollection, previousCollection);
|
|
1251
|
+
// RAM-only keys are not supposed to be saved to storage
|
|
1252
|
+
if (isRamOnlyKey(collectionKey)) {
|
|
1253
|
+
OnyxUtils.sendActionToDevTools(OnyxUtils.METHOD.SET_COLLECTION, undefined, mutableCollection);
|
|
1254
|
+
return updatePromise;
|
|
1255
|
+
}
|
|
1190
1256
|
return storage_1.default.multiSet(keyValuePairs)
|
|
1191
1257
|
.catch((error) => OnyxUtils.retryOperation(error, setCollectionWithRetry, { collectionKey, collection }, retryAttempt))
|
|
1192
1258
|
.then(() => {
|
|
@@ -1278,10 +1344,12 @@ function mergeCollectionWithPatches({ collectionKey, collection, mergeReplaceNul
|
|
|
1278
1344
|
const previousCollectionPromise = Promise.all(existingKeys.map((key) => get(key).then((value) => [key, value]))).then(Object.fromEntries);
|
|
1279
1345
|
// New keys will be added via multiSet while existing keys will be updated using multiMerge
|
|
1280
1346
|
// This is because setting a key that doesn't exist yet with multiMerge will throw errors
|
|
1281
|
-
|
|
1347
|
+
// We can skip this step for RAM-only keys as they should never be saved to storage
|
|
1348
|
+
if (!isRamOnlyKey(collectionKey) && keyValuePairsForExistingCollection.length > 0) {
|
|
1282
1349
|
promises.push(storage_1.default.multiMerge(keyValuePairsForExistingCollection));
|
|
1283
1350
|
}
|
|
1284
|
-
|
|
1351
|
+
// We can skip this step for RAM-only keys as they should never be saved to storage
|
|
1352
|
+
if (!isRamOnlyKey(collectionKey) && keyValuePairsForNewCollection.length > 0) {
|
|
1285
1353
|
promises.push(storage_1.default.multiSet(keyValuePairsForNewCollection));
|
|
1286
1354
|
}
|
|
1287
1355
|
// finalMergedCollection contains all the keys that were merged, without the keys of incompatible updates
|
|
@@ -1344,6 +1412,10 @@ function partialSetCollection({ collectionKey, collection }, retryAttempt) {
|
|
|
1344
1412
|
for (const [key, value] of keyValuePairs)
|
|
1345
1413
|
OnyxCache_1.default.set(key, value);
|
|
1346
1414
|
const updatePromise = scheduleNotifyCollectionSubscribers(collectionKey, mutableCollection, previousCollection);
|
|
1415
|
+
if (isRamOnlyKey(collectionKey)) {
|
|
1416
|
+
sendActionToDevTools(METHOD.SET_COLLECTION, undefined, mutableCollection);
|
|
1417
|
+
return updatePromise;
|
|
1418
|
+
}
|
|
1347
1419
|
return storage_1.default.multiSet(keyValuePairs)
|
|
1348
1420
|
.catch((error) => retryOperation(error, partialSetCollection, { collectionKey, collection }, retryAttempt))
|
|
1349
1421
|
.then(() => {
|
|
@@ -1411,6 +1483,8 @@ const OnyxUtils = {
|
|
|
1411
1483
|
unsubscribeFromKey,
|
|
1412
1484
|
getSkippableCollectionMemberIDs,
|
|
1413
1485
|
setSkippableCollectionMemberIDs,
|
|
1486
|
+
getSnapshotMergeKeys,
|
|
1487
|
+
setSnapshotMergeKeys,
|
|
1414
1488
|
storeKeyBySubscriptions,
|
|
1415
1489
|
deleteKeyBySubscriptions,
|
|
1416
1490
|
addKeyToRecentlyAccessedIfNeeded,
|
|
@@ -1423,6 +1497,7 @@ const OnyxUtils = {
|
|
|
1423
1497
|
setWithRetry,
|
|
1424
1498
|
multiSetWithRetry,
|
|
1425
1499
|
setCollectionWithRetry,
|
|
1500
|
+
isRamOnlyKey,
|
|
1426
1501
|
};
|
|
1427
1502
|
GlobalSettings.addGlobalSettingsChangeListener(({ enablePerformanceMetrics }) => {
|
|
1428
1503
|
if (!enablePerformanceMetrics) {
|
package/dist/types.d.ts
CHANGED
|
@@ -364,6 +364,18 @@ type InitOptions = {
|
|
|
364
364
|
* Additionally, any subscribers from these keys to won't receive any data from Onyx.
|
|
365
365
|
*/
|
|
366
366
|
skippableCollectionMemberIDs?: string[];
|
|
367
|
+
/**
|
|
368
|
+
* Array of keys that when provided to Onyx are flagged as RAM-only keys, and thus are not saved to disk.
|
|
369
|
+
*/
|
|
370
|
+
ramOnlyKeys?: OnyxKey[];
|
|
371
|
+
/**
|
|
372
|
+
* A list of field names that should always be merged into snapshot entries even if those fields are
|
|
373
|
+
* missing in the snapshot. Snapshots are saved "views" of a key's data used to populate read-only
|
|
374
|
+
* or cached lists, and by default Onyx only merges fields that already exist in that saved view.
|
|
375
|
+
* Use this to opt-in to additional fields that must appear in snapshots (for example, pending flags)
|
|
376
|
+
* without hardcoding app-specific logic inside Onyx.
|
|
377
|
+
*/
|
|
378
|
+
snapshotMergeKeys?: string[];
|
|
367
379
|
};
|
|
368
380
|
type GenericFunction = (...args: any[]) => any;
|
|
369
381
|
/**
|
package/dist/useOnyx.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ type UseOnyxOptions<TKey extends OnyxKey, TReturnValue> = {
|
|
|
8
8
|
canEvict?: boolean;
|
|
9
9
|
/**
|
|
10
10
|
* If set to `false`, then no data will be prefilled into the component.
|
|
11
|
+
* @deprecated This param is going to be removed soon. Use RAM-only keys instead.
|
|
11
12
|
*/
|
|
12
13
|
initWithStoredValues?: boolean;
|
|
13
14
|
/**
|