react-native-onyx 2.0.111 → 2.0.112

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/Onyx.d.ts CHANGED
@@ -2,7 +2,7 @@ import * as Logger from './Logger';
2
2
  import type { CollectionKeyBase, ConnectOptions, InitOptions, Mapping, OnyxKey, OnyxMergeCollectionInput, OnyxMergeInput, OnyxMultiSetInput, OnyxSetInput, OnyxUpdate } from './types';
3
3
  import type { Connection } from './OnyxConnectionManager';
4
4
  /** Initialize the store with actions and listening for storage events */
5
- declare function init({ keys, initialKeyStates, evictableKeys, maxCachedKeysCount, shouldSyncMultipleInstances, debugSetState, enablePerformanceMetrics, skippableCollectionMemberIDs, }: InitOptions): void;
5
+ declare function init({ keys, initialKeyStates, evictableKeys, maxCachedKeysCount, shouldSyncMultipleInstances, debugSetState, enablePerformanceMetrics, skippableCollectionMemberIDs, fullyMergedSnapshotKeys, }: InitOptions): void;
6
6
  /**
7
7
  * Connects to an Onyx key given the options passed and listens to its changes.
8
8
  *
package/dist/Onyx.js CHANGED
@@ -40,7 +40,7 @@ const OnyxConnectionManager_1 = __importDefault(require("./OnyxConnectionManager
40
40
  const GlobalSettings = __importStar(require("./GlobalSettings"));
41
41
  const metrics_1 = __importDefault(require("./metrics"));
42
42
  /** Initialize the store with actions and listening for storage events */
43
- function init({ keys = {}, initialKeyStates = {}, evictableKeys = [], maxCachedKeysCount = 1000, shouldSyncMultipleInstances = !!global.localStorage, debugSetState = false, enablePerformanceMetrics = false, skippableCollectionMemberIDs = [], }) {
43
+ function init({ keys = {}, initialKeyStates = {}, evictableKeys = [], maxCachedKeysCount = 1000, shouldSyncMultipleInstances = !!global.localStorage, debugSetState = false, enablePerformanceMetrics = false, skippableCollectionMemberIDs = [], fullyMergedSnapshotKeys = [], }) {
44
44
  var _a;
45
45
  if (enablePerformanceMetrics) {
46
46
  GlobalSettings.setPerformanceMetricsEnabled(true);
@@ -61,7 +61,7 @@ function init({ keys = {}, initialKeyStates = {}, evictableKeys = [], maxCachedK
61
61
  if (maxCachedKeysCount > 0) {
62
62
  OnyxCache_1.default.setRecentKeysLimit(maxCachedKeysCount);
63
63
  }
64
- OnyxUtils_1.default.initStoreValues(keys, initialKeyStates, evictableKeys);
64
+ OnyxUtils_1.default.initStoreValues(keys, initialKeyStates, evictableKeys, fullyMergedSnapshotKeys);
65
65
  // Initialize all of our keys with data provided then give green light to any pending connections
66
66
  Promise.all([OnyxCache_1.default.addEvictableKeysToRecentlyAccessedList(OnyxUtils_1.default.isCollectionKey, OnyxUtils_1.default.getAllKeys), OnyxUtils_1.default.initializeWithDefaultKeyStates()]).then(OnyxUtils_1.default.getDeferredInitTask().resolve);
67
67
  }
@@ -43,8 +43,9 @@ declare function setSkippableCollectionMemberIDs(ids: Set<string>): void;
43
43
  * @param keys - `ONYXKEYS` constants object from Onyx.init()
44
44
  * @param initialKeyStates - initial data to set when `init()` and `clear()` are called
45
45
  * @param evictableKeys - This is an array of keys (individual or collection patterns) that when provided to Onyx are flagged as "safe" for removal.
46
+ * @param fullyMergedSnapshotKeys - Array of snapshot collection keys where full merge is supported and data structure can be changed after merge.
46
47
  */
47
- declare function initStoreValues(keys: DeepRecord<string, OnyxKey>, initialKeyStates: Partial<KeyValueMapping>, evictableKeys: OnyxKey[]): void;
48
+ declare function initStoreValues(keys: DeepRecord<string, OnyxKey>, initialKeyStates: Partial<KeyValueMapping>, evictableKeys: OnyxKey[], fullyMergedSnapshotKeysParam?: string[]): void;
48
49
  /**
49
50
  * Sends an action to DevTools extension
50
51
  *
@@ -105,7 +106,7 @@ declare function getCollectionKeys(): Set<OnyxKey>;
105
106
  * is associated with a collection of keys.
106
107
  */
107
108
  declare function isCollectionKey(key: OnyxKey): key is CollectionKeyBase;
108
- declare function isCollectionMemberKey<TCollectionKey extends CollectionKeyBase>(collectionKey: TCollectionKey, key: string, collectionKeyLength: number): key is `${TCollectionKey}${string}`;
109
+ declare function isCollectionMemberKey<TCollectionKey extends CollectionKeyBase>(collectionKey: TCollectionKey, key: string): key is `${TCollectionKey}${string}`;
109
110
  /**
110
111
  * Splits a collection member key into the collection key part and the ID part.
111
112
  * @param key - The collection member key to split.
package/dist/OnyxUtils.js CHANGED
@@ -29,6 +29,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
29
29
  /* eslint-disable no-continue */
30
30
  const fast_equals_1 = require("fast-equals");
31
31
  const clone_1 = __importDefault(require("lodash/clone"));
32
+ const pick_1 = __importDefault(require("lodash/pick"));
32
33
  const DevTools_1 = __importDefault(require("./DevTools"));
33
34
  const Logger = __importStar(require("./Logger"));
34
35
  const OnyxCache_1 = __importStar(require("./OnyxCache"));
@@ -65,6 +66,7 @@ let batchUpdatesQueue = [];
65
66
  // Used for comparison with a new update to avoid invoking the Onyx.connect callback with the same data.
66
67
  const lastConnectionCallbackData = new Map();
67
68
  let snapshotKey = null;
69
+ let fullyMergedSnapshotKeys;
68
70
  // Keeps track of the last subscriptionID that was used so we can keep incrementing it
69
71
  let lastSubscriptionID = 0;
70
72
  // Connections can be made before `Onyx.init`. They would wait for this task before resolving
@@ -116,8 +118,9 @@ function setSkippableCollectionMemberIDs(ids) {
116
118
  * @param keys - `ONYXKEYS` constants object from Onyx.init()
117
119
  * @param initialKeyStates - initial data to set when `init()` and `clear()` are called
118
120
  * @param evictableKeys - This is an array of keys (individual or collection patterns) that when provided to Onyx are flagged as "safe" for removal.
121
+ * @param fullyMergedSnapshotKeys - Array of snapshot collection keys where full merge is supported and data structure can be changed after merge.
119
122
  */
120
- function initStoreValues(keys, initialKeyStates, evictableKeys) {
123
+ function initStoreValues(keys, initialKeyStates, evictableKeys, fullyMergedSnapshotKeysParam) {
121
124
  var _a;
122
125
  // We need the value of the collection keys later for checking if a
123
126
  // key is a collection. We store it in a map for faster lookup.
@@ -133,6 +136,7 @@ function initStoreValues(keys, initialKeyStates, evictableKeys) {
133
136
  OnyxCache_1.default.setEvictionAllowList(evictableKeys);
134
137
  if (typeof keys.COLLECTION === 'object' && typeof keys.COLLECTION.SNAPSHOT === 'string') {
135
138
  snapshotKey = keys.COLLECTION.SNAPSHOT;
139
+ fullyMergedSnapshotKeys = new Set(fullyMergedSnapshotKeysParam !== null && fullyMergedSnapshotKeysParam !== void 0 ? fullyMergedSnapshotKeysParam : []);
136
140
  }
137
141
  }
138
142
  function sendActionToDevTools(method, key, value, mergedValue = undefined) {
@@ -361,8 +365,8 @@ function getCollectionKeys() {
361
365
  function isCollectionKey(key) {
362
366
  return onyxCollectionKeySet.has(key);
363
367
  }
364
- function isCollectionMemberKey(collectionKey, key, collectionKeyLength) {
365
- return key.startsWith(collectionKey) && key.length > collectionKeyLength;
368
+ function isCollectionMemberKey(collectionKey, key) {
369
+ return key.startsWith(collectionKey) && key.length > collectionKey.length;
366
370
  }
367
371
  /**
368
372
  * Splits a collection member key into the collection key part and the ID part.
@@ -372,7 +376,7 @@ function isCollectionMemberKey(collectionKey, key, collectionKeyLength) {
372
376
  * or throws an Error if the key is not a collection one.
373
377
  */
374
378
  function splitCollectionMemberKey(key, collectionKey) {
375
- if (collectionKey && !isCollectionMemberKey(collectionKey, key, collectionKey.length)) {
379
+ if (collectionKey && !isCollectionMemberKey(collectionKey, key)) {
376
380
  throw new Error(`Invalid '${collectionKey}' collection key provided, it isn't compatible with '${key}' key.`);
377
381
  }
378
382
  if (!collectionKey) {
@@ -450,13 +454,12 @@ function tryGetCachedValue(key, mapping) {
450
454
  function getCachedCollection(collectionKey, collectionMemberKeys) {
451
455
  const allKeys = collectionMemberKeys || OnyxCache_1.default.getAllKeys();
452
456
  const collection = {};
453
- const collectionKeyLength = collectionKey.length;
454
457
  // forEach exists on both Set and Array
455
458
  allKeys.forEach((key) => {
456
459
  // If we don't have collectionMemberKeys array then we have to check whether a key is a collection member key.
457
460
  // Because in that case the keys will be coming from `cache.getAllKeys()` and we need to filter out the keys that
458
461
  // are not part of the collection.
459
- if (!collectionMemberKeys && !isCollectionMemberKey(collectionKey, key, collectionKeyLength)) {
462
+ if (!collectionMemberKeys && !isCollectionMemberKey(collectionKey, key)) {
460
463
  return;
461
464
  }
462
465
  const cachedValue = OnyxCache_1.default.get(key);
@@ -479,7 +482,6 @@ function keysChanged(collectionKey, partialCollection, partialPreviousCollection
479
482
  // 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
480
483
  // 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().
481
484
  const stateMappingKeys = Object.keys(callbackToStateMapping);
482
- const collectionKeyLength = collectionKey.length;
483
485
  for (const stateMappingKey of stateMappingKeys) {
484
486
  const subscriber = callbackToStateMapping[stateMappingKey];
485
487
  if (!subscriber) {
@@ -496,7 +498,7 @@ function keysChanged(collectionKey, partialCollection, partialPreviousCollection
496
498
  /**
497
499
  * e.g. Onyx.connect({key: `${ONYXKEYS.COLLECTION.REPORT}{reportID}`, callback: ...});
498
500
  */
499
- const isSubscribedToCollectionMemberKey = isCollectionMemberKey(collectionKey, subscriber.key, collectionKeyLength);
501
+ const isSubscribedToCollectionMemberKey = isCollectionMemberKey(collectionKey, subscriber.key);
500
502
  // Regular Onyx.connect() subscriber found.
501
503
  if (typeof subscriber.callback === 'function') {
502
504
  if (!notifyConnectSubscribers) {
@@ -1121,7 +1123,6 @@ function updateSnapshots(data, mergeFn) {
1121
1123
  return [];
1122
1124
  const promises = [];
1123
1125
  const snapshotCollection = OnyxUtils.getCachedCollection(snapshotCollectionKey);
1124
- const snapshotCollectionKeyLength = snapshotCollectionKey.length;
1125
1126
  Object.entries(snapshotCollection).forEach(([snapshotEntryKey, snapshotEntryValue]) => {
1126
1127
  // Snapshots may not be present in cache. We don't know how to update them so we skip.
1127
1128
  if (!snapshotEntryValue) {
@@ -1130,7 +1131,7 @@ function updateSnapshots(data, mergeFn) {
1130
1131
  let updatedData = {};
1131
1132
  data.forEach(({ key, value }) => {
1132
1133
  // snapshots are normal keys so we want to skip update if they are written to Onyx
1133
- if (OnyxUtils.isCollectionMemberKey(snapshotCollectionKey, key, snapshotCollectionKeyLength)) {
1134
+ if (OnyxUtils.isCollectionMemberKey(snapshotCollectionKey, key)) {
1134
1135
  return;
1135
1136
  }
1136
1137
  if (typeof snapshotEntryValue !== 'object' || !('data' in snapshotEntryValue)) {
@@ -1149,7 +1150,17 @@ function updateSnapshots(data, mergeFn) {
1149
1150
  return;
1150
1151
  }
1151
1152
  const oldValue = updatedData[key] || {};
1152
- updatedData = Object.assign(Object.assign({}, updatedData), { [key]: Object.assign(oldValue, value) });
1153
+ let collectionKey;
1154
+ try {
1155
+ collectionKey = getCollectionKey(key);
1156
+ }
1157
+ catch (e) {
1158
+ // If getCollectionKey() throws an error it means the key is not a collection key.
1159
+ collectionKey = undefined;
1160
+ }
1161
+ const shouldFullyMerge = fullyMergedSnapshotKeys === null || fullyMergedSnapshotKeys === void 0 ? void 0 : fullyMergedSnapshotKeys.has(collectionKey || key);
1162
+ const newValue = shouldFullyMerge ? value : (0, pick_1.default)(value, Object.keys(snapshotData[key]));
1163
+ updatedData = Object.assign(Object.assign({}, updatedData), { [key]: Object.assign(oldValue, newValue) });
1153
1164
  });
1154
1165
  // Skip the update if there's no data to be merged
1155
1166
  if (utils_1.default.isEmptyObject(updatedData)) {
package/dist/types.d.ts CHANGED
@@ -403,6 +403,13 @@ type InitOptions = {
403
403
  * Additionally, any subscribers from these keys to won't receive any data from Onyx.
404
404
  */
405
405
  skippableCollectionMemberIDs?: string[];
406
+ /**
407
+ * Array of snapshot collection keys where full merge is supported and data structure can be changed after merge.
408
+ * For e.g. if oldSnapshotData is {report_1: {name 'Fitsum'}} and BE update is {report_1: {name:'Fitsum2', nickName:'Fitse'}}
409
+ * if it is fullyMergedSnapshotkey the `nickName` prop that didn't exist in the previous data will be merged
410
+ * otherwise only existing prop will be picked from the BE update and merged (in this case only name).
411
+ */
412
+ fullyMergedSnapshotKeys?: string[];
406
413
  };
407
414
  type GenericFunction = (...args: any[]) => any;
408
415
  /**
package/dist/useOnyx.js CHANGED
@@ -74,9 +74,7 @@ function useOnyx(key, options, dependencies = []) {
74
74
  try {
75
75
  const previousCollectionKey = OnyxUtils_1.default.splitCollectionMemberKey(previousKey)[0];
76
76
  const collectionKey = OnyxUtils_1.default.splitCollectionMemberKey(key)[0];
77
- if (OnyxUtils_1.default.isCollectionMemberKey(previousCollectionKey, previousKey, previousCollectionKey.length) &&
78
- OnyxUtils_1.default.isCollectionMemberKey(collectionKey, key, collectionKey.length) &&
79
- previousCollectionKey === collectionKey) {
77
+ if (OnyxUtils_1.default.isCollectionMemberKey(previousCollectionKey, previousKey) && OnyxUtils_1.default.isCollectionMemberKey(collectionKey, key) && previousCollectionKey === collectionKey) {
80
78
  return;
81
79
  }
82
80
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-onyx",
3
- "version": "2.0.111",
3
+ "version": "2.0.112",
4
4
  "author": "Expensify, Inc.",
5
5
  "homepage": "https://expensify.com",
6
6
  "description": "State management for React Native",