🚨 Latest Research:Tanstack npm Packages Compromised in Ongoing Mini Shai-Hulud Supply-Chain Attack.Learn More
Socket
Book a DemoSign in
Socket

react-native-onyx

Package Overview
Dependencies
Maintainers
1
Versions
347
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-native-onyx - npm Package Compare versions

Comparing version
3.0.62
to
3.0.63
+1
-1
dist/Onyx.d.ts

@@ -5,3 +5,3 @@ import * as Logger from './Logger';

/** Initialize the store with actions and listening for storage events */
declare function init({ keys, initialKeyStates, evictableKeys, maxCachedKeysCount, shouldSyncMultipleInstances, enableDevTools, skippableCollectionMemberIDs, ramOnlyKeys, snapshotMergeKeys, }: InitOptions): void;
declare function init({ keys, initialKeyStates, evictableKeys, shouldSyncMultipleInstances, enableDevTools, skippableCollectionMemberIDs, ramOnlyKeys, snapshotMergeKeys, }: InitOptions): void;
/**

@@ -8,0 +8,0 @@ * Connects to an Onyx key given the options passed and listens to its changes.

@@ -50,3 +50,3 @@ "use strict";

/** Initialize the store with actions and listening for storage events */
function init({ keys = {}, initialKeyStates = {}, evictableKeys = [], maxCachedKeysCount = 1000, shouldSyncMultipleInstances = !!global.localStorage, enableDevTools = true, skippableCollectionMemberIDs = [], ramOnlyKeys = [], snapshotMergeKeys = [], }) {
function init({ keys = {}, initialKeyStates = {}, evictableKeys = [], shouldSyncMultipleInstances = !!global.localStorage, enableDevTools = true, skippableCollectionMemberIDs = [], ramOnlyKeys = [], snapshotMergeKeys = [], }) {
var _a;

@@ -73,5 +73,2 @@ (0, DevTools_1.initDevTools)(enableDevTools);

}
if (maxCachedKeysCount > 0) {
OnyxCache_1.default.setRecentKeysLimit(maxCachedKeysCount);
}
OnyxUtils_1.default.initStoreValues(keys, initialKeyStates, evictableKeys);

@@ -78,0 +75,0 @@ // Initialize all of our keys with data provided then give green light to any pending connections.

@@ -18,4 +18,2 @@ import type { ValueOf } from 'type-fest';

private nullishStorageKeys;
/** Unique list of keys maintained in access order (most recent at the end) */
private recentKeys;
/** A map of cached values */

@@ -30,8 +28,4 @@ private storageMap;

private pendingPromises;
/** Maximum size of the keys store din cache */
private maxRecentKeysSize;
/** List of keys that are safe to remove when we reach max storage */
private evictionAllowList;
/** Map of keys and connection arrays whose keys will never be automatically evicted */
private evictionBlocklist;
/** List of keys that have been directly subscribed to or recently modified from least to most recent */

@@ -66,8 +60,5 @@ private recentlyAccessedKeys;

hasCacheForKey(key: OnyxKey): boolean;
/** Get a cached value from storage */
get(key: OnyxKey): OnyxValue<OnyxKey>;
/**
* Get a cached value from storage
* @param [shouldReindexCache] – This is an LRU cache, and by default accessing a value will make it become last in line to be evicted. This flag can be used to skip that and just access the value directly without side-effects.
*/
get(key: OnyxKey, shouldReindexCache?: boolean): OnyxValue<OnyxKey>;
/**
* Set's a key value in cache

@@ -102,8 +93,2 @@ * Adds the key to the storage keys list as well

captureTask(taskName: CacheTask, promise: Promise<OnyxValue<OnyxKey>>): Promise<OnyxValue<OnyxKey>>;
/** Adds a key to the top of the recently accessed keys */
addToAccessedKeys(key: OnyxKey): void;
/** Remove keys that don't fall into the range of recently used keys */
removeLeastRecentlyUsedKeys(): void;
/** Set the recent keys list size */
setRecentKeysLimit(limit: number): void;
/** Check if the value has changed */

@@ -117,6 +102,2 @@ hasValueChanged(key: OnyxKey, value: OnyxValue<OnyxKey>): boolean;

/**
* Get the eviction block list that prevents keys from being evicted
*/
getEvictionBlocklist(): Record<OnyxKey, string[] | undefined>;
/**
* Checks to see if this key has been flagged as safe for removal.

@@ -146,3 +127,3 @@ * @param testKey - Key to check

/**
* Finds a key that can be safely evicted
* Finds the least recently accessed key that can be safely evicted from storage.
*/

@@ -149,0 +130,0 @@ getKeyForEviction(): OnyxKey | undefined;

@@ -24,8 +24,4 @@ "use strict";

constructor() {
/** Maximum size of the keys store din cache */
this.maxRecentKeysSize = 0;
/** List of keys that are safe to remove when we reach max storage */
this.evictionAllowList = [];
/** Map of keys and connection arrays whose keys will never be automatically evicted */
this.evictionBlocklist = {};
/** List of keys that have been directly subscribed to or recently modified from least to most recent */

@@ -35,3 +31,2 @@ this.recentlyAccessedKeys = new Set();

this.nullishStorageKeys = new Set();
this.recentKeys = new Set();
this.storageMap = {};

@@ -41,3 +36,3 @@ this.collectionData = {};

// bind all public methods to prevent problems with `this`
(0, bindAll_1.default)(this, 'getAllKeys', 'get', 'hasCacheForKey', 'addKey', 'addNullishStorageKey', 'hasNullishStorageKey', 'clearNullishStorageKeys', 'set', 'drop', 'merge', 'hasPendingTask', 'getTaskPromise', 'captureTask', 'addToAccessedKeys', 'removeLeastRecentlyUsedKeys', 'setRecentKeysLimit', 'setAllKeys', 'setEvictionAllowList', 'getEvictionBlocklist', 'isEvictableKey', 'removeLastAccessedKey', 'addLastAccessedKey', 'addEvictableKeysToRecentlyAccessedList', 'getKeyForEviction', 'setCollectionKeys', 'getCollectionData', 'hasValueChanged');
(0, bindAll_1.default)(this, 'getAllKeys', 'get', 'hasCacheForKey', 'addKey', 'addNullishStorageKey', 'hasNullishStorageKey', 'clearNullishStorageKeys', 'set', 'drop', 'merge', 'hasPendingTask', 'getTaskPromise', 'captureTask', 'setAllKeys', 'setEvictionAllowList', 'isEvictableKey', 'removeLastAccessedKey', 'addLastAccessedKey', 'addEvictableKeysToRecentlyAccessedList', 'getKeyForEviction', 'setCollectionKeys', 'getCollectionData', 'hasValueChanged');
}

@@ -88,10 +83,4 @@ /** Get all the storage keys */

}
/**
* Get a cached value from storage
* @param [shouldReindexCache] – This is an LRU cache, and by default accessing a value will make it become last in line to be evicted. This flag can be used to skip that and just access the value directly without side-effects.
*/
get(key, shouldReindexCache = true) {
if (shouldReindexCache) {
this.addToAccessedKeys(key);
}
/** Get a cached value from storage */
get(key) {
return this.storageMap[key];

@@ -105,3 +94,2 @@ }

this.addKey(key);
this.addToAccessedKeys(key);
// When a key is explicitly set in cache, we can remove it from the list of nullish keys,

@@ -142,3 +130,2 @@ // since it will either be set to a non nullish value or removed from the cache completely.

this.storageKeys.delete(key);
this.recentKeys.delete(key);
OnyxKeys_1.default.deregisterMemberKey(key);

@@ -160,3 +147,2 @@ }

this.addKey(key);
this.addToAccessedKeys(key);
const collectionKey = OnyxKeys_1.default.getCollectionKey(key);

@@ -210,44 +196,5 @@ if (value === null || value === undefined) {

}
/** Adds a key to the top of the recently accessed keys */
addToAccessedKeys(key) {
this.recentKeys.delete(key);
this.recentKeys.add(key);
}
/** Remove keys that don't fall into the range of recently used keys */
removeLeastRecentlyUsedKeys() {
const numKeysToRemove = this.recentKeys.size - this.maxRecentKeysSize;
if (numKeysToRemove <= 0) {
return;
}
const iterator = this.recentKeys.values();
const keysToRemove = [];
const recentKeysArray = Array.from(this.recentKeys);
const mostRecentKey = recentKeysArray[recentKeysArray.length - 1];
let iterResult = iterator.next();
while (!iterResult.done) {
const key = iterResult.value;
// Don't consider the most recently accessed key for eviction
// This ensures we don't immediately evict a key we just added
if (key !== undefined && key !== mostRecentKey && this.isEvictableKey(key)) {
keysToRemove.push(key);
}
iterResult = iterator.next();
}
for (const key of keysToRemove) {
delete this.storageMap[key];
// Remove from collection data cache if this is a collection member
const collectionKey = OnyxKeys_1.default.getCollectionKey(key);
if (collectionKey && this.collectionData[collectionKey]) {
delete this.collectionData[collectionKey][key];
}
this.recentKeys.delete(key);
}
}
/** Set the recent keys list size */
setRecentKeysLimit(limit) {
this.maxRecentKeysSize = limit;
}
/** Check if the value has changed */
hasValueChanged(key, value) {
const currentValue = this.get(key, false);
const currentValue = this.get(key);
return !(0, fast_equals_1.deepEqual)(currentValue, value);

@@ -263,8 +210,2 @@ }

/**
* Get the eviction block list that prevents keys from being evicted
*/
getEvictionBlocklist() {
return this.evictionBlocklist;
}
/**
* Checks to see if this key has been flagged as safe for removal.

@@ -316,11 +257,8 @@ * @param testKey - Key to check

/**
* Finds a key that can be safely evicted
* Finds the least recently accessed key that can be safely evicted from storage.
*/
getKeyForEviction() {
for (const key of this.recentlyAccessedKeys) {
if (!this.evictionBlocklist[key]) {
return key;
}
}
return undefined;
// recentlyAccessedKeys is ordered from least to most recently accessed,
// so the first element is the best candidate for eviction.
return this.recentlyAccessedKeys.values().next().value;
}

@@ -327,0 +265,0 @@ /**

@@ -75,11 +75,2 @@ import type { ConnectOptions } from './Onyx';

refreshSessionID(): void;
/**
* Adds the connection to the eviction block list. Connections added to this list can never be evicted.
* */
addToEvictionBlockList(connection: Connection): void;
/**
* Removes a connection previously added to this list
* which will enable it to be evicted again.
*/
removeFromEvictionBlockList(connection: Connection): void;
}

@@ -86,0 +77,0 @@ declare const connectionManager: OnyxConnectionManager;

@@ -44,3 +44,2 @@ "use strict";

const Str = __importStar(require("./Str"));
const OnyxCache_1 = __importDefault(require("./OnyxCache"));
const OnyxSnapshotCache_1 = __importDefault(require("./OnyxSnapshotCache"));

@@ -56,3 +55,3 @@ /**

// Binds all public methods to prevent problems with `this`.
(0, bindAll_1.default)(this, 'generateConnectionID', 'fireCallbacks', 'connect', 'disconnect', 'disconnectAll', 'refreshSessionID', 'addToEvictionBlockList', 'removeFromEvictionBlockList');
(0, bindAll_1.default)(this, 'generateConnectionID', 'fireCallbacks', 'connect', 'disconnect', 'disconnectAll', 'refreshSessionID');
}

@@ -169,3 +168,2 @@ /**

OnyxUtils_1.default.unsubscribeFromKey(connectionMetadata.subscriptionID);
this.removeFromEvictionBlockList(connection);
this.connectionsMap.delete(connection.id);

@@ -178,7 +176,4 @@ }

disconnectAll() {
for (const [connectionID, connectionMetadata] of this.connectionsMap.entries()) {
for (const connectionMetadata of this.connectionsMap.values()) {
OnyxUtils_1.default.unsubscribeFromKey(connectionMetadata.subscriptionID);
for (const callbackID of connectionMetadata.callbacks.keys()) {
this.removeFromEvictionBlockList({ id: connectionID, callbackID });
}
}

@@ -197,47 +192,4 @@ this.connectionsMap.clear();

}
/**
* Adds the connection to the eviction block list. Connections added to this list can never be evicted.
* */
addToEvictionBlockList(connection) {
var _a;
if (!connection) {
Logger.logInfo(`[ConnectionManager] Attempted to add connection to eviction block list passing an undefined connection object.`);
return;
}
const connectionMetadata = this.connectionsMap.get(connection.id);
if (!connectionMetadata) {
Logger.logInfo(`[ConnectionManager] Attempted to add connection to eviction block list but no connection was found.`);
return;
}
const evictionBlocklist = OnyxCache_1.default.getEvictionBlocklist();
if (!evictionBlocklist[connectionMetadata.onyxKey]) {
evictionBlocklist[connectionMetadata.onyxKey] = [];
}
(_a = evictionBlocklist[connectionMetadata.onyxKey]) === null || _a === void 0 ? void 0 : _a.push(`${connection.id}_${connection.callbackID}`);
}
/**
* Removes a connection previously added to this list
* which will enable it to be evicted again.
*/
removeFromEvictionBlockList(connection) {
var _a, _b, _c;
if (!connection) {
Logger.logInfo(`[ConnectionManager] Attempted to remove connection from eviction block list passing an undefined connection object.`);
return;
}
const connectionMetadata = this.connectionsMap.get(connection.id);
if (!connectionMetadata) {
Logger.logInfo(`[ConnectionManager] Attempted to remove connection from eviction block list but no connection was found.`);
return;
}
const evictionBlocklist = OnyxCache_1.default.getEvictionBlocklist();
evictionBlocklist[connectionMetadata.onyxKey] =
(_b = (_a = evictionBlocklist[connectionMetadata.onyxKey]) === null || _a === void 0 ? void 0 : _a.filter((evictionKey) => evictionKey !== `${connection.id}_${connection.callbackID}`)) !== null && _b !== void 0 ? _b : [];
// Remove the key if there are no more subscribers.
if (((_c = evictionBlocklist[connectionMetadata.onyxKey]) === null || _c === void 0 ? void 0 : _c.length) === 0) {
delete evictionBlocklist[connectionMetadata.onyxKey];
}
}
}
const connectionManager = new OnyxConnectionManager();
exports.default = connectionManager;

@@ -43,3 +43,3 @@ import type { OnyxKey, OnyxValue } from './types';

*
* Other options like `canEvict` and `reuseConnection` don't affect the data transformation
* Other options like `reuseConnection` don't affect the data transformation
* or timing behavior of getSnapshot, so they're excluded from the cache key for better cache hit rates.

@@ -46,0 +46,0 @@ */

@@ -40,3 +40,3 @@ "use strict";

*
* Other options like `canEvict` and `reuseConnection` don't affect the data transformation
* Other options like `reuseConnection` don't affect the data transformation
* or timing behavior of getSnapshot, so they're excluded from the cache key for better cache hit rates.

@@ -43,0 +43,0 @@ */

@@ -131,7 +131,2 @@ import type { ValueOf } from 'type-fest';

/**
* We check to see if this key is flagged as safe for eviction and add it to the recentlyAccessedKeys list so that when we
* run out of storage the least recently accessed key can be removed.
*/
declare function addKeyToRecentlyAccessedIfNeeded<TKey extends OnyxKey>(key: TKey): void;
/**
* Gets the data for a given an array of matching keys, combines them into an object, and sends the result back to the subscriber.

@@ -316,3 +311,2 @@ */

deleteKeyBySubscriptions: typeof deleteKeyBySubscriptions;
addKeyToRecentlyAccessedIfNeeded: typeof addKeyToRecentlyAccessedIfNeeded;
reduceCollectionWithSelector: typeof reduceCollectionWithSelector;

@@ -319,0 +313,0 @@ updateSnapshots: typeof updateSnapshots;

@@ -337,12 +337,6 @@ import type { Merge } from 'type-fest';

* This is an array of keys (individual or collection patterns) that when provided to Onyx are flagged
* as "safe" for removal. Any components subscribing to these keys must also implement a canEvict option. See the README for more info.
* as "safe" for removal.
*/
evictableKeys?: OnyxKey[];
/**
* Sets how many recent keys should we try to keep in cache
* Setting this to 0 would practically mean no cache
* We try to free cache when we connect to a safe eviction key
*/
maxCachedKeysCount?: number;
/**
* Auto synchronize storage events between multiple instances

@@ -349,0 +343,0 @@ * of Onyx running in different tabs/windows. Defaults to true for platforms that support local storage (web/desktop)

@@ -6,6 +6,2 @@ import type { DependencyList } from 'react';

/**
* Determines if this key in this subscription is safe to be evicted.
*/
canEvict?: boolean;
/**
* If set to `false`, then no data will be prefilled into the component.

@@ -12,0 +8,0 @@ * @deprecated This param is going to be removed soon. Use RAM-only keys instead.

@@ -135,16 +135,2 @@ "use strict";

}, [...dependencies]);
const checkEvictableKey = (0, react_1.useCallback)(() => {
if ((options === null || options === void 0 ? void 0 : options.canEvict) === undefined || !connectionRef.current) {
return;
}
if (!OnyxCache_1.default.isEvictableKey(key)) {
throw new Error(`canEvict can't be used on key '${key}'. This key must explicitly be flagged as safe for removal by adding it to Onyx.init({evictableKeys: []}).`);
}
if (options.canEvict) {
OnyxConnectionManager_1.default.removeFromEvictionBlockList(connectionRef.current);
}
else {
OnyxConnectionManager_1.default.addToEvictionBlockList(connectionRef.current);
}
}, [key, options === null || options === void 0 ? void 0 : options.canEvict]);
// Tracks the last memoizedSelector reference that getSnapshot() has computed with.

@@ -266,3 +252,2 @@ // When the selector changes, this mismatch forces getSnapshot() to re-evaluate

});
checkEvictableKey();
return () => {

@@ -277,6 +262,3 @@ if (!connectionRef.current) {

};
}, [key, options === null || options === void 0 ? void 0 : options.initWithStoredValues, options === null || options === void 0 ? void 0 : options.reuseConnection, checkEvictableKey]);
(0, react_1.useEffect)(() => {
checkEvictableKey();
}, [checkEvictableKey]);
}, [key, options === null || options === void 0 ? void 0 : options.initWithStoredValues, options === null || options === void 0 ? void 0 : options.reuseConnection]);
const result = (0, react_1.useSyncExternalStore)(subscribe, getSnapshot);

@@ -283,0 +265,0 @@ return result;

{
"name": "react-native-onyx",
"version": "3.0.62",
"version": "3.0.63",
"author": "Expensify, Inc.",

@@ -5,0 +5,0 @@ "homepage": "https://expensify.com",

@@ -317,16 +317,13 @@ # `react-native-onyx`

# Cache Eviction
# Storage Eviction
Different platforms come with varying storage capacities and Onyx has a way to gracefully fail when those storage limits are encountered. When Onyx fails to set or modify a key the following steps are taken:
1. Onyx looks at a list of recently accessed keys (access is defined as subscribed to or modified) and locates the key that was least recently accessed
2. It then deletes this key and retries the original operation
1. Onyx looks at a list of evictable keys ordered by recent access and locates the least recently accessed one
2. It then deletes this key from both cache and storage, and retries the original operation
3. This process repeats up to 5 times until the write succeeds or no more evictable keys are available
By default, Onyx will not evict anything from storage and will presume all keys are "unsafe" to remove unless explicitly told otherwise.
**To flag a key as safe for removal:**
- Add the key to the `evictableKeys` option in `Onyx.init(options)`
- Implement `canEvict` in the Onyx config for each component subscribing to a key
- The key will only be deleted when all subscribers return `true` for `canEvict`
**To flag a key as safe for removal**, add the key to the `evictableKeys` option in `Onyx.init(options)`:
e.g.
```js

@@ -338,19 +335,4 @@ Onyx.init({

```js
const ReportActionsView = ({reportID, isActiveReport}) => {
const [reportActions] = useOnyx(
`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}_`,
{canEvict: () => !isActiveReport}
);
Only individual (non-collection) keys matching the `evictableKeys` patterns will be considered for eviction. Collection keys themselves cannot be evicted — only their individual members can.
return (
<View>
{/* Render with reportActions data */}
</View>
);
};
export default ReportActionsView;
```
# Debug mode

@@ -357,0 +339,0 @@

Sorry, the diff of this file is too big to display