react-native-onyx 3.0.115 → 3.0.117

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.
@@ -1,189 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- const lodash_bindall_1 = __importDefault(require("lodash.bindall"));
40
- const Logger = __importStar(require("./Logger"));
41
- const OnyxUtils_1 = __importDefault(require("./OnyxUtils"));
42
- const OnyxKeys_1 = __importDefault(require("./OnyxKeys"));
43
- const Str = __importStar(require("./Str"));
44
- const OnyxSnapshotCache_1 = __importDefault(require("./OnyxSnapshotCache"));
45
- /**
46
- * Manages Onyx connections of `Onyx.connect()` and `useOnyx()` subscribers.
47
- */
48
- class OnyxConnectionManager {
49
- constructor() {
50
- this.connectionsMap = new Map();
51
- this.lastCallbackID = 0;
52
- this.sessionID = Str.guid();
53
- // Binds all public methods to prevent problems with `this`.
54
- (0, lodash_bindall_1.default)(this, 'generateConnectionID', 'fireCallbacks', 'connect', 'disconnect', 'disconnectAll', 'refreshSessionID');
55
- }
56
- /**
57
- * Generates a connection ID based on the `connectOptions` object passed to the function.
58
- *
59
- * The properties used to generate the ID are handpicked for performance reasons and
60
- * according to their purpose and effect they produce in the Onyx connection.
61
- */
62
- generateConnectionID(connectOptions) {
63
- const { key, reuseConnection } = connectOptions;
64
- // The current session ID is appended to the connection ID so we can have different connections
65
- // after an `Onyx.clear()` operation.
66
- let suffix = `,sessionID=${this.sessionID}`;
67
- // We will generate a unique ID when `reuseConnection` is `false`, which means the subscriber
68
- // explicitly wants the connection to not be reused. Collection-root subscriptions are now always
69
- // snapshot mode, so they can be reused like any other connection.
70
- if (reuseConnection === false) {
71
- suffix += `,uniqueID=${Str.guid()}`;
72
- }
73
- return `onyxKey=${key}${suffix}`;
74
- }
75
- /**
76
- * Fires all the subscribers callbacks associated with that connection ID.
77
- */
78
- fireCallbacks(connectionID) {
79
- const connection = this.connectionsMap.get(connectionID);
80
- if (!connection) {
81
- return;
82
- }
83
- for (const callback of connection.callbacks.values()) {
84
- try {
85
- if (OnyxKeys_1.default.isCollectionKey(connection.onyxKey)) {
86
- callback(connection.cachedCallbackValue, connection.cachedCallbackKey);
87
- }
88
- else {
89
- callback(connection.cachedCallbackValue, connection.cachedCallbackKey);
90
- }
91
- }
92
- catch (error) {
93
- Logger.logAlert(`[ConnectionManager] Subscriber callback threw an error for key '${connection.onyxKey}': ${String(error)}`);
94
- }
95
- }
96
- }
97
- /**
98
- * Connects to an Onyx key given the options passed and listens to its changes.
99
- *
100
- * @param connectOptions The options object that will define the behavior of the connection.
101
- * @returns The connection object to use when calling `disconnect()`.
102
- */
103
- connect(connectOptions) {
104
- const connectionID = this.generateConnectionID(connectOptions);
105
- let connectionMetadata = this.connectionsMap.get(connectionID);
106
- let subscriptionID;
107
- const callbackID = String(this.lastCallbackID++);
108
- // If there is no connection yet for that connection ID, we create a new one.
109
- if (!connectionMetadata) {
110
- const callback = (value, key) => {
111
- const createdConnection = this.connectionsMap.get(connectionID);
112
- if (createdConnection) {
113
- // We signal that the first connection was made and now any new subscribers
114
- // can fire their callbacks immediately with the cached value when connecting.
115
- createdConnection.isConnectionMade = true;
116
- createdConnection.cachedCallbackValue = value;
117
- createdConnection.cachedCallbackKey = key;
118
- this.fireCallbacks(connectionID);
119
- }
120
- };
121
- subscriptionID = OnyxUtils_1.default.subscribeToKey(Object.assign(Object.assign({}, connectOptions), { callback }));
122
- connectionMetadata = {
123
- subscriptionID,
124
- onyxKey: connectOptions.key,
125
- isConnectionMade: false,
126
- callbacks: new Map(),
127
- };
128
- this.connectionsMap.set(connectionID, connectionMetadata);
129
- }
130
- // We add the subscriber's callback to the list of callbacks associated with this connection.
131
- if (connectOptions.callback) {
132
- connectionMetadata.callbacks.set(callbackID, connectOptions.callback);
133
- }
134
- // If the first connection is already made we want any new subscribers to receive the cached callback value immediately.
135
- if (connectionMetadata.isConnectionMade) {
136
- // Defer the callback execution to the next tick of the event loop.
137
- // This ensures that the current execution flow completes and the result connection object is available when the callback fires.
138
- Promise.resolve().then(() => {
139
- var _a;
140
- (_a = connectOptions.callback) === null || _a === void 0 ? void 0 : _a.call(connectOptions, connectionMetadata.cachedCallbackValue, connectionMetadata.cachedCallbackKey);
141
- });
142
- }
143
- return { id: connectionID, callbackID };
144
- }
145
- /**
146
- * Disconnects and removes the listener from the Onyx key.
147
- *
148
- * @param connection Connection object returned by calling `connect()`.
149
- */
150
- disconnect(connection) {
151
- if (!connection) {
152
- Logger.logInfo(`[ConnectionManager] Attempted to disconnect passing an undefined connection object.`);
153
- return;
154
- }
155
- const connectionMetadata = this.connectionsMap.get(connection.id);
156
- if (!connectionMetadata) {
157
- Logger.logInfo(`[ConnectionManager] Attempted to disconnect but no connection was found.`);
158
- return;
159
- }
160
- // Removes the callback from the connection's callbacks map.
161
- connectionMetadata.callbacks.delete(connection.callbackID);
162
- // If the connection's callbacks map is empty we can safely unsubscribe from the Onyx key.
163
- if (connectionMetadata.callbacks.size === 0) {
164
- OnyxUtils_1.default.unsubscribeFromKey(connectionMetadata.subscriptionID);
165
- this.connectionsMap.delete(connection.id);
166
- }
167
- }
168
- /**
169
- * Disconnect all subscribers from Onyx.
170
- */
171
- disconnectAll() {
172
- for (const connectionMetadata of this.connectionsMap.values()) {
173
- OnyxUtils_1.default.unsubscribeFromKey(connectionMetadata.subscriptionID);
174
- }
175
- this.connectionsMap.clear();
176
- // Clear snapshot cache when all connections are disconnected
177
- OnyxSnapshotCache_1.default.clear();
178
- }
179
- /**
180
- * Refreshes the connection manager's session ID.
181
- */
182
- refreshSessionID() {
183
- this.sessionID = Str.guid();
184
- // Clear snapshot cache when session refreshes to avoid stale cache issues
185
- OnyxSnapshotCache_1.default.clear();
186
- }
187
- }
188
- const connectionManager = new OnyxConnectionManager();
189
- exports.default = connectionManager;
@@ -1,75 +0,0 @@
1
- import type { OnyxKey, OnyxValue } from './types';
2
- import type { UseOnyxOptions, UseOnyxResult, UseOnyxSelector } from './useOnyx';
3
- /**
4
- * Manages snapshot caching for useOnyx hook performance optimization.
5
- * Handles selector function tracking and memoized getSnapshot results.
6
- */
7
- declare class OnyxSnapshotCache {
8
- /**
9
- * Snapshot cache is a two-level map. The top-level keys are Onyx keys. The top-level values maps.
10
- * The second-level keys are a custom composite string defined by this.registerConsumer. These represent a unique useOnyx config, which is not fully represented by the Onyx key alone.
11
- * The reason we have two levels is for performance: not to make cache access faster, but to make cache invalidation faster.
12
- * We can invalidate the snapshot cache for a given Onyx key with one map.delete operation on the top-level map, rather than having to loop through a large single-level map and delete any matching keys.
13
- */
14
- private snapshotCache;
15
- /**
16
- * Maps selector functions to unique IDs for cache key generation
17
- */
18
- private selectorIDMap;
19
- /**
20
- * Counter for generating incremental selector IDs
21
- */
22
- private selectorIDCounter;
23
- /**
24
- * Reference counting for cache keys to enable automatic cleanup.
25
- * Maps cache key (string) to number of consumers using it.
26
- */
27
- private cacheKeyRefCounts;
28
- constructor();
29
- /**
30
- * Generate unique ID for selector functions using incrementing numbers
31
- */
32
- getSelectorID<TKey extends OnyxKey, TReturnValue>(selector: UseOnyxSelector<TKey, TReturnValue>): number;
33
- /**
34
- * Register a consumer for a cache key and return the cache key.
35
- * Generates cache key and increments reference counter.
36
- *
37
- * The properties used to generate the cache key are handpicked for performance reasons and
38
- * according to their purpose and effect they produce in the useOnyx hook behavior:
39
- *
40
- * - `selector`: Different selectors produce different results, so each selector needs its own cache entry
41
- *
42
- * Other options like `reuseConnection` don't affect the data transformation
43
- * or timing behavior of getSnapshot, so they're excluded from the cache key for better cache hit rates.
44
- */
45
- registerConsumer<TKey extends OnyxKey, TReturnValue>(key: TKey, options: Pick<UseOnyxOptions<TKey, TReturnValue>, 'selector'>): string;
46
- /**
47
- * Deregister a consumer for a cache key.
48
- * Decrements reference counter and removes cache entry if no consumers remain.
49
- */
50
- deregisterConsumer(key: OnyxKey, cacheKey: string): void;
51
- /**
52
- * Get cached snapshot result for a key and cache key combination
53
- */
54
- getCachedResult<TResult extends UseOnyxResult<OnyxValue<OnyxKey>>>(key: OnyxKey, cacheKey: string): TResult | undefined;
55
- /**
56
- * Set cached snapshot result for a key and cache key combination
57
- */
58
- setCachedResult<TResult extends UseOnyxResult<OnyxValue<OnyxKey>>>(key: OnyxKey, cacheKey: string, result: TResult): void;
59
- /**
60
- * Selective cache invalidation to prevent data unavailability
61
- * Collection members invalidate upward, collections don't cascade downward
62
- */
63
- invalidateForKey(keyToInvalidate: OnyxKey): void;
64
- /**
65
- * Clear all snapshot cache
66
- */
67
- clear(): void;
68
- /**
69
- * Clear selector ID mappings (useful for testing)
70
- */
71
- clearSelectorIds(): void;
72
- }
73
- declare const onyxSnapshotCache: OnyxSnapshotCache;
74
- export default onyxSnapshotCache;
75
- export { OnyxSnapshotCache };
@@ -1,125 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.OnyxSnapshotCache = void 0;
7
- const OnyxKeys_1 = __importDefault(require("./OnyxKeys"));
8
- /**
9
- * Manages snapshot caching for useOnyx hook performance optimization.
10
- * Handles selector function tracking and memoized getSnapshot results.
11
- */
12
- class OnyxSnapshotCache {
13
- constructor() {
14
- this.snapshotCache = new Map();
15
- this.selectorIDMap = new WeakMap();
16
- this.selectorIDCounter = 0;
17
- this.cacheKeyRefCounts = new Map();
18
- }
19
- /**
20
- * Generate unique ID for selector functions using incrementing numbers
21
- */
22
- getSelectorID(selector) {
23
- const typedSelector = selector;
24
- const existingID = this.selectorIDMap.get(typedSelector);
25
- if (existingID !== undefined) {
26
- return existingID;
27
- }
28
- const id = this.selectorIDCounter++;
29
- this.selectorIDMap.set(typedSelector, id);
30
- return id;
31
- }
32
- /**
33
- * Register a consumer for a cache key and return the cache key.
34
- * Generates cache key and increments reference counter.
35
- *
36
- * The properties used to generate the cache key are handpicked for performance reasons and
37
- * according to their purpose and effect they produce in the useOnyx hook behavior:
38
- *
39
- * - `selector`: Different selectors produce different results, so each selector needs its own cache entry
40
- *
41
- * Other options like `reuseConnection` don't affect the data transformation
42
- * or timing behavior of getSnapshot, so they're excluded from the cache key for better cache hit rates.
43
- */
44
- registerConsumer(key, options) {
45
- var _a;
46
- const selectorID = (options === null || options === void 0 ? void 0 : options.selector) ? this.getSelectorID(options.selector) : 'no_selector';
47
- const cacheKey = `${key}_${selectorID}`;
48
- // Increment reference count for this cache key
49
- const currentCount = (_a = this.cacheKeyRefCounts.get(cacheKey)) !== null && _a !== void 0 ? _a : 0;
50
- this.cacheKeyRefCounts.set(cacheKey, currentCount + 1);
51
- return cacheKey;
52
- }
53
- /**
54
- * Deregister a consumer for a cache key.
55
- * Decrements reference counter and removes cache entry if no consumers remain.
56
- */
57
- deregisterConsumer(key, cacheKey) {
58
- var _a;
59
- const currentCount = (_a = this.cacheKeyRefCounts.get(cacheKey)) !== null && _a !== void 0 ? _a : 0;
60
- if (currentCount <= 1) {
61
- // Last consumer - remove from reference counter and cache
62
- this.cacheKeyRefCounts.delete(cacheKey);
63
- // Remove from snapshot cache
64
- const keyCache = this.snapshotCache.get(key);
65
- if (keyCache) {
66
- keyCache.delete(cacheKey);
67
- // If this was the last cache entry for this Onyx key, remove the key entirely
68
- if (keyCache.size === 0) {
69
- this.snapshotCache.delete(key);
70
- }
71
- }
72
- }
73
- else {
74
- // Still has other consumers - just decrement count
75
- this.cacheKeyRefCounts.set(cacheKey, currentCount - 1);
76
- }
77
- }
78
- /**
79
- * Get cached snapshot result for a key and cache key combination
80
- */
81
- getCachedResult(key, cacheKey) {
82
- const keyCache = this.snapshotCache.get(key);
83
- return keyCache === null || keyCache === void 0 ? void 0 : keyCache.get(cacheKey);
84
- }
85
- /**
86
- * Set cached snapshot result for a key and cache key combination
87
- */
88
- setCachedResult(key, cacheKey, result) {
89
- let keyCache = this.snapshotCache.get(key);
90
- if (!keyCache) {
91
- keyCache = new Map();
92
- this.snapshotCache.set(key, keyCache);
93
- }
94
- keyCache.set(cacheKey, result);
95
- }
96
- /**
97
- * Selective cache invalidation to prevent data unavailability
98
- * Collection members invalidate upward, collections don't cascade downward
99
- */
100
- invalidateForKey(keyToInvalidate) {
101
- // Always invalidate the exact key
102
- this.snapshotCache.delete(keyToInvalidate);
103
- // Check if the key is a collection member and invalidate the collection base key
104
- const collectionBaseKey = OnyxKeys_1.default.getCollectionKey(keyToInvalidate);
105
- if (collectionBaseKey) {
106
- this.snapshotCache.delete(collectionBaseKey);
107
- }
108
- }
109
- /**
110
- * Clear all snapshot cache
111
- */
112
- clear() {
113
- this.snapshotCache.clear();
114
- }
115
- /**
116
- * Clear selector ID mappings (useful for testing)
117
- */
118
- clearSelectorIds() {
119
- this.selectorIDCounter = 0;
120
- }
121
- }
122
- exports.OnyxSnapshotCache = OnyxSnapshotCache;
123
- // Create and export a singleton instance
124
- const onyxSnapshotCache = new OnyxSnapshotCache();
125
- exports.default = onyxSnapshotCache;
@@ -1,18 +0,0 @@
1
- /**
2
- * Wraps a selector function so that:
3
- * - Calling the wrapper with the same input reference twice short-circuits to the cached output
4
- * (cheap `===` check, no recompute).
5
- * - Calling with a different input that produces a deep-equal output returns the *previous*
6
- * output reference, so downstream `===` comparisons treat it as unchanged.
7
- *
8
- * This is the minimum needed for `useSyncExternalStore` to not loop when consumers pass
9
- * inline selectors that allocate fresh objects on every call (e.g. `(e) => ({id: e?.id})`):
10
- * without the deep-equal fallback, every `getSnapshot` would return a new reference and React
11
- * would re-render (or throw "getSnapshot should be cached") indefinitely.
12
- *
13
- * Stateful by design — each call to `createMemoizedSelector` produces an independent wrapper
14
- * with its own `lastInput`/`lastOutput` cache, so a wrapper must not be shared across
15
- * subscriptions that can see different inputs.
16
- */
17
- declare function createMemoizedSelector<TInput, TOutput>(selector: (input: TInput) => TOutput): (input: TInput) => TOutput;
18
- export default createMemoizedSelector;
@@ -1,37 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const fast_equals_1 = require("fast-equals");
4
- /**
5
- * Wraps a selector function so that:
6
- * - Calling the wrapper with the same input reference twice short-circuits to the cached output
7
- * (cheap `===` check, no recompute).
8
- * - Calling with a different input that produces a deep-equal output returns the *previous*
9
- * output reference, so downstream `===` comparisons treat it as unchanged.
10
- *
11
- * This is the minimum needed for `useSyncExternalStore` to not loop when consumers pass
12
- * inline selectors that allocate fresh objects on every call (e.g. `(e) => ({id: e?.id})`):
13
- * without the deep-equal fallback, every `getSnapshot` would return a new reference and React
14
- * would re-render (or throw "getSnapshot should be cached") indefinitely.
15
- *
16
- * Stateful by design — each call to `createMemoizedSelector` produces an independent wrapper
17
- * with its own `lastInput`/`lastOutput` cache, so a wrapper must not be shared across
18
- * subscriptions that can see different inputs.
19
- */
20
- function createMemoizedSelector(selector) {
21
- let lastInput;
22
- let lastOutput;
23
- let hasComputed = false;
24
- return (input) => {
25
- if (hasComputed && lastInput === input) {
26
- return lastOutput;
27
- }
28
- const next = selector(input);
29
- lastInput = input;
30
- if (!hasComputed || !(0, fast_equals_1.deepEqual)(lastOutput, next)) {
31
- lastOutput = next;
32
- hasComputed = true;
33
- }
34
- return lastOutput;
35
- };
36
- }
37
- exports.default = createMemoizedSelector;
@@ -1,5 +0,0 @@
1
- /**
2
- * Identity-pair-memoized shallowEqual: same (a, b) references → cached verdict, no walk.
3
- */
4
- declare function memoizedShallowEqual(a: unknown, b: unknown): boolean;
5
- export default memoizedShallowEqual;
@@ -1,34 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const fast_equals_1 = require("fast-equals");
4
- /**
5
- * Memoizes shallowEqual verdicts by the identity of the compared objects. Onyx values are
6
- * treated as immutable (merge/set replace objects, never mutate), so a (prev, next) reference
7
- * pair always yields the same verdict. In the hot case — N no-selector hooks on the same big
8
- * key — every hook compares the exact same two cache-owned objects, so the first hook pays for
9
- * the O(keys) walk and the rest resolve in O(1). WeakMap keys make stale entries impossible to
10
- * read (lookup requires holding both exact objects) and let GC reclaim them.
11
- */
12
- const shallowEqualVerdicts = new WeakMap();
13
- /**
14
- * Identity-pair-memoized shallowEqual: same (a, b) references → cached verdict, no walk.
15
- */
16
- function memoizedShallowEqual(a, b) {
17
- // Only object pairs are memoizable (WeakMap keys) — anything else is O(1) to compare anyway.
18
- if (typeof a !== 'object' || a === null || typeof b !== 'object' || b === null) {
19
- return (0, fast_equals_1.shallowEqual)(a, b);
20
- }
21
- let verdictsForA = shallowEqualVerdicts.get(a);
22
- if (!verdictsForA) {
23
- verdictsForA = new WeakMap();
24
- shallowEqualVerdicts.set(a, verdictsForA);
25
- }
26
- const cachedVerdict = verdictsForA.get(b);
27
- if (cachedVerdict !== undefined) {
28
- return cachedVerdict;
29
- }
30
- const verdict = (0, fast_equals_1.shallowEqual)(a, b);
31
- verdictsForA.set(b, verdict);
32
- return verdict;
33
- }
34
- exports.default = memoizedShallowEqual;