react-native-onyx 3.0.51 → 3.0.53
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.js +7 -2
- package/dist/OnyxUtils.js +59 -9
- package/dist/storage/__mocks__/index.d.ts +1 -0
- package/dist/storage/__mocks__/index.js +1 -0
- package/dist/storage/index.js +5 -0
- package/dist/storage/providers/IDBKeyValProvider/index.js +6 -0
- package/dist/storage/providers/MemoryOnlyProvider.js +6 -0
- package/dist/storage/providers/NoopProvider.js +6 -0
- package/dist/storage/providers/SQLiteProvider.js +10 -0
- package/dist/storage/providers/types.d.ts +5 -0
- package/dist/types.d.ts +3 -2
- package/package.json +1 -1
package/dist/Onyx.js
CHANGED
|
@@ -78,8 +78,13 @@ function init({ keys = {}, initialKeyStates = {}, evictableKeys = [], maxCachedK
|
|
|
78
78
|
OnyxCache_1.default.setRecentKeysLimit(maxCachedKeysCount);
|
|
79
79
|
}
|
|
80
80
|
OnyxUtils_1.default.initStoreValues(keys, initialKeyStates, evictableKeys);
|
|
81
|
-
// Initialize all of our keys with data provided then give green light to any pending connections
|
|
82
|
-
|
|
81
|
+
// Initialize all of our keys with data provided then give green light to any pending connections.
|
|
82
|
+
// addEvictableKeysToRecentlyAccessedList must run after initializeWithDefaultKeyStates because
|
|
83
|
+
// eager cache loading populates the key index (cache.setAllKeys) inside initializeWithDefaultKeyStates,
|
|
84
|
+
// and the evictable keys list depends on that index being populated.
|
|
85
|
+
OnyxUtils_1.default.initializeWithDefaultKeyStates()
|
|
86
|
+
.then(() => OnyxCache_1.default.addEvictableKeysToRecentlyAccessedList(OnyxUtils_1.default.isCollectionKey, OnyxUtils_1.default.getAllKeys))
|
|
87
|
+
.then(OnyxUtils_1.default.getDeferredInitTask().resolve);
|
|
83
88
|
}
|
|
84
89
|
/**
|
|
85
90
|
* Connects to an Onyx key given the options passed and listens to its changes.
|
package/dist/OnyxUtils.js
CHANGED
|
@@ -91,7 +91,9 @@ let snapshotKey = null;
|
|
|
91
91
|
let lastSubscriptionID = 0;
|
|
92
92
|
// Connections can be made before `Onyx.init`. They would wait for this task before resolving
|
|
93
93
|
const deferredInitTask = (0, createDeferredTask_1.default)();
|
|
94
|
-
//
|
|
94
|
+
// Collection member IDs that Onyx should silently ignore across all operations — reads, writes, cache, and subscriber
|
|
95
|
+
// notifications. This is used to filter out keys formed from invalid/default IDs (e.g. "-1", "0",
|
|
96
|
+
// "undefined", "null", "NaN") that can appear when an ID variable is accidentally coerced to string.
|
|
95
97
|
let skippableCollectionMemberIDs = new Set();
|
|
96
98
|
// Holds a set of keys that should always be merged into snapshot entries.
|
|
97
99
|
let snapshotMergeKeys = new Set();
|
|
@@ -906,17 +908,65 @@ function mergeInternal(mode, changes, existingValue) {
|
|
|
906
908
|
* Merge user provided default key value pairs.
|
|
907
909
|
*/
|
|
908
910
|
function initializeWithDefaultKeyStates() {
|
|
909
|
-
//
|
|
910
|
-
//
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
911
|
+
// Eagerly load the entire database into cache in a single batch read.
|
|
912
|
+
// This is faster than lazy-loading individual keys because:
|
|
913
|
+
// 1. One DB transaction instead of hundreds
|
|
914
|
+
// 2. All subsequent reads are synchronous cache hits
|
|
915
|
+
return storage_1.default.getAll()
|
|
916
|
+
.then((pairs) => {
|
|
917
|
+
const allDataFromStorage = {};
|
|
918
|
+
for (const [key, value] of pairs) {
|
|
919
|
+
// RAM-only keys should not be cached from storage as they may have stale persisted data
|
|
920
|
+
// from before the key was migrated to RAM-only.
|
|
921
|
+
if (isRamOnlyKey(key)) {
|
|
922
|
+
continue;
|
|
923
|
+
}
|
|
924
|
+
// Skip collection members that are marked as skippable
|
|
925
|
+
if (skippableCollectionMemberIDs.size && getCollectionKey(key)) {
|
|
926
|
+
const [, collectionMemberID] = splitCollectionMemberKey(key);
|
|
927
|
+
if (skippableCollectionMemberIDs.has(collectionMemberID)) {
|
|
928
|
+
continue;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
allDataFromStorage[key] = value;
|
|
932
|
+
}
|
|
933
|
+
// Load all storage data into cache silently (no subscriber notifications)
|
|
934
|
+
OnyxCache_1.default.setAllKeys(Object.keys(allDataFromStorage));
|
|
935
|
+
OnyxCache_1.default.merge(allDataFromStorage);
|
|
936
|
+
// For keys that have a developer-defined default (via `initialKeyStates`), merge the
|
|
937
|
+
// persisted value with the default so new properties added in code updates are applied
|
|
938
|
+
// without wiping user data that already exists in storage.
|
|
939
|
+
const defaultKeysFromStorage = Object.keys(defaultKeyStates).reduce((obj, key) => {
|
|
940
|
+
if (key in allDataFromStorage) {
|
|
941
|
+
// eslint-disable-next-line no-param-reassign
|
|
942
|
+
obj[key] = allDataFromStorage[key];
|
|
943
|
+
}
|
|
944
|
+
return obj;
|
|
945
|
+
}, {});
|
|
946
|
+
const merged = utils_1.default.fastMerge(defaultKeysFromStorage, defaultKeyStates, {
|
|
915
947
|
shouldRemoveNestedNulls: true,
|
|
916
948
|
}).result;
|
|
917
949
|
OnyxCache_1.default.merge(merged !== null && merged !== void 0 ? merged : {});
|
|
918
|
-
|
|
950
|
+
// Notify subscribers about default key states so that any subscriber that connected
|
|
951
|
+
// before init (e.g. during module load) receives the merged default values immediately
|
|
952
|
+
for (const [key, value] of Object.entries(merged !== null && merged !== void 0 ? merged : {})) {
|
|
919
953
|
keyChanged(key, value);
|
|
954
|
+
}
|
|
955
|
+
})
|
|
956
|
+
.catch((error) => {
|
|
957
|
+
Logger.logAlert(`Failed to load data from storage during init. The app will boot with default key states only. Error: ${error}`);
|
|
958
|
+
// Populate the key index so getAllKeys() returns correct results for default keys.
|
|
959
|
+
// Without this, subscribers that check getAllKeys() would see an empty set even
|
|
960
|
+
// though we have default values in cache.
|
|
961
|
+
OnyxCache_1.default.setAllKeys(Object.keys(defaultKeyStates));
|
|
962
|
+
// Boot with defaults so the app renders instead of deadlocking.
|
|
963
|
+
// Users will get a fresh-install experience but the app won't be bricked.
|
|
964
|
+
OnyxCache_1.default.merge(defaultKeyStates);
|
|
965
|
+
// Notify subscribers about default key states so that any subscriber that connected
|
|
966
|
+
// before init (e.g. during module load) receives the merged default values immediately
|
|
967
|
+
for (const [key, value] of Object.entries(defaultKeyStates)) {
|
|
968
|
+
keyChanged(key, value);
|
|
969
|
+
}
|
|
920
970
|
});
|
|
921
971
|
}
|
|
922
972
|
/**
|
|
@@ -1041,7 +1091,7 @@ function unsubscribeFromKey(subscriptionID) {
|
|
|
1041
1091
|
if (!callbackToStateMapping[subscriptionID]) {
|
|
1042
1092
|
return;
|
|
1043
1093
|
}
|
|
1044
|
-
deleteKeyBySubscriptions(
|
|
1094
|
+
deleteKeyBySubscriptions(subscriptionID);
|
|
1045
1095
|
delete callbackToStateMapping[subscriptionID];
|
|
1046
1096
|
}
|
|
1047
1097
|
function updateSnapshots(data, mergeFn) {
|
|
@@ -10,6 +10,7 @@ declare const StorageMock: {
|
|
|
10
10
|
removeItems: jest.Mock<Promise<void>, [keys: import("../providers/types").StorageKeyList], any>;
|
|
11
11
|
clear: jest.Mock<Promise<void>, [], any>;
|
|
12
12
|
getAllKeys: jest.Mock<Promise<import("../providers/types").StorageKeyList>, [], any>;
|
|
13
|
+
getAll: jest.Mock<Promise<import("../providers/types").StorageKeyValuePair[]>, [], any>;
|
|
13
14
|
getDatabaseSize: jest.Mock<Promise<{
|
|
14
15
|
bytesUsed: number;
|
|
15
16
|
bytesRemaining: number;
|
|
@@ -48,6 +48,7 @@ const StorageMock = {
|
|
|
48
48
|
removeItems: jest.fn(MemoryOnlyProvider_1.default.removeItems),
|
|
49
49
|
clear: jest.fn(MemoryOnlyProvider_1.default.clear),
|
|
50
50
|
getAllKeys: jest.fn(MemoryOnlyProvider_1.default.getAllKeys),
|
|
51
|
+
getAll: jest.fn(MemoryOnlyProvider_1.default.getAll),
|
|
51
52
|
getDatabaseSize: jest.fn(MemoryOnlyProvider_1.default.getDatabaseSize),
|
|
52
53
|
keepInstancesSync: jest.fn(),
|
|
53
54
|
getMockStore: jest.fn(() => MemoryOnlyProvider_1.mockStore),
|
package/dist/storage/index.js
CHANGED
|
@@ -181,6 +181,10 @@ const storage = {
|
|
|
181
181
|
* Returns all available keys
|
|
182
182
|
*/
|
|
183
183
|
getAllKeys: () => tryOrDegradePerformance(() => provider.getAllKeys()),
|
|
184
|
+
/**
|
|
185
|
+
* Returns all key-value pairs from storage in a single batch operation
|
|
186
|
+
*/
|
|
187
|
+
getAll: () => tryOrDegradePerformance(() => provider.getAll()),
|
|
184
188
|
/**
|
|
185
189
|
* Gets the total bytes of the store
|
|
186
190
|
*/
|
|
@@ -211,5 +215,6 @@ GlobalSettings.addGlobalSettingsChangeListener(({ enablePerformanceMetrics }) =>
|
|
|
211
215
|
storage.removeItems = (0, metrics_1.default)(storage.removeItems, 'Storage.removeItems');
|
|
212
216
|
storage.clear = (0, metrics_1.default)(storage.clear, 'Storage.clear');
|
|
213
217
|
storage.getAllKeys = (0, metrics_1.default)(storage.getAllKeys, 'Storage.getAllKeys');
|
|
218
|
+
storage.getAll = (0, metrics_1.default)(storage.getAll, 'Storage.getAll');
|
|
214
219
|
});
|
|
215
220
|
exports.default = storage;
|
|
@@ -131,6 +131,12 @@ const provider = {
|
|
|
131
131
|
}
|
|
132
132
|
return IDB.keys(provider.store);
|
|
133
133
|
},
|
|
134
|
+
getAll() {
|
|
135
|
+
if (!provider.store) {
|
|
136
|
+
throw new Error('Store not initialized!');
|
|
137
|
+
}
|
|
138
|
+
return IDB.entries(provider.store);
|
|
139
|
+
},
|
|
134
140
|
getItem(key) {
|
|
135
141
|
if (!provider.store) {
|
|
136
142
|
throw new Error('Store not initialized!');
|
|
@@ -111,6 +111,12 @@ const provider = {
|
|
|
111
111
|
getAllKeys() {
|
|
112
112
|
return Promise.resolve(underscore_1.default.keys(provider.store));
|
|
113
113
|
},
|
|
114
|
+
/**
|
|
115
|
+
* Returns all key-value pairs from memory
|
|
116
|
+
*/
|
|
117
|
+
getAll() {
|
|
118
|
+
return Promise.resolve(Object.entries(provider.store));
|
|
119
|
+
},
|
|
114
120
|
/**
|
|
115
121
|
* Gets the total bytes of the store.
|
|
116
122
|
* `bytesRemaining` will always be `Number.POSITIVE_INFINITY` since we don't have a hard limit on memory.
|
|
@@ -73,6 +73,12 @@ const provider = {
|
|
|
73
73
|
getAllKeys() {
|
|
74
74
|
return Promise.resolve([]);
|
|
75
75
|
},
|
|
76
|
+
/**
|
|
77
|
+
* Returns all key-value pairs from storage
|
|
78
|
+
*/
|
|
79
|
+
getAll() {
|
|
80
|
+
return Promise.resolve([]);
|
|
81
|
+
},
|
|
76
82
|
/**
|
|
77
83
|
* Gets the total bytes of the store.
|
|
78
84
|
* `bytesRemaining` will always be `Number.POSITIVE_INFINITY` since we don't have a hard limit on memory.
|
|
@@ -147,6 +147,16 @@ const provider = {
|
|
|
147
147
|
return (result !== null && result !== void 0 ? result : []);
|
|
148
148
|
});
|
|
149
149
|
},
|
|
150
|
+
getAll() {
|
|
151
|
+
if (!provider.store) {
|
|
152
|
+
throw new Error('Store is not initialized!');
|
|
153
|
+
}
|
|
154
|
+
return provider.store.executeAsync('SELECT record_key, valueJSON FROM keyvaluepairs;').then(({ rows }) => {
|
|
155
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
156
|
+
const result = rows === null || rows === void 0 ? void 0 : rows._array.map((row) => [row.record_key, JSON.parse(row.valueJSON)]);
|
|
157
|
+
return (result !== null && result !== void 0 ? result : []);
|
|
158
|
+
});
|
|
159
|
+
},
|
|
150
160
|
removeItem(key) {
|
|
151
161
|
if (!provider.store) {
|
|
152
162
|
throw new Error('Store is not initialized!');
|
|
@@ -46,6 +46,11 @@ type StorageProvider<TStore> = {
|
|
|
46
46
|
* Returns all keys available in storage
|
|
47
47
|
*/
|
|
48
48
|
getAllKeys: () => Promise<StorageKeyList>;
|
|
49
|
+
/**
|
|
50
|
+
* Returns all key-value pairs from storage in a single batch operation.
|
|
51
|
+
* More efficient than getAllKeys + multiGet for loading the entire database.
|
|
52
|
+
*/
|
|
53
|
+
getAll: () => Promise<StorageKeyValuePair[]>;
|
|
49
54
|
/**
|
|
50
55
|
* Removes given key and its value from storage
|
|
51
56
|
*/
|
package/dist/types.d.ts
CHANGED
|
@@ -360,8 +360,9 @@ type InitOptions = {
|
|
|
360
360
|
*/
|
|
361
361
|
enableDevTools?: boolean;
|
|
362
362
|
/**
|
|
363
|
-
* Array of collection member IDs
|
|
364
|
-
*
|
|
363
|
+
* Array of collection member IDs that Onyx should silently ignore across all operations.
|
|
364
|
+
* This prevents keys formed from invalid or default IDs (e.g. "-1", "0", "undefined") from
|
|
365
|
+
* polluting cache or triggering subscriber notifications.
|
|
365
366
|
*/
|
|
366
367
|
skippableCollectionMemberIDs?: string[];
|
|
367
368
|
/**
|