react-native-onyx 2.0.81 → 2.0.83

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,11 @@
1
+ /**
2
+ * Stores settings from Onyx.init globally so they can be made accessible by other parts of the library.
3
+ */
4
+ declare const globalSettings: {
5
+ enablePerformanceMetrics: boolean;
6
+ };
7
+ type GlobalSettings = typeof globalSettings;
8
+ declare function addGlobalSettingsChangeListener(listener: (settings: GlobalSettings) => unknown): () => void;
9
+ declare function setPerformanceMetricsEnabled(enabled: boolean): void;
10
+ declare function isPerformanceMetricsEnabled(): boolean;
11
+ export { setPerformanceMetricsEnabled, isPerformanceMetricsEnabled, addGlobalSettingsChangeListener };
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ /**
3
+ * Stores settings from Onyx.init globally so they can be made accessible by other parts of the library.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.addGlobalSettingsChangeListener = exports.isPerformanceMetricsEnabled = exports.setPerformanceMetricsEnabled = void 0;
7
+ const globalSettings = {
8
+ enablePerformanceMetrics: false,
9
+ };
10
+ const listeners = new Set();
11
+ function addGlobalSettingsChangeListener(listener) {
12
+ listeners.add(listener);
13
+ return () => {
14
+ listeners.delete(listener);
15
+ };
16
+ }
17
+ exports.addGlobalSettingsChangeListener = addGlobalSettingsChangeListener;
18
+ function notifyListeners() {
19
+ listeners.forEach((listener) => listener(globalSettings));
20
+ }
21
+ function setPerformanceMetricsEnabled(enabled) {
22
+ globalSettings.enablePerformanceMetrics = enabled;
23
+ notifyListeners();
24
+ }
25
+ exports.setPerformanceMetricsEnabled = setPerformanceMetricsEnabled;
26
+ function isPerformanceMetricsEnabled() {
27
+ return globalSettings.enablePerformanceMetrics;
28
+ }
29
+ exports.isPerformanceMetricsEnabled = isPerformanceMetricsEnabled;
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, safeEvictionKeys, maxCachedKeysCount, shouldSyncMultipleInstances, debugSetState, }: InitOptions): void;
5
+ declare function init({ keys, initialKeyStates, safeEvictionKeys, maxCachedKeysCount, shouldSyncMultipleInstances, debugSetState, enablePerformanceMetrics, }: InitOptions): void;
6
6
  /**
7
7
  * Connects to an Onyx key given the options passed and listens to its changes.
8
8
  *
@@ -134,7 +134,7 @@ declare function update(data: OnyxUpdate[]): Promise<void>;
134
134
  */
135
135
  declare function setCollection<TKey extends CollectionKeyBase, TMap extends string>(collectionKey: TKey, collection: OnyxMergeCollectionInput<TMap>): Promise<void>;
136
136
  declare const Onyx: {
137
- readonly METHOD: {
137
+ METHOD: {
138
138
  readonly SET: "set";
139
139
  readonly MERGE: "merge";
140
140
  readonly MERGE_COLLECTION: "mergecollection";
@@ -142,17 +142,17 @@ declare const Onyx: {
142
142
  readonly MULTI_SET: "multiset";
143
143
  readonly CLEAR: "clear";
144
144
  };
145
- readonly connect: typeof connect;
146
- readonly disconnect: typeof disconnect;
147
- readonly set: typeof set;
148
- readonly multiSet: typeof multiSet;
149
- readonly merge: typeof merge;
150
- readonly mergeCollection: typeof mergeCollection;
151
- readonly setCollection: typeof setCollection;
152
- readonly update: typeof update;
153
- readonly clear: typeof clear;
154
- readonly init: typeof init;
155
- readonly registerLogger: typeof Logger.registerLogger;
145
+ connect: typeof connect;
146
+ disconnect: typeof disconnect;
147
+ set: typeof set;
148
+ multiSet: typeof multiSet;
149
+ merge: typeof merge;
150
+ mergeCollection: typeof mergeCollection;
151
+ setCollection: typeof setCollection;
152
+ update: typeof update;
153
+ clear: typeof clear;
154
+ init: typeof init;
155
+ registerLogger: typeof Logger.registerLogger;
156
156
  };
157
157
  export default Onyx;
158
158
  export type { OnyxUpdate, Mapping, ConnectOptions };
package/dist/Onyx.js CHANGED
@@ -38,9 +38,15 @@ const DevTools_1 = __importDefault(require("./DevTools"));
38
38
  const OnyxUtils_1 = __importDefault(require("./OnyxUtils"));
39
39
  const logMessages_1 = __importDefault(require("./logMessages"));
40
40
  const OnyxConnectionManager_1 = __importDefault(require("./OnyxConnectionManager"));
41
+ const GlobalSettings = __importStar(require("./GlobalSettings"));
42
+ const metrics_1 = __importDefault(require("./metrics"));
41
43
  /** Initialize the store with actions and listening for storage events */
42
- function init({ keys = {}, initialKeyStates = {}, safeEvictionKeys = [], maxCachedKeysCount = 1000, shouldSyncMultipleInstances = Boolean(global.localStorage), debugSetState = false, }) {
44
+ function init({ keys = {}, initialKeyStates = {}, safeEvictionKeys = [], maxCachedKeysCount = 1000, shouldSyncMultipleInstances = Boolean(global.localStorage), debugSetState = false, enablePerformanceMetrics = false, }) {
43
45
  var _a;
46
+ if (enablePerformanceMetrics) {
47
+ GlobalSettings.setPerformanceMetricsEnabled(true);
48
+ applyDecorators();
49
+ }
44
50
  storage_1.default.init();
45
51
  if (shouldSyncMultipleInstances) {
46
52
  (_a = storage_1.default.keepInstancesSync) === null || _a === void 0 ? void 0 : _a.call(storage_1.default, (key, value) => {
@@ -515,7 +521,7 @@ function updateSnapshots(data) {
515
521
  function update(data) {
516
522
  // First, validate the Onyx object is in the format we expect
517
523
  data.forEach(({ onyxMethod, key, value }) => {
518
- if (![OnyxUtils_1.default.METHOD.CLEAR, OnyxUtils_1.default.METHOD.SET, OnyxUtils_1.default.METHOD.MERGE, OnyxUtils_1.default.METHOD.MERGE_COLLECTION, OnyxUtils_1.default.METHOD.MULTI_SET].includes(onyxMethod)) {
524
+ if (!Object.values(OnyxUtils_1.default.METHOD).includes(onyxMethod)) {
519
525
  throw new Error(`Invalid onyxMethod ${onyxMethod} in Onyx update.`);
520
526
  }
521
527
  if (onyxMethod === OnyxUtils_1.default.METHOD.MULTI_SET) {
@@ -552,18 +558,14 @@ function update(data) {
552
558
  const promises = [];
553
559
  let clearPromise = Promise.resolve();
554
560
  data.forEach(({ onyxMethod, key, value }) => {
555
- switch (onyxMethod) {
556
- case OnyxUtils_1.default.METHOD.SET:
557
- enqueueSetOperation(key, value);
558
- break;
559
- case OnyxUtils_1.default.METHOD.MERGE:
560
- enqueueMergeOperation(key, value);
561
- break;
562
- case OnyxUtils_1.default.METHOD.MERGE_COLLECTION: {
561
+ const handlers = {
562
+ [OnyxUtils_1.default.METHOD.SET]: enqueueSetOperation,
563
+ [OnyxUtils_1.default.METHOD.MERGE]: enqueueMergeOperation,
564
+ [OnyxUtils_1.default.METHOD.MERGE_COLLECTION]: () => {
563
565
  const collection = value;
564
566
  if (!OnyxUtils_1.default.isValidNonEmptyCollectionForMerge(collection)) {
565
567
  Logger.logInfo('mergeCollection enqueued within update() with invalid or empty value. Skipping this operation.');
566
- break;
568
+ return;
567
569
  }
568
570
  // Confirm all the collection keys belong to the same parent
569
571
  const collectionKeys = Object.keys(collection);
@@ -571,17 +573,14 @@ function update(data) {
571
573
  const mergedCollection = collection;
572
574
  collectionKeys.forEach((collectionKey) => enqueueMergeOperation(collectionKey, mergedCollection[collectionKey]));
573
575
  }
574
- break;
575
- }
576
- case OnyxUtils_1.default.METHOD.MULTI_SET:
577
- Object.entries(value).forEach(([entryKey, entryValue]) => enqueueSetOperation(entryKey, entryValue));
578
- break;
579
- case OnyxUtils_1.default.METHOD.CLEAR:
576
+ },
577
+ [OnyxUtils_1.default.METHOD.SET_COLLECTION]: (k, v) => promises.push(() => setCollection(k, v)),
578
+ [OnyxUtils_1.default.METHOD.MULTI_SET]: (k, v) => Object.entries(v).forEach(([entryKey, entryValue]) => enqueueSetOperation(entryKey, entryValue)),
579
+ [OnyxUtils_1.default.METHOD.CLEAR]: () => {
580
580
  clearPromise = clear();
581
- break;
582
- default:
583
- break;
584
- }
581
+ },
582
+ };
583
+ handlers[onyxMethod](key, value);
585
584
  });
586
585
  // Group all the collection-related keys and update each collection in a single `mergeCollection` call.
587
586
  // This is needed to prevent multiple `mergeCollection` calls for the same collection and `merge` calls for the individual items of the said collection.
@@ -679,4 +678,23 @@ const Onyx = {
679
678
  init,
680
679
  registerLogger: Logger.registerLogger,
681
680
  };
681
+ function applyDecorators() {
682
+ // We are reassigning the functions directly so that internal function calls are also decorated
683
+ /* eslint-disable rulesdir/prefer-actions-set-data */
684
+ // @ts-expect-error Reassign
685
+ connect = (0, metrics_1.default)(connect, 'Onyx.connect');
686
+ // @ts-expect-error Reassign
687
+ set = (0, metrics_1.default)(set, 'Onyx.set');
688
+ // @ts-expect-error Reassign
689
+ multiSet = (0, metrics_1.default)(multiSet, 'Onyx.multiSet');
690
+ // @ts-expect-error Reassign
691
+ merge = (0, metrics_1.default)(merge, 'Onyx.merge');
692
+ // @ts-expect-error Reassign
693
+ mergeCollection = (0, metrics_1.default)(mergeCollection, 'Onyx.mergeCollection');
694
+ // @ts-expect-error Reassign
695
+ update = (0, metrics_1.default)(update, 'Onyx.update');
696
+ // @ts-expect-error Reassign
697
+ clear = (0, metrics_1.default)(clear, 'Onyx.clear');
698
+ /* eslint-enable rulesdir/prefer-actions-set-data */
699
+ }
682
700
  exports.default = Onyx;
@@ -278,4 +278,5 @@ declare const OnyxUtils: {
278
278
  unsubscribeFromKey: typeof unsubscribeFromKey;
279
279
  getEvictionBlocklist: typeof getEvictionBlocklist;
280
280
  };
281
+ export type { OnyxMethod };
281
282
  export default OnyxUtils;
package/dist/OnyxUtils.js CHANGED
@@ -39,6 +39,8 @@ const batch_1 = __importDefault(require("./batch"));
39
39
  const storage_1 = __importDefault(require("./storage"));
40
40
  const utils_1 = __importDefault(require("./utils"));
41
41
  const createDeferredTask_1 = __importDefault(require("./createDeferredTask"));
42
+ const GlobalSettings = __importStar(require("./GlobalSettings"));
43
+ const metrics_1 = __importDefault(require("./metrics"));
42
44
  // Method constants
43
45
  const METHOD = {
44
46
  SET: 'set',
@@ -1161,4 +1163,48 @@ const OnyxUtils = {
1161
1163
  unsubscribeFromKey,
1162
1164
  getEvictionBlocklist,
1163
1165
  };
1166
+ GlobalSettings.addGlobalSettingsChangeListener(({ enablePerformanceMetrics }) => {
1167
+ if (!enablePerformanceMetrics) {
1168
+ return;
1169
+ }
1170
+ // We are reassigning the functions directly so that internal function calls are also decorated
1171
+ // @ts-expect-error Reassign
1172
+ initStoreValues = (0, metrics_1.default)(initStoreValues, 'OnyxUtils.initStoreValues');
1173
+ // @ts-expect-error Reassign
1174
+ maybeFlushBatchUpdates = (0, metrics_1.default)(maybeFlushBatchUpdates, 'OnyxUtils.maybeFlushBatchUpdates');
1175
+ // @ts-expect-error Reassign
1176
+ batchUpdates = (0, metrics_1.default)(batchUpdates, 'OnyxUtils.batchUpdates');
1177
+ // @ts-expect-error Complex type signature
1178
+ get = (0, metrics_1.default)(get, 'OnyxUtils.get');
1179
+ // @ts-expect-error Reassign
1180
+ getAllKeys = (0, metrics_1.default)(getAllKeys, 'OnyxUtils.getAllKeys');
1181
+ // @ts-expect-error Reassign
1182
+ getCollectionKeys = (0, metrics_1.default)(getCollectionKeys, 'OnyxUtils.getCollectionKeys');
1183
+ // @ts-expect-error Reassign
1184
+ addAllSafeEvictionKeysToRecentlyAccessedList = (0, metrics_1.default)(addAllSafeEvictionKeysToRecentlyAccessedList, 'OnyxUtils.addAllSafeEvictionKeysToRecentlyAccessedList');
1185
+ // @ts-expect-error Reassign
1186
+ keysChanged = (0, metrics_1.default)(keysChanged, 'OnyxUtils.keysChanged');
1187
+ // @ts-expect-error Reassign
1188
+ keyChanged = (0, metrics_1.default)(keyChanged, 'OnyxUtils.keyChanged');
1189
+ // @ts-expect-error Reassign
1190
+ sendDataToConnection = (0, metrics_1.default)(sendDataToConnection, 'OnyxUtils.sendDataToConnection');
1191
+ // @ts-expect-error Reassign
1192
+ scheduleSubscriberUpdate = (0, metrics_1.default)(scheduleSubscriberUpdate, 'OnyxUtils.scheduleSubscriberUpdate');
1193
+ // @ts-expect-error Reassign
1194
+ scheduleNotifyCollectionSubscribers = (0, metrics_1.default)(scheduleNotifyCollectionSubscribers, 'OnyxUtils.scheduleNotifyCollectionSubscribers');
1195
+ // @ts-expect-error Reassign
1196
+ remove = (0, metrics_1.default)(remove, 'OnyxUtils.remove');
1197
+ // @ts-expect-error Reassign
1198
+ reportStorageQuota = (0, metrics_1.default)(reportStorageQuota, 'OnyxUtils.reportStorageQuota');
1199
+ // @ts-expect-error Complex type signature
1200
+ evictStorageAndRetry = (0, metrics_1.default)(evictStorageAndRetry, 'OnyxUtils.evictStorageAndRetry');
1201
+ // @ts-expect-error Reassign
1202
+ broadcastUpdate = (0, metrics_1.default)(broadcastUpdate, 'OnyxUtils.broadcastUpdate');
1203
+ // @ts-expect-error Reassign
1204
+ initializeWithDefaultKeyStates = (0, metrics_1.default)(initializeWithDefaultKeyStates, 'OnyxUtils.initializeWithDefaultKeyStates');
1205
+ // @ts-expect-error Complex type signature
1206
+ multiGet = (0, metrics_1.default)(multiGet, 'OnyxUtils.multiGet');
1207
+ // @ts-expect-error Reassign
1208
+ subscribeToKey = (0, metrics_1.default)(subscribeToKey, 'OnyxUtils.subscribeToKey');
1209
+ });
1164
1210
  exports.default = OnyxUtils;
@@ -0,0 +1,10 @@
1
+ type ImportType = ReturnType<typeof require>;
2
+ /**
3
+ * Create a lazily-imported module proxy.
4
+ * This is useful for lazily requiring optional dependencies.
5
+ */
6
+ declare const createModuleProxy: <TModule>(getModule: () => ImportType) => TModule;
7
+ declare class OptionalDependencyNotInstalledError extends Error {
8
+ constructor(name: string);
9
+ }
10
+ export { createModuleProxy, OptionalDependencyNotInstalledError };
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OptionalDependencyNotInstalledError = exports.createModuleProxy = void 0;
4
+ /**
5
+ * Create a lazily-imported module proxy.
6
+ * This is useful for lazily requiring optional dependencies.
7
+ */
8
+ const createModuleProxy = (getModule) => {
9
+ const holder = { module: undefined };
10
+ const proxy = new Proxy(holder, {
11
+ get: (target, property) => {
12
+ if (property === '$$typeof') {
13
+ // If inlineRequires is enabled, Metro will look up all imports
14
+ // with the $$typeof operator. In this case, this will throw the
15
+ // `OptionalDependencyNotInstalledError` error because we try to access the module
16
+ // even though we are not using it (Metro does it), so instead we return undefined
17
+ // to bail out of inlineRequires here.
18
+ return undefined;
19
+ }
20
+ if (target.module == null) {
21
+ // lazy initialize module via require()
22
+ // caller needs to make sure the require() call is wrapped in a try/catch
23
+ // eslint-disable-next-line no-param-reassign
24
+ target.module = getModule();
25
+ }
26
+ return target.module[property];
27
+ },
28
+ });
29
+ return proxy;
30
+ };
31
+ exports.createModuleProxy = createModuleProxy;
32
+ class OptionalDependencyNotInstalledError extends Error {
33
+ constructor(name) {
34
+ super(`${name} is not installed!`);
35
+ }
36
+ }
37
+ exports.OptionalDependencyNotInstalledError = OptionalDependencyNotInstalledError;
@@ -0,0 +1 @@
1
+ export default performance;
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ // Use the existing performance API on web
4
+ exports.default = performance;
@@ -0,0 +1,20 @@
1
+ declare const PerformanceProxy: {
2
+ timeOrigin: number;
3
+ now: () => number;
4
+ mark: (markName: string, markOptions?: import("react-native-performance/lib/typescript/performance").MarkOptions | undefined) => import("react-native-performance").PerformanceMark;
5
+ clearMarks: (name?: string | undefined) => void;
6
+ measure: (measureName: string, startOrMeasureOptions?: import("react-native-performance/lib/typescript/performance").StartOrMeasureOptions, endMark?: string | number | undefined) => import("react-native-performance").PerformanceMeasure;
7
+ clearMeasures: (name?: string | undefined) => void;
8
+ metric: (name: string, valueOrOptions: import("react-native-performance/lib/typescript/performance").ValueOrOptions) => import("react-native-performance").PerformanceMetric;
9
+ clearMetrics: (name?: string | undefined) => void;
10
+ getEntries: () => import("react-native-performance").PerformanceEntry[];
11
+ getEntriesByName: (name: string, type?: import("react-native-performance").EntryType | undefined) => import("react-native-performance").PerformanceEntry[];
12
+ getEntriesByType: {
13
+ (type: "measure"): import("react-native-performance").PerformanceMeasure[];
14
+ (type: "mark"): import("react-native-performance").PerformanceMark[];
15
+ (type: "resource"): import("react-native-performance").PerformanceResourceTiming[];
16
+ (type: "metric"): import("react-native-performance").PerformanceMetric[];
17
+ (type: "react-native-mark"): import("react-native-performance").PerformanceReactNativeMark[];
18
+ };
19
+ };
20
+ export default PerformanceProxy;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const ModuleProxy_1 = require("../ModuleProxy");
4
+ const PerformanceProxy = (0, ModuleProxy_1.createModuleProxy)(() => {
5
+ try {
6
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
7
+ return require('react-native-performance').default;
8
+ }
9
+ catch (_a) {
10
+ throw new ModuleProxy_1.OptionalDependencyNotInstalledError('react-native-performance');
11
+ }
12
+ });
13
+ exports.default = PerformanceProxy;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Wraps a function with metrics capturing logic
3
+ */
4
+ declare function decorateWithMetrics<Args extends unknown[], ReturnType>(func: (...args: Args) => ReturnType, alias?: string): {
5
+ (...args: Args): ReturnType;
6
+ name: string;
7
+ };
8
+ export default decorateWithMetrics;
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const PerformanceProxy_1 = __importDefault(require("./dependencies/PerformanceProxy"));
7
+ const decoratedAliases = new Set();
8
+ /**
9
+ * Capture a measurement between the start mark and now
10
+ */
11
+ function measureMarkToNow(startMark, detail) {
12
+ PerformanceProxy_1.default.measure(`${startMark.name} [${startMark.detail.args.toString()}]`, {
13
+ start: startMark.startTime,
14
+ end: PerformanceProxy_1.default.now(),
15
+ detail: Object.assign(Object.assign({}, startMark.detail), detail),
16
+ });
17
+ }
18
+ function isPromiseLike(value) {
19
+ return value != null && typeof value === 'object' && 'then' in value;
20
+ }
21
+ /**
22
+ * Wraps a function with metrics capturing logic
23
+ */
24
+ function decorateWithMetrics(func, alias = func.name) {
25
+ if (decoratedAliases.has(alias)) {
26
+ throw new Error(`"${alias}" is already decorated`);
27
+ }
28
+ decoratedAliases.add(alias);
29
+ function decorated(...args) {
30
+ const mark = PerformanceProxy_1.default.mark(alias, { detail: { args, alias } });
31
+ const originalReturnValue = func(...args);
32
+ if (isPromiseLike(originalReturnValue)) {
33
+ /*
34
+ * The handlers added here are not affecting the original promise
35
+ * They create a separate chain that's not exposed (returned) to the original caller
36
+ */
37
+ originalReturnValue
38
+ .then((result) => {
39
+ measureMarkToNow(mark, { result });
40
+ })
41
+ .catch((error) => {
42
+ measureMarkToNow(mark, { error });
43
+ });
44
+ return originalReturnValue;
45
+ }
46
+ measureMarkToNow(mark, { result: originalReturnValue });
47
+ return originalReturnValue;
48
+ }
49
+ decorated.name = `${alias}_DECORATED`;
50
+ return decorated;
51
+ }
52
+ exports.default = decorateWithMetrics;
@@ -2,5 +2,5 @@ import type StorageProvider from './providers/types';
2
2
  type Storage = {
3
3
  getStorageProvider: () => StorageProvider;
4
4
  } & Omit<StorageProvider, 'name'>;
5
- declare const Storage: Storage;
6
- export default Storage;
5
+ declare const storage: Storage;
6
+ export default storage;
@@ -30,6 +30,8 @@ const Logger = __importStar(require("../Logger"));
30
30
  const platforms_1 = __importDefault(require("./platforms"));
31
31
  const InstanceSync_1 = __importDefault(require("./InstanceSync"));
32
32
  const MemoryOnlyProvider_1 = __importDefault(require("./providers/MemoryOnlyProvider"));
33
+ const GlobalSettings = __importStar(require("../GlobalSettings"));
34
+ const metrics_1 = __importDefault(require("../metrics"));
33
35
  let provider = platforms_1.default;
34
36
  let shouldKeepInstancesSync = false;
35
37
  let finishInitalization;
@@ -71,7 +73,7 @@ function tryOrDegradePerformance(fn, waitForInitialization = true) {
71
73
  });
72
74
  });
73
75
  }
74
- const Storage = {
76
+ const storage = {
75
77
  /**
76
78
  * Returns the storage provider currently in use
77
79
  */
@@ -184,4 +186,20 @@ const Storage = {
184
186
  InstanceSync_1.default.init(onStorageKeyChanged, this);
185
187
  },
186
188
  };
187
- exports.default = Storage;
189
+ GlobalSettings.addGlobalSettingsChangeListener(({ enablePerformanceMetrics }) => {
190
+ if (!enablePerformanceMetrics) {
191
+ return;
192
+ }
193
+ // Apply decorators
194
+ storage.getItem = (0, metrics_1.default)(storage.getItem, 'Storage.getItem');
195
+ storage.multiGet = (0, metrics_1.default)(storage.multiGet, 'Storage.multiGet');
196
+ storage.setItem = (0, metrics_1.default)(storage.setItem, 'Storage.setItem');
197
+ storage.multiSet = (0, metrics_1.default)(storage.multiSet, 'Storage.multiSet');
198
+ storage.mergeItem = (0, metrics_1.default)(storage.mergeItem, 'Storage.mergeItem');
199
+ storage.multiMerge = (0, metrics_1.default)(storage.multiMerge, 'Storage.multiMerge');
200
+ storage.removeItem = (0, metrics_1.default)(storage.removeItem, 'Storage.removeItem');
201
+ storage.removeItems = (0, metrics_1.default)(storage.removeItems, 'Storage.removeItems');
202
+ storage.clear = (0, metrics_1.default)(storage.clear, 'Storage.clear');
203
+ storage.getAllKeys = (0, metrics_1.default)(storage.getAllKeys, 'Storage.getAllKeys');
204
+ });
205
+ exports.default = storage;
package/dist/types.d.ts CHANGED
@@ -2,6 +2,7 @@ import type { Merge } from 'type-fest';
2
2
  import type { BuiltIns } from 'type-fest/source/internal';
3
3
  import type OnyxUtils from './OnyxUtils';
4
4
  import type { WithOnyxInstance, WithOnyxState } from './withOnyx/types';
5
+ import type { OnyxMethod } from './OnyxUtils';
5
6
  /**
6
7
  * Utility type that excludes `null` from the type `TValue`.
7
8
  */
@@ -329,35 +330,43 @@ type OnyxMergeInput<TKey extends OnyxKey> = OnyxInput<TKey>;
329
330
  * This represents the value that can be passed to `Onyx.merge` and to `Onyx.update` with the method "MERGE"
330
331
  */
331
332
  type OnyxMergeCollectionInput<TKey extends OnyxKey, TMap = object> = Collection<TKey, NonNullable<OnyxInput<TKey>>, TMap>;
332
- /**
333
- * Represents different kinds of updates that can be passed to `Onyx.update()` method. It is a discriminated union of
334
- * different update methods (`SET`, `MERGE`, `MERGE_COLLECTION`), each with their own key and value structure.
335
- */
336
- type OnyxUpdate = {
337
- [TKey in OnyxKey]: {
338
- onyxMethod: typeof OnyxUtils.METHOD.SET;
339
- key: TKey;
340
- value: OnyxSetInput<TKey>;
341
- } | {
342
- onyxMethod: typeof OnyxUtils.METHOD.MULTI_SET;
343
- key: TKey;
333
+ type OnyxMethodMap = typeof OnyxUtils.METHOD;
334
+ type OnyxMethodValueMap = {
335
+ [OnyxUtils.METHOD.SET]: {
336
+ key: OnyxKey;
337
+ value: OnyxSetInput<OnyxKey>;
338
+ };
339
+ [OnyxUtils.METHOD.MULTI_SET]: {
340
+ key: OnyxKey;
344
341
  value: OnyxMultiSetInput;
345
- } | {
346
- onyxMethod: typeof OnyxUtils.METHOD.MERGE;
347
- key: TKey;
348
- value: OnyxMergeInput<TKey>;
349
- } | {
350
- onyxMethod: typeof OnyxUtils.METHOD.CLEAR;
351
- key: TKey;
342
+ };
343
+ [OnyxUtils.METHOD.MERGE]: {
344
+ key: OnyxKey;
345
+ value: OnyxMergeInput<OnyxKey>;
346
+ };
347
+ [OnyxUtils.METHOD.CLEAR]: {
348
+ key: OnyxKey;
352
349
  value?: undefined;
353
350
  };
354
- }[OnyxKey] | {
355
- [TKey in CollectionKeyBase]: {
356
- onyxMethod: typeof OnyxUtils.METHOD.MERGE_COLLECTION;
357
- key: TKey;
358
- value: OnyxMergeCollectionInput<TKey>;
351
+ [OnyxUtils.METHOD.MERGE_COLLECTION]: {
352
+ key: CollectionKeyBase;
353
+ value: OnyxMergeCollectionInput<CollectionKeyBase>;
354
+ };
355
+ [OnyxUtils.METHOD.SET_COLLECTION]: {
356
+ key: CollectionKeyBase;
357
+ value: OnyxMergeCollectionInput<CollectionKeyBase>;
359
358
  };
360
- }[CollectionKeyBase];
359
+ };
360
+ /**
361
+ * OnyxUpdate type includes all onyx methods used in OnyxMethodValueMap.
362
+ * If a new method is added to OnyxUtils.METHOD constant, it must be added to OnyxMethodValueMap type.
363
+ * Otherwise it will show static type errors.
364
+ */
365
+ type OnyxUpdate = {
366
+ [Method in OnyxMethod]: {
367
+ onyxMethod: Method;
368
+ } & OnyxMethodValueMap[Method];
369
+ }[OnyxMethod];
361
370
  /**
362
371
  * Represents the options used in `Onyx.init()` method.
363
372
  */
@@ -384,6 +393,11 @@ type InitOptions = {
384
393
  shouldSyncMultipleInstances?: boolean;
385
394
  /** Enables debugging setState() calls to connected components */
386
395
  debugSetState?: boolean;
396
+ /**
397
+ * If enabled it will use the performance API to measure the time taken by Onyx operations.
398
+ * @default false
399
+ */
400
+ enablePerformanceMetrics?: boolean;
387
401
  };
388
402
  type GenericFunction = (...args: any[]) => any;
389
403
  /**
@@ -393,4 +407,4 @@ type MixedOperationsQueue = {
393
407
  merge: OnyxInputKeyValueMapping;
394
408
  set: OnyxInputKeyValueMapping;
395
409
  };
396
- export type { BaseConnectOptions, Collection, CollectionConnectCallback, CollectionConnectOptions, CollectionKey, CollectionKeyBase, ConnectOptions, CustomTypeOptions, DeepRecord, DefaultConnectCallback, DefaultConnectOptions, ExtractOnyxCollectionValue, GenericFunction, InitOptions, Key, KeyValueMapping, Mapping, NonNull, NonUndefined, OnyxInputKeyValueMapping, NullishDeep, OnyxCollection, OnyxEntry, OnyxKey, OnyxInputValue, OnyxCollectionInputValue, OnyxInput, OnyxSetInput, OnyxMultiSetInput, OnyxMergeInput, OnyxMergeCollectionInput, OnyxUpdate, OnyxValue, Selector, WithOnyxConnectOptions, MixedOperationsQueue, };
410
+ export type { BaseConnectOptions, Collection, CollectionConnectCallback, CollectionConnectOptions, CollectionKey, CollectionKeyBase, ConnectOptions, CustomTypeOptions, DeepRecord, DefaultConnectCallback, DefaultConnectOptions, ExtractOnyxCollectionValue, GenericFunction, InitOptions, Key, KeyValueMapping, Mapping, NonNull, NonUndefined, OnyxInputKeyValueMapping, NullishDeep, OnyxCollection, OnyxEntry, OnyxKey, OnyxInputValue, OnyxCollectionInputValue, OnyxInput, OnyxSetInput, OnyxMultiSetInput, OnyxMergeInput, OnyxMergeCollectionInput, OnyxMethod, OnyxMethodMap, OnyxUpdate, OnyxValue, Selector, WithOnyxConnectOptions, MixedOperationsQueue, };
package/lib/index.ts ADDED
@@ -0,0 +1,51 @@
1
+ import type {ConnectOptions, OnyxUpdate} from './Onyx';
2
+ import Onyx from './Onyx';
3
+ import type {
4
+ CustomTypeOptions,
5
+ KeyValueMapping,
6
+ NullishDeep,
7
+ OnyxCollection,
8
+ OnyxEntry,
9
+ OnyxKey,
10
+ OnyxValue,
11
+ Selector,
12
+ OnyxInputValue,
13
+ OnyxCollectionInputValue,
14
+ OnyxInput,
15
+ OnyxSetInput,
16
+ OnyxMultiSetInput,
17
+ OnyxMergeInput,
18
+ OnyxMergeCollectionInput,
19
+ } from './types';
20
+ import type {FetchStatus, ResultMetadata, UseOnyxResult} from './useOnyx';
21
+ import type {Connection} from './OnyxConnectionManager';
22
+ import useOnyx from './useOnyx';
23
+ import withOnyx from './withOnyx';
24
+ import type {WithOnyxState} from './withOnyx/types';
25
+
26
+ export default Onyx;
27
+ export {useOnyx, withOnyx};
28
+ export type {
29
+ ConnectOptions,
30
+ CustomTypeOptions,
31
+ FetchStatus,
32
+ KeyValueMapping,
33
+ NullishDeep,
34
+ OnyxCollection,
35
+ OnyxEntry,
36
+ OnyxKey,
37
+ OnyxInputValue,
38
+ OnyxCollectionInputValue,
39
+ OnyxInput,
40
+ OnyxSetInput,
41
+ OnyxMultiSetInput,
42
+ OnyxMergeInput,
43
+ OnyxMergeCollectionInput,
44
+ OnyxUpdate,
45
+ OnyxValue,
46
+ ResultMetadata,
47
+ Selector,
48
+ UseOnyxResult,
49
+ WithOnyxState,
50
+ Connection,
51
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-onyx",
3
- "version": "2.0.81",
3
+ "version": "2.0.83",
4
4
  "author": "Expensify, Inc.",
5
5
  "homepage": "https://expensify.com",
6
6
  "description": "State management for React Native",
@@ -25,8 +25,7 @@
25
25
  "README.md",
26
26
  "LICENSE.md"
27
27
  ],
28
- "main": "dist/index.js",
29
- "types": "dist/index.d.ts",
28
+ "main": "lib/index.ts",
30
29
  "scripts": {
31
30
  "lint": "eslint .",
32
31
  "typecheck": "tsc --noEmit",