react-native-onyx 3.0.66 → 3.0.68

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.
@@ -135,7 +135,7 @@ declare function getCollectionDataAndSendAsObject<TKey extends OnyxKey>(matching
135
135
  * Remove a key from Onyx and update the subscribers
136
136
  */
137
137
  declare function remove<TKey extends OnyxKey>(key: TKey, isProcessingCollectionUpdate?: boolean): Promise<void>;
138
- declare function reportStorageQuota(): Promise<void>;
138
+ declare function reportStorageQuota(error?: Error): Promise<void>;
139
139
  /**
140
140
  * Handles storage operation failures based on the error type:
141
141
  * - Storage capacity errors: evicts data and retries the operation
@@ -257,6 +257,10 @@ declare function mergeCollectionWithPatches<TKey extends CollectionKeyBase>({ co
257
257
  declare function partialSetCollection<TKey extends CollectionKeyBase>({ collectionKey, collection }: SetCollectionParams<TKey>, retryAttempt?: number): Promise<void>;
258
258
  declare function logKeyChanged(onyxMethod: Extract<OnyxMethod, 'set' | 'merge'>, key: OnyxKey, value: unknown, hasChanged: boolean): void;
259
259
  declare function logKeyRemoved(onyxMethod: Extract<OnyxMethod, 'set' | 'merge'>, key: OnyxKey): void;
260
+ /**
261
+ * Getter - returns the callback to state mapping, useful in test environments.
262
+ */
263
+ declare function getCallbackToStateMapping(): Record<number, CallbackToStateMapping<OnyxKey>>;
260
264
  /**
261
265
  * Clear internal variables used in this file, useful in test environments.
262
266
  */
@@ -316,6 +320,7 @@ declare const OnyxUtils: {
316
320
  setWithRetry: typeof setWithRetry;
317
321
  multiSetWithRetry: typeof multiSetWithRetry;
318
322
  setCollectionWithRetry: typeof setCollectionWithRetry;
323
+ getCallbackToStateMapping: typeof getCallbackToStateMapping;
319
324
  };
320
325
  export type { OnyxMethod };
321
326
  export default OnyxUtils;
package/dist/OnyxUtils.js CHANGED
@@ -633,13 +633,13 @@ function remove(key, isProcessingCollectionUpdate) {
633
633
  }
634
634
  return storage_1.default.removeItem(key).then(() => undefined);
635
635
  }
636
- function reportStorageQuota() {
636
+ function reportStorageQuota(error) {
637
637
  return storage_1.default.getDatabaseSize()
638
638
  .then(({ bytesUsed, bytesRemaining }) => {
639
- Logger.logInfo(`Storage Quota Check -- bytesUsed: ${bytesUsed} bytesRemaining: ${bytesRemaining}`);
639
+ Logger.logInfo(`Storage Quota Check -- bytesUsed: ${bytesUsed} bytesRemaining: ${bytesRemaining}. Original error: ${error}`);
640
640
  })
641
641
  .catch((dbSizeError) => {
642
- Logger.logAlert(`Unable to get database size. Error: ${dbSizeError}`);
642
+ Logger.logAlert(`Unable to get database size. getDatabaseSize error: ${dbSizeError}. Original error: ${error}`);
643
643
  });
644
644
  }
645
645
  /**
@@ -654,7 +654,7 @@ function retryOperation(error, onyxMethod, defaultParams, retryAttempt) {
654
654
  const nextRetryAttempt = currentRetryAttempt + 1;
655
655
  Logger.logInfo(`Failed to save to storage. Error: ${error}. onyxMethod: ${onyxMethod.name}. retryAttempt: ${currentRetryAttempt}/${MAX_STORAGE_OPERATION_RETRY_ATTEMPTS}`);
656
656
  if (error && Str.startsWith(error.message, "Failed to execute 'put' on 'IDBObjectStore'")) {
657
- Logger.logAlert('Attempted to set invalid data set in Onyx. Please ensure all data is serializable.');
657
+ Logger.logAlert(`Attempted to set invalid data set in Onyx. Please ensure all data is serializable. Error: ${error}`);
658
658
  throw error;
659
659
  }
660
660
  const errorMessage = (_b = (_a = error === null || error === void 0 ? void 0 : error.message) === null || _a === void 0 ? void 0 : _a.toLowerCase) === null || _b === void 0 ? void 0 : _b.call(_a);
@@ -674,12 +674,12 @@ function retryOperation(error, onyxMethod, defaultParams, retryAttempt) {
674
674
  // If we have no acceptable keys to remove then we are possibly trying to save mission critical data. If this is the case,
675
675
  // then we should stop retrying as there is not much the user can do to fix this. Instead of getting them stuck in an infinite loop we
676
676
  // will allow this write to be skipped.
677
- Logger.logAlert('Out of storage. But found no acceptable keys to remove.');
678
- return reportStorageQuota();
677
+ Logger.logAlert(`Out of storage. But found no acceptable keys to remove. Error: ${error}`);
678
+ return reportStorageQuota(error);
679
679
  }
680
680
  // Remove the least recently accessed key and retry.
681
- Logger.logInfo(`Out of storage. Evicting least recently accessed key (${keyForRemoval}) and retrying.`);
682
- reportStorageQuota();
681
+ Logger.logInfo(`Out of storage. Evicting least recently accessed key (${keyForRemoval}) and retrying. Error: ${error}`);
682
+ reportStorageQuota(error);
683
683
  // @ts-expect-error No overload matches this call.
684
684
  return remove(keyForRemoval).then(() => onyxMethod(defaultParams, nextRetryAttempt));
685
685
  }
@@ -866,6 +866,24 @@ function subscribeToKey(connectOptions) {
866
866
  const subscriptionID = lastSubscriptionID++;
867
867
  callbackToStateMapping[subscriptionID] = mapping;
868
868
  callbackToStateMapping[subscriptionID].subscriptionID = subscriptionID;
869
+ // If the subscriber is attempting to connect to a collection member whose ID is skippable (e.g. "undefined", "null", etc.)
870
+ // we suppress wiring the subscription fully to avoid unnecessary callback emissions such as for "report_undefined".
871
+ // We still return a valid subscriptionID so callers can disconnect safely.
872
+ try {
873
+ const skippableIDs = getSkippableCollectionMemberIDs();
874
+ if (skippableIDs.size) {
875
+ const [, collectionMemberID] = OnyxKeys_1.default.splitCollectionMemberKey(mapping.key);
876
+ if (skippableIDs.has(collectionMemberID)) {
877
+ // Clean up the provisional mapping to avoid retaining unused subscribers.
878
+ OnyxCache_1.default.addNullishStorageKey(mapping.key);
879
+ delete callbackToStateMapping[subscriptionID];
880
+ return subscriptionID;
881
+ }
882
+ }
883
+ }
884
+ catch (e) {
885
+ // Not a collection member key, proceed as usual.
886
+ }
869
887
  // When keyChanged is called, a key is passed and the method looks through all the Subscribers in callbackToStateMapping for the matching key to get the subscriptionID
870
888
  // to avoid having to loop through all the Subscribers all the time (even when just one connection belongs to one key),
871
889
  // We create a mapping from key to lists of subscriptionIDs to access the specific list of subscriptionIDs.
@@ -1374,6 +1392,12 @@ function logKeyChanged(onyxMethod, key, value, hasChanged) {
1374
1392
  function logKeyRemoved(onyxMethod, key) {
1375
1393
  Logger.logInfo(`${onyxMethod} called for key: ${key} => null passed, so key was removed`);
1376
1394
  }
1395
+ /**
1396
+ * Getter - returns the callback to state mapping, useful in test environments.
1397
+ */
1398
+ function getCallbackToStateMapping() {
1399
+ return callbackToStateMapping;
1400
+ }
1377
1401
  /**
1378
1402
  * Clear internal variables used in this file, useful in test environments.
1379
1403
  */
@@ -1432,5 +1456,6 @@ const OnyxUtils = {
1432
1456
  setWithRetry,
1433
1457
  multiSetWithRetry,
1434
1458
  setCollectionWithRetry,
1459
+ getCallbackToStateMapping,
1435
1460
  };
1436
1461
  exports.default = OnyxUtils;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-onyx",
3
- "version": "3.0.66",
3
+ "version": "3.0.68",
4
4
  "author": "Expensify, Inc.",
5
5
  "homepage": "https://expensify.com",
6
6
  "description": "State management for React Native",