react-native-onyx 3.0.60 → 3.0.62
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 +8 -11
- package/dist/OnyxMerge/index.js +2 -3
- package/dist/OnyxMerge/index.native.js +2 -3
- package/dist/OnyxMerge/types.d.ts +0 -1
- package/dist/OnyxUtils.d.ts +2 -17
- package/dist/OnyxUtils.js +93 -110
- package/dist/storage/providers/SQLiteProvider.js +0 -6
- package/package.json +5 -5
package/dist/Onyx.js
CHANGED
|
@@ -246,9 +246,8 @@ function merge(key, changes) {
|
|
|
246
246
|
OnyxUtils_1.default.logKeyRemoved(OnyxUtils_1.default.METHOD.MERGE, key);
|
|
247
247
|
return Promise.resolve();
|
|
248
248
|
}
|
|
249
|
-
return OnyxMerge_1.default.applyMerge(key, existingValue, validChanges).then(({ mergedValue
|
|
249
|
+
return OnyxMerge_1.default.applyMerge(key, existingValue, validChanges).then(({ mergedValue }) => {
|
|
250
250
|
OnyxUtils_1.default.sendActionToDevTools(OnyxUtils_1.default.METHOD.MERGE, key, changes, mergedValue);
|
|
251
|
-
return updatePromise;
|
|
252
251
|
});
|
|
253
252
|
}
|
|
254
253
|
catch (error) {
|
|
@@ -347,14 +346,6 @@ function clear(keysToPreserve = []) {
|
|
|
347
346
|
// If it isn't preserved and doesn't have a default, we'll remove it
|
|
348
347
|
keysToBeClearedFromStorage.push(key);
|
|
349
348
|
}
|
|
350
|
-
const updatePromises = [];
|
|
351
|
-
// Notify the subscribers for each key/value group so they can receive the new values
|
|
352
|
-
for (const [key, value] of Object.entries(keyValuesToResetIndividually)) {
|
|
353
|
-
updatePromises.push(OnyxUtils_1.default.scheduleSubscriberUpdate(key, value));
|
|
354
|
-
}
|
|
355
|
-
for (const [key, value] of Object.entries(keyValuesToResetAsCollection)) {
|
|
356
|
-
updatePromises.push(OnyxUtils_1.default.scheduleNotifyCollectionSubscribers(key, value.newValues, value.oldValues));
|
|
357
|
-
}
|
|
358
349
|
// Exclude RAM-only keys to prevent them from being saved to storage
|
|
359
350
|
const defaultKeyValuePairs = Object.entries(Object.keys(defaultKeyStates)
|
|
360
351
|
.filter((key) => !keysToPreserve.some((preserveKey) => OnyxKeys_1.default.isKeyMatch(preserveKey, key)) && !OnyxKeys_1.default.isRamOnlyKey(key))
|
|
@@ -371,7 +362,13 @@ function clear(keysToPreserve = []) {
|
|
|
371
362
|
.then(() => storage_1.default.multiSet(defaultKeyValuePairs))
|
|
372
363
|
.then(() => {
|
|
373
364
|
DevTools_1.default.clearState(keysToPreserve);
|
|
374
|
-
|
|
365
|
+
// Notify the subscribers for each key/value group so they can receive the new values
|
|
366
|
+
for (const [key, value] of Object.entries(keyValuesToResetIndividually)) {
|
|
367
|
+
OnyxUtils_1.default.keyChanged(key, value);
|
|
368
|
+
}
|
|
369
|
+
for (const [key, value] of Object.entries(keyValuesToResetAsCollection)) {
|
|
370
|
+
OnyxUtils_1.default.keysChanged(key, value.newValues, value.oldValues);
|
|
371
|
+
}
|
|
375
372
|
});
|
|
376
373
|
})
|
|
377
374
|
.then(() => undefined);
|
package/dist/OnyxMerge/index.js
CHANGED
|
@@ -14,17 +14,16 @@ const applyMerge = (key, existingValue, validChanges) => {
|
|
|
14
14
|
// Logging properties only since values could be sensitive things we don't want to log.
|
|
15
15
|
OnyxUtils_1.default.logKeyChanged(OnyxUtils_1.default.METHOD.MERGE, key, mergedValue, hasChanged);
|
|
16
16
|
// This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
|
|
17
|
-
|
|
17
|
+
OnyxUtils_1.default.broadcastUpdate(key, mergedValue, hasChanged);
|
|
18
18
|
const shouldSkipStorageOperations = !hasChanged || OnyxKeys_1.default.isRamOnlyKey(key);
|
|
19
19
|
// If the value has not changed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
|
|
20
20
|
// If the key is marked as RAM-only, it should not be saved nor updated in the storage.
|
|
21
21
|
if (shouldSkipStorageOperations) {
|
|
22
|
-
return Promise.resolve({ mergedValue
|
|
22
|
+
return Promise.resolve({ mergedValue });
|
|
23
23
|
}
|
|
24
24
|
// For web platforms we use `setItem` since the object was already merged with its changes before.
|
|
25
25
|
return storage_1.default.setItem(key, mergedValue).then(() => ({
|
|
26
26
|
mergedValue,
|
|
27
|
-
updatePromise,
|
|
28
27
|
}));
|
|
29
28
|
};
|
|
30
29
|
const OnyxMerge = {
|
|
@@ -20,18 +20,17 @@ const applyMerge = (key, existingValue, validChanges) => {
|
|
|
20
20
|
// Logging properties only since values could be sensitive things we don't want to log.
|
|
21
21
|
OnyxUtils_1.default.logKeyChanged(OnyxUtils_1.default.METHOD.MERGE, key, mergedValue, hasChanged);
|
|
22
22
|
// This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
|
|
23
|
-
|
|
23
|
+
OnyxUtils_1.default.broadcastUpdate(key, mergedValue, hasChanged);
|
|
24
24
|
const shouldSkipStorageOperations = !hasChanged || OnyxKeys_1.default.isRamOnlyKey(key);
|
|
25
25
|
// If the value has not changed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
|
|
26
26
|
// If the key is marked as RAM-only, it should not be saved nor updated in the storage.
|
|
27
27
|
if (shouldSkipStorageOperations) {
|
|
28
|
-
return Promise.resolve({ mergedValue
|
|
28
|
+
return Promise.resolve({ mergedValue });
|
|
29
29
|
}
|
|
30
30
|
// For native platforms we use `mergeItem` that will take advantage of JSON_PATCH and JSON_REPLACE SQL operations to
|
|
31
31
|
// merge the object in a performant way.
|
|
32
32
|
return storage_1.default.mergeItem(key, batchedChanges, replaceNullPatches).then(() => ({
|
|
33
33
|
mergedValue,
|
|
34
|
-
updatePromise,
|
|
35
34
|
}));
|
|
36
35
|
};
|
|
37
36
|
const OnyxMerge = {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { OnyxInput, OnyxKey } from '../types';
|
|
2
2
|
type ApplyMergeResult<TValue> = {
|
|
3
3
|
mergedValue: TValue;
|
|
4
|
-
updatePromise: Promise<void>;
|
|
5
4
|
};
|
|
6
5
|
type ApplyMerge = <TKey extends OnyxKey, TValue extends OnyxInput<OnyxKey> | undefined, TChange extends OnyxInput<OnyxKey> | null>(key: TKey, existingValue: TValue, validChanges: TChange[]) => Promise<ApplyMergeResult<TChange>>;
|
|
7
6
|
export type { ApplyMerge, ApplyMergeResult };
|
package/dist/OnyxUtils.d.ts
CHANGED
|
@@ -126,7 +126,7 @@ declare function keyChanged<TKey extends OnyxKey>(key: TKey, value: OnyxValue<TK
|
|
|
126
126
|
/**
|
|
127
127
|
* Sends the data obtained from the keys to the connection.
|
|
128
128
|
*/
|
|
129
|
-
declare function sendDataToConnection<TKey extends OnyxKey>(mapping: CallbackToStateMapping<TKey>,
|
|
129
|
+
declare function sendDataToConnection<TKey extends OnyxKey>(mapping: CallbackToStateMapping<TKey>, matchedKey: TKey | undefined): void;
|
|
130
130
|
/**
|
|
131
131
|
* We check to see if this key is flagged as safe for eviction and add it to the recentlyAccessedKeys list so that when we
|
|
132
132
|
* run out of storage the least recently accessed key can be removed.
|
|
@@ -136,19 +136,6 @@ declare function addKeyToRecentlyAccessedIfNeeded<TKey extends OnyxKey>(key: TKe
|
|
|
136
136
|
* Gets the data for a given an array of matching keys, combines them into an object, and sends the result back to the subscriber.
|
|
137
137
|
*/
|
|
138
138
|
declare function getCollectionDataAndSendAsObject<TKey extends OnyxKey>(matchingKeys: CollectionKeyBase[], mapping: CallbackToStateMapping<TKey>): void;
|
|
139
|
-
/**
|
|
140
|
-
* Schedules an update that will be appended to the macro task queue (so it doesn't update the subscribers immediately).
|
|
141
|
-
*
|
|
142
|
-
* @example
|
|
143
|
-
* scheduleSubscriberUpdate(key, value, subscriber => subscriber.initWithStoredValues === false)
|
|
144
|
-
*/
|
|
145
|
-
declare function scheduleSubscriberUpdate<TKey extends OnyxKey>(key: TKey, value: OnyxValue<TKey>, canUpdateSubscriber?: (subscriber?: CallbackToStateMapping<OnyxKey>) => boolean, isProcessingCollectionUpdate?: boolean): Promise<void>;
|
|
146
|
-
/**
|
|
147
|
-
* This method is similar to scheduleSubscriberUpdate but it is built for working specifically with collections
|
|
148
|
-
* so that keysChanged() is triggered for the collection and not keyChanged(). If this was not done, then the
|
|
149
|
-
* subscriber callbacks receive the data in a different format than they normally expect and it breaks code.
|
|
150
|
-
*/
|
|
151
|
-
declare function scheduleNotifyCollectionSubscribers<TKey extends OnyxKey>(key: TKey, value: OnyxCollection<KeyValueMapping[TKey]>, previousValue?: OnyxCollection<KeyValueMapping[TKey]>): Promise<void>;
|
|
152
139
|
/**
|
|
153
140
|
* Remove a key from Onyx and update the subscribers
|
|
154
141
|
*/
|
|
@@ -164,7 +151,7 @@ declare function retryOperation<TMethod extends RetriableOnyxOperation>(error: E
|
|
|
164
151
|
/**
|
|
165
152
|
* Notifies subscribers and writes current value to cache
|
|
166
153
|
*/
|
|
167
|
-
declare function broadcastUpdate<TKey extends OnyxKey>(key: TKey, value: OnyxValue<TKey>, hasChanged?: boolean):
|
|
154
|
+
declare function broadcastUpdate<TKey extends OnyxKey>(key: TKey, value: OnyxValue<TKey>, hasChanged?: boolean): void;
|
|
168
155
|
declare function hasPendingMergeForKey(key: OnyxKey): boolean;
|
|
169
156
|
/**
|
|
170
157
|
* Storage expects array like: [["@MyApp_user", value_1], ["@MyApp_key", value_2]]
|
|
@@ -303,8 +290,6 @@ declare const OnyxUtils: {
|
|
|
303
290
|
keyChanged: typeof keyChanged;
|
|
304
291
|
sendDataToConnection: typeof sendDataToConnection;
|
|
305
292
|
getCollectionDataAndSendAsObject: typeof getCollectionDataAndSendAsObject;
|
|
306
|
-
scheduleSubscriberUpdate: typeof scheduleSubscriberUpdate;
|
|
307
|
-
scheduleNotifyCollectionSubscribers: typeof scheduleNotifyCollectionSubscribers;
|
|
308
293
|
remove: typeof remove;
|
|
309
294
|
reportStorageQuota: typeof reportStorageQuota;
|
|
310
295
|
retryOperation: typeof retryOperation;
|
package/dist/OnyxUtils.js
CHANGED
|
@@ -73,8 +73,6 @@ const MAX_STORAGE_OPERATION_RETRY_ATTEMPTS = 5;
|
|
|
73
73
|
// Key/value store of Onyx key and arrays of values to merge
|
|
74
74
|
let mergeQueue = {};
|
|
75
75
|
let mergeQueuePromise = {};
|
|
76
|
-
// Used to schedule subscriber update to the macro task queue
|
|
77
|
-
let nextMacrotaskPromise = null;
|
|
78
76
|
// Holds a mapping of all the React components that want their state subscribed to a store key
|
|
79
77
|
let callbackToStateMapping = {};
|
|
80
78
|
// Holds a mapping of the connected key to the subscriptionID for faster lookups
|
|
@@ -476,36 +474,42 @@ function keysChanged(collectionKey, partialCollection, partialPreviousCollection
|
|
|
476
474
|
const isSubscribedToCollectionMemberKey = OnyxKeys_1.default.isCollectionMemberKey(collectionKey, subscriber.key);
|
|
477
475
|
// Regular Onyx.connect() subscriber found.
|
|
478
476
|
if (typeof subscriber.callback === 'function') {
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
if (
|
|
483
|
-
subscriber.
|
|
477
|
+
try {
|
|
478
|
+
// If they are subscribed to the collection key and using waitForCollectionCallback then we'll
|
|
479
|
+
// send the whole cached collection.
|
|
480
|
+
if (isSubscribedToCollectionKey) {
|
|
481
|
+
lastConnectionCallbackData.set(subscriber.subscriptionID, { value: cachedCollection, matchedKey: subscriber.key });
|
|
482
|
+
if (subscriber.waitForCollectionCallback) {
|
|
483
|
+
subscriber.callback(cachedCollection, subscriber.key, partialCollection);
|
|
484
|
+
continue;
|
|
485
|
+
}
|
|
486
|
+
// If they are not using waitForCollectionCallback then we notify the subscriber with
|
|
487
|
+
// the new merged data but only for any keys in the partial collection.
|
|
488
|
+
const dataKeys = Object.keys(partialCollection !== null && partialCollection !== void 0 ? partialCollection : {});
|
|
489
|
+
for (const dataKey of dataKeys) {
|
|
490
|
+
if ((0, fast_equals_1.deepEqual)(cachedCollection[dataKey], previousCollection[dataKey])) {
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
subscriber.callback(cachedCollection[dataKey], dataKey);
|
|
494
|
+
}
|
|
484
495
|
continue;
|
|
485
496
|
}
|
|
486
|
-
//
|
|
487
|
-
//
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
if ((0, fast_equals_1.deepEqual)(cachedCollection[dataKey], previousCollection[dataKey])) {
|
|
497
|
+
// And if the subscriber is specifically only tracking a particular collection member key then we will
|
|
498
|
+
// notify them with the cached data for that key only.
|
|
499
|
+
if (isSubscribedToCollectionMemberKey) {
|
|
500
|
+
if ((0, fast_equals_1.deepEqual)(cachedCollection[subscriber.key], previousCollection[subscriber.key])) {
|
|
491
501
|
continue;
|
|
492
502
|
}
|
|
493
|
-
subscriber.callback
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
}
|
|
497
|
-
// And if the subscriber is specifically only tracking a particular collection member key then we will
|
|
498
|
-
// notify them with the cached data for that key only.
|
|
499
|
-
if (isSubscribedToCollectionMemberKey) {
|
|
500
|
-
if ((0, fast_equals_1.deepEqual)(cachedCollection[subscriber.key], previousCollection[subscriber.key])) {
|
|
503
|
+
const subscriberCallback = subscriber.callback;
|
|
504
|
+
subscriberCallback(cachedCollection[subscriber.key], subscriber.key);
|
|
505
|
+
lastConnectionCallbackData.set(subscriber.subscriptionID, { value: cachedCollection[subscriber.key], matchedKey: subscriber.key });
|
|
501
506
|
continue;
|
|
502
507
|
}
|
|
503
|
-
const subscriberCallback = subscriber.callback;
|
|
504
|
-
subscriberCallback(cachedCollection[subscriber.key], subscriber.key);
|
|
505
|
-
lastConnectionCallbackData.set(subscriber.subscriptionID, cachedCollection[subscriber.key]);
|
|
506
508
|
continue;
|
|
507
509
|
}
|
|
508
|
-
|
|
510
|
+
catch (error) {
|
|
511
|
+
Logger.logAlert(`[OnyxUtils.keysChanged] Subscriber callback threw an error for key '${collectionKey}': ${error}`);
|
|
512
|
+
}
|
|
509
513
|
}
|
|
510
514
|
}
|
|
511
515
|
}
|
|
@@ -546,27 +550,35 @@ function keyChanged(key, value, canUpdateSubscriber = () => true, isProcessingCo
|
|
|
546
550
|
}
|
|
547
551
|
// Subscriber is a regular call to connect() and provided a callback
|
|
548
552
|
if (typeof subscriber.callback === 'function') {
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
if (OnyxKeys_1.default.isCollectionKey(subscriber.key) && subscriber.waitForCollectionCallback) {
|
|
553
|
-
// Skip individual key changes for collection callbacks during collection updates
|
|
554
|
-
// to prevent duplicate callbacks - the collection update will handle this properly
|
|
555
|
-
if (isProcessingCollectionUpdate) {
|
|
553
|
+
try {
|
|
554
|
+
const lastData = lastConnectionCallbackData.get(subscriber.subscriptionID);
|
|
555
|
+
if (lastData && lastData.matchedKey === key && lastData.value === value) {
|
|
556
556
|
continue;
|
|
557
557
|
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
558
|
+
if (OnyxKeys_1.default.isCollectionKey(subscriber.key) && subscriber.waitForCollectionCallback) {
|
|
559
|
+
// Skip individual key changes for collection callbacks during collection updates
|
|
560
|
+
// to prevent duplicate callbacks - the collection update will handle this properly
|
|
561
|
+
if (isProcessingCollectionUpdate) {
|
|
562
|
+
continue;
|
|
563
|
+
}
|
|
564
|
+
let cachedCollection = cachedCollections[subscriber.key];
|
|
565
|
+
if (!cachedCollection) {
|
|
566
|
+
cachedCollection = getCachedCollection(subscriber.key);
|
|
567
|
+
cachedCollections[subscriber.key] = cachedCollection;
|
|
568
|
+
}
|
|
569
|
+
cachedCollection[key] = value;
|
|
570
|
+
lastConnectionCallbackData.set(subscriber.subscriptionID, { value: cachedCollection, matchedKey: subscriber.key });
|
|
571
|
+
subscriber.callback(cachedCollection, subscriber.key, { [key]: value });
|
|
572
|
+
continue;
|
|
562
573
|
}
|
|
563
|
-
|
|
564
|
-
|
|
574
|
+
const subscriberCallback = subscriber.callback;
|
|
575
|
+
subscriberCallback(value, key);
|
|
576
|
+
lastConnectionCallbackData.set(subscriber.subscriptionID, { value, matchedKey: key });
|
|
565
577
|
continue;
|
|
566
578
|
}
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
579
|
+
catch (error) {
|
|
580
|
+
Logger.logAlert(`[OnyxUtils.keyChanged] Subscriber callback threw an error for key '${key}': ${error}`);
|
|
581
|
+
}
|
|
570
582
|
continue;
|
|
571
583
|
}
|
|
572
584
|
console.error('Warning: Found a matching subscriber to a key that changed, but no callback could be found.');
|
|
@@ -575,22 +587,34 @@ function keyChanged(key, value, canUpdateSubscriber = () => true, isProcessingCo
|
|
|
575
587
|
/**
|
|
576
588
|
* Sends the data obtained from the keys to the connection.
|
|
577
589
|
*/
|
|
578
|
-
function sendDataToConnection(mapping,
|
|
590
|
+
function sendDataToConnection(mapping, matchedKey) {
|
|
579
591
|
var _a, _b;
|
|
580
592
|
// If the mapping no longer exists then we should not send any data.
|
|
581
593
|
// This means our subscriber was disconnected.
|
|
582
594
|
if (!callbackToStateMapping[mapping.subscriptionID]) {
|
|
583
595
|
return;
|
|
584
596
|
}
|
|
597
|
+
// Always read the latest value from cache to avoid stale or duplicate data.
|
|
598
|
+
// For collection subscribers with waitForCollectionCallback, read the full collection.
|
|
599
|
+
// For individual key subscribers, read just that key's value.
|
|
600
|
+
let value;
|
|
601
|
+
if (OnyxKeys_1.default.isCollectionKey(mapping.key) && mapping.waitForCollectionCallback) {
|
|
602
|
+
const collection = getCachedCollection(mapping.key);
|
|
603
|
+
value = Object.keys(collection).length > 0 ? collection : undefined;
|
|
604
|
+
}
|
|
605
|
+
else {
|
|
606
|
+
value = OnyxCache_1.default.get(matchedKey !== null && matchedKey !== void 0 ? matchedKey : mapping.key);
|
|
607
|
+
}
|
|
585
608
|
// For regular callbacks, we never want to pass null values, but always just undefined if a value is not set in cache or storage.
|
|
586
|
-
|
|
587
|
-
const
|
|
588
|
-
|
|
589
|
-
//
|
|
590
|
-
|
|
609
|
+
value = value === null ? undefined : value;
|
|
610
|
+
const lastData = lastConnectionCallbackData.get(mapping.subscriptionID);
|
|
611
|
+
// If the value has not changed for the same key we do not need to trigger the callback.
|
|
612
|
+
// We compare matchedKey to avoid suppressing callbacks for different collection members
|
|
613
|
+
// that happen to have shallow-equal values (e.g. during hydration racing with set()).
|
|
614
|
+
if (lastData && lastData.matchedKey === matchedKey && (0, fast_equals_1.shallowEqual)(lastData.value, value)) {
|
|
591
615
|
return;
|
|
592
616
|
}
|
|
593
|
-
(_b = (_a = mapping).callback) === null || _b === void 0 ? void 0 : _b.call(_a,
|
|
617
|
+
(_b = (_a = mapping).callback) === null || _b === void 0 ? void 0 : _b.call(_a, value, matchedKey);
|
|
594
618
|
}
|
|
595
619
|
/**
|
|
596
620
|
* We check to see if this key is flagged as safe for eviction and add it to the recentlyAccessedKeys list so that when we
|
|
@@ -609,50 +633,16 @@ function addKeyToRecentlyAccessedIfNeeded(key) {
|
|
|
609
633
|
* Gets the data for a given an array of matching keys, combines them into an object, and sends the result back to the subscriber.
|
|
610
634
|
*/
|
|
611
635
|
function getCollectionDataAndSendAsObject(matchingKeys, mapping) {
|
|
612
|
-
multiGet(matchingKeys).then((
|
|
613
|
-
|
|
614
|
-
sendDataToConnection(mapping, data, mapping.key);
|
|
636
|
+
multiGet(matchingKeys).then(() => {
|
|
637
|
+
sendDataToConnection(mapping, mapping.key);
|
|
615
638
|
});
|
|
616
639
|
}
|
|
617
|
-
/**
|
|
618
|
-
* Delays promise resolution until the next macrotask to prevent race condition if the key subscription is in progress.
|
|
619
|
-
*
|
|
620
|
-
* @param callback The keyChanged/keysChanged callback
|
|
621
|
-
* */
|
|
622
|
-
function prepareSubscriberUpdate(callback) {
|
|
623
|
-
if (!nextMacrotaskPromise) {
|
|
624
|
-
nextMacrotaskPromise = new Promise((resolve) => {
|
|
625
|
-
setTimeout(() => {
|
|
626
|
-
nextMacrotaskPromise = null;
|
|
627
|
-
resolve();
|
|
628
|
-
}, 0);
|
|
629
|
-
});
|
|
630
|
-
}
|
|
631
|
-
return Promise.all([nextMacrotaskPromise, Promise.resolve().then(callback)]).then();
|
|
632
|
-
}
|
|
633
|
-
/**
|
|
634
|
-
* Schedules an update that will be appended to the macro task queue (so it doesn't update the subscribers immediately).
|
|
635
|
-
*
|
|
636
|
-
* @example
|
|
637
|
-
* scheduleSubscriberUpdate(key, value, subscriber => subscriber.initWithStoredValues === false)
|
|
638
|
-
*/
|
|
639
|
-
function scheduleSubscriberUpdate(key, value, canUpdateSubscriber = () => true, isProcessingCollectionUpdate = false) {
|
|
640
|
-
return prepareSubscriberUpdate(() => keyChanged(key, value, canUpdateSubscriber, isProcessingCollectionUpdate));
|
|
641
|
-
}
|
|
642
|
-
/**
|
|
643
|
-
* This method is similar to scheduleSubscriberUpdate but it is built for working specifically with collections
|
|
644
|
-
* so that keysChanged() is triggered for the collection and not keyChanged(). If this was not done, then the
|
|
645
|
-
* subscriber callbacks receive the data in a different format than they normally expect and it breaks code.
|
|
646
|
-
*/
|
|
647
|
-
function scheduleNotifyCollectionSubscribers(key, value, previousValue) {
|
|
648
|
-
return prepareSubscriberUpdate(() => keysChanged(key, value, previousValue));
|
|
649
|
-
}
|
|
650
640
|
/**
|
|
651
641
|
* Remove a key from Onyx and update the subscribers
|
|
652
642
|
*/
|
|
653
643
|
function remove(key, isProcessingCollectionUpdate) {
|
|
654
644
|
OnyxCache_1.default.drop(key);
|
|
655
|
-
|
|
645
|
+
keyChanged(key, undefined, undefined, isProcessingCollectionUpdate);
|
|
656
646
|
if (OnyxKeys_1.default.isRamOnlyKey(key)) {
|
|
657
647
|
return Promise.resolve();
|
|
658
648
|
}
|
|
@@ -720,7 +710,7 @@ function broadcastUpdate(key, value, hasChanged) {
|
|
|
720
710
|
else {
|
|
721
711
|
OnyxCache_1.default.addToAccessedKeys(key);
|
|
722
712
|
}
|
|
723
|
-
|
|
713
|
+
keyChanged(key, value, (subscriber) => hasChanged || (subscriber === null || subscriber === void 0 ? void 0 : subscriber.initWithStoredValues) === false);
|
|
724
714
|
}
|
|
725
715
|
function hasPendingMergeForKey(key) {
|
|
726
716
|
return !!mergeQueue[key];
|
|
@@ -943,7 +933,7 @@ function subscribeToKey(connectOptions) {
|
|
|
943
933
|
const matchedKey = OnyxKeys_1.default.isCollectionKey(mapping.key) && mapping.waitForCollectionCallback ? mapping.key : undefined;
|
|
944
934
|
// Here we cannot use batching because the nullish value is expected to be set immediately for default props
|
|
945
935
|
// or they will be undefined.
|
|
946
|
-
sendDataToConnection(mapping,
|
|
936
|
+
sendDataToConnection(mapping, matchedKey);
|
|
947
937
|
return;
|
|
948
938
|
}
|
|
949
939
|
// When using a callback subscriber we will either trigger the provided callback for each key we find or combine all values
|
|
@@ -956,15 +946,15 @@ function subscribeToKey(connectOptions) {
|
|
|
956
946
|
return;
|
|
957
947
|
}
|
|
958
948
|
// We did not opt into using waitForCollectionCallback mode so the callback is called for every matching key.
|
|
959
|
-
multiGet(matchingKeys).then((
|
|
960
|
-
for (const
|
|
961
|
-
sendDataToConnection(mapping,
|
|
949
|
+
multiGet(matchingKeys).then(() => {
|
|
950
|
+
for (const key of matchingKeys) {
|
|
951
|
+
sendDataToConnection(mapping, key);
|
|
962
952
|
}
|
|
963
953
|
});
|
|
964
954
|
return;
|
|
965
955
|
}
|
|
966
956
|
// If we are not subscribed to a collection key then there's only a single key to send an update for.
|
|
967
|
-
get(mapping.key).then((
|
|
957
|
+
get(mapping.key).then(() => sendDataToConnection(mapping, mapping.key));
|
|
968
958
|
return;
|
|
969
959
|
}
|
|
970
960
|
console.error('Warning: Onyx.connect() was found without a callback');
|
|
@@ -1098,21 +1088,20 @@ function setWithRetry({ key, value, options }, retryAttempt) {
|
|
|
1098
1088
|
const hasChanged = (options === null || options === void 0 ? void 0 : options.skipCacheCheck) ? true : OnyxCache_1.default.hasValueChanged(key, valueWithoutNestedNullValues);
|
|
1099
1089
|
OnyxUtils.logKeyChanged(OnyxUtils.METHOD.SET, key, value, hasChanged);
|
|
1100
1090
|
// This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
|
|
1101
|
-
|
|
1091
|
+
OnyxUtils.broadcastUpdate(key, valueWithoutNestedNullValues, hasChanged);
|
|
1102
1092
|
// If the value has not changed and this isn't a retry attempt, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
|
|
1103
1093
|
if (!hasChanged && !retryAttempt) {
|
|
1104
|
-
return
|
|
1094
|
+
return Promise.resolve();
|
|
1105
1095
|
}
|
|
1106
1096
|
// If a key is a RAM-only key or a member of RAM-only collection, we skip the step that modifies the storage
|
|
1107
1097
|
if (OnyxKeys_1.default.isRamOnlyKey(key)) {
|
|
1108
1098
|
OnyxUtils.sendActionToDevTools(OnyxUtils.METHOD.SET, key, valueWithoutNestedNullValues);
|
|
1109
|
-
return
|
|
1099
|
+
return Promise.resolve();
|
|
1110
1100
|
}
|
|
1111
1101
|
return storage_1.default.setItem(key, valueWithoutNestedNullValues)
|
|
1112
1102
|
.catch((error) => OnyxUtils.retryOperation(error, setWithRetry, { key, value: valueWithoutNestedNullValues, options }, retryAttempt))
|
|
1113
1103
|
.then(() => {
|
|
1114
1104
|
OnyxUtils.sendActionToDevTools(OnyxUtils.METHOD.SET, key, valueWithoutNestedNullValues);
|
|
1115
|
-
return updatePromise;
|
|
1116
1105
|
});
|
|
1117
1106
|
}
|
|
1118
1107
|
/**
|
|
@@ -1142,16 +1131,16 @@ function multiSetWithRetry(data, retryAttempt) {
|
|
|
1142
1131
|
}, {});
|
|
1143
1132
|
}
|
|
1144
1133
|
const keyValuePairsToSet = OnyxUtils.prepareKeyValuePairsForStorage(newData, true);
|
|
1145
|
-
const
|
|
1134
|
+
for (const [key, value] of keyValuePairsToSet) {
|
|
1146
1135
|
// When we use multiSet to set a key we want to clear the current delta changes from Onyx.merge that were queued
|
|
1147
1136
|
// before the value was set. If Onyx.merge is currently reading the old value from storage, it will then not apply the changes.
|
|
1148
1137
|
if (OnyxUtils.hasPendingMergeForKey(key)) {
|
|
1149
1138
|
delete OnyxUtils.getMergeQueue()[key];
|
|
1150
1139
|
}
|
|
1151
|
-
// Update cache and optimistically inform subscribers
|
|
1140
|
+
// Update cache and optimistically inform subscribers
|
|
1152
1141
|
OnyxCache_1.default.set(key, value);
|
|
1153
|
-
|
|
1154
|
-
}
|
|
1142
|
+
keyChanged(key, value);
|
|
1143
|
+
}
|
|
1155
1144
|
const keyValuePairsToStore = keyValuePairsToSet.filter((keyValuePair) => {
|
|
1156
1145
|
const [key] = keyValuePair;
|
|
1157
1146
|
// Filter out the RAM-only key value pairs, as they should not be saved to storage
|
|
@@ -1161,9 +1150,7 @@ function multiSetWithRetry(data, retryAttempt) {
|
|
|
1161
1150
|
.catch((error) => OnyxUtils.retryOperation(error, multiSetWithRetry, newData, retryAttempt))
|
|
1162
1151
|
.then(() => {
|
|
1163
1152
|
OnyxUtils.sendActionToDevTools(OnyxUtils.METHOD.MULTI_SET, undefined, newData);
|
|
1164
|
-
|
|
1165
|
-
})
|
|
1166
|
-
.then(() => undefined);
|
|
1153
|
+
});
|
|
1167
1154
|
}
|
|
1168
1155
|
/**
|
|
1169
1156
|
* Sets a collection by replacing all existing collection members with new values.
|
|
@@ -1216,17 +1203,16 @@ function setCollectionWithRetry({ collectionKey, collection }, retryAttempt) {
|
|
|
1216
1203
|
const previousCollection = OnyxUtils.getCachedCollection(collectionKey);
|
|
1217
1204
|
for (const [key, value] of keyValuePairs)
|
|
1218
1205
|
OnyxCache_1.default.set(key, value);
|
|
1219
|
-
|
|
1206
|
+
keysChanged(collectionKey, mutableCollection, previousCollection);
|
|
1220
1207
|
// RAM-only keys are not supposed to be saved to storage
|
|
1221
1208
|
if (OnyxKeys_1.default.isRamOnlyKey(collectionKey)) {
|
|
1222
1209
|
OnyxUtils.sendActionToDevTools(OnyxUtils.METHOD.SET_COLLECTION, undefined, mutableCollection);
|
|
1223
|
-
return
|
|
1210
|
+
return;
|
|
1224
1211
|
}
|
|
1225
1212
|
return storage_1.default.multiSet(keyValuePairs)
|
|
1226
1213
|
.catch((error) => OnyxUtils.retryOperation(error, setCollectionWithRetry, { collectionKey, collection }, retryAttempt))
|
|
1227
1214
|
.then(() => {
|
|
1228
1215
|
OnyxUtils.sendActionToDevTools(OnyxUtils.METHOD.SET_COLLECTION, undefined, mutableCollection);
|
|
1229
|
-
return updatePromise;
|
|
1230
1216
|
});
|
|
1231
1217
|
});
|
|
1232
1218
|
}
|
|
@@ -1333,7 +1319,7 @@ function mergeCollectionWithPatches({ collectionKey, collection, mergeReplaceNul
|
|
|
1333
1319
|
// and update all subscribers
|
|
1334
1320
|
const promiseUpdate = previousCollectionPromise.then((previousCollection) => {
|
|
1335
1321
|
OnyxCache_1.default.merge(finalMergedCollection);
|
|
1336
|
-
|
|
1322
|
+
keysChanged(collectionKey, finalMergedCollection, previousCollection);
|
|
1337
1323
|
});
|
|
1338
1324
|
return Promise.all(promises)
|
|
1339
1325
|
.catch((error) => retryOperation(error, mergeCollectionWithPatches, { collectionKey, collection: resultCollection, mergeReplaceNullPatches, isProcessingCollectionUpdate }, retryAttempt))
|
|
@@ -1386,16 +1372,15 @@ function partialSetCollection({ collectionKey, collection }, retryAttempt) {
|
|
|
1386
1372
|
const keyValuePairs = prepareKeyValuePairsForStorage(mutableCollection, true, undefined, true);
|
|
1387
1373
|
for (const [key, value] of keyValuePairs)
|
|
1388
1374
|
OnyxCache_1.default.set(key, value);
|
|
1389
|
-
|
|
1375
|
+
keysChanged(collectionKey, mutableCollection, previousCollection);
|
|
1390
1376
|
if (OnyxKeys_1.default.isRamOnlyKey(collectionKey)) {
|
|
1391
1377
|
sendActionToDevTools(METHOD.SET_COLLECTION, undefined, mutableCollection);
|
|
1392
|
-
return
|
|
1378
|
+
return;
|
|
1393
1379
|
}
|
|
1394
1380
|
return storage_1.default.multiSet(keyValuePairs)
|
|
1395
1381
|
.catch((error) => retryOperation(error, partialSetCollection, { collectionKey, collection }, retryAttempt))
|
|
1396
1382
|
.then(() => {
|
|
1397
1383
|
sendActionToDevTools(METHOD.SET_COLLECTION, undefined, mutableCollection);
|
|
1398
|
-
return updatePromise;
|
|
1399
1384
|
});
|
|
1400
1385
|
});
|
|
1401
1386
|
}
|
|
@@ -1432,8 +1417,6 @@ const OnyxUtils = {
|
|
|
1432
1417
|
keyChanged,
|
|
1433
1418
|
sendDataToConnection,
|
|
1434
1419
|
getCollectionDataAndSendAsObject,
|
|
1435
|
-
scheduleSubscriberUpdate,
|
|
1436
|
-
scheduleNotifyCollectionSubscribers,
|
|
1437
1420
|
remove,
|
|
1438
1421
|
reportStorageQuota,
|
|
1439
1422
|
retryOperation,
|
|
@@ -6,12 +6,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const react_native_nitro_sqlite_1 = require("react-native-nitro-sqlite");
|
|
7
7
|
const react_native_device_info_1 = require("react-native-device-info");
|
|
8
8
|
const utils_1 = __importDefault(require("../../utils"));
|
|
9
|
-
// By default, NitroSQLite does not accept nullish values due to current limitations in Nitro Modules.
|
|
10
|
-
// This flag enables a feature in NitroSQLite that allows for nullish values to be passed to operations, such as "execute" or "executeBatch".
|
|
11
|
-
// Simple null handling can potentially add a minor performance overhead,
|
|
12
|
-
// since parameters and results from SQLite queries need to be parsed from and to JavaScript nullish values.
|
|
13
|
-
// https://github.com/margelo/react-native-nitro-sqlite#sending-and-receiving-nullish-values
|
|
14
|
-
(0, react_native_nitro_sqlite_1.enableSimpleNullHandling)();
|
|
15
9
|
const DB_NAME = 'OnyxDB';
|
|
16
10
|
/**
|
|
17
11
|
* Prevents the stringifying of the object markers.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-onyx",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.62",
|
|
4
4
|
"author": "Expensify, Inc.",
|
|
5
5
|
"homepage": "https://expensify.com",
|
|
6
6
|
"description": "State management for React Native",
|
|
@@ -91,8 +91,8 @@
|
|
|
91
91
|
"react": "18.2.0",
|
|
92
92
|
"react-native": "0.76.3",
|
|
93
93
|
"react-native-device-info": "^10.3.0",
|
|
94
|
-
"react-native-nitro-modules": "^0.
|
|
95
|
-
"react-native-nitro-sqlite": "^9.
|
|
94
|
+
"react-native-nitro-modules": "^0.35.0",
|
|
95
|
+
"react-native-nitro-sqlite": "^9.6.0",
|
|
96
96
|
"react-test-renderer": "18.2.0",
|
|
97
97
|
"reassure": "1.4.0",
|
|
98
98
|
"ts-node": "^10.9.2",
|
|
@@ -104,8 +104,8 @@
|
|
|
104
104
|
"react": ">=18.1.0",
|
|
105
105
|
"react-native": ">=0.75.0",
|
|
106
106
|
"react-native-device-info": "^10.3.0",
|
|
107
|
-
"react-native-nitro-modules": ">=0.
|
|
108
|
-
"react-native-nitro-sqlite": "^9.
|
|
107
|
+
"react-native-nitro-modules": ">=0.35.0",
|
|
108
|
+
"react-native-nitro-sqlite": "^9.6.0"
|
|
109
109
|
},
|
|
110
110
|
"peerDependenciesMeta": {
|
|
111
111
|
"idb-keyval": {
|