react-native-onyx 2.0.21 → 2.0.23

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 (41) hide show
  1. package/API.md +49 -64
  2. package/dist/DevTools.js +0 -1
  3. package/dist/Onyx.d.ts +49 -258
  4. package/dist/Onyx.js +192 -1165
  5. package/dist/OnyxCache.d.ts +14 -15
  6. package/dist/OnyxUtils.d.ts +320 -0
  7. package/dist/OnyxUtils.js +1061 -0
  8. package/dist/PerformanceUtils.d.ts +3 -5
  9. package/dist/index.d.ts +3 -2
  10. package/dist/storage/InstanceSync/index.d.ts +14 -0
  11. package/dist/storage/InstanceSync/index.js +20 -0
  12. package/dist/storage/InstanceSync/index.web.d.ts +27 -0
  13. package/dist/storage/InstanceSync/index.web.js +59 -0
  14. package/dist/storage/__mocks__/index.d.ts +15 -13
  15. package/dist/storage/__mocks__/index.js +43 -81
  16. package/dist/storage/index.d.ts +6 -2
  17. package/dist/storage/index.js +170 -2
  18. package/dist/storage/platforms/index.d.ts +2 -0
  19. package/dist/storage/{NativeStorage.js → platforms/index.js} +2 -2
  20. package/dist/storage/platforms/index.native.d.ts +2 -0
  21. package/dist/storage/{index.native.js → platforms/index.native.js} +2 -2
  22. package/dist/storage/providers/{IDBKeyVal.js → IDBKeyValProvider.js} +23 -19
  23. package/dist/storage/providers/MemoryOnlyProvider.d.ts +9 -0
  24. package/dist/storage/providers/MemoryOnlyProvider.js +124 -0
  25. package/dist/storage/providers/NoopProvider.js +85 -0
  26. package/dist/storage/providers/SQLiteProvider.d.ts +3 -0
  27. package/dist/storage/providers/{SQLiteStorage.js → SQLiteProvider.js} +17 -11
  28. package/dist/storage/providers/types.d.ts +17 -14
  29. package/dist/types.d.ts +128 -55
  30. package/dist/types.js +2 -0
  31. package/dist/useOnyx.js +11 -10
  32. package/dist/utils.d.ts +2 -2
  33. package/dist/utils.js +29 -16
  34. package/dist/withOnyx.js +6 -5
  35. package/package.json +1 -1
  36. package/dist/storage/NativeStorage.d.ts +0 -2
  37. package/dist/storage/WebStorage.d.ts +0 -3
  38. package/dist/storage/WebStorage.js +0 -62
  39. package/dist/storage/index.native.d.ts +0 -2
  40. /package/dist/storage/providers/{IDBKeyVal.d.ts → IDBKeyValProvider.d.ts} +0 -0
  41. /package/dist/storage/providers/{SQLiteStorage.d.ts → NoopProvider.d.ts} +0 -0
@@ -1,10 +1,8 @@
1
- type Mapping = Record<string, unknown> & {
2
- key: string;
3
- displayName: string;
4
- };
1
+ import type { OnyxKey } from './types';
2
+ import type { Mapping } from './Onyx';
5
3
  declare function setShouldDebugSetState(debug: boolean): void;
6
4
  /**
7
5
  * Provide insights into why a setState() call occurred by diffing the before and after values.
8
6
  */
9
- declare function logSetStateCall(mapping: Mapping, previousValue: unknown, newValue: unknown, caller: string, keyThatChanged: string): void;
7
+ declare function logSetStateCall<TKey extends OnyxKey>(mapping: Mapping<TKey>, previousValue: unknown, newValue: unknown, caller: string, keyThatChanged?: string): void;
10
8
  export { logSetStateCall, setShouldDebugSetState };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import Onyx from './Onyx';
2
2
  import type { OnyxUpdate, ConnectOptions } from './Onyx';
3
- import type { CustomTypeOptions, OnyxCollection, OnyxEntry, NullishDeep, KeyValueMapping, OnyxKey, Selector, WithOnyxInstanceState } from './types';
3
+ import type { CustomTypeOptions, OnyxCollection, OnyxEntry, NullishDeep, KeyValueMapping, OnyxKey, Selector, WithOnyxInstanceState, OnyxValue } from './types';
4
+ import type { UseOnyxResult, FetchStatus } from './useOnyx';
4
5
  import useOnyx from './useOnyx';
5
6
  import withOnyx from './withOnyx';
6
7
  export default Onyx;
7
8
  export { withOnyx, useOnyx };
8
- export type { CustomTypeOptions, OnyxCollection, OnyxEntry, OnyxUpdate, ConnectOptions, NullishDeep, KeyValueMapping, OnyxKey, Selector, WithOnyxInstanceState };
9
+ export type { CustomTypeOptions, OnyxCollection, OnyxEntry, OnyxUpdate, ConnectOptions, NullishDeep, KeyValueMapping, OnyxKey, Selector, WithOnyxInstanceState, UseOnyxResult, OnyxValue, FetchStatus, };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * This is used to keep multiple browser tabs in sync, therefore only needed on web
3
+ * On native platforms, we omit this syncing logic by setting this to mock implementation.
4
+ */
5
+ declare const InstanceSync: {
6
+ shouldBeUsed: boolean;
7
+ init: (...args: any[]) => void;
8
+ setItem: (...args: any[]) => void;
9
+ removeItem: (...args: any[]) => void;
10
+ removeItems: (...args: any[]) => void;
11
+ mergeItem: (...args: any[]) => void;
12
+ clear: <T extends () => void>(callback: T) => Promise<void>;
13
+ };
14
+ export default InstanceSync;
@@ -0,0 +1,20 @@
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 noop_1 = __importDefault(require("lodash/noop"));
7
+ /**
8
+ * This is used to keep multiple browser tabs in sync, therefore only needed on web
9
+ * On native platforms, we omit this syncing logic by setting this to mock implementation.
10
+ */
11
+ const InstanceSync = {
12
+ shouldBeUsed: false,
13
+ init: noop_1.default,
14
+ setItem: noop_1.default,
15
+ removeItem: noop_1.default,
16
+ removeItems: noop_1.default,
17
+ mergeItem: noop_1.default,
18
+ clear: (callback) => Promise.resolve(callback()),
19
+ };
20
+ exports.default = InstanceSync;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The InstancesSync object provides data-changed events like the ones that exist
3
+ * when using LocalStorage APIs in the browser. These events are great because multiple tabs can listen for when
4
+ * data changes and then stay up-to-date with everything happening in Onyx.
5
+ */
6
+ import type { OnyxKey } from '../../types';
7
+ import type { KeyList, OnStorageKeyChanged } from '../providers/types';
8
+ import type StorageProvider from '../providers/types';
9
+ /**
10
+ * Raise an event through `localStorage` to let other tabs know a value changed
11
+ * @param {String} onyxKey
12
+ */
13
+ declare function raiseStorageSyncEvent(onyxKey: OnyxKey): void;
14
+ declare function raiseStorageSyncManyKeysEvent(onyxKeys: KeyList): void;
15
+ declare const InstanceSync: {
16
+ shouldBeUsed: boolean;
17
+ /**
18
+ * @param {Function} onStorageKeyChanged Storage synchronization mechanism keeping all opened tabs in sync
19
+ */
20
+ init: (onStorageKeyChanged: OnStorageKeyChanged, store: StorageProvider) => void;
21
+ setItem: typeof raiseStorageSyncEvent;
22
+ removeItem: typeof raiseStorageSyncEvent;
23
+ removeItems: typeof raiseStorageSyncManyKeysEvent;
24
+ mergeItem: typeof raiseStorageSyncEvent;
25
+ clear: (clearImplementation: () => void) => Promise<void>;
26
+ };
27
+ export default InstanceSync;
@@ -0,0 +1,59 @@
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 NoopProvider_1 = __importDefault(require("../providers/NoopProvider"));
7
+ const SYNC_ONYX = 'SYNC_ONYX';
8
+ /**
9
+ * Raise an event through `localStorage` to let other tabs know a value changed
10
+ * @param {String} onyxKey
11
+ */
12
+ function raiseStorageSyncEvent(onyxKey) {
13
+ global.localStorage.setItem(SYNC_ONYX, onyxKey);
14
+ global.localStorage.removeItem(SYNC_ONYX);
15
+ }
16
+ function raiseStorageSyncManyKeysEvent(onyxKeys) {
17
+ onyxKeys.forEach((onyxKey) => {
18
+ raiseStorageSyncEvent(onyxKey);
19
+ });
20
+ }
21
+ let storage = NoopProvider_1.default;
22
+ const InstanceSync = {
23
+ shouldBeUsed: true,
24
+ /**
25
+ * @param {Function} onStorageKeyChanged Storage synchronization mechanism keeping all opened tabs in sync
26
+ */
27
+ init: (onStorageKeyChanged, store) => {
28
+ storage = store;
29
+ // This listener will only be triggered by events coming from other tabs
30
+ global.addEventListener('storage', (event) => {
31
+ // Ignore events that don't originate from the SYNC_ONYX logic
32
+ if (event.key !== SYNC_ONYX || !event.newValue) {
33
+ return;
34
+ }
35
+ const onyxKey = event.newValue;
36
+ storage.getItem(onyxKey).then((value) => onStorageKeyChanged(onyxKey, value));
37
+ });
38
+ },
39
+ setItem: raiseStorageSyncEvent,
40
+ removeItem: raiseStorageSyncEvent,
41
+ removeItems: raiseStorageSyncManyKeysEvent,
42
+ mergeItem: raiseStorageSyncEvent,
43
+ clear: (clearImplementation) => {
44
+ let allKeys;
45
+ // The keys must be retrieved before storage is cleared or else the list of keys would be empty
46
+ return storage
47
+ .getAllKeys()
48
+ .then((keys) => {
49
+ allKeys = keys;
50
+ })
51
+ .then(() => clearImplementation())
52
+ .then(() => {
53
+ // Now that storage is cleared, the storage sync event can happen which is a more atomic action
54
+ // for other browser tabs
55
+ raiseStorageSyncManyKeysEvent(allKeys);
56
+ });
57
+ },
58
+ };
59
+ exports.default = InstanceSync;
@@ -1,23 +1,25 @@
1
1
  /// <reference types="jest" />
2
- import type { KeyValuePairList } from '../providers/types';
3
- declare const idbKeyvalMockSpy: {
4
- idbKeyvalSet: jest.Mock<Promise<any>, [key: any, value: any]>;
5
- setItem: jest.Mock<Promise<void | import("react-native-quick-sqlite").QueryResult>, [key: string, value: IDBValidKey]>;
6
- getItem: jest.Mock<Promise<IDBValidKey | null>, [key: string]>;
2
+ declare const StorageMock: {
3
+ init: jest.Mock<void, []>;
4
+ getItem: jest.Mock<Promise<unknown>, [key: any]>;
5
+ multiGet: jest.Mock<Promise<import("../providers/types").KeyValuePairList>, [keys: import("../providers/types").KeyList]>;
6
+ setItem: jest.Mock<Promise<void | import("react-native-quick-sqlite").QueryResult>, [key: any, value: unknown]>;
7
+ multiSet: jest.Mock<Promise<void | import("react-native-quick-sqlite").BatchQueryResult>, [pairs: import("../providers/types").KeyValuePairList]>;
8
+ mergeItem: jest.Mock<Promise<void | import("react-native-quick-sqlite").BatchQueryResult>, [key: any, changes: unknown, modifiedData: unknown]>;
9
+ multiMerge: jest.Mock<Promise<import("react-native-quick-sqlite").BatchQueryResult | IDBValidKey[]>, [pairs: import("../providers/types").KeyValuePairList]>;
7
10
  removeItem: jest.Mock<Promise<void | import("react-native-quick-sqlite").QueryResult>, [key: string]>;
8
11
  removeItems: jest.Mock<Promise<void | import("react-native-quick-sqlite").QueryResult>, [keys: import("../providers/types").KeyList]>;
9
12
  clear: jest.Mock<Promise<void | import("react-native-quick-sqlite").QueryResult>, []>;
10
13
  getAllKeys: jest.Mock<Promise<import("../providers/types").KeyList>, []>;
11
- multiGet: jest.Mock<Promise<KeyValuePairList>, [keys: import("../providers/types").KeyList]>;
12
- multiSet: jest.Mock<Promise<void | import("react-native-quick-sqlite").BatchQueryResult>, [pairs: KeyValuePairList]>;
13
- multiMerge: jest.Mock<Promise<import("react-native-quick-sqlite").BatchQueryResult | IDBValidKey[]>, [pairs: KeyValuePairList]>;
14
- mergeItem: jest.Mock<Promise<void | import("react-native-quick-sqlite").BatchQueryResult>, [key: string, changes: IDBValidKey, modifiedData: IDBValidKey]>;
15
- getStorageMap: jest.Mock<Record<string, IDBValidKey>, []>;
16
- setInitialMockData: jest.Mock<void, [data: any]>;
17
14
  getDatabaseSize: jest.Mock<Promise<{
18
15
  bytesUsed: number;
19
16
  bytesRemaining: number;
20
17
  }>, []>;
21
- setMemoryOnlyKeys: jest.Mock<void, []>;
18
+ keepInstancesSync: jest.Mock<any, any>;
19
+ mockSet: (key: string, value: unknown) => Promise<unknown>;
20
+ getMockStore: jest.Mock<{
21
+ [x: string]: unknown;
22
+ }, []>;
23
+ setMockStore: jest.Mock<void, [data: any]>;
22
24
  };
23
- export default idbKeyvalMockSpy;
25
+ export default StorageMock;
@@ -1,85 +1,47 @@
1
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 utils_1 = __importDefault(require("../../utils"));
7
- let storageMapInternal = {};
8
- const set = jest.fn((key, value) => {
9
- storageMapInternal[key] = value;
10
- return Promise.resolve(value);
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;
11
17
  });
12
- const idbKeyvalMock = {
13
- setItem(key, value) {
14
- return set(key, value);
15
- },
16
- multiSet(pairs) {
17
- const setPromises = pairs.map(([key, value]) => this.setItem(key, value));
18
- return new Promise((resolve) => {
19
- Promise.all(setPromises).then(() => resolve(storageMapInternal));
20
- });
21
- },
22
- getItem(key) {
23
- return Promise.resolve(storageMapInternal[key]);
24
- },
25
- multiGet(keys) {
26
- const getPromises = keys.map((key) => new Promise((resolve) => {
27
- this.getItem(key).then((value) => resolve([key, value]));
28
- }));
29
- return Promise.all(getPromises);
30
- },
31
- multiMerge(pairs) {
32
- pairs.forEach(([key, value]) => {
33
- const existingValue = storageMapInternal[key];
34
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
35
- const newValue = utils_1.default.fastMerge(existingValue, value);
36
- set(key, newValue);
37
- });
38
- return Promise.resolve(storageMapInternal);
39
- },
40
- mergeItem(key, _changes, modifiedData) {
41
- return this.setItem(key, modifiedData);
42
- },
43
- removeItem(key) {
44
- delete storageMapInternal[key];
45
- return Promise.resolve();
46
- },
47
- removeItems(keys) {
48
- keys.forEach((key) => {
49
- delete storageMapInternal[key];
50
- });
51
- return Promise.resolve();
52
- },
53
- clear() {
54
- storageMapInternal = {};
55
- return Promise.resolve();
56
- },
57
- getAllKeys() {
58
- return Promise.resolve(Object.keys(storageMapInternal));
59
- },
60
- getDatabaseSize() {
61
- return Promise.resolve({ bytesRemaining: 0, bytesUsed: 99999 });
62
- },
63
- // eslint-disable-next-line @typescript-eslint/no-empty-function
64
- setMemoryOnlyKeys() { },
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;
65
24
  };
66
- const idbKeyvalMockSpy = {
67
- idbKeyvalSet: set,
68
- setItem: jest.fn(idbKeyvalMock.setItem),
69
- getItem: jest.fn(idbKeyvalMock.getItem),
70
- removeItem: jest.fn(idbKeyvalMock.removeItem),
71
- removeItems: jest.fn(idbKeyvalMock.removeItems),
72
- clear: jest.fn(idbKeyvalMock.clear),
73
- getAllKeys: jest.fn(idbKeyvalMock.getAllKeys),
74
- multiGet: jest.fn(idbKeyvalMock.multiGet),
75
- multiSet: jest.fn(idbKeyvalMock.multiSet),
76
- multiMerge: jest.fn(idbKeyvalMock.multiMerge),
77
- mergeItem: jest.fn(idbKeyvalMock.mergeItem),
78
- getStorageMap: jest.fn(() => storageMapInternal),
79
- setInitialMockData: jest.fn((data) => {
80
- storageMapInternal = data;
81
- }),
82
- getDatabaseSize: jest.fn(idbKeyvalMock.getDatabaseSize),
83
- setMemoryOnlyKeys: jest.fn(idbKeyvalMock.setMemoryOnlyKeys),
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ const MemoryOnlyProvider_1 = __importStar(require("../providers/MemoryOnlyProvider"));
27
+ const init = jest.fn(MemoryOnlyProvider_1.default.init);
28
+ init();
29
+ const StorageMock = {
30
+ init,
31
+ getItem: jest.fn(MemoryOnlyProvider_1.default.getItem),
32
+ multiGet: jest.fn(MemoryOnlyProvider_1.default.multiGet),
33
+ setItem: jest.fn(MemoryOnlyProvider_1.default.setItem),
34
+ multiSet: jest.fn(MemoryOnlyProvider_1.default.multiSet),
35
+ mergeItem: jest.fn(MemoryOnlyProvider_1.default.mergeItem),
36
+ multiMerge: jest.fn(MemoryOnlyProvider_1.default.multiMerge),
37
+ removeItem: jest.fn(MemoryOnlyProvider_1.default.removeItem),
38
+ removeItems: jest.fn(MemoryOnlyProvider_1.default.removeItems),
39
+ clear: jest.fn(MemoryOnlyProvider_1.default.clear),
40
+ getAllKeys: jest.fn(MemoryOnlyProvider_1.default.getAllKeys),
41
+ getDatabaseSize: jest.fn(MemoryOnlyProvider_1.default.getDatabaseSize),
42
+ keepInstancesSync: jest.fn(),
43
+ mockSet: MemoryOnlyProvider_1.mockSet,
44
+ getMockStore: jest.fn(() => MemoryOnlyProvider_1.mockStore),
45
+ setMockStore: jest.fn((data) => (0, MemoryOnlyProvider_1.setMockStore)(data)),
84
46
  };
85
- exports.default = idbKeyvalMockSpy;
47
+ exports.default = StorageMock;
@@ -1,2 +1,6 @@
1
- import WebStorage from './WebStorage';
2
- export default WebStorage;
1
+ import type StorageProvider from './providers/types';
2
+ type Storage = {
3
+ getStorageProvider: () => StorageProvider;
4
+ } & Omit<StorageProvider, 'name'>;
5
+ declare const Storage: Storage;
6
+ export default Storage;
@@ -1,7 +1,175 @@
1
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
+ };
2
25
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
27
  };
5
28
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const WebStorage_1 = __importDefault(require("./WebStorage"));
7
- exports.default = WebStorage_1.default;
29
+ const Logger = __importStar(require("../Logger"));
30
+ const platforms_1 = __importDefault(require("./platforms"));
31
+ const InstanceSync_1 = __importDefault(require("./InstanceSync"));
32
+ const MemoryOnlyProvider_1 = __importDefault(require("./providers/MemoryOnlyProvider"));
33
+ let provider = platforms_1.default;
34
+ let shouldKeepInstancesSync = false;
35
+ let finishInitalization;
36
+ const initPromise = new Promise((resolve) => {
37
+ finishInitalization = resolve;
38
+ });
39
+ /**
40
+ * Degrade performance by removing the storage provider and only using cache
41
+ */
42
+ function degradePerformance(error) {
43
+ Logger.logAlert(`Error while using ${provider.name}. Falling back to only using cache and dropping storage.`);
44
+ console.error(error);
45
+ provider = MemoryOnlyProvider_1.default;
46
+ }
47
+ /**
48
+ * Runs a piece of code and degrades performance if certain errors are thrown
49
+ */
50
+ function tryOrDegradePerformance(fn, waitForInitialization = true) {
51
+ return new Promise((resolve, reject) => {
52
+ const promise = waitForInitialization ? initPromise : Promise.resolve();
53
+ promise.then(() => {
54
+ try {
55
+ resolve(fn());
56
+ }
57
+ catch (error) {
58
+ // Test for known critical errors that the storage provider throws, e.g. when storage is full
59
+ if (error instanceof Error) {
60
+ // IndexedDB error when storage is full (https://github.com/Expensify/App/issues/29403)
61
+ if (error.message.includes('Internal error opening backing store for indexedDB.open')) {
62
+ degradePerformance(error);
63
+ }
64
+ // catch the error if DB connection can not be established/DB can not be created
65
+ if (error.message.includes('IDBKeyVal store could not be created')) {
66
+ degradePerformance(error);
67
+ }
68
+ }
69
+ reject(error);
70
+ }
71
+ });
72
+ });
73
+ }
74
+ const Storage = {
75
+ /**
76
+ * Returns the storage provider currently in use
77
+ */
78
+ getStorageProvider() {
79
+ return provider;
80
+ },
81
+ /**
82
+ * Initializes all providers in the list of storage providers
83
+ * and enables fallback providers if necessary
84
+ */
85
+ init() {
86
+ tryOrDegradePerformance(provider.init, false).finally(() => {
87
+ finishInitalization();
88
+ });
89
+ },
90
+ /**
91
+ * Get the value of a given key or return `null` if it's not available
92
+ */
93
+ getItem: (key) => tryOrDegradePerformance(() => provider.getItem(key)),
94
+ /**
95
+ * Get multiple key-value pairs for the give array of keys in a batch
96
+ */
97
+ multiGet: (keys) => tryOrDegradePerformance(() => provider.multiGet(keys)),
98
+ /**
99
+ * Sets the value for a given key. The only requirement is that the value should be serializable to JSON string
100
+ */
101
+ setItem: (key, value) => tryOrDegradePerformance(() => {
102
+ const promise = provider.setItem(key, value);
103
+ if (shouldKeepInstancesSync) {
104
+ return promise.then(() => InstanceSync_1.default.setItem(key));
105
+ }
106
+ return promise;
107
+ }),
108
+ /**
109
+ * Stores multiple key-value pairs in a batch
110
+ */
111
+ multiSet: (pairs) => tryOrDegradePerformance(() => provider.multiSet(pairs)),
112
+ /**
113
+ * Merging an existing value with a new one
114
+ */
115
+ mergeItem: (key, changes, modifiedData) => tryOrDegradePerformance(() => {
116
+ const promise = provider.mergeItem(key, changes, modifiedData);
117
+ if (shouldKeepInstancesSync) {
118
+ return promise.then(() => InstanceSync_1.default.mergeItem(key));
119
+ }
120
+ return promise;
121
+ }),
122
+ /**
123
+ * Multiple merging of existing and new values in a batch
124
+ * This function also removes all nested null values from an object.
125
+ */
126
+ multiMerge: (pairs) => tryOrDegradePerformance(() => provider.multiMerge(pairs)),
127
+ /**
128
+ * Removes given key and its value
129
+ */
130
+ removeItem: (key) => tryOrDegradePerformance(() => {
131
+ const promise = provider.removeItem(key);
132
+ if (shouldKeepInstancesSync) {
133
+ return promise.then(() => InstanceSync_1.default.removeItem(key));
134
+ }
135
+ return promise;
136
+ }),
137
+ /**
138
+ * Remove given keys and their values
139
+ */
140
+ removeItems: (keys) => tryOrDegradePerformance(() => {
141
+ const promise = provider.removeItems(keys);
142
+ if (shouldKeepInstancesSync) {
143
+ return promise.then(() => InstanceSync_1.default.removeItems(keys));
144
+ }
145
+ return promise;
146
+ }),
147
+ /**
148
+ * Clears everything
149
+ */
150
+ clear: () => tryOrDegradePerformance(() => {
151
+ if (shouldKeepInstancesSync) {
152
+ return InstanceSync_1.default.clear(() => provider.clear());
153
+ }
154
+ return provider.clear();
155
+ }),
156
+ /**
157
+ * Returns all available keys
158
+ */
159
+ getAllKeys: () => tryOrDegradePerformance(() => provider.getAllKeys()),
160
+ /**
161
+ * Gets the total bytes of the store
162
+ */
163
+ getDatabaseSize: () => tryOrDegradePerformance(() => provider.getDatabaseSize()),
164
+ /**
165
+ * @param onStorageKeyChanged - Storage synchronization mechanism keeping all opened tabs in sync (web only)
166
+ */
167
+ keepInstancesSync(onStorageKeyChanged) {
168
+ // If InstanceSync shouldn't be used, it means we're on a native platform and we don't need to keep instances in sync
169
+ if (!InstanceSync_1.default.shouldBeUsed)
170
+ return;
171
+ shouldKeepInstancesSync = true;
172
+ InstanceSync_1.default.init(onStorageKeyChanged, this);
173
+ },
174
+ };
175
+ exports.default = Storage;
@@ -0,0 +1,2 @@
1
+ import WebStorage from '../providers/IDBKeyValProvider';
2
+ export default WebStorage;
@@ -3,5 +3,5 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const SQLiteStorage_1 = __importDefault(require("./providers/SQLiteStorage"));
7
- exports.default = SQLiteStorage_1.default;
6
+ const IDBKeyValProvider_1 = __importDefault(require("../providers/IDBKeyValProvider"));
7
+ exports.default = IDBKeyValProvider_1.default;
@@ -0,0 +1,2 @@
1
+ import NativeStorage from '../providers/SQLiteProvider';
2
+ export default NativeStorage;
@@ -3,5 +3,5 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const NativeStorage_1 = __importDefault(require("./NativeStorage"));
7
- exports.default = NativeStorage_1.default;
6
+ const SQLiteProvider_1 = __importDefault(require("../providers/SQLiteProvider"));
7
+ exports.default = SQLiteProvider_1.default;
@@ -7,24 +7,30 @@ const idb_keyval_1 = require("idb-keyval");
7
7
  const utils_1 = __importDefault(require("../../utils"));
8
8
  // We don't want to initialize the store while the JS bundle loads as idb-keyval will try to use global.indexedDB
9
9
  // which might not be available in certain environments that load the bundle (e.g. electron main process).
10
- let customStoreInstance;
11
- function getCustomStore() {
12
- if (!customStoreInstance) {
13
- customStoreInstance = (0, idb_keyval_1.createStore)('OnyxDB', 'keyvaluepairs');
14
- }
15
- return customStoreInstance;
16
- }
10
+ let idbKeyValStore;
17
11
  const provider = {
18
- setItem: (key, value) => (0, idb_keyval_1.set)(key, value, getCustomStore()),
19
- multiGet: (keysParam) => (0, idb_keyval_1.getMany)(keysParam, getCustomStore()).then((values) => values.map((value, index) => [keysParam[index], value])),
20
- multiMerge: (pairs) => getCustomStore()('readwrite', (store) => {
12
+ /**
13
+ * The name of the provider that can be printed to the logs
14
+ */
15
+ name: 'IDBKeyValProvider',
16
+ /**
17
+ * Initializes the storage provider
18
+ */
19
+ init() {
20
+ const newIdbKeyValStore = (0, idb_keyval_1.createStore)('OnyxDB', 'keyvaluepairs');
21
+ if (newIdbKeyValStore == null)
22
+ throw Error('IDBKeyVal store could not be created');
23
+ idbKeyValStore = newIdbKeyValStore;
24
+ },
25
+ setItem: (key, value) => (0, idb_keyval_1.set)(key, value, idbKeyValStore),
26
+ multiGet: (keysParam) => (0, idb_keyval_1.getMany)(keysParam, idbKeyValStore).then((values) => values.map((value, index) => [keysParam[index], value])),
27
+ multiMerge: (pairs) => idbKeyValStore('readwrite', (store) => {
21
28
  // Note: we are using the manual store transaction here, to fit the read and update
22
29
  // of the items in one transaction to achieve best performance.
23
30
  const getValues = Promise.all(pairs.map(([key]) => (0, idb_keyval_1.promisifyRequest)(store.get(key))));
24
31
  return getValues.then((values) => {
25
32
  const upsertMany = pairs.map(([key, value], index) => {
26
33
  const prev = values[index];
27
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
34
  const newValue = utils_1.default.fastMerge(prev, value);
29
35
  return (0, idb_keyval_1.promisifyRequest)(store.put(newValue, key));
30
36
  });
@@ -35,16 +41,14 @@ const provider = {
35
41
  // Since Onyx also merged the existing value with the changes, we can just set the value directly
36
42
  return provider.setItem(key, modifiedData);
37
43
  },
38
- multiSet: (pairs) => (0, idb_keyval_1.setMany)(pairs, getCustomStore()),
39
- clear: () => (0, idb_keyval_1.clear)(getCustomStore()),
40
- // eslint-disable-next-line @typescript-eslint/no-empty-function
41
- setMemoryOnlyKeys: () => { },
42
- getAllKeys: () => (0, idb_keyval_1.keys)(getCustomStore()),
43
- getItem: (key) => (0, idb_keyval_1.get)(key, getCustomStore())
44
+ multiSet: (pairs) => (0, idb_keyval_1.setMany)(pairs, idbKeyValStore),
45
+ clear: () => (0, idb_keyval_1.clear)(idbKeyValStore),
46
+ getAllKeys: () => (0, idb_keyval_1.keys)(idbKeyValStore),
47
+ getItem: (key) => (0, idb_keyval_1.get)(key, idbKeyValStore)
44
48
  // idb-keyval returns undefined for missing items, but this needs to return null so that idb-keyval does the same thing as SQLiteStorage.
45
49
  .then((val) => (val === undefined ? null : val)),
46
- removeItem: (key) => (0, idb_keyval_1.del)(key, getCustomStore()),
47
- removeItems: (keysParam) => (0, idb_keyval_1.delMany)(keysParam, getCustomStore()),
50
+ removeItem: (key) => (0, idb_keyval_1.del)(key, idbKeyValStore),
51
+ removeItems: (keysParam) => (0, idb_keyval_1.delMany)(keysParam, idbKeyValStore),
48
52
  getDatabaseSize() {
49
53
  if (!window.navigator || !window.navigator.storage) {
50
54
  throw new Error('StorageManager browser API unavailable');
@@ -0,0 +1,9 @@
1
+ import type StorageProvider from './types';
2
+ import type { OnyxKey, OnyxValue } from '../../types';
3
+ type Store = Record<OnyxKey, OnyxValue<OnyxKey>>;
4
+ declare let store: Store;
5
+ declare const set: (key: OnyxKey, value: OnyxValue<OnyxKey>) => Promise<unknown>;
6
+ declare const provider: StorageProvider;
7
+ declare const setMockStore: (data: Store) => void;
8
+ export default provider;
9
+ export { store as mockStore, set as mockSet, setMockStore };