react-native-onyx 1.0.131 → 2.0.1

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.
Files changed (64) hide show
  1. package/API.md +83 -22
  2. package/README.md +3 -5
  3. package/dist/DevTools.d.ts +23 -0
  4. package/{lib → dist}/DevTools.js +16 -18
  5. package/dist/Logger.js +32 -0
  6. package/dist/MDTable.d.ts +36 -0
  7. package/{lib → dist}/MDTable.js +12 -17
  8. package/{lib → dist}/Onyx.js +278 -477
  9. package/dist/OnyxCache.d.ts +121 -0
  10. package/{lib → dist}/OnyxCache.js +16 -53
  11. package/{lib/Str.js → dist/Str.d.ts} +2 -11
  12. package/dist/Str.js +31 -0
  13. package/dist/SyncQueue.d.ts +32 -0
  14. package/{lib → dist}/SyncQueue.js +9 -11
  15. package/dist/batch.d.ts +2 -0
  16. package/dist/batch.js +4 -0
  17. package/dist/batch.native.d.ts +2 -0
  18. package/dist/batch.native.js +4 -0
  19. package/dist/compose.d.ts +19 -0
  20. package/{lib → dist}/compose.js +5 -8
  21. package/dist/createDeferredTask.d.ts +12 -0
  22. package/{lib → dist}/createDeferredTask.js +4 -2
  23. package/dist/index.d.ts +6 -0
  24. package/dist/index.js +10 -0
  25. package/dist/metrics/PerformanceUtils.d.ts +14 -0
  26. package/{lib → dist}/metrics/PerformanceUtils.js +16 -16
  27. package/dist/metrics/index.d.ts +4 -0
  28. package/dist/metrics/index.js +14 -0
  29. package/dist/metrics/index.native.d.ts +43 -0
  30. package/{lib → dist}/metrics/index.native.js +80 -102
  31. package/{lib/storage/NativeStorage.js → dist/storage/NativeStorage.d.ts} +1 -2
  32. package/dist/storage/NativeStorage.js +7 -0
  33. package/dist/storage/WebStorage.d.ts +19 -0
  34. package/{lib → dist}/storage/WebStorage.js +24 -34
  35. package/dist/storage/__mocks__/index.d.ts +23 -0
  36. package/{lib → dist}/storage/__mocks__/index.js +17 -19
  37. package/{lib/storage/index.web.js → dist/storage/index.d.ts} +1 -2
  38. package/dist/storage/index.js +7 -0
  39. package/{lib/storage/index.native.js → dist/storage/index.native.d.ts} +1 -2
  40. package/dist/storage/index.native.js +7 -0
  41. package/dist/storage/providers/IDBKeyVal.d.ts +26 -0
  42. package/{lib → dist}/storage/providers/IDBKeyVal.js +38 -52
  43. package/dist/storage/providers/SQLiteStorage.d.ts +52 -0
  44. package/{lib → dist}/storage/providers/SQLiteStorage.js +27 -42
  45. package/{lib → dist}/utils.js +14 -27
  46. package/{lib → dist}/withOnyx.js +122 -159
  47. package/package.json +23 -54
  48. package/dist/web.development.js +0 -4308
  49. package/dist/web.development.js.map +0 -1
  50. package/dist/web.min.js +0 -2
  51. package/dist/web.min.js.map +0 -1
  52. package/lib/Logger.js +0 -31
  53. package/lib/batch.js +0 -3
  54. package/lib/batch.native.js +0 -3
  55. package/lib/index.d.ts +0 -6
  56. package/lib/index.js +0 -5
  57. package/lib/metrics/index.web.js +0 -10
  58. package/native.js +0 -11
  59. package/web.js +0 -12
  60. /package/{lib → dist}/Logger.d.ts +0 -0
  61. /package/{lib → dist}/Onyx.d.ts +0 -0
  62. /package/{lib → dist}/types.d.ts +0 -0
  63. /package/{lib → dist}/utils.d.ts +0 -0
  64. /package/{lib → dist}/withOnyx.d.ts +0 -0
@@ -1,16 +1,43 @@
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
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
1
29
  /* eslint-disable no-continue */
2
- import {deepEqual} from 'fast-equals';
3
- import _ from 'underscore';
4
- import * as Logger from './Logger';
5
- import cache from './OnyxCache';
6
- import * as Str from './Str';
7
- import createDeferredTask from './createDeferredTask';
8
- import * as PerformanceUtils from './metrics/PerformanceUtils';
9
- import Storage from './storage';
10
- import utils from './utils';
11
- import unstable_batchedUpdates from './batch';
12
- import DevTools from './DevTools';
13
-
30
+ const fast_equals_1 = require("fast-equals");
31
+ const underscore_1 = __importDefault(require("underscore"));
32
+ const Logger = __importStar(require("./Logger"));
33
+ const OnyxCache_1 = __importDefault(require("./OnyxCache"));
34
+ const Str = __importStar(require("./Str"));
35
+ const createDeferredTask_1 = __importDefault(require("./createDeferredTask"));
36
+ const PerformanceUtils = __importStar(require("./metrics/PerformanceUtils"));
37
+ const storage_1 = __importDefault(require("./storage"));
38
+ const utils_1 = __importDefault(require("./utils"));
39
+ const batch_1 = __importDefault(require("./batch"));
40
+ const DevTools_1 = __importDefault(require("./DevTools"));
14
41
  // Method constants
15
42
  const METHOD = {
16
43
  SET: 'set',
@@ -19,40 +46,29 @@ const METHOD = {
19
46
  MULTI_SET: 'multiset',
20
47
  CLEAR: 'clear',
21
48
  };
22
-
23
49
  // Key/value store of Onyx key and arrays of values to merge
24
50
  const mergeQueue = {};
25
51
  const mergeQueuePromise = {};
26
-
27
52
  // Keeps track of the last connectionID that was used so we can keep incrementing it
28
53
  let lastConnectionID = 0;
29
-
30
54
  // Holds a mapping of all the react components that want their state subscribed to a store key
31
55
  const callbackToStateMapping = {};
32
-
33
56
  // Keeps a copy of the values of the onyx collection keys as a map for faster lookups
34
57
  let onyxCollectionKeyMap = new Map();
35
-
36
58
  // Holds a list of keys that have been directly subscribed to or recently modified from least to most recent
37
59
  let recentlyAccessedKeys = [];
38
-
39
60
  // Holds a list of keys that are safe to remove when we reach max storage. If a key does not match with
40
61
  // whatever appears in this list it will NEVER be a candidate for eviction.
41
62
  let evictionAllowList = [];
42
-
43
63
  // Holds a map of keys and connectionID arrays whose keys will never be automatically evicted as
44
64
  // long as we have at least one subscriber that returns false for the canEvict property.
45
65
  const evictionBlocklist = {};
46
-
47
66
  // Optional user-provided key value states set when Onyx initializes or clears
48
67
  let defaultKeyStates = {};
49
-
50
68
  // Connections can be made before `Onyx.init`. They would wait for this task before resolving
51
- const deferredInitTask = createDeferredTask();
52
-
69
+ const deferredInitTask = (0, createDeferredTask_1.default)();
53
70
  let batchUpdatesPromise = null;
54
71
  let batchUpdatesQueue = [];
55
-
56
72
  /**
57
73
  * Sends an action to DevTools extension
58
74
  *
@@ -62,9 +78,8 @@ let batchUpdatesQueue = [];
62
78
  * @param {any} mergedValue - (optional) value that was written in the storage after a merge method was executed.
63
79
  */
64
80
  function sendActionToDevTools(method, key, value, mergedValue = undefined) {
65
- DevTools.registerAction(utils.formatActionName(method, key), value, key ? {[key]: mergedValue || value} : value);
81
+ DevTools_1.default.registerAction(utils_1.default.formatActionName(method, key), value, key ? { [key]: mergedValue || value } : value);
66
82
  }
67
-
68
83
  /**
69
84
  * We are batching together onyx updates. This helps with use cases where we schedule onyx updates after each other.
70
85
  * This happens for example in the Onyx.update function, where we process API responses that might contain a lot of
@@ -76,7 +91,6 @@ function maybeFlushBatchUpdates() {
76
91
  if (batchUpdatesPromise) {
77
92
  return batchUpdatesPromise;
78
93
  }
79
-
80
94
  batchUpdatesPromise = new Promise((resolve) => {
81
95
  /* We use (setTimeout, 0) here which should be called once native module calls are flushed (usually at the end of the frame)
82
96
  * We may investigate if (setTimeout, 1) (which in React Native is equal to requestAnimationFrame) works even better
@@ -86,23 +100,20 @@ function maybeFlushBatchUpdates() {
86
100
  const updatesCopy = batchUpdatesQueue;
87
101
  batchUpdatesQueue = [];
88
102
  batchUpdatesPromise = null;
89
- unstable_batchedUpdates(() => {
103
+ (0, batch_1.default)(() => {
90
104
  updatesCopy.forEach((applyUpdates) => {
91
105
  applyUpdates();
92
106
  });
93
107
  });
94
-
95
108
  resolve();
96
109
  }, 0);
97
110
  });
98
111
  return batchUpdatesPromise;
99
112
  }
100
-
101
113
  function batchUpdates(updates) {
102
114
  batchUpdatesQueue.push(updates);
103
115
  return maybeFlushBatchUpdates();
104
116
  }
105
-
106
117
  /**
107
118
  * Uses a selector function to return a simplified version of sourceData
108
119
  * @param {Mixed} sourceData
@@ -111,7 +122,6 @@ function batchUpdates(updates) {
111
122
  * @returns {Mixed}
112
123
  */
113
124
  const getSubsetOfData = (sourceData, selector, withOnyxInstanceState) => selector(sourceData, withOnyxInstanceState);
114
-
115
125
  /**
116
126
  * Takes a collection of items (eg. {testKey_1:{a:'a'}, testKey_2:{b:'b'}})
117
127
  * and runs it through a reducer function to return a subset of the data according to a selector.
@@ -121,18 +131,11 @@ const getSubsetOfData = (sourceData, selector, withOnyxInstanceState) => selecto
121
131
  * @param {Object} [withOnyxInstanceState]
122
132
  * @returns {Object}
123
133
  */
124
- const reduceCollectionWithSelector = (collection, selector, withOnyxInstanceState) =>
125
- _.reduce(
126
- collection,
127
- (finalCollection, item, key) => {
128
- // eslint-disable-next-line no-param-reassign
129
- finalCollection[key] = getSubsetOfData(item, selector, withOnyxInstanceState);
130
-
131
- return finalCollection;
132
- },
133
- {},
134
- );
135
-
134
+ const reduceCollectionWithSelector = (collection, selector, withOnyxInstanceState) => underscore_1.default.reduce(collection, (finalCollection, item, key) => {
135
+ // eslint-disable-next-line no-param-reassign
136
+ finalCollection[key] = getSubsetOfData(item, selector, withOnyxInstanceState);
137
+ return finalCollection;
138
+ }, {});
136
139
  /**
137
140
  * Get some data from the store
138
141
  *
@@ -142,28 +145,23 @@ const reduceCollectionWithSelector = (collection, selector, withOnyxInstanceStat
142
145
  */
143
146
  function get(key) {
144
147
  // When we already have the value in cache - resolve right away
145
- if (cache.hasCacheForKey(key)) {
146
- return Promise.resolve(cache.getValue(key));
148
+ if (OnyxCache_1.default.hasCacheForKey(key)) {
149
+ return Promise.resolve(OnyxCache_1.default.getValue(key));
147
150
  }
148
-
149
151
  const taskName = `get:${key}`;
150
-
151
152
  // When a value retrieving task for this key is still running hook to it
152
- if (cache.hasPendingTask(taskName)) {
153
- return cache.getTaskPromise(taskName);
153
+ if (OnyxCache_1.default.hasPendingTask(taskName)) {
154
+ return OnyxCache_1.default.getTaskPromise(taskName);
154
155
  }
155
-
156
156
  // Otherwise retrieve the value from storage and capture a promise to aid concurrent usages
157
- const promise = Storage.getItem(key)
157
+ const promise = storage_1.default.getItem(key)
158
158
  .then((val) => {
159
- cache.set(key, val);
160
- return val;
161
- })
159
+ OnyxCache_1.default.set(key, val);
160
+ return val;
161
+ })
162
162
  .catch((err) => Logger.logInfo(`Unable to get item from persistent storage. Key: ${key} Error: ${err}`));
163
-
164
- return cache.captureTask(taskName, promise);
163
+ return OnyxCache_1.default.captureTask(taskName, promise);
165
164
  }
166
-
167
165
  /**
168
166
  * Returns current key names stored in persisted storage
169
167
  * @private
@@ -171,27 +169,22 @@ function get(key) {
171
169
  */
172
170
  function getAllKeys() {
173
171
  // When we've already read stored keys, resolve right away
174
- const storedKeys = cache.getAllKeys();
172
+ const storedKeys = OnyxCache_1.default.getAllKeys();
175
173
  if (storedKeys.length > 0) {
176
174
  return Promise.resolve(storedKeys);
177
175
  }
178
-
179
176
  const taskName = 'getAllKeys';
180
-
181
177
  // When a value retrieving task for all keys is still running hook to it
182
- if (cache.hasPendingTask(taskName)) {
183
- return cache.getTaskPromise(taskName);
178
+ if (OnyxCache_1.default.hasPendingTask(taskName)) {
179
+ return OnyxCache_1.default.getTaskPromise(taskName);
184
180
  }
185
-
186
181
  // Otherwise retrieve the keys from storage and capture a promise to aid concurrent usages
187
- const promise = Storage.getAllKeys().then((keys) => {
188
- _.each(keys, (key) => cache.addKey(key));
182
+ const promise = storage_1.default.getAllKeys().then((keys) => {
183
+ underscore_1.default.each(keys, (key) => OnyxCache_1.default.addKey(key));
189
184
  return keys;
190
185
  });
191
-
192
- return cache.captureTask(taskName, promise);
186
+ return OnyxCache_1.default.captureTask(taskName, promise);
193
187
  }
194
-
195
188
  /**
196
189
  * Checks to see if the a subscriber's supplied key
197
190
  * is associated with a collection of keys.
@@ -203,7 +196,6 @@ function getAllKeys() {
203
196
  function isCollectionKey(key) {
204
197
  return onyxCollectionKeyMap.has(key);
205
198
  }
206
-
207
199
  /**
208
200
  * @param {String} collectionKey
209
201
  * @param {String} key
@@ -212,7 +204,6 @@ function isCollectionKey(key) {
212
204
  function isCollectionMemberKey(collectionKey, key) {
213
205
  return Str.startsWith(key, collectionKey) && key.length > collectionKey.length;
214
206
  }
215
-
216
207
  /**
217
208
  * Checks to see if a provided key is the exact configured key of our connected subscriber
218
209
  * or if the provided key is a collection member key (in case our configured key is a "collection key")
@@ -225,7 +216,6 @@ function isCollectionMemberKey(collectionKey, key) {
225
216
  function isKeyMatch(configKey, key) {
226
217
  return isCollectionKey(configKey) ? Str.startsWith(key, configKey) : configKey === key;
227
218
  }
228
-
229
219
  /**
230
220
  * Checks to see if this key has been flagged as
231
221
  * safe for removal.
@@ -235,9 +225,8 @@ function isKeyMatch(configKey, key) {
235
225
  * @returns {Boolean}
236
226
  */
237
227
  function isSafeEvictionKey(testKey) {
238
- return _.some(evictionAllowList, (key) => isKeyMatch(key, testKey));
228
+ return underscore_1.default.some(evictionAllowList, (key) => isKeyMatch(key, testKey));
239
229
  }
240
-
241
230
  /**
242
231
  * Tries to get a value from the cache. If the value is not present in cache it will return the default value or undefined.
243
232
  * If the requested key is a collection, it will return an object with all the collection members.
@@ -247,34 +236,26 @@ function isSafeEvictionKey(testKey) {
247
236
  * @returns {Mixed}
248
237
  */
249
238
  function tryGetCachedValue(key, mapping = {}) {
250
- let val = cache.getValue(key);
251
-
239
+ let val = OnyxCache_1.default.getValue(key);
252
240
  if (isCollectionKey(key)) {
253
- const allCacheKeys = cache.getAllKeys();
254
-
241
+ const allCacheKeys = OnyxCache_1.default.getAllKeys();
255
242
  // It is possible we haven't loaded all keys yet so we do not know if the
256
243
  // collection actually exists.
257
244
  if (allCacheKeys.length === 0) {
258
245
  return;
259
246
  }
260
- const matchingKeys = _.filter(allCacheKeys, (k) => k.startsWith(key));
261
- const values = _.reduce(
262
- matchingKeys,
263
- (finalObject, matchedKey) => {
264
- const cachedValue = cache.getValue(matchedKey);
265
- if (cachedValue) {
266
- // This is permissible because we're in the process of constructing the final object in a reduce function.
267
- // eslint-disable-next-line no-param-reassign
268
- finalObject[matchedKey] = cachedValue;
269
- }
270
- return finalObject;
271
- },
272
- {},
273
- );
274
-
247
+ const matchingKeys = underscore_1.default.filter(allCacheKeys, (k) => k.startsWith(key));
248
+ const values = underscore_1.default.reduce(matchingKeys, (finalObject, matchedKey) => {
249
+ const cachedValue = OnyxCache_1.default.getValue(matchedKey);
250
+ if (cachedValue) {
251
+ // This is permissible because we're in the process of constructing the final object in a reduce function.
252
+ // eslint-disable-next-line no-param-reassign
253
+ finalObject[matchedKey] = cachedValue;
254
+ }
255
+ return finalObject;
256
+ }, {});
275
257
  val = values;
276
258
  }
277
-
278
259
  if (mapping.selector) {
279
260
  const state = mapping.withOnyxInstance ? mapping.withOnyxInstance.state : undefined;
280
261
  if (isCollectionKey(key)) {
@@ -282,10 +263,8 @@ function tryGetCachedValue(key, mapping = {}) {
282
263
  }
283
264
  return getSubsetOfData(val, mapping.selector, state);
284
265
  }
285
-
286
266
  return val;
287
267
  }
288
-
289
268
  /**
290
269
  * Remove a key from the recently accessed key list.
291
270
  *
@@ -293,9 +272,8 @@ function tryGetCachedValue(key, mapping = {}) {
293
272
  * @param {String} key
294
273
  */
295
274
  function removeLastAccessedKey(key) {
296
- recentlyAccessedKeys = _.without(recentlyAccessedKeys, key);
275
+ recentlyAccessedKeys = underscore_1.default.without(recentlyAccessedKeys, key);
297
276
  }
298
-
299
277
  /**
300
278
  * Add a key to the list of recently accessed keys. The least
301
279
  * recently accessed key should be at the head and the most
@@ -309,11 +287,9 @@ function addLastAccessedKey(key) {
309
287
  if (isCollectionKey(key) || !isSafeEvictionKey(key)) {
310
288
  return;
311
289
  }
312
-
313
290
  removeLastAccessedKey(key);
314
291
  recentlyAccessedKeys.push(key);
315
292
  }
316
-
317
293
  /**
318
294
  * Removes a key previously added to this list
319
295
  * which will enable it to be deleted again.
@@ -323,14 +299,12 @@ function addLastAccessedKey(key) {
323
299
  * @param {Number} connectionID
324
300
  */
325
301
  function removeFromEvictionBlockList(key, connectionID) {
326
- evictionBlocklist[key] = _.without(evictionBlocklist[key] || [], connectionID);
327
-
302
+ evictionBlocklist[key] = underscore_1.default.without(evictionBlocklist[key] || [], connectionID);
328
303
  // Remove the key if there are no more subscribers
329
304
  if (evictionBlocklist[key].length === 0) {
330
305
  delete evictionBlocklist[key];
331
306
  }
332
307
  }
333
-
334
308
  /**
335
309
  * Keys added to this list can never be deleted.
336
310
  *
@@ -340,14 +314,11 @@ function removeFromEvictionBlockList(key, connectionID) {
340
314
  */
341
315
  function addToEvictionBlockList(key, connectionID) {
342
316
  removeFromEvictionBlockList(key, connectionID);
343
-
344
317
  if (!evictionBlocklist[key]) {
345
318
  evictionBlocklist[key] = [];
346
319
  }
347
-
348
320
  evictionBlocklist[key].push(connectionID);
349
321
  }
350
-
351
322
  /**
352
323
  * Take all the keys that are safe to evict and add them to
353
324
  * the recently accessed list when initializing the app. This
@@ -359,8 +330,8 @@ function addToEvictionBlockList(key, connectionID) {
359
330
  */
360
331
  function addAllSafeEvictionKeysToRecentlyAccessedList() {
361
332
  return getAllKeys().then((keys) => {
362
- _.each(evictionAllowList, (safeEvictionKey) => {
363
- _.each(keys, (key) => {
333
+ underscore_1.default.each(evictionAllowList, (safeEvictionKey) => {
334
+ underscore_1.default.each(keys, (key) => {
364
335
  if (!isKeyMatch(safeEvictionKey, key)) {
365
336
  return;
366
337
  }
@@ -369,31 +340,23 @@ function addAllSafeEvictionKeysToRecentlyAccessedList() {
369
340
  });
370
341
  });
371
342
  }
372
-
373
343
  /**
374
344
  * @private
375
345
  * @param {String} collectionKey
376
346
  * @returns {Object}
377
347
  */
378
348
  function getCachedCollection(collectionKey) {
379
- const collectionMemberKeys = _.filter(cache.getAllKeys(), (storedKey) => isCollectionMemberKey(collectionKey, storedKey));
380
-
381
- return _.reduce(
382
- collectionMemberKeys,
383
- (prev, curr) => {
384
- const cachedValue = cache.getValue(curr);
385
- if (!cachedValue) {
386
- return prev;
387
- }
388
-
389
- // eslint-disable-next-line no-param-reassign
390
- prev[curr] = cachedValue;
349
+ const collectionMemberKeys = underscore_1.default.filter(OnyxCache_1.default.getAllKeys(), (storedKey) => isCollectionMemberKey(collectionKey, storedKey));
350
+ return underscore_1.default.reduce(collectionMemberKeys, (prev, curr) => {
351
+ const cachedValue = OnyxCache_1.default.getValue(curr);
352
+ if (!cachedValue) {
391
353
  return prev;
392
- },
393
- {},
394
- );
354
+ }
355
+ // eslint-disable-next-line no-param-reassign
356
+ prev[curr] = cachedValue;
357
+ return prev;
358
+ }, {});
395
359
  }
396
-
397
360
  /**
398
361
  * When a collection of keys change, search for any callbacks matching the collection key and trigger those callbacks
399
362
  *
@@ -407,38 +370,32 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
407
370
  // We are iterating over all subscribers similar to keyChanged(). However, we are looking for subscribers who are subscribing to either a collection key or
408
371
  // 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
409
372
  // 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().
410
- const stateMappingKeys = _.keys(callbackToStateMapping);
373
+ const stateMappingKeys = underscore_1.default.keys(callbackToStateMapping);
411
374
  for (let i = 0; i < stateMappingKeys.length; i++) {
412
375
  const subscriber = callbackToStateMapping[stateMappingKeys[i]];
413
376
  if (!subscriber) {
414
377
  continue;
415
378
  }
416
-
417
379
  // Skip iteration if we do not have a collection key or a collection member key on this subscriber
418
380
  if (!Str.startsWith(subscriber.key, collectionKey)) {
419
381
  continue;
420
382
  }
421
-
422
383
  /**
423
384
  * e.g. Onyx.connect({key: ONYXKEYS.COLLECTION.REPORT, callback: ...});
424
385
  */
425
386
  const isSubscribedToCollectionKey = subscriber.key === collectionKey;
426
-
427
387
  /**
428
388
  * e.g. Onyx.connect({key: `${ONYXKEYS.COLLECTION.REPORT}{reportID}`, callback: ...});
429
389
  */
430
390
  const isSubscribedToCollectionMemberKey = isCollectionMemberKey(collectionKey, subscriber.key);
431
-
432
391
  // We prepare the "cached collection" which is the entire collection + the new partial data that
433
392
  // was merged in via mergeCollection().
434
393
  const cachedCollection = getCachedCollection(collectionKey);
435
-
436
394
  // Regular Onyx.connect() subscriber found.
437
- if (_.isFunction(subscriber.callback)) {
395
+ if (underscore_1.default.isFunction(subscriber.callback)) {
438
396
  if (!notifyRegularSubscibers) {
439
397
  continue;
440
398
  }
441
-
442
399
  // If they are subscribed to the collection key and using waitForCollectionCallback then we'll
443
400
  // send the whole cached collection.
444
401
  if (isSubscribedToCollectionKey) {
@@ -446,33 +403,28 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
446
403
  subscriber.callback(cachedCollection);
447
404
  continue;
448
405
  }
449
-
450
406
  // If they are not using waitForCollectionCallback then we notify the subscriber with
451
407
  // the new merged data but only for any keys in the partial collection.
452
- const dataKeys = _.keys(partialCollection);
408
+ const dataKeys = underscore_1.default.keys(partialCollection);
453
409
  for (let j = 0; j < dataKeys.length; j++) {
454
410
  const dataKey = dataKeys[j];
455
411
  subscriber.callback(cachedCollection[dataKey], dataKey);
456
412
  }
457
413
  continue;
458
414
  }
459
-
460
415
  // And if the subscriber is specifically only tracking a particular collection member key then we will
461
416
  // notify them with the cached data for that key only.
462
417
  if (isSubscribedToCollectionMemberKey) {
463
418
  subscriber.callback(cachedCollection[subscriber.key], subscriber.key);
464
419
  continue;
465
420
  }
466
-
467
421
  continue;
468
422
  }
469
-
470
423
  // React component subscriber found.
471
424
  if (subscriber.withOnyxInstance) {
472
425
  if (!notifyWithOnyxSubscibers) {
473
426
  continue;
474
427
  }
475
-
476
428
  // We are subscribed to a collection key so we must update the data in state with the new
477
429
  // collection member key values from the partial update.
478
430
  if (isSubscribedToCollectionKey) {
@@ -482,8 +434,7 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
482
434
  subscriber.withOnyxInstance.setStateProxy((prevState) => {
483
435
  const previousData = prevState[subscriber.statePropertyName];
484
436
  const newData = reduceCollectionWithSelector(cachedCollection, subscriber.selector, subscriber.withOnyxInstance.state);
485
-
486
- if (!deepEqual(previousData, newData)) {
437
+ if (!(0, fast_equals_1.deepEqual)(previousData, newData)) {
487
438
  return {
488
439
  [subscriber.statePropertyName]: newData,
489
440
  };
@@ -492,15 +443,13 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
492
443
  });
493
444
  continue;
494
445
  }
495
-
496
446
  subscriber.withOnyxInstance.setStateProxy((prevState) => {
497
- const finalCollection = _.clone(prevState[subscriber.statePropertyName] || {});
498
- const dataKeys = _.keys(partialCollection);
447
+ const finalCollection = underscore_1.default.clone(prevState[subscriber.statePropertyName] || {});
448
+ const dataKeys = underscore_1.default.keys(partialCollection);
499
449
  for (let j = 0; j < dataKeys.length; j++) {
500
450
  const dataKey = dataKeys[j];
501
451
  finalCollection[dataKey] = cachedCollection[dataKey];
502
452
  }
503
-
504
453
  PerformanceUtils.logSetStateCall(subscriber, prevState[subscriber.statePropertyName], finalCollection, 'keysChanged', collectionKey);
505
454
  return {
506
455
  [subscriber.statePropertyName]: finalCollection,
@@ -508,16 +457,14 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
508
457
  });
509
458
  continue;
510
459
  }
511
-
512
460
  // If a React component is only interested in a single key then we can set the cached value directly to the state name.
513
461
  if (isSubscribedToCollectionMemberKey) {
514
462
  // However, we only want to update this subscriber if the partial data contains a change.
515
463
  // Otherwise, we would update them with a value they already have and trigger an unnecessary re-render.
516
464
  const dataFromCollection = partialCollection[subscriber.key];
517
- if (_.isUndefined(dataFromCollection)) {
465
+ if (underscore_1.default.isUndefined(dataFromCollection)) {
518
466
  continue;
519
467
  }
520
-
521
468
  // If the subscriber has a selector, then the component's state must only be updated with the data
522
469
  // returned by the selector and the state should only change when the subset of data changes from what
523
470
  // it was previously.
@@ -525,30 +472,26 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
525
472
  subscriber.withOnyxInstance.setStateProxy((prevState) => {
526
473
  const prevData = prevState[subscriber.statePropertyName];
527
474
  const newData = getSubsetOfData(cachedCollection[subscriber.key], subscriber.selector, subscriber.withOnyxInstance.state);
528
- if (!deepEqual(prevData, newData)) {
475
+ if (!(0, fast_equals_1.deepEqual)(prevData, newData)) {
529
476
  PerformanceUtils.logSetStateCall(subscriber, prevData, newData, 'keysChanged', collectionKey);
530
477
  return {
531
478
  [subscriber.statePropertyName]: newData,
532
479
  };
533
480
  }
534
-
535
481
  return null;
536
482
  });
537
483
  continue;
538
484
  }
539
-
540
485
  subscriber.withOnyxInstance.setStateProxy((prevState) => {
541
486
  const data = cachedCollection[subscriber.key];
542
487
  const previousData = prevState[subscriber.statePropertyName];
543
-
544
488
  // Avoids triggering unnecessary re-renders when feeding empty objects
545
- if (utils.areObjectsEmpty(data, previousData)) {
489
+ if (utils_1.default.areObjectsEmpty(data, previousData)) {
546
490
  return null;
547
491
  }
548
492
  if (data === previousData) {
549
493
  return null;
550
494
  }
551
-
552
495
  PerformanceUtils.logSetStateCall(subscriber, previousData, data, 'keysChanged', collectionKey);
553
496
  return {
554
497
  [subscriber.statePropertyName]: data,
@@ -558,7 +501,6 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
558
501
  }
559
502
  }
560
503
  }
561
-
562
504
  /**
563
505
  * When a key change happens, search for any callbacks matching the key or collection key and trigger those callbacks
564
506
  *
@@ -574,24 +516,23 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
574
516
  */
575
517
  function keyChanged(key, data, canUpdateSubscriber, notifyRegularSubscibers = true, notifyWithOnyxSubscibers = true) {
576
518
  // Add or remove this key from the recentlyAccessedKeys lists
577
- if (!_.isNull(data)) {
519
+ if (!underscore_1.default.isNull(data)) {
578
520
  addLastAccessedKey(key);
579
- } else {
521
+ }
522
+ else {
580
523
  removeLastAccessedKey(key);
581
524
  }
582
-
583
525
  // 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
584
526
  // 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
585
527
  // 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.
586
- const stateMappingKeys = _.keys(callbackToStateMapping);
528
+ const stateMappingKeys = underscore_1.default.keys(callbackToStateMapping);
587
529
  for (let i = 0; i < stateMappingKeys.length; i++) {
588
530
  const subscriber = callbackToStateMapping[stateMappingKeys[i]];
589
- if (!subscriber || !isKeyMatch(subscriber.key, key) || (_.isFunction(canUpdateSubscriber) && !canUpdateSubscriber(subscriber))) {
531
+ if (!subscriber || !isKeyMatch(subscriber.key, key) || (underscore_1.default.isFunction(canUpdateSubscriber) && !canUpdateSubscriber(subscriber))) {
590
532
  continue;
591
533
  }
592
-
593
534
  // Subscriber is a regular call to connect() and provided a callback
594
- if (_.isFunction(subscriber.callback)) {
535
+ if (underscore_1.default.isFunction(subscriber.callback)) {
595
536
  if (!notifyRegularSubscibers) {
596
537
  continue;
597
538
  }
@@ -601,17 +542,14 @@ function keyChanged(key, data, canUpdateSubscriber, notifyRegularSubscibers = tr
601
542
  subscriber.callback(cachedCollection);
602
543
  continue;
603
544
  }
604
-
605
545
  subscriber.callback(data, key);
606
546
  continue;
607
547
  }
608
-
609
548
  // Subscriber connected via withOnyx() HOC
610
549
  if (subscriber.withOnyxInstance) {
611
550
  if (!notifyWithOnyxSubscibers) {
612
551
  continue;
613
552
  }
614
-
615
553
  // Check if we are subscribing to a collection key and overwrite the collection member key value in state
616
554
  if (isCollectionKey(subscriber.key)) {
617
555
  // If the subscriber has a selector, then the consumer of this data must only be given the data
@@ -622,11 +560,8 @@ function keyChanged(key, data, canUpdateSubscriber, notifyRegularSubscibers = tr
622
560
  const newData = {
623
561
  [key]: getSubsetOfData(data, subscriber.selector, subscriber.withOnyxInstance.state),
624
562
  };
625
- const prevDataWithNewData = {
626
- ...prevData,
627
- ...newData,
628
- };
629
- if (!deepEqual(prevData, prevDataWithNewData)) {
563
+ const prevDataWithNewData = Object.assign(Object.assign({}, prevData), newData);
564
+ if (!(0, fast_equals_1.deepEqual)(prevData, prevDataWithNewData)) {
630
565
  PerformanceUtils.logSetStateCall(subscriber, prevData, newData, 'keyChanged', key);
631
566
  return {
632
567
  [subscriber.statePropertyName]: prevDataWithNewData,
@@ -636,13 +571,9 @@ function keyChanged(key, data, canUpdateSubscriber, notifyRegularSubscibers = tr
636
571
  });
637
572
  continue;
638
573
  }
639
-
640
574
  subscriber.withOnyxInstance.setStateProxy((prevState) => {
641
575
  const collection = prevState[subscriber.statePropertyName] || {};
642
- const newCollection = {
643
- ...collection,
644
- [key]: data,
645
- };
576
+ const newCollection = Object.assign(Object.assign({}, collection), { [key]: data });
646
577
  PerformanceUtils.logSetStateCall(subscriber, collection, newCollection, 'keyChanged', key);
647
578
  return {
648
579
  [subscriber.statePropertyName]: newCollection,
@@ -650,14 +581,13 @@ function keyChanged(key, data, canUpdateSubscriber, notifyRegularSubscibers = tr
650
581
  });
651
582
  continue;
652
583
  }
653
-
654
584
  // If the subscriber has a selector, then the component's state must only be updated with the data
655
585
  // returned by the selector and only if the selected data has changed.
656
586
  if (subscriber.selector) {
657
587
  subscriber.withOnyxInstance.setStateProxy((prevState) => {
658
588
  const previousValue = getSubsetOfData(prevState[subscriber.statePropertyName], subscriber.selector, subscriber.withOnyxInstance.state);
659
589
  const newValue = getSubsetOfData(data, subscriber.selector, subscriber.withOnyxInstance.state);
660
- if (!deepEqual(previousValue, newValue)) {
590
+ if (!(0, fast_equals_1.deepEqual)(previousValue, newValue)) {
661
591
  return {
662
592
  [subscriber.statePropertyName]: newValue,
663
593
  };
@@ -666,19 +596,16 @@ function keyChanged(key, data, canUpdateSubscriber, notifyRegularSubscibers = tr
666
596
  });
667
597
  continue;
668
598
  }
669
-
670
599
  // If we did not match on a collection key then we just set the new data to the state property
671
600
  subscriber.withOnyxInstance.setStateProxy((prevState) => {
672
601
  const previousData = prevState[subscriber.statePropertyName];
673
-
674
602
  // Avoids triggering unnecessary re-renders when feeding empty objects
675
- if (utils.areObjectsEmpty(data, previousData)) {
603
+ if (utils_1.default.areObjectsEmpty(data, previousData)) {
676
604
  return null;
677
605
  }
678
606
  if (previousData === data) {
679
607
  return null;
680
608
  }
681
-
682
609
  PerformanceUtils.logSetStateCall(subscriber, previousData, data, 'keyChanged', key);
683
610
  return {
684
611
  [subscriber.statePropertyName]: data,
@@ -686,11 +613,9 @@ function keyChanged(key, data, canUpdateSubscriber, notifyRegularSubscibers = tr
686
613
  });
687
614
  continue;
688
615
  }
689
-
690
616
  console.error('Warning: Found a matching subscriber to a key that changed, but no callback or withOnyxInstance could be found.');
691
617
  }
692
618
  }
693
-
694
619
  /**
695
620
  * Sends the data obtained from the keys to the connection. It either:
696
621
  * - sets state on the withOnyxInstances
@@ -712,36 +637,33 @@ function sendDataToConnection(mapping, val, matchedKey, isBatched) {
712
637
  if (!callbackToStateMapping[mapping.connectionID]) {
713
638
  return;
714
639
  }
715
-
716
640
  if (mapping.withOnyxInstance) {
717
641
  let newData = val;
718
-
719
642
  // If the mapping has a selector, then the component's state must only be updated with the data
720
643
  // returned by the selector.
721
644
  if (mapping.selector) {
722
645
  if (isCollectionKey(mapping.key)) {
723
646
  newData = reduceCollectionWithSelector(val, mapping.selector, mapping.withOnyxInstance.state);
724
- } else {
647
+ }
648
+ else {
725
649
  newData = getSubsetOfData(val, mapping.selector, mapping.withOnyxInstance.state);
726
650
  }
727
651
  }
728
-
729
652
  PerformanceUtils.logSetStateCall(mapping, null, newData, 'sendDataToConnection');
730
653
  if (isBatched) {
731
654
  batchUpdates(() => {
732
655
  mapping.withOnyxInstance.setWithOnyxState(mapping.statePropertyName, newData);
733
656
  });
734
- } else {
657
+ }
658
+ else {
735
659
  mapping.withOnyxInstance.setWithOnyxState(mapping.statePropertyName, newData);
736
660
  }
737
661
  return;
738
662
  }
739
-
740
- if (_.isFunction(mapping.callback)) {
663
+ if (underscore_1.default.isFunction(mapping.callback)) {
741
664
  mapping.callback(val, matchedKey);
742
665
  }
743
666
  }
744
-
745
667
  /**
746
668
  * We check to see if this key is flagged as safe for eviction and add it to the recentlyAccessedKeys list so that when we
747
669
  * run out of storage the least recently accessed key can be removed.
@@ -753,20 +675,16 @@ function addKeyToRecentlyAccessedIfNeeded(mapping) {
753
675
  if (!isSafeEvictionKey(mapping.key)) {
754
676
  return;
755
677
  }
756
-
757
678
  // Try to free some cache whenever we connect to a safe eviction key
758
- cache.removeLeastRecentlyUsedKeys();
759
-
679
+ OnyxCache_1.default.removeLeastRecentlyUsedKeys();
760
680
  if (mapping.withOnyxInstance && !isCollectionKey(mapping.key)) {
761
681
  // All React components subscribing to a key flagged as a safe eviction key must implement the canEvict property.
762
- if (_.isUndefined(mapping.canEvict)) {
682
+ if (underscore_1.default.isUndefined(mapping.canEvict)) {
763
683
  throw new Error(`Cannot subscribe to safe eviction key '${mapping.key}' without providing a canEvict value.`);
764
684
  }
765
-
766
685
  addLastAccessedKey(mapping.key);
767
686
  }
768
687
  }
769
-
770
688
  /**
771
689
  * Gets the data for a given an array of matching keys, combines them into an object, and sends the result back to the subscriber.
772
690
  *
@@ -775,21 +693,14 @@ function addKeyToRecentlyAccessedIfNeeded(mapping) {
775
693
  * @param {Object} mapping
776
694
  */
777
695
  function getCollectionDataAndSendAsObject(matchingKeys, mapping) {
778
- Promise.all(_.map(matchingKeys, (key) => get(key)))
779
- .then((values) =>
780
- _.reduce(
781
- values,
782
- (finalObject, value, i) => {
783
- // eslint-disable-next-line no-param-reassign
784
- finalObject[matchingKeys[i]] = value;
785
- return finalObject;
786
- },
787
- {},
788
- ),
789
- )
696
+ Promise.all(underscore_1.default.map(matchingKeys, (key) => get(key)))
697
+ .then((values) => underscore_1.default.reduce(values, (finalObject, value, i) => {
698
+ // eslint-disable-next-line no-param-reassign
699
+ finalObject[matchingKeys[i]] = value;
700
+ return finalObject;
701
+ }, {}))
790
702
  .then((val) => sendDataToConnection(mapping, val, undefined, true));
791
703
  }
792
-
793
704
  /**
794
705
  * Subscribes a react component's state directly to a store key
795
706
  *
@@ -822,87 +733,75 @@ function connect(mapping) {
822
733
  const connectionID = lastConnectionID++;
823
734
  callbackToStateMapping[connectionID] = mapping;
824
735
  callbackToStateMapping[connectionID].connectionID = connectionID;
825
-
826
736
  if (mapping.initWithStoredValues === false) {
827
737
  return connectionID;
828
738
  }
829
-
830
739
  // Commit connection only after init passes
831
740
  deferredInitTask.promise
832
741
  .then(() => addKeyToRecentlyAccessedIfNeeded(mapping))
833
742
  .then(() => {
834
- // Performance improvement
835
- // If the mapping is connected to an onyx key that is not a collection
836
- // we can skip the call to getAllKeys() and return an array with a single item
837
- if (Boolean(mapping.key) && typeof mapping.key === 'string' && !mapping.key.endsWith('_') && cache.storageKeys.has(mapping.key)) {
838
- return [mapping.key];
839
- }
840
- return getAllKeys();
841
- })
743
+ // Performance improvement
744
+ // If the mapping is connected to an onyx key that is not a collection
745
+ // we can skip the call to getAllKeys() and return an array with a single item
746
+ if (Boolean(mapping.key) && typeof mapping.key === 'string' && !mapping.key.endsWith('_') && OnyxCache_1.default.storageKeys.has(mapping.key)) {
747
+ return [mapping.key];
748
+ }
749
+ return getAllKeys();
750
+ })
842
751
  .then((keys) => {
843
- // We search all the keys in storage to see if any are a "match" for the subscriber we are connecting so that we
844
- // can send data back to the subscriber. Note that multiple keys can match as a subscriber could either be
845
- // subscribed to a "collection key" or a single key.
846
- const matchingKeys = _.filter(keys, (key) => isKeyMatch(mapping.key, key));
847
-
848
- // If the key being connected to does not exist we initialize the value with null. For subscribers that connected
849
- // directly via connect() they will simply get a null value sent to them without any information about which key matched
850
- // since there are none matched. In withOnyx() we wait for all connected keys to return a value before rendering the child
851
- // component. This null value will be filtered out so that the connected component can utilize defaultProps.
852
- if (matchingKeys.length === 0) {
853
- if (mapping.key && !isCollectionKey(mapping.key)) {
854
- cache.set(mapping.key, null);
855
- }
856
-
857
- // Here we cannot use batching because the null value is expected to be set immediately for default props
858
- // or they will be undefined.
859
- sendDataToConnection(mapping, null, undefined, false);
860
- return;
752
+ // We search all the keys in storage to see if any are a "match" for the subscriber we are connecting so that we
753
+ // can send data back to the subscriber. Note that multiple keys can match as a subscriber could either be
754
+ // subscribed to a "collection key" or a single key.
755
+ const matchingKeys = underscore_1.default.filter(keys, (key) => isKeyMatch(mapping.key, key));
756
+ // If the key being connected to does not exist we initialize the value with null. For subscribers that connected
757
+ // directly via connect() they will simply get a null value sent to them without any information about which key matched
758
+ // since there are none matched. In withOnyx() we wait for all connected keys to return a value before rendering the child
759
+ // component. This null value will be filtered out so that the connected component can utilize defaultProps.
760
+ if (matchingKeys.length === 0) {
761
+ if (mapping.key && !isCollectionKey(mapping.key)) {
762
+ OnyxCache_1.default.set(mapping.key, null);
861
763
  }
862
-
863
- // When using a callback subscriber we will either trigger the provided callback for each key we find or combine all values
864
- // into an object and just make a single call. The latter behavior is enabled by providing a waitForCollectionCallback key
865
- // combined with a subscription to a collection key.
866
- if (_.isFunction(mapping.callback)) {
867
- if (isCollectionKey(mapping.key)) {
868
- if (mapping.waitForCollectionCallback) {
869
- getCollectionDataAndSendAsObject(matchingKeys, mapping);
870
- return;
871
- }
872
-
873
- // We did not opt into using waitForCollectionCallback mode so the callback is called for every matching key.
874
- for (let i = 0; i < matchingKeys.length; i++) {
875
- get(matchingKeys[i]).then((val) => sendDataToConnection(mapping, val, matchingKeys[i], true));
876
- }
764
+ // Here we cannot use batching because the null value is expected to be set immediately for default props
765
+ // or they will be undefined.
766
+ sendDataToConnection(mapping, null, undefined, false);
767
+ return;
768
+ }
769
+ // When using a callback subscriber we will either trigger the provided callback for each key we find or combine all values
770
+ // into an object and just make a single call. The latter behavior is enabled by providing a waitForCollectionCallback key
771
+ // combined with a subscription to a collection key.
772
+ if (underscore_1.default.isFunction(mapping.callback)) {
773
+ if (isCollectionKey(mapping.key)) {
774
+ if (mapping.waitForCollectionCallback) {
775
+ getCollectionDataAndSendAsObject(matchingKeys, mapping);
877
776
  return;
878
777
  }
879
-
880
- // If we are not subscribed to a collection key then there's only a single key to send an update for.
881
- get(mapping.key).then((val) => sendDataToConnection(mapping, val, mapping.key, true));
778
+ // We did not opt into using waitForCollectionCallback mode so the callback is called for every matching key.
779
+ for (let i = 0; i < matchingKeys.length; i++) {
780
+ get(matchingKeys[i]).then((val) => sendDataToConnection(mapping, val, matchingKeys[i], true));
781
+ }
882
782
  return;
883
783
  }
884
-
885
- // If we have a withOnyxInstance that means a React component has subscribed via the withOnyx() HOC and we need to
886
- // group collection key member data into an object.
887
- if (mapping.withOnyxInstance) {
888
- if (isCollectionKey(mapping.key)) {
889
- getCollectionDataAndSendAsObject(matchingKeys, mapping);
890
- return;
891
- }
892
-
893
- // If the subscriber is not using a collection key then we just send a single value back to the subscriber
894
- get(mapping.key).then((val) => sendDataToConnection(mapping, val, mapping.key, true));
784
+ // If we are not subscribed to a collection key then there's only a single key to send an update for.
785
+ get(mapping.key).then((val) => sendDataToConnection(mapping, val, mapping.key, true));
786
+ return;
787
+ }
788
+ // If we have a withOnyxInstance that means a React component has subscribed via the withOnyx() HOC and we need to
789
+ // group collection key member data into an object.
790
+ if (mapping.withOnyxInstance) {
791
+ if (isCollectionKey(mapping.key)) {
792
+ getCollectionDataAndSendAsObject(matchingKeys, mapping);
895
793
  return;
896
794
  }
897
-
898
- console.error('Warning: Onyx.connect() was found without a callback or withOnyxInstance');
899
- });
900
-
795
+ // If the subscriber is not using a collection key then we just send a single value back to the subscriber
796
+ get(mapping.key).then((val) => sendDataToConnection(mapping, val, mapping.key, true));
797
+ return;
798
+ }
799
+ console.error('Warning: Onyx.connect() was found without a callback or withOnyxInstance');
800
+ });
901
801
  // The connectionID is returned back to the caller so that it can be used to clean up the connection when it's no longer needed
902
802
  // by calling Onyx.disconnect(connectionID).
903
803
  return connectionID;
904
804
  }
905
-
906
805
  /**
907
806
  * Remove the listener for a react component
908
807
  * @example
@@ -915,16 +814,13 @@ function disconnect(connectionID, keyToRemoveFromEvictionBlocklist) {
915
814
  if (!callbackToStateMapping[connectionID]) {
916
815
  return;
917
816
  }
918
-
919
817
  // Remove this key from the eviction block list as we are no longer
920
818
  // subscribing to it and it should be safe to delete again
921
819
  if (keyToRemoveFromEvictionBlocklist) {
922
820
  removeFromEvictionBlockList(keyToRemoveFromEvictionBlocklist, connectionID);
923
821
  }
924
-
925
822
  delete callbackToStateMapping[connectionID];
926
823
  }
927
-
928
824
  /**
929
825
  * Schedules an update that will be appended to the macro task queue (so it doesn't update the subscribers immediately).
930
826
  *
@@ -941,7 +837,6 @@ function scheduleSubscriberUpdate(key, value, canUpdateSubscriber) {
941
837
  batchUpdates(() => keyChanged(key, value, canUpdateSubscriber, false, true));
942
838
  return Promise.all([maybeFlushBatchUpdates(), promise]);
943
839
  }
944
-
945
840
  /**
946
841
  * This method is similar to notifySubscribersOnNextTick but it is built for working specifically with collections
947
842
  * so that keysChanged() is triggered for the collection and not keyChanged(). If this was not done, then the
@@ -956,7 +851,6 @@ function scheduleNotifyCollectionSubscribers(key, value) {
956
851
  batchUpdates(() => keysChanged(key, value, false, true));
957
852
  return Promise.all([maybeFlushBatchUpdates(), promise]);
958
853
  }
959
-
960
854
  /**
961
855
  * Remove a key from Onyx and update the subscribers
962
856
  *
@@ -965,25 +859,23 @@ function scheduleNotifyCollectionSubscribers(key, value) {
965
859
  * @return {Promise}
966
860
  */
967
861
  function remove(key) {
968
- cache.drop(key);
862
+ OnyxCache_1.default.drop(key);
969
863
  scheduleSubscriberUpdate(key, null);
970
- return Storage.removeItem(key);
864
+ return storage_1.default.removeItem(key);
971
865
  }
972
-
973
866
  /**
974
867
  * @private
975
868
  * @returns {Promise<void>}
976
869
  */
977
870
  function reportStorageQuota() {
978
- return Storage.getDatabaseSize()
979
- .then(({bytesUsed, bytesRemaining}) => {
980
- Logger.logInfo(`Storage Quota Check -- bytesUsed: ${bytesUsed} bytesRemaining: ${bytesRemaining}`);
981
- })
871
+ return storage_1.default.getDatabaseSize()
872
+ .then(({ bytesUsed, bytesRemaining }) => {
873
+ Logger.logInfo(`Storage Quota Check -- bytesUsed: ${bytesUsed} bytesRemaining: ${bytesRemaining}`);
874
+ })
982
875
  .catch((dbSizeError) => {
983
- Logger.logAlert(`Unable to get database size. Error: ${dbSizeError}`);
984
- });
876
+ Logger.logAlert(`Unable to get database size. Error: ${dbSizeError}`);
877
+ });
985
878
  }
986
-
987
879
  /**
988
880
  * If we fail to set or merge we must handle this by
989
881
  * evicting some data from Onyx and then retrying to do
@@ -997,14 +889,12 @@ function reportStorageQuota() {
997
889
  */
998
890
  function evictStorageAndRetry(error, onyxMethod, ...args) {
999
891
  Logger.logInfo(`Failed to save to storage. Error: ${error}. onyxMethod: ${onyxMethod.name}`);
1000
-
1001
892
  if (error && Str.startsWith(error.message, "Failed to execute 'put' on 'IDBObjectStore'")) {
1002
893
  Logger.logAlert('Attempted to set invalid data set in Onyx. Please ensure all data is serializable.');
1003
894
  throw error;
1004
895
  }
1005
-
1006
896
  // Find the first key that we can remove that has no subscribers in our blocklist
1007
- const keyForRemoval = _.find(recentlyAccessedKeys, (key) => !evictionBlocklist[key]);
897
+ const keyForRemoval = underscore_1.default.find(recentlyAccessedKeys, (key) => !evictionBlocklist[key]);
1008
898
  if (!keyForRemoval) {
1009
899
  // If we have no acceptable keys to remove then we are possibly trying to save mission critical data. If this is the case,
1010
900
  // 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
@@ -1012,13 +902,11 @@ function evictStorageAndRetry(error, onyxMethod, ...args) {
1012
902
  Logger.logAlert('Out of storage. But found no acceptable keys to remove.');
1013
903
  return reportStorageQuota();
1014
904
  }
1015
-
1016
905
  // Remove the least recently viewed key that is not currently being accessed and retry.
1017
906
  Logger.logInfo(`Out of storage. Evicting least recently accessed key (${keyForRemoval}) and retrying.`);
1018
907
  reportStorageQuota();
1019
908
  return remove(keyForRemoval).then(() => onyxMethod(...args));
1020
909
  }
1021
-
1022
910
  /**
1023
911
  * Notifys subscribers and writes current value to cache
1024
912
  *
@@ -1031,19 +919,17 @@ function evictStorageAndRetry(error, onyxMethod, ...args) {
1031
919
  */
1032
920
  function broadcastUpdate(key, value, method, hasChanged, wasRemoved = false) {
1033
921
  // Logging properties only since values could be sensitive things we don't want to log
1034
- Logger.logInfo(`${method}() called for key: ${key}${_.isObject(value) ? ` properties: ${_.keys(value).join(',')}` : ''}`);
1035
-
922
+ Logger.logInfo(`${method}() called for key: ${key}${underscore_1.default.isObject(value) ? ` properties: ${underscore_1.default.keys(value).join(',')}` : ''}`);
1036
923
  // Update subscribers if the cached value has changed, or when the subscriber specifically requires
1037
924
  // all updates regardless of value changes (indicated by initWithStoredValues set to false).
1038
925
  if (hasChanged && !wasRemoved) {
1039
- cache.set(key, value);
1040
- } else {
1041
- cache.addToAccessedKeys(key);
926
+ OnyxCache_1.default.set(key, value);
927
+ }
928
+ else {
929
+ OnyxCache_1.default.addToAccessedKeys(key);
1042
930
  }
1043
-
1044
931
  return scheduleSubscriberUpdate(key, value, (subscriber) => hasChanged || subscriber.initWithStoredValues === false);
1045
932
  }
1046
-
1047
933
  /**
1048
934
  * @param {String} key
1049
935
  * @returns {Boolean}
@@ -1051,7 +937,6 @@ function broadcastUpdate(key, value, method, hasChanged, wasRemoved = false) {
1051
937
  function hasPendingMergeForKey(key) {
1052
938
  return Boolean(mergeQueue[key]);
1053
939
  }
1054
-
1055
940
  /**
1056
941
  * Removes a key from storage if the value is null.
1057
942
  * Otherwise removes all nested null values in objects and returns the object
@@ -1060,17 +945,15 @@ function hasPendingMergeForKey(key) {
1060
945
  * @returns {Mixed} The value without null values and a boolean "wasRemoved", which indicates if the key got removed completely
1061
946
  */
1062
947
  function removeNullValues(key, value) {
1063
- if (_.isNull(value)) {
948
+ if (underscore_1.default.isNull(value)) {
1064
949
  remove(key);
1065
- return {value, wasRemoved: true};
950
+ return { value, wasRemoved: true };
1066
951
  }
1067
-
1068
952
  // We can remove all null values in an object by merging it with itself
1069
953
  // utils.fastMerge recursively goes through the object and removes all null values
1070
954
  // Passing two identical objects as source and target to fastMerge will not change it, but only remove the null values
1071
- return {value: utils.removeNestedNullValues(value), wasRemoved: false};
955
+ return { value: utils_1.default.removeNestedNullValues(value), wasRemoved: false };
1072
956
  }
1073
-
1074
957
  /**
1075
958
  * Write a value to our store with the given key
1076
959
  *
@@ -1081,30 +964,24 @@ function removeNullValues(key, value) {
1081
964
  */
1082
965
  function set(key, value) {
1083
966
  // If the value is null, we remove the key from storage
1084
- const {value: valueAfterRemoving, wasRemoved} = removeNullValues(key, value);
1085
-
967
+ const { value: valueAfterRemoving, wasRemoved } = removeNullValues(key, value);
1086
968
  if (hasPendingMergeForKey(key)) {
1087
969
  delete mergeQueue[key];
1088
970
  }
1089
-
1090
- const hasChanged = cache.hasValueChanged(key, valueAfterRemoving);
1091
-
971
+ const hasChanged = OnyxCache_1.default.hasValueChanged(key, valueAfterRemoving);
1092
972
  // This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
1093
973
  const updatePromise = broadcastUpdate(key, valueAfterRemoving, 'set', hasChanged, wasRemoved);
1094
-
1095
974
  // If the value has not changed or the key got removed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
1096
975
  if (!hasChanged || wasRemoved) {
1097
976
  return updatePromise;
1098
977
  }
1099
-
1100
- return Storage.setItem(key, valueAfterRemoving)
978
+ return storage_1.default.setItem(key, valueAfterRemoving)
1101
979
  .catch((error) => evictStorageAndRetry(error, set, key, valueAfterRemoving))
1102
980
  .then(() => {
1103
- sendActionToDevTools(METHOD.SET, key, valueAfterRemoving);
1104
- return updatePromise;
1105
- });
981
+ sendActionToDevTools(METHOD.SET, key, valueAfterRemoving);
982
+ return updatePromise;
983
+ });
1106
984
  }
1107
-
1108
985
  /**
1109
986
  * Storage expects array like: [["@MyApp_user", value_1], ["@MyApp_key", value_2]]
1110
987
  * This method transforms an object like {'@MyApp_user': myUserValue, '@MyApp_key': myKeyValue}
@@ -1115,18 +992,14 @@ function set(key, value) {
1115
992
  */
1116
993
  function prepareKeyValuePairsForStorage(data) {
1117
994
  const keyValuePairs = [];
1118
-
1119
- _.forEach(data, (value, key) => {
1120
- const {value: valueAfterRemoving, wasRemoved} = removeNullValues(key, value);
1121
-
1122
- if (wasRemoved) return;
1123
-
995
+ underscore_1.default.forEach(data, (value, key) => {
996
+ const { value: valueAfterRemoving, wasRemoved } = removeNullValues(key, value);
997
+ if (wasRemoved)
998
+ return;
1124
999
  keyValuePairs.push([key, valueAfterRemoving]);
1125
1000
  });
1126
-
1127
1001
  return keyValuePairs;
1128
1002
  }
1129
-
1130
1003
  /**
1131
1004
  * Sets multiple keys and values
1132
1005
  *
@@ -1137,21 +1010,18 @@ function prepareKeyValuePairsForStorage(data) {
1137
1010
  */
1138
1011
  function multiSet(data) {
1139
1012
  const keyValuePairs = prepareKeyValuePairsForStorage(data);
1140
-
1141
- const updatePromises = _.map(keyValuePairs, ([key, value]) => {
1013
+ const updatePromises = underscore_1.default.map(keyValuePairs, ([key, value]) => {
1142
1014
  // Update cache and optimistically inform subscribers on the next tick
1143
- cache.set(key, value);
1015
+ OnyxCache_1.default.set(key, value);
1144
1016
  return scheduleSubscriberUpdate(key, value);
1145
1017
  });
1146
-
1147
- return Storage.multiSet(keyValuePairs)
1018
+ return storage_1.default.multiSet(keyValuePairs)
1148
1019
  .catch((error) => evictStorageAndRetry(error, multiSet, data))
1149
1020
  .then(() => {
1150
- sendActionToDevTools(METHOD.MULTI_SET, undefined, data);
1151
- return Promise.all(updatePromises);
1152
- });
1021
+ sendActionToDevTools(METHOD.MULTI_SET, undefined, data);
1022
+ return Promise.all(updatePromises);
1023
+ });
1153
1024
  }
1154
-
1155
1025
  /**
1156
1026
  * Merges an array of changes with an existing value
1157
1027
  *
@@ -1162,22 +1032,18 @@ function multiSet(data) {
1162
1032
  * @returns {*}
1163
1033
  */
1164
1034
  function applyMerge(existingValue, changes, shouldRemoveNullObjectValues) {
1165
- const lastChange = _.last(changes);
1166
-
1167
- if (_.isArray(lastChange)) {
1035
+ const lastChange = underscore_1.default.last(changes);
1036
+ if (underscore_1.default.isArray(lastChange)) {
1168
1037
  return lastChange;
1169
1038
  }
1170
-
1171
- if (_.some(changes, _.isObject)) {
1039
+ if (underscore_1.default.some(changes, underscore_1.default.isObject)) {
1172
1040
  // Object values are then merged one after the other
1173
- return _.reduce(changes, (modifiedData, change) => utils.fastMerge(modifiedData, change, shouldRemoveNullObjectValues), existingValue || {});
1041
+ return underscore_1.default.reduce(changes, (modifiedData, change) => utils_1.default.fastMerge(modifiedData, change, shouldRemoveNullObjectValues), existingValue || {});
1174
1042
  }
1175
-
1176
1043
  // If we have anything else we can't merge it so we'll
1177
1044
  // simply return the last value that was queued
1178
1045
  return lastChange;
1179
1046
  }
1180
-
1181
1047
  /**
1182
1048
  * Merge a new value into an existing value at a key.
1183
1049
  *
@@ -1201,10 +1067,9 @@ function applyMerge(existingValue, changes, shouldRemoveNullObjectValues) {
1201
1067
  function merge(key, changes) {
1202
1068
  // Top-level undefined values are ignored
1203
1069
  // Therefore we need to prevent adding them to the merge queue
1204
- if (_.isUndefined(changes)) {
1070
+ if (underscore_1.default.isUndefined(changes)) {
1205
1071
  return mergeQueue[key] ? mergeQueuePromise[key] : Promise.resolve();
1206
1072
  }
1207
-
1208
1073
  // Merge attempts are batched together. The delta should be applied after a single call to get() to prevent a race condition.
1209
1074
  // Using the initial value from storage in subsequent merge attempts will lead to an incorrect final merged value.
1210
1075
  if (mergeQueue[key]) {
@@ -1212,32 +1077,26 @@ function merge(key, changes) {
1212
1077
  return mergeQueuePromise[key];
1213
1078
  }
1214
1079
  mergeQueue[key] = [changes];
1215
-
1216
1080
  mergeQueuePromise[key] = get(key).then((existingValue) => {
1217
1081
  // Calls to Onyx.set after a merge will terminate the current merge process and clear the merge queue
1218
- if (mergeQueue[key] == null) return;
1219
-
1082
+ if (mergeQueue[key] == null)
1083
+ return;
1220
1084
  try {
1221
1085
  // We first only merge the changes, so we can provide these to the native implementation (SQLite uses only delta changes in "JSON_PATCH" to merge)
1222
1086
  // We don't want to remove null values from the "batchedChanges", because SQLite uses them to remove keys from storage natively.
1223
1087
  let batchedChanges = applyMerge(undefined, mergeQueue[key], false);
1224
-
1225
1088
  // The presence of a `null` in the merge queue instructs us to drop the existing value.
1226
1089
  // In this case, we can't simply merge the batched changes with the existing value, because then the null in the merge queue would have no effect
1227
- const shouldOverwriteExistingValue = _.includes(mergeQueue[key], null);
1228
-
1090
+ const shouldOverwriteExistingValue = underscore_1.default.includes(mergeQueue[key], null);
1229
1091
  // Clean up the write queue, so we don't apply these changes again
1230
1092
  delete mergeQueue[key];
1231
1093
  delete mergeQueuePromise[key];
1232
-
1233
1094
  // If the batched changes equal null, we want to remove the key from storage, to reduce storage size
1234
- const {wasRemoved} = removeNullValues(key, batchedChanges);
1235
-
1095
+ const { wasRemoved } = removeNullValues(key, batchedChanges);
1236
1096
  // After that we merge the batched changes with the existing value
1237
1097
  // We can remove null values from the "modifiedData", because "null" implicates that the user wants to remove a value from storage.
1238
1098
  // The "modifiedData" will be directly "set" in storage instead of being merged
1239
1099
  const modifiedData = shouldOverwriteExistingValue ? batchedChanges : applyMerge(existingValue, [batchedChanges], true);
1240
-
1241
1100
  // On native platforms we use SQLite which utilises JSON_PATCH to merge changes.
1242
1101
  // JSON_PATCH generally removes null values from the stored object.
1243
1102
  // When there is no existing value though, SQLite will just insert the changes as a new value and thus the null values won't be removed.
@@ -1245,45 +1104,38 @@ function merge(key, changes) {
1245
1104
  if (!existingValue) {
1246
1105
  batchedChanges = applyMerge(undefined, [batchedChanges], true);
1247
1106
  }
1248
-
1249
- const hasChanged = cache.hasValueChanged(key, modifiedData);
1250
-
1107
+ const hasChanged = OnyxCache_1.default.hasValueChanged(key, modifiedData);
1251
1108
  // This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
1252
1109
  const updatePromise = broadcastUpdate(key, modifiedData, 'merge', hasChanged, wasRemoved);
1253
-
1254
1110
  // If the value has not changed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
1255
1111
  if (!hasChanged || wasRemoved) {
1256
1112
  return updatePromise;
1257
1113
  }
1258
-
1259
- return Storage.mergeItem(key, batchedChanges, modifiedData).then(() => {
1114
+ return storage_1.default.mergeItem(key, batchedChanges, modifiedData).then(() => {
1260
1115
  sendActionToDevTools(METHOD.MERGE, key, changes, modifiedData);
1261
1116
  return updatePromise;
1262
1117
  });
1263
- } catch (error) {
1118
+ }
1119
+ catch (error) {
1264
1120
  Logger.logAlert(`An error occurred while applying merge for key: ${key}, Error: ${error}`);
1265
1121
  return Promise.resolve();
1266
1122
  }
1267
1123
  });
1268
-
1269
1124
  return mergeQueuePromise[key];
1270
1125
  }
1271
-
1272
1126
  /**
1273
1127
  * Merge user provided default key value pairs.
1274
1128
  * @private
1275
1129
  * @returns {Promise}
1276
1130
  */
1277
1131
  function initializeWithDefaultKeyStates() {
1278
- return Storage.multiGet(_.keys(defaultKeyStates)).then((pairs) => {
1279
- const asObject = _.object(pairs);
1280
-
1281
- const merged = utils.fastMerge(asObject, defaultKeyStates);
1282
- cache.merge(merged);
1283
- _.each(merged, (val, key) => keyChanged(key, val));
1132
+ return storage_1.default.multiGet(underscore_1.default.keys(defaultKeyStates)).then((pairs) => {
1133
+ const asObject = underscore_1.default.object(pairs);
1134
+ const merged = utils_1.default.fastMerge(asObject, defaultKeyStates);
1135
+ OnyxCache_1.default.merge(merged);
1136
+ underscore_1.default.each(merged, (val, key) => keyChanged(key, val));
1284
1137
  });
1285
1138
  }
1286
-
1287
1139
  /**
1288
1140
  * Clear out all the data in the store
1289
1141
  *
@@ -1311,68 +1163,60 @@ function clear(keysToPreserve = []) {
1311
1163
  const keysToBeClearedFromStorage = [];
1312
1164
  const keyValuesToResetAsCollection = {};
1313
1165
  const keyValuesToResetIndividually = {};
1314
-
1315
1166
  // The only keys that should not be cleared are:
1316
1167
  // 1. Anything specifically passed in keysToPreserve (because some keys like language preferences, offline
1317
1168
  // status, or activeClients need to remain in Onyx even when signed out)
1318
1169
  // 2. Any keys with a default state (because they need to remain in Onyx as their default, and setting them
1319
1170
  // to null would cause unknown behavior)
1320
- _.each(keys, (key) => {
1321
- const isKeyToPreserve = _.contains(keysToPreserve, key);
1322
- const isDefaultKey = _.has(defaultKeyStates, key);
1323
-
1171
+ underscore_1.default.each(keys, (key) => {
1172
+ const isKeyToPreserve = underscore_1.default.contains(keysToPreserve, key);
1173
+ const isDefaultKey = underscore_1.default.has(defaultKeyStates, key);
1324
1174
  // If the key is being removed or reset to default:
1325
1175
  // 1. Update it in the cache
1326
1176
  // 2. Figure out whether it is a collection key or not,
1327
1177
  // since collection key subscribers need to be updated differently
1328
1178
  if (!isKeyToPreserve) {
1329
- const oldValue = cache.getValue(key);
1330
- const newValue = _.get(defaultKeyStates, key, null);
1179
+ const oldValue = OnyxCache_1.default.getValue(key);
1180
+ const newValue = underscore_1.default.get(defaultKeyStates, key, null);
1331
1181
  if (newValue !== oldValue) {
1332
- cache.set(key, newValue);
1182
+ OnyxCache_1.default.set(key, newValue);
1333
1183
  const collectionKey = key.substring(0, key.indexOf('_') + 1);
1334
1184
  if (collectionKey) {
1335
1185
  if (!keyValuesToResetAsCollection[collectionKey]) {
1336
1186
  keyValuesToResetAsCollection[collectionKey] = {};
1337
1187
  }
1338
1188
  keyValuesToResetAsCollection[collectionKey][key] = newValue;
1339
- } else {
1189
+ }
1190
+ else {
1340
1191
  keyValuesToResetIndividually[key] = newValue;
1341
1192
  }
1342
1193
  }
1343
1194
  }
1344
-
1345
1195
  if (isKeyToPreserve || isDefaultKey) {
1346
1196
  return;
1347
1197
  }
1348
-
1349
1198
  // If it isn't preserved and doesn't have a default, we'll remove it
1350
1199
  keysToBeClearedFromStorage.push(key);
1351
1200
  });
1352
-
1353
1201
  const updatePromises = [];
1354
-
1355
1202
  // Notify the subscribers for each key/value group so they can receive the new values
1356
- _.each(keyValuesToResetIndividually, (value, key) => {
1203
+ underscore_1.default.each(keyValuesToResetIndividually, (value, key) => {
1357
1204
  updatePromises.push(scheduleSubscriberUpdate(key, value));
1358
1205
  });
1359
- _.each(keyValuesToResetAsCollection, (value, key) => {
1206
+ underscore_1.default.each(keyValuesToResetAsCollection, (value, key) => {
1360
1207
  updatePromises.push(scheduleNotifyCollectionSubscribers(key, value));
1361
1208
  });
1362
-
1363
- const defaultKeyValuePairs = _.pairs(_.omit(defaultKeyStates, keysToPreserve));
1364
-
1209
+ const defaultKeyValuePairs = underscore_1.default.pairs(underscore_1.default.omit(defaultKeyStates, keysToPreserve));
1365
1210
  // Remove only the items that we want cleared from storage, and reset others to default
1366
- _.each(keysToBeClearedFromStorage, (key) => cache.drop(key));
1367
- return Storage.removeItems(keysToBeClearedFromStorage)
1368
- .then(() => Storage.multiSet(defaultKeyValuePairs))
1211
+ underscore_1.default.each(keysToBeClearedFromStorage, (key) => OnyxCache_1.default.drop(key));
1212
+ return storage_1.default.removeItems(keysToBeClearedFromStorage)
1213
+ .then(() => storage_1.default.multiSet(defaultKeyValuePairs))
1369
1214
  .then(() => {
1370
- DevTools.clearState(keysToPreserve);
1371
- return Promise.all(updatePromises);
1372
- });
1215
+ DevTools_1.default.clearState(keysToPreserve);
1216
+ return Promise.all(updatePromises);
1217
+ });
1373
1218
  });
1374
1219
  }
1375
-
1376
1220
  /**
1377
1221
  * Merges a collection based on their keys
1378
1222
  *
@@ -1388,78 +1232,66 @@ function clear(keysToPreserve = []) {
1388
1232
  * @returns {Promise}
1389
1233
  */
1390
1234
  function mergeCollection(collectionKey, collection) {
1391
- if (!_.isObject(collection) || _.isArray(collection) || _.isEmpty(collection)) {
1235
+ if (!underscore_1.default.isObject(collection) || underscore_1.default.isArray(collection) || underscore_1.default.isEmpty(collection)) {
1392
1236
  Logger.logInfo('mergeCollection() called with invalid or empty value. Skipping this update.');
1393
1237
  return Promise.resolve();
1394
1238
  }
1395
-
1396
1239
  // Confirm all the collection keys belong to the same parent
1397
1240
  let hasCollectionKeyCheckFailed = false;
1398
- _.each(collection, (_data, dataKey) => {
1241
+ underscore_1.default.each(collection, (_data, dataKey) => {
1399
1242
  if (isKeyMatch(collectionKey, dataKey)) {
1400
1243
  return;
1401
1244
  }
1402
-
1403
1245
  if (process.env.NODE_ENV === 'development') {
1404
1246
  throw new Error(`Provided collection doesn't have all its data belonging to the same parent. CollectionKey: ${collectionKey}, DataKey: ${dataKey}`);
1405
1247
  }
1406
-
1407
1248
  hasCollectionKeyCheckFailed = true;
1408
1249
  Logger.logAlert(`Provided collection doesn't have all its data belonging to the same parent. CollectionKey: ${collectionKey}, DataKey: ${dataKey}`);
1409
1250
  });
1410
-
1411
1251
  // Gracefully handle bad mergeCollection updates so it doesn't block the merge queue
1412
1252
  if (hasCollectionKeyCheckFailed) {
1413
1253
  return Promise.resolve();
1414
1254
  }
1415
-
1416
1255
  return getAllKeys().then((persistedKeys) => {
1417
1256
  // Split to keys that exist in storage and keys that don't
1418
- const [existingKeys, newKeys] = _.chain(collection)
1257
+ const [existingKeys, newKeys] = underscore_1.default.chain(collection)
1419
1258
  .pick((value, key) => {
1420
- if (_.isNull(value)) {
1421
- remove(key);
1422
- return false;
1423
- }
1424
- return true;
1425
- })
1259
+ if (underscore_1.default.isNull(value)) {
1260
+ remove(key);
1261
+ return false;
1262
+ }
1263
+ return true;
1264
+ })
1426
1265
  .keys()
1427
1266
  .partition((key) => persistedKeys.includes(key))
1428
1267
  .value();
1429
-
1430
- const existingKeyCollection = _.pick(collection, existingKeys);
1431
- const newCollection = _.pick(collection, newKeys);
1268
+ const existingKeyCollection = underscore_1.default.pick(collection, existingKeys);
1269
+ const newCollection = underscore_1.default.pick(collection, newKeys);
1432
1270
  const keyValuePairsForExistingCollection = prepareKeyValuePairsForStorage(existingKeyCollection);
1433
1271
  const keyValuePairsForNewCollection = prepareKeyValuePairsForStorage(newCollection);
1434
-
1435
1272
  const promises = [];
1436
-
1437
1273
  // New keys will be added via multiSet while existing keys will be updated using multiMerge
1438
1274
  // This is because setting a key that doesn't exist yet with multiMerge will throw errors
1439
1275
  if (keyValuePairsForExistingCollection.length > 0) {
1440
- promises.push(Storage.multiMerge(keyValuePairsForExistingCollection));
1276
+ promises.push(storage_1.default.multiMerge(keyValuePairsForExistingCollection));
1441
1277
  }
1442
-
1443
1278
  if (keyValuePairsForNewCollection.length > 0) {
1444
- promises.push(Storage.multiSet(keyValuePairsForNewCollection));
1279
+ promises.push(storage_1.default.multiSet(keyValuePairsForNewCollection));
1445
1280
  }
1446
-
1447
1281
  // Prefill cache if necessary by calling get() on any existing keys and then merge original data to cache
1448
1282
  // and update all subscribers
1449
- const promiseUpdate = Promise.all(_.map(existingKeys, get)).then(() => {
1450
- cache.merge(collection);
1283
+ const promiseUpdate = Promise.all(underscore_1.default.map(existingKeys, get)).then(() => {
1284
+ OnyxCache_1.default.merge(collection);
1451
1285
  return scheduleNotifyCollectionSubscribers(collectionKey, collection);
1452
1286
  });
1453
-
1454
1287
  return Promise.all(promises)
1455
1288
  .catch((error) => evictStorageAndRetry(error, mergeCollection, collection))
1456
1289
  .then(() => {
1457
- sendActionToDevTools(METHOD.MERGE_COLLECTION, undefined, collection);
1458
- return promiseUpdate;
1459
- });
1290
+ sendActionToDevTools(METHOD.MERGE_COLLECTION, undefined, collection);
1291
+ return promiseUpdate;
1292
+ });
1460
1293
  });
1461
1294
  }
1462
-
1463
1295
  /**
1464
1296
  * Insert API responses and lifecycle data into Onyx
1465
1297
  *
@@ -1468,24 +1300,23 @@ function mergeCollection(collectionKey, collection) {
1468
1300
  */
1469
1301
  function update(data) {
1470
1302
  // First, validate the Onyx object is in the format we expect
1471
- _.each(data, ({onyxMethod, key, value}) => {
1472
- if (!_.contains([METHOD.CLEAR, METHOD.SET, METHOD.MERGE, METHOD.MERGE_COLLECTION, METHOD.MULTI_SET], onyxMethod)) {
1303
+ underscore_1.default.each(data, ({ onyxMethod, key, value }) => {
1304
+ if (!underscore_1.default.contains([METHOD.CLEAR, METHOD.SET, METHOD.MERGE, METHOD.MERGE_COLLECTION, METHOD.MULTI_SET], onyxMethod)) {
1473
1305
  throw new Error(`Invalid onyxMethod ${onyxMethod} in Onyx update.`);
1474
1306
  }
1475
1307
  if (onyxMethod === METHOD.MULTI_SET) {
1476
1308
  // For multiset, we just expect the value to be an object
1477
- if (!_.isObject(value) || _.isArray(value) || _.isFunction(value)) {
1309
+ if (!underscore_1.default.isObject(value) || underscore_1.default.isArray(value) || underscore_1.default.isFunction(value)) {
1478
1310
  throw new Error('Invalid value provided in Onyx multiSet. Onyx multiSet value must be of type object.');
1479
1311
  }
1480
- } else if (onyxMethod !== METHOD.CLEAR && !_.isString(key)) {
1312
+ }
1313
+ else if (onyxMethod !== METHOD.CLEAR && !underscore_1.default.isString(key)) {
1481
1314
  throw new Error(`Invalid ${typeof key} key provided in Onyx update. Onyx key must be of type string.`);
1482
1315
  }
1483
1316
  });
1484
-
1485
1317
  const promises = [];
1486
1318
  let clearPromise = Promise.resolve();
1487
-
1488
- _.each(data, ({onyxMethod, key, value}) => {
1319
+ underscore_1.default.each(data, ({ onyxMethod, key, value }) => {
1489
1320
  switch (onyxMethod) {
1490
1321
  case METHOD.SET:
1491
1322
  promises.push(() => set(key, value));
@@ -1506,21 +1337,17 @@ function update(data) {
1506
1337
  break;
1507
1338
  }
1508
1339
  });
1509
-
1510
- return clearPromise.then(() => Promise.all(_.map(promises, (p) => p())));
1340
+ return clearPromise.then(() => Promise.all(underscore_1.default.map(promises, (p) => p())));
1511
1341
  }
1512
-
1513
1342
  /**
1514
1343
  * When set these keys will not be persisted to storage
1515
1344
  * @param {string[]} keyList
1516
1345
  */
1517
1346
  function setMemoryOnlyKeys(keyList) {
1518
- Storage.setMemoryOnlyKeys(keyList);
1519
-
1347
+ storage_1.default.setMemoryOnlyKeys(keyList);
1520
1348
  // When in memory only mode for certain keys we do not want to ever drop items from the cache as the user will have no way to recover them again via storage.
1521
- cache.setRecentKeysLimit(Infinity);
1349
+ OnyxCache_1.default.setRecentKeysLimit(Infinity);
1522
1350
  }
1523
-
1524
1351
  /**
1525
1352
  * Initialize the store with actions and listening for storage events
1526
1353
  *
@@ -1546,60 +1373,39 @@ function setMemoryOnlyKeys(keyList) {
1546
1373
  * },
1547
1374
  * });
1548
1375
  */
1549
- function init({
1550
- keys = {},
1551
- initialKeyStates = {},
1552
- safeEvictionKeys = [],
1553
- maxCachedKeysCount = 1000,
1554
- captureMetrics = false,
1555
- shouldSyncMultipleInstances = Boolean(global.localStorage),
1556
- debugSetState = false,
1557
- } = {}) {
1376
+ function init({ keys = {}, initialKeyStates = {}, safeEvictionKeys = [], maxCachedKeysCount = 1000, captureMetrics = false, shouldSyncMultipleInstances = Boolean(global.localStorage), debugSetState = false, } = {}) {
1558
1377
  if (captureMetrics) {
1559
1378
  // The code here is only bundled and applied when the captureMetrics is set
1560
1379
  // eslint-disable-next-line no-use-before-define
1561
1380
  applyDecorators();
1562
1381
  }
1563
-
1564
1382
  if (debugSetState) {
1565
1383
  PerformanceUtils.setShouldDebugSetState(true);
1566
1384
  }
1567
-
1568
1385
  if (maxCachedKeysCount > 0) {
1569
- cache.setRecentKeysLimit(maxCachedKeysCount);
1386
+ OnyxCache_1.default.setRecentKeysLimit(maxCachedKeysCount);
1570
1387
  }
1571
-
1572
1388
  // We need the value of the collection keys later for checking if a
1573
1389
  // key is a collection. We store it in a map for faster lookup.
1574
- const collectionValues = _.values(keys.COLLECTION);
1575
- onyxCollectionKeyMap = _.reduce(
1576
- collectionValues,
1577
- (acc, val) => {
1578
- acc.set(val, true);
1579
- return acc;
1580
- },
1581
- new Map(),
1582
- );
1583
-
1390
+ const collectionValues = underscore_1.default.values(keys.COLLECTION);
1391
+ onyxCollectionKeyMap = underscore_1.default.reduce(collectionValues, (acc, val) => {
1392
+ acc.set(val, true);
1393
+ return acc;
1394
+ }, new Map());
1584
1395
  // Set our default key states to use when initializing and clearing Onyx data
1585
1396
  defaultKeyStates = initialKeyStates;
1586
-
1587
- DevTools.initState(initialKeyStates);
1588
-
1397
+ DevTools_1.default.initState(initialKeyStates);
1589
1398
  // Let Onyx know about which keys are safe to evict
1590
1399
  evictionAllowList = safeEvictionKeys;
1591
-
1592
1400
  // Initialize all of our keys with data provided then give green light to any pending connections
1593
1401
  Promise.all([addAllSafeEvictionKeysToRecentlyAccessedList(), initializeWithDefaultKeyStates()]).then(deferredInitTask.resolve);
1594
-
1595
- if (shouldSyncMultipleInstances && _.isFunction(Storage.keepInstancesSync)) {
1596
- Storage.keepInstancesSync((key, value) => {
1597
- cache.set(key, value);
1402
+ if (shouldSyncMultipleInstances && underscore_1.default.isFunction(storage_1.default.keepInstancesSync)) {
1403
+ storage_1.default.keepInstancesSync((key, value) => {
1404
+ OnyxCache_1.default.set(key, value);
1598
1405
  keyChanged(key, value);
1599
1406
  });
1600
1407
  }
1601
1408
  }
1602
-
1603
1409
  const Onyx = {
1604
1410
  connect,
1605
1411
  disconnect,
@@ -1620,7 +1426,6 @@ const Onyx = {
1620
1426
  tryGetCachedValue,
1621
1427
  hasPendingMergeForKey,
1622
1428
  };
1623
-
1624
1429
  /**
1625
1430
  * Apply calls statistic decorators to benchmark Onyx
1626
1431
  *
@@ -1629,7 +1434,6 @@ const Onyx = {
1629
1434
  function applyDecorators() {
1630
1435
  // We're requiring the script dynamically here so that it's only evaluated when decorators are used
1631
1436
  const decorate = require('./metrics');
1632
-
1633
1437
  // Re-assign with decorated functions
1634
1438
  /* eslint-disable no-func-assign */
1635
1439
  get = decorate.decorateWithMetrics(get, 'Onyx:get');
@@ -1642,7 +1446,6 @@ function applyDecorators() {
1642
1446
  initializeWithDefaultKeyStates = decorate.decorateWithMetrics(initializeWithDefaultKeyStates, 'Onyx:defaults');
1643
1447
  update = decorate.decorateWithMetrics(update, 'Onyx:update');
1644
1448
  /* eslint-enable */
1645
-
1646
1449
  // Re-expose decorated methods
1647
1450
  /* eslint-disable rulesdir/prefer-actions-set-data */
1648
1451
  Onyx.set = set;
@@ -1652,11 +1455,9 @@ function applyDecorators() {
1652
1455
  Onyx.mergeCollection = mergeCollection;
1653
1456
  Onyx.update = update;
1654
1457
  /* eslint-enable */
1655
-
1656
1458
  // Expose stats methods on Onyx
1657
1459
  Onyx.getMetrics = decorate.getMetrics;
1658
1460
  Onyx.resetMetrics = decorate.resetMetrics;
1659
1461
  Onyx.printMetrics = decorate.printMetrics;
1660
1462
  }
1661
-
1662
- export default Onyx;
1463
+ exports.default = Onyx;