react-native-onyx 3.0.61 → 3.0.63
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 +6 -24
- package/dist/Onyx.d.ts +1 -1
- package/dist/Onyx.js +1 -4
- package/dist/OnyxCache.d.ts +3 -22
- package/dist/OnyxCache.js +8 -70
- package/dist/OnyxConnectionManager.d.ts +0 -9
- package/dist/OnyxConnectionManager.js +2 -50
- package/dist/OnyxSnapshotCache.d.ts +1 -1
- package/dist/OnyxSnapshotCache.js +1 -1
- package/dist/OnyxUtils.d.ts +0 -6
- package/dist/OnyxUtils.js +8 -23
- package/dist/storage/providers/SQLiteProvider.js +0 -6
- package/dist/types.d.ts +1 -7
- package/dist/useOnyx.d.ts +0 -4
- package/dist/useOnyx.js +1 -19
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -314,42 +314,24 @@ If a platform needs to use a separate library (like using MMVK for react-native)
|
|
|
314
314
|
|
|
315
315
|
[Docs](./API.md)
|
|
316
316
|
|
|
317
|
-
#
|
|
317
|
+
# Storage Eviction
|
|
318
318
|
|
|
319
319
|
Different platforms come with varying storage capacities and Onyx has a way to gracefully fail when those storage limits are encountered. When Onyx fails to set or modify a key the following steps are taken:
|
|
320
|
-
1. Onyx looks at a list of
|
|
321
|
-
2. It then deletes this key and retries the original operation
|
|
320
|
+
1. Onyx looks at a list of evictable keys ordered by recent access and locates the least recently accessed one
|
|
321
|
+
2. It then deletes this key from both cache and storage, and retries the original operation
|
|
322
|
+
3. This process repeats up to 5 times until the write succeeds or no more evictable keys are available
|
|
322
323
|
|
|
323
324
|
By default, Onyx will not evict anything from storage and will presume all keys are "unsafe" to remove unless explicitly told otherwise.
|
|
324
325
|
|
|
325
|
-
**To flag a key as safe for removal
|
|
326
|
-
- Add the key to the `evictableKeys` option in `Onyx.init(options)`
|
|
327
|
-
- Implement `canEvict` in the Onyx config for each component subscribing to a key
|
|
328
|
-
- The key will only be deleted when all subscribers return `true` for `canEvict`
|
|
326
|
+
**To flag a key as safe for removal**, add the key to the `evictableKeys` option in `Onyx.init(options)`:
|
|
329
327
|
|
|
330
|
-
e.g.
|
|
331
328
|
```js
|
|
332
329
|
Onyx.init({
|
|
333
330
|
evictableKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS],
|
|
334
331
|
});
|
|
335
332
|
```
|
|
336
333
|
|
|
337
|
-
|
|
338
|
-
const ReportActionsView = ({reportID, isActiveReport}) => {
|
|
339
|
-
const [reportActions] = useOnyx(
|
|
340
|
-
`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}_`,
|
|
341
|
-
{canEvict: () => !isActiveReport}
|
|
342
|
-
);
|
|
343
|
-
|
|
344
|
-
return (
|
|
345
|
-
<View>
|
|
346
|
-
{/* Render with reportActions data */}
|
|
347
|
-
</View>
|
|
348
|
-
);
|
|
349
|
-
};
|
|
350
|
-
|
|
351
|
-
export default ReportActionsView;
|
|
352
|
-
```
|
|
334
|
+
Only individual (non-collection) keys matching the `evictableKeys` patterns will be considered for eviction. Collection keys themselves cannot be evicted — only their individual members can.
|
|
353
335
|
|
|
354
336
|
# Debug mode
|
|
355
337
|
|
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,
|
|
5
|
+
declare function init({ keys, initialKeyStates, evictableKeys, shouldSyncMultipleInstances, 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
|
@@ -47,7 +47,7 @@ const logMessages_1 = __importDefault(require("./logMessages"));
|
|
|
47
47
|
const OnyxConnectionManager_1 = __importDefault(require("./OnyxConnectionManager"));
|
|
48
48
|
const OnyxMerge_1 = __importDefault(require("./OnyxMerge"));
|
|
49
49
|
/** Initialize the store with actions and listening for storage events */
|
|
50
|
-
function init({ keys = {}, initialKeyStates = {}, evictableKeys = [],
|
|
50
|
+
function init({ keys = {}, initialKeyStates = {}, evictableKeys = [], shouldSyncMultipleInstances = !!global.localStorage, enableDevTools = true, skippableCollectionMemberIDs = [], ramOnlyKeys = [], snapshotMergeKeys = [], }) {
|
|
51
51
|
var _a;
|
|
52
52
|
(0, DevTools_1.initDevTools)(enableDevTools);
|
|
53
53
|
storage_1.default.init();
|
|
@@ -69,9 +69,6 @@ function init({ keys = {}, initialKeyStates = {}, evictableKeys = [], maxCachedK
|
|
|
69
69
|
OnyxUtils_1.default.keyChanged(key, value, undefined, isKeyCollectionMember);
|
|
70
70
|
});
|
|
71
71
|
}
|
|
72
|
-
if (maxCachedKeysCount > 0) {
|
|
73
|
-
OnyxCache_1.default.setRecentKeysLimit(maxCachedKeysCount);
|
|
74
|
-
}
|
|
75
72
|
OnyxUtils_1.default.initStoreValues(keys, initialKeyStates, evictableKeys);
|
|
76
73
|
// Initialize all of our keys with data provided then give green light to any pending connections.
|
|
77
74
|
// addEvictableKeysToRecentlyAccessedList must run after initializeWithDefaultKeyStates because
|
package/dist/OnyxCache.d.ts
CHANGED
|
@@ -15,8 +15,6 @@ declare class OnyxCache {
|
|
|
15
15
|
private storageKeys;
|
|
16
16
|
/** A list of keys where a nullish value has been fetched from storage before, but the key still exists in cache */
|
|
17
17
|
private nullishStorageKeys;
|
|
18
|
-
/** Unique list of keys maintained in access order (most recent at the end) */
|
|
19
|
-
private recentKeys;
|
|
20
18
|
/** A map of cached values */
|
|
21
19
|
private storageMap;
|
|
22
20
|
/** Cache of complete collection data objects for O(1) retrieval */
|
|
@@ -26,12 +24,8 @@ declare class OnyxCache {
|
|
|
26
24
|
* Using a map yields better performance on operations such a delete
|
|
27
25
|
*/
|
|
28
26
|
private pendingPromises;
|
|
29
|
-
/** Maximum size of the keys store din cache */
|
|
30
|
-
private maxRecentKeysSize;
|
|
31
27
|
/** List of keys that are safe to remove when we reach max storage */
|
|
32
28
|
private evictionAllowList;
|
|
33
|
-
/** Map of keys and connection arrays whose keys will never be automatically evicted */
|
|
34
|
-
private evictionBlocklist;
|
|
35
29
|
/** List of keys that have been directly subscribed to or recently modified from least to most recent */
|
|
36
30
|
private recentlyAccessedKeys;
|
|
37
31
|
constructor();
|
|
@@ -61,11 +55,8 @@ declare class OnyxCache {
|
|
|
61
55
|
clearNullishStorageKeys(): void;
|
|
62
56
|
/** Check whether cache has data for the given key */
|
|
63
57
|
hasCacheForKey(key: OnyxKey): boolean;
|
|
64
|
-
/**
|
|
65
|
-
|
|
66
|
-
* @param [shouldReindexCache] – This is an LRU cache, and by default accessing a value will make it become last in line to be evicted. This flag can be used to skip that and just access the value directly without side-effects.
|
|
67
|
-
*/
|
|
68
|
-
get(key: OnyxKey, shouldReindexCache?: boolean): OnyxValue<OnyxKey>;
|
|
58
|
+
/** Get a cached value from storage */
|
|
59
|
+
get(key: OnyxKey): OnyxValue<OnyxKey>;
|
|
69
60
|
/**
|
|
70
61
|
* Set's a key value in cache
|
|
71
62
|
* Adds the key to the storage keys list as well
|
|
@@ -96,12 +87,6 @@ declare class OnyxCache {
|
|
|
96
87
|
* @param taskName - unique name for the task
|
|
97
88
|
*/
|
|
98
89
|
captureTask(taskName: CacheTask, promise: Promise<OnyxValue<OnyxKey>>): Promise<OnyxValue<OnyxKey>>;
|
|
99
|
-
/** Adds a key to the top of the recently accessed keys */
|
|
100
|
-
addToAccessedKeys(key: OnyxKey): void;
|
|
101
|
-
/** Remove keys that don't fall into the range of recently used keys */
|
|
102
|
-
removeLeastRecentlyUsedKeys(): void;
|
|
103
|
-
/** Set the recent keys list size */
|
|
104
|
-
setRecentKeysLimit(limit: number): void;
|
|
105
90
|
/** Check if the value has changed */
|
|
106
91
|
hasValueChanged(key: OnyxKey, value: OnyxValue<OnyxKey>): boolean;
|
|
107
92
|
/**
|
|
@@ -109,10 +94,6 @@ declare class OnyxCache {
|
|
|
109
94
|
* @param keys - Array of OnyxKeys that are safe to evict
|
|
110
95
|
*/
|
|
111
96
|
setEvictionAllowList(keys: OnyxKey[]): void;
|
|
112
|
-
/**
|
|
113
|
-
* Get the eviction block list that prevents keys from being evicted
|
|
114
|
-
*/
|
|
115
|
-
getEvictionBlocklist(): Record<OnyxKey, string[] | undefined>;
|
|
116
97
|
/**
|
|
117
98
|
* Checks to see if this key has been flagged as safe for removal.
|
|
118
99
|
* @param testKey - Key to check
|
|
@@ -138,7 +119,7 @@ declare class OnyxCache {
|
|
|
138
119
|
*/
|
|
139
120
|
addEvictableKeysToRecentlyAccessedList(isCollectionKeyFn: (key: OnyxKey) => boolean, getAllKeysFn: () => Promise<Set<OnyxKey>>): Promise<void>;
|
|
140
121
|
/**
|
|
141
|
-
* Finds
|
|
122
|
+
* Finds the least recently accessed key that can be safely evicted from storage.
|
|
142
123
|
*/
|
|
143
124
|
getKeyForEviction(): OnyxKey | undefined;
|
|
144
125
|
/**
|
package/dist/OnyxCache.js
CHANGED
|
@@ -21,22 +21,17 @@ exports.TASK = TASK;
|
|
|
21
21
|
*/
|
|
22
22
|
class OnyxCache {
|
|
23
23
|
constructor() {
|
|
24
|
-
/** Maximum size of the keys store din cache */
|
|
25
|
-
this.maxRecentKeysSize = 0;
|
|
26
24
|
/** List of keys that are safe to remove when we reach max storage */
|
|
27
25
|
this.evictionAllowList = [];
|
|
28
|
-
/** Map of keys and connection arrays whose keys will never be automatically evicted */
|
|
29
|
-
this.evictionBlocklist = {};
|
|
30
26
|
/** List of keys that have been directly subscribed to or recently modified from least to most recent */
|
|
31
27
|
this.recentlyAccessedKeys = new Set();
|
|
32
28
|
this.storageKeys = new Set();
|
|
33
29
|
this.nullishStorageKeys = new Set();
|
|
34
|
-
this.recentKeys = new Set();
|
|
35
30
|
this.storageMap = {};
|
|
36
31
|
this.collectionData = {};
|
|
37
32
|
this.pendingPromises = new Map();
|
|
38
33
|
// bind all public methods to prevent problems with `this`
|
|
39
|
-
(0, bindAll_1.default)(this, 'getAllKeys', 'get', 'hasCacheForKey', 'addKey', 'addNullishStorageKey', 'hasNullishStorageKey', 'clearNullishStorageKeys', 'set', 'drop', 'merge', 'hasPendingTask', 'getTaskPromise', 'captureTask', '
|
|
34
|
+
(0, bindAll_1.default)(this, 'getAllKeys', 'get', 'hasCacheForKey', 'addKey', 'addNullishStorageKey', 'hasNullishStorageKey', 'clearNullishStorageKeys', 'set', 'drop', 'merge', 'hasPendingTask', 'getTaskPromise', 'captureTask', 'setAllKeys', 'setEvictionAllowList', 'isEvictableKey', 'removeLastAccessedKey', 'addLastAccessedKey', 'addEvictableKeysToRecentlyAccessedList', 'getKeyForEviction', 'setCollectionKeys', 'getCollectionData', 'hasValueChanged');
|
|
40
35
|
}
|
|
41
36
|
/** Get all the storage keys */
|
|
42
37
|
getAllKeys() {
|
|
@@ -82,14 +77,8 @@ class OnyxCache {
|
|
|
82
77
|
hasCacheForKey(key) {
|
|
83
78
|
return this.storageMap[key] !== undefined || this.hasNullishStorageKey(key);
|
|
84
79
|
}
|
|
85
|
-
/**
|
|
86
|
-
|
|
87
|
-
* @param [shouldReindexCache] – This is an LRU cache, and by default accessing a value will make it become last in line to be evicted. This flag can be used to skip that and just access the value directly without side-effects.
|
|
88
|
-
*/
|
|
89
|
-
get(key, shouldReindexCache = true) {
|
|
90
|
-
if (shouldReindexCache) {
|
|
91
|
-
this.addToAccessedKeys(key);
|
|
92
|
-
}
|
|
80
|
+
/** Get a cached value from storage */
|
|
81
|
+
get(key) {
|
|
93
82
|
return this.storageMap[key];
|
|
94
83
|
}
|
|
95
84
|
/**
|
|
@@ -98,7 +87,6 @@ class OnyxCache {
|
|
|
98
87
|
*/
|
|
99
88
|
set(key, value) {
|
|
100
89
|
this.addKey(key);
|
|
101
|
-
this.addToAccessedKeys(key);
|
|
102
90
|
// When a key is explicitly set in cache, we can remove it from the list of nullish keys,
|
|
103
91
|
// since it will either be set to a non nullish value or removed from the cache completely.
|
|
104
92
|
this.nullishStorageKeys.delete(key);
|
|
@@ -134,7 +122,6 @@ class OnyxCache {
|
|
|
134
122
|
delete this.collectionData[key];
|
|
135
123
|
}
|
|
136
124
|
this.storageKeys.delete(key);
|
|
137
|
-
this.recentKeys.delete(key);
|
|
138
125
|
OnyxKeys_1.default.deregisterMemberKey(key);
|
|
139
126
|
}
|
|
140
127
|
/**
|
|
@@ -151,7 +138,6 @@ class OnyxCache {
|
|
|
151
138
|
}).result);
|
|
152
139
|
for (const [key, value] of Object.entries(data)) {
|
|
153
140
|
this.addKey(key);
|
|
154
|
-
this.addToAccessedKeys(key);
|
|
155
141
|
const collectionKey = OnyxKeys_1.default.getCollectionKey(key);
|
|
156
142
|
if (value === null || value === undefined) {
|
|
157
143
|
this.addNullishStorageKey(key);
|
|
@@ -200,48 +186,9 @@ class OnyxCache {
|
|
|
200
186
|
this.pendingPromises.set(taskName, returnPromise);
|
|
201
187
|
return returnPromise;
|
|
202
188
|
}
|
|
203
|
-
/** Adds a key to the top of the recently accessed keys */
|
|
204
|
-
addToAccessedKeys(key) {
|
|
205
|
-
this.recentKeys.delete(key);
|
|
206
|
-
this.recentKeys.add(key);
|
|
207
|
-
}
|
|
208
|
-
/** Remove keys that don't fall into the range of recently used keys */
|
|
209
|
-
removeLeastRecentlyUsedKeys() {
|
|
210
|
-
const numKeysToRemove = this.recentKeys.size - this.maxRecentKeysSize;
|
|
211
|
-
if (numKeysToRemove <= 0) {
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
const iterator = this.recentKeys.values();
|
|
215
|
-
const keysToRemove = [];
|
|
216
|
-
const recentKeysArray = Array.from(this.recentKeys);
|
|
217
|
-
const mostRecentKey = recentKeysArray[recentKeysArray.length - 1];
|
|
218
|
-
let iterResult = iterator.next();
|
|
219
|
-
while (!iterResult.done) {
|
|
220
|
-
const key = iterResult.value;
|
|
221
|
-
// Don't consider the most recently accessed key for eviction
|
|
222
|
-
// This ensures we don't immediately evict a key we just added
|
|
223
|
-
if (key !== undefined && key !== mostRecentKey && this.isEvictableKey(key)) {
|
|
224
|
-
keysToRemove.push(key);
|
|
225
|
-
}
|
|
226
|
-
iterResult = iterator.next();
|
|
227
|
-
}
|
|
228
|
-
for (const key of keysToRemove) {
|
|
229
|
-
delete this.storageMap[key];
|
|
230
|
-
// Remove from collection data cache if this is a collection member
|
|
231
|
-
const collectionKey = OnyxKeys_1.default.getCollectionKey(key);
|
|
232
|
-
if (collectionKey && this.collectionData[collectionKey]) {
|
|
233
|
-
delete this.collectionData[collectionKey][key];
|
|
234
|
-
}
|
|
235
|
-
this.recentKeys.delete(key);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
/** Set the recent keys list size */
|
|
239
|
-
setRecentKeysLimit(limit) {
|
|
240
|
-
this.maxRecentKeysSize = limit;
|
|
241
|
-
}
|
|
242
189
|
/** Check if the value has changed */
|
|
243
190
|
hasValueChanged(key, value) {
|
|
244
|
-
const currentValue = this.get(key
|
|
191
|
+
const currentValue = this.get(key);
|
|
245
192
|
return !(0, fast_equals_1.deepEqual)(currentValue, value);
|
|
246
193
|
}
|
|
247
194
|
/**
|
|
@@ -251,12 +198,6 @@ class OnyxCache {
|
|
|
251
198
|
setEvictionAllowList(keys) {
|
|
252
199
|
this.evictionAllowList = keys;
|
|
253
200
|
}
|
|
254
|
-
/**
|
|
255
|
-
* Get the eviction block list that prevents keys from being evicted
|
|
256
|
-
*/
|
|
257
|
-
getEvictionBlocklist() {
|
|
258
|
-
return this.evictionBlocklist;
|
|
259
|
-
}
|
|
260
201
|
/**
|
|
261
202
|
* Checks to see if this key has been flagged as safe for removal.
|
|
262
203
|
* @param testKey - Key to check
|
|
@@ -304,15 +245,12 @@ class OnyxCache {
|
|
|
304
245
|
});
|
|
305
246
|
}
|
|
306
247
|
/**
|
|
307
|
-
* Finds
|
|
248
|
+
* Finds the least recently accessed key that can be safely evicted from storage.
|
|
308
249
|
*/
|
|
309
250
|
getKeyForEviction() {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
return undefined;
|
|
251
|
+
// recentlyAccessedKeys is ordered from least to most recently accessed,
|
|
252
|
+
// so the first element is the best candidate for eviction.
|
|
253
|
+
return this.recentlyAccessedKeys.values().next().value;
|
|
316
254
|
}
|
|
317
255
|
/**
|
|
318
256
|
* Set the collection keys for optimized storage
|
|
@@ -72,15 +72,6 @@ declare class OnyxConnectionManager {
|
|
|
72
72
|
* Refreshes the connection manager's session ID.
|
|
73
73
|
*/
|
|
74
74
|
refreshSessionID(): void;
|
|
75
|
-
/**
|
|
76
|
-
* Adds the connection to the eviction block list. Connections added to this list can never be evicted.
|
|
77
|
-
* */
|
|
78
|
-
addToEvictionBlockList(connection: Connection): void;
|
|
79
|
-
/**
|
|
80
|
-
* Removes a connection previously added to this list
|
|
81
|
-
* which will enable it to be evicted again.
|
|
82
|
-
*/
|
|
83
|
-
removeFromEvictionBlockList(connection: Connection): void;
|
|
84
75
|
}
|
|
85
76
|
declare const connectionManager: OnyxConnectionManager;
|
|
86
77
|
export default connectionManager;
|
|
@@ -41,7 +41,6 @@ const Logger = __importStar(require("./Logger"));
|
|
|
41
41
|
const OnyxUtils_1 = __importDefault(require("./OnyxUtils"));
|
|
42
42
|
const OnyxKeys_1 = __importDefault(require("./OnyxKeys"));
|
|
43
43
|
const Str = __importStar(require("./Str"));
|
|
44
|
-
const OnyxCache_1 = __importDefault(require("./OnyxCache"));
|
|
45
44
|
const OnyxSnapshotCache_1 = __importDefault(require("./OnyxSnapshotCache"));
|
|
46
45
|
/**
|
|
47
46
|
* Manages Onyx connections of `Onyx.connect()` and `useOnyx()` subscribers.
|
|
@@ -52,7 +51,7 @@ class OnyxConnectionManager {
|
|
|
52
51
|
this.lastCallbackID = 0;
|
|
53
52
|
this.sessionID = Str.guid();
|
|
54
53
|
// Binds all public methods to prevent problems with `this`.
|
|
55
|
-
(0, bindAll_1.default)(this, 'generateConnectionID', 'fireCallbacks', 'connect', 'disconnect', 'disconnectAll', 'refreshSessionID'
|
|
54
|
+
(0, bindAll_1.default)(this, 'generateConnectionID', 'fireCallbacks', 'connect', 'disconnect', 'disconnectAll', 'refreshSessionID');
|
|
56
55
|
}
|
|
57
56
|
/**
|
|
58
57
|
* Generates a connection ID based on the `connectOptions` object passed to the function.
|
|
@@ -164,7 +163,6 @@ class OnyxConnectionManager {
|
|
|
164
163
|
// If the connection's callbacks map is empty we can safely unsubscribe from the Onyx key.
|
|
165
164
|
if (connectionMetadata.callbacks.size === 0) {
|
|
166
165
|
OnyxUtils_1.default.unsubscribeFromKey(connectionMetadata.subscriptionID);
|
|
167
|
-
this.removeFromEvictionBlockList(connection);
|
|
168
166
|
this.connectionsMap.delete(connection.id);
|
|
169
167
|
}
|
|
170
168
|
}
|
|
@@ -172,11 +170,8 @@ class OnyxConnectionManager {
|
|
|
172
170
|
* Disconnect all subscribers from Onyx.
|
|
173
171
|
*/
|
|
174
172
|
disconnectAll() {
|
|
175
|
-
for (const
|
|
173
|
+
for (const connectionMetadata of this.connectionsMap.values()) {
|
|
176
174
|
OnyxUtils_1.default.unsubscribeFromKey(connectionMetadata.subscriptionID);
|
|
177
|
-
for (const callbackID of connectionMetadata.callbacks.keys()) {
|
|
178
|
-
this.removeFromEvictionBlockList({ id: connectionID, callbackID });
|
|
179
|
-
}
|
|
180
175
|
}
|
|
181
176
|
this.connectionsMap.clear();
|
|
182
177
|
// Clear snapshot cache when all connections are disconnected
|
|
@@ -190,49 +185,6 @@ class OnyxConnectionManager {
|
|
|
190
185
|
// Clear snapshot cache when session refreshes to avoid stale cache issues
|
|
191
186
|
OnyxSnapshotCache_1.default.clear();
|
|
192
187
|
}
|
|
193
|
-
/**
|
|
194
|
-
* Adds the connection to the eviction block list. Connections added to this list can never be evicted.
|
|
195
|
-
* */
|
|
196
|
-
addToEvictionBlockList(connection) {
|
|
197
|
-
var _a;
|
|
198
|
-
if (!connection) {
|
|
199
|
-
Logger.logInfo(`[ConnectionManager] Attempted to add connection to eviction block list passing an undefined connection object.`);
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
const connectionMetadata = this.connectionsMap.get(connection.id);
|
|
203
|
-
if (!connectionMetadata) {
|
|
204
|
-
Logger.logInfo(`[ConnectionManager] Attempted to add connection to eviction block list but no connection was found.`);
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
const evictionBlocklist = OnyxCache_1.default.getEvictionBlocklist();
|
|
208
|
-
if (!evictionBlocklist[connectionMetadata.onyxKey]) {
|
|
209
|
-
evictionBlocklist[connectionMetadata.onyxKey] = [];
|
|
210
|
-
}
|
|
211
|
-
(_a = evictionBlocklist[connectionMetadata.onyxKey]) === null || _a === void 0 ? void 0 : _a.push(`${connection.id}_${connection.callbackID}`);
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* Removes a connection previously added to this list
|
|
215
|
-
* which will enable it to be evicted again.
|
|
216
|
-
*/
|
|
217
|
-
removeFromEvictionBlockList(connection) {
|
|
218
|
-
var _a, _b, _c;
|
|
219
|
-
if (!connection) {
|
|
220
|
-
Logger.logInfo(`[ConnectionManager] Attempted to remove connection from eviction block list passing an undefined connection object.`);
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
|
-
const connectionMetadata = this.connectionsMap.get(connection.id);
|
|
224
|
-
if (!connectionMetadata) {
|
|
225
|
-
Logger.logInfo(`[ConnectionManager] Attempted to remove connection from eviction block list but no connection was found.`);
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
const evictionBlocklist = OnyxCache_1.default.getEvictionBlocklist();
|
|
229
|
-
evictionBlocklist[connectionMetadata.onyxKey] =
|
|
230
|
-
(_b = (_a = evictionBlocklist[connectionMetadata.onyxKey]) === null || _a === void 0 ? void 0 : _a.filter((evictionKey) => evictionKey !== `${connection.id}_${connection.callbackID}`)) !== null && _b !== void 0 ? _b : [];
|
|
231
|
-
// Remove the key if there are no more subscribers.
|
|
232
|
-
if (((_c = evictionBlocklist[connectionMetadata.onyxKey]) === null || _c === void 0 ? void 0 : _c.length) === 0) {
|
|
233
|
-
delete evictionBlocklist[connectionMetadata.onyxKey];
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
188
|
}
|
|
237
189
|
const connectionManager = new OnyxConnectionManager();
|
|
238
190
|
exports.default = connectionManager;
|
|
@@ -40,7 +40,7 @@ declare class OnyxSnapshotCache {
|
|
|
40
40
|
* - `selector`: Different selectors produce different results, so each selector needs its own cache entry
|
|
41
41
|
* - `initWithStoredValues`: This flag changes the initial loading behavior and affects the returned fetch status
|
|
42
42
|
*
|
|
43
|
-
* Other options like `
|
|
43
|
+
* Other options like `reuseConnection` don't affect the data transformation
|
|
44
44
|
* or timing behavior of getSnapshot, so they're excluded from the cache key for better cache hit rates.
|
|
45
45
|
*/
|
|
46
46
|
registerConsumer<TKey extends OnyxKey, TReturnValue>(options: Pick<UseOnyxOptions<TKey, TReturnValue>, 'selector' | 'initWithStoredValues'>): string;
|
|
@@ -37,7 +37,7 @@ class OnyxSnapshotCache {
|
|
|
37
37
|
* - `selector`: Different selectors produce different results, so each selector needs its own cache entry
|
|
38
38
|
* - `initWithStoredValues`: This flag changes the initial loading behavior and affects the returned fetch status
|
|
39
39
|
*
|
|
40
|
-
* Other options like `
|
|
40
|
+
* Other options like `reuseConnection` don't affect the data transformation
|
|
41
41
|
* or timing behavior of getSnapshot, so they're excluded from the cache key for better cache hit rates.
|
|
42
42
|
*/
|
|
43
43
|
registerConsumer(options) {
|
package/dist/OnyxUtils.d.ts
CHANGED
|
@@ -127,11 +127,6 @@ declare function keyChanged<TKey extends OnyxKey>(key: TKey, value: OnyxValue<TK
|
|
|
127
127
|
* Sends the data obtained from the keys to the connection.
|
|
128
128
|
*/
|
|
129
129
|
declare function sendDataToConnection<TKey extends OnyxKey>(mapping: CallbackToStateMapping<TKey>, matchedKey: TKey | undefined): void;
|
|
130
|
-
/**
|
|
131
|
-
* We check to see if this key is flagged as safe for eviction and add it to the recentlyAccessedKeys list so that when we
|
|
132
|
-
* run out of storage the least recently accessed key can be removed.
|
|
133
|
-
*/
|
|
134
|
-
declare function addKeyToRecentlyAccessedIfNeeded<TKey extends OnyxKey>(key: TKey): void;
|
|
135
130
|
/**
|
|
136
131
|
* Gets the data for a given an array of matching keys, combines them into an object, and sends the result back to the subscriber.
|
|
137
132
|
*/
|
|
@@ -312,7 +307,6 @@ declare const OnyxUtils: {
|
|
|
312
307
|
setSnapshotMergeKeys: typeof setSnapshotMergeKeys;
|
|
313
308
|
storeKeyBySubscriptions: typeof storeKeyBySubscriptions;
|
|
314
309
|
deleteKeyBySubscriptions: typeof deleteKeyBySubscriptions;
|
|
315
|
-
addKeyToRecentlyAccessedIfNeeded: typeof addKeyToRecentlyAccessedIfNeeded;
|
|
316
310
|
reduceCollectionWithSelector: typeof reduceCollectionWithSelector;
|
|
317
311
|
updateSnapshots: typeof updateSnapshots;
|
|
318
312
|
mergeCollectionWithPatches: typeof mergeCollectionWithPatches;
|
package/dist/OnyxUtils.js
CHANGED
|
@@ -521,8 +521,8 @@ function keysChanged(collectionKey, partialCollection, partialPreviousCollection
|
|
|
521
521
|
*/
|
|
522
522
|
function keyChanged(key, value, canUpdateSubscriber = () => true, isProcessingCollectionUpdate = false) {
|
|
523
523
|
var _a, _b;
|
|
524
|
-
// Add or remove this key from the recentlyAccessedKeys
|
|
525
|
-
if (value !== null) {
|
|
524
|
+
// Add or remove this key from the recentlyAccessedKeys list
|
|
525
|
+
if (value !== null && value !== undefined) {
|
|
526
526
|
OnyxCache_1.default.addLastAccessedKey(key, OnyxKeys_1.default.isCollectionKey(key));
|
|
527
527
|
}
|
|
528
528
|
else {
|
|
@@ -616,19 +616,6 @@ function sendDataToConnection(mapping, matchedKey) {
|
|
|
616
616
|
}
|
|
617
617
|
(_b = (_a = mapping).callback) === null || _b === void 0 ? void 0 : _b.call(_a, value, matchedKey);
|
|
618
618
|
}
|
|
619
|
-
/**
|
|
620
|
-
* We check to see if this key is flagged as safe for eviction and add it to the recentlyAccessedKeys list so that when we
|
|
621
|
-
* run out of storage the least recently accessed key can be removed.
|
|
622
|
-
*/
|
|
623
|
-
function addKeyToRecentlyAccessedIfNeeded(key) {
|
|
624
|
-
if (!OnyxCache_1.default.isEvictableKey(key)) {
|
|
625
|
-
return;
|
|
626
|
-
}
|
|
627
|
-
// Add the key to recentKeys first (this makes it the most recent key)
|
|
628
|
-
OnyxCache_1.default.addToAccessedKeys(key);
|
|
629
|
-
// Try to free some cache whenever we connect to a safe eviction key
|
|
630
|
-
OnyxCache_1.default.removeLeastRecentlyUsedKeys();
|
|
631
|
-
}
|
|
632
619
|
/**
|
|
633
620
|
* Gets the data for a given an array of matching keys, combines them into an object, and sends the result back to the subscriber.
|
|
634
621
|
*/
|
|
@@ -683,7 +670,7 @@ function retryOperation(error, onyxMethod, defaultParams, retryAttempt) {
|
|
|
683
670
|
// @ts-expect-error No overload matches this call.
|
|
684
671
|
return onyxMethod(defaultParams, nextRetryAttempt);
|
|
685
672
|
}
|
|
686
|
-
// Find the
|
|
673
|
+
// Find the least recently accessed evictable key that we can remove
|
|
687
674
|
const keyForRemoval = OnyxCache_1.default.getKeyForEviction();
|
|
688
675
|
if (!keyForRemoval) {
|
|
689
676
|
// If we have no acceptable keys to remove then we are possibly trying to save mission critical data. If this is the case,
|
|
@@ -692,7 +679,7 @@ function retryOperation(error, onyxMethod, defaultParams, retryAttempt) {
|
|
|
692
679
|
Logger.logAlert('Out of storage. But found no acceptable keys to remove.');
|
|
693
680
|
return reportStorageQuota();
|
|
694
681
|
}
|
|
695
|
-
// Remove the least recently
|
|
682
|
+
// Remove the least recently accessed key and retry.
|
|
696
683
|
Logger.logInfo(`Out of storage. Evicting least recently accessed key (${keyForRemoval}) and retrying.`);
|
|
697
684
|
reportStorageQuota();
|
|
698
685
|
// @ts-expect-error No overload matches this call.
|
|
@@ -707,9 +694,6 @@ function broadcastUpdate(key, value, hasChanged) {
|
|
|
707
694
|
if (hasChanged) {
|
|
708
695
|
OnyxCache_1.default.set(key, value);
|
|
709
696
|
}
|
|
710
|
-
else {
|
|
711
|
-
OnyxCache_1.default.addToAccessedKeys(key);
|
|
712
|
-
}
|
|
713
697
|
keyChanged(key, value, (subscriber) => hasChanged || (subscriber === null || subscriber === void 0 ? void 0 : subscriber.initWithStoredValues) === false);
|
|
714
698
|
}
|
|
715
699
|
function hasPendingMergeForKey(key) {
|
|
@@ -893,7 +877,9 @@ function subscribeToKey(connectOptions) {
|
|
|
893
877
|
}
|
|
894
878
|
// Commit connection only after init passes
|
|
895
879
|
deferredInitTask.promise
|
|
896
|
-
.then(
|
|
880
|
+
// This first .then() adds a microtask tick for compatibility reasons and
|
|
881
|
+
// to ensure subscribers don't receive an extra initial callback before Onyx.update() data arrives.
|
|
882
|
+
.then(() => undefined)
|
|
897
883
|
.then(() => {
|
|
898
884
|
// Performance improvement
|
|
899
885
|
// If the mapping is connected to an onyx key that is not a collection
|
|
@@ -1060,7 +1046,7 @@ function setWithRetry({ key, value, options }, retryAttempt) {
|
|
|
1060
1046
|
if (value === undefined) {
|
|
1061
1047
|
return Promise.resolve();
|
|
1062
1048
|
}
|
|
1063
|
-
const existingValue = OnyxCache_1.default.get(key
|
|
1049
|
+
const existingValue = OnyxCache_1.default.get(key);
|
|
1064
1050
|
// If the existing value as well as the new value are null, we can return early.
|
|
1065
1051
|
if (existingValue === undefined && value === null) {
|
|
1066
1052
|
return Promise.resolve();
|
|
@@ -1439,7 +1425,6 @@ const OnyxUtils = {
|
|
|
1439
1425
|
setSnapshotMergeKeys,
|
|
1440
1426
|
storeKeyBySubscriptions,
|
|
1441
1427
|
deleteKeyBySubscriptions,
|
|
1442
|
-
addKeyToRecentlyAccessedIfNeeded,
|
|
1443
1428
|
reduceCollectionWithSelector,
|
|
1444
1429
|
updateSnapshots,
|
|
1445
1430
|
mergeCollectionWithPatches,
|
|
@@ -6,12 +6,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const react_native_nitro_sqlite_1 = require("react-native-nitro-sqlite");
|
|
7
7
|
const react_native_device_info_1 = require("react-native-device-info");
|
|
8
8
|
const utils_1 = __importDefault(require("../../utils"));
|
|
9
|
-
// By default, NitroSQLite does not accept nullish values due to current limitations in Nitro Modules.
|
|
10
|
-
// This flag enables a feature in NitroSQLite that allows for nullish values to be passed to operations, such as "execute" or "executeBatch".
|
|
11
|
-
// Simple null handling can potentially add a minor performance overhead,
|
|
12
|
-
// since parameters and results from SQLite queries need to be parsed from and to JavaScript nullish values.
|
|
13
|
-
// https://github.com/margelo/react-native-nitro-sqlite#sending-and-receiving-nullish-values
|
|
14
|
-
(0, react_native_nitro_sqlite_1.enableSimpleNullHandling)();
|
|
15
9
|
const DB_NAME = 'OnyxDB';
|
|
16
10
|
/**
|
|
17
11
|
* Prevents the stringifying of the object markers.
|
package/dist/types.d.ts
CHANGED
|
@@ -334,15 +334,9 @@ type InitOptions = {
|
|
|
334
334
|
initialKeyStates?: Partial<OnyxInputKeyValueMapping>;
|
|
335
335
|
/**
|
|
336
336
|
* This is an array of keys (individual or collection patterns) that when provided to Onyx are flagged
|
|
337
|
-
* as "safe" for removal.
|
|
337
|
+
* as "safe" for removal.
|
|
338
338
|
*/
|
|
339
339
|
evictableKeys?: OnyxKey[];
|
|
340
|
-
/**
|
|
341
|
-
* Sets how many recent keys should we try to keep in cache
|
|
342
|
-
* Setting this to 0 would practically mean no cache
|
|
343
|
-
* We try to free cache when we connect to a safe eviction key
|
|
344
|
-
*/
|
|
345
|
-
maxCachedKeysCount?: number;
|
|
346
340
|
/**
|
|
347
341
|
* Auto synchronize storage events between multiple instances
|
|
348
342
|
* of Onyx running in different tabs/windows. Defaults to true for platforms that support local storage (web/desktop)
|
package/dist/useOnyx.d.ts
CHANGED
|
@@ -2,10 +2,6 @@ import type { DependencyList } from 'react';
|
|
|
2
2
|
import type { OnyxKey, OnyxValue } from './types';
|
|
3
3
|
type UseOnyxSelector<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>> = (data: OnyxValue<TKey> | undefined) => TReturnValue;
|
|
4
4
|
type UseOnyxOptions<TKey extends OnyxKey, TReturnValue> = {
|
|
5
|
-
/**
|
|
6
|
-
* Determines if this key in this subscription is safe to be evicted.
|
|
7
|
-
*/
|
|
8
|
-
canEvict?: boolean;
|
|
9
5
|
/**
|
|
10
6
|
* If set to `false`, then no data will be prefilled into the component.
|
|
11
7
|
* @deprecated This param is going to be removed soon. Use RAM-only keys instead.
|
package/dist/useOnyx.js
CHANGED
|
@@ -132,20 +132,6 @@ function useOnyx(key, options, dependencies = []) {
|
|
|
132
132
|
onStoreChangeFnRef.current();
|
|
133
133
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
134
134
|
}, [...dependencies]);
|
|
135
|
-
const checkEvictableKey = (0, react_1.useCallback)(() => {
|
|
136
|
-
if ((options === null || options === void 0 ? void 0 : options.canEvict) === undefined || !connectionRef.current) {
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
if (!OnyxCache_1.default.isEvictableKey(key)) {
|
|
140
|
-
throw new Error(`canEvict can't be used on key '${key}'. This key must explicitly be flagged as safe for removal by adding it to Onyx.init({evictableKeys: []}).`);
|
|
141
|
-
}
|
|
142
|
-
if (options.canEvict) {
|
|
143
|
-
OnyxConnectionManager_1.default.removeFromEvictionBlockList(connectionRef.current);
|
|
144
|
-
}
|
|
145
|
-
else {
|
|
146
|
-
OnyxConnectionManager_1.default.addToEvictionBlockList(connectionRef.current);
|
|
147
|
-
}
|
|
148
|
-
}, [key, options === null || options === void 0 ? void 0 : options.canEvict]);
|
|
149
135
|
// Tracks the last memoizedSelector reference that getSnapshot() has computed with.
|
|
150
136
|
// When the selector changes, this mismatch forces getSnapshot() to re-evaluate
|
|
151
137
|
// even if all other conditions (isFirstConnection, shouldGetCachedValue, key) are false.
|
|
@@ -262,7 +248,6 @@ function useOnyx(key, options, dependencies = []) {
|
|
|
262
248
|
waitForCollectionCallback: OnyxKeys_1.default.isCollectionKey(key),
|
|
263
249
|
reuseConnection: options === null || options === void 0 ? void 0 : options.reuseConnection,
|
|
264
250
|
});
|
|
265
|
-
checkEvictableKey();
|
|
266
251
|
return () => {
|
|
267
252
|
if (!connectionRef.current) {
|
|
268
253
|
return;
|
|
@@ -272,10 +257,7 @@ function useOnyx(key, options, dependencies = []) {
|
|
|
272
257
|
isConnectingRef.current = false;
|
|
273
258
|
onStoreChangeFnRef.current = null;
|
|
274
259
|
};
|
|
275
|
-
}, [key, options === null || options === void 0 ? void 0 : options.initWithStoredValues, options === null || options === void 0 ? void 0 : options.reuseConnection
|
|
276
|
-
(0, react_1.useEffect)(() => {
|
|
277
|
-
checkEvictableKey();
|
|
278
|
-
}, [checkEvictableKey]);
|
|
260
|
+
}, [key, options === null || options === void 0 ? void 0 : options.initWithStoredValues, options === null || options === void 0 ? void 0 : options.reuseConnection]);
|
|
279
261
|
const result = (0, react_1.useSyncExternalStore)(subscribe, getSnapshot);
|
|
280
262
|
return result;
|
|
281
263
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-onyx",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.63",
|
|
4
4
|
"author": "Expensify, Inc.",
|
|
5
5
|
"homepage": "https://expensify.com",
|
|
6
6
|
"description": "State management for React Native",
|
|
@@ -91,8 +91,8 @@
|
|
|
91
91
|
"react": "18.2.0",
|
|
92
92
|
"react-native": "0.76.3",
|
|
93
93
|
"react-native-device-info": "^10.3.0",
|
|
94
|
-
"react-native-nitro-modules": "^0.
|
|
95
|
-
"react-native-nitro-sqlite": "^9.
|
|
94
|
+
"react-native-nitro-modules": "^0.35.0",
|
|
95
|
+
"react-native-nitro-sqlite": "^9.6.0",
|
|
96
96
|
"react-test-renderer": "18.2.0",
|
|
97
97
|
"reassure": "1.4.0",
|
|
98
98
|
"ts-node": "^10.9.2",
|
|
@@ -104,8 +104,8 @@
|
|
|
104
104
|
"react": ">=18.1.0",
|
|
105
105
|
"react-native": ">=0.75.0",
|
|
106
106
|
"react-native-device-info": "^10.3.0",
|
|
107
|
-
"react-native-nitro-modules": ">=0.
|
|
108
|
-
"react-native-nitro-sqlite": "^9.
|
|
107
|
+
"react-native-nitro-modules": ">=0.35.0",
|
|
108
|
+
"react-native-nitro-sqlite": "^9.6.0"
|
|
109
109
|
},
|
|
110
110
|
"peerDependenciesMeta": {
|
|
111
111
|
"idb-keyval": {
|