react-native-onyx 3.0.117 → 3.0.119

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/API.md CHANGED
@@ -63,6 +63,19 @@ Any existing collection members not included in the new data will be removed.</p
63
63
  Live RAM-only values and writes that have not reached storage are not included.
64
64
  Treat the returned object and its nested values as read-only.</p>
65
65
  </dd>
66
+ <dt><a href="#get">get(key)</a> ⇒</dt>
67
+ <dd><p>Reads the current value of an Onyx key once, without subscribing. Use <code>useOnyx()</code> or
68
+ <code>Onyx.connectWithoutView()</code> when the value has to stay current.</p>
69
+ <p>The read is served from the cache, which <code>init()</code> fills with the whole store, so it returns what a
70
+ subscription to the same key would deliver. The value is the cached one rather than a copy, so treat
71
+ it as read-only.</p>
72
+ </dd>
73
+ <dt><a href="#multiGet">multiGet(keys)</a> ⇒</dt>
74
+ <dd><p>Reads several Onyx keys at once, without subscribing. Use <code>useOnyx()</code> or <code>Onyx.connectWithoutView()</code> when
75
+ the values have to stay current.</p>
76
+ <p>Values come back in the order of the keys given, and each is what get() returns for its key. To read a
77
+ whole collection, pass the collection key rather than listing its members.</p>
78
+ </dd>
66
79
  </dl>
67
80
 
68
81
  <a name="init"></a>
@@ -280,3 +293,49 @@ Live RAM-only values and writes that have not reached storage are not included.
280
293
  Treat the returned object and its nested values as read-only.
281
294
 
282
295
  **Kind**: global function
296
+ <a name="get"></a>
297
+
298
+ ## get(key) ⇒
299
+ Reads the current value of an Onyx key once, without subscribing. Use `useOnyx()` or
300
+ `Onyx.connectWithoutView()` when the value has to stay current.
301
+
302
+ The read is served from the cache, which `init()` fills with the whole store, so it returns what a
303
+ subscription to the same key would deliver. The value is the cached one rather than a copy, so treat
304
+ it as read-only.
305
+
306
+ **Kind**: global function
307
+ **Returns**: The current value, or `undefined` if the key has none.
308
+
309
+ | Param | Description |
310
+ | --- | --- |
311
+ | key | ONYXKEY to read, either a collection key or a single key |
312
+
313
+ **Example**
314
+ ```js
315
+ const report = await Onyx.get(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`);
316
+ const allReports = await Onyx.get(ONYXKEYS.COLLECTION.REPORT);
317
+ ```
318
+ <a name="multiGet"></a>
319
+
320
+ ## multiGet(keys) ⇒
321
+ Reads several Onyx keys at once, without subscribing. Use `useOnyx()` or `Onyx.connectWithoutView()` when
322
+ the values have to stay current.
323
+
324
+ Values come back in the order of the keys given, and each is what get() returns for its key. To read a
325
+ whole collection, pass the collection key rather than listing its members.
326
+
327
+ **Kind**: global function
328
+ **Returns**: The values in the order of their keys, each `undefined` where a key has no value.
329
+
330
+ | Param | Description |
331
+ | --- | --- |
332
+ | keys | ONYXKEYS to read, in any mix of collection keys and single keys |
333
+
334
+ **Example**
335
+ ```js
336
+ const [session, wallet, report] = await Onyx.multiGet([
337
+ ONYXKEYS.SESSION,
338
+ ONYXKEYS.WALLET,
339
+ `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
340
+ ]);
341
+ ```
package/dist/Onyx.d.ts CHANGED
@@ -161,6 +161,42 @@ declare function setCollection<TKey extends CollectionKeyBase>(collectionKey: TK
161
161
  * Treat the returned object and its nested values as read-only.
162
162
  */
163
163
  declare function exportState(): Promise<Record<OnyxKey, OnyxValue<OnyxKey>>>;
164
+ /**
165
+ * Reads the current value of an Onyx key once, without subscribing. Use `useOnyx()` or
166
+ * `Onyx.connectWithoutView()` when the value has to stay current.
167
+ *
168
+ * The read is served from the cache, which `init()` fills with the whole store, so it returns what a
169
+ * subscription to the same key would deliver. The value is the cached one rather than a copy, so treat
170
+ * it as read-only.
171
+ *
172
+ * @example
173
+ * const report = await Onyx.get(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`);
174
+ * const allReports = await Onyx.get(ONYXKEYS.COLLECTION.REPORT);
175
+ *
176
+ * @param key ONYXKEY to read, either a collection key or a single key
177
+ * @returns The current value, or `undefined` if the key has none.
178
+ */
179
+ declare function get<TKey extends OnyxKey>(key: TKey): Promise<OnyxValue<TKey>>;
180
+ /**
181
+ * Reads several Onyx keys at once, without subscribing. Use `useOnyx()` or `Onyx.connectWithoutView()` when
182
+ * the values have to stay current.
183
+ *
184
+ * Values come back in the order of the keys given, and each is what get() returns for its key. To read a
185
+ * whole collection, pass the collection key rather than listing its members.
186
+ *
187
+ * @example
188
+ * const [session, wallet, report] = await Onyx.multiGet([
189
+ * ONYXKEYS.SESSION,
190
+ * ONYXKEYS.WALLET,
191
+ * `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
192
+ * ]);
193
+ *
194
+ * @param keys ONYXKEYS to read, in any mix of collection keys and single keys
195
+ * @returns The values in the order of their keys, each `undefined` where a key has no value.
196
+ */
197
+ declare function multiGet<const Keys extends readonly OnyxKey[]>(keys: Keys): Promise<{
198
+ [Index in keyof Keys]: OnyxValue<Keys[Index]>;
199
+ }>;
164
200
  declare const Onyx: {
165
201
  METHOD: {
166
202
  readonly SET: "set";
@@ -182,6 +218,8 @@ declare const Onyx: {
182
218
  clear: typeof clear;
183
219
  exportState: typeof exportState;
184
220
  init: typeof init;
221
+ get: typeof get;
222
+ multiGet: typeof multiGet;
185
223
  registerLogger: typeof Logger.registerLogger;
186
224
  };
187
225
  export default Onyx;
package/dist/Onyx.js CHANGED
@@ -473,6 +473,7 @@ function clear(keysToPreserve = []) {
473
473
  .then(() => storage_1.default.multiSet(defaultKeyValuePairs))
474
474
  .then(() => {
475
475
  DevTools_1.default.clearState(keysToPreserve);
476
+ OnyxSubscriptionManager_1.default.resetCacheMissReports();
476
477
  // Notify the subscribers for each key/value group so they can receive the new values
477
478
  for (const [key, value] of Object.entries(keyValuesToResetIndividually)) {
478
479
  OnyxUtils_1.default.notifyKey(key, value);
@@ -662,6 +663,45 @@ function exportState() {
662
663
  return state;
663
664
  }));
664
665
  }
666
+ /**
667
+ * Reads the current value of an Onyx key once, without subscribing. Use `useOnyx()` or
668
+ * `Onyx.connectWithoutView()` when the value has to stay current.
669
+ *
670
+ * The read is served from the cache, which `init()` fills with the whole store, so it returns what a
671
+ * subscription to the same key would deliver. The value is the cached one rather than a copy, so treat
672
+ * it as read-only.
673
+ *
674
+ * @example
675
+ * const report = await Onyx.get(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`);
676
+ * const allReports = await Onyx.get(ONYXKEYS.COLLECTION.REPORT);
677
+ *
678
+ * @param key ONYXKEY to read, either a collection key or a single key
679
+ * @returns The current value, or `undefined` if the key has none.
680
+ */
681
+ function get(key) {
682
+ return OnyxUtils_1.default.afterInit(() => { var _a; return Promise.resolve(((_a = OnyxSubscriptionManager_1.default.getState(key)) !== null && _a !== void 0 ? _a : undefined)); });
683
+ }
684
+ /**
685
+ * Reads several Onyx keys at once, without subscribing. Use `useOnyx()` or `Onyx.connectWithoutView()` when
686
+ * the values have to stay current.
687
+ *
688
+ * Values come back in the order of the keys given, and each is what get() returns for its key. To read a
689
+ * whole collection, pass the collection key rather than listing its members.
690
+ *
691
+ * @example
692
+ * const [session, wallet, report] = await Onyx.multiGet([
693
+ * ONYXKEYS.SESSION,
694
+ * ONYXKEYS.WALLET,
695
+ * `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
696
+ * ]);
697
+ *
698
+ * @param keys ONYXKEYS to read, in any mix of collection keys and single keys
699
+ * @returns The values in the order of their keys, each `undefined` where a key has no value.
700
+ */
701
+ function multiGet(keys) {
702
+ // map() widens the key tuple to an array, so the per-slot value types survive only through the cast.
703
+ return OnyxUtils_1.default.afterInit(() => Promise.resolve(keys.map((key) => { var _a; return (_a = OnyxSubscriptionManager_1.default.getState(key)) !== null && _a !== void 0 ? _a : undefined; })));
704
+ }
665
705
  const Onyx = {
666
706
  METHOD: OnyxUtils_1.default.METHOD,
667
707
  connect,
@@ -676,6 +716,8 @@ const Onyx = {
676
716
  clear,
677
717
  exportState,
678
718
  init,
719
+ get,
720
+ multiGet,
679
721
  registerLogger: Logger.registerLogger,
680
722
  };
681
723
  exports.default = Onyx;
@@ -48,6 +48,7 @@ declare class OnyxSubscriptionManager {
48
48
  * Wipe all subscriptions. Used by tests and `Onyx.clear()` follow-on.
49
49
  */
50
50
  clearAll(): void;
51
+ resetCacheMissReports(): void;
51
52
  /**
52
53
  * True if there are any subscribers for the given key (exact or parent collection).
53
54
  */
@@ -39,6 +39,29 @@ Object.defineProperty(exports, "__esModule", { value: true });
39
39
  const Logger = __importStar(require("./Logger"));
40
40
  const OnyxCache_1 = __importDefault(require("./OnyxCache"));
41
41
  const OnyxKeys_1 = __importDefault(require("./OnyxKeys"));
42
+ const storage_1 = __importDefault(require("./storage"));
43
+ const reportedCacheMisses = new Set();
44
+ function reportCacheMissIfStorageHasValue(key) {
45
+ var _a;
46
+ if (OnyxKeys_1.default.isRamOnlyKey(key) || !OnyxCache_1.default.getAllKeys().has(key) || OnyxCache_1.default.hasNullishStorageKey(key)) {
47
+ return;
48
+ }
49
+ const reportKey = (_a = OnyxKeys_1.default.getCollectionKey(key)) !== null && _a !== void 0 ? _a : key;
50
+ if (reportedCacheMisses.has(reportKey)) {
51
+ return;
52
+ }
53
+ reportedCacheMisses.add(reportKey);
54
+ storage_1.default.getItem(key)
55
+ .then((value) => {
56
+ if (value === undefined || value === null) {
57
+ return;
58
+ }
59
+ Logger.logHmmm(`Cache held no value for a key storage still has: ${reportKey}`);
60
+ })
61
+ .catch((error) => {
62
+ Logger.logInfo(`Could not check storage for a suspected cache miss on ${reportKey}. Error: ${String(error)}`);
63
+ });
64
+ }
42
65
  /**
43
66
  * OnyxSubscriptionManager is a registry for Onyx subscriptions.
44
67
  * Subscriptions are stored in `keyListeners`, a flat map keyed by OnyxKey.
@@ -58,7 +81,11 @@ class OnyxSubscriptionManager {
58
81
  if (OnyxKeys_1.default.isCollectionKey(key)) {
59
82
  return OnyxCache_1.default.getCollectionData(key);
60
83
  }
61
- return OnyxCache_1.default.get(key);
84
+ const value = OnyxCache_1.default.get(key);
85
+ if (value === undefined) {
86
+ reportCacheMissIfStorageHasValue(key);
87
+ }
88
+ return value;
62
89
  }
63
90
  /**
64
91
  * Subscribe to an exact key. For a collection root key this is "collection mode": the
@@ -164,6 +191,10 @@ class OnyxSubscriptionManager {
164
191
  */
165
192
  clearAll() {
166
193
  this.keyListeners.clear();
194
+ this.resetCacheMissReports();
195
+ }
196
+ resetCacheMissReports() {
197
+ reportedCacheMisses.clear();
167
198
  }
168
199
  /**
169
200
  * True if there are any subscribers for the given key (exact or parent collection).
@@ -31,6 +31,10 @@ function classifyIDBError(error) {
31
31
  if (message.includes('internal error opening backing store')) {
32
32
  return errors_1.StorageErrorClass.FATAL;
33
33
  }
34
+ // Chromium persistence failure with no cause attached, recovered by a fresh connection.
35
+ if (name === 'unknownerror' && message === 'internal error.') {
36
+ return errors_1.StorageErrorClass.FATAL;
37
+ }
34
38
  // Transient connection/transport failures — the cached connection is stale and a reopen fixes it:
35
39
  // - InvalidStateError: connection closed between getDB() resolving and db.transaction().
36
40
  // - AbortError: write transaction aborted (connection close / versionchange / sibling abort).
@@ -209,6 +209,7 @@ function createStore(dbName, storeName) {
209
209
  Logger.logInfo(`IDB heal: backing store error detected — dropping cached connection and reopening (${healAttemptsRemaining} attempts left)`, {
210
210
  dbName,
211
211
  storeName,
212
+ errorMessage: error instanceof Error ? error.message : String(error),
212
213
  });
213
214
  dbp = undefined;
214
215
  return executeTransaction(txMode, callback).then((result) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-onyx",
3
- "version": "3.0.117",
3
+ "version": "3.0.119",
4
4
  "author": "Expensify, Inc.",
5
5
  "homepage": "https://expensify.com",
6
6
  "description": "State management for React Native",