react-native-onyx 1.0.126 → 1.0.128

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.
@@ -0,0 +1,71 @@
1
+ import _ from 'underscore';
2
+
3
+ const ERROR_LABEL = 'Onyx DevTools - Error: ';
4
+
5
+ /* eslint-disable no-underscore-dangle */
6
+ class DevTools {
7
+ constructor() {
8
+ this.remoteDev = this.connectViaExtension();
9
+ this.state = {};
10
+ this.defaultState = {};
11
+ }
12
+
13
+ connectViaExtension(options) {
14
+ try {
15
+ if ((options && options.remote) || typeof window === 'undefined' || !window.__REDUX_DEVTOOLS_EXTENSION__) {
16
+ return;
17
+ }
18
+ return window.__REDUX_DEVTOOLS_EXTENSION__.connect(options);
19
+ } catch (e) {
20
+ console.error(ERROR_LABEL, e);
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Registers an action that updated the current state of the storage
26
+ *
27
+ * @param {string} type - name of the action
28
+ * @param {any} payload - data written to the storage
29
+ * @param {object} stateChanges - partial state that got updated after the changes
30
+ */
31
+ registerAction(type, payload = undefined, stateChanges = {}) {
32
+ try {
33
+ if (!this.remoteDev) {
34
+ return;
35
+ }
36
+ const newState = {
37
+ ...this.state,
38
+ ...stateChanges,
39
+ };
40
+ this.remoteDev.send({type, payload}, newState);
41
+ this.state = newState;
42
+ } catch (e) {
43
+ console.error(ERROR_LABEL, e);
44
+ }
45
+ }
46
+
47
+ initState(initialState = {}) {
48
+ try {
49
+ if (!this.remoteDev) {
50
+ return;
51
+ }
52
+ this.remoteDev.init(initialState);
53
+ this.state = initialState;
54
+ this.defaultState = initialState;
55
+ } catch (e) {
56
+ console.error(ERROR_LABEL, e);
57
+ }
58
+ }
59
+
60
+ /**
61
+ * This clears the internal state of the DevTools, preserving the keys included in `keysToPreserve`
62
+ *
63
+ * @param {string[]} keysToPreserve
64
+ */
65
+ clearState(keysToPreserve = []) {
66
+ const newState = _.mapObject(this.state, (value, key) => (keysToPreserve.includes(key) ? value : this.defaultState[key]));
67
+ this.registerAction('CLEAR', undefined, newState);
68
+ }
69
+ }
70
+
71
+ export default new DevTools();
package/lib/Onyx.d.ts CHANGED
@@ -107,6 +107,7 @@ declare const METHOD: {
107
107
  readonly SET: 'set';
108
108
  readonly MERGE: 'merge';
109
109
  readonly MERGE_COLLECTION: 'mergecollection';
110
+ readonly MULTI_SET: 'multiset';
110
111
  readonly CLEAR: 'clear';
111
112
  };
112
113
 
package/lib/Onyx.js CHANGED
@@ -11,6 +11,7 @@ import * as Broadcast from './broadcast';
11
11
  import * as ActiveClientManager from './ActiveClientManager';
12
12
  import utils from './utils';
13
13
  import unstable_batchedUpdates from './batch';
14
+ import DevTools from './DevTools';
14
15
 
15
16
  // Method constants
16
17
  const METHOD = {
@@ -62,6 +63,18 @@ let onClearCallback = null;
62
63
  let batchUpdatesPromise = null;
63
64
  let batchUpdatesQueue = [];
64
65
 
66
+ /**
67
+ * Sends an action to DevTools extension
68
+ *
69
+ * @param {string} method - Onyx method from METHOD
70
+ * @param {string} key - Onyx key that was changed
71
+ * @param {any} value - contains the change that was made by the method
72
+ * @param {any} mergedValue - (optional) value that was written in the storage after a merge method was executed.
73
+ */
74
+ function sendActionToDevTools(method, key, value, mergedValue = undefined) {
75
+ DevTools.registerAction(utils.formatActionName(method, key), value, key ? {[key]: mergedValue || value} : value);
76
+ }
77
+
65
78
  /**
66
79
  * We are batching together onyx updates. This helps with use cases where we schedule onyx updates after each other.
67
80
  * This happens for example in the Onyx.update function, where we process API responses that might contain a lot of
@@ -1105,7 +1118,10 @@ function set(key, value) {
1105
1118
 
1106
1119
  return Storage.setItem(key, valueAfterRemoving)
1107
1120
  .catch((error) => evictStorageAndRetry(error, set, key, valueAfterRemoving))
1108
- .then(() => updatePromise);
1121
+ .then(() => {
1122
+ sendActionToDevTools(METHOD.SET, key, valueAfterRemoving);
1123
+ return updatePromise;
1124
+ });
1109
1125
  }
1110
1126
 
1111
1127
  /**
@@ -1158,7 +1174,10 @@ function multiSet(data) {
1158
1174
 
1159
1175
  return Storage.multiSet(keyValuePairs)
1160
1176
  .catch((error) => evictStorageAndRetry(error, multiSet, data))
1161
- .then(() => Promise.all(updatePromises));
1177
+ .then(() => {
1178
+ sendActionToDevTools(METHOD.MULTI_SET, undefined, data);
1179
+ return Promise.all(updatePromises);
1180
+ });
1162
1181
  }
1163
1182
 
1164
1183
  /**
@@ -1274,7 +1293,10 @@ function merge(key, changes) {
1274
1293
  return updatePromise;
1275
1294
  }
1276
1295
 
1277
- return Storage.mergeItem(key, batchedChanges, modifiedData).then(() => updatePromise);
1296
+ return Storage.mergeItem(key, batchedChanges, modifiedData).then(() => {
1297
+ sendActionToDevTools(METHOD.MERGE, key, changes, modifiedData);
1298
+ return updatePromise;
1299
+ });
1278
1300
  } catch (error) {
1279
1301
  Logger.logAlert(`An error occurred while applying merge for key: ${key}, Error: ${error}`);
1280
1302
  return Promise.resolve();
@@ -1395,6 +1417,7 @@ function clear(keysToPreserve = []) {
1395
1417
  .then(() => {
1396
1418
  isClearing = false;
1397
1419
  Broadcast.sendMessage({type: METHOD.CLEAR, keysToPreserve});
1420
+ DevTools.clearState(keysToPreserve);
1398
1421
  return Promise.all(updatePromises);
1399
1422
  });
1400
1423
  });
@@ -1480,7 +1503,10 @@ function mergeCollection(collectionKey, collection) {
1480
1503
 
1481
1504
  return Promise.all(promises)
1482
1505
  .catch((error) => evictStorageAndRetry(error, mergeCollection, collection))
1483
- .then(() => promiseUpdate);
1506
+ .then(() => {
1507
+ sendActionToDevTools(METHOD.MERGE_COLLECTION, undefined, collection);
1508
+ return promiseUpdate;
1509
+ });
1484
1510
  });
1485
1511
  }
1486
1512
 
@@ -1659,6 +1685,8 @@ function init({
1659
1685
  // Set our default key states to use when initializing and clearing Onyx data
1660
1686
  defaultKeyStates = initialKeyStates;
1661
1687
 
1688
+ DevTools.initState(initialKeyStates);
1689
+
1662
1690
  // Let Onyx know about which keys are safe to evict
1663
1691
  evictionAllowList = safeEvictionKeys;
1664
1692
 
package/lib/utils.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { OnyxKey } from './types';
2
+
1
3
  /**
2
4
  * Merges two objects and removes null values if "shouldRemoveNullObjectValues" is set to true
3
5
  *
@@ -7,4 +9,9 @@
7
9
  */
8
10
  declare function fastMerge<T>(target: T, source: T, shouldRemoveNullObjectValues: boolean = true): T;
9
11
 
10
- export default {fastMerge};
12
+ /**
13
+ * Returns a formatted action name to be send to DevTools, given the method and optionally the key that was changed
14
+ */
15
+ declare function formatActionName(method: string, key?: OnyxKey): string;
16
+
17
+ export default { fastMerge, formatActionName };
package/lib/utils.js CHANGED
@@ -105,4 +105,8 @@ function removeNestedNullValues(value) {
105
105
  return value;
106
106
  }
107
107
 
108
- export default {areObjectsEmpty, fastMerge, removeNestedNullValues};
108
+ function formatActionName(method, key) {
109
+ return key ? `${method.toUpperCase()}/${key}` : method.toUpperCase();
110
+ }
111
+
112
+ export default {areObjectsEmpty, fastMerge, formatActionName, removeNestedNullValues};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-onyx",
3
- "version": "1.0.126",
3
+ "version": "1.0.128",
4
4
  "author": "Expensify, Inc.",
5
5
  "homepage": "https://expensify.com",
6
6
  "description": "State management for React Native",
@@ -55,7 +55,7 @@
55
55
  "@react-native-community/eslint-config": "^2.0.0",
56
56
  "@testing-library/jest-native": "^3.4.2",
57
57
  "@testing-library/react-native": "^7.0.2",
58
- "@types/node": "^20.7.1",
58
+ "@types/node": "^20.11.5",
59
59
  "@types/react": "^18.2.14",
60
60
  "babel-eslint": "^10.1.0",
61
61
  "babel-jest": "^26.2.2",
@@ -107,8 +107,8 @@
107
107
  }
108
108
  },
109
109
  "engines": {
110
- "node": "20.9.0",
111
- "npm": "10.1.0"
110
+ "node": ">=20.9.0",
111
+ "npm": ">=10.2.3"
112
112
  },
113
113
  "jest": {
114
114
  "preset": "react-native",