react-native-onyx 2.0.103 → 2.0.104
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 +3 -3
- package/dist/Onyx.d.ts +1 -1
- package/dist/Onyx.js +3 -3
- package/dist/OnyxCache.d.ts +49 -0
- package/dist/OnyxCache.js +119 -8
- package/dist/OnyxConnectionManager.js +3 -2
- package/dist/OnyxUtils.d.ts +2 -30
- package/dist/OnyxUtils.js +11 -69
- package/dist/types.d.ts +1 -1
- package/dist/useOnyx.js +2 -2
- package/dist/withOnyx/index.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -388,14 +388,14 @@ Different platforms come with varying storage capacities and Onyx has a way to g
|
|
|
388
388
|
By default, Onyx will not evict anything from storage and will presume all keys are "unsafe" to remove unless explicitly told otherwise.
|
|
389
389
|
|
|
390
390
|
**To flag a key as safe for removal:**
|
|
391
|
-
- Add the key to the `
|
|
391
|
+
- Add the key to the `evictableKeys` option in `Onyx.init(options)`
|
|
392
392
|
- Implement `canEvict` in the Onyx config for each component subscribing to a key
|
|
393
393
|
- The key will only be deleted when all subscribers return `true` for `canEvict`
|
|
394
394
|
|
|
395
395
|
e.g.
|
|
396
396
|
```js
|
|
397
397
|
Onyx.init({
|
|
398
|
-
|
|
398
|
+
evictableKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS],
|
|
399
399
|
});
|
|
400
400
|
```
|
|
401
401
|
|
|
@@ -423,7 +423,7 @@ Provide the `captureMetrics` boolean flag to `Onyx.init` to capture call statist
|
|
|
423
423
|
```js
|
|
424
424
|
Onyx.init({
|
|
425
425
|
keys: ONYXKEYS,
|
|
426
|
-
|
|
426
|
+
evictableKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS],
|
|
427
427
|
captureMetrics: Config.BENCHMARK_ONYX,
|
|
428
428
|
});
|
|
429
429
|
```
|
package/dist/Onyx.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as Logger from './Logger';
|
|
|
2
2
|
import type { CollectionKeyBase, ConnectOptions, InitOptions, Mapping, OnyxKey, OnyxMergeCollectionInput, OnyxMergeInput, OnyxMultiSetInput, OnyxSetInput, OnyxUpdate } 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,
|
|
5
|
+
declare function init({ keys, initialKeyStates, evictableKeys, maxCachedKeysCount, shouldSyncMultipleInstances, debugSetState, enablePerformanceMetrics, skippableCollectionMemberIDs, }: InitOptions): void;
|
|
6
6
|
/**
|
|
7
7
|
* Connects to an Onyx key given the options passed and listens to its changes.
|
|
8
8
|
*
|
package/dist/Onyx.js
CHANGED
|
@@ -40,7 +40,7 @@ const OnyxConnectionManager_1 = __importDefault(require("./OnyxConnectionManager
|
|
|
40
40
|
const GlobalSettings = __importStar(require("./GlobalSettings"));
|
|
41
41
|
const metrics_1 = __importDefault(require("./metrics"));
|
|
42
42
|
/** Initialize the store with actions and listening for storage events */
|
|
43
|
-
function init({ keys = {}, initialKeyStates = {},
|
|
43
|
+
function init({ keys = {}, initialKeyStates = {}, evictableKeys = [], maxCachedKeysCount = 1000, shouldSyncMultipleInstances = !!global.localStorage, debugSetState = false, enablePerformanceMetrics = false, skippableCollectionMemberIDs = [], }) {
|
|
44
44
|
var _a;
|
|
45
45
|
if (enablePerformanceMetrics) {
|
|
46
46
|
GlobalSettings.setPerformanceMetricsEnabled(true);
|
|
@@ -61,9 +61,9 @@ function init({ keys = {}, initialKeyStates = {}, safeEvictionKeys = [], maxCach
|
|
|
61
61
|
if (maxCachedKeysCount > 0) {
|
|
62
62
|
OnyxCache_1.default.setRecentKeysLimit(maxCachedKeysCount);
|
|
63
63
|
}
|
|
64
|
-
OnyxUtils_1.default.initStoreValues(keys, initialKeyStates,
|
|
64
|
+
OnyxUtils_1.default.initStoreValues(keys, initialKeyStates, evictableKeys);
|
|
65
65
|
// Initialize all of our keys with data provided then give green light to any pending connections
|
|
66
|
-
Promise.all([OnyxUtils_1.default.
|
|
66
|
+
Promise.all([OnyxCache_1.default.addEvictableKeysToRecentlyAccessedList(OnyxUtils_1.default.isCollectionKey, OnyxUtils_1.default.getAllKeys), OnyxUtils_1.default.initializeWithDefaultKeyStates()]).then(OnyxUtils_1.default.getDeferredInitTask().resolve);
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
69
69
|
* Connects to an Onyx key given the options passed and listens to its changes.
|
package/dist/OnyxCache.d.ts
CHANGED
|
@@ -26,6 +26,12 @@ declare class OnyxCache {
|
|
|
26
26
|
private pendingPromises;
|
|
27
27
|
/** Maximum size of the keys store din cache */
|
|
28
28
|
private maxRecentKeysSize;
|
|
29
|
+
/** List of keys that are safe to remove when we reach max storage */
|
|
30
|
+
private evictionAllowList;
|
|
31
|
+
/** Map of keys and connection arrays whose keys will never be automatically evicted */
|
|
32
|
+
private evictionBlocklist;
|
|
33
|
+
/** List of keys that have been directly subscribed to or recently modified from least to most recent */
|
|
34
|
+
private recentlyAccessedKeys;
|
|
29
35
|
constructor();
|
|
30
36
|
/** Get all the storage keys */
|
|
31
37
|
getAllKeys(): Set<OnyxKey>;
|
|
@@ -96,6 +102,49 @@ declare class OnyxCache {
|
|
|
96
102
|
setRecentKeysLimit(limit: number): void;
|
|
97
103
|
/** Check if the value has changed */
|
|
98
104
|
hasValueChanged(key: OnyxKey, value: OnyxValue<OnyxKey>): boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Sets the list of keys that are considered safe for eviction
|
|
107
|
+
* @param keys - Array of OnyxKeys that are safe to evict
|
|
108
|
+
*/
|
|
109
|
+
setEvictionAllowList(keys: OnyxKey[]): void;
|
|
110
|
+
/**
|
|
111
|
+
* Get the eviction block list that prevents keys from being evicted
|
|
112
|
+
*/
|
|
113
|
+
getEvictionBlocklist(): Record<OnyxKey, string[] | undefined>;
|
|
114
|
+
/**
|
|
115
|
+
* Checks to see if this key has been flagged as safe for removal.
|
|
116
|
+
* @param testKey - Key to check
|
|
117
|
+
*/
|
|
118
|
+
isEvictableKey(testKey: OnyxKey): boolean;
|
|
119
|
+
/**
|
|
120
|
+
* Check if a given key matches a pattern key
|
|
121
|
+
* @param configKey - Pattern that may contain a wildcard
|
|
122
|
+
* @param key - Key to test against the pattern
|
|
123
|
+
*/
|
|
124
|
+
private isKeyMatch;
|
|
125
|
+
/**
|
|
126
|
+
* Remove a key from the recently accessed key list.
|
|
127
|
+
*/
|
|
128
|
+
removeLastAccessedKey(key: OnyxKey): void;
|
|
129
|
+
/**
|
|
130
|
+
* Add a key to the list of recently accessed keys. The least
|
|
131
|
+
* recently accessed key should be at the head and the most
|
|
132
|
+
* recently accessed key at the tail.
|
|
133
|
+
*/
|
|
134
|
+
addLastAccessedKey(key: OnyxKey, isCollectionKey: boolean): void;
|
|
135
|
+
/**
|
|
136
|
+
* Take all the keys that are safe to evict and add them to
|
|
137
|
+
* the recently accessed list when initializing the app. This
|
|
138
|
+
* enables keys that have not recently been accessed to be
|
|
139
|
+
* removed.
|
|
140
|
+
* @param isCollectionKeyFn - Function to determine if a key is a collection key
|
|
141
|
+
* @param getAllKeysFn - Function to get all keys, defaults to Storage.getAllKeys
|
|
142
|
+
*/
|
|
143
|
+
addEvictableKeysToRecentlyAccessedList(isCollectionKeyFn: (key: OnyxKey) => boolean, getAllKeysFn: () => Promise<Set<OnyxKey>>): Promise<void>;
|
|
144
|
+
/**
|
|
145
|
+
* Finds a key that can be safely evicted
|
|
146
|
+
*/
|
|
147
|
+
getKeyForEviction(): OnyxKey | undefined;
|
|
99
148
|
}
|
|
100
149
|
declare const instance: OnyxCache;
|
|
101
150
|
export default instance;
|
package/dist/OnyxCache.js
CHANGED
|
@@ -1,4 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
27
|
};
|
|
@@ -7,6 +30,7 @@ exports.TASK = void 0;
|
|
|
7
30
|
const fast_equals_1 = require("fast-equals");
|
|
8
31
|
const bindAll_1 = __importDefault(require("lodash/bindAll"));
|
|
9
32
|
const utils_1 = __importDefault(require("./utils"));
|
|
33
|
+
const Str = __importStar(require("./Str"));
|
|
10
34
|
// Task constants
|
|
11
35
|
const TASK = {
|
|
12
36
|
GET: 'get',
|
|
@@ -22,13 +46,19 @@ class OnyxCache {
|
|
|
22
46
|
constructor() {
|
|
23
47
|
/** Maximum size of the keys store din cache */
|
|
24
48
|
this.maxRecentKeysSize = 0;
|
|
49
|
+
/** List of keys that are safe to remove when we reach max storage */
|
|
50
|
+
this.evictionAllowList = [];
|
|
51
|
+
/** Map of keys and connection arrays whose keys will never be automatically evicted */
|
|
52
|
+
this.evictionBlocklist = {};
|
|
53
|
+
/** List of keys that have been directly subscribed to or recently modified from least to most recent */
|
|
54
|
+
this.recentlyAccessedKeys = [];
|
|
25
55
|
this.storageKeys = new Set();
|
|
26
56
|
this.nullishStorageKeys = new Set();
|
|
27
57
|
this.recentKeys = new Set();
|
|
28
58
|
this.storageMap = {};
|
|
29
59
|
this.pendingPromises = new Map();
|
|
30
60
|
// bind all public methods to prevent problems with `this`
|
|
31
|
-
(0, bindAll_1.default)(this, 'getAllKeys', 'get', 'hasCacheForKey', 'addKey', 'addNullishStorageKey', 'hasNullishStorageKey', 'clearNullishStorageKeys', 'set', 'drop', 'merge', 'hasPendingTask', 'getTaskPromise', 'captureTask', 'removeLeastRecentlyUsedKeys', 'setRecentKeysLimit', 'setAllKeys');
|
|
61
|
+
(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');
|
|
32
62
|
}
|
|
33
63
|
/** Get all the storage keys */
|
|
34
64
|
getAllKeys() {
|
|
@@ -158,18 +188,25 @@ class OnyxCache {
|
|
|
158
188
|
}
|
|
159
189
|
/** Remove keys that don't fall into the range of recently used keys */
|
|
160
190
|
removeLeastRecentlyUsedKeys() {
|
|
161
|
-
|
|
191
|
+
const numKeysToRemove = this.recentKeys.size - this.maxRecentKeysSize;
|
|
162
192
|
if (numKeysToRemove <= 0) {
|
|
163
193
|
return;
|
|
164
194
|
}
|
|
165
195
|
const iterator = this.recentKeys.values();
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
196
|
+
const keysToRemove = [];
|
|
197
|
+
const recentKeysArray = Array.from(this.recentKeys);
|
|
198
|
+
const mostRecentKey = recentKeysArray[recentKeysArray.length - 1];
|
|
199
|
+
let iterResult = iterator.next();
|
|
200
|
+
while (!iterResult.done) {
|
|
201
|
+
const key = iterResult.value;
|
|
202
|
+
// Don't consider the most recently accessed key for eviction
|
|
203
|
+
// This ensures we don't immediately evict a key we just added
|
|
204
|
+
if (key !== undefined && key !== mostRecentKey && this.isEvictableKey(key)) {
|
|
205
|
+
keysToRemove.push(key);
|
|
206
|
+
}
|
|
207
|
+
iterResult = iterator.next();
|
|
171
208
|
}
|
|
172
|
-
for (const key of
|
|
209
|
+
for (const key of keysToRemove) {
|
|
173
210
|
delete this.storageMap[key];
|
|
174
211
|
this.recentKeys.delete(key);
|
|
175
212
|
}
|
|
@@ -182,6 +219,80 @@ class OnyxCache {
|
|
|
182
219
|
hasValueChanged(key, value) {
|
|
183
220
|
return !(0, fast_equals_1.deepEqual)(this.storageMap[key], value);
|
|
184
221
|
}
|
|
222
|
+
/**
|
|
223
|
+
* Sets the list of keys that are considered safe for eviction
|
|
224
|
+
* @param keys - Array of OnyxKeys that are safe to evict
|
|
225
|
+
*/
|
|
226
|
+
setEvictionAllowList(keys) {
|
|
227
|
+
this.evictionAllowList = keys;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Get the eviction block list that prevents keys from being evicted
|
|
231
|
+
*/
|
|
232
|
+
getEvictionBlocklist() {
|
|
233
|
+
return this.evictionBlocklist;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Checks to see if this key has been flagged as safe for removal.
|
|
237
|
+
* @param testKey - Key to check
|
|
238
|
+
*/
|
|
239
|
+
isEvictableKey(testKey) {
|
|
240
|
+
return this.evictionAllowList.some((key) => this.isKeyMatch(key, testKey));
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Check if a given key matches a pattern key
|
|
244
|
+
* @param configKey - Pattern that may contain a wildcard
|
|
245
|
+
* @param key - Key to test against the pattern
|
|
246
|
+
*/
|
|
247
|
+
isKeyMatch(configKey, key) {
|
|
248
|
+
const isCollectionKey = configKey.endsWith('_');
|
|
249
|
+
return isCollectionKey ? Str.startsWith(key, configKey) : configKey === key;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Remove a key from the recently accessed key list.
|
|
253
|
+
*/
|
|
254
|
+
removeLastAccessedKey(key) {
|
|
255
|
+
this.recentlyAccessedKeys = this.recentlyAccessedKeys.filter((recentlyAccessedKey) => recentlyAccessedKey !== key);
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Add a key to the list of recently accessed keys. The least
|
|
259
|
+
* recently accessed key should be at the head and the most
|
|
260
|
+
* recently accessed key at the tail.
|
|
261
|
+
*/
|
|
262
|
+
addLastAccessedKey(key, isCollectionKey) {
|
|
263
|
+
// Only specific keys belong in this list since we cannot remove an entire collection.
|
|
264
|
+
if (isCollectionKey || !this.isEvictableKey(key)) {
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
this.removeLastAccessedKey(key);
|
|
268
|
+
this.recentlyAccessedKeys.push(key);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Take all the keys that are safe to evict and add them to
|
|
272
|
+
* the recently accessed list when initializing the app. This
|
|
273
|
+
* enables keys that have not recently been accessed to be
|
|
274
|
+
* removed.
|
|
275
|
+
* @param isCollectionKeyFn - Function to determine if a key is a collection key
|
|
276
|
+
* @param getAllKeysFn - Function to get all keys, defaults to Storage.getAllKeys
|
|
277
|
+
*/
|
|
278
|
+
addEvictableKeysToRecentlyAccessedList(isCollectionKeyFn, getAllKeysFn) {
|
|
279
|
+
return getAllKeysFn().then((keys) => {
|
|
280
|
+
this.evictionAllowList.forEach((evictableKey) => {
|
|
281
|
+
keys.forEach((key) => {
|
|
282
|
+
if (!this.isKeyMatch(evictableKey, key)) {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
this.addLastAccessedKey(key, isCollectionKeyFn(key));
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Finds a key that can be safely evicted
|
|
292
|
+
*/
|
|
293
|
+
getKeyForEviction() {
|
|
294
|
+
return this.recentlyAccessedKeys.find((key) => !this.evictionBlocklist[key]);
|
|
295
|
+
}
|
|
185
296
|
}
|
|
186
297
|
const instance = new OnyxCache();
|
|
187
298
|
exports.default = instance;
|
|
@@ -31,6 +31,7 @@ const Logger = __importStar(require("./Logger"));
|
|
|
31
31
|
const OnyxUtils_1 = __importDefault(require("./OnyxUtils"));
|
|
32
32
|
const Str = __importStar(require("./Str"));
|
|
33
33
|
const utils_1 = __importDefault(require("./utils"));
|
|
34
|
+
const OnyxCache_1 = __importDefault(require("./OnyxCache"));
|
|
34
35
|
/**
|
|
35
36
|
* Manages Onyx connections of `Onyx.connect()`, `useOnyx()` and `withOnyx()` subscribers.
|
|
36
37
|
*/
|
|
@@ -192,7 +193,7 @@ class OnyxConnectionManager {
|
|
|
192
193
|
Logger.logInfo(`[ConnectionManager] Attempted to add connection to eviction block list but no connection was found.`);
|
|
193
194
|
return;
|
|
194
195
|
}
|
|
195
|
-
const evictionBlocklist =
|
|
196
|
+
const evictionBlocklist = OnyxCache_1.default.getEvictionBlocklist();
|
|
196
197
|
if (!evictionBlocklist[connectionMetadata.onyxKey]) {
|
|
197
198
|
evictionBlocklist[connectionMetadata.onyxKey] = [];
|
|
198
199
|
}
|
|
@@ -213,7 +214,7 @@ class OnyxConnectionManager {
|
|
|
213
214
|
Logger.logInfo(`[ConnectionManager] Attempted to remove connection from eviction block list but no connection was found.`);
|
|
214
215
|
return;
|
|
215
216
|
}
|
|
216
|
-
const evictionBlocklist =
|
|
217
|
+
const evictionBlocklist = OnyxCache_1.default.getEvictionBlocklist();
|
|
217
218
|
evictionBlocklist[connectionMetadata.onyxKey] =
|
|
218
219
|
(_b = (_a = evictionBlocklist[connectionMetadata.onyxKey]) === null || _a === void 0 ? void 0 : _a.filter((evictionKey) => evictionKey !== `${connection.id}_${connection.callbackID}`)) !== null && _b !== void 0 ? _b : [];
|
|
219
220
|
// Remove the key if there are no more subscribers.
|
package/dist/OnyxUtils.d.ts
CHANGED
|
@@ -29,10 +29,6 @@ declare function getDefaultKeyStates(): Record<OnyxKey, OnyxValue<OnyxKey>>;
|
|
|
29
29
|
* Getter - returns the deffered init task.
|
|
30
30
|
*/
|
|
31
31
|
declare function getDeferredInitTask(): DeferredTask;
|
|
32
|
-
/**
|
|
33
|
-
* Getter - returns the eviction block list.
|
|
34
|
-
*/
|
|
35
|
-
declare function getEvictionBlocklist(): Record<OnyxKey, string[] | undefined>;
|
|
36
32
|
/**
|
|
37
33
|
* Getter - returns the skippable collection member IDs.
|
|
38
34
|
*/
|
|
@@ -46,9 +42,9 @@ declare function setSkippableCollectionMemberIDs(ids: Set<string>): void;
|
|
|
46
42
|
*
|
|
47
43
|
* @param keys - `ONYXKEYS` constants object from Onyx.init()
|
|
48
44
|
* @param initialKeyStates - initial data to set when `init()` and `clear()` are called
|
|
49
|
-
* @param
|
|
45
|
+
* @param evictableKeys - This is an array of keys (individual or collection patterns) that when provided to Onyx are flagged as "safe" for removal.
|
|
50
46
|
*/
|
|
51
|
-
declare function initStoreValues(keys: DeepRecord<string, OnyxKey>, initialKeyStates: Partial<KeyValueMapping>,
|
|
47
|
+
declare function initStoreValues(keys: DeepRecord<string, OnyxKey>, initialKeyStates: Partial<KeyValueMapping>, evictableKeys: OnyxKey[]): void;
|
|
52
48
|
/**
|
|
53
49
|
* Sends an action to DevTools extension
|
|
54
50
|
*
|
|
@@ -123,8 +119,6 @@ declare function splitCollectionMemberKey<TKey extends CollectionKey, Collection
|
|
|
123
119
|
* or if the provided key is a collection member key (in case our configured key is a "collection key")
|
|
124
120
|
*/
|
|
125
121
|
declare function isKeyMatch(configKey: OnyxKey, key: OnyxKey): boolean;
|
|
126
|
-
/** Checks to see if this key has been flagged as safe for removal. */
|
|
127
|
-
declare function isSafeEvictionKey(testKey: OnyxKey): boolean;
|
|
128
122
|
/**
|
|
129
123
|
* Extracts the collection identifier of a given collection member key.
|
|
130
124
|
*
|
|
@@ -143,23 +137,6 @@ declare function getCollectionKey(key: CollectionKey): string;
|
|
|
143
137
|
* If the requested key is a collection, it will return an object with all the collection members.
|
|
144
138
|
*/
|
|
145
139
|
declare function tryGetCachedValue<TKey extends OnyxKey>(key: TKey, mapping?: Partial<Mapping<TKey>>): OnyxValue<OnyxKey>;
|
|
146
|
-
/**
|
|
147
|
-
* Remove a key from the recently accessed key list.
|
|
148
|
-
*/
|
|
149
|
-
declare function removeLastAccessedKey(key: OnyxKey): void;
|
|
150
|
-
/**
|
|
151
|
-
* Add a key to the list of recently accessed keys. The least
|
|
152
|
-
* recently accessed key should be at the head and the most
|
|
153
|
-
* recently accessed key at the tail.
|
|
154
|
-
*/
|
|
155
|
-
declare function addLastAccessedKey(key: OnyxKey): void;
|
|
156
|
-
/**
|
|
157
|
-
* Take all the keys that are safe to evict and add them to
|
|
158
|
-
* the recently accessed list when initializing the app. This
|
|
159
|
-
* enables keys that have not recently been accessed to be
|
|
160
|
-
* removed.
|
|
161
|
-
*/
|
|
162
|
-
declare function addAllSafeEvictionKeysToRecentlyAccessedList(): Promise<void>;
|
|
163
140
|
declare function getCachedCollection<TKey extends CollectionKeyBase>(collectionKey: TKey, collectionMemberKeys?: string[]): NonNullable<OnyxCollection<KeyValueMapping[TKey]>>;
|
|
164
141
|
/**
|
|
165
142
|
* When a collection of keys change, search for any callbacks matching the collection key and trigger those callbacks
|
|
@@ -292,11 +269,7 @@ declare const OnyxUtils: {
|
|
|
292
269
|
isCollectionMemberKey: typeof isCollectionMemberKey;
|
|
293
270
|
splitCollectionMemberKey: typeof splitCollectionMemberKey;
|
|
294
271
|
isKeyMatch: typeof isKeyMatch;
|
|
295
|
-
isSafeEvictionKey: typeof isSafeEvictionKey;
|
|
296
272
|
tryGetCachedValue: typeof tryGetCachedValue;
|
|
297
|
-
removeLastAccessedKey: typeof removeLastAccessedKey;
|
|
298
|
-
addLastAccessedKey: typeof addLastAccessedKey;
|
|
299
|
-
addAllSafeEvictionKeysToRecentlyAccessedList: typeof addAllSafeEvictionKeysToRecentlyAccessedList;
|
|
300
273
|
getCachedCollection: typeof getCachedCollection;
|
|
301
274
|
keysChanged: typeof keysChanged;
|
|
302
275
|
keyChanged: typeof keyChanged;
|
|
@@ -321,7 +294,6 @@ declare const OnyxUtils: {
|
|
|
321
294
|
doAllCollectionItemsBelongToSameParent: typeof doAllCollectionItemsBelongToSameParent;
|
|
322
295
|
subscribeToKey: typeof subscribeToKey;
|
|
323
296
|
unsubscribeFromKey: typeof unsubscribeFromKey;
|
|
324
|
-
getEvictionBlocklist: typeof getEvictionBlocklist;
|
|
325
297
|
getSkippableCollectionMemberIDs: typeof getSkippableCollectionMemberIDs;
|
|
326
298
|
setSkippableCollectionMemberIDs: typeof setSkippableCollectionMemberIDs;
|
|
327
299
|
storeKeyBySubscriptions: typeof storeKeyBySubscriptions;
|
package/dist/OnyxUtils.js
CHANGED
|
@@ -59,14 +59,6 @@ const callbackToStateMapping = {};
|
|
|
59
59
|
let onyxCollectionKeySet = new Set();
|
|
60
60
|
// Holds a mapping of the connected key to the subscriptionID for faster lookups
|
|
61
61
|
const onyxKeyToSubscriptionIDs = new Map();
|
|
62
|
-
// Holds a list of keys that have been directly subscribed to or recently modified from least to most recent
|
|
63
|
-
let recentlyAccessedKeys = [];
|
|
64
|
-
// Holds a list of keys that are safe to remove when we reach max storage. If a key does not match with
|
|
65
|
-
// whatever appears in this list it will NEVER be a candidate for eviction.
|
|
66
|
-
let evictionAllowList = [];
|
|
67
|
-
// Holds a map of keys and connection arrays whose keys will never be automatically evicted as
|
|
68
|
-
// long as we have at least one subscriber that returns false for the canEvict property.
|
|
69
|
-
const evictionBlocklist = {};
|
|
70
62
|
// Optional user-provided key value states set when Onyx initializes or clears
|
|
71
63
|
let defaultKeyStates = {};
|
|
72
64
|
let batchUpdatesPromise = null;
|
|
@@ -107,12 +99,6 @@ function getDefaultKeyStates() {
|
|
|
107
99
|
function getDeferredInitTask() {
|
|
108
100
|
return deferredInitTask;
|
|
109
101
|
}
|
|
110
|
-
/**
|
|
111
|
-
* Getter - returns the eviction block list.
|
|
112
|
-
*/
|
|
113
|
-
function getEvictionBlocklist() {
|
|
114
|
-
return evictionBlocklist;
|
|
115
|
-
}
|
|
116
102
|
/**
|
|
117
103
|
* Getter - returns the skippable collection member IDs.
|
|
118
104
|
*/
|
|
@@ -130,9 +116,9 @@ function setSkippableCollectionMemberIDs(ids) {
|
|
|
130
116
|
*
|
|
131
117
|
* @param keys - `ONYXKEYS` constants object from Onyx.init()
|
|
132
118
|
* @param initialKeyStates - initial data to set when `init()` and `clear()` are called
|
|
133
|
-
* @param
|
|
119
|
+
* @param evictableKeys - This is an array of keys (individual or collection patterns) that when provided to Onyx are flagged as "safe" for removal.
|
|
134
120
|
*/
|
|
135
|
-
function initStoreValues(keys, initialKeyStates,
|
|
121
|
+
function initStoreValues(keys, initialKeyStates, evictableKeys) {
|
|
136
122
|
var _a;
|
|
137
123
|
// We need the value of the collection keys later for checking if a
|
|
138
124
|
// key is a collection. We store it in a map for faster lookup.
|
|
@@ -145,7 +131,7 @@ function initStoreValues(keys, initialKeyStates, safeEvictionKeys) {
|
|
|
145
131
|
defaultKeyStates = initialKeyStates;
|
|
146
132
|
DevTools_1.default.initState(initialKeyStates);
|
|
147
133
|
// Let Onyx know about which keys are safe to evict
|
|
148
|
-
|
|
134
|
+
OnyxCache_1.default.setEvictionAllowList(evictableKeys);
|
|
149
135
|
if (typeof keys.COLLECTION === 'object' && typeof keys.COLLECTION.SNAPSHOT === 'string') {
|
|
150
136
|
snapshotKey = keys.COLLECTION.SNAPSHOT;
|
|
151
137
|
}
|
|
@@ -403,10 +389,6 @@ function splitCollectionMemberKey(key, collectionKey) {
|
|
|
403
389
|
function isKeyMatch(configKey, key) {
|
|
404
390
|
return isCollectionKey(configKey) ? Str.startsWith(key, configKey) : configKey === key;
|
|
405
391
|
}
|
|
406
|
-
/** Checks to see if this key has been flagged as safe for removal. */
|
|
407
|
-
function isSafeEvictionKey(testKey) {
|
|
408
|
-
return evictionAllowList.some((key) => isKeyMatch(key, testKey));
|
|
409
|
-
}
|
|
410
392
|
/**
|
|
411
393
|
* Extracts the collection identifier of a given collection member key.
|
|
412
394
|
*
|
|
@@ -466,43 +448,6 @@ function tryGetCachedValue(key, mapping) {
|
|
|
466
448
|
}
|
|
467
449
|
return val;
|
|
468
450
|
}
|
|
469
|
-
/**
|
|
470
|
-
* Remove a key from the recently accessed key list.
|
|
471
|
-
*/
|
|
472
|
-
function removeLastAccessedKey(key) {
|
|
473
|
-
recentlyAccessedKeys = recentlyAccessedKeys.filter((recentlyAccessedKey) => recentlyAccessedKey !== key);
|
|
474
|
-
}
|
|
475
|
-
/**
|
|
476
|
-
* Add a key to the list of recently accessed keys. The least
|
|
477
|
-
* recently accessed key should be at the head and the most
|
|
478
|
-
* recently accessed key at the tail.
|
|
479
|
-
*/
|
|
480
|
-
function addLastAccessedKey(key) {
|
|
481
|
-
// Only specific keys belong in this list since we cannot remove an entire collection.
|
|
482
|
-
if (isCollectionKey(key) || !isSafeEvictionKey(key)) {
|
|
483
|
-
return;
|
|
484
|
-
}
|
|
485
|
-
removeLastAccessedKey(key);
|
|
486
|
-
recentlyAccessedKeys.push(key);
|
|
487
|
-
}
|
|
488
|
-
/**
|
|
489
|
-
* Take all the keys that are safe to evict and add them to
|
|
490
|
-
* the recently accessed list when initializing the app. This
|
|
491
|
-
* enables keys that have not recently been accessed to be
|
|
492
|
-
* removed.
|
|
493
|
-
*/
|
|
494
|
-
function addAllSafeEvictionKeysToRecentlyAccessedList() {
|
|
495
|
-
return getAllKeys().then((keys) => {
|
|
496
|
-
evictionAllowList.forEach((safeEvictionKey) => {
|
|
497
|
-
keys.forEach((key) => {
|
|
498
|
-
if (!isKeyMatch(safeEvictionKey, key)) {
|
|
499
|
-
return;
|
|
500
|
-
}
|
|
501
|
-
addLastAccessedKey(key);
|
|
502
|
-
});
|
|
503
|
-
});
|
|
504
|
-
});
|
|
505
|
-
}
|
|
506
451
|
function getCachedCollection(collectionKey, collectionMemberKeys) {
|
|
507
452
|
const allKeys = collectionMemberKeys || OnyxCache_1.default.getAllKeys();
|
|
508
453
|
const collection = {};
|
|
@@ -688,10 +633,10 @@ function keyChanged(key, value, previousValue, canUpdateSubscriber = () => true,
|
|
|
688
633
|
var _a, _b;
|
|
689
634
|
// Add or remove this key from the recentlyAccessedKeys lists
|
|
690
635
|
if (value !== null) {
|
|
691
|
-
addLastAccessedKey(key);
|
|
636
|
+
OnyxCache_1.default.addLastAccessedKey(key, isCollectionKey(key));
|
|
692
637
|
}
|
|
693
638
|
else {
|
|
694
|
-
removeLastAccessedKey(key);
|
|
639
|
+
OnyxCache_1.default.removeLastAccessedKey(key);
|
|
695
640
|
}
|
|
696
641
|
// We get the subscribers interested in the key that has just changed. If the subscriber's key is a collection key then we will
|
|
697
642
|
// notify them if the key that changed is a collection member. Or if it is a regular key notify them when there is an exact match. Depending on whether the subscriber
|
|
@@ -872,9 +817,11 @@ function sendDataToConnection(mapping, value, matchedKey, isBatched) {
|
|
|
872
817
|
* run out of storage the least recently accessed key can be removed.
|
|
873
818
|
*/
|
|
874
819
|
function addKeyToRecentlyAccessedIfNeeded(mapping) {
|
|
875
|
-
if (!
|
|
820
|
+
if (!OnyxCache_1.default.isEvictableKey(mapping.key)) {
|
|
876
821
|
return;
|
|
877
822
|
}
|
|
823
|
+
// Add the key to recentKeys first (this makes it the most recent key)
|
|
824
|
+
OnyxCache_1.default.addToAccessedKeys(mapping.key);
|
|
878
825
|
// Try to free some cache whenever we connect to a safe eviction key
|
|
879
826
|
OnyxCache_1.default.removeLeastRecentlyUsedKeys();
|
|
880
827
|
if (utils_1.default.hasWithOnyxInstance(mapping) && !isCollectionKey(mapping.key)) {
|
|
@@ -882,7 +829,7 @@ function addKeyToRecentlyAccessedIfNeeded(mapping) {
|
|
|
882
829
|
if (mapping.canEvict === undefined) {
|
|
883
830
|
throw new Error(`Cannot subscribe to safe eviction key '${mapping.key}' without providing a canEvict value.`);
|
|
884
831
|
}
|
|
885
|
-
addLastAccessedKey(mapping.key);
|
|
832
|
+
OnyxCache_1.default.addLastAccessedKey(mapping.key, isCollectionKey(mapping.key));
|
|
886
833
|
}
|
|
887
834
|
}
|
|
888
835
|
/**
|
|
@@ -945,7 +892,7 @@ function evictStorageAndRetry(error, onyxMethod, ...args) {
|
|
|
945
892
|
throw error;
|
|
946
893
|
}
|
|
947
894
|
// Find the first key that we can remove that has no subscribers in our blocklist
|
|
948
|
-
const keyForRemoval =
|
|
895
|
+
const keyForRemoval = OnyxCache_1.default.getKeyForEviction();
|
|
949
896
|
if (!keyForRemoval) {
|
|
950
897
|
// If we have no acceptable keys to remove then we are possibly trying to save mission critical data. If this is the case,
|
|
951
898
|
// then we should stop retrying as there is not much the user can do to fix this. Instead of getting them stuck in an infinite loop we
|
|
@@ -1231,11 +1178,7 @@ const OnyxUtils = {
|
|
|
1231
1178
|
isCollectionMemberKey,
|
|
1232
1179
|
splitCollectionMemberKey,
|
|
1233
1180
|
isKeyMatch,
|
|
1234
|
-
isSafeEvictionKey,
|
|
1235
1181
|
tryGetCachedValue,
|
|
1236
|
-
removeLastAccessedKey,
|
|
1237
|
-
addLastAccessedKey,
|
|
1238
|
-
addAllSafeEvictionKeysToRecentlyAccessedList,
|
|
1239
1182
|
getCachedCollection,
|
|
1240
1183
|
keysChanged,
|
|
1241
1184
|
keyChanged,
|
|
@@ -1260,7 +1203,6 @@ const OnyxUtils = {
|
|
|
1260
1203
|
doAllCollectionItemsBelongToSameParent,
|
|
1261
1204
|
subscribeToKey,
|
|
1262
1205
|
unsubscribeFromKey,
|
|
1263
|
-
getEvictionBlocklist,
|
|
1264
1206
|
getSkippableCollectionMemberIDs,
|
|
1265
1207
|
setSkippableCollectionMemberIDs,
|
|
1266
1208
|
storeKeyBySubscriptions,
|
|
@@ -1287,7 +1229,7 @@ GlobalSettings.addGlobalSettingsChangeListener(({ enablePerformanceMetrics }) =>
|
|
|
1287
1229
|
// @ts-expect-error Reassign
|
|
1288
1230
|
getCollectionKeys = (0, metrics_1.default)(getCollectionKeys, 'OnyxUtils.getCollectionKeys');
|
|
1289
1231
|
// @ts-expect-error Reassign
|
|
1290
|
-
|
|
1232
|
+
addEvictableKeysToRecentlyAccessedList = (0, metrics_1.default)(OnyxCache_1.default.addEvictableKeysToRecentlyAccessedList, 'OnyxCache.addEvictableKeysToRecentlyAccessedList');
|
|
1291
1233
|
// @ts-expect-error Reassign
|
|
1292
1234
|
keysChanged = (0, metrics_1.default)(keysChanged, 'OnyxUtils.keysChanged');
|
|
1293
1235
|
// @ts-expect-error Reassign
|
package/dist/types.d.ts
CHANGED
|
@@ -379,7 +379,7 @@ type InitOptions = {
|
|
|
379
379
|
* This is an array of keys (individual or collection patterns) that when provided to Onyx are flagged
|
|
380
380
|
* as "safe" for removal. Any components subscribing to these keys must also implement a canEvict option. See the README for more info.
|
|
381
381
|
*/
|
|
382
|
-
|
|
382
|
+
evictableKeys?: OnyxKey[];
|
|
383
383
|
/**
|
|
384
384
|
* Sets how many recent keys should we try to keep in cache
|
|
385
385
|
* Setting this to 0 would practically mean no cache
|
package/dist/useOnyx.js
CHANGED
|
@@ -124,8 +124,8 @@ function useOnyx(key, options, dependencies = []) {
|
|
|
124
124
|
if ((options === null || options === void 0 ? void 0 : options.canEvict) === undefined || !connectionRef.current) {
|
|
125
125
|
return;
|
|
126
126
|
}
|
|
127
|
-
if (!
|
|
128
|
-
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({
|
|
127
|
+
if (!OnyxCache_1.default.isEvictableKey(key)) {
|
|
128
|
+
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: []}).`);
|
|
129
129
|
}
|
|
130
130
|
if (options.canEvict) {
|
|
131
131
|
OnyxConnectionManager_1.default.removeFromEvictionBlockList(connectionRef.current);
|
package/dist/withOnyx/index.js
CHANGED
|
@@ -257,8 +257,8 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
|
|
|
257
257
|
}
|
|
258
258
|
const canEvict = !!Str.result(mapping.canEvict, this.props);
|
|
259
259
|
const key = Str.result(mapping.key, this.props);
|
|
260
|
-
if (!
|
|
261
|
-
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({
|
|
260
|
+
if (!OnyxCache_1.default.isEvictableKey(key)) {
|
|
261
|
+
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: []}).`);
|
|
262
262
|
}
|
|
263
263
|
if (canEvict) {
|
|
264
264
|
OnyxConnectionManager_1.default.removeFromEvictionBlockList(this.activeConnections[key]);
|