react-native-onyx 2.0.26 → 2.0.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/OnyxUtils.js CHANGED
@@ -26,9 +26,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
26
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
+ /* eslint-disable @typescript-eslint/prefer-for-of */
29
30
  /* eslint-disable no-continue */
30
31
  const fast_equals_1 = require("fast-equals");
31
- const underscore_1 = __importDefault(require("underscore"));
32
+ const clone_1 = __importDefault(require("lodash/clone"));
32
33
  const Logger = __importStar(require("./Logger"));
33
34
  const OnyxCache_1 = __importDefault(require("./OnyxCache"));
34
35
  const Str = __importStar(require("./Str"));
@@ -66,32 +67,24 @@ let batchUpdatesPromise = null;
66
67
  let batchUpdatesQueue = [];
67
68
  /**
68
69
  * Getter - returns the merge queue.
69
- *
70
- * @returns {Object} The callback to state mapping.
71
70
  */
72
71
  function getMergeQueue() {
73
72
  return mergeQueue;
74
73
  }
75
74
  /**
76
75
  * Getter - returns the merge queue promise.
77
- *
78
- * @returns {Object} The callback to state mapping.
79
76
  */
80
77
  function getMergeQueuePromise() {
81
78
  return mergeQueuePromise;
82
79
  }
83
80
  /**
84
81
  * Getter - returns the callback to state mapping.
85
- *
86
- * @returns {Object} The callback to state mapping.
87
82
  */
88
83
  function getCallbackToStateMapping() {
89
84
  return callbackToStateMapping;
90
85
  }
91
86
  /**
92
87
  * Getter - returns the default key states.
93
- *
94
- * @returns {Object} The callback to state mapping.
95
88
  */
96
89
  function getDefaultKeyStates() {
97
90
  return defaultKeyStates;
@@ -99,15 +92,16 @@ function getDefaultKeyStates() {
99
92
  /**
100
93
  * Sets the initial values for the Onyx store
101
94
  *
102
- * @param {Object} keys - `ONYXKEYS` constants object from Onyx.init()
103
- * @param {Object} initialKeyStates - initial data to set when `init()` and `clear()` are called
104
- * @param {Array<String>} safeEvictionKeys - This is an array of keys (individual or collection patterns) that when provided to Onyx are flagged as "safe" for removal.
95
+ * @param keys - `ONYXKEYS` constants object from Onyx.init()
96
+ * @param initialKeyStates - initial data to set when `init()` and `clear()` are called
97
+ * @param safeEvictionKeys - This is an array of keys (individual or collection patterns) that when provided to Onyx are flagged as "safe" for removal.
105
98
  */
106
99
  function initStoreValues(keys, initialKeyStates, safeEvictionKeys) {
100
+ var _a;
107
101
  // We need the value of the collection keys later for checking if a
108
102
  // key is a collection. We store it in a map for faster lookup.
109
- const collectionValues = underscore_1.default.values(keys.COLLECTION);
110
- onyxCollectionKeyMap = underscore_1.default.reduce(collectionValues, (acc, val) => {
103
+ const collectionValues = Object.values((_a = keys.COLLECTION) !== null && _a !== void 0 ? _a : {});
104
+ onyxCollectionKeyMap = collectionValues.reduce((acc, val) => {
111
105
  acc.set(val, true);
112
106
  return acc;
113
107
  }, new Map());
@@ -117,14 +111,6 @@ function initStoreValues(keys, initialKeyStates, safeEvictionKeys) {
117
111
  // Let Onyx know about which keys are safe to evict
118
112
  evictionAllowList = safeEvictionKeys;
119
113
  }
120
- /**
121
- * Sends an action to DevTools extension
122
- *
123
- * @param {string} method - Onyx method from METHOD
124
- * @param {string} key - Onyx key that was changed
125
- * @param {any} value - contains the change that was made by the method
126
- * @param {any} mergedValue - (optional) value that was written in the storage after a merge method was executed.
127
- */
128
114
  function sendActionToDevTools(method, key, value, mergedValue = undefined) {
129
115
  DevTools_1.default.registerAction(utils_1.default.formatActionName(method, key), value, key ? { [key]: mergedValue || value } : value);
130
116
  }
@@ -133,7 +119,6 @@ function sendActionToDevTools(method, key, value, mergedValue = undefined) {
133
119
  * This happens for example in the Onyx.update function, where we process API responses that might contain a lot of
134
120
  * update operations. Instead of calling the subscribers for each update operation, we batch them together which will
135
121
  * cause react to schedule the updates at once instead of after each other. This is mainly a performance optimization.
136
- * @returns {Promise}
137
122
  */
138
123
  function maybeFlushBatchUpdates() {
139
124
  if (batchUpdatesPromise) {
@@ -162,35 +147,19 @@ function batchUpdates(updates) {
162
147
  batchUpdatesQueue.push(updates);
163
148
  return maybeFlushBatchUpdates();
164
149
  }
165
- /**
166
- * Uses a selector function to return a simplified version of sourceData
167
- * @param {Mixed} sourceData
168
- * @param {Function} selector Function that takes sourceData and returns a simplified version of it
169
- * @param {Object} [withOnyxInstanceState]
170
- * @returns {Mixed}
171
- */
172
- const getSubsetOfData = (sourceData, selector, withOnyxInstanceState) => selector(sourceData, withOnyxInstanceState);
173
150
  /**
174
151
  * Takes a collection of items (eg. {testKey_1:{a:'a'}, testKey_2:{b:'b'}})
175
152
  * and runs it through a reducer function to return a subset of the data according to a selector.
176
153
  * The resulting collection will only contain items that are returned by the selector.
177
- * @param {Object} collection
178
- * @param {String|Function} selector (see method docs for getSubsetOfData() for full details)
179
- * @param {Object} [withOnyxInstanceState]
180
- * @returns {Object}
181
- */
182
- const reduceCollectionWithSelector = (collection, selector, withOnyxInstanceState) => underscore_1.default.reduce(collection, (finalCollection, item, key) => {
183
- // eslint-disable-next-line no-param-reassign
184
- finalCollection[key] = getSubsetOfData(item, selector, withOnyxInstanceState);
185
- return finalCollection;
186
- }, {});
187
- /**
188
- * Get some data from the store
189
- *
190
- * @private
191
- * @param {string} key
192
- * @returns {Promise<*>}
193
154
  */
155
+ function reduceCollectionWithSelector(collection, selector, withOnyxInstanceState) {
156
+ return Object.entries(collection !== null && collection !== void 0 ? collection : {}).reduce((finalCollection, [key, item]) => {
157
+ // eslint-disable-next-line no-param-reassign
158
+ finalCollection[key] = selector(item, withOnyxInstanceState);
159
+ return finalCollection;
160
+ }, {});
161
+ }
162
+ /** Get some data from the store */
194
163
  function get(key) {
195
164
  // When we already have the value in cache - resolve right away
196
165
  if (OnyxCache_1.default.hasCacheForKey(key)) {
@@ -210,11 +179,7 @@ function get(key) {
210
179
  .catch((err) => Logger.logInfo(`Unable to get item from persistent storage. Key: ${key} Error: ${err}`));
211
180
  return OnyxCache_1.default.captureTask(taskName, promise);
212
181
  }
213
- /**
214
- * Returns current key names stored in persisted storage
215
- * @private
216
- * @returns {Promise<Set<Key>>}
217
- */
182
+ /** Returns current key names stored in persisted storage */
218
183
  function getAllKeys() {
219
184
  // When we've already read stored keys, resolve right away
220
185
  const storedKeys = OnyxCache_1.default.getAllKeys();
@@ -237,25 +202,17 @@ function getAllKeys() {
237
202
  /**
238
203
  * Checks to see if the a subscriber's supplied key
239
204
  * is associated with a collection of keys.
240
- *
241
- * @param {String} key
242
- * @returns {Boolean}
243
205
  */
244
206
  function isCollectionKey(key) {
245
207
  return onyxCollectionKeyMap.has(key);
246
208
  }
247
- /**
248
- * @param {String} collectionKey
249
- * @param {String} key
250
- * @returns {Boolean}
251
- */
252
209
  function isCollectionMemberKey(collectionKey, key) {
253
210
  return Str.startsWith(key, collectionKey) && key.length > collectionKey.length;
254
211
  }
255
212
  /**
256
213
  * Splits a collection member key into the collection key part and the ID part.
257
- * @param {String} key - The collection member key to split.
258
- * @returns {Array<String>} A tuple where the first element is the collection part and the second element is the ID part.
214
+ * @param key - The collection member key to split.
215
+ * @returns A tuple where the first element is the collection part and the second element is the ID part.
259
216
  */
260
217
  function splitCollectionMemberKey(key) {
261
218
  const underscoreIndex = key.indexOf('_');
@@ -267,35 +224,19 @@ function splitCollectionMemberKey(key) {
267
224
  /**
268
225
  * Checks to see if a provided key is the exact configured key of our connected subscriber
269
226
  * or if the provided key is a collection member key (in case our configured key is a "collection key")
270
- *
271
- * @private
272
- * @param {String} configKey
273
- * @param {String} key
274
- * @return {Boolean}
275
227
  */
276
228
  function isKeyMatch(configKey, key) {
277
229
  return isCollectionKey(configKey) ? Str.startsWith(key, configKey) : configKey === key;
278
230
  }
279
- /**
280
- * Checks to see if this key has been flagged as
281
- * safe for removal.
282
- *
283
- * @private
284
- * @param {String} testKey
285
- * @returns {Boolean}
286
- */
231
+ /** Checks to see if this key has been flagged as safe for removal. */
287
232
  function isSafeEvictionKey(testKey) {
288
- return underscore_1.default.some(evictionAllowList, (key) => isKeyMatch(key, testKey));
233
+ return evictionAllowList.some((key) => isKeyMatch(key, testKey));
289
234
  }
290
235
  /**
291
236
  * Tries to get a value from the cache. If the value is not present in cache it will return the default value or undefined.
292
237
  * If the requested key is a collection, it will return an object with all the collection members.
293
- *
294
- * @param {String} key
295
- * @param {Object} mapping
296
- * @returns {Mixed}
297
238
  */
298
- function tryGetCachedValue(key, mapping = {}) {
239
+ function tryGetCachedValue(key, mapping) {
299
240
  let val = OnyxCache_1.default.getValue(key);
300
241
  if (isCollectionKey(key)) {
301
242
  const allCacheKeys = OnyxCache_1.default.getAllKeys();
@@ -304,14 +245,8 @@ function tryGetCachedValue(key, mapping = {}) {
304
245
  if (allCacheKeys.size === 0) {
305
246
  return;
306
247
  }
307
- const matchingKeys = [];
308
- allCacheKeys.forEach((k) => {
309
- if (!k.startsWith(key)) {
310
- return;
311
- }
312
- matchingKeys.push(k);
313
- });
314
- const values = underscore_1.default.reduce(matchingKeys, (finalObject, matchedKey) => {
248
+ const matchingKeys = Array.from(allCacheKeys).filter((k) => k.startsWith(key));
249
+ const values = matchingKeys.reduce((finalObject, matchedKey) => {
315
250
  const cachedValue = OnyxCache_1.default.getValue(matchedKey);
316
251
  if (cachedValue) {
317
252
  // This is permissible because we're in the process of constructing the final object in a reduce function.
@@ -322,31 +257,25 @@ function tryGetCachedValue(key, mapping = {}) {
322
257
  }, {});
323
258
  val = values;
324
259
  }
325
- if (mapping.selector) {
260
+ if (mapping === null || mapping === void 0 ? void 0 : mapping.selector) {
326
261
  const state = mapping.withOnyxInstance ? mapping.withOnyxInstance.state : undefined;
327
262
  if (isCollectionKey(key)) {
328
263
  return reduceCollectionWithSelector(val, mapping.selector, state);
329
264
  }
330
- return getSubsetOfData(val, mapping.selector, state);
265
+ return mapping.selector(val, state);
331
266
  }
332
267
  return val;
333
268
  }
334
269
  /**
335
270
  * Remove a key from the recently accessed key list.
336
- *
337
- * @private
338
- * @param {String} key
339
271
  */
340
272
  function removeLastAccessedKey(key) {
341
- recentlyAccessedKeys = underscore_1.default.without(recentlyAccessedKeys, key);
273
+ recentlyAccessedKeys = recentlyAccessedKeys.filter((recentlyAccessedKey) => recentlyAccessedKey !== key);
342
274
  }
343
275
  /**
344
276
  * Add a key to the list of recently accessed keys. The least
345
277
  * recently accessed key should be at the head and the most
346
278
  * recently accessed key at the tail.
347
- *
348
- * @private
349
- * @param {String} key
350
279
  */
351
280
  function addLastAccessedKey(key) {
352
281
  // Only specific keys belong in this list since we cannot remove an entire collection.
@@ -359,25 +288,16 @@ function addLastAccessedKey(key) {
359
288
  /**
360
289
  * Removes a key previously added to this list
361
290
  * which will enable it to be deleted again.
362
- *
363
- * @private
364
- * @param {String} key
365
- * @param {Number} connectionID
366
291
  */
367
292
  function removeFromEvictionBlockList(key, connectionID) {
368
- evictionBlocklist[key] = underscore_1.default.without(evictionBlocklist[key] || [], connectionID);
293
+ var _a, _b, _c;
294
+ evictionBlocklist[key] = (_b = (_a = evictionBlocklist[key]) === null || _a === void 0 ? void 0 : _a.filter((evictionKey) => evictionKey !== connectionID)) !== null && _b !== void 0 ? _b : [];
369
295
  // Remove the key if there are no more subscribers
370
- if (evictionBlocklist[key].length === 0) {
296
+ if (((_c = evictionBlocklist[key]) === null || _c === void 0 ? void 0 : _c.length) === 0) {
371
297
  delete evictionBlocklist[key];
372
298
  }
373
299
  }
374
- /**
375
- * Keys added to this list can never be deleted.
376
- *
377
- * @private
378
- * @param {String} key
379
- * @param {Number} connectionID
380
- */
300
+ /** Keys added to this list can never be deleted. */
381
301
  function addToEvictionBlockList(key, connectionID) {
382
302
  removeFromEvictionBlockList(key, connectionID);
383
303
  if (!evictionBlocklist[key]) {
@@ -390,13 +310,10 @@ function addToEvictionBlockList(key, connectionID) {
390
310
  * the recently accessed list when initializing the app. This
391
311
  * enables keys that have not recently been accessed to be
392
312
  * removed.
393
- *
394
- * @private
395
- * @returns {Promise}
396
313
  */
397
314
  function addAllSafeEvictionKeysToRecentlyAccessedList() {
398
315
  return getAllKeys().then((keys) => {
399
- underscore_1.default.each(evictionAllowList, (safeEvictionKey) => {
316
+ evictionAllowList.forEach((safeEvictionKey) => {
400
317
  keys.forEach((key) => {
401
318
  if (!isKeyMatch(safeEvictionKey, key)) {
402
319
  return;
@@ -406,43 +323,26 @@ function addAllSafeEvictionKeysToRecentlyAccessedList() {
406
323
  });
407
324
  });
408
325
  }
409
- /**
410
- * @private
411
- * @param {String} collectionKey
412
- * @returns {Object}
413
- */
414
326
  function getCachedCollection(collectionKey) {
415
- const collectionMemberKeys = [];
416
- OnyxCache_1.default.getAllKeys().forEach((storedKey) => {
417
- if (!isCollectionMemberKey(collectionKey, storedKey)) {
418
- return;
419
- }
420
- collectionMemberKeys.push(storedKey);
421
- });
422
- return underscore_1.default.reduce(collectionMemberKeys, (prev, curr) => {
423
- const cachedValue = OnyxCache_1.default.getValue(curr);
327
+ const collectionMemberKeys = Array.from(OnyxCache_1.default.getAllKeys()).filter((storedKey) => isCollectionMemberKey(collectionKey, storedKey));
328
+ return collectionMemberKeys.reduce((prev, key) => {
329
+ const cachedValue = OnyxCache_1.default.getValue(key);
424
330
  if (!cachedValue) {
425
331
  return prev;
426
332
  }
427
333
  // eslint-disable-next-line no-param-reassign
428
- prev[curr] = cachedValue;
334
+ prev[key] = cachedValue;
429
335
  return prev;
430
336
  }, {});
431
337
  }
432
338
  /**
433
339
  * When a collection of keys change, search for any callbacks matching the collection key and trigger those callbacks
434
- *
435
- * @private
436
- * @param {String} collectionKey
437
- * @param {Object} partialCollection - a partial collection of grouped member keys
438
- * @param {boolean} [notifyRegularSubscibers=true]
439
- * @param {boolean} [notifyWithOnyxSubscibers=true]
440
340
  */
441
341
  function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers = true, notifyWithOnyxSubscibers = true) {
442
342
  // We are iterating over all subscribers similar to keyChanged(). However, we are looking for subscribers who are subscribing to either a collection key or
443
343
  // individual collection key member for the collection that is being updated. It is important to note that the collection parameter cane be a PARTIAL collection
444
344
  // and does not represent all of the combined keys and values for a collection key. It is just the "new" data that was merged in via mergeCollection().
445
- const stateMappingKeys = underscore_1.default.keys(callbackToStateMapping);
345
+ const stateMappingKeys = Object.keys(callbackToStateMapping);
446
346
  for (let i = 0; i < stateMappingKeys.length; i++) {
447
347
  const subscriber = callbackToStateMapping[stateMappingKeys[i]];
448
348
  if (!subscriber) {
@@ -464,7 +364,7 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
464
364
  // was merged in via mergeCollection().
465
365
  const cachedCollection = getCachedCollection(collectionKey);
466
366
  // Regular Onyx.connect() subscriber found.
467
- if (underscore_1.default.isFunction(subscriber.callback)) {
367
+ if (typeof subscriber.callback === 'function') {
468
368
  if (!notifyRegularSubscibers) {
469
369
  continue;
470
370
  }
@@ -477,7 +377,7 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
477
377
  }
478
378
  // If they are not using waitForCollectionCallback then we notify the subscriber with
479
379
  // the new merged data but only for any keys in the partial collection.
480
- const dataKeys = underscore_1.default.keys(partialCollection);
380
+ const dataKeys = Object.keys(partialCollection !== null && partialCollection !== void 0 ? partialCollection : {});
481
381
  for (let j = 0; j < dataKeys.length; j++) {
482
382
  const dataKey = dataKeys[j];
483
383
  subscriber.callback(cachedCollection[dataKey], dataKey);
@@ -487,13 +387,14 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
487
387
  // And if the subscriber is specifically only tracking a particular collection member key then we will
488
388
  // notify them with the cached data for that key only.
489
389
  if (isSubscribedToCollectionMemberKey) {
490
- subscriber.callback(cachedCollection[subscriber.key], subscriber.key);
390
+ const subscriberCallback = subscriber.callback;
391
+ subscriberCallback(cachedCollection[subscriber.key], subscriber.key);
491
392
  continue;
492
393
  }
493
394
  continue;
494
395
  }
495
396
  // React component subscriber found.
496
- if (subscriber.withOnyxInstance) {
397
+ if ('withOnyxInstance' in subscriber && subscriber.withOnyxInstance) {
497
398
  if (!notifyWithOnyxSubscibers) {
498
399
  continue;
499
400
  }
@@ -502,10 +403,11 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
502
403
  if (isSubscribedToCollectionKey) {
503
404
  // If the subscriber has a selector, then the component's state must only be updated with the data
504
405
  // returned by the selector.
505
- if (subscriber.selector) {
406
+ const collectionSelector = subscriber.selector;
407
+ if (collectionSelector) {
506
408
  subscriber.withOnyxInstance.setStateProxy((prevState) => {
507
409
  const previousData = prevState[subscriber.statePropertyName];
508
- const newData = reduceCollectionWithSelector(cachedCollection, subscriber.selector, subscriber.withOnyxInstance.state);
410
+ const newData = reduceCollectionWithSelector(cachedCollection, collectionSelector, subscriber.withOnyxInstance.state);
509
411
  if (!(0, fast_equals_1.deepEqual)(previousData, newData)) {
510
412
  return {
511
413
  [subscriber.statePropertyName]: newData,
@@ -516,13 +418,14 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
516
418
  continue;
517
419
  }
518
420
  subscriber.withOnyxInstance.setStateProxy((prevState) => {
519
- const finalCollection = underscore_1.default.clone(prevState[subscriber.statePropertyName] || {});
520
- const dataKeys = underscore_1.default.keys(partialCollection);
421
+ var _a;
422
+ const finalCollection = (0, clone_1.default)((_a = prevState === null || prevState === void 0 ? void 0 : prevState[subscriber.statePropertyName]) !== null && _a !== void 0 ? _a : {});
423
+ const dataKeys = Object.keys(partialCollection !== null && partialCollection !== void 0 ? partialCollection : {});
521
424
  for (let j = 0; j < dataKeys.length; j++) {
522
425
  const dataKey = dataKeys[j];
523
426
  finalCollection[dataKey] = cachedCollection[dataKey];
524
427
  }
525
- PerformanceUtils.logSetStateCall(subscriber, prevState[subscriber.statePropertyName], finalCollection, 'keysChanged', collectionKey);
428
+ PerformanceUtils.logSetStateCall(subscriber, prevState === null || prevState === void 0 ? void 0 : prevState[subscriber.statePropertyName], finalCollection, 'keysChanged', collectionKey);
526
429
  return {
527
430
  [subscriber.statePropertyName]: finalCollection,
528
431
  };
@@ -533,17 +436,18 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
533
436
  if (isSubscribedToCollectionMemberKey) {
534
437
  // However, we only want to update this subscriber if the partial data contains a change.
535
438
  // Otherwise, we would update them with a value they already have and trigger an unnecessary re-render.
536
- const dataFromCollection = partialCollection[subscriber.key];
537
- if (underscore_1.default.isUndefined(dataFromCollection)) {
439
+ const dataFromCollection = partialCollection === null || partialCollection === void 0 ? void 0 : partialCollection[subscriber.key];
440
+ if (dataFromCollection === undefined) {
538
441
  continue;
539
442
  }
540
443
  // If the subscriber has a selector, then the component's state must only be updated with the data
541
444
  // returned by the selector and the state should only change when the subset of data changes from what
542
445
  // it was previously.
543
- if (subscriber.selector) {
446
+ const selector = subscriber.selector;
447
+ if (selector) {
544
448
  subscriber.withOnyxInstance.setStateProxy((prevState) => {
545
449
  const prevData = prevState[subscriber.statePropertyName];
546
- const newData = getSubsetOfData(cachedCollection[subscriber.key], subscriber.selector, subscriber.withOnyxInstance.state);
450
+ const newData = selector(cachedCollection[subscriber.key], subscriber.withOnyxInstance.state);
547
451
  if (!(0, fast_equals_1.deepEqual)(prevData, newData)) {
548
452
  PerformanceUtils.logSetStateCall(subscriber, prevData, newData, 'keysChanged', collectionKey);
549
453
  return {
@@ -578,18 +482,10 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
578
482
  *
579
483
  * @example
580
484
  * keyChanged(key, value, subscriber => subscriber.initWithStoredValues === false)
581
- *
582
- * @private
583
- * @param {String} key
584
- * @param {*} data
585
- * @param {*} prevData
586
- * @param {Function} [canUpdateSubscriber] only subscribers that pass this truth test will be updated
587
- * @param {boolean} [notifyRegularSubscibers=true]
588
- * @param {boolean} [notifyWithOnyxSubscibers=true]
589
485
  */
590
486
  function keyChanged(key, data, prevData, canUpdateSubscriber = () => true, notifyRegularSubscibers = true, notifyWithOnyxSubscibers = true) {
591
487
  // Add or remove this key from the recentlyAccessedKeys lists
592
- if (!underscore_1.default.isNull(data)) {
488
+ if (data !== null) {
593
489
  addLastAccessedKey(key);
594
490
  }
595
491
  else {
@@ -598,14 +494,14 @@ function keyChanged(key, data, prevData, canUpdateSubscriber = () => true, notif
598
494
  // We are iterating over all subscribers to see if they are interested in the key that has just changed. If the subscriber's key is a collection key then we will
599
495
  // 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
600
496
  // was connected via withOnyx we will call setState() directly on the withOnyx instance. If it is a regular connection we will pass the data to the provided callback.
601
- const stateMappingKeys = underscore_1.default.keys(callbackToStateMapping);
497
+ const stateMappingKeys = Object.keys(callbackToStateMapping);
602
498
  for (let i = 0; i < stateMappingKeys.length; i++) {
603
499
  const subscriber = callbackToStateMapping[stateMappingKeys[i]];
604
500
  if (!subscriber || !isKeyMatch(subscriber.key, key) || !canUpdateSubscriber(subscriber)) {
605
501
  continue;
606
502
  }
607
503
  // Subscriber is a regular call to connect() and provided a callback
608
- if (underscore_1.default.isFunction(subscriber.callback)) {
504
+ if (typeof subscriber.callback === 'function') {
609
505
  if (!notifyRegularSubscibers) {
610
506
  continue;
611
507
  }
@@ -615,23 +511,25 @@ function keyChanged(key, data, prevData, canUpdateSubscriber = () => true, notif
615
511
  subscriber.callback(cachedCollection);
616
512
  continue;
617
513
  }
618
- subscriber.callback(data, key);
514
+ const subscriberCallback = subscriber.callback;
515
+ subscriberCallback(data, key);
619
516
  continue;
620
517
  }
621
518
  // Subscriber connected via withOnyx() HOC
622
- if (subscriber.withOnyxInstance) {
519
+ if ('withOnyxInstance' in subscriber && subscriber.withOnyxInstance) {
623
520
  if (!notifyWithOnyxSubscibers) {
624
521
  continue;
625
522
  }
523
+ const selector = subscriber.selector;
626
524
  // Check if we are subscribing to a collection key and overwrite the collection member key value in state
627
525
  if (isCollectionKey(subscriber.key)) {
628
526
  // If the subscriber has a selector, then the consumer of this data must only be given the data
629
527
  // returned by the selector and only when the selected data has changed.
630
- if (subscriber.selector) {
528
+ if (selector) {
631
529
  subscriber.withOnyxInstance.setStateProxy((prevState) => {
632
530
  const prevWithOnyxData = prevState[subscriber.statePropertyName];
633
531
  const newWithOnyxData = {
634
- [key]: getSubsetOfData(data, subscriber.selector, subscriber.withOnyxInstance.state),
532
+ [key]: selector(data, subscriber.withOnyxInstance.state),
635
533
  };
636
534
  const prevDataWithNewData = Object.assign(Object.assign({}, prevWithOnyxData), newWithOnyxData);
637
535
  if (!(0, fast_equals_1.deepEqual)(prevWithOnyxData, prevDataWithNewData)) {
@@ -656,10 +554,10 @@ function keyChanged(key, data, prevData, canUpdateSubscriber = () => true, notif
656
554
  }
657
555
  // If the subscriber has a selector, then the component's state must only be updated with the data
658
556
  // returned by the selector and only if the selected data has changed.
659
- if (subscriber.selector) {
557
+ if (selector) {
660
558
  subscriber.withOnyxInstance.setStateProxy(() => {
661
- const previousValue = getSubsetOfData(prevData, subscriber.selector, subscriber.withOnyxInstance.state);
662
- const newValue = getSubsetOfData(data, subscriber.selector, subscriber.withOnyxInstance.state);
559
+ const previousValue = selector(prevData, subscriber.withOnyxInstance.state);
560
+ const newValue = selector(data, subscriber.withOnyxInstance.state);
663
561
  if (!(0, fast_equals_1.deepEqual)(previousValue, newValue)) {
664
562
  return {
665
563
  [subscriber.statePropertyName]: newValue,
@@ -693,24 +591,15 @@ function keyChanged(key, data, prevData, canUpdateSubscriber = () => true, notif
693
591
  * Sends the data obtained from the keys to the connection. It either:
694
592
  * - sets state on the withOnyxInstances
695
593
  * - triggers the callback function
696
- *
697
- * @private
698
- * @param {Object} mapping
699
- * @param {Object} [mapping.withOnyxInstance]
700
- * @param {String} [mapping.statePropertyName]
701
- * @param {Function} [mapping.callback]
702
- * @param {String} [mapping.selector]
703
- * @param {*|null} val
704
- * @param {String|undefined} matchedKey
705
- * @param {Boolean} isBatched
706
594
  */
707
595
  function sendDataToConnection(mapping, val, matchedKey, isBatched) {
596
+ var _a, _b;
708
597
  // If the mapping no longer exists then we should not send any data.
709
598
  // This means our subscriber disconnected or withOnyx wrapped component unmounted.
710
599
  if (!callbackToStateMapping[mapping.connectionID]) {
711
600
  return;
712
601
  }
713
- if (mapping.withOnyxInstance) {
602
+ if ('withOnyxInstance' in mapping && mapping.withOnyxInstance) {
714
603
  let newData = val;
715
604
  // If the mapping has a selector, then the component's state must only be updated with the data
716
605
  // returned by the selector.
@@ -719,30 +608,23 @@ function sendDataToConnection(mapping, val, matchedKey, isBatched) {
719
608
  newData = reduceCollectionWithSelector(val, mapping.selector, mapping.withOnyxInstance.state);
720
609
  }
721
610
  else {
722
- newData = getSubsetOfData(val, mapping.selector, mapping.withOnyxInstance.state);
611
+ newData = mapping.selector(val, mapping.withOnyxInstance.state);
723
612
  }
724
613
  }
725
614
  PerformanceUtils.logSetStateCall(mapping, null, newData, 'sendDataToConnection');
726
615
  if (isBatched) {
727
- batchUpdates(() => {
728
- mapping.withOnyxInstance.setWithOnyxState(mapping.statePropertyName, newData);
729
- });
616
+ batchUpdates(() => mapping.withOnyxInstance.setWithOnyxState(mapping.statePropertyName, newData));
730
617
  }
731
618
  else {
732
619
  mapping.withOnyxInstance.setWithOnyxState(mapping.statePropertyName, newData);
733
620
  }
734
621
  return;
735
622
  }
736
- if (underscore_1.default.isFunction(mapping.callback)) {
737
- mapping.callback(val, matchedKey);
738
- }
623
+ (_b = (_a = mapping).callback) === null || _b === void 0 ? void 0 : _b.call(_a, val, matchedKey);
739
624
  }
740
625
  /**
741
626
  * We check to see if this key is flagged as safe for eviction and add it to the recentlyAccessedKeys list so that when we
742
627
  * run out of storage the least recently accessed key can be removed.
743
- *
744
- * @private
745
- * @param {Object} mapping
746
628
  */
747
629
  function addKeyToRecentlyAccessedIfNeeded(mapping) {
748
630
  if (!isSafeEvictionKey(mapping.key)) {
@@ -750,9 +632,9 @@ function addKeyToRecentlyAccessedIfNeeded(mapping) {
750
632
  }
751
633
  // Try to free some cache whenever we connect to a safe eviction key
752
634
  OnyxCache_1.default.removeLeastRecentlyUsedKeys();
753
- if (mapping.withOnyxInstance && !isCollectionKey(mapping.key)) {
635
+ if ('withOnyxInstance' in mapping && mapping.withOnyxInstance && !isCollectionKey(mapping.key)) {
754
636
  // All React components subscribing to a key flagged as a safe eviction key must implement the canEvict property.
755
- if (underscore_1.default.isUndefined(mapping.canEvict)) {
637
+ if (mapping.canEvict === undefined) {
756
638
  throw new Error(`Cannot subscribe to safe eviction key '${mapping.key}' without providing a canEvict value.`);
757
639
  }
758
640
  addLastAccessedKey(mapping.key);
@@ -760,10 +642,6 @@ function addKeyToRecentlyAccessedIfNeeded(mapping) {
760
642
  }
761
643
  /**
762
644
  * Gets the data for a given an array of matching keys, combines them into an object, and sends the result back to the subscriber.
763
- *
764
- * @private
765
- * @param {Array} matchingKeys
766
- * @param {Object} mapping
767
645
  */
768
646
  function getCollectionDataAndSendAsObject(matchingKeys, mapping) {
769
647
  // Keys that are not in the cache
@@ -808,7 +686,7 @@ function getCollectionDataAndSendAsObject(matchingKeys, mapping) {
808
686
  // We are going to get the missing keys using multiGet from the storage.
809
687
  .then(() => {
810
688
  if (missingKeys.length === 0) {
811
- return Promise.resolve();
689
+ return Promise.resolve(undefined);
812
690
  }
813
691
  return storage_1.default.multiGet(missingKeys);
814
692
  })
@@ -819,9 +697,9 @@ function getCollectionDataAndSendAsObject(matchingKeys, mapping) {
819
697
  }
820
698
  // temp object is used to merge the missing data into the cache
821
699
  const temp = {};
822
- values.forEach((value) => {
823
- data[value[0]] = value[1];
824
- temp[value[0]] = value[1];
700
+ values.forEach(([key, value]) => {
701
+ data[key] = value;
702
+ temp[key] = value;
825
703
  });
826
704
  OnyxCache_1.default.merge(temp);
827
705
  return Promise.resolve();
@@ -836,49 +714,31 @@ function getCollectionDataAndSendAsObject(matchingKeys, mapping) {
836
714
  *
837
715
  * @example
838
716
  * scheduleSubscriberUpdate(key, value, subscriber => subscriber.initWithStoredValues === false)
839
- *
840
- * @param {String} key
841
- * @param {*} value
842
- * @param {*} prevValue
843
- * @param {Function} [canUpdateSubscriber] only subscribers that pass this truth test will be updated
844
- * @returns {Promise}
845
717
  */
846
718
  function scheduleSubscriberUpdate(key, value, prevValue, canUpdateSubscriber = () => true) {
847
719
  const promise = Promise.resolve().then(() => keyChanged(key, value, prevValue, canUpdateSubscriber, true, false));
848
720
  batchUpdates(() => keyChanged(key, value, prevValue, canUpdateSubscriber, false, true));
849
- return Promise.all([maybeFlushBatchUpdates(), promise]);
721
+ return Promise.all([maybeFlushBatchUpdates(), promise]).then(() => undefined);
850
722
  }
851
723
  /**
852
724
  * This method is similar to notifySubscribersOnNextTick but it is built for working specifically with collections
853
725
  * so that keysChanged() is triggered for the collection and not keyChanged(). If this was not done, then the
854
726
  * subscriber callbacks receive the data in a different format than they normally expect and it breaks code.
855
- *
856
- * @param {String} key
857
- * @param {*} value
858
- * @returns {Promise}
859
727
  */
860
728
  function scheduleNotifyCollectionSubscribers(key, value) {
861
729
  const promise = Promise.resolve().then(() => keysChanged(key, value, true, false));
862
730
  batchUpdates(() => keysChanged(key, value, false, true));
863
- return Promise.all([maybeFlushBatchUpdates(), promise]);
731
+ return Promise.all([maybeFlushBatchUpdates(), promise]).then(() => undefined);
864
732
  }
865
733
  /**
866
734
  * Remove a key from Onyx and update the subscribers
867
- *
868
- * @private
869
- * @param {String} key
870
- * @return {Promise}
871
735
  */
872
736
  function remove(key) {
873
737
  const prevValue = OnyxCache_1.default.getValue(key, false);
874
738
  OnyxCache_1.default.drop(key);
875
739
  scheduleSubscriberUpdate(key, null, prevValue);
876
- return storage_1.default.removeItem(key);
740
+ return storage_1.default.removeItem(key).then(() => undefined);
877
741
  }
878
- /**
879
- * @private
880
- * @returns {Promise<void>}
881
- */
882
742
  function reportStorageQuota() {
883
743
  return storage_1.default.getDatabaseSize()
884
744
  .then(({ bytesUsed, bytesRemaining }) => {
@@ -892,12 +752,6 @@ function reportStorageQuota() {
892
752
  * If we fail to set or merge we must handle this by
893
753
  * evicting some data from Onyx and then retrying to do
894
754
  * whatever it is we attempted to do.
895
- *
896
- * @private
897
- * @param {Error} error
898
- * @param {Function} onyxMethod
899
- * @param {...any} args
900
- * @return {Promise}
901
755
  */
902
756
  function evictStorageAndRetry(error, onyxMethod, ...args) {
903
757
  Logger.logInfo(`Failed to save to storage. Error: ${error}. onyxMethod: ${onyxMethod.name}`);
@@ -906,7 +760,7 @@ function evictStorageAndRetry(error, onyxMethod, ...args) {
906
760
  throw error;
907
761
  }
908
762
  // Find the first key that we can remove that has no subscribers in our blocklist
909
- const keyForRemoval = underscore_1.default.find(recentlyAccessedKeys, (key) => !evictionBlocklist[key]);
763
+ const keyForRemoval = recentlyAccessedKeys.find((key) => !evictionBlocklist[key]);
910
764
  if (!keyForRemoval) {
911
765
  // If we have no acceptable keys to remove then we are possibly trying to save mission critical data. If this is the case,
912
766
  // 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
@@ -917,16 +771,11 @@ function evictStorageAndRetry(error, onyxMethod, ...args) {
917
771
  // Remove the least recently viewed key that is not currently being accessed and retry.
918
772
  Logger.logInfo(`Out of storage. Evicting least recently accessed key (${keyForRemoval}) and retrying.`);
919
773
  reportStorageQuota();
774
+ // @ts-expect-error No overload matches this call.
920
775
  return remove(keyForRemoval).then(() => onyxMethod(...args));
921
776
  }
922
777
  /**
923
- * Notifys subscribers and writes current value to cache
924
- *
925
- * @param {String} key
926
- * @param {*} value
927
- * @param {Boolean} hasChanged
928
- * @param {Boolean} wasRemoved
929
- * @returns {Promise}
778
+ * Notifies subscribers and writes current value to cache
930
779
  */
931
780
  function broadcastUpdate(key, value, hasChanged, wasRemoved = false) {
932
781
  const prevValue = OnyxCache_1.default.getValue(key, false);
@@ -938,24 +787,19 @@ function broadcastUpdate(key, value, hasChanged, wasRemoved = false) {
938
787
  else {
939
788
  OnyxCache_1.default.addToAccessedKeys(key);
940
789
  }
941
- return scheduleSubscriberUpdate(key, value, prevValue, (subscriber) => hasChanged || subscriber.initWithStoredValues === false);
790
+ return scheduleSubscriberUpdate(key, value, prevValue, (subscriber) => hasChanged || (subscriber === null || subscriber === void 0 ? void 0 : subscriber.initWithStoredValues) === false).then(() => undefined);
942
791
  }
943
- /**
944
- * @param {String} key
945
- * @returns {Boolean}
946
- */
947
792
  function hasPendingMergeForKey(key) {
948
- return Boolean(mergeQueue[key]);
793
+ return !!mergeQueue[key];
949
794
  }
950
795
  /**
951
796
  * Removes a key from storage if the value is null.
952
797
  * Otherwise removes all nested null values in objects and returns the object
953
- * @param {String} key
954
- * @param {Mixed} value
955
- * @returns {Mixed} The value without null values and a boolean "wasRemoved", which indicates if the key got removed completely
798
+ *
799
+ * @returns The value without null values and a boolean "wasRemoved", which indicates if the key got removed completely
956
800
  */
957
801
  function removeNullValues(key, value) {
958
- if (underscore_1.default.isNull(value)) {
802
+ if (value === null) {
959
803
  remove(key);
960
804
  return { value, wasRemoved: true };
961
805
  }
@@ -968,16 +812,16 @@ function removeNullValues(key, value) {
968
812
  * Storage expects array like: [["@MyApp_user", value_1], ["@MyApp_key", value_2]]
969
813
  * This method transforms an object like {'@MyApp_user': myUserValue, '@MyApp_key': myKeyValue}
970
814
  * to an array of key-value pairs in the above format and removes key-value pairs that are being set to null
971
- * @private
972
- * @param {Record} data
973
- * @return {Array} an array of key - value pairs <[key, value]>
815
+
816
+ * @return an array of key - value pairs <[key, value]>
974
817
  */
975
818
  function prepareKeyValuePairsForStorage(data) {
976
819
  const keyValuePairs = [];
977
- underscore_1.default.forEach(data, (value, key) => {
820
+ Object.entries(data).forEach(([key, value]) => {
978
821
  const { value: valueAfterRemoving, wasRemoved } = removeNullValues(key, value);
979
- if (wasRemoved)
822
+ if (wasRemoved) {
980
823
  return;
824
+ }
981
825
  keyValuePairs.push([key, valueAfterRemoving]);
982
826
  });
983
827
  return keyValuePairs;
@@ -985,20 +829,16 @@ function prepareKeyValuePairsForStorage(data) {
985
829
  /**
986
830
  * Merges an array of changes with an existing value
987
831
  *
988
- * @private
989
- * @param {*} existingValue
990
- * @param {Array<*>} changes Array of changes that should be applied to the existing value
991
- * @param {Boolean} shouldRemoveNullObjectValues
992
- * @returns {*}
832
+ * @param changes Array of changes that should be applied to the existing value
993
833
  */
994
834
  function applyMerge(existingValue, changes, shouldRemoveNullObjectValues) {
995
- const lastChange = underscore_1.default.last(changes);
996
- if (underscore_1.default.isArray(lastChange)) {
835
+ const lastChange = changes === null || changes === void 0 ? void 0 : changes.at(-1);
836
+ if (Array.isArray(lastChange)) {
997
837
  return lastChange;
998
838
  }
999
- if (underscore_1.default.some(changes, underscore_1.default.isObject)) {
839
+ if (changes.some((change) => typeof change === 'object')) {
1000
840
  // Object values are then merged one after the other
1001
- return underscore_1.default.reduce(changes, (modifiedData, change) => utils_1.default.fastMerge(modifiedData, change, shouldRemoveNullObjectValues), existingValue || {});
841
+ return changes.reduce((modifiedData, change) => utils_1.default.fastMerge(modifiedData, change, shouldRemoveNullObjectValues), existingValue || {});
1002
842
  }
1003
843
  // If we have anything else we can't merge it so we'll
1004
844
  // simply return the last value that was queued
@@ -1006,15 +846,13 @@ function applyMerge(existingValue, changes, shouldRemoveNullObjectValues) {
1006
846
  }
1007
847
  /**
1008
848
  * Merge user provided default key value pairs.
1009
- * @private
1010
- * @returns {Promise}
1011
849
  */
1012
850
  function initializeWithDefaultKeyStates() {
1013
- return storage_1.default.multiGet(underscore_1.default.keys(defaultKeyStates)).then((pairs) => {
1014
- const existingDataAsObject = underscore_1.default.object(pairs);
851
+ return storage_1.default.multiGet(Object.keys(defaultKeyStates)).then((pairs) => {
852
+ const existingDataAsObject = Object.fromEntries(pairs);
1015
853
  const merged = utils_1.default.fastMerge(existingDataAsObject, defaultKeyStates);
1016
- OnyxCache_1.default.merge(merged);
1017
- underscore_1.default.each(merged, (val, key) => keyChanged(key, val, existingDataAsObject));
854
+ OnyxCache_1.default.merge(merged !== null && merged !== void 0 ? merged : {});
855
+ Object.entries(merged !== null && merged !== void 0 ? merged : {}).forEach(([key, value]) => keyChanged(key, value, existingDataAsObject));
1018
856
  });
1019
857
  }
1020
858
  const OnyxUtils = {