UNPKG

276 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
7var react = _interopDefault(require('react'));
8var reactDom = _interopDefault(require('react-dom'));
9
10/**
11 * Copyright (c) Meta Platforms, Inc. and affiliates.
12 *
13 * This source code is licensed under the MIT license found in the
14 * LICENSE file in the root directory of this source tree.
15 *
16 *
17 * @format
18 * @oncall recoil
19 */
20
21function err(message) {
22 const error = new Error(message); // In V8, Error objects keep the closure scope chain alive until the
23 // err.stack property is accessed.
24
25 if (error.stack === undefined) {
26 // IE sets the stack only if error is thrown
27 try {
28 throw error;
29 } catch (_) {} // eslint-disable-line fb-www/no-unused-catch-bindings, no-empty
30
31 }
32
33 return error;
34}
35
36var err_1 = err;
37
38// @oss-only
39
40
41var Recoil_err = err_1;
42
43/**
44 * Copyright (c) Meta Platforms, Inc. and affiliates.
45 *
46 * This source code is licensed under the MIT license found in the
47 * LICENSE file in the root directory of this source tree.
48 *
49 *
50 * @format
51 * @oncall recoil
52 */
53
54// Split declaration and implementation to allow this function to pretend to
55// check for actual instance of Promise instead of something with a `then`
56// method.
57// eslint-disable-next-line no-redeclare
58function isPromise(p) {
59 return !!p && typeof p.then === 'function';
60}
61
62var Recoil_isPromise = isPromise;
63
64function nullthrows(x, message) {
65 if (x != null) {
66 return x;
67 }
68
69 throw Recoil_err(message !== null && message !== void 0 ? message : 'Got unexpected null or undefined');
70}
71
72var Recoil_nullthrows = nullthrows;
73
74function _defineProperty(obj, key, value) {
75 if (key in obj) {
76 Object.defineProperty(obj, key, {
77 value: value,
78 enumerable: true,
79 configurable: true,
80 writable: true
81 });
82 } else {
83 obj[key] = value;
84 }
85
86 return obj;
87}
88
89class BaseLoadable {
90 getValue() {
91 throw Recoil_err('BaseLoadable');
92 }
93
94 toPromise() {
95 throw Recoil_err('BaseLoadable');
96 }
97
98 valueMaybe() {
99 throw Recoil_err('BaseLoadable');
100 }
101
102 valueOrThrow() {
103 // $FlowFixMe[prop-missing]
104 throw Recoil_err(`Loadable expected value, but in "${this.state}" state`);
105 }
106
107 promiseMaybe() {
108 throw Recoil_err('BaseLoadable');
109 }
110
111 promiseOrThrow() {
112 // $FlowFixMe[prop-missing]
113 throw Recoil_err(`Loadable expected promise, but in "${this.state}" state`);
114 }
115
116 errorMaybe() {
117 throw Recoil_err('BaseLoadable');
118 }
119
120 errorOrThrow() {
121 // $FlowFixMe[prop-missing]
122 throw Recoil_err(`Loadable expected error, but in "${this.state}" state`);
123 }
124
125 is(other) {
126 // $FlowFixMe[prop-missing]
127 return other.state === this.state && other.contents === this.contents;
128 }
129
130 map(_map) {
131 throw Recoil_err('BaseLoadable');
132 }
133
134}
135
136class ValueLoadable extends BaseLoadable {
137 constructor(value) {
138 super();
139
140 _defineProperty(this, "state", 'hasValue');
141
142 _defineProperty(this, "contents", void 0);
143
144 this.contents = value;
145 }
146
147 getValue() {
148 return this.contents;
149 }
150
151 toPromise() {
152 return Promise.resolve(this.contents);
153 }
154
155 valueMaybe() {
156 return this.contents;
157 }
158
159 valueOrThrow() {
160 return this.contents;
161 }
162
163 promiseMaybe() {
164 return undefined;
165 }
166
167 errorMaybe() {
168 return undefined;
169 }
170
171 map(map) {
172 try {
173 const next = map(this.contents);
174 return Recoil_isPromise(next) ? loadableWithPromise(next) : isLoadable(next) ? next : loadableWithValue(next);
175 } catch (e) {
176 return Recoil_isPromise(e) ? // If we "suspended", then try again.
177 // errors and subsequent retries will be handled in 'loading' case
178 // $FlowFixMe[prop-missing]
179 loadableWithPromise(e.next(() => this.map(map))) : loadableWithError(e);
180 }
181 }
182
183}
184
185class ErrorLoadable extends BaseLoadable {
186 constructor(error) {
187 super();
188
189 _defineProperty(this, "state", 'hasError');
190
191 _defineProperty(this, "contents", void 0);
192
193 this.contents = error;
194 }
195
196 getValue() {
197 throw this.contents;
198 }
199
200 toPromise() {
201 return Promise.reject(this.contents);
202 }
203
204 valueMaybe() {
205 return undefined;
206 }
207
208 promiseMaybe() {
209 return undefined;
210 }
211
212 errorMaybe() {
213 return this.contents;
214 }
215
216 errorOrThrow() {
217 return this.contents;
218 }
219
220 map(_map) {
221 // $FlowIssue[incompatible-return]
222 return this;
223 }
224
225}
226
227class LoadingLoadable extends BaseLoadable {
228 constructor(promise) {
229 super();
230
231 _defineProperty(this, "state", 'loading');
232
233 _defineProperty(this, "contents", void 0);
234
235 this.contents = promise;
236 }
237
238 getValue() {
239 throw this.contents;
240 }
241
242 toPromise() {
243 return this.contents;
244 }
245
246 valueMaybe() {
247 return undefined;
248 }
249
250 promiseMaybe() {
251 return this.contents;
252 }
253
254 promiseOrThrow() {
255 return this.contents;
256 }
257
258 errorMaybe() {
259 return undefined;
260 }
261
262 map(map) {
263 return loadableWithPromise(this.contents.then(value => {
264 const next = map(value);
265
266 if (isLoadable(next)) {
267 const nextLoadable = next;
268
269 switch (nextLoadable.state) {
270 case 'hasValue':
271 return nextLoadable.contents;
272
273 case 'hasError':
274 throw nextLoadable.contents;
275
276 case 'loading':
277 return nextLoadable.contents;
278 }
279 } // $FlowIssue[incompatible-return]
280
281
282 return next;
283 }) // $FlowFixMe[incompatible-call]
284 .catch(e => {
285 if (Recoil_isPromise(e)) {
286 // we were "suspended," try again
287 return e.then(() => this.map(map).contents);
288 }
289
290 throw e;
291 }));
292 }
293
294}
295
296function loadableWithValue(value) {
297 return Object.freeze(new ValueLoadable(value));
298}
299
300function loadableWithError(error) {
301 return Object.freeze(new ErrorLoadable(error));
302}
303
304function loadableWithPromise(promise) {
305 return Object.freeze(new LoadingLoadable(promise));
306}
307
308function loadableLoading() {
309 return Object.freeze(new LoadingLoadable(new Promise(() => {})));
310}
311
312function loadableAllArray(inputs) {
313 return inputs.every(i => i.state === 'hasValue') ? loadableWithValue(inputs.map(i => i.contents)) : inputs.some(i => i.state === 'hasError') ? loadableWithError(Recoil_nullthrows(inputs.find(i => i.state === 'hasError'), 'Invalid loadable passed to loadableAll').contents) : loadableWithPromise(Promise.all(inputs.map(i => i.contents)));
314}
315
316function loadableAll(inputs) {
317 const unwrapedInputs = Array.isArray(inputs) ? inputs : Object.getOwnPropertyNames(inputs).map(key => inputs[key]);
318 const normalizedInputs = unwrapedInputs.map(x => isLoadable(x) ? x : Recoil_isPromise(x) ? loadableWithPromise(x) : loadableWithValue(x));
319 const output = loadableAllArray(normalizedInputs);
320 return Array.isArray(inputs) ? // $FlowIssue[incompatible-return]
321 output : // Object.getOwnPropertyNames() has consistent key ordering with ES6
322 // $FlowIssue[incompatible-call]
323 output.map(outputs => Object.getOwnPropertyNames(inputs).reduce( // $FlowFixMe[invalid-computed-prop]
324 (out, key, idx) => ({ ...out,
325 [key]: outputs[idx]
326 }), {}));
327}
328
329function isLoadable(x) {
330 return x instanceof BaseLoadable;
331}
332
333const LoadableStaticInterface = {
334 of: value => Recoil_isPromise(value) ? loadableWithPromise(value) : isLoadable(value) ? value : loadableWithValue(value),
335 error: error => loadableWithError(error),
336 // $FlowIssue[incompatible-return]
337 loading: () => loadableLoading(),
338 // $FlowIssue[unclear-type]
339 all: loadableAll,
340 isLoadable
341};
342var Recoil_Loadable = {
343 loadableWithValue,
344 loadableWithError,
345 loadableWithPromise,
346 loadableLoading,
347 loadableAll,
348 isLoadable,
349 RecoilLoadable: LoadableStaticInterface
350};
351
352var Recoil_Loadable_1 = Recoil_Loadable.loadableWithValue;
353var Recoil_Loadable_2 = Recoil_Loadable.loadableWithError;
354var Recoil_Loadable_3 = Recoil_Loadable.loadableWithPromise;
355var Recoil_Loadable_4 = Recoil_Loadable.loadableLoading;
356var Recoil_Loadable_5 = Recoil_Loadable.loadableAll;
357var Recoil_Loadable_6 = Recoil_Loadable.isLoadable;
358var Recoil_Loadable_7 = Recoil_Loadable.RecoilLoadable;
359
360var Recoil_Loadable$1 = /*#__PURE__*/Object.freeze({
361 __proto__: null,
362 loadableWithValue: Recoil_Loadable_1,
363 loadableWithError: Recoil_Loadable_2,
364 loadableWithPromise: Recoil_Loadable_3,
365 loadableLoading: Recoil_Loadable_4,
366 loadableAll: Recoil_Loadable_5,
367 isLoadable: Recoil_Loadable_6,
368 RecoilLoadable: Recoil_Loadable_7
369});
370
371const env = {
372 RECOIL_DUPLICATE_ATOM_KEY_CHECKING_ENABLED: true,
373 // Note: RECOIL_GKS_ENABLED settings will only be honored in OSS builds of Recoil
374 RECOIL_GKS_ENABLED: new Set(['recoil_hamt_2020', 'recoil_sync_external_store', 'recoil_suppress_rerender_in_callback', 'recoil_memory_managament_2020'])
375};
376
377function readProcessEnvBooleanFlag(name, set) {
378 var _process$env$name, _process$env$name$toL;
379
380 const sanitizedValue = (_process$env$name = process.env[name]) === null || _process$env$name === void 0 ? void 0 : (_process$env$name$toL = _process$env$name.toLowerCase()) === null || _process$env$name$toL === void 0 ? void 0 : _process$env$name$toL.trim();
381
382 if (sanitizedValue == null || sanitizedValue === '') {
383 return;
384 }
385
386 const allowedValues = ['true', 'false'];
387
388 if (!allowedValues.includes(sanitizedValue)) {
389 throw Recoil_err(`process.env.${name} value must be 'true', 'false', or empty: ${sanitizedValue}`);
390 }
391
392 set(sanitizedValue === 'true');
393}
394
395function readProcessEnvStringArrayFlag(name, set) {
396 var _process$env$name2;
397
398 const sanitizedValue = (_process$env$name2 = process.env[name]) === null || _process$env$name2 === void 0 ? void 0 : _process$env$name2.trim();
399
400 if (sanitizedValue == null || sanitizedValue === '') {
401 return;
402 }
403
404 set(sanitizedValue.split(/\s*,\s*|\s+/));
405}
406/**
407 * Allow NodeJS/NextJS/etc to set the initial state through process.env variable
408 * Note: we don't assume 'process' is available in all runtime environments
409 *
410 * @see https://github.com/facebookexperimental/Recoil/issues/733
411 */
412
413
414function applyProcessEnvFlagOverrides() {
415 var _process;
416
417 // note: this check is needed in addition to the check below, runtime error will occur without it!
418 // eslint-disable-next-line fb-www/typeof-undefined
419 if (typeof process === 'undefined') {
420 return;
421 }
422
423 if (((_process = process) === null || _process === void 0 ? void 0 : _process.env) == null) {
424 return;
425 }
426
427 readProcessEnvBooleanFlag('RECOIL_DUPLICATE_ATOM_KEY_CHECKING_ENABLED', value => {
428 env.RECOIL_DUPLICATE_ATOM_KEY_CHECKING_ENABLED = value;
429 });
430 readProcessEnvStringArrayFlag('RECOIL_GKS_ENABLED', value => {
431 value.forEach(gk => {
432 env.RECOIL_GKS_ENABLED.add(gk);
433 });
434 });
435}
436
437applyProcessEnvFlagOverrides();
438var Recoil_RecoilEnv = env;
439
440function Recoil_gkx_OSS(gk) {
441 return Recoil_RecoilEnv.RECOIL_GKS_ENABLED.has(gk);
442}
443
444Recoil_gkx_OSS.setPass = gk => {
445 Recoil_RecoilEnv.RECOIL_GKS_ENABLED.add(gk);
446};
447
448Recoil_gkx_OSS.setFail = gk => {
449 Recoil_RecoilEnv.RECOIL_GKS_ENABLED.delete(gk);
450};
451
452Recoil_gkx_OSS.clear = () => {
453 Recoil_RecoilEnv.RECOIL_GKS_ENABLED.clear();
454};
455
456var Recoil_gkx = Recoil_gkx_OSS; // @oss-only
457
458/**
459 * Copyright (c) Meta Platforms, Inc. and affiliates.
460 *
461 * This source code is licensed under the MIT license found in the
462 * LICENSE file in the root directory of this source tree.
463 *
464 *
465 * @format
466 * @oncall recoil
467 */
468
469function recoverableViolation(message, _projectName, {
470 error
471} = {}) {
472 if (process.env.NODE_ENV !== "production") {
473 console.error(message, error);
474 }
475
476 return null;
477}
478
479var recoverableViolation_1 = recoverableViolation;
480
481// @oss-only
482
483
484var Recoil_recoverableViolation = recoverableViolation_1;
485
486var _createMutableSource, _useMutableSource, _useSyncExternalStore;
487
488
489
490
491
492
493
494const createMutableSource = // flowlint-next-line unclear-type:off
495(_createMutableSource = react.createMutableSource) !== null && _createMutableSource !== void 0 ? _createMutableSource : react.unstable_createMutableSource;
496const useMutableSource = // flowlint-next-line unclear-type:off
497(_useMutableSource = react.useMutableSource) !== null && _useMutableSource !== void 0 ? _useMutableSource : react.unstable_useMutableSource; // https://github.com/reactwg/react-18/discussions/86
498
499const useSyncExternalStore = // flowlint-next-line unclear-type:off
500(_useSyncExternalStore = react.useSyncExternalStore) !== null && _useSyncExternalStore !== void 0 ? _useSyncExternalStore : // flowlint-next-line unclear-type:off
501react.unstable_useSyncExternalStore;
502let ReactRendererVersionMismatchWarnOnce = false; // Check if the current renderer supports `useSyncExternalStore()`.
503// Since React goes through a proxy dispatcher and the current renderer can
504// change we can't simply check if `React.useSyncExternalStore()` is defined.
505
506function currentRendererSupportsUseSyncExternalStore() {
507 var _ReactCurrentDispatch;
508
509 // $FlowFixMe[incompatible-use]
510 const {
511 ReactCurrentDispatcher,
512 ReactCurrentOwner
513 } =
514 /* $FlowFixMe[prop-missing] This workaround was approved as a safer mechanism
515 * to detect if the current renderer supports useSyncExternalStore()
516 * https://fb.workplace.com/groups/reactjs/posts/9558682330846963/ */
517 react.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
518 const dispatcher = (_ReactCurrentDispatch = ReactCurrentDispatcher === null || ReactCurrentDispatcher === void 0 ? void 0 : ReactCurrentDispatcher.current) !== null && _ReactCurrentDispatch !== void 0 ? _ReactCurrentDispatch : ReactCurrentOwner.currentDispatcher;
519 const isUseSyncExternalStoreSupported = dispatcher.useSyncExternalStore != null;
520
521 if (useSyncExternalStore && !isUseSyncExternalStoreSupported && !ReactRendererVersionMismatchWarnOnce) {
522 ReactRendererVersionMismatchWarnOnce = true;
523 Recoil_recoverableViolation('A React renderer without React 18+ API support is being used with React 18+.');
524 }
525
526 return isUseSyncExternalStoreSupported;
527}
528
529/**
530 * mode: The React API and approach to use for syncing state with React
531 * early: Re-renders from Recoil updates occur:
532 * 1) earlier
533 * 2) in sync with React updates in the same batch
534 * 3) before transaction observers instead of after.
535 * concurrent: Is the current mode compatible with Concurrent Mode and useTransition()
536 */
537function reactMode() {
538 // NOTE: This mode is currently broken with some Suspense cases
539 // see Recoil_selector-test.js
540 if (Recoil_gkx('recoil_transition_support')) {
541 return {
542 mode: 'TRANSITION_SUPPORT',
543 early: true,
544 concurrent: true
545 };
546 }
547
548 if (Recoil_gkx('recoil_sync_external_store') && useSyncExternalStore != null) {
549 return {
550 mode: 'SYNC_EXTERNAL_STORE',
551 early: true,
552 concurrent: false
553 };
554 }
555
556 if (Recoil_gkx('recoil_mutable_source') && useMutableSource != null && typeof window !== 'undefined' && !window.$disableRecoilValueMutableSource_TEMP_HACK_DO_NOT_USE) {
557 return Recoil_gkx('recoil_suppress_rerender_in_callback') ? {
558 mode: 'MUTABLE_SOURCE',
559 early: true,
560 concurrent: true
561 } : {
562 mode: 'MUTABLE_SOURCE',
563 early: false,
564 concurrent: false
565 };
566 }
567
568 return Recoil_gkx('recoil_suppress_rerender_in_callback') ? {
569 mode: 'LEGACY',
570 early: true,
571 concurrent: false
572 } : {
573 mode: 'LEGACY',
574 early: false,
575 concurrent: false
576 };
577} // TODO Need to figure out if there is a standard/open-source equivalent to see if hot module replacement is happening:
578
579
580function isFastRefreshEnabled() {
581 // @fb-only: const {isAcceptingUpdate} = require('__debug');
582 // @fb-only: return typeof isAcceptingUpdate === 'function' && isAcceptingUpdate();
583 return false; // @oss-only
584}
585
586var Recoil_ReactMode = {
587 createMutableSource,
588 useMutableSource,
589 useSyncExternalStore,
590 currentRendererSupportsUseSyncExternalStore,
591 reactMode,
592 isFastRefreshEnabled
593};
594
595/**
596 * Copyright (c) Meta Platforms, Inc. and affiliates.
597 *
598 * This source code is licensed under the MIT license found in the
599 * LICENSE file in the root directory of this source tree.
600 *
601 *
602 * @format
603 * @oncall recoil
604 */
605
606// eslint-disable-next-line no-unused-vars
607class AbstractRecoilValue {
608 constructor(newKey) {
609 _defineProperty(this, "key", void 0);
610
611 this.key = newKey;
612 }
613
614 toJSON() {
615 return {
616 key: this.key
617 };
618 }
619
620}
621
622class RecoilState extends AbstractRecoilValue {}
623
624class RecoilValueReadOnly extends AbstractRecoilValue {}
625
626function isRecoilValue(x) {
627 return x instanceof RecoilState || x instanceof RecoilValueReadOnly;
628}
629
630var Recoil_RecoilValue = {
631 AbstractRecoilValue,
632 RecoilState,
633 RecoilValueReadOnly,
634 isRecoilValue
635};
636
637var Recoil_RecoilValue_1 = Recoil_RecoilValue.AbstractRecoilValue;
638var Recoil_RecoilValue_2 = Recoil_RecoilValue.RecoilState;
639var Recoil_RecoilValue_3 = Recoil_RecoilValue.RecoilValueReadOnly;
640var Recoil_RecoilValue_4 = Recoil_RecoilValue.isRecoilValue;
641
642var Recoil_RecoilValue$1 = /*#__PURE__*/Object.freeze({
643 __proto__: null,
644 AbstractRecoilValue: Recoil_RecoilValue_1,
645 RecoilState: Recoil_RecoilValue_2,
646 RecoilValueReadOnly: Recoil_RecoilValue_3,
647 isRecoilValue: Recoil_RecoilValue_4
648});
649
650/**
651 * Copyright (c) Meta Platforms, Inc. and affiliates.
652 *
653 * This source code is licensed under the MIT license found in the
654 * LICENSE file in the root directory of this source tree.
655 *
656 *
657 * @format
658 * @oncall recoil
659 */
660
661function sprintf(format, ...args) {
662 let index = 0;
663 return format.replace(/%s/g, () => String(args[index++]));
664}
665
666var sprintf_1 = sprintf;
667
668function expectationViolation(format, ...args) {
669 if (process.env.NODE_ENV !== "production") {
670 const message = sprintf_1.call(null, format, ...args);
671 const error = new Error(message);
672 error.name = 'Expectation Violation';
673 console.error(error);
674 }
675}
676
677var expectationViolation_1 = expectationViolation;
678
679// @oss-only
680
681
682var Recoil_expectationViolation = expectationViolation_1;
683
684/**
685 * Copyright (c) Meta Platforms, Inc. and affiliates.
686 *
687 * This source code is licensed under the MIT license found in the
688 * LICENSE file in the root directory of this source tree.
689 *
690 *
691 * @format
692 * @oncall recoil
693 */
694/**
695 * Creates a new iterable whose output is generated by passing the input
696 * iterable's values through the mapper function.
697 */
698
699function mapIterable(iterable, callback) {
700 // Use generator to create iterable/iterator
701 return function* () {
702 let index = 0;
703
704 for (const value of iterable) {
705 yield callback(value, index++);
706 }
707 }();
708}
709
710var Recoil_mapIterable = mapIterable;
711
712const {
713 isFastRefreshEnabled: isFastRefreshEnabled$1
714} = Recoil_ReactMode;
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730class DefaultValue {}
731
732const DEFAULT_VALUE = new DefaultValue();
733// flowlint-next-line unclear-type:off
734const nodes = new Map(); // flowlint-next-line unclear-type:off
735
736const recoilValues = new Map();
737/* eslint-disable no-redeclare */
738
739function recoilValuesForKeys(keys) {
740 return Recoil_mapIterable(keys, key => Recoil_nullthrows(recoilValues.get(key)));
741}
742
743function checkForDuplicateAtomKey(key) {
744 if (nodes.has(key)) {
745 const message = `Duplicate atom key "${key}". This is a FATAL ERROR in
746 production. But it is safe to ignore this warning if it occurred because of
747 hot module replacement.`;
748
749 if (process.env.NODE_ENV !== "production") {
750 // TODO Figure this out for open-source
751 if (!isFastRefreshEnabled$1()) {
752 Recoil_expectationViolation(message, 'recoil');
753 }
754 } else {
755 // @fb-only: recoverableViolation(message, 'recoil');
756 console.warn(message); // @oss-only
757 }
758 }
759}
760
761function registerNode(node) {
762 if (Recoil_RecoilEnv.RECOIL_DUPLICATE_ATOM_KEY_CHECKING_ENABLED) {
763 checkForDuplicateAtomKey(node.key);
764 }
765
766 nodes.set(node.key, node);
767 const recoilValue = node.set == null ? new Recoil_RecoilValue$1.RecoilValueReadOnly(node.key) : new Recoil_RecoilValue$1.RecoilState(node.key);
768 recoilValues.set(node.key, recoilValue);
769 return recoilValue;
770}
771/* eslint-enable no-redeclare */
772
773
774class NodeMissingError extends Error {} // flowlint-next-line unclear-type:off
775
776
777function getNode(key) {
778 const node = nodes.get(key);
779
780 if (node == null) {
781 throw new NodeMissingError(`Missing definition for RecoilValue: "${key}""`);
782 }
783
784 return node;
785} // flowlint-next-line unclear-type:off
786
787
788function getNodeMaybe(key) {
789 return nodes.get(key);
790}
791
792const configDeletionHandlers = new Map();
793
794function deleteNodeConfigIfPossible(key) {
795 var _node$shouldDeleteCon;
796
797 if (!Recoil_gkx('recoil_memory_managament_2020')) {
798 return;
799 }
800
801 const node = nodes.get(key);
802
803 if (node !== null && node !== void 0 && (_node$shouldDeleteCon = node.shouldDeleteConfigOnRelease) !== null && _node$shouldDeleteCon !== void 0 && _node$shouldDeleteCon.call(node)) {
804 var _getConfigDeletionHan;
805
806 nodes.delete(key);
807 (_getConfigDeletionHan = getConfigDeletionHandler(key)) === null || _getConfigDeletionHan === void 0 ? void 0 : _getConfigDeletionHan();
808 configDeletionHandlers.delete(key);
809 }
810}
811
812function setConfigDeletionHandler(key, fn) {
813 if (!Recoil_gkx('recoil_memory_managament_2020')) {
814 return;
815 }
816
817 if (fn === undefined) {
818 configDeletionHandlers.delete(key);
819 } else {
820 configDeletionHandlers.set(key, fn);
821 }
822}
823
824function getConfigDeletionHandler(key) {
825 return configDeletionHandlers.get(key);
826}
827
828var Recoil_Node = {
829 nodes,
830 recoilValues,
831 registerNode,
832 getNode,
833 getNodeMaybe,
834 deleteNodeConfigIfPossible,
835 setConfigDeletionHandler,
836 getConfigDeletionHandler,
837 recoilValuesForKeys,
838 NodeMissingError,
839 DefaultValue,
840 DEFAULT_VALUE
841};
842
843/**
844 * Copyright (c) Meta Platforms, Inc. and affiliates.
845 *
846 * This source code is licensed under the MIT license found in the
847 * LICENSE file in the root directory of this source tree.
848 *
849 *
850 * @format
851 * @oncall recoil
852 */
853
854function enqueueExecution(s, f) {
855 f();
856}
857
858var Recoil_Queue = {
859 enqueueExecution
860};
861
862function createCommonjsModule(fn, module) {
863 return module = { exports: {} }, fn(module, module.exports), module.exports;
864}
865
866var hamt_1 = createCommonjsModule(function (module) {
867
868var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
869 return typeof obj;
870} : function (obj) {
871 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
872};
873/**
874 @fileOverview Hash Array Mapped Trie.
875
876 Code based on: https://github.com/exclipy/pdata
877*/
878
879
880var hamt = {}; // export
881
882/* Configuration
883 ******************************************************************************/
884
885var SIZE = 5;
886var BUCKET_SIZE = Math.pow(2, SIZE);
887var MASK = BUCKET_SIZE - 1;
888var MAX_INDEX_NODE = BUCKET_SIZE / 2;
889var MIN_ARRAY_NODE = BUCKET_SIZE / 4;
890/*
891 ******************************************************************************/
892
893var nothing = {};
894
895var constant = function constant(x) {
896 return function () {
897 return x;
898 };
899};
900/**
901 Get 32 bit hash of string.
902
903 Based on:
904 http://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript-jquery
905*/
906
907
908var hash = hamt.hash = function (str) {
909 var type = typeof str === 'undefined' ? 'undefined' : _typeof(str);
910 if (type === 'number') return str;
911 if (type !== 'string') str += '';
912 var hash = 0;
913
914 for (var i = 0, len = str.length; i < len; ++i) {
915 var c = str.charCodeAt(i);
916 hash = (hash << 5) - hash + c | 0;
917 }
918
919 return hash;
920};
921/* Bit Ops
922 ******************************************************************************/
923
924/**
925 Hamming weight.
926
927 Taken from: http://jsperf.com/hamming-weight
928*/
929
930
931var popcount = function popcount(x) {
932 x -= x >> 1 & 0x55555555;
933 x = (x & 0x33333333) + (x >> 2 & 0x33333333);
934 x = x + (x >> 4) & 0x0f0f0f0f;
935 x += x >> 8;
936 x += x >> 16;
937 return x & 0x7f;
938};
939
940var hashFragment = function hashFragment(shift, h) {
941 return h >>> shift & MASK;
942};
943
944var toBitmap = function toBitmap(x) {
945 return 1 << x;
946};
947
948var fromBitmap = function fromBitmap(bitmap, bit) {
949 return popcount(bitmap & bit - 1);
950};
951/* Array Ops
952 ******************************************************************************/
953
954/**
955 Set a value in an array.
956
957 @param mutate Should the input array be mutated?
958 @param at Index to change.
959 @param v New value
960 @param arr Array.
961*/
962
963
964var arrayUpdate = function arrayUpdate(mutate, at, v, arr) {
965 var out = arr;
966
967 if (!mutate) {
968 var len = arr.length;
969 out = new Array(len);
970
971 for (var i = 0; i < len; ++i) {
972 out[i] = arr[i];
973 }
974 }
975
976 out[at] = v;
977 return out;
978};
979/**
980 Remove a value from an array.
981
982 @param mutate Should the input array be mutated?
983 @param at Index to remove.
984 @param arr Array.
985*/
986
987
988var arraySpliceOut = function arraySpliceOut(mutate, at, arr) {
989 var newLen = arr.length - 1;
990 var i = 0;
991 var g = 0;
992 var out = arr;
993
994 if (mutate) {
995 i = g = at;
996 } else {
997 out = new Array(newLen);
998
999 while (i < at) {
1000 out[g++] = arr[i++];
1001 }
1002 }
1003
1004 ++i;
1005
1006 while (i <= newLen) {
1007 out[g++] = arr[i++];
1008 }
1009
1010 if (mutate) {
1011 out.length = newLen;
1012 }
1013
1014 return out;
1015};
1016/**
1017 Insert a value into an array.
1018
1019 @param mutate Should the input array be mutated?
1020 @param at Index to insert at.
1021 @param v Value to insert,
1022 @param arr Array.
1023*/
1024
1025
1026var arraySpliceIn = function arraySpliceIn(mutate, at, v, arr) {
1027 var len = arr.length;
1028
1029 if (mutate) {
1030 var _i = len;
1031
1032 while (_i >= at) {
1033 arr[_i--] = arr[_i];
1034 }
1035
1036 arr[at] = v;
1037 return arr;
1038 }
1039
1040 var i = 0,
1041 g = 0;
1042 var out = new Array(len + 1);
1043
1044 while (i < at) {
1045 out[g++] = arr[i++];
1046 }
1047
1048 out[at] = v;
1049
1050 while (i < len) {
1051 out[++g] = arr[i++];
1052 }
1053
1054 return out;
1055};
1056/* Node Structures
1057 ******************************************************************************/
1058
1059
1060var LEAF = 1;
1061var COLLISION = 2;
1062var INDEX = 3;
1063var ARRAY = 4;
1064/**
1065 Empty node.
1066*/
1067
1068var empty = {
1069 __hamt_isEmpty: true
1070};
1071
1072var isEmptyNode = function isEmptyNode(x) {
1073 return x === empty || x && x.__hamt_isEmpty;
1074};
1075/**
1076 Leaf holding a value.
1077
1078 @member edit Edit of the node.
1079 @member hash Hash of key.
1080 @member key Key.
1081 @member value Value stored.
1082*/
1083
1084
1085var Leaf = function Leaf(edit, hash, key, value) {
1086 return {
1087 type: LEAF,
1088 edit: edit,
1089 hash: hash,
1090 key: key,
1091 value: value,
1092 _modify: Leaf__modify
1093 };
1094};
1095/**
1096 Leaf holding multiple values with the same hash but different keys.
1097
1098 @member edit Edit of the node.
1099 @member hash Hash of key.
1100 @member children Array of collision children node.
1101*/
1102
1103
1104var Collision = function Collision(edit, hash, children) {
1105 return {
1106 type: COLLISION,
1107 edit: edit,
1108 hash: hash,
1109 children: children,
1110 _modify: Collision__modify
1111 };
1112};
1113/**
1114 Internal node with a sparse set of children.
1115
1116 Uses a bitmap and array to pack children.
1117
1118 @member edit Edit of the node.
1119 @member mask Bitmap that encode the positions of children in the array.
1120 @member children Array of child nodes.
1121*/
1122
1123
1124var IndexedNode = function IndexedNode(edit, mask, children) {
1125 return {
1126 type: INDEX,
1127 edit: edit,
1128 mask: mask,
1129 children: children,
1130 _modify: IndexedNode__modify
1131 };
1132};
1133/**
1134 Internal node with many children.
1135
1136 @member edit Edit of the node.
1137 @member size Number of children.
1138 @member children Array of child nodes.
1139*/
1140
1141
1142var ArrayNode = function ArrayNode(edit, size, children) {
1143 return {
1144 type: ARRAY,
1145 edit: edit,
1146 size: size,
1147 children: children,
1148 _modify: ArrayNode__modify
1149 };
1150};
1151/**
1152 Is `node` a leaf node?
1153*/
1154
1155
1156var isLeaf = function isLeaf(node) {
1157 return node === empty || node.type === LEAF || node.type === COLLISION;
1158};
1159/* Internal node operations.
1160 ******************************************************************************/
1161
1162/**
1163 Expand an indexed node into an array node.
1164
1165 @param edit Current edit.
1166 @param frag Index of added child.
1167 @param child Added child.
1168 @param mask Index node mask before child added.
1169 @param subNodes Index node children before child added.
1170*/
1171
1172
1173var expand = function expand(edit, frag, child, bitmap, subNodes) {
1174 var arr = [];
1175 var bit = bitmap;
1176 var count = 0;
1177
1178 for (var i = 0; bit; ++i) {
1179 if (bit & 1) arr[i] = subNodes[count++];
1180 bit >>>= 1;
1181 }
1182
1183 arr[frag] = child;
1184 return ArrayNode(edit, count + 1, arr);
1185};
1186/**
1187 Collapse an array node into a indexed node.
1188
1189 @param edit Current edit.
1190 @param count Number of elements in new array.
1191 @param removed Index of removed element.
1192 @param elements Array node children before remove.
1193*/
1194
1195
1196var pack = function pack(edit, count, removed, elements) {
1197 var children = new Array(count - 1);
1198 var g = 0;
1199 var bitmap = 0;
1200
1201 for (var i = 0, len = elements.length; i < len; ++i) {
1202 if (i !== removed) {
1203 var elem = elements[i];
1204
1205 if (elem && !isEmptyNode(elem)) {
1206 children[g++] = elem;
1207 bitmap |= 1 << i;
1208 }
1209 }
1210 }
1211
1212 return IndexedNode(edit, bitmap, children);
1213};
1214/**
1215 Merge two leaf nodes.
1216
1217 @param shift Current shift.
1218 @param h1 Node 1 hash.
1219 @param n1 Node 1.
1220 @param h2 Node 2 hash.
1221 @param n2 Node 2.
1222*/
1223
1224
1225var mergeLeaves = function mergeLeaves(edit, shift, h1, n1, h2, n2) {
1226 if (h1 === h2) return Collision(edit, h1, [n2, n1]);
1227 var subH1 = hashFragment(shift, h1);
1228 var subH2 = hashFragment(shift, h2);
1229 return IndexedNode(edit, toBitmap(subH1) | toBitmap(subH2), subH1 === subH2 ? [mergeLeaves(edit, shift + SIZE, h1, n1, h2, n2)] : subH1 < subH2 ? [n1, n2] : [n2, n1]);
1230};
1231/**
1232 Update an entry in a collision list.
1233
1234 @param mutate Should mutation be used?
1235 @param edit Current edit.
1236 @param keyEq Key compare function.
1237 @param hash Hash of collision.
1238 @param list Collision list.
1239 @param f Update function.
1240 @param k Key to update.
1241 @param size Size ref.
1242*/
1243
1244
1245var updateCollisionList = function updateCollisionList(mutate, edit, keyEq, h, list, f, k, size) {
1246 var len = list.length;
1247
1248 for (var i = 0; i < len; ++i) {
1249 var child = list[i];
1250
1251 if (keyEq(k, child.key)) {
1252 var value = child.value;
1253
1254 var _newValue = f(value);
1255
1256 if (_newValue === value) return list;
1257
1258 if (_newValue === nothing) {
1259 --size.value;
1260 return arraySpliceOut(mutate, i, list);
1261 }
1262
1263 return arrayUpdate(mutate, i, Leaf(edit, h, k, _newValue), list);
1264 }
1265 }
1266
1267 var newValue = f();
1268 if (newValue === nothing) return list;
1269 ++size.value;
1270 return arrayUpdate(mutate, len, Leaf(edit, h, k, newValue), list);
1271};
1272
1273var canEditNode = function canEditNode(edit, node) {
1274 return edit === node.edit;
1275};
1276/* Editing
1277 ******************************************************************************/
1278
1279
1280var Leaf__modify = function Leaf__modify(edit, keyEq, shift, f, h, k, size) {
1281 if (keyEq(k, this.key)) {
1282 var _v = f(this.value);
1283
1284 if (_v === this.value) return this;else if (_v === nothing) {
1285 --size.value;
1286 return empty;
1287 }
1288
1289 if (canEditNode(edit, this)) {
1290 this.value = _v;
1291 return this;
1292 }
1293
1294 return Leaf(edit, h, k, _v);
1295 }
1296
1297 var v = f();
1298 if (v === nothing) return this;
1299 ++size.value;
1300 return mergeLeaves(edit, shift, this.hash, this, h, Leaf(edit, h, k, v));
1301};
1302
1303var Collision__modify = function Collision__modify(edit, keyEq, shift, f, h, k, size) {
1304 if (h === this.hash) {
1305 var canEdit = canEditNode(edit, this);
1306 var list = updateCollisionList(canEdit, edit, keyEq, this.hash, this.children, f, k, size);
1307 if (list === this.children) return this;
1308 return list.length > 1 ? Collision(edit, this.hash, list) : list[0]; // collapse single element collision list
1309 }
1310
1311 var v = f();
1312 if (v === nothing) return this;
1313 ++size.value;
1314 return mergeLeaves(edit, shift, this.hash, this, h, Leaf(edit, h, k, v));
1315};
1316
1317var IndexedNode__modify = function IndexedNode__modify(edit, keyEq, shift, f, h, k, size) {
1318 var mask = this.mask;
1319 var children = this.children;
1320 var frag = hashFragment(shift, h);
1321 var bit = toBitmap(frag);
1322 var indx = fromBitmap(mask, bit);
1323 var exists = mask & bit;
1324 var current = exists ? children[indx] : empty;
1325
1326 var child = current._modify(edit, keyEq, shift + SIZE, f, h, k, size);
1327
1328 if (current === child) return this;
1329 var canEdit = canEditNode(edit, this);
1330 var bitmap = mask;
1331 var newChildren = void 0;
1332
1333 if (exists && isEmptyNode(child)) {
1334 // remove
1335 bitmap &= ~bit;
1336 if (!bitmap) return empty;
1337 if (children.length <= 2 && isLeaf(children[indx ^ 1])) return children[indx ^ 1]; // collapse
1338
1339 newChildren = arraySpliceOut(canEdit, indx, children);
1340 } else if (!exists && !isEmptyNode(child)) {
1341 // add
1342 if (children.length >= MAX_INDEX_NODE) return expand(edit, frag, child, mask, children);
1343 bitmap |= bit;
1344 newChildren = arraySpliceIn(canEdit, indx, child, children);
1345 } else {
1346 // modify
1347 newChildren = arrayUpdate(canEdit, indx, child, children);
1348 }
1349
1350 if (canEdit) {
1351 this.mask = bitmap;
1352 this.children = newChildren;
1353 return this;
1354 }
1355
1356 return IndexedNode(edit, bitmap, newChildren);
1357};
1358
1359var ArrayNode__modify = function ArrayNode__modify(edit, keyEq, shift, f, h, k, size) {
1360 var count = this.size;
1361 var children = this.children;
1362 var frag = hashFragment(shift, h);
1363 var child = children[frag];
1364
1365 var newChild = (child || empty)._modify(edit, keyEq, shift + SIZE, f, h, k, size);
1366
1367 if (child === newChild) return this;
1368 var canEdit = canEditNode(edit, this);
1369 var newChildren = void 0;
1370
1371 if (isEmptyNode(child) && !isEmptyNode(newChild)) {
1372 // add
1373 ++count;
1374 newChildren = arrayUpdate(canEdit, frag, newChild, children);
1375 } else if (!isEmptyNode(child) && isEmptyNode(newChild)) {
1376 // remove
1377 --count;
1378 if (count <= MIN_ARRAY_NODE) return pack(edit, count, frag, children);
1379 newChildren = arrayUpdate(canEdit, frag, empty, children);
1380 } else {
1381 // modify
1382 newChildren = arrayUpdate(canEdit, frag, newChild, children);
1383 }
1384
1385 if (canEdit) {
1386 this.size = count;
1387 this.children = newChildren;
1388 return this;
1389 }
1390
1391 return ArrayNode(edit, count, newChildren);
1392};
1393
1394empty._modify = function (edit, keyEq, shift, f, h, k, size) {
1395 var v = f();
1396 if (v === nothing) return empty;
1397 ++size.value;
1398 return Leaf(edit, h, k, v);
1399};
1400/*
1401 ******************************************************************************/
1402
1403
1404function Map(editable, edit, config, root, size) {
1405 this._editable = editable;
1406 this._edit = edit;
1407 this._config = config;
1408 this._root = root;
1409 this._size = size;
1410}
1411
1412Map.prototype.setTree = function (newRoot, newSize) {
1413 if (this._editable) {
1414 this._root = newRoot;
1415 this._size = newSize;
1416 return this;
1417 }
1418
1419 return newRoot === this._root ? this : new Map(this._editable, this._edit, this._config, newRoot, newSize);
1420};
1421/* Queries
1422 ******************************************************************************/
1423
1424/**
1425 Lookup the value for `key` in `map` using a custom `hash`.
1426
1427 Returns the value or `alt` if none.
1428*/
1429
1430
1431var tryGetHash = hamt.tryGetHash = function (alt, hash, key, map) {
1432 var node = map._root;
1433 var shift = 0;
1434 var keyEq = map._config.keyEq;
1435
1436 while (true) {
1437 switch (node.type) {
1438 case LEAF:
1439 {
1440 return keyEq(key, node.key) ? node.value : alt;
1441 }
1442
1443 case COLLISION:
1444 {
1445 if (hash === node.hash) {
1446 var children = node.children;
1447
1448 for (var i = 0, len = children.length; i < len; ++i) {
1449 var child = children[i];
1450 if (keyEq(key, child.key)) return child.value;
1451 }
1452 }
1453
1454 return alt;
1455 }
1456
1457 case INDEX:
1458 {
1459 var frag = hashFragment(shift, hash);
1460 var bit = toBitmap(frag);
1461
1462 if (node.mask & bit) {
1463 node = node.children[fromBitmap(node.mask, bit)];
1464 shift += SIZE;
1465 break;
1466 }
1467
1468 return alt;
1469 }
1470
1471 case ARRAY:
1472 {
1473 node = node.children[hashFragment(shift, hash)];
1474
1475 if (node) {
1476 shift += SIZE;
1477 break;
1478 }
1479
1480 return alt;
1481 }
1482
1483 default:
1484 return alt;
1485 }
1486 }
1487};
1488
1489Map.prototype.tryGetHash = function (alt, hash, key) {
1490 return tryGetHash(alt, hash, key, this);
1491};
1492/**
1493 Lookup the value for `key` in `map` using internal hash function.
1494
1495 @see `tryGetHash`
1496*/
1497
1498
1499var tryGet = hamt.tryGet = function (alt, key, map) {
1500 return tryGetHash(alt, map._config.hash(key), key, map);
1501};
1502
1503Map.prototype.tryGet = function (alt, key) {
1504 return tryGet(alt, key, this);
1505};
1506/**
1507 Lookup the value for `key` in `map` using a custom `hash`.
1508
1509 Returns the value or `undefined` if none.
1510*/
1511
1512
1513var getHash = hamt.getHash = function (hash, key, map) {
1514 return tryGetHash(undefined, hash, key, map);
1515};
1516
1517Map.prototype.getHash = function (hash, key) {
1518 return getHash(hash, key, this);
1519};
1520/**
1521 Lookup the value for `key` in `map` using internal hash function.
1522
1523 @see `get`
1524*/
1525
1526
1527var get = hamt.get = function (key, map) {
1528 return tryGetHash(undefined, map._config.hash(key), key, map);
1529};
1530
1531Map.prototype.get = function (key, alt) {
1532 return tryGet(alt, key, this);
1533};
1534/**
1535 Does an entry exist for `key` in `map`? Uses custom `hash`.
1536*/
1537
1538
1539var hasHash = hamt.has = function (hash, key, map) {
1540 return tryGetHash(nothing, hash, key, map) !== nothing;
1541};
1542
1543Map.prototype.hasHash = function (hash, key) {
1544 return hasHash(hash, key, this);
1545};
1546/**
1547 Does an entry exist for `key` in `map`? Uses internal hash function.
1548*/
1549
1550
1551var has = hamt.has = function (key, map) {
1552 return hasHash(map._config.hash(key), key, map);
1553};
1554
1555Map.prototype.has = function (key) {
1556 return has(key, this);
1557};
1558
1559var defKeyCompare = function defKeyCompare(x, y) {
1560 return x === y;
1561};
1562/**
1563 Create an empty map.
1564
1565 @param config Configuration.
1566*/
1567
1568
1569hamt.make = function (config) {
1570 return new Map(0, 0, {
1571 keyEq: config && config.keyEq || defKeyCompare,
1572 hash: config && config.hash || hash
1573 }, empty, 0);
1574};
1575/**
1576 Empty map.
1577*/
1578
1579
1580hamt.empty = hamt.make();
1581/**
1582 Does `map` contain any elements?
1583*/
1584
1585var isEmpty = hamt.isEmpty = function (map) {
1586 return map && !!isEmptyNode(map._root);
1587};
1588
1589Map.prototype.isEmpty = function () {
1590 return isEmpty(this);
1591};
1592/* Updates
1593 ******************************************************************************/
1594
1595/**
1596 Alter the value stored for `key` in `map` using function `f` using
1597 custom hash.
1598
1599 `f` is invoked with the current value for `k` if it exists,
1600 or no arguments if no such value exists. `modify` will always either
1601 update or insert a value into the map.
1602
1603 Returns a map with the modified value. Does not alter `map`.
1604*/
1605
1606
1607var modifyHash = hamt.modifyHash = function (f, hash, key, map) {
1608 var size = {
1609 value: map._size
1610 };
1611
1612 var newRoot = map._root._modify(map._editable ? map._edit : NaN, map._config.keyEq, 0, f, hash, key, size);
1613
1614 return map.setTree(newRoot, size.value);
1615};
1616
1617Map.prototype.modifyHash = function (hash, key, f) {
1618 return modifyHash(f, hash, key, this);
1619};
1620/**
1621 Alter the value stored for `key` in `map` using function `f` using
1622 internal hash function.
1623
1624 @see `modifyHash`
1625*/
1626
1627
1628var modify = hamt.modify = function (f, key, map) {
1629 return modifyHash(f, map._config.hash(key), key, map);
1630};
1631
1632Map.prototype.modify = function (key, f) {
1633 return modify(f, key, this);
1634};
1635/**
1636 Store `value` for `key` in `map` using custom `hash`.
1637
1638 Returns a map with the modified value. Does not alter `map`.
1639*/
1640
1641
1642var setHash = hamt.setHash = function (hash, key, value, map) {
1643 return modifyHash(constant(value), hash, key, map);
1644};
1645
1646Map.prototype.setHash = function (hash, key, value) {
1647 return setHash(hash, key, value, this);
1648};
1649/**
1650 Store `value` for `key` in `map` using internal hash function.
1651
1652 @see `setHash`
1653*/
1654
1655
1656var set = hamt.set = function (key, value, map) {
1657 return setHash(map._config.hash(key), key, value, map);
1658};
1659
1660Map.prototype.set = function (key, value) {
1661 return set(key, value, this);
1662};
1663/**
1664 Remove the entry for `key` in `map`.
1665
1666 Returns a map with the value removed. Does not alter `map`.
1667*/
1668
1669
1670var del = constant(nothing);
1671
1672var removeHash = hamt.removeHash = function (hash, key, map) {
1673 return modifyHash(del, hash, key, map);
1674};
1675
1676Map.prototype.removeHash = Map.prototype.deleteHash = function (hash, key) {
1677 return removeHash(hash, key, this);
1678};
1679/**
1680 Remove the entry for `key` in `map` using internal hash function.
1681
1682 @see `removeHash`
1683*/
1684
1685
1686var remove = hamt.remove = function (key, map) {
1687 return removeHash(map._config.hash(key), key, map);
1688};
1689
1690Map.prototype.remove = Map.prototype.delete = function (key) {
1691 return remove(key, this);
1692};
1693/* Mutation
1694 ******************************************************************************/
1695
1696/**
1697 Mark `map` as mutable.
1698 */
1699
1700
1701var beginMutation = hamt.beginMutation = function (map) {
1702 return new Map(map._editable + 1, map._edit + 1, map._config, map._root, map._size);
1703};
1704
1705Map.prototype.beginMutation = function () {
1706 return beginMutation(this);
1707};
1708/**
1709 Mark `map` as immutable.
1710 */
1711
1712
1713var endMutation = hamt.endMutation = function (map) {
1714 map._editable = map._editable && map._editable - 1;
1715 return map;
1716};
1717
1718Map.prototype.endMutation = function () {
1719 return endMutation(this);
1720};
1721/**
1722 Mutate `map` within the context of `f`.
1723 @param f
1724 @param map HAMT
1725*/
1726
1727
1728var mutate = hamt.mutate = function (f, map) {
1729 var transient = beginMutation(map);
1730 f(transient);
1731 return endMutation(transient);
1732};
1733
1734Map.prototype.mutate = function (f) {
1735 return mutate(f, this);
1736};
1737/* Traversal
1738 ******************************************************************************/
1739
1740/**
1741 Apply a continuation.
1742*/
1743
1744
1745var appk = function appk(k) {
1746 return k && lazyVisitChildren(k[0], k[1], k[2], k[3], k[4]);
1747};
1748/**
1749 Recursively visit all values stored in an array of nodes lazily.
1750*/
1751
1752
1753var lazyVisitChildren = function lazyVisitChildren(len, children, i, f, k) {
1754 while (i < len) {
1755 var child = children[i++];
1756 if (child && !isEmptyNode(child)) return lazyVisit(child, f, [len, children, i, f, k]);
1757 }
1758
1759 return appk(k);
1760};
1761/**
1762 Recursively visit all values stored in `node` lazily.
1763*/
1764
1765
1766var lazyVisit = function lazyVisit(node, f, k) {
1767 switch (node.type) {
1768 case LEAF:
1769 return {
1770 value: f(node),
1771 rest: k
1772 };
1773
1774 case COLLISION:
1775 case ARRAY:
1776 case INDEX:
1777 var children = node.children;
1778 return lazyVisitChildren(children.length, children, 0, f, k);
1779
1780 default:
1781 return appk(k);
1782 }
1783};
1784
1785var DONE = {
1786 done: true
1787};
1788/**
1789 Javascript iterator over a map.
1790*/
1791
1792function MapIterator(v) {
1793 this.v = v;
1794}
1795
1796MapIterator.prototype.next = function () {
1797 if (!this.v) return DONE;
1798 var v0 = this.v;
1799 this.v = appk(v0.rest);
1800 return v0;
1801};
1802
1803MapIterator.prototype[Symbol.iterator] = function () {
1804 return this;
1805};
1806/**
1807 Lazily visit each value in map with function `f`.
1808*/
1809
1810
1811var visit = function visit(map, f) {
1812 return new MapIterator(lazyVisit(map._root, f));
1813};
1814/**
1815 Get a Javascsript iterator of `map`.
1816
1817 Iterates over `[key, value]` arrays.
1818*/
1819
1820
1821var buildPairs = function buildPairs(x) {
1822 return [x.key, x.value];
1823};
1824
1825var entries = hamt.entries = function (map) {
1826 return visit(map, buildPairs);
1827};
1828
1829Map.prototype.entries = Map.prototype[Symbol.iterator] = function () {
1830 return entries(this);
1831};
1832/**
1833 Get array of all keys in `map`.
1834
1835 Order is not guaranteed.
1836*/
1837
1838
1839var buildKeys = function buildKeys(x) {
1840 return x.key;
1841};
1842
1843var keys = hamt.keys = function (map) {
1844 return visit(map, buildKeys);
1845};
1846
1847Map.prototype.keys = function () {
1848 return keys(this);
1849};
1850/**
1851 Get array of all values in `map`.
1852
1853 Order is not guaranteed, duplicates are preserved.
1854*/
1855
1856
1857var buildValues = function buildValues(x) {
1858 return x.value;
1859};
1860
1861var values = hamt.values = Map.prototype.values = function (map) {
1862 return visit(map, buildValues);
1863};
1864
1865Map.prototype.values = function () {
1866 return values(this);
1867};
1868/* Fold
1869 ******************************************************************************/
1870
1871/**
1872 Visit every entry in the map, aggregating data.
1873
1874 Order of nodes is not guaranteed.
1875
1876 @param f Function mapping accumulated value, value, and key to new value.
1877 @param z Starting value.
1878 @param m HAMT
1879*/
1880
1881
1882var fold = hamt.fold = function (f, z, m) {
1883 var root = m._root;
1884 if (root.type === LEAF) return f(z, root.value, root.key);
1885 var toVisit = [root.children];
1886 var children = void 0;
1887
1888 while (children = toVisit.pop()) {
1889 for (var i = 0, len = children.length; i < len;) {
1890 var child = children[i++];
1891
1892 if (child && child.type) {
1893 if (child.type === LEAF) z = f(z, child.value, child.key);else toVisit.push(child.children);
1894 }
1895 }
1896 }
1897
1898 return z;
1899};
1900
1901Map.prototype.fold = function (f, z) {
1902 return fold(f, z, this);
1903};
1904/**
1905 Visit every entry in the map, aggregating data.
1906
1907 Order of nodes is not guaranteed.
1908
1909 @param f Function invoked with value and key
1910 @param map HAMT
1911*/
1912
1913
1914var forEach = hamt.forEach = function (f, map) {
1915 return fold(function (_, value, key) {
1916 return f(value, key, map);
1917 }, null, map);
1918};
1919
1920Map.prototype.forEach = function (f) {
1921 return forEach(f, this);
1922};
1923/* Aggregate
1924 ******************************************************************************/
1925
1926/**
1927 Get the number of entries in `map`.
1928*/
1929
1930
1931var count = hamt.count = function (map) {
1932 return map._size;
1933};
1934
1935Map.prototype.count = function () {
1936 return count(this);
1937};
1938
1939Object.defineProperty(Map.prototype, 'size', {
1940 get: Map.prototype.count
1941});
1942/* Export
1943 ******************************************************************************/
1944
1945if ( module.exports) {
1946 module.exports = hamt;
1947} else {
1948 undefined.hamt = hamt;
1949}
1950});
1951
1952class BuiltInMap {
1953 constructor(existing) {
1954 _defineProperty(this, "_map", void 0);
1955
1956 this._map = new Map(existing === null || existing === void 0 ? void 0 : existing.entries());
1957 }
1958
1959 keys() {
1960 return this._map.keys();
1961 }
1962
1963 entries() {
1964 return this._map.entries();
1965 }
1966
1967 get(k) {
1968 return this._map.get(k);
1969 }
1970
1971 has(k) {
1972 return this._map.has(k);
1973 }
1974
1975 set(k, v) {
1976 this._map.set(k, v);
1977
1978 return this;
1979 }
1980
1981 delete(k) {
1982 this._map.delete(k);
1983
1984 return this;
1985 }
1986
1987 clone() {
1988 return persistentMap(this);
1989 }
1990
1991 toMap() {
1992 return new Map(this._map);
1993 }
1994
1995}
1996
1997class HashArrayMappedTrieMap {
1998 // Because hamt.empty is not a function there is no way to introduce type
1999 // parameters on it, so empty is typed as HAMTPlusMap<string, mixed>.
2000 // $FlowIssue
2001 constructor(existing) {
2002 _defineProperty(this, "_hamt", hamt_1.empty.beginMutation());
2003
2004 if (existing instanceof HashArrayMappedTrieMap) {
2005 const h = existing._hamt.endMutation();
2006
2007 existing._hamt = h.beginMutation();
2008 this._hamt = h.beginMutation();
2009 } else if (existing) {
2010 for (const [k, v] of existing.entries()) {
2011 this._hamt.set(k, v);
2012 }
2013 }
2014 }
2015
2016 keys() {
2017 return this._hamt.keys();
2018 }
2019
2020 entries() {
2021 return this._hamt.entries();
2022 }
2023
2024 get(k) {
2025 return this._hamt.get(k);
2026 }
2027
2028 has(k) {
2029 return this._hamt.has(k);
2030 }
2031
2032 set(k, v) {
2033 this._hamt.set(k, v);
2034
2035 return this;
2036 }
2037
2038 delete(k) {
2039 this._hamt.delete(k);
2040
2041 return this;
2042 }
2043
2044 clone() {
2045 return persistentMap(this);
2046 }
2047
2048 toMap() {
2049 return new Map(this._hamt);
2050 }
2051
2052}
2053
2054function persistentMap(existing) {
2055 if (Recoil_gkx('recoil_hamt_2020')) {
2056 return new HashArrayMappedTrieMap(existing);
2057 } else {
2058 return new BuiltInMap(existing);
2059 }
2060}
2061
2062var Recoil_PersistentMap = {
2063 persistentMap
2064};
2065
2066var Recoil_PersistentMap_1 = Recoil_PersistentMap.persistentMap;
2067
2068var Recoil_PersistentMap$1 = /*#__PURE__*/Object.freeze({
2069 __proto__: null,
2070 persistentMap: Recoil_PersistentMap_1
2071});
2072
2073/**
2074 * Copyright (c) Meta Platforms, Inc. and affiliates.
2075 *
2076 * This source code is licensed under the MIT license found in the
2077 * LICENSE file in the root directory of this source tree.
2078 *
2079 *
2080 * @format
2081 * @oncall recoil
2082 */
2083/**
2084 * Returns a set containing all of the values from the first set that are not
2085 * present in any of the subsequent sets.
2086 *
2087 * Note: this is written procedurally (i.e., without filterSet) for performant
2088 * use in tight loops.
2089 */
2090
2091function differenceSets(set, ...setsWithValuesToRemove) {
2092 const ret = new Set();
2093
2094 FIRST: for (const value of set) {
2095 for (const otherSet of setsWithValuesToRemove) {
2096 if (otherSet.has(value)) {
2097 continue FIRST;
2098 }
2099 }
2100
2101 ret.add(value);
2102 }
2103
2104 return ret;
2105}
2106
2107var Recoil_differenceSets = differenceSets;
2108
2109/**
2110 * Copyright (c) Meta Platforms, Inc. and affiliates.
2111 *
2112 * This source code is licensed under the MIT license found in the
2113 * LICENSE file in the root directory of this source tree.
2114 *
2115 *
2116 * @format
2117 * @oncall recoil
2118 */
2119/**
2120 * Returns a new Map object with the same keys as the original, but with the
2121 * values replaced with the output of the given callback function.
2122 */
2123
2124function mapMap(map, callback) {
2125 const result = new Map();
2126 map.forEach((value, key) => {
2127 result.set(key, callback(value, key));
2128 });
2129 return result;
2130}
2131
2132var Recoil_mapMap = mapMap;
2133
2134function makeGraph() {
2135 return {
2136 nodeDeps: new Map(),
2137 nodeToNodeSubscriptions: new Map()
2138 };
2139}
2140
2141function cloneGraph(graph) {
2142 return {
2143 nodeDeps: Recoil_mapMap(graph.nodeDeps, s => new Set(s)),
2144 nodeToNodeSubscriptions: Recoil_mapMap(graph.nodeToNodeSubscriptions, s => new Set(s))
2145 };
2146} // Note that this overwrites the deps of existing nodes, rather than unioning
2147// the new deps with the old deps.
2148
2149
2150function mergeDepsIntoGraph(key, newDeps, graph, // If olderGraph is given then we will not overwrite changes made to the given
2151// graph compared with olderGraph:
2152olderGraph) {
2153 const {
2154 nodeDeps,
2155 nodeToNodeSubscriptions
2156 } = graph;
2157 const oldDeps = nodeDeps.get(key);
2158
2159 if (oldDeps && olderGraph && oldDeps !== olderGraph.nodeDeps.get(key)) {
2160 return;
2161 } // Update nodeDeps:
2162
2163
2164 nodeDeps.set(key, newDeps); // Add new deps to nodeToNodeSubscriptions:
2165
2166 const addedDeps = oldDeps == null ? newDeps : Recoil_differenceSets(newDeps, oldDeps);
2167
2168 for (const dep of addedDeps) {
2169 if (!nodeToNodeSubscriptions.has(dep)) {
2170 nodeToNodeSubscriptions.set(dep, new Set());
2171 }
2172
2173 const existing = Recoil_nullthrows(nodeToNodeSubscriptions.get(dep));
2174 existing.add(key);
2175 } // Remove removed deps from nodeToNodeSubscriptions:
2176
2177
2178 if (oldDeps) {
2179 const removedDeps = Recoil_differenceSets(oldDeps, newDeps);
2180
2181 for (const dep of removedDeps) {
2182 if (!nodeToNodeSubscriptions.has(dep)) {
2183 return;
2184 }
2185
2186 const existing = Recoil_nullthrows(nodeToNodeSubscriptions.get(dep));
2187 existing.delete(key);
2188
2189 if (existing.size === 0) {
2190 nodeToNodeSubscriptions.delete(dep);
2191 }
2192 }
2193 }
2194}
2195
2196function saveDepsToStore(key, deps, store, version) {
2197 var _storeState$nextTree, _storeState$previousT, _storeState$previousT2, _storeState$previousT3;
2198
2199 const storeState = store.getState();
2200
2201 if (!(version === storeState.currentTree.version || version === ((_storeState$nextTree = storeState.nextTree) === null || _storeState$nextTree === void 0 ? void 0 : _storeState$nextTree.version) || version === ((_storeState$previousT = storeState.previousTree) === null || _storeState$previousT === void 0 ? void 0 : _storeState$previousT.version))) {
2202 Recoil_recoverableViolation('Tried to save dependencies to a discarded tree');
2203 } // Merge the dependencies discovered into the store's dependency map
2204 // for the version that was read:
2205
2206
2207 const graph = store.getGraph(version);
2208 mergeDepsIntoGraph(key, deps, graph); // If this version is not the latest version, also write these dependencies
2209 // into later versions if they don't already have their own:
2210
2211 if (version === ((_storeState$previousT2 = storeState.previousTree) === null || _storeState$previousT2 === void 0 ? void 0 : _storeState$previousT2.version)) {
2212 const currentGraph = store.getGraph(storeState.currentTree.version);
2213 mergeDepsIntoGraph(key, deps, currentGraph, graph);
2214 }
2215
2216 if (version === ((_storeState$previousT3 = storeState.previousTree) === null || _storeState$previousT3 === void 0 ? void 0 : _storeState$previousT3.version) || version === storeState.currentTree.version) {
2217 var _storeState$nextTree2;
2218
2219 const nextVersion = (_storeState$nextTree2 = storeState.nextTree) === null || _storeState$nextTree2 === void 0 ? void 0 : _storeState$nextTree2.version;
2220
2221 if (nextVersion !== undefined) {
2222 const nextGraph = store.getGraph(nextVersion);
2223 mergeDepsIntoGraph(key, deps, nextGraph, graph);
2224 }
2225 }
2226}
2227
2228var Recoil_Graph = {
2229 cloneGraph,
2230 graph: makeGraph,
2231 saveDepsToStore
2232};
2233
2234/**
2235 * Copyright (c) Meta Platforms, Inc. and affiliates.
2236 *
2237 * This source code is licensed under the MIT license found in the
2238 * LICENSE file in the root directory of this source tree.
2239 *
2240 *
2241 * @format
2242 * @oncall recoil
2243 */
2244
2245let nextTreeStateVersion = 0;
2246
2247const getNextTreeStateVersion = () => nextTreeStateVersion++;
2248
2249let nextStoreID = 0;
2250
2251const getNextStoreID = () => nextStoreID++;
2252
2253let nextComponentID = 0;
2254
2255const getNextComponentID = () => nextComponentID++;
2256
2257var Recoil_Keys = {
2258 getNextTreeStateVersion,
2259 getNextStoreID,
2260 getNextComponentID
2261};
2262
2263const {
2264 persistentMap: persistentMap$1
2265} = Recoil_PersistentMap$1;
2266
2267const {
2268 graph
2269} = Recoil_Graph;
2270
2271const {
2272 getNextTreeStateVersion: getNextTreeStateVersion$1
2273} = Recoil_Keys;
2274
2275function makeEmptyTreeState() {
2276 const version = getNextTreeStateVersion$1();
2277 return {
2278 version,
2279 stateID: version,
2280 transactionMetadata: {},
2281 dirtyAtoms: new Set(),
2282 atomValues: persistentMap$1(),
2283 nonvalidatedAtoms: persistentMap$1()
2284 };
2285}
2286
2287function makeEmptyStoreState() {
2288 const currentTree = makeEmptyTreeState();
2289 return {
2290 currentTree,
2291 nextTree: null,
2292 previousTree: null,
2293 commitDepth: 0,
2294 knownAtoms: new Set(),
2295 knownSelectors: new Set(),
2296 transactionSubscriptions: new Map(),
2297 nodeTransactionSubscriptions: new Map(),
2298 nodeToComponentSubscriptions: new Map(),
2299 queuedComponentCallbacks_DEPRECATED: [],
2300 suspendedComponentResolvers: new Set(),
2301 graphsByVersion: new Map().set(currentTree.version, graph()),
2302 retention: {
2303 referenceCounts: new Map(),
2304 nodesRetainedByZone: new Map(),
2305 retainablesToCheckForRelease: new Set()
2306 },
2307 nodeCleanupFunctions: new Map()
2308 };
2309}
2310
2311var Recoil_State = {
2312 makeEmptyTreeState,
2313 makeEmptyStoreState,
2314 getNextTreeStateVersion: getNextTreeStateVersion$1
2315};
2316
2317/**
2318 * Copyright (c) Meta Platforms, Inc. and affiliates.
2319 *
2320 * This source code is licensed under the MIT license found in the
2321 * LICENSE file in the root directory of this source tree.
2322 *
2323 *
2324 * @format
2325 * @oncall recoil
2326 */
2327
2328class RetentionZone {}
2329
2330function retentionZone() {
2331 return new RetentionZone();
2332}
2333
2334var Recoil_RetentionZone = {
2335 RetentionZone,
2336 retentionZone
2337};
2338
2339/**
2340 * Copyright (c) Meta Platforms, Inc. and affiliates.
2341 *
2342 * This source code is licensed under the MIT license found in the
2343 * LICENSE file in the root directory of this source tree.
2344 *
2345 * Utilities for working with built-in Maps and Sets without mutating them.
2346 *
2347 *
2348 * @format
2349 * @oncall recoil
2350 */
2351
2352function setByAddingToSet(set, v) {
2353 const next = new Set(set);
2354 next.add(v);
2355 return next;
2356}
2357
2358function setByDeletingFromSet(set, v) {
2359 const next = new Set(set);
2360 next.delete(v);
2361 return next;
2362}
2363
2364function mapBySettingInMap(map, k, v) {
2365 const next = new Map(map);
2366 next.set(k, v);
2367 return next;
2368}
2369
2370function mapByUpdatingInMap(map, k, updater) {
2371 const next = new Map(map);
2372 next.set(k, updater(next.get(k)));
2373 return next;
2374}
2375
2376function mapByDeletingFromMap(map, k) {
2377 const next = new Map(map);
2378 next.delete(k);
2379 return next;
2380}
2381
2382function mapByDeletingMultipleFromMap(map, ks) {
2383 const next = new Map(map);
2384 ks.forEach(k => next.delete(k));
2385 return next;
2386}
2387
2388var Recoil_CopyOnWrite = {
2389 setByAddingToSet,
2390 setByDeletingFromSet,
2391 mapBySettingInMap,
2392 mapByUpdatingInMap,
2393 mapByDeletingFromMap,
2394 mapByDeletingMultipleFromMap
2395};
2396
2397/**
2398 * Copyright (c) Meta Platforms, Inc. and affiliates.
2399 *
2400 * This source code is licensed under the MIT license found in the
2401 * LICENSE file in the root directory of this source tree.
2402 *
2403 *
2404 * @format
2405 * @oncall recoil
2406 */
2407/**
2408 * Creates a new iterable whose output is generated by passing the input
2409 * iterable's values through the filter function.
2410 */
2411
2412function* filterIterable(iterable, predicate) {
2413 // Use generator to create iterable/iterator
2414 let index = 0;
2415
2416 for (const value of iterable) {
2417 if (predicate(value, index++)) {
2418 yield value;
2419 }
2420 }
2421}
2422
2423var Recoil_filterIterable = filterIterable;
2424
2425/**
2426 * Copyright (c) Meta Platforms, Inc. and affiliates.
2427 *
2428 * This source code is licensed under the MIT license found in the
2429 * LICENSE file in the root directory of this source tree.
2430 *
2431 *
2432 * @format
2433 * @oncall recoil
2434 */
2435/**
2436 * Return a proxy object based on the provided base and factories objects.
2437 * The proxy will include all properties of the base object as-is.
2438 * The factories object contains callbacks to obtain the values of the properies
2439 * for its keys.
2440 *
2441 * This is useful for providing users an object where some properties may be
2442 * lazily computed only on first access.
2443 */
2444// $FlowIssue[unclear-type]
2445
2446function lazyProxy(base, factories) {
2447 const proxy = new Proxy(base, {
2448 // Compute and cache lazy property if not already done.
2449 get: (target, prop) => {
2450 if (!(prop in target) && prop in factories) {
2451 target[prop] = factories[prop]();
2452 }
2453
2454 return target[prop];
2455 },
2456 // This method allows user to iterate keys as normal
2457 ownKeys: target => {
2458
2459 return Object.keys(target);
2460 }
2461 }); // $FlowIssue[incompatible-return]
2462
2463 return proxy;
2464}
2465
2466var Recoil_lazyProxy = lazyProxy;
2467
2468const {
2469 getNode: getNode$1,
2470 getNodeMaybe: getNodeMaybe$1,
2471 recoilValuesForKeys: recoilValuesForKeys$1
2472} = Recoil_Node;
2473
2474const {
2475 RetentionZone: RetentionZone$1
2476} = Recoil_RetentionZone;
2477
2478const {
2479 setByAddingToSet: setByAddingToSet$1
2480} = Recoil_CopyOnWrite;
2481
2482
2483
2484
2485
2486
2487
2488 // flowlint-next-line unclear-type:off
2489
2490
2491const emptySet = Object.freeze(new Set());
2492
2493class ReadOnlyRecoilValueError extends Error {}
2494
2495function initializeRetentionForNode(store, nodeKey, retainedBy) {
2496 if (!Recoil_gkx('recoil_memory_managament_2020')) {
2497 return () => undefined;
2498 }
2499
2500 const {
2501 nodesRetainedByZone
2502 } = store.getState().retention;
2503
2504 function addToZone(zone) {
2505 let set = nodesRetainedByZone.get(zone);
2506
2507 if (!set) {
2508 nodesRetainedByZone.set(zone, set = new Set());
2509 }
2510
2511 set.add(nodeKey);
2512 }
2513
2514 if (retainedBy instanceof RetentionZone$1) {
2515 addToZone(retainedBy);
2516 } else if (Array.isArray(retainedBy)) {
2517 for (const zone of retainedBy) {
2518 addToZone(zone);
2519 }
2520 }
2521
2522 return () => {
2523 if (!Recoil_gkx('recoil_memory_managament_2020')) {
2524 return;
2525 }
2526
2527 const {
2528 retention
2529 } = store.getState();
2530
2531 function deleteFromZone(zone) {
2532 const set = retention.nodesRetainedByZone.get(zone);
2533 set === null || set === void 0 ? void 0 : set.delete(nodeKey);
2534
2535 if (set && set.size === 0) {
2536 retention.nodesRetainedByZone.delete(zone);
2537 }
2538 }
2539
2540 if (retainedBy instanceof RetentionZone$1) {
2541 deleteFromZone(retainedBy);
2542 } else if (Array.isArray(retainedBy)) {
2543 for (const zone of retainedBy) {
2544 deleteFromZone(zone);
2545 }
2546 }
2547 };
2548}
2549
2550function initializeNodeIfNewToStore(store, treeState, key, trigger) {
2551 const storeState = store.getState();
2552
2553 if (storeState.nodeCleanupFunctions.has(key)) {
2554 return;
2555 }
2556
2557 const node = getNode$1(key);
2558 const retentionCleanup = initializeRetentionForNode(store, key, node.retainedBy);
2559 const nodeCleanup = node.init(store, treeState, trigger);
2560 storeState.nodeCleanupFunctions.set(key, () => {
2561 nodeCleanup();
2562 retentionCleanup();
2563 });
2564}
2565
2566function initializeNode(store, key, trigger) {
2567 initializeNodeIfNewToStore(store, store.getState().currentTree, key, trigger);
2568}
2569
2570function cleanUpNode(store, key) {
2571 var _state$nodeCleanupFun;
2572
2573 const state = store.getState();
2574 (_state$nodeCleanupFun = state.nodeCleanupFunctions.get(key)) === null || _state$nodeCleanupFun === void 0 ? void 0 : _state$nodeCleanupFun();
2575 state.nodeCleanupFunctions.delete(key);
2576} // Get the current value loadable of a node and update the state.
2577// Update dependencies and subscriptions for selectors.
2578// Update saved value validation for atoms.
2579
2580
2581function getNodeLoadable(store, state, key) {
2582 initializeNodeIfNewToStore(store, state, key, 'get');
2583 return getNode$1(key).get(store, state);
2584} // Peek at the current value loadable for a node without any evaluation or state change
2585
2586
2587function peekNodeLoadable(store, state, key) {
2588 return getNode$1(key).peek(store, state);
2589} // Write value directly to state bypassing the Node interface as the node
2590// definitions may not have been loaded yet when processing the initial snapshot.
2591
2592
2593function setUnvalidatedAtomValue_DEPRECATED(state, key, newValue) {
2594 var _node$invalidate;
2595
2596 const node = getNodeMaybe$1(key);
2597 node === null || node === void 0 ? void 0 : (_node$invalidate = node.invalidate) === null || _node$invalidate === void 0 ? void 0 : _node$invalidate.call(node, state);
2598 return { ...state,
2599 atomValues: state.atomValues.clone().delete(key),
2600 nonvalidatedAtoms: state.nonvalidatedAtoms.clone().set(key, newValue),
2601 dirtyAtoms: setByAddingToSet$1(state.dirtyAtoms, key)
2602 };
2603} // Return the discovered dependencies and values to be written by setting
2604// a node value. (Multiple values may be written due to selectors getting to
2605// set upstreams; deps may be discovered because of reads in updater functions.)
2606
2607
2608function setNodeValue(store, state, key, newValue) {
2609 const node = getNode$1(key);
2610
2611 if (node.set == null) {
2612 throw new ReadOnlyRecoilValueError(`Attempt to set read-only RecoilValue: ${key}`);
2613 }
2614
2615 const set = node.set; // so flow doesn't lose the above refinement.
2616
2617 initializeNodeIfNewToStore(store, state, key, 'set');
2618 return set(store, state, newValue);
2619}
2620
2621function peekNodeInfo(store, state, key) {
2622 const storeState = store.getState();
2623 const graph = store.getGraph(state.version);
2624 const type = getNode$1(key).nodeType;
2625 return Recoil_lazyProxy({
2626 type
2627 }, {
2628 // $FlowFixMe[underconstrained-implicit-instantiation]
2629 loadable: () => peekNodeLoadable(store, state, key),
2630 isActive: () => storeState.knownAtoms.has(key) || storeState.knownSelectors.has(key),
2631 isSet: () => type === 'selector' ? false : state.atomValues.has(key),
2632 isModified: () => state.dirtyAtoms.has(key),
2633 // Report current dependencies. If the node hasn't been evaluated, then
2634 // dependencies may be missing based on the current state.
2635 deps: () => {
2636 var _graph$nodeDeps$get;
2637
2638 return recoilValuesForKeys$1((_graph$nodeDeps$get = graph.nodeDeps.get(key)) !== null && _graph$nodeDeps$get !== void 0 ? _graph$nodeDeps$get : []);
2639 },
2640 // Reports all "current" subscribers. Evaluating other nodes or
2641 // previous in-progress async evaluations may introduce new subscribers.
2642 subscribers: () => {
2643 var _storeState$nodeToCom, _storeState$nodeToCom2;
2644
2645 return {
2646 nodes: recoilValuesForKeys$1(Recoil_filterIterable(getDownstreamNodes(store, state, new Set([key])), nodeKey => nodeKey !== key)),
2647 components: Recoil_mapIterable((_storeState$nodeToCom = (_storeState$nodeToCom2 = storeState.nodeToComponentSubscriptions.get(key)) === null || _storeState$nodeToCom2 === void 0 ? void 0 : _storeState$nodeToCom2.values()) !== null && _storeState$nodeToCom !== void 0 ? _storeState$nodeToCom : [], ([name]) => ({
2648 name
2649 }))
2650 };
2651 }
2652 });
2653} // Find all of the recursively dependent nodes
2654
2655
2656function getDownstreamNodes(store, state, keys) {
2657 const visitedNodes = new Set();
2658 const visitingNodes = Array.from(keys);
2659 const graph = store.getGraph(state.version);
2660
2661 for (let key = visitingNodes.pop(); key; key = visitingNodes.pop()) {
2662 var _graph$nodeToNodeSubs;
2663
2664 visitedNodes.add(key);
2665 const subscribedNodes = (_graph$nodeToNodeSubs = graph.nodeToNodeSubscriptions.get(key)) !== null && _graph$nodeToNodeSubs !== void 0 ? _graph$nodeToNodeSubs : emptySet;
2666
2667 for (const downstreamNode of subscribedNodes) {
2668 if (!visitedNodes.has(downstreamNode)) {
2669 visitingNodes.push(downstreamNode);
2670 }
2671 }
2672 }
2673
2674 return visitedNodes;
2675}
2676
2677var Recoil_FunctionalCore = {
2678 getNodeLoadable,
2679 peekNodeLoadable,
2680 setNodeValue,
2681 initializeNode,
2682 cleanUpNode,
2683 setUnvalidatedAtomValue_DEPRECATED,
2684 peekNodeInfo,
2685 getDownstreamNodes
2686};
2687
2688/**
2689 * Copyright (c) Meta Platforms, Inc. and affiliates.
2690 *
2691 * This source code is licensed under the MIT license found in the
2692 * LICENSE file in the root directory of this source tree.
2693 *
2694 *
2695 * @format
2696 * @oncall recoil
2697 */
2698
2699let _invalidateMemoizedSnapshot = null;
2700
2701function setInvalidateMemoizedSnapshot(invalidate) {
2702 _invalidateMemoizedSnapshot = invalidate;
2703}
2704
2705function invalidateMemoizedSnapshot() {
2706 var _invalidateMemoizedSn;
2707
2708 (_invalidateMemoizedSn = _invalidateMemoizedSnapshot) === null || _invalidateMemoizedSn === void 0 ? void 0 : _invalidateMemoizedSn();
2709}
2710
2711var Recoil_SnapshotCache = {
2712 setInvalidateMemoizedSnapshot,
2713 invalidateMemoizedSnapshot
2714};
2715
2716const {
2717 getDownstreamNodes: getDownstreamNodes$1,
2718 getNodeLoadable: getNodeLoadable$1,
2719 setNodeValue: setNodeValue$1
2720} = Recoil_FunctionalCore;
2721
2722const {
2723 getNextComponentID: getNextComponentID$1
2724} = Recoil_Keys;
2725
2726const {
2727 getNode: getNode$2,
2728 getNodeMaybe: getNodeMaybe$2
2729} = Recoil_Node;
2730
2731const {
2732 DefaultValue: DefaultValue$1
2733} = Recoil_Node;
2734
2735const {
2736 reactMode: reactMode$1
2737} = Recoil_ReactMode;
2738
2739const {
2740 AbstractRecoilValue: AbstractRecoilValue$1,
2741 RecoilState: RecoilState$1,
2742 RecoilValueReadOnly: RecoilValueReadOnly$1,
2743 isRecoilValue: isRecoilValue$1
2744} = Recoil_RecoilValue$1;
2745
2746const {
2747 invalidateMemoizedSnapshot: invalidateMemoizedSnapshot$1
2748} = Recoil_SnapshotCache;
2749
2750
2751
2752
2753
2754
2755
2756function getRecoilValueAsLoadable(store, {
2757 key
2758}, treeState = store.getState().currentTree) {
2759 var _storeState$nextTree, _storeState$previousT;
2760
2761 // Reading from an older tree can cause bugs because the dependencies that we
2762 // discover during the read are lost.
2763 const storeState = store.getState();
2764
2765 if (!(treeState.version === storeState.currentTree.version || treeState.version === ((_storeState$nextTree = storeState.nextTree) === null || _storeState$nextTree === void 0 ? void 0 : _storeState$nextTree.version) || treeState.version === ((_storeState$previousT = storeState.previousTree) === null || _storeState$previousT === void 0 ? void 0 : _storeState$previousT.version))) {
2766 Recoil_recoverableViolation('Tried to read from a discarded tree');
2767 }
2768
2769 const loadable = getNodeLoadable$1(store, treeState, key);
2770
2771 if (loadable.state === 'loading') {
2772 loadable.contents.catch(() => {
2773 /**
2774 * HACK: intercept thrown error here to prevent an uncaught promise exception. Ideally this would happen closer to selector
2775 * execution (perhaps introducing a new ERROR class to be resolved by async selectors that are in an error state)
2776 */
2777 return;
2778 });
2779 }
2780
2781 return loadable;
2782}
2783
2784function applyAtomValueWrites(atomValues, writes) {
2785 const result = atomValues.clone();
2786 writes.forEach((v, k) => {
2787 if (v.state === 'hasValue' && v.contents instanceof DefaultValue$1) {
2788 result.delete(k);
2789 } else {
2790 result.set(k, v);
2791 }
2792 });
2793 return result;
2794}
2795
2796function valueFromValueOrUpdater(store, state, {
2797 key
2798}, valueOrUpdater) {
2799 if (typeof valueOrUpdater === 'function') {
2800 // Updater form: pass in the current value. Throw if the current value
2801 // is unavailable (namely when updating an async selector that's
2802 // pending or errored):
2803 const current = getNodeLoadable$1(store, state, key);
2804
2805 if (current.state === 'loading') {
2806 const msg = `Tried to set atom or selector "${key}" using an updater function while the current state is pending, this is not currently supported.`;
2807 Recoil_recoverableViolation(msg);
2808 throw Recoil_err(msg);
2809 } else if (current.state === 'hasError') {
2810 throw current.contents;
2811 } // T itself may be a function, so our refinement is not sufficient:
2812
2813
2814 return valueOrUpdater(current.contents); // flowlint-line unclear-type:off
2815 } else {
2816 return valueOrUpdater;
2817 }
2818}
2819
2820function applyAction(store, state, action) {
2821 if (action.type === 'set') {
2822 const {
2823 recoilValue,
2824 valueOrUpdater
2825 } = action;
2826 const newValue = valueFromValueOrUpdater(store, state, recoilValue, valueOrUpdater);
2827 const writes = setNodeValue$1(store, state, recoilValue.key, newValue);
2828
2829 for (const [key, loadable] of writes.entries()) {
2830 writeLoadableToTreeState(state, key, loadable);
2831 }
2832 } else if (action.type === 'setLoadable') {
2833 const {
2834 recoilValue: {
2835 key
2836 },
2837 loadable
2838 } = action;
2839 writeLoadableToTreeState(state, key, loadable);
2840 } else if (action.type === 'markModified') {
2841 const {
2842 recoilValue: {
2843 key
2844 }
2845 } = action;
2846 state.dirtyAtoms.add(key);
2847 } else if (action.type === 'setUnvalidated') {
2848 var _node$invalidate;
2849
2850 // Write value directly to state bypassing the Node interface as the node
2851 // definitions may not have been loaded yet when processing the initial snapshot.
2852 const {
2853 recoilValue: {
2854 key
2855 },
2856 unvalidatedValue
2857 } = action;
2858 const node = getNodeMaybe$2(key);
2859 node === null || node === void 0 ? void 0 : (_node$invalidate = node.invalidate) === null || _node$invalidate === void 0 ? void 0 : _node$invalidate.call(node, state);
2860 state.atomValues.delete(key);
2861 state.nonvalidatedAtoms.set(key, unvalidatedValue);
2862 state.dirtyAtoms.add(key);
2863 } else {
2864 Recoil_recoverableViolation(`Unknown action ${action.type}`);
2865 }
2866}
2867
2868function writeLoadableToTreeState(state, key, loadable) {
2869 if (loadable.state === 'hasValue' && loadable.contents instanceof DefaultValue$1) {
2870 state.atomValues.delete(key);
2871 } else {
2872 state.atomValues.set(key, loadable);
2873 }
2874
2875 state.dirtyAtoms.add(key);
2876 state.nonvalidatedAtoms.delete(key);
2877}
2878
2879function applyActionsToStore(store, actions) {
2880 store.replaceState(state => {
2881 const newState = copyTreeState(state);
2882
2883 for (const action of actions) {
2884 applyAction(store, newState, action);
2885 }
2886
2887 invalidateDownstreams(store, newState);
2888 invalidateMemoizedSnapshot$1();
2889 return newState;
2890 });
2891}
2892
2893function queueOrPerformStateUpdate(store, action) {
2894 if (batchStack.length) {
2895 const actionsByStore = batchStack[batchStack.length - 1];
2896 let actions = actionsByStore.get(store);
2897
2898 if (!actions) {
2899 actionsByStore.set(store, actions = []);
2900 }
2901
2902 actions.push(action);
2903 } else {
2904 applyActionsToStore(store, [action]);
2905 }
2906}
2907
2908const batchStack = [];
2909
2910function batchStart() {
2911 const actionsByStore = new Map();
2912 batchStack.push(actionsByStore);
2913 return () => {
2914 for (const [store, actions] of actionsByStore) {
2915 applyActionsToStore(store, actions);
2916 }
2917
2918 const popped = batchStack.pop();
2919
2920 if (popped !== actionsByStore) {
2921 Recoil_recoverableViolation('Incorrect order of batch popping');
2922 }
2923 };
2924}
2925
2926function copyTreeState(state) {
2927 return { ...state,
2928 atomValues: state.atomValues.clone(),
2929 nonvalidatedAtoms: state.nonvalidatedAtoms.clone(),
2930 dirtyAtoms: new Set(state.dirtyAtoms)
2931 };
2932}
2933
2934function invalidateDownstreams(store, state) {
2935 // Inform any nodes that were changed or downstream of changes so that they
2936 // can clear out any caches as needed due to the update:
2937 const downstreams = getDownstreamNodes$1(store, state, state.dirtyAtoms);
2938
2939 for (const key of downstreams) {
2940 var _getNodeMaybe, _getNodeMaybe$invalid;
2941
2942 (_getNodeMaybe = getNodeMaybe$2(key)) === null || _getNodeMaybe === void 0 ? void 0 : (_getNodeMaybe$invalid = _getNodeMaybe.invalidate) === null || _getNodeMaybe$invalid === void 0 ? void 0 : _getNodeMaybe$invalid.call(_getNodeMaybe, state);
2943 }
2944}
2945
2946function setRecoilValue(store, recoilValue, valueOrUpdater) {
2947 queueOrPerformStateUpdate(store, {
2948 type: 'set',
2949 recoilValue,
2950 valueOrUpdater
2951 });
2952}
2953
2954function setRecoilValueLoadable(store, recoilValue, loadable) {
2955 if (loadable instanceof DefaultValue$1) {
2956 return setRecoilValue(store, recoilValue, loadable);
2957 }
2958
2959 queueOrPerformStateUpdate(store, {
2960 type: 'setLoadable',
2961 recoilValue,
2962 loadable: loadable
2963 });
2964}
2965
2966function markRecoilValueModified(store, recoilValue) {
2967 queueOrPerformStateUpdate(store, {
2968 type: 'markModified',
2969 recoilValue
2970 });
2971}
2972
2973function setUnvalidatedRecoilValue(store, recoilValue, unvalidatedValue) {
2974 queueOrPerformStateUpdate(store, {
2975 type: 'setUnvalidated',
2976 recoilValue,
2977 unvalidatedValue
2978 });
2979}
2980
2981function subscribeToRecoilValue(store, {
2982 key
2983}, callback, componentDebugName = null) {
2984 const subID = getNextComponentID$1();
2985 const storeState = store.getState();
2986
2987 if (!storeState.nodeToComponentSubscriptions.has(key)) {
2988 storeState.nodeToComponentSubscriptions.set(key, new Map());
2989 }
2990
2991 Recoil_nullthrows(storeState.nodeToComponentSubscriptions.get(key)).set(subID, [componentDebugName !== null && componentDebugName !== void 0 ? componentDebugName : '<not captured>', callback]); // Handle the case that, during the same tick that we are subscribing, an atom
2992 // has been updated by some effect handler. Otherwise we will miss the update.
2993
2994 const mode = reactMode$1();
2995
2996 if (mode.early && (mode.mode === 'LEGACY' || mode.mode === 'MUTABLE_SOURCE')) {
2997 const nextTree = store.getState().nextTree;
2998
2999 if (nextTree && nextTree.dirtyAtoms.has(key)) {
3000 callback(nextTree);
3001 }
3002 }
3003
3004 return {
3005 release: () => {
3006 const releaseStoreState = store.getState();
3007 const subs = releaseStoreState.nodeToComponentSubscriptions.get(key);
3008
3009 if (subs === undefined || !subs.has(subID)) {
3010 Recoil_recoverableViolation(`Subscription missing at release time for atom ${key}. This is a bug in Recoil.`);
3011 return;
3012 }
3013
3014 subs.delete(subID);
3015
3016 if (subs.size === 0) {
3017 releaseStoreState.nodeToComponentSubscriptions.delete(key);
3018 }
3019 }
3020 };
3021}
3022
3023function refreshRecoilValue(store, recoilValue) {
3024 var _node$clearCache;
3025
3026 const {
3027 currentTree
3028 } = store.getState();
3029 const node = getNode$2(recoilValue.key);
3030 (_node$clearCache = node.clearCache) === null || _node$clearCache === void 0 ? void 0 : _node$clearCache.call(node, store, currentTree);
3031}
3032
3033var Recoil_RecoilValueInterface = {
3034 RecoilValueReadOnly: RecoilValueReadOnly$1,
3035 AbstractRecoilValue: AbstractRecoilValue$1,
3036 RecoilState: RecoilState$1,
3037 getRecoilValueAsLoadable,
3038 setRecoilValue,
3039 setRecoilValueLoadable,
3040 markRecoilValueModified,
3041 setUnvalidatedRecoilValue,
3042 subscribeToRecoilValue,
3043 isRecoilValue: isRecoilValue$1,
3044 applyAtomValueWrites,
3045 // TODO Remove export when deprecating initialStoreState_DEPRECATED in RecoilRoot
3046 batchStart,
3047 writeLoadableToTreeState,
3048 invalidateDownstreams,
3049 copyTreeState,
3050 refreshRecoilValue
3051};
3052
3053/**
3054 * Copyright (c) Meta Platforms, Inc. and affiliates.
3055 *
3056 * This source code is licensed under the MIT license found in the
3057 * LICENSE file in the root directory of this source tree.
3058 *
3059 *
3060 * @format
3061 * @oncall recoil
3062 */
3063/**
3064 * The someSet() method tests whether some elements in the given Set pass the
3065 * test implemented by the provided function.
3066 */
3067
3068function someSet(set, callback, context) {
3069 const iterator = set.entries();
3070 let current = iterator.next();
3071
3072 while (!current.done) {
3073 const entry = current.value;
3074
3075 if (callback.call(context, entry[1], entry[0], set)) {
3076 return true;
3077 }
3078
3079 current = iterator.next();
3080 }
3081
3082 return false;
3083}
3084
3085var Recoil_someSet = someSet;
3086
3087const {
3088 cleanUpNode: cleanUpNode$1
3089} = Recoil_FunctionalCore;
3090
3091const {
3092 deleteNodeConfigIfPossible: deleteNodeConfigIfPossible$1,
3093 getNode: getNode$3
3094} = Recoil_Node;
3095
3096const {
3097 RetentionZone: RetentionZone$2
3098} = Recoil_RetentionZone;
3099
3100
3101
3102
3103
3104
3105
3106 // Components that aren't mounted after suspending for this long will be assumed
3107// to be discarded and their resources released.
3108
3109
3110const SUSPENSE_TIMEOUT_MS = 120000;
3111const emptySet$1 = new Set();
3112
3113function releaseRetainablesNowOnCurrentTree(store, retainables) {
3114 const storeState = store.getState();
3115 const treeState = storeState.currentTree;
3116
3117 if (storeState.nextTree) {
3118 Recoil_recoverableViolation('releaseNodesNowOnCurrentTree should only be called at the end of a batch');
3119 return; // leak memory rather than erase something that's about to be used.
3120 }
3121
3122 const nodes = new Set();
3123
3124 for (const r of retainables) {
3125 if (r instanceof RetentionZone$2) {
3126 for (const n of nodesRetainedByZone(storeState, r)) {
3127 nodes.add(n);
3128 }
3129 } else {
3130 nodes.add(r);
3131 }
3132 }
3133
3134 const releasableNodes = findReleasableNodes(store, nodes);
3135
3136 for (const node of releasableNodes) {
3137 releaseNode(store, treeState, node);
3138 }
3139}
3140
3141function findReleasableNodes(store, searchFromNodes) {
3142 const storeState = store.getState();
3143 const treeState = storeState.currentTree;
3144 const graph = store.getGraph(treeState.version);
3145 const releasableNodes = new Set(); // mutated to collect answer
3146
3147 const nonReleasableNodes = new Set();
3148 findReleasableNodesInner(searchFromNodes);
3149 return releasableNodes;
3150
3151 function findReleasableNodesInner(searchFromNodes) {
3152 const releasableNodesFoundThisIteration = new Set();
3153 const downstreams = getDownstreamNodesInTopologicalOrder(store, treeState, searchFromNodes, releasableNodes, // don't descend into these
3154 nonReleasableNodes // don't descend into these
3155 ); // Find which of the downstream nodes are releasable and which are not:
3156
3157 for (const node of downstreams) {
3158 var _storeState$retention;
3159
3160 // Not releasable if configured to be retained forever:
3161 if (getNode$3(node).retainedBy === 'recoilRoot') {
3162 nonReleasableNodes.add(node);
3163 continue;
3164 } // Not releasable if retained directly by a component:
3165
3166
3167 if (((_storeState$retention = storeState.retention.referenceCounts.get(node)) !== null && _storeState$retention !== void 0 ? _storeState$retention : 0) > 0) {
3168 nonReleasableNodes.add(node);
3169 continue;
3170 } // Not releasable if retained by a zone:
3171
3172
3173 if (zonesThatCouldRetainNode(node).some(z => storeState.retention.referenceCounts.get(z))) {
3174 nonReleasableNodes.add(node);
3175 continue;
3176 } // Not releasable if it has a non-releasable child (which will already be in
3177 // nonReleasableNodes because we are going in topological order):
3178
3179
3180 const nodeChildren = graph.nodeToNodeSubscriptions.get(node);
3181
3182 if (nodeChildren && Recoil_someSet(nodeChildren, child => nonReleasableNodes.has(child))) {
3183 nonReleasableNodes.add(node);
3184 continue;
3185 }
3186
3187 releasableNodes.add(node);
3188 releasableNodesFoundThisIteration.add(node);
3189 } // If we found any releasable nodes, we need to walk UP from those nodes to
3190 // find whether their parents can now be released as well:
3191
3192
3193 const parents = new Set();
3194
3195 for (const node of releasableNodesFoundThisIteration) {
3196 for (const parent of (_graph$nodeDeps$get = graph.nodeDeps.get(node)) !== null && _graph$nodeDeps$get !== void 0 ? _graph$nodeDeps$get : emptySet$1) {
3197 var _graph$nodeDeps$get;
3198
3199 if (!releasableNodes.has(parent)) {
3200 parents.add(parent);
3201 }
3202 }
3203 }
3204
3205 if (parents.size) {
3206 findReleasableNodesInner(parents);
3207 }
3208 }
3209} // Children before parents
3210
3211
3212function getDownstreamNodesInTopologicalOrder(store, treeState, nodes, // Mutable set is destroyed in place
3213doNotDescendInto1, doNotDescendInto2) {
3214 const graph = store.getGraph(treeState.version);
3215 const answer = [];
3216 const visited = new Set();
3217
3218 while (nodes.size > 0) {
3219 visit(Recoil_nullthrows(nodes.values().next().value));
3220 }
3221
3222 return answer;
3223
3224 function visit(node) {
3225 if (doNotDescendInto1.has(node) || doNotDescendInto2.has(node)) {
3226 nodes.delete(node);
3227 return;
3228 }
3229
3230 if (visited.has(node)) {
3231 return;
3232 }
3233
3234 const children = graph.nodeToNodeSubscriptions.get(node);
3235
3236 if (children) {
3237 for (const child of children) {
3238 visit(child);
3239 }
3240 }
3241
3242 visited.add(node);
3243 nodes.delete(node);
3244 answer.push(node);
3245 }
3246}
3247
3248function releaseNode(store, treeState, node) {
3249 if (!Recoil_gkx('recoil_memory_managament_2020')) {
3250 return;
3251 } // Atom effects, in-closure caches, etc.:
3252
3253
3254 cleanUpNode$1(store, node); // Delete from store state:
3255
3256 const storeState = store.getState();
3257 storeState.knownAtoms.delete(node);
3258 storeState.knownSelectors.delete(node);
3259 storeState.nodeTransactionSubscriptions.delete(node);
3260 storeState.retention.referenceCounts.delete(node);
3261 const zones = zonesThatCouldRetainNode(node);
3262
3263 for (const zone of zones) {
3264 var _storeState$retention2;
3265
3266 (_storeState$retention2 = storeState.retention.nodesRetainedByZone.get(zone)) === null || _storeState$retention2 === void 0 ? void 0 : _storeState$retention2.delete(node);
3267 } // Note that we DO NOT delete from nodeToComponentSubscriptions because this
3268 // already happens when the last component that was retaining the node unmounts,
3269 // and this could happen either before or after that.
3270 // Delete from TreeState and dep graph:
3271
3272
3273 treeState.atomValues.delete(node);
3274 treeState.dirtyAtoms.delete(node);
3275 treeState.nonvalidatedAtoms.delete(node);
3276 const graph = storeState.graphsByVersion.get(treeState.version);
3277
3278 if (graph) {
3279 const deps = graph.nodeDeps.get(node);
3280
3281 if (deps !== undefined) {
3282 graph.nodeDeps.delete(node);
3283
3284 for (const dep of deps) {
3285 var _graph$nodeToNodeSubs;
3286
3287 (_graph$nodeToNodeSubs = graph.nodeToNodeSubscriptions.get(dep)) === null || _graph$nodeToNodeSubs === void 0 ? void 0 : _graph$nodeToNodeSubs.delete(node);
3288 }
3289 } // No need to delete sub's deps as there should be no subs at this point.
3290 // But an invariant would require deleting nodes in topological order.
3291
3292
3293 graph.nodeToNodeSubscriptions.delete(node);
3294 } // Node config (for family members only as their configs can be recreated, and
3295 // only if they are not retained within any other Stores):
3296
3297
3298 deleteNodeConfigIfPossible$1(node);
3299}
3300
3301function nodesRetainedByZone(storeState, zone) {
3302 var _storeState$retention3;
3303
3304 return (_storeState$retention3 = storeState.retention.nodesRetainedByZone.get(zone)) !== null && _storeState$retention3 !== void 0 ? _storeState$retention3 : emptySet$1;
3305}
3306
3307function zonesThatCouldRetainNode(node) {
3308 const retainedBy = getNode$3(node).retainedBy;
3309
3310 if (retainedBy === undefined || retainedBy === 'components' || retainedBy === 'recoilRoot') {
3311 return [];
3312 } else if (retainedBy instanceof RetentionZone$2) {
3313 return [retainedBy];
3314 } else {
3315 return retainedBy; // it's an array of zones
3316 }
3317}
3318
3319function scheduleOrPerformPossibleReleaseOfRetainable(store, retainable) {
3320 const state = store.getState();
3321
3322 if (state.nextTree) {
3323 state.retention.retainablesToCheckForRelease.add(retainable);
3324 } else {
3325 releaseRetainablesNowOnCurrentTree(store, new Set([retainable]));
3326 }
3327}
3328
3329function updateRetainCount(store, retainable, delta) {
3330 var _map$get;
3331
3332 if (!Recoil_gkx('recoil_memory_managament_2020')) {
3333 return;
3334 }
3335
3336 const map = store.getState().retention.referenceCounts;
3337 const newCount = ((_map$get = map.get(retainable)) !== null && _map$get !== void 0 ? _map$get : 0) + delta;
3338
3339 if (newCount === 0) {
3340 updateRetainCountToZero(store, retainable);
3341 } else {
3342 map.set(retainable, newCount);
3343 }
3344}
3345
3346function updateRetainCountToZero(store, retainable) {
3347 if (!Recoil_gkx('recoil_memory_managament_2020')) {
3348 return;
3349 }
3350
3351 const map = store.getState().retention.referenceCounts;
3352 map.delete(retainable);
3353 scheduleOrPerformPossibleReleaseOfRetainable(store, retainable);
3354}
3355
3356function releaseScheduledRetainablesNow(store) {
3357 if (!Recoil_gkx('recoil_memory_managament_2020')) {
3358 return;
3359 }
3360
3361 const state = store.getState();
3362 releaseRetainablesNowOnCurrentTree(store, state.retention.retainablesToCheckForRelease);
3363 state.retention.retainablesToCheckForRelease.clear();
3364}
3365
3366function retainedByOptionWithDefault(r) {
3367 // The default will change from 'recoilRoot' to 'components' in the future.
3368 return r === undefined ? 'recoilRoot' : r;
3369}
3370
3371var Recoil_Retention = {
3372 SUSPENSE_TIMEOUT_MS,
3373 updateRetainCount,
3374 updateRetainCountToZero,
3375 releaseScheduledRetainablesNow,
3376 retainedByOptionWithDefault
3377};
3378
3379/**
3380 * Copyright (c) Meta Platforms, Inc. and affiliates.
3381 *
3382 * This source code is licensed under the MIT license found in the
3383 * LICENSE file in the root directory of this source tree.
3384 *
3385 * This is to export esstiential functions from react-dom
3386 * for our web build
3387 *
3388 *
3389 * @format
3390 * @oncall recoil
3391 */
3392const {
3393 unstable_batchedUpdates
3394} = reactDom;
3395
3396var ReactBatchedUpdates = {
3397 unstable_batchedUpdates
3398};
3399
3400/**
3401 * Copyright (c) Meta Platforms, Inc. and affiliates.
3402 *
3403 * This source code is licensed under the MIT license found in the
3404 * LICENSE file in the root directory of this source tree.
3405 *
3406 * This is to export esstiential functions from react-dom
3407 * for our web build
3408 *
3409 *
3410 * @format
3411 * @oncall recoil
3412 */
3413// @fb-only: const {unstable_batchedUpdates} = require('ReactDOMComet');
3414// prettier-ignore
3415const {
3416 unstable_batchedUpdates: unstable_batchedUpdates$1
3417} = ReactBatchedUpdates; // @oss-only
3418
3419
3420var Recoil_ReactBatchedUpdates = {
3421 unstable_batchedUpdates: unstable_batchedUpdates$1
3422};
3423
3424/**
3425 * Copyright (c) Meta Platforms, Inc. and affiliates.
3426 *
3427 * This source code is licensed under the MIT license found in the
3428 * LICENSE file in the root directory of this source tree.
3429 *
3430 *
3431 * @format
3432 * @oncall recoil
3433 */
3434const {
3435 batchStart: batchStart$1
3436} = Recoil_RecoilValueInterface;
3437
3438const {
3439 unstable_batchedUpdates: unstable_batchedUpdates$2
3440} = Recoil_ReactBatchedUpdates; // flowlint-next-line unclear-type:off
3441
3442
3443/*
3444 * During SSR, unstable_batchedUpdates may be undefined so this
3445 * falls back to a basic function that executes the batch
3446 */
3447let batcher = unstable_batchedUpdates$2 || (batchFn => batchFn());
3448/**
3449 * Sets the provided batcher function as the batcher function used by Recoil.
3450 *
3451 * Set the batcher to a custom batcher for your renderer,
3452 * if you use a renderer other than React DOM or React Native.
3453 */
3454
3455
3456const setBatcher = newBatcher => {
3457 batcher = newBatcher;
3458};
3459/**
3460 * Returns the current batcher function.
3461 */
3462
3463
3464const getBatcher = () => batcher;
3465/**
3466 * Calls the current batcher function and passes the
3467 * provided callback function.
3468 */
3469
3470
3471const batchUpdates = callback => {
3472 batcher(() => {
3473 let batchEnd = () => undefined;
3474
3475 try {
3476 batchEnd = batchStart$1();
3477 callback();
3478 } finally {
3479 batchEnd();
3480 }
3481 });
3482};
3483
3484var Recoil_Batching = {
3485 getBatcher,
3486 setBatcher,
3487 batchUpdates
3488};
3489
3490/**
3491 * Copyright (c) Meta Platforms, Inc. and affiliates.
3492 *
3493 * This source code is licensed under the MIT license found in the
3494 * LICENSE file in the root directory of this source tree.
3495 *
3496 *
3497 * @format
3498 * @oncall recoil
3499 */
3500/**
3501 * Combines multiple Iterables into a single Iterable.
3502 * Traverses the input Iterables in the order provided and maintains the order
3503 * of their elements.
3504 *
3505 * Example:
3506 * ```
3507 * const r = Array.from(concatIterables(['a', 'b'], ['c'], ['d', 'e', 'f']));
3508 * r == ['a', 'b', 'c', 'd', 'e', 'f'];
3509 * ```
3510 */
3511
3512function* concatIterables(iters) {
3513 for (const iter of iters) {
3514 for (const val of iter) {
3515 yield val;
3516 }
3517 }
3518}
3519
3520var Recoil_concatIterables = concatIterables;
3521
3522/**
3523 * Copyright (c) Meta Platforms, Inc. and affiliates.
3524 *
3525 * This source code is licensed under the MIT license found in the
3526 * LICENSE file in the root directory of this source tree.
3527 *
3528 *
3529 * @format
3530 * @oncall recoil
3531 */
3532/* eslint-disable fb-www/typeof-undefined */
3533
3534const isSSR = // $FlowFixMe(site=recoil) Window does not have a FlowType definition https://github.com/facebook/flow/issues/6709
3535typeof Window === 'undefined' || typeof window === 'undefined';
3536/* eslint-enable fb-www/typeof-undefined */
3537
3538const isWindow = value => !isSSR && ( // $FlowFixMe(site=recoil) Window does not have a FlowType definition https://github.com/facebook/flow/issues/6709
3539value === window || value instanceof Window);
3540
3541const isReactNative = typeof navigator !== 'undefined' && navigator.product === 'ReactNative'; // eslint-disable-line fb-www/typeof-undefined
3542
3543var Recoil_Environment = {
3544 isSSR,
3545 isReactNative,
3546 isWindow
3547};
3548
3549/**
3550 * Copyright (c) Meta Platforms, Inc. and affiliates.
3551 *
3552 * This source code is licensed under the MIT license found in the
3553 * LICENSE file in the root directory of this source tree.
3554 *
3555 *
3556 * @format
3557 * @oncall recoil
3558 */
3559/**
3560 * Caches a function's results based on the key returned by the passed
3561 * hashFunction.
3562 */
3563
3564function memoizeWithArgsHash(fn, hashFunction) {
3565 let cache;
3566 return (...args) => {
3567 if (!cache) {
3568 cache = {};
3569 }
3570
3571 const key = hashFunction(...args);
3572
3573 if (!Object.hasOwnProperty.call(cache, key)) {
3574 cache[key] = fn(...args);
3575 }
3576
3577 return cache[key];
3578 };
3579}
3580/**
3581 * Caches a function's results based on a comparison of the arguments.
3582 * Only caches the last return of the function.
3583 * Defaults to reference equality
3584 */
3585
3586
3587function memoizeOneWithArgsHash(fn, hashFunction) {
3588 let lastKey;
3589 let lastResult; // breaking cache when arguments change
3590
3591 return (...args) => {
3592 const key = hashFunction(...args);
3593
3594 if (lastKey === key) {
3595 return lastResult;
3596 }
3597
3598 lastKey = key;
3599 lastResult = fn(...args);
3600 return lastResult;
3601 };
3602}
3603/**
3604 * Caches a function's results based on a comparison of the arguments.
3605 * Only caches the last return of the function.
3606 * Defaults to reference equality
3607 */
3608
3609
3610function memoizeOneWithArgsHashAndInvalidation(fn, hashFunction) {
3611 let lastKey;
3612 let lastResult; // breaking cache when arguments change
3613
3614 const memoizedFn = (...args) => {
3615 const key = hashFunction(...args);
3616
3617 if (lastKey === key) {
3618 return lastResult;
3619 }
3620
3621 lastKey = key;
3622 lastResult = fn(...args);
3623 return lastResult;
3624 };
3625
3626 const invalidate = () => {
3627 lastKey = null;
3628 };
3629
3630 return [memoizedFn, invalidate];
3631}
3632
3633var Recoil_Memoize = {
3634 memoizeWithArgsHash,
3635 memoizeOneWithArgsHash,
3636 memoizeOneWithArgsHashAndInvalidation
3637};
3638
3639const {
3640 batchUpdates: batchUpdates$1
3641} = Recoil_Batching;
3642
3643const {
3644 initializeNode: initializeNode$1,
3645 peekNodeInfo: peekNodeInfo$1
3646} = Recoil_FunctionalCore;
3647
3648const {
3649 graph: graph$1
3650} = Recoil_Graph;
3651
3652const {
3653 getNextStoreID: getNextStoreID$1
3654} = Recoil_Keys;
3655
3656const {
3657 DEFAULT_VALUE: DEFAULT_VALUE$1,
3658 recoilValues: recoilValues$1,
3659 recoilValuesForKeys: recoilValuesForKeys$2
3660} = Recoil_Node;
3661
3662const {
3663 AbstractRecoilValue: AbstractRecoilValue$2,
3664 getRecoilValueAsLoadable: getRecoilValueAsLoadable$1,
3665 setRecoilValue: setRecoilValue$1,
3666 setUnvalidatedRecoilValue: setUnvalidatedRecoilValue$1
3667} = Recoil_RecoilValueInterface;
3668
3669const {
3670 updateRetainCount: updateRetainCount$1
3671} = Recoil_Retention;
3672
3673const {
3674 setInvalidateMemoizedSnapshot: setInvalidateMemoizedSnapshot$1
3675} = Recoil_SnapshotCache;
3676
3677const {
3678 getNextTreeStateVersion: getNextTreeStateVersion$2,
3679 makeEmptyStoreState: makeEmptyStoreState$1
3680} = Recoil_State;
3681
3682
3683
3684const {
3685 isSSR: isSSR$1
3686} = Recoil_Environment;
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696const {
3697 memoizeOneWithArgsHashAndInvalidation: memoizeOneWithArgsHashAndInvalidation$1
3698} = Recoil_Memoize;
3699
3700
3701
3702 // Opaque at this surface because it's part of the public API from here.
3703
3704
3705const retainWarning = `
3706Recoil Snapshots only last for the duration of the callback they are provided to. To keep a Snapshot longer, do this:
3707
3708 const release = snapshot.retain();
3709 try {
3710 await doSomethingWithSnapshot(snapshot);
3711 } finally {
3712 release();
3713 }
3714
3715This is currently a DEV-only warning but will become a thrown exception in the next release of Recoil.
3716`; // A "Snapshot" is "read-only" and captures a specific set of values of atoms.
3717// However, the data-flow-graph and selector values may evolve as selector
3718// evaluation functions are executed and async selectors resolve.
3719
3720class Snapshot {
3721 // eslint-disable-next-line fb-www/no-uninitialized-properties
3722 constructor(storeState, parentStoreID) {
3723 _defineProperty(this, "_store", void 0);
3724
3725 _defineProperty(this, "_refCount", 1);
3726
3727 _defineProperty(this, "getLoadable", recoilValue => {
3728 this.checkRefCount_INTERNAL();
3729 return getRecoilValueAsLoadable$1(this._store, recoilValue);
3730 });
3731
3732 _defineProperty(this, "getPromise", recoilValue => {
3733 this.checkRefCount_INTERNAL();
3734 return this.getLoadable(recoilValue).toPromise();
3735 });
3736
3737 _defineProperty(this, "getNodes_UNSTABLE", opt => {
3738 this.checkRefCount_INTERNAL(); // TODO Deal with modified selectors
3739
3740 if ((opt === null || opt === void 0 ? void 0 : opt.isModified) === true) {
3741 if ((opt === null || opt === void 0 ? void 0 : opt.isInitialized) === false) {
3742 return [];
3743 }
3744
3745 const state = this._store.getState().currentTree;
3746
3747 return recoilValuesForKeys$2(state.dirtyAtoms);
3748 }
3749
3750 const knownAtoms = this._store.getState().knownAtoms;
3751
3752 const knownSelectors = this._store.getState().knownSelectors;
3753
3754 return (opt === null || opt === void 0 ? void 0 : opt.isInitialized) == null ? recoilValues$1.values() : opt.isInitialized === true ? recoilValuesForKeys$2(Recoil_concatIterables([knownAtoms, knownSelectors])) : Recoil_filterIterable(recoilValues$1.values(), ({
3755 key
3756 }) => !knownAtoms.has(key) && !knownSelectors.has(key));
3757 });
3758
3759 _defineProperty(this, "getInfo_UNSTABLE", ({
3760 key
3761 }) => {
3762 this.checkRefCount_INTERNAL();
3763 return peekNodeInfo$1(this._store, this._store.getState().currentTree, key);
3764 });
3765
3766 _defineProperty(this, "map", mapper => {
3767 this.checkRefCount_INTERNAL();
3768 const mutableSnapshot = new MutableSnapshot(this, batchUpdates$1);
3769 mapper(mutableSnapshot); // if removing batchUpdates from `set` add it here
3770
3771 return mutableSnapshot;
3772 });
3773
3774 _defineProperty(this, "asyncMap", async mapper => {
3775 this.checkRefCount_INTERNAL();
3776 const mutableSnapshot = new MutableSnapshot(this, batchUpdates$1);
3777 mutableSnapshot.retain(); // Retain new snapshot during async mapper
3778
3779 await mapper(mutableSnapshot); // Continue to retain the new snapshot for the user, but auto-release it
3780 // after the next tick, the same as a new synchronous snapshot.
3781
3782 mutableSnapshot.autoRelease_INTERNAL();
3783 return mutableSnapshot;
3784 });
3785
3786 this._store = {
3787 storeID: getNextStoreID$1(),
3788 parentStoreID,
3789 getState: () => storeState,
3790 replaceState: replacer => {
3791 // no batching, so nextTree is never active
3792 storeState.currentTree = replacer(storeState.currentTree);
3793 },
3794 getGraph: version => {
3795 const graphs = storeState.graphsByVersion;
3796
3797 if (graphs.has(version)) {
3798 return Recoil_nullthrows(graphs.get(version));
3799 }
3800
3801 const newGraph = graph$1();
3802 graphs.set(version, newGraph);
3803 return newGraph;
3804 },
3805 subscribeToTransactions: () => ({
3806 release: () => {}
3807 }),
3808 addTransactionMetadata: () => {
3809 throw Recoil_err('Cannot subscribe to Snapshots');
3810 }
3811 }; // Initialize any nodes that are live in the parent store (primarily so that
3812 // this snapshot gets counted towards the node's live stores count).
3813 // TODO Optimize this when cloning snapshots for callbacks
3814
3815 for (const nodeKey of this._store.getState().knownAtoms) {
3816 initializeNode$1(this._store, nodeKey, 'get');
3817 updateRetainCount$1(this._store, nodeKey, 1);
3818 }
3819
3820 this.autoRelease_INTERNAL();
3821 }
3822
3823 retain() {
3824 if (this._refCount <= 0) {
3825 if (process.env.NODE_ENV !== "production") {
3826 throw Recoil_err('Snapshot has already been released.');
3827 } else {
3828 Recoil_recoverableViolation('Attempt to retain() Snapshot that was already released.');
3829 }
3830 }
3831
3832 this._refCount++;
3833 let released = false;
3834 return () => {
3835 if (!released) {
3836 released = true;
3837
3838 this._release();
3839 }
3840 };
3841 }
3842 /**
3843 * Release the snapshot on the next tick. This means the snapshot is retained
3844 * during the execution of the current function using it.
3845 */
3846
3847
3848 autoRelease_INTERNAL() {
3849 if (!isSSR$1) {
3850 // Use timeout of 10 to workaround Firefox issue: https://github.com/facebookexperimental/Recoil/issues/1936
3851 window.setTimeout(() => this._release(), 10);
3852 }
3853 }
3854
3855 _release() {
3856 this._refCount--;
3857
3858 if (this._refCount === 0) {
3859 this._store.getState().nodeCleanupFunctions.forEach(cleanup => cleanup());
3860
3861 this._store.getState().nodeCleanupFunctions.clear();
3862
3863 if (!Recoil_gkx('recoil_memory_managament_2020')) {
3864 return;
3865 } // Temporarily nerfing this to allow us to find broken call sites without
3866 // actually breaking anybody yet.
3867 // for (const k of this._store.getState().knownAtoms) {
3868 // updateRetainCountToZero(this._store, k);
3869 // }
3870
3871 } else if (this._refCount < 0) {
3872 if (process.env.NODE_ENV !== "production") {
3873 Recoil_recoverableViolation('Snapshot released an extra time.');
3874 }
3875 }
3876 }
3877
3878 isRetained() {
3879 return this._refCount > 0;
3880 }
3881
3882 checkRefCount_INTERNAL() {
3883 if (Recoil_gkx('recoil_memory_managament_2020') && this._refCount <= 0) {
3884 if (process.env.NODE_ENV !== "production") {
3885 Recoil_recoverableViolation(retainWarning);
3886 } // What we will ship later:
3887 // throw err(retainWarning);
3888
3889 }
3890 }
3891
3892 getStore_INTERNAL() {
3893 this.checkRefCount_INTERNAL();
3894 return this._store;
3895 }
3896
3897 getID() {
3898 this.checkRefCount_INTERNAL();
3899 return this._store.getState().currentTree.stateID;
3900 }
3901
3902 getStoreID() {
3903 this.checkRefCount_INTERNAL();
3904 return this._store.storeID;
3905 } // We want to allow the methods to be destructured and used as accessors
3906
3907 /* eslint-disable fb-www/extra-arrow-initializer */
3908
3909 /* eslint-enable fb-www/extra-arrow-initializer */
3910
3911
3912}
3913
3914function cloneStoreState(store, treeState, bumpVersion = false) {
3915 const storeState = store.getState();
3916 const version = bumpVersion ? getNextTreeStateVersion$2() : treeState.version;
3917 return {
3918 // Always clone the TreeState to isolate stores from accidental mutations.
3919 // For example, reading a selector from a cloned snapshot shouldn't cache
3920 // in the original treestate which may cause the original to skip
3921 // initialization of upstream atoms.
3922 currentTree: {
3923 // TODO snapshots shouldn't really have versions because a new version number
3924 // is always assigned when the snapshot is gone to.
3925 version: bumpVersion ? version : treeState.version,
3926 stateID: bumpVersion ? version : treeState.stateID,
3927 transactionMetadata: { ...treeState.transactionMetadata
3928 },
3929 dirtyAtoms: new Set(treeState.dirtyAtoms),
3930 atomValues: treeState.atomValues.clone(),
3931 nonvalidatedAtoms: treeState.nonvalidatedAtoms.clone()
3932 },
3933 commitDepth: 0,
3934 nextTree: null,
3935 previousTree: null,
3936 knownAtoms: new Set(storeState.knownAtoms),
3937 // FIXME here's a copy
3938 knownSelectors: new Set(storeState.knownSelectors),
3939 // FIXME here's a copy
3940 transactionSubscriptions: new Map(),
3941 nodeTransactionSubscriptions: new Map(),
3942 nodeToComponentSubscriptions: new Map(),
3943 queuedComponentCallbacks_DEPRECATED: [],
3944 suspendedComponentResolvers: new Set(),
3945 graphsByVersion: new Map().set(version, store.getGraph(treeState.version)),
3946 retention: {
3947 referenceCounts: new Map(),
3948 nodesRetainedByZone: new Map(),
3949 retainablesToCheckForRelease: new Set()
3950 },
3951 // FIXME here's a copy
3952 // Create blank cleanup handlers for atoms so snapshots don't re-run
3953 // atom effects.
3954 nodeCleanupFunctions: new Map(Recoil_mapIterable(storeState.nodeCleanupFunctions.entries(), ([key]) => [key, () => {}]))
3955 };
3956} // Factory to build a fresh snapshot
3957
3958
3959function freshSnapshot(initializeState) {
3960 const snapshot = new Snapshot(makeEmptyStoreState$1());
3961 return initializeState != null ? snapshot.map(initializeState) : snapshot;
3962} // Factory to clone a snapshot state
3963
3964
3965const [memoizedCloneSnapshot, invalidateMemoizedSnapshot$2] = memoizeOneWithArgsHashAndInvalidation$1( // $FlowFixMe[missing-local-annot]
3966(store, version) => {
3967 var _storeState$nextTree;
3968
3969 const storeState = store.getState();
3970 const treeState = version === 'latest' ? (_storeState$nextTree = storeState.nextTree) !== null && _storeState$nextTree !== void 0 ? _storeState$nextTree : storeState.currentTree : Recoil_nullthrows(storeState.previousTree);
3971 return new Snapshot(cloneStoreState(store, treeState), store.storeID);
3972}, (store, version) => {
3973 var _store$getState$nextT, _store$getState$previ;
3974
3975 return String(version) + String(store.storeID) + String((_store$getState$nextT = store.getState().nextTree) === null || _store$getState$nextT === void 0 ? void 0 : _store$getState$nextT.version) + String(store.getState().currentTree.version) + String((_store$getState$previ = store.getState().previousTree) === null || _store$getState$previ === void 0 ? void 0 : _store$getState$previ.version);
3976}); // Avoid circular dependencies
3977
3978setInvalidateMemoizedSnapshot$1(invalidateMemoizedSnapshot$2);
3979
3980function cloneSnapshot(store, version = 'latest') {
3981 const snapshot = memoizedCloneSnapshot(store, version);
3982
3983 if (!snapshot.isRetained()) {
3984 invalidateMemoizedSnapshot$2();
3985 return memoizedCloneSnapshot(store, version);
3986 }
3987
3988 return snapshot;
3989}
3990
3991class MutableSnapshot extends Snapshot {
3992 constructor(snapshot, batch) {
3993 super(cloneStoreState(snapshot.getStore_INTERNAL(), snapshot.getStore_INTERNAL().getState().currentTree, true), snapshot.getStoreID());
3994
3995 _defineProperty(this, "_batch", void 0);
3996
3997 _defineProperty(this, "set", (recoilState, newValueOrUpdater) => {
3998 this.checkRefCount_INTERNAL();
3999 const store = this.getStore_INTERNAL(); // This batchUpdates ensures this `set` is applied immediately and you can
4000 // read the written value after calling `set`. I would like to remove this
4001 // behavior and only batch in `Snapshot.map`, but this would be a breaking
4002 // change potentially.
4003
4004 this._batch(() => {
4005 updateRetainCount$1(store, recoilState.key, 1);
4006 setRecoilValue$1(this.getStore_INTERNAL(), recoilState, newValueOrUpdater);
4007 });
4008 });
4009
4010 _defineProperty(this, "reset", recoilState => {
4011 this.checkRefCount_INTERNAL();
4012 const store = this.getStore_INTERNAL(); // See note at `set` about batched updates.
4013
4014 this._batch(() => {
4015 updateRetainCount$1(store, recoilState.key, 1);
4016 setRecoilValue$1(this.getStore_INTERNAL(), recoilState, DEFAULT_VALUE$1);
4017 });
4018 });
4019
4020 _defineProperty(this, "setUnvalidatedAtomValues_DEPRECATED", values => {
4021 this.checkRefCount_INTERNAL();
4022 const store = this.getStore_INTERNAL(); // See note at `set` about batched updates.
4023
4024 batchUpdates$1(() => {
4025 for (const [k, v] of values.entries()) {
4026 updateRetainCount$1(store, k, 1);
4027 setUnvalidatedRecoilValue$1(store, new AbstractRecoilValue$2(k), v);
4028 }
4029 });
4030 });
4031
4032 this._batch = batch;
4033 }
4034
4035}
4036
4037var Recoil_Snapshot = {
4038 Snapshot,
4039 MutableSnapshot,
4040 freshSnapshot,
4041 cloneSnapshot
4042};
4043
4044var Recoil_Snapshot_1 = Recoil_Snapshot.Snapshot;
4045var Recoil_Snapshot_2 = Recoil_Snapshot.MutableSnapshot;
4046var Recoil_Snapshot_3 = Recoil_Snapshot.freshSnapshot;
4047var Recoil_Snapshot_4 = Recoil_Snapshot.cloneSnapshot;
4048
4049var Recoil_Snapshot$1 = /*#__PURE__*/Object.freeze({
4050 __proto__: null,
4051 Snapshot: Recoil_Snapshot_1,
4052 MutableSnapshot: Recoil_Snapshot_2,
4053 freshSnapshot: Recoil_Snapshot_3,
4054 cloneSnapshot: Recoil_Snapshot_4
4055});
4056
4057/**
4058 * Copyright (c) Meta Platforms, Inc. and affiliates.
4059 *
4060 * This source code is licensed under the MIT license found in the
4061 * LICENSE file in the root directory of this source tree.
4062 *
4063 *
4064 * @format
4065 * @oncall recoil
4066 */
4067
4068function unionSets(...sets) {
4069 const result = new Set();
4070
4071 for (const set of sets) {
4072 for (const value of set) {
4073 result.add(value);
4074 }
4075 }
4076
4077 return result;
4078}
4079
4080var Recoil_unionSets = unionSets;
4081
4082const {
4083 useRef
4084} = react;
4085/**
4086 * The same as `useRef()` except that if a function is specified then it will
4087 * call that function to get the value to initialize the reference with.
4088 * This is similar to how `useState()` behaves when given a function. It allows
4089 * the user to avoid generating the initial value for subsequent renders.
4090 * The tradeoff is that to set the reference to a function itself you need to
4091 * nest it: useRefInitOnce(() => () => {...});
4092 */
4093
4094
4095function useRefInitOnce(initialValue) {
4096 // $FlowExpectedError[incompatible-call]
4097 const ref = useRef(initialValue);
4098
4099 if (ref.current === initialValue && typeof initialValue === 'function') {
4100 // $FlowExpectedError[incompatible-use]
4101 ref.current = initialValue();
4102 }
4103
4104 return ref;
4105}
4106
4107var Recoil_useRefInitOnce = useRefInitOnce;
4108
4109// @fb-only: const RecoilusagelogEvent = require('RecoilusagelogEvent');
4110// @fb-only: const RecoilUsageLogFalcoEvent = require('RecoilUsageLogFalcoEvent');
4111// @fb-only: const URI = require('URI');
4112
4113
4114const {
4115 getNextTreeStateVersion: getNextTreeStateVersion$3,
4116 makeEmptyStoreState: makeEmptyStoreState$2
4117} = Recoil_State;
4118
4119const {
4120 cleanUpNode: cleanUpNode$2,
4121 getDownstreamNodes: getDownstreamNodes$2,
4122 initializeNode: initializeNode$2,
4123 setNodeValue: setNodeValue$2,
4124 setUnvalidatedAtomValue_DEPRECATED: setUnvalidatedAtomValue_DEPRECATED$1
4125} = Recoil_FunctionalCore;
4126
4127const {
4128 graph: graph$2
4129} = Recoil_Graph;
4130
4131const {
4132 cloneGraph: cloneGraph$1
4133} = Recoil_Graph;
4134
4135const {
4136 getNextStoreID: getNextStoreID$2
4137} = Recoil_Keys;
4138
4139const {
4140 createMutableSource: createMutableSource$1,
4141 reactMode: reactMode$2
4142} = Recoil_ReactMode;
4143
4144const {
4145 applyAtomValueWrites: applyAtomValueWrites$1
4146} = Recoil_RecoilValueInterface;
4147
4148const {
4149 releaseScheduledRetainablesNow: releaseScheduledRetainablesNow$1
4150} = Recoil_Retention;
4151
4152const {
4153 freshSnapshot: freshSnapshot$1
4154} = Recoil_Snapshot$1;
4155
4156
4157
4158const {
4159 useCallback,
4160 useContext,
4161 useEffect,
4162 useMemo,
4163 useRef: useRef$1,
4164 useState
4165} = react;
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181function notInAContext() {
4182 throw Recoil_err('This component must be used inside a <RecoilRoot> component.');
4183}
4184
4185const defaultStore = Object.freeze({
4186 storeID: getNextStoreID$2(),
4187 getState: notInAContext,
4188 replaceState: notInAContext,
4189 getGraph: notInAContext,
4190 subscribeToTransactions: notInAContext,
4191 addTransactionMetadata: notInAContext
4192});
4193let stateReplacerIsBeingExecuted = false;
4194
4195function startNextTreeIfNeeded(store) {
4196 if (stateReplacerIsBeingExecuted) {
4197 throw Recoil_err('An atom update was triggered within the execution of a state updater function. State updater functions provided to Recoil must be pure functions.');
4198 }
4199
4200 const storeState = store.getState();
4201
4202 if (storeState.nextTree === null) {
4203 if (Recoil_gkx('recoil_memory_managament_2020') && Recoil_gkx('recoil_release_on_cascading_update_killswitch_2021')) {
4204 // If this is a cascading update (that is, rendering due to one state change
4205 // invokes a second state change), we won't have cleaned up retainables yet
4206 // because this normally happens after notifying components. Do it before
4207 // proceeding with the cascading update so that it remains predictable:
4208 if (storeState.commitDepth > 0) {
4209 releaseScheduledRetainablesNow$1(store);
4210 }
4211 }
4212
4213 const version = storeState.currentTree.version;
4214 const nextVersion = getNextTreeStateVersion$3();
4215 storeState.nextTree = { ...storeState.currentTree,
4216 version: nextVersion,
4217 stateID: nextVersion,
4218 dirtyAtoms: new Set(),
4219 transactionMetadata: {}
4220 };
4221 storeState.graphsByVersion.set(nextVersion, cloneGraph$1(Recoil_nullthrows(storeState.graphsByVersion.get(version))));
4222 }
4223}
4224
4225const AppContext = react.createContext({
4226 current: defaultStore
4227});
4228
4229const useStoreRef = () => useContext(AppContext); // $FlowExpectedError[incompatible-call]
4230
4231
4232const MutableSourceContext = react.createContext(null);
4233
4234function useRecoilMutableSource() {
4235 const mutableSource = useContext(MutableSourceContext);
4236
4237 if (mutableSource == null) {
4238 Recoil_expectationViolation('Attempted to use a Recoil hook outside of a <RecoilRoot>. ' + '<RecoilRoot> must be an ancestor of any component that uses ' + 'Recoil hooks.');
4239 }
4240
4241 return mutableSource;
4242}
4243
4244function notifyComponents(store, storeState, treeState) {
4245 const dependentNodes = getDownstreamNodes$2(store, treeState, treeState.dirtyAtoms);
4246
4247 for (const key of dependentNodes) {
4248 const comps = storeState.nodeToComponentSubscriptions.get(key);
4249
4250 if (comps) {
4251 for (const [_subID, [_debugName, callback]] of comps) {
4252 callback(treeState);
4253 }
4254 }
4255 }
4256}
4257
4258function sendEndOfBatchNotifications(store) {
4259 const storeState = store.getState();
4260 const treeState = storeState.currentTree; // Inform transaction subscribers of the transaction:
4261
4262 const dirtyAtoms = treeState.dirtyAtoms;
4263
4264 if (dirtyAtoms.size) {
4265 // Execute Node-specific subscribers before global subscribers
4266 for (const [key, subscriptions] of storeState.nodeTransactionSubscriptions) {
4267 if (dirtyAtoms.has(key)) {
4268 for (const [_, subscription] of subscriptions) {
4269 subscription(store);
4270 }
4271 }
4272 }
4273
4274 for (const [_, subscription] of storeState.transactionSubscriptions) {
4275 subscription(store);
4276 }
4277
4278 if (!reactMode$2().early || storeState.suspendedComponentResolvers.size > 0) {
4279 // Notifying components is needed to wake from suspense, even when using
4280 // early rendering.
4281 notifyComponents(store, storeState, treeState); // Wake all suspended components so the right one(s) can try to re-render.
4282 // We need to wake up components not just when some asynchronous selector
4283 // resolved, but also when changing synchronous values because this may cause
4284 // a selector to change from asynchronous to synchronous, in which case there
4285 // would be no follow-up asynchronous resolution to wake us up.
4286 // TODO OPTIMIZATION Only wake up related downstream components
4287
4288 storeState.suspendedComponentResolvers.forEach(cb => cb());
4289 storeState.suspendedComponentResolvers.clear();
4290 }
4291 } // Special behavior ONLY invoked by useInterface.
4292 // FIXME delete queuedComponentCallbacks_DEPRECATED when deleting useInterface.
4293
4294
4295 storeState.queuedComponentCallbacks_DEPRECATED.forEach(cb => cb(treeState));
4296 storeState.queuedComponentCallbacks_DEPRECATED.splice(0, storeState.queuedComponentCallbacks_DEPRECATED.length);
4297}
4298
4299function endBatch(store) {
4300 const storeState = store.getState();
4301 storeState.commitDepth++;
4302
4303 try {
4304 const {
4305 nextTree
4306 } = storeState; // Ignore commits that are not because of Recoil transactions -- namely,
4307 // because something above RecoilRoot re-rendered:
4308
4309 if (nextTree == null) {
4310 return;
4311 } // nextTree is now committed -- note that copying and reset occurs when
4312 // a transaction begins, in startNextTreeIfNeeded:
4313
4314
4315 storeState.previousTree = storeState.currentTree;
4316 storeState.currentTree = nextTree;
4317 storeState.nextTree = null;
4318 sendEndOfBatchNotifications(store);
4319
4320 if (storeState.previousTree != null) {
4321 storeState.graphsByVersion.delete(storeState.previousTree.version);
4322 } else {
4323 Recoil_recoverableViolation('Ended batch with no previous state, which is unexpected', 'recoil');
4324 }
4325
4326 storeState.previousTree = null;
4327
4328 if (Recoil_gkx('recoil_memory_managament_2020')) {
4329 // Only release retainables if there were no writes during the end of the
4330 // batch. This avoids releasing something we might be about to use.
4331 if (nextTree == null) {
4332 releaseScheduledRetainablesNow$1(store);
4333 }
4334 }
4335 } finally {
4336 storeState.commitDepth--;
4337 }
4338}
4339/*
4340 * The purpose of the Batcher is to observe when React batches end so that
4341 * Recoil state changes can be batched. Whenever Recoil state changes, we call
4342 * setState on the batcher. Then we wait for that change to be committed, which
4343 * signifies the end of the batch. That's when we respond to the Recoil change.
4344 */
4345
4346
4347function Batcher({
4348 setNotifyBatcherOfChange
4349}) {
4350 const storeRef = useStoreRef();
4351 const [, setState] = useState([]); // $FlowFixMe[incompatible-call]
4352
4353 setNotifyBatcherOfChange(() => setState({}));
4354 useEffect(() => {
4355 // $FlowFixMe[incompatible-call]
4356 setNotifyBatcherOfChange(() => setState({})); // If an asynchronous selector resolves after the Batcher is unmounted,
4357 // notifyBatcherOfChange will still be called. An error gets thrown whenever
4358 // setState is called after a component is already unmounted, so this sets
4359 // notifyBatcherOfChange to be a no-op.
4360
4361 return () => {
4362 setNotifyBatcherOfChange(() => {});
4363 };
4364 }, [setNotifyBatcherOfChange]);
4365 useEffect(() => {
4366 // enqueueExecution runs this function immediately; it is only used to
4367 // manipulate the order of useEffects during tests, since React seems to
4368 // call useEffect in an unpredictable order sometimes.
4369 Recoil_Queue.enqueueExecution('Batcher', () => {
4370 endBatch(storeRef.current);
4371 });
4372 });
4373 return null;
4374}
4375
4376if (process.env.NODE_ENV !== "production") {
4377 if (typeof window !== 'undefined' && !window.$recoilDebugStates) {
4378 window.$recoilDebugStates = [];
4379 }
4380} // When removing this deprecated function, remove stateBySettingRecoilValue
4381// which will no longer be needed.
4382
4383
4384function initialStoreState_DEPRECATED(store, initializeState) {
4385 const initial = makeEmptyStoreState$2();
4386 initializeState({
4387 set: (atom, value) => {
4388 const state = initial.currentTree;
4389 const writes = setNodeValue$2(store, state, atom.key, value);
4390 const writtenNodes = new Set(writes.keys());
4391 const nonvalidatedAtoms = state.nonvalidatedAtoms.clone();
4392
4393 for (const n of writtenNodes) {
4394 nonvalidatedAtoms.delete(n);
4395 }
4396
4397 initial.currentTree = { ...state,
4398 dirtyAtoms: Recoil_unionSets(state.dirtyAtoms, writtenNodes),
4399 atomValues: applyAtomValueWrites$1(state.atomValues, writes),
4400 // NB: PLEASE un-export applyAtomValueWrites when deleting this code
4401 nonvalidatedAtoms
4402 };
4403 },
4404 setUnvalidatedAtomValues: atomValues => {
4405 // FIXME replace this with a mutative loop
4406 atomValues.forEach((v, k) => {
4407 initial.currentTree = setUnvalidatedAtomValue_DEPRECATED$1(initial.currentTree, k, v);
4408 });
4409 }
4410 });
4411 return initial;
4412} // Initialize state snapshot for <RecoilRoot> for the initializeState prop.
4413// Atom effect initialization takes precedence over this prop.
4414// Any atom effects will be run before initialization, but then cleaned up,
4415// they are then re-run when used as part of rendering. These semantics are
4416// compatible with React StrictMode where effects may be re-run multiple times
4417// but state initialization only happens once the first time.
4418
4419
4420function initialStoreState(initializeState) {
4421 // Initialize a snapshot and get its store
4422 const snapshot = freshSnapshot$1(initializeState);
4423 const storeState = snapshot.getStore_INTERNAL().getState(); // Counteract the snapshot auto-release
4424
4425 snapshot.retain(); // Cleanup any effects run during initialization and clear the handlers so
4426 // they will re-initialize if used during rendering. This allows atom effect
4427 // initialization to take precedence over initializeState and be compatible
4428 // with StrictMode semantics.
4429
4430 storeState.nodeCleanupFunctions.forEach(cleanup => cleanup());
4431 storeState.nodeCleanupFunctions.clear();
4432 return storeState;
4433}
4434
4435let nextID = 0;
4436
4437function RecoilRoot_INTERNAL({
4438 initializeState_DEPRECATED,
4439 initializeState,
4440 store_INTERNAL: storeProp,
4441 // For use with React "context bridging"
4442 children
4443}) {
4444 // prettier-ignore
4445 // @fb-only: useEffect(() => {
4446 // @fb-only: if (gkx('recoil_usage_logging')) {
4447 // @fb-only: try {
4448 // @fb-only: RecoilUsageLogFalcoEvent.log(() => ({
4449 // @fb-only: type: RecoilusagelogEvent.RECOIL_ROOT_MOUNTED,
4450 // @fb-only: path: URI.getRequestURI().getPath(),
4451 // @fb-only: }));
4452 // @fb-only: } catch {
4453 // @fb-only: recoverableViolation(
4454 // @fb-only: 'Error when logging Recoil Usage event',
4455 // @fb-only: 'recoil',
4456 // @fb-only: );
4457 // @fb-only: }
4458 // @fb-only: }
4459 // @fb-only: }, []);
4460 let storeStateRef; // eslint-disable-line prefer-const
4461
4462 const getGraph = version => {
4463 const graphs = storeStateRef.current.graphsByVersion;
4464
4465 if (graphs.has(version)) {
4466 return Recoil_nullthrows(graphs.get(version));
4467 }
4468
4469 const newGraph = graph$2();
4470 graphs.set(version, newGraph);
4471 return newGraph;
4472 };
4473
4474 const subscribeToTransactions = (callback, key) => {
4475 if (key == null) {
4476 // Global transaction subscriptions
4477 const {
4478 transactionSubscriptions
4479 } = storeRef.current.getState();
4480 const id = nextID++;
4481 transactionSubscriptions.set(id, callback);
4482 return {
4483 release: () => {
4484 transactionSubscriptions.delete(id);
4485 }
4486 };
4487 } else {
4488 // Node-specific transaction subscriptions:
4489 const {
4490 nodeTransactionSubscriptions
4491 } = storeRef.current.getState();
4492
4493 if (!nodeTransactionSubscriptions.has(key)) {
4494 nodeTransactionSubscriptions.set(key, new Map());
4495 }
4496
4497 const id = nextID++;
4498 Recoil_nullthrows(nodeTransactionSubscriptions.get(key)).set(id, callback);
4499 return {
4500 release: () => {
4501 const subs = nodeTransactionSubscriptions.get(key);
4502
4503 if (subs) {
4504 subs.delete(id);
4505
4506 if (subs.size === 0) {
4507 nodeTransactionSubscriptions.delete(key);
4508 }
4509 }
4510 }
4511 };
4512 }
4513 };
4514
4515 const addTransactionMetadata = metadata => {
4516 startNextTreeIfNeeded(storeRef.current);
4517
4518 for (const k of Object.keys(metadata)) {
4519 Recoil_nullthrows(storeRef.current.getState().nextTree).transactionMetadata[k] = metadata[k];
4520 }
4521 };
4522
4523 const replaceState = replacer => {
4524 startNextTreeIfNeeded(storeRef.current); // Use replacer to get the next state:
4525
4526 const nextTree = Recoil_nullthrows(storeStateRef.current.nextTree);
4527 let replaced;
4528
4529 try {
4530 stateReplacerIsBeingExecuted = true;
4531 replaced = replacer(nextTree);
4532 } finally {
4533 stateReplacerIsBeingExecuted = false;
4534 }
4535
4536 if (replaced === nextTree) {
4537 return;
4538 }
4539
4540 if (process.env.NODE_ENV !== "production") {
4541 if (typeof window !== 'undefined') {
4542 window.$recoilDebugStates.push(replaced); // TODO this shouldn't happen here because it's not batched
4543 }
4544 } // Save changes to nextTree and schedule a React update:
4545
4546
4547 storeStateRef.current.nextTree = replaced;
4548
4549 if (reactMode$2().early) {
4550 notifyComponents(storeRef.current, storeStateRef.current, replaced);
4551 }
4552
4553 Recoil_nullthrows(notifyBatcherOfChange.current)();
4554 };
4555
4556 const notifyBatcherOfChange = useRef$1(null);
4557 const setNotifyBatcherOfChange = useCallback(x => {
4558 notifyBatcherOfChange.current = x;
4559 }, [notifyBatcherOfChange]);
4560 const storeRef = Recoil_useRefInitOnce(() => storeProp !== null && storeProp !== void 0 ? storeProp : {
4561 storeID: getNextStoreID$2(),
4562 getState: () => storeStateRef.current,
4563 replaceState,
4564 getGraph,
4565 subscribeToTransactions,
4566 addTransactionMetadata
4567 });
4568
4569 if (storeProp != null) {
4570 storeRef.current = storeProp;
4571 }
4572
4573 storeStateRef = Recoil_useRefInitOnce(() => initializeState_DEPRECATED != null ? initialStoreState_DEPRECATED(storeRef.current, initializeState_DEPRECATED) : initializeState != null ? initialStoreState(initializeState) : makeEmptyStoreState$2());
4574 const mutableSource = useMemo(() => createMutableSource$1 === null || createMutableSource$1 === void 0 ? void 0 : createMutableSource$1(storeStateRef, () => storeStateRef.current.currentTree.version), [storeStateRef]); // Cleanup when the <RecoilRoot> is unmounted
4575
4576 useEffect(() => {
4577 // React is free to call effect cleanup handlers and effects at will, the
4578 // deps array is only an optimization. For example, React strict mode
4579 // will execute each effect twice for testing. Therefore, we need symmetry
4580 // to re-initialize all known atoms after they were cleaned up.
4581 const store = storeRef.current;
4582
4583 for (const atomKey of new Set(store.getState().knownAtoms)) {
4584 initializeNode$2(store, atomKey, 'get');
4585 }
4586
4587 return () => {
4588 for (const atomKey of store.getState().knownAtoms) {
4589 cleanUpNode$2(store, atomKey);
4590 }
4591 };
4592 }, [storeRef]);
4593 return /*#__PURE__*/react.createElement(AppContext.Provider, {
4594 value: storeRef
4595 }, /*#__PURE__*/react.createElement(MutableSourceContext.Provider, {
4596 value: mutableSource
4597 }, /*#__PURE__*/react.createElement(Batcher, {
4598 setNotifyBatcherOfChange: setNotifyBatcherOfChange
4599 }), children));
4600}
4601
4602function RecoilRoot(props) {
4603 const {
4604 override,
4605 ...propsExceptOverride
4606 } = props;
4607 const ancestorStoreRef = useStoreRef();
4608
4609 if (override === false && ancestorStoreRef.current !== defaultStore) {
4610 // If ancestorStoreRef.current !== defaultStore, it means that this
4611 // RecoilRoot is not nested within another.
4612 return props.children;
4613 }
4614
4615 return /*#__PURE__*/react.createElement(RecoilRoot_INTERNAL, propsExceptOverride);
4616}
4617
4618function useRecoilStoreID() {
4619 return useStoreRef().current.storeID;
4620}
4621
4622var Recoil_RecoilRoot = {
4623 RecoilRoot,
4624 useStoreRef,
4625 useRecoilMutableSource,
4626 useRecoilStoreID,
4627 notifyComponents_FOR_TESTING: notifyComponents,
4628 sendEndOfBatchNotifications_FOR_TESTING: sendEndOfBatchNotifications
4629};
4630
4631/**
4632 * Copyright (c) Meta Platforms, Inc. and affiliates.
4633 *
4634 * This source code is licensed under the MIT license found in the
4635 * LICENSE file in the root directory of this source tree.
4636 *
4637 *
4638 * @format
4639 * @oncall recoil
4640 */
4641
4642function shallowArrayEqual(a, b) {
4643 if (a === b) {
4644 return true;
4645 }
4646
4647 if (a.length !== b.length) {
4648 return false;
4649 }
4650
4651 for (let i = 0, l = a.length; i < l; i++) {
4652 if (a[i] !== b[i]) {
4653 return false;
4654 }
4655 }
4656
4657 return true;
4658}
4659
4660var Recoil_shallowArrayEqual = shallowArrayEqual;
4661
4662const {
4663 useEffect: useEffect$1,
4664 useRef: useRef$2
4665} = react;
4666
4667function usePrevious(value) {
4668 const ref = useRef$2();
4669 useEffect$1(() => {
4670 // $FlowFixMe[incompatible-type]
4671 ref.current = value;
4672 });
4673 return ref.current;
4674}
4675
4676var Recoil_usePrevious = usePrevious;
4677
4678const {
4679 useStoreRef: useStoreRef$1
4680} = Recoil_RecoilRoot;
4681
4682const {
4683 SUSPENSE_TIMEOUT_MS: SUSPENSE_TIMEOUT_MS$1
4684} = Recoil_Retention;
4685
4686const {
4687 updateRetainCount: updateRetainCount$2
4688} = Recoil_Retention;
4689
4690const {
4691 RetentionZone: RetentionZone$3
4692} = Recoil_RetentionZone;
4693
4694const {
4695 useEffect: useEffect$2,
4696 useRef: useRef$3
4697} = react;
4698
4699const {
4700 isSSR: isSSR$2
4701} = Recoil_Environment;
4702
4703
4704
4705
4706
4707 // I don't see a way to avoid the any type here because we want to accept readable
4708// and writable values with any type parameter, but normally with writable ones
4709// RecoilState<SomeT> is not a subtype of RecoilState<mixed>.
4710
4711
4712// flowlint-line unclear-type:off
4713function useRetain(toRetain) {
4714 if (!Recoil_gkx('recoil_memory_managament_2020')) {
4715 return;
4716 } // eslint-disable-next-line fb-www/react-hooks
4717
4718
4719 return useRetain_ACTUAL(toRetain);
4720}
4721
4722function useRetain_ACTUAL(toRetain) {
4723 const array = Array.isArray(toRetain) ? toRetain : [toRetain];
4724 const retainables = array.map(a => a instanceof RetentionZone$3 ? a : a.key);
4725 const storeRef = useStoreRef$1();
4726 useEffect$2(() => {
4727 if (!Recoil_gkx('recoil_memory_managament_2020')) {
4728 return;
4729 }
4730
4731 const store = storeRef.current;
4732
4733 if (timeoutID.current && !isSSR$2) {
4734 // Already performed a temporary retain on render, simply cancel the release
4735 // of that temporary retain.
4736 window.clearTimeout(timeoutID.current);
4737 timeoutID.current = null;
4738 } else {
4739 for (const r of retainables) {
4740 updateRetainCount$2(store, r, 1);
4741 }
4742 }
4743
4744 return () => {
4745 for (const r of retainables) {
4746 updateRetainCount$2(store, r, -1);
4747 }
4748 }; // eslint-disable-next-line fb-www/react-hooks-deps
4749 }, [storeRef, ...retainables]); // We want to retain if the component suspends. This is terrible but the Suspense
4750 // API affords us no better option. If we suspend and never commit after some
4751 // seconds, then release. The 'actual' retain/release in the effect above
4752 // cancels this.
4753
4754 const timeoutID = useRef$3();
4755 const previousRetainables = Recoil_usePrevious(retainables);
4756
4757 if (!isSSR$2 && (previousRetainables === undefined || !Recoil_shallowArrayEqual(previousRetainables, retainables))) {
4758 const store = storeRef.current;
4759
4760 for (const r of retainables) {
4761 updateRetainCount$2(store, r, 1);
4762 }
4763
4764 if (previousRetainables) {
4765 for (const r of previousRetainables) {
4766 updateRetainCount$2(store, r, -1);
4767 }
4768 }
4769
4770 if (timeoutID.current) {
4771 window.clearTimeout(timeoutID.current);
4772 }
4773
4774 timeoutID.current = window.setTimeout(() => {
4775 timeoutID.current = null;
4776
4777 for (const r of retainables) {
4778 updateRetainCount$2(store, r, -1);
4779 }
4780 }, SUSPENSE_TIMEOUT_MS$1);
4781 }
4782}
4783
4784var Recoil_useRetain = useRetain;
4785
4786/**
4787 * Copyright (c) Meta Platforms, Inc. and affiliates.
4788 *
4789 * This source code is licensed under the MIT license found in the
4790 * LICENSE file in the root directory of this source tree.
4791 *
4792 *
4793 * @format
4794 * @oncall recoil
4795 */
4796/**
4797 * THIS CODE HAS BEEN COMMENTED OUT INTENTIONALLY
4798 *
4799 * This technique of getting the component name is imperfect, since it both only
4800 * works in a non-minified code base, and more importantly introduces performance
4801 * problems since it relies in throwing errors which is an expensive operation.
4802 *
4803 * At some point we may want to reevaluate this technique hence why we have commented
4804 * this code out, rather than delete it all together.
4805 */
4806// const {useRef} = require('react');
4807// const gkx = require('recoil-shared/util/Recoil_gkx');
4808// const stackTraceParser = require('recoil-shared/util/Recoil_stackTraceParser');
4809
4810function useComponentName() {
4811 // const nameRef = useRef();
4812 // if (__DEV__) {
4813 // if (gkx('recoil_infer_component_names')) {
4814 // if (nameRef.current === undefined) {
4815 // // There is no blessed way to determine the calling React component from
4816 // // within a hook. This hack uses the fact that hooks must start with 'use'
4817 // // and that hooks are either called by React Components or other hooks. It
4818 // // follows therefore, that to find the calling component, you simply need
4819 // // to look down the stack and find the first function which doesn't start
4820 // // with 'use'. We are only enabling this in dev for now, since once the
4821 // // codebase is minified, the naming assumptions no longer hold true.
4822 // // eslint-disable-next-line fb-www/no-new-error
4823 // const frames = stackTraceParser(new Error().stack);
4824 // for (const {methodName} of frames) {
4825 // // I observed cases where the frame was of the form 'Object.useXXX'
4826 // // hence why I'm searching for hooks following a word boundary
4827 // if (!methodName.match(/\buse[^\b]+$/)) {
4828 // return (nameRef.current = methodName);
4829 // }
4830 // }
4831 // nameRef.current = null;
4832 // }
4833 // return nameRef.current ?? '<unable to determine component name>';
4834 // }
4835 // }
4836 // @fb-only: return "<component name only available when both in dev mode and when passing GK 'recoil_infer_component_names'>";
4837 return '<component name not available>'; // @oss-only
4838}
4839
4840var Recoil_useComponentName = useComponentName;
4841
4842const {
4843 batchUpdates: batchUpdates$2
4844} = Recoil_Batching;
4845
4846const {
4847 DEFAULT_VALUE: DEFAULT_VALUE$2
4848} = Recoil_Node;
4849
4850const {
4851 currentRendererSupportsUseSyncExternalStore: currentRendererSupportsUseSyncExternalStore$1,
4852 reactMode: reactMode$3,
4853 useMutableSource: useMutableSource$1,
4854 useSyncExternalStore: useSyncExternalStore$1
4855} = Recoil_ReactMode;
4856
4857const {
4858 useRecoilMutableSource: useRecoilMutableSource$1,
4859 useStoreRef: useStoreRef$2
4860} = Recoil_RecoilRoot;
4861
4862const {
4863 isRecoilValue: isRecoilValue$2
4864} = Recoil_RecoilValue$1;
4865
4866const {
4867 AbstractRecoilValue: AbstractRecoilValue$3,
4868 getRecoilValueAsLoadable: getRecoilValueAsLoadable$2,
4869 setRecoilValue: setRecoilValue$2,
4870 setUnvalidatedRecoilValue: setUnvalidatedRecoilValue$2,
4871 subscribeToRecoilValue: subscribeToRecoilValue$1
4872} = Recoil_RecoilValueInterface;
4873
4874
4875
4876const {
4877 useCallback: useCallback$1,
4878 useEffect: useEffect$3,
4879 useMemo: useMemo$1,
4880 useRef: useRef$4,
4881 useState: useState$1
4882} = react;
4883
4884const {
4885 setByAddingToSet: setByAddingToSet$2
4886} = Recoil_CopyOnWrite;
4887
4888
4889
4890const {
4891 isSSR: isSSR$3
4892} = Recoil_Environment;
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906function handleLoadable(loadable, recoilValue, storeRef) {
4907 // We can't just throw the promise we are waiting on to Suspense. If the
4908 // upstream dependencies change it may produce a state in which the component
4909 // can render, but it would still be suspended on a Promise that may never resolve.
4910 if (loadable.state === 'hasValue') {
4911 return loadable.contents;
4912 } else if (loadable.state === 'loading') {
4913 const promise = new Promise(resolve => {
4914 const suspendedComponentResolvers = storeRef.current.getState().suspendedComponentResolvers;
4915 suspendedComponentResolvers.add(resolve); // SSR should clear out the wake-up resolver if the Promise is resolved
4916 // to avoid infinite loops. (See https://github.com/facebookexperimental/Recoil/pull/2073)
4917
4918 if (isSSR$3 && Recoil_isPromise(loadable.contents)) {
4919 loadable.contents.finally(() => {
4920 suspendedComponentResolvers.delete(resolve);
4921 });
4922 }
4923 }); // $FlowExpectedError Flow(prop-missing) for integrating with tools that inspect thrown promises @fb-only
4924 // @fb-only: promise.displayName = `Recoil State: ${recoilValue.key}`;
4925
4926 throw promise;
4927 } else if (loadable.state === 'hasError') {
4928 throw loadable.contents;
4929 } else {
4930 throw Recoil_err(`Invalid value of loadable atom "${recoilValue.key}"`);
4931 }
4932}
4933
4934function validateRecoilValue(recoilValue, hookName // $FlowFixMe[missing-local-annot]
4935) {
4936 if (!isRecoilValue$2(recoilValue)) {
4937 throw Recoil_err(`Invalid argument to ${hookName}: expected an atom or selector but got ${String(recoilValue)}`);
4938 }
4939}
4940
4941/**
4942 * Various things are broken with useRecoilInterface, particularly concurrent
4943 * mode, React strict mode, and memory management. They will not be fixed.
4944 * */
4945function useRecoilInterface_DEPRECATED() {
4946 const componentName = Recoil_useComponentName();
4947 const storeRef = useStoreRef$2(); // eslint-disable-next-line fb-www/react-no-unused-state-hook
4948
4949 const [, forceUpdate] = useState$1([]);
4950 const recoilValuesUsed = useRef$4(new Set());
4951 recoilValuesUsed.current = new Set(); // Track the RecoilValues used just during this render
4952
4953 const previousSubscriptions = useRef$4(new Set());
4954 const subscriptions = useRef$4(new Map());
4955 const unsubscribeFrom = useCallback$1(key => {
4956 const sub = subscriptions.current.get(key);
4957
4958 if (sub) {
4959 sub.release();
4960 subscriptions.current.delete(key);
4961 }
4962 }, [subscriptions]);
4963 const updateState = useCallback$1((_state, key) => {
4964 if (subscriptions.current.has(key)) {
4965 forceUpdate([]);
4966 }
4967 }, []); // Effect to add/remove subscriptions as nodes are used
4968
4969 useEffect$3(() => {
4970 const store = storeRef.current;
4971 Recoil_differenceSets(recoilValuesUsed.current, previousSubscriptions.current).forEach(key => {
4972 if (subscriptions.current.has(key)) {
4973 Recoil_expectationViolation(`Double subscription to RecoilValue "${key}"`);
4974 return;
4975 }
4976
4977 const sub = subscribeToRecoilValue$1(store, new AbstractRecoilValue$3(key), state => updateState(state, key), componentName);
4978 subscriptions.current.set(key, sub);
4979 /**
4980 * Since we're subscribing in an effect we need to update to the latest
4981 * value of the atom since it may have changed since we rendered. We can
4982 * go ahead and do that now, unless we're in the middle of a batch --
4983 * in which case we should do it at the end of the batch, due to the
4984 * following edge case: Suppose an atom is updated in another useEffect
4985 * of this same component. Then the following sequence of events occur:
4986 * 1. Atom is updated and subs fired (but we may not be subscribed
4987 * yet depending on order of effects, so we miss this) Updated value
4988 * is now in nextTree, but not currentTree.
4989 * 2. This effect happens. We subscribe and update.
4990 * 3. From the update we re-render and read currentTree, with old value.
4991 * 4. Batcher's effect sets currentTree to nextTree.
4992 * In this sequence we miss the update. To avoid that, add the update
4993 * to queuedComponentCallback if a batch is in progress.
4994 */
4995 // FIXME delete queuedComponentCallbacks_DEPRECATED when deleting useInterface.
4996
4997 const state = store.getState();
4998
4999 if (state.nextTree) {
5000 store.getState().queuedComponentCallbacks_DEPRECATED.push(() => {
5001 updateState(store.getState(), key);
5002 });
5003 } else {
5004 updateState(store.getState(), key);
5005 }
5006 });
5007 Recoil_differenceSets(previousSubscriptions.current, recoilValuesUsed.current).forEach(key => {
5008 unsubscribeFrom(key);
5009 });
5010 previousSubscriptions.current = recoilValuesUsed.current;
5011 }); // Effect to unsubscribe from all when unmounting
5012
5013 useEffect$3(() => {
5014 const currentSubscriptions = subscriptions.current; // Restore subscriptions that were cleared due to StrictMode running this effect twice
5015
5016 Recoil_differenceSets(recoilValuesUsed.current, new Set(currentSubscriptions.keys())).forEach(key => {
5017 const sub = subscribeToRecoilValue$1(storeRef.current, new AbstractRecoilValue$3(key), state => updateState(state, key), componentName);
5018 currentSubscriptions.set(key, sub);
5019 });
5020 return () => currentSubscriptions.forEach((_, key) => unsubscribeFrom(key));
5021 }, [componentName, storeRef, unsubscribeFrom, updateState]);
5022 return useMemo$1(() => {
5023 // eslint-disable-next-line no-shadow
5024 function useSetRecoilState(recoilState) {
5025 if (process.env.NODE_ENV !== "production") {
5026 validateRecoilValue(recoilState, 'useSetRecoilState');
5027 }
5028
5029 return newValueOrUpdater => {
5030 setRecoilValue$2(storeRef.current, recoilState, newValueOrUpdater);
5031 };
5032 } // eslint-disable-next-line no-shadow
5033
5034
5035 function useResetRecoilState(recoilState) {
5036 if (process.env.NODE_ENV !== "production") {
5037 validateRecoilValue(recoilState, 'useResetRecoilState');
5038 }
5039
5040 return () => setRecoilValue$2(storeRef.current, recoilState, DEFAULT_VALUE$2);
5041 } // eslint-disable-next-line no-shadow
5042
5043
5044 function useRecoilValueLoadable(recoilValue) {
5045 var _storeState$nextTree;
5046
5047 if (process.env.NODE_ENV !== "production") {
5048 validateRecoilValue(recoilValue, 'useRecoilValueLoadable');
5049 }
5050
5051 if (!recoilValuesUsed.current.has(recoilValue.key)) {
5052 recoilValuesUsed.current = setByAddingToSet$2(recoilValuesUsed.current, recoilValue.key);
5053 } // TODO Restore optimization to memoize lookup
5054
5055
5056 const storeState = storeRef.current.getState();
5057 return getRecoilValueAsLoadable$2(storeRef.current, recoilValue, reactMode$3().early ? (_storeState$nextTree = storeState.nextTree) !== null && _storeState$nextTree !== void 0 ? _storeState$nextTree : storeState.currentTree : storeState.currentTree);
5058 } // eslint-disable-next-line no-shadow
5059
5060
5061 function useRecoilValue(recoilValue) {
5062 if (process.env.NODE_ENV !== "production") {
5063 validateRecoilValue(recoilValue, 'useRecoilValue');
5064 }
5065
5066 const loadable = useRecoilValueLoadable(recoilValue);
5067 return handleLoadable(loadable, recoilValue, storeRef);
5068 } // eslint-disable-next-line no-shadow
5069
5070
5071 function useRecoilState(recoilState) {
5072 if (process.env.NODE_ENV !== "production") {
5073 validateRecoilValue(recoilState, 'useRecoilState');
5074 }
5075
5076 return [useRecoilValue(recoilState), useSetRecoilState(recoilState)];
5077 } // eslint-disable-next-line no-shadow
5078
5079
5080 function useRecoilStateLoadable(recoilState) {
5081 if (process.env.NODE_ENV !== "production") {
5082 validateRecoilValue(recoilState, 'useRecoilStateLoadable');
5083 }
5084
5085 return [useRecoilValueLoadable(recoilState), useSetRecoilState(recoilState)];
5086 }
5087
5088 return {
5089 getRecoilValue: useRecoilValue,
5090 getRecoilValueLoadable: useRecoilValueLoadable,
5091 getRecoilState: useRecoilState,
5092 getRecoilStateLoadable: useRecoilStateLoadable,
5093 getSetRecoilState: useSetRecoilState,
5094 getResetRecoilState: useResetRecoilState
5095 };
5096 }, [recoilValuesUsed, storeRef]);
5097}
5098
5099const recoilComponentGetRecoilValueCount_FOR_TESTING = {
5100 current: 0
5101};
5102
5103function useRecoilValueLoadable_SYNC_EXTERNAL_STORE(recoilValue) {
5104 const storeRef = useStoreRef$2();
5105 const componentName = Recoil_useComponentName();
5106 const getSnapshot = useCallback$1(() => {
5107 var _storeState$nextTree2;
5108
5109 if (process.env.NODE_ENV !== "production") {
5110 recoilComponentGetRecoilValueCount_FOR_TESTING.current++;
5111 }
5112
5113 const store = storeRef.current;
5114 const storeState = store.getState();
5115 const treeState = reactMode$3().early ? (_storeState$nextTree2 = storeState.nextTree) !== null && _storeState$nextTree2 !== void 0 ? _storeState$nextTree2 : storeState.currentTree : storeState.currentTree;
5116 const loadable = getRecoilValueAsLoadable$2(store, recoilValue, treeState);
5117 return {
5118 loadable,
5119 key: recoilValue.key
5120 };
5121 }, [storeRef, recoilValue]); // Memoize the state to avoid unnecessary rerenders
5122
5123 const memoizePreviousSnapshot = useCallback$1(getState => {
5124 let prevState;
5125 return () => {
5126 var _prevState, _prevState2;
5127
5128 const nextState = getState();
5129
5130 if ((_prevState = prevState) !== null && _prevState !== void 0 && _prevState.loadable.is(nextState.loadable) && ((_prevState2 = prevState) === null || _prevState2 === void 0 ? void 0 : _prevState2.key) === nextState.key) {
5131 return prevState;
5132 }
5133
5134 prevState = nextState;
5135 return nextState;
5136 };
5137 }, []);
5138 const getMemoizedSnapshot = useMemo$1(() => memoizePreviousSnapshot(getSnapshot), [getSnapshot, memoizePreviousSnapshot]);
5139 const subscribe = useCallback$1(notify => {
5140 const store = storeRef.current;
5141 const subscription = subscribeToRecoilValue$1(store, recoilValue, notify, componentName);
5142 return subscription.release;
5143 }, [storeRef, recoilValue, componentName]);
5144 return useSyncExternalStore$1(subscribe, getMemoizedSnapshot, // getSnapshot()
5145 getMemoizedSnapshot // getServerSnapshot() for SSR support
5146 ).loadable;
5147}
5148
5149function useRecoilValueLoadable_MUTABLE_SOURCE(recoilValue) {
5150 const storeRef = useStoreRef$2();
5151 const getLoadable = useCallback$1(() => {
5152 var _storeState$nextTree3;
5153
5154 const store = storeRef.current;
5155 const storeState = store.getState();
5156 const treeState = reactMode$3().early ? (_storeState$nextTree3 = storeState.nextTree) !== null && _storeState$nextTree3 !== void 0 ? _storeState$nextTree3 : storeState.currentTree : storeState.currentTree;
5157 return getRecoilValueAsLoadable$2(store, recoilValue, treeState);
5158 }, [storeRef, recoilValue]);
5159 const getLoadableWithTesting = useCallback$1(() => {
5160 if (process.env.NODE_ENV !== "production") {
5161 recoilComponentGetRecoilValueCount_FOR_TESTING.current++;
5162 }
5163
5164 return getLoadable();
5165 }, [getLoadable]);
5166 const componentName = Recoil_useComponentName();
5167 const subscribe = useCallback$1((_storeState, notify) => {
5168 const store = storeRef.current;
5169 const subscription = subscribeToRecoilValue$1(store, recoilValue, () => {
5170 if (!Recoil_gkx('recoil_suppress_rerender_in_callback')) {
5171 return notify();
5172 } // Only re-render if the value has changed.
5173 // This will evaluate the atom/selector now as well as when the
5174 // component renders, but that may help with prefetching.
5175
5176
5177 const newLoadable = getLoadable();
5178
5179 if (!prevLoadableRef.current.is(newLoadable)) {
5180 notify();
5181 } // If the component is suspended then the effect setting prevLoadableRef
5182 // will not run. So, set the previous value here when its subscription
5183 // is fired to wake it up. We can't just rely on this, though, because
5184 // this only executes when an atom/selector is dirty and the atom/selector
5185 // passed to the hook can dynamically change.
5186
5187
5188 prevLoadableRef.current = newLoadable;
5189 }, componentName);
5190 return subscription.release;
5191 }, [storeRef, recoilValue, componentName, getLoadable]);
5192 const source = useRecoilMutableSource$1();
5193
5194 if (source == null) {
5195 throw Recoil_err('Recoil hooks must be used in components contained within a <RecoilRoot> component.');
5196 }
5197
5198 const loadable = useMutableSource$1(source, getLoadableWithTesting, subscribe);
5199 const prevLoadableRef = useRef$4(loadable);
5200 useEffect$3(() => {
5201 prevLoadableRef.current = loadable;
5202 });
5203 return loadable;
5204}
5205
5206function useRecoilValueLoadable_TRANSITION_SUPPORT(recoilValue) {
5207 const storeRef = useStoreRef$2();
5208 const componentName = Recoil_useComponentName(); // Accessors to get the current state
5209
5210 const getLoadable = useCallback$1(() => {
5211 var _storeState$nextTree4;
5212
5213 if (process.env.NODE_ENV !== "production") {
5214 recoilComponentGetRecoilValueCount_FOR_TESTING.current++;
5215 }
5216
5217 const store = storeRef.current;
5218 const storeState = store.getState();
5219 const treeState = reactMode$3().early ? (_storeState$nextTree4 = storeState.nextTree) !== null && _storeState$nextTree4 !== void 0 ? _storeState$nextTree4 : storeState.currentTree : storeState.currentTree;
5220 return getRecoilValueAsLoadable$2(store, recoilValue, treeState);
5221 }, [storeRef, recoilValue]);
5222 const getState = useCallback$1(() => ({
5223 loadable: getLoadable(),
5224 key: recoilValue.key
5225 }), [getLoadable, recoilValue.key]); // Memoize state snapshots
5226
5227 const updateState = useCallback$1(prevState => {
5228 const nextState = getState();
5229 return prevState.loadable.is(nextState.loadable) && prevState.key === nextState.key ? prevState : nextState;
5230 }, [getState]); // Subscribe to Recoil state changes
5231
5232 useEffect$3(() => {
5233 const subscription = subscribeToRecoilValue$1(storeRef.current, recoilValue, _state => {
5234 setState(updateState);
5235 }, componentName); // Update state in case we are using a different key
5236
5237 setState(updateState);
5238 return subscription.release;
5239 }, [componentName, recoilValue, storeRef, updateState]); // Get the current state
5240
5241 const [state, setState] = useState$1(getState); // If we changed keys, then return the state for the new key.
5242 // This is important in case the old key would cause the component to suspend.
5243 // We don't have to set the new state here since the subscribing effect above
5244 // will do that.
5245
5246 return state.key !== recoilValue.key ? getState().loadable : state.loadable;
5247}
5248
5249function useRecoilValueLoadable_LEGACY(recoilValue) {
5250 const storeRef = useStoreRef$2(); // eslint-disable-next-line fb-www/react-no-unused-state-hook
5251
5252 const [, forceUpdate] = useState$1([]);
5253 const componentName = Recoil_useComponentName();
5254 const getLoadable = useCallback$1(() => {
5255 var _storeState$nextTree5;
5256
5257 if (process.env.NODE_ENV !== "production") {
5258 recoilComponentGetRecoilValueCount_FOR_TESTING.current++;
5259 }
5260
5261 const store = storeRef.current;
5262 const storeState = store.getState();
5263 const treeState = reactMode$3().early ? (_storeState$nextTree5 = storeState.nextTree) !== null && _storeState$nextTree5 !== void 0 ? _storeState$nextTree5 : storeState.currentTree : storeState.currentTree;
5264 return getRecoilValueAsLoadable$2(store, recoilValue, treeState);
5265 }, [storeRef, recoilValue]);
5266 const loadable = getLoadable();
5267 const prevLoadableRef = useRef$4(loadable);
5268 useEffect$3(() => {
5269 prevLoadableRef.current = loadable;
5270 });
5271 useEffect$3(() => {
5272 const store = storeRef.current;
5273 const storeState = store.getState();
5274 const subscription = subscribeToRecoilValue$1(store, recoilValue, _state => {
5275 var _prevLoadableRef$curr;
5276
5277 if (!Recoil_gkx('recoil_suppress_rerender_in_callback')) {
5278 return forceUpdate([]);
5279 }
5280
5281 const newLoadable = getLoadable();
5282
5283 if (!((_prevLoadableRef$curr = prevLoadableRef.current) !== null && _prevLoadableRef$curr !== void 0 && _prevLoadableRef$curr.is(newLoadable))) {
5284 // $FlowFixMe[incompatible-call]
5285 forceUpdate(newLoadable);
5286 }
5287
5288 prevLoadableRef.current = newLoadable;
5289 }, componentName);
5290 /**
5291 * Since we're subscribing in an effect we need to update to the latest
5292 * value of the atom since it may have changed since we rendered. We can
5293 * go ahead and do that now, unless we're in the middle of a batch --
5294 * in which case we should do it at the end of the batch, due to the
5295 * following edge case: Suppose an atom is updated in another useEffect
5296 * of this same component. Then the following sequence of events occur:
5297 * 1. Atom is updated and subs fired (but we may not be subscribed
5298 * yet depending on order of effects, so we miss this) Updated value
5299 * is now in nextTree, but not currentTree.
5300 * 2. This effect happens. We subscribe and update.
5301 * 3. From the update we re-render and read currentTree, with old value.
5302 * 4. Batcher's effect sets currentTree to nextTree.
5303 * In this sequence we miss the update. To avoid that, add the update
5304 * to queuedComponentCallback if a batch is in progress.
5305 */
5306
5307 if (storeState.nextTree) {
5308 store.getState().queuedComponentCallbacks_DEPRECATED.push(() => {
5309 // $FlowFixMe[incompatible-type]
5310 prevLoadableRef.current = null;
5311 forceUpdate([]);
5312 });
5313 } else {
5314 var _prevLoadableRef$curr2;
5315
5316 if (!Recoil_gkx('recoil_suppress_rerender_in_callback')) {
5317 return forceUpdate([]);
5318 }
5319
5320 const newLoadable = getLoadable();
5321
5322 if (!((_prevLoadableRef$curr2 = prevLoadableRef.current) !== null && _prevLoadableRef$curr2 !== void 0 && _prevLoadableRef$curr2.is(newLoadable))) {
5323 // $FlowFixMe[incompatible-call]
5324 forceUpdate(newLoadable);
5325 }
5326
5327 prevLoadableRef.current = newLoadable;
5328 }
5329
5330 return subscription.release;
5331 }, [componentName, getLoadable, recoilValue, storeRef]);
5332 return loadable;
5333}
5334/**
5335 Like useRecoilValue(), but either returns the value if available or
5336 just undefined if not available for any reason, such as pending or error.
5337*/
5338
5339
5340function useRecoilValueLoadable(recoilValue) {
5341 if (process.env.NODE_ENV !== "production") {
5342 validateRecoilValue(recoilValue, 'useRecoilValueLoadable');
5343 }
5344
5345 if (Recoil_gkx('recoil_memory_managament_2020')) {
5346 // eslint-disable-next-line fb-www/react-hooks
5347 Recoil_useRetain(recoilValue);
5348 }
5349
5350 return {
5351 TRANSITION_SUPPORT: useRecoilValueLoadable_TRANSITION_SUPPORT,
5352 // Recoil will attemp to detect if `useSyncExternalStore()` is supported with
5353 // `reactMode()` before calling it. However, sometimes the host React
5354 // environment supports it but uses additional React renderers (such as with
5355 // `react-three-fiber`) which do not. While this is technically a user issue
5356 // by using a renderer with React 18+ that doesn't fully support React 18 we
5357 // don't want to break users if it can be avoided. As the current renderer can
5358 // change at runtime, we need to dynamically check and fallback if necessary.
5359 SYNC_EXTERNAL_STORE: currentRendererSupportsUseSyncExternalStore$1() ? useRecoilValueLoadable_SYNC_EXTERNAL_STORE : useRecoilValueLoadable_TRANSITION_SUPPORT,
5360 MUTABLE_SOURCE: useRecoilValueLoadable_MUTABLE_SOURCE,
5361 LEGACY: useRecoilValueLoadable_LEGACY
5362 }[reactMode$3().mode](recoilValue);
5363}
5364/**
5365 Returns the value represented by the RecoilValue.
5366 If the value is pending, it will throw a Promise to suspend the component,
5367 if the value is an error it will throw it for the nearest React error boundary.
5368 This will also subscribe the component for any updates in the value.
5369 */
5370
5371
5372function useRecoilValue(recoilValue) {
5373 if (process.env.NODE_ENV !== "production") {
5374 validateRecoilValue(recoilValue, 'useRecoilValue');
5375 }
5376
5377 const storeRef = useStoreRef$2();
5378 const loadable = useRecoilValueLoadable(recoilValue);
5379 return handleLoadable(loadable, recoilValue, storeRef);
5380}
5381/**
5382 Returns a function that allows the value of a RecoilState to be updated, but does
5383 not subscribe the component to changes to that RecoilState.
5384*/
5385
5386
5387function useSetRecoilState(recoilState) {
5388 if (process.env.NODE_ENV !== "production") {
5389 validateRecoilValue(recoilState, 'useSetRecoilState');
5390 }
5391
5392 const storeRef = useStoreRef$2();
5393 return useCallback$1(newValueOrUpdater => {
5394 setRecoilValue$2(storeRef.current, recoilState, newValueOrUpdater);
5395 }, [storeRef, recoilState]);
5396}
5397/**
5398 Returns a function that will reset the value of a RecoilState to its default
5399*/
5400
5401
5402function useResetRecoilState(recoilState) {
5403 if (process.env.NODE_ENV !== "production") {
5404 validateRecoilValue(recoilState, 'useResetRecoilState');
5405 }
5406
5407 const storeRef = useStoreRef$2();
5408 return useCallback$1(() => {
5409 setRecoilValue$2(storeRef.current, recoilState, DEFAULT_VALUE$2);
5410 }, [storeRef, recoilState]);
5411}
5412/**
5413 Equivalent to useState(). Allows the value of the RecoilState to be read and written.
5414 Subsequent updates to the RecoilState will cause the component to re-render. If the
5415 RecoilState is pending, this will suspend the component and initiate the
5416 retrieval of the value. If evaluating the RecoilState resulted in an error, this will
5417 throw the error so that the nearest React error boundary can catch it.
5418*/
5419
5420
5421function useRecoilState(recoilState) {
5422 if (process.env.NODE_ENV !== "production") {
5423 validateRecoilValue(recoilState, 'useRecoilState');
5424 }
5425
5426 return [useRecoilValue(recoilState), useSetRecoilState(recoilState)];
5427}
5428/**
5429 Like useRecoilState(), but does not cause Suspense or React error handling. Returns
5430 an object that indicates whether the RecoilState is available, pending, or
5431 unavailable due to an error.
5432*/
5433
5434
5435function useRecoilStateLoadable(recoilState) {
5436 if (process.env.NODE_ENV !== "production") {
5437 validateRecoilValue(recoilState, 'useRecoilStateLoadable');
5438 }
5439
5440 return [useRecoilValueLoadable(recoilState), useSetRecoilState(recoilState)];
5441}
5442
5443function useSetUnvalidatedAtomValues() {
5444 const storeRef = useStoreRef$2();
5445 return (values, transactionMetadata = {}) => {
5446 batchUpdates$2(() => {
5447 storeRef.current.addTransactionMetadata(transactionMetadata);
5448 values.forEach((value, key) => setUnvalidatedRecoilValue$2(storeRef.current, new AbstractRecoilValue$3(key), value));
5449 });
5450 };
5451}
5452/**
5453 * Experimental variants of hooks with support for useTransition()
5454 */
5455
5456
5457function useRecoilValueLoadable_TRANSITION_SUPPORT_UNSTABLE(recoilValue) {
5458 if (process.env.NODE_ENV !== "production") {
5459 validateRecoilValue(recoilValue, 'useRecoilValueLoadable_TRANSITION_SUPPORT_UNSTABLE');
5460
5461 if (!reactMode$3().early) {
5462 Recoil_recoverableViolation('Attepmt to use a hook with UNSTABLE_TRANSITION_SUPPORT in a rendering mode incompatible with concurrent rendering. Try enabling the recoil_sync_external_store or recoil_transition_support GKs.');
5463 }
5464 }
5465
5466 if (Recoil_gkx('recoil_memory_managament_2020')) {
5467 // eslint-disable-next-line fb-www/react-hooks
5468 Recoil_useRetain(recoilValue);
5469 }
5470
5471 return useRecoilValueLoadable_TRANSITION_SUPPORT(recoilValue);
5472}
5473
5474function useRecoilValue_TRANSITION_SUPPORT_UNSTABLE(recoilValue) {
5475 if (process.env.NODE_ENV !== "production") {
5476 validateRecoilValue(recoilValue, 'useRecoilValue_TRANSITION_SUPPORT_UNSTABLE');
5477 }
5478
5479 const storeRef = useStoreRef$2();
5480 const loadable = useRecoilValueLoadable_TRANSITION_SUPPORT_UNSTABLE(recoilValue);
5481 return handleLoadable(loadable, recoilValue, storeRef);
5482}
5483
5484function useRecoilState_TRANSITION_SUPPORT_UNSTABLE(recoilState) {
5485 if (process.env.NODE_ENV !== "production") {
5486 validateRecoilValue(recoilState, 'useRecoilState_TRANSITION_SUPPORT_UNSTABLE');
5487 }
5488
5489 return [useRecoilValue_TRANSITION_SUPPORT_UNSTABLE(recoilState), useSetRecoilState(recoilState)];
5490}
5491
5492var Recoil_Hooks = {
5493 recoilComponentGetRecoilValueCount_FOR_TESTING,
5494 useRecoilInterface: useRecoilInterface_DEPRECATED,
5495 useRecoilState,
5496 useRecoilStateLoadable,
5497 useRecoilValue,
5498 useRecoilValueLoadable,
5499 useResetRecoilState,
5500 useSetRecoilState,
5501 useSetUnvalidatedAtomValues,
5502 useRecoilValueLoadable_TRANSITION_SUPPORT_UNSTABLE,
5503 useRecoilValue_TRANSITION_SUPPORT_UNSTABLE,
5504 useRecoilState_TRANSITION_SUPPORT_UNSTABLE
5505};
5506
5507/**
5508 * Copyright (c) Meta Platforms, Inc. and affiliates.
5509 *
5510 * This source code is licensed under the MIT license found in the
5511 * LICENSE file in the root directory of this source tree.
5512 *
5513 *
5514 * @format
5515 * @oncall recoil
5516 */
5517/**
5518 * Returns a map containing all of the keys + values from the original map where
5519 * the given callback returned true.
5520 */
5521
5522function filterMap(map, callback) {
5523 const result = new Map();
5524
5525 for (const [key, value] of map) {
5526 if (callback(value, key)) {
5527 result.set(key, value);
5528 }
5529 }
5530
5531 return result;
5532}
5533
5534var Recoil_filterMap = filterMap;
5535
5536/**
5537 * Copyright (c) Meta Platforms, Inc. and affiliates.
5538 *
5539 * This source code is licensed under the MIT license found in the
5540 * LICENSE file in the root directory of this source tree.
5541 *
5542 *
5543 * @format
5544 * @oncall recoil
5545 */
5546/**
5547 * Returns a set containing all of the values from the original set where
5548 * the given callback returned true.
5549 */
5550
5551function filterSet(set, callback) {
5552 const result = new Set();
5553
5554 for (const value of set) {
5555 if (callback(value)) {
5556 result.add(value);
5557 }
5558 }
5559
5560 return result;
5561}
5562
5563var Recoil_filterSet = filterSet;
5564
5565/**
5566 * Copyright (c) Meta Platforms, Inc. and affiliates.
5567 *
5568 * This source code is licensed under the MIT license found in the
5569 * LICENSE file in the root directory of this source tree.
5570 *
5571 *
5572 * @format
5573 * @oncall recoil
5574 */
5575
5576function mergeMaps(...maps) {
5577 const result = new Map();
5578
5579 for (let i = 0; i < maps.length; i++) {
5580 const iterator = maps[i].keys();
5581 let nextKey;
5582
5583 while (!(nextKey = iterator.next()).done) {
5584 // $FlowIssue[incompatible-call] - map/iterator knows nothing about flow types
5585 result.set(nextKey.value, maps[i].get(nextKey.value));
5586 }
5587 }
5588
5589 return result;
5590}
5591
5592var Recoil_mergeMaps = mergeMaps;
5593
5594const {
5595 batchUpdates: batchUpdates$3
5596} = Recoil_Batching;
5597
5598const {
5599 DEFAULT_VALUE: DEFAULT_VALUE$3,
5600 getNode: getNode$4,
5601 nodes: nodes$1
5602} = Recoil_Node;
5603
5604const {
5605 useStoreRef: useStoreRef$3
5606} = Recoil_RecoilRoot;
5607
5608const {
5609 AbstractRecoilValue: AbstractRecoilValue$4,
5610 setRecoilValueLoadable: setRecoilValueLoadable$1
5611} = Recoil_RecoilValueInterface;
5612
5613const {
5614 SUSPENSE_TIMEOUT_MS: SUSPENSE_TIMEOUT_MS$2
5615} = Recoil_Retention;
5616
5617const {
5618 cloneSnapshot: cloneSnapshot$1
5619} = Recoil_Snapshot$1;
5620
5621const {
5622 useCallback: useCallback$2,
5623 useEffect: useEffect$4,
5624 useRef: useRef$5,
5625 useState: useState$2
5626} = react;
5627
5628const {
5629 isSSR: isSSR$4
5630} = Recoil_Environment;
5631
5632
5633
5634
5635
5636
5637
5638
5639
5640
5641
5642
5643
5644
5645
5646function useTransactionSubscription(callback) {
5647 const storeRef = useStoreRef$3();
5648 useEffect$4(() => {
5649 const sub = storeRef.current.subscribeToTransactions(callback);
5650 return sub.release;
5651 }, [callback, storeRef]);
5652}
5653
5654function externallyVisibleAtomValuesInState(state) {
5655 const atomValues = state.atomValues.toMap();
5656 const persistedAtomContentsValues = Recoil_mapMap(Recoil_filterMap(atomValues, (v, k) => {
5657 const node = getNode$4(k);
5658 const persistence = node.persistence_UNSTABLE;
5659 return persistence != null && persistence.type !== 'none' && v.state === 'hasValue';
5660 }), v => v.contents); // Merge in nonvalidated atoms; we may not have defs for them but they will
5661 // all have persistence on or they wouldn't be there in the first place.
5662
5663 return Recoil_mergeMaps(state.nonvalidatedAtoms.toMap(), persistedAtomContentsValues);
5664}
5665
5666/**
5667 Calls the given callback after any atoms have been modified and the consequent
5668 component re-renders have been committed. This is intended for persisting
5669 the values of the atoms to storage. The stored values can then be restored
5670 using the useSetUnvalidatedAtomValues hook.
5671
5672 The callback receives the following info:
5673
5674 atomValues: The current value of every atom that is both persistable (persistence
5675 type not set to 'none') and whose value is available (not in an
5676 error or loading state).
5677
5678 previousAtomValues: The value of every persistable and available atom before
5679 the transaction began.
5680
5681 atomInfo: A map containing the persistence settings for each atom. Every key
5682 that exists in atomValues will also exist in atomInfo.
5683
5684 modifiedAtoms: The set of atoms that were written to during the transaction.
5685
5686 transactionMetadata: Arbitrary information that was added via the
5687 useSetUnvalidatedAtomValues hook. Useful for ignoring the useSetUnvalidatedAtomValues
5688 transaction, to avoid loops.
5689*/
5690function useTransactionObservation_DEPRECATED(callback) {
5691 useTransactionSubscription(useCallback$2(store => {
5692 let previousTree = store.getState().previousTree;
5693 const currentTree = store.getState().currentTree;
5694
5695 if (!previousTree) {
5696 Recoil_recoverableViolation('Transaction subscribers notified without a previous tree being present -- this is a bug in Recoil');
5697 previousTree = store.getState().currentTree; // attempt to trundle on
5698 }
5699
5700 const atomValues = externallyVisibleAtomValuesInState(currentTree);
5701 const previousAtomValues = externallyVisibleAtomValuesInState(previousTree);
5702 const atomInfo = Recoil_mapMap(nodes$1, node => {
5703 var _node$persistence_UNS, _node$persistence_UNS2, _node$persistence_UNS3, _node$persistence_UNS4;
5704
5705 return {
5706 persistence_UNSTABLE: {
5707 type: (_node$persistence_UNS = (_node$persistence_UNS2 = node.persistence_UNSTABLE) === null || _node$persistence_UNS2 === void 0 ? void 0 : _node$persistence_UNS2.type) !== null && _node$persistence_UNS !== void 0 ? _node$persistence_UNS : 'none',
5708 backButton: (_node$persistence_UNS3 = (_node$persistence_UNS4 = node.persistence_UNSTABLE) === null || _node$persistence_UNS4 === void 0 ? void 0 : _node$persistence_UNS4.backButton) !== null && _node$persistence_UNS3 !== void 0 ? _node$persistence_UNS3 : false
5709 }
5710 };
5711 }); // Filter on existance in atomValues so that externally-visible rules
5712 // are also applied to modified atoms (specifically exclude selectors):
5713
5714 const modifiedAtoms = Recoil_filterSet(currentTree.dirtyAtoms, k => atomValues.has(k) || previousAtomValues.has(k));
5715 callback({
5716 atomValues,
5717 previousAtomValues,
5718 atomInfo,
5719 modifiedAtoms,
5720 transactionMetadata: { ...currentTree.transactionMetadata
5721 }
5722 });
5723 }, [callback]));
5724}
5725
5726function useRecoilTransactionObserver(callback) {
5727 useTransactionSubscription(useCallback$2(store => {
5728 const snapshot = cloneSnapshot$1(store, 'latest');
5729 const previousSnapshot = cloneSnapshot$1(store, 'previous');
5730 callback({
5731 snapshot,
5732 previousSnapshot
5733 });
5734 }, [callback]));
5735} // Return a snapshot of the current state and subscribe to all state changes
5736
5737
5738function useRecoilSnapshot() {
5739 const storeRef = useStoreRef$3();
5740 const [snapshot, setSnapshot] = useState$2(() => cloneSnapshot$1(storeRef.current));
5741 const previousSnapshot = Recoil_usePrevious(snapshot);
5742 const timeoutID = useRef$5();
5743 const releaseRef = useRef$5();
5744 useTransactionSubscription(useCallback$2(store => setSnapshot(cloneSnapshot$1(store)), [])); // Retain snapshot for duration component is mounted
5745
5746 useEffect$4(() => {
5747 const release = snapshot.retain(); // Release the retain from the rendering call
5748
5749 if (timeoutID.current && !isSSR$4) {
5750 var _releaseRef$current;
5751
5752 window.clearTimeout(timeoutID.current);
5753 timeoutID.current = null;
5754 (_releaseRef$current = releaseRef.current) === null || _releaseRef$current === void 0 ? void 0 : _releaseRef$current.call(releaseRef);
5755 releaseRef.current = null;
5756 }
5757
5758 return () => {
5759 // Defer the release. If "Fast Refresh"" is used then the component may
5760 // re-render with the same state. The previous cleanup will then run and
5761 // then the new effect will run. We don't want the snapshot to be released
5762 // by that cleanup before the new effect has a chance to retain it again.
5763 // Use timeout of 10 to workaround Firefox issue: https://github.com/facebookexperimental/Recoil/issues/1936
5764 window.setTimeout(release, 10);
5765 };
5766 }, [snapshot]); // Retain snapshot until above effect is run.
5767 // Release after a threshold in case component is suspended.
5768
5769 if (previousSnapshot !== snapshot && !isSSR$4) {
5770 // Release the previous snapshot
5771 if (timeoutID.current) {
5772 var _releaseRef$current2;
5773
5774 window.clearTimeout(timeoutID.current);
5775 timeoutID.current = null;
5776 (_releaseRef$current2 = releaseRef.current) === null || _releaseRef$current2 === void 0 ? void 0 : _releaseRef$current2.call(releaseRef);
5777 releaseRef.current = null;
5778 }
5779
5780 releaseRef.current = snapshot.retain();
5781 timeoutID.current = window.setTimeout(() => {
5782 var _releaseRef$current3;
5783
5784 timeoutID.current = null;
5785 (_releaseRef$current3 = releaseRef.current) === null || _releaseRef$current3 === void 0 ? void 0 : _releaseRef$current3.call(releaseRef);
5786 releaseRef.current = null;
5787 }, SUSPENSE_TIMEOUT_MS$2);
5788 }
5789
5790 return snapshot;
5791}
5792
5793function gotoSnapshot(store, snapshot) {
5794 var _storeState$nextTree;
5795
5796 const storeState = store.getState();
5797 const prev = (_storeState$nextTree = storeState.nextTree) !== null && _storeState$nextTree !== void 0 ? _storeState$nextTree : storeState.currentTree;
5798 const next = snapshot.getStore_INTERNAL().getState().currentTree;
5799 batchUpdates$3(() => {
5800 const keysToUpdate = new Set();
5801
5802 for (const keys of [prev.atomValues.keys(), next.atomValues.keys()]) {
5803 for (const key of keys) {
5804 var _prev$atomValues$get, _next$atomValues$get;
5805
5806 if (((_prev$atomValues$get = prev.atomValues.get(key)) === null || _prev$atomValues$get === void 0 ? void 0 : _prev$atomValues$get.contents) !== ((_next$atomValues$get = next.atomValues.get(key)) === null || _next$atomValues$get === void 0 ? void 0 : _next$atomValues$get.contents) && getNode$4(key).shouldRestoreFromSnapshots) {
5807 keysToUpdate.add(key);
5808 }
5809 }
5810 }
5811
5812 keysToUpdate.forEach(key => {
5813 setRecoilValueLoadable$1(store, new AbstractRecoilValue$4(key), next.atomValues.has(key) ? Recoil_nullthrows(next.atomValues.get(key)) : DEFAULT_VALUE$3);
5814 });
5815 store.replaceState(state => ({ ...state,
5816 stateID: snapshot.getID()
5817 }));
5818 });
5819}
5820
5821function useGotoRecoilSnapshot() {
5822 const storeRef = useStoreRef$3();
5823 return useCallback$2(snapshot => gotoSnapshot(storeRef.current, snapshot), [storeRef]);
5824}
5825
5826var Recoil_SnapshotHooks = {
5827 useRecoilSnapshot,
5828 gotoSnapshot,
5829 useGotoRecoilSnapshot,
5830 useRecoilTransactionObserver,
5831 useTransactionObservation_DEPRECATED,
5832 useTransactionSubscription_DEPRECATED: useTransactionSubscription
5833};
5834
5835const {
5836 peekNodeInfo: peekNodeInfo$2
5837} = Recoil_FunctionalCore;
5838
5839const {
5840 useStoreRef: useStoreRef$4
5841} = Recoil_RecoilRoot;
5842
5843function useGetRecoilValueInfo() {
5844 const storeRef = useStoreRef$4(); // $FlowFixMe[incompatible-return]
5845
5846 return ({
5847 key
5848 }) => peekNodeInfo$2(storeRef.current, storeRef.current.getState().currentTree, key);
5849}
5850
5851var Recoil_useGetRecoilValueInfo = useGetRecoilValueInfo;
5852
5853const {
5854 reactMode: reactMode$4
5855} = Recoil_ReactMode;
5856
5857const {
5858 RecoilRoot: RecoilRoot$1,
5859 useStoreRef: useStoreRef$5
5860} = Recoil_RecoilRoot;
5861
5862
5863
5864const {
5865 useMemo: useMemo$2
5866} = react;
5867
5868function useRecoilBridgeAcrossReactRoots() {
5869 // The test fails when using useMutableSource(), but only if act() is used
5870 // for the nested root. So, this may only be a testing environment issue.
5871 if (reactMode$4().mode === 'MUTABLE_SOURCE') {
5872 // eslint-disable-next-line fb-www/no-console
5873 console.warn('Warning: There are known issues using useRecoilBridgeAcrossReactRoots() in recoil_mutable_source rendering mode. Please consider upgrading to recoil_sync_external_store mode.');
5874 }
5875
5876 const store = useStoreRef$5().current;
5877 return useMemo$2(() => {
5878 // eslint-disable-next-line no-shadow
5879 function RecoilBridge({
5880 children
5881 }) {
5882 return /*#__PURE__*/react.createElement(RecoilRoot$1, {
5883 store_INTERNAL: store
5884 }, children);
5885 }
5886
5887 return RecoilBridge;
5888 }, [store]);
5889}
5890
5891var Recoil_useRecoilBridgeAcrossReactRoots = useRecoilBridgeAcrossReactRoots;
5892
5893const {
5894 loadableWithValue: loadableWithValue$1
5895} = Recoil_Loadable$1;
5896
5897const {
5898 initializeNode: initializeNode$3
5899} = Recoil_FunctionalCore;
5900
5901const {
5902 DEFAULT_VALUE: DEFAULT_VALUE$4,
5903 getNode: getNode$5
5904} = Recoil_Node;
5905
5906const {
5907 copyTreeState: copyTreeState$1,
5908 getRecoilValueAsLoadable: getRecoilValueAsLoadable$3,
5909 invalidateDownstreams: invalidateDownstreams$1,
5910 writeLoadableToTreeState: writeLoadableToTreeState$1
5911} = Recoil_RecoilValueInterface;
5912
5913
5914
5915function isAtom(recoilValue) {
5916 return getNode$5(recoilValue.key).nodeType === 'atom';
5917}
5918
5919class TransactionInterfaceImpl {
5920 constructor(store, treeState) {
5921 _defineProperty(this, "_store", void 0);
5922
5923 _defineProperty(this, "_treeState", void 0);
5924
5925 _defineProperty(this, "_changes", void 0);
5926
5927 _defineProperty(this, "get", recoilValue => {
5928 if (this._changes.has(recoilValue.key)) {
5929 // $FlowIssue[incompatible-return]
5930 return this._changes.get(recoilValue.key);
5931 }
5932
5933 if (!isAtom(recoilValue)) {
5934 throw Recoil_err('Reading selectors within atomicUpdate is not supported');
5935 }
5936
5937 const loadable = getRecoilValueAsLoadable$3(this._store, recoilValue, this._treeState);
5938
5939 if (loadable.state === 'hasValue') {
5940 return loadable.contents;
5941 } else if (loadable.state === 'hasError') {
5942 throw loadable.contents;
5943 } else {
5944 throw Recoil_err(`Expected Recoil atom ${recoilValue.key} to have a value, but it is in a loading state.`);
5945 }
5946 });
5947
5948 _defineProperty(this, "set", (recoilState, valueOrUpdater) => {
5949 if (!isAtom(recoilState)) {
5950 throw Recoil_err('Setting selectors within atomicUpdate is not supported');
5951 }
5952
5953 if (typeof valueOrUpdater === 'function') {
5954 const current = this.get(recoilState);
5955
5956 this._changes.set(recoilState.key, valueOrUpdater(current)); // flowlint-line unclear-type:off
5957
5958 } else {
5959 // Initialize atom and run effects if not initialized yet
5960 initializeNode$3(this._store, recoilState.key, 'set');
5961
5962 this._changes.set(recoilState.key, valueOrUpdater);
5963 }
5964 });
5965
5966 _defineProperty(this, "reset", recoilState => {
5967 this.set(recoilState, DEFAULT_VALUE$4);
5968 });
5969
5970 this._store = store;
5971 this._treeState = treeState;
5972 this._changes = new Map();
5973 } // Allow destructing
5974 // eslint-disable-next-line fb-www/extra-arrow-initializer
5975
5976
5977 newTreeState_INTERNAL() {
5978 if (this._changes.size === 0) {
5979 return this._treeState;
5980 }
5981
5982 const newState = copyTreeState$1(this._treeState);
5983
5984 for (const [k, v] of this._changes) {
5985 writeLoadableToTreeState$1(newState, k, loadableWithValue$1(v));
5986 }
5987
5988 invalidateDownstreams$1(this._store, newState);
5989 return newState;
5990 }
5991
5992}
5993
5994function atomicUpdater(store) {
5995 return fn => {
5996 store.replaceState(treeState => {
5997 const changeset = new TransactionInterfaceImpl(store, treeState);
5998 fn(changeset);
5999 return changeset.newTreeState_INTERNAL();
6000 });
6001 };
6002}
6003
6004var Recoil_AtomicUpdates = {
6005 atomicUpdater
6006};
6007
6008var Recoil_AtomicUpdates_1 = Recoil_AtomicUpdates.atomicUpdater;
6009
6010var Recoil_AtomicUpdates$1 = /*#__PURE__*/Object.freeze({
6011 __proto__: null,
6012 atomicUpdater: Recoil_AtomicUpdates_1
6013});
6014
6015/**
6016 * Copyright (c) Meta Platforms, Inc. and affiliates.
6017 *
6018 * This source code is licensed under the MIT license found in the
6019 * LICENSE file in the root directory of this source tree.
6020 *
6021 *
6022 * @format
6023 * @oncall recoil
6024 */
6025
6026function invariant(condition, message) {
6027 if (!condition) {
6028 throw new Error(message);
6029 }
6030}
6031
6032var invariant_1 = invariant;
6033
6034// @oss-only
6035
6036
6037var Recoil_invariant = invariant_1;
6038
6039const {
6040 atomicUpdater: atomicUpdater$1
6041} = Recoil_AtomicUpdates$1;
6042
6043const {
6044 batchUpdates: batchUpdates$4
6045} = Recoil_Batching;
6046
6047const {
6048 DEFAULT_VALUE: DEFAULT_VALUE$5
6049} = Recoil_Node;
6050
6051const {
6052 useStoreRef: useStoreRef$6
6053} = Recoil_RecoilRoot;
6054
6055const {
6056 refreshRecoilValue: refreshRecoilValue$1,
6057 setRecoilValue: setRecoilValue$3
6058} = Recoil_RecoilValueInterface;
6059
6060const {
6061 cloneSnapshot: cloneSnapshot$2
6062} = Recoil_Snapshot$1;
6063
6064const {
6065 gotoSnapshot: gotoSnapshot$1
6066} = Recoil_SnapshotHooks;
6067
6068const {
6069 useCallback: useCallback$3
6070} = react;
6071
6072
6073
6074
6075
6076
6077
6078
6079
6080class Sentinel {}
6081
6082const SENTINEL = new Sentinel();
6083
6084function recoilCallback(store, fn, args, extraInterface) {
6085 let ret = SENTINEL;
6086 let releaseSnapshot;
6087 batchUpdates$4(() => {
6088 const errMsg = 'useRecoilCallback() expects a function that returns a function: ' + 'it accepts a function of the type (RecoilInterface) => (Args) => ReturnType ' + 'and returns a callback function (Args) => ReturnType, where RecoilInterface is ' + 'an object {snapshot, set, ...} and Args and ReturnType are the argument and return ' + 'types of the callback you want to create. Please see the docs ' + 'at recoiljs.org for details.';
6089
6090 if (typeof fn !== 'function') {
6091 throw Recoil_err(errMsg);
6092 } // Clone the snapshot lazily to avoid overhead if the callback does not use it.
6093 // Note that this means the snapshot may represent later state from when
6094 // the callback was called if it first accesses the snapshot asynchronously.
6095
6096
6097 const callbackInterface = Recoil_lazyProxy({ ...(extraInterface !== null && extraInterface !== void 0 ? extraInterface : {}),
6098 // flowlint-line unclear-type:off
6099 // $FlowFixMe[missing-local-annot]
6100 set: (node, newValue) => setRecoilValue$3(store, node, newValue),
6101 // $FlowFixMe[missing-local-annot]
6102 reset: node => setRecoilValue$3(store, node, DEFAULT_VALUE$5),
6103 // $FlowFixMe[missing-local-annot]
6104 refresh: node => refreshRecoilValue$1(store, node),
6105 gotoSnapshot: snapshot => gotoSnapshot$1(store, snapshot),
6106 transact_UNSTABLE: transaction => atomicUpdater$1(store)(transaction)
6107 }, {
6108 snapshot: () => {
6109 const snapshot = cloneSnapshot$2(store);
6110 releaseSnapshot = snapshot.retain();
6111 return snapshot;
6112 }
6113 });
6114 const callback = fn(callbackInterface);
6115
6116 if (typeof callback !== 'function') {
6117 throw Recoil_err(errMsg);
6118 }
6119
6120 ret = callback(...args);
6121 });
6122 !!(ret instanceof Sentinel) ? process.env.NODE_ENV !== "production" ? Recoil_invariant(false, 'batchUpdates should return immediately') : Recoil_invariant(false) : void 0;
6123
6124 if (Recoil_isPromise(ret)) {
6125 ret = ret.finally(() => {
6126 var _releaseSnapshot;
6127
6128 (_releaseSnapshot = releaseSnapshot) === null || _releaseSnapshot === void 0 ? void 0 : _releaseSnapshot();
6129 });
6130 } else {
6131 var _releaseSnapshot2;
6132
6133 (_releaseSnapshot2 = releaseSnapshot) === null || _releaseSnapshot2 === void 0 ? void 0 : _releaseSnapshot2();
6134 }
6135
6136 return ret;
6137}
6138
6139function useRecoilCallback(fn, deps) {
6140 const storeRef = useStoreRef$6();
6141 return useCallback$3( // $FlowIssue[incompatible-call]
6142 (...args) => {
6143 return recoilCallback(storeRef.current, fn, args);
6144 }, deps != null ? [...deps, storeRef] : undefined // eslint-disable-line fb-www/react-hooks-deps
6145 );
6146}
6147
6148var Recoil_useRecoilCallback = {
6149 recoilCallback,
6150 useRecoilCallback
6151};
6152
6153const {
6154 useStoreRef: useStoreRef$7
6155} = Recoil_RecoilRoot;
6156
6157const {
6158 refreshRecoilValue: refreshRecoilValue$2
6159} = Recoil_RecoilValueInterface;
6160
6161const {
6162 useCallback: useCallback$4
6163} = react;
6164
6165function useRecoilRefresher(recoilValue) {
6166 const storeRef = useStoreRef$7();
6167 return useCallback$4(() => {
6168 const store = storeRef.current;
6169 refreshRecoilValue$2(store, recoilValue);
6170 }, [recoilValue, storeRef]);
6171}
6172
6173var Recoil_useRecoilRefresher = useRecoilRefresher;
6174
6175const {
6176 atomicUpdater: atomicUpdater$2
6177} = Recoil_AtomicUpdates$1;
6178
6179const {
6180 useStoreRef: useStoreRef$8
6181} = Recoil_RecoilRoot;
6182
6183const {
6184 useMemo: useMemo$3
6185} = react;
6186
6187function useRecoilTransaction(fn, deps) {
6188 const storeRef = useStoreRef$8();
6189 return useMemo$3(() => (...args) => {
6190 const atomicUpdate = atomicUpdater$2(storeRef.current);
6191 atomicUpdate(transactionInterface => {
6192 fn(transactionInterface)(...args);
6193 });
6194 }, deps != null ? [...deps, storeRef] : undefined // eslint-disable-line fb-www/react-hooks-deps
6195 );
6196}
6197
6198var Recoil_useRecoilTransaction = useRecoilTransaction;
6199
6200/**
6201 * Copyright (c) Meta Platforms, Inc. and affiliates.
6202 *
6203 * This source code is licensed under the MIT license found in the
6204 * LICENSE file in the root directory of this source tree.
6205 *
6206 *
6207 * @format
6208 * @oncall recoil
6209 */
6210
6211class WrappedValue {
6212 constructor(value) {
6213 _defineProperty(this, "value", void 0);
6214
6215 this.value = value;
6216 }
6217
6218}
6219
6220var Recoil_Wrapper = {
6221 WrappedValue
6222};
6223
6224var Recoil_Wrapper_1 = Recoil_Wrapper.WrappedValue;
6225
6226var Recoil_Wrapper$1 = /*#__PURE__*/Object.freeze({
6227 __proto__: null,
6228 WrappedValue: Recoil_Wrapper_1
6229});
6230
6231const {
6232 isFastRefreshEnabled: isFastRefreshEnabled$2
6233} = Recoil_ReactMode;
6234
6235
6236
6237class ChangedPathError extends Error {}
6238
6239class TreeCache {
6240 // $FlowIssue[unclear-type]
6241 constructor(options) {
6242 var _options$onHit, _options$onSet, _options$mapNodeValue;
6243
6244 _defineProperty(this, "_name", void 0);
6245
6246 _defineProperty(this, "_numLeafs", void 0);
6247
6248 _defineProperty(this, "_root", void 0);
6249
6250 _defineProperty(this, "_onHit", void 0);
6251
6252 _defineProperty(this, "_onSet", void 0);
6253
6254 _defineProperty(this, "_mapNodeValue", void 0);
6255
6256 this._name = options === null || options === void 0 ? void 0 : options.name;
6257 this._numLeafs = 0;
6258 this._root = null;
6259 this._onHit = (_options$onHit = options === null || options === void 0 ? void 0 : options.onHit) !== null && _options$onHit !== void 0 ? _options$onHit : () => {};
6260 this._onSet = (_options$onSet = options === null || options === void 0 ? void 0 : options.onSet) !== null && _options$onSet !== void 0 ? _options$onSet : () => {};
6261 this._mapNodeValue = (_options$mapNodeValue = options === null || options === void 0 ? void 0 : options.mapNodeValue) !== null && _options$mapNodeValue !== void 0 ? _options$mapNodeValue : val => val;
6262 }
6263
6264 size() {
6265 return this._numLeafs;
6266 } // $FlowIssue[unclear-type]
6267
6268
6269 root() {
6270 return this._root;
6271 }
6272
6273 get(getNodeValue, handlers) {
6274 var _this$getLeafNode;
6275
6276 return (_this$getLeafNode = this.getLeafNode(getNodeValue, handlers)) === null || _this$getLeafNode === void 0 ? void 0 : _this$getLeafNode.value;
6277 }
6278
6279 getLeafNode(getNodeValue, handlers) {
6280 if (this._root == null) {
6281 return undefined;
6282 } // Iterate down the tree based on the current node values until we hit a leaf
6283 // $FlowIssue[unclear-type]
6284
6285
6286 let node = this._root;
6287
6288 while (node) {
6289 handlers === null || handlers === void 0 ? void 0 : handlers.onNodeVisit(node);
6290
6291 if (node.type === 'leaf') {
6292 this._onHit(node);
6293
6294 return node;
6295 }
6296
6297 const nodeValue = this._mapNodeValue(getNodeValue(node.nodeKey));
6298
6299 node = node.branches.get(nodeValue);
6300 }
6301
6302 return undefined;
6303 }
6304
6305 set(route, value, handlers) {
6306 const addLeaf = () => {
6307 var _node2, _node3, _this$_root2, _handlers$onNodeVisit2;
6308
6309 // First, setup the branch nodes for the route:
6310 // Iterate down the tree to find or add branch nodes following the route
6311 let node;
6312 let branchKey;
6313
6314 for (const [nodeKey, nodeValue] of route) {
6315 var _node, _handlers$onNodeVisit, _this$_root;
6316
6317 // If the previous root was a leaf, while we not have a get(), it means
6318 // the selector has inconsistent values or implementation changed.
6319 const root = this._root;
6320
6321 if ((root === null || root === void 0 ? void 0 : root.type) === 'leaf') {
6322 throw this.invalidCacheError();
6323 } // node now refers to the next node down in the tree
6324
6325
6326 const parent = node; // $FlowFixMe[prop-missing]
6327 // $FlowFixMe[incompatible-type]
6328
6329 node = parent ? parent.branches.get(branchKey) : root; // $FlowFixMe[prop-missing]
6330 // $FlowFixMe[incompatible-type]
6331
6332 node = (_node = node) !== null && _node !== void 0 ? _node : {
6333 type: 'branch',
6334 nodeKey,
6335 parent,
6336 branches: new Map(),
6337 branchKey
6338 }; // If we found an existing node, confirm it has a consistent value
6339
6340 if (node.type !== 'branch' || node.nodeKey !== nodeKey) {
6341 throw this.invalidCacheError();
6342 } // Add the branch node to the tree
6343
6344
6345 parent === null || parent === void 0 ? void 0 : parent.branches.set(branchKey, node);
6346 handlers === null || handlers === void 0 ? void 0 : (_handlers$onNodeVisit = handlers.onNodeVisit) === null || _handlers$onNodeVisit === void 0 ? void 0 : _handlers$onNodeVisit.call(handlers, node); // Prepare for next iteration and install root if it is new.
6347
6348 branchKey = this._mapNodeValue(nodeValue);
6349 this._root = (_this$_root = this._root) !== null && _this$_root !== void 0 ? _this$_root : node;
6350 } // Second, setup the leaf node:
6351 // If there is an existing leaf for this route confirm it is consistent
6352
6353
6354 const oldLeaf = node ? (_node2 = node) === null || _node2 === void 0 ? void 0 : _node2.branches.get(branchKey) : this._root;
6355
6356 if (oldLeaf != null && (oldLeaf.type !== 'leaf' || oldLeaf.branchKey !== branchKey)) {
6357 throw this.invalidCacheError();
6358 } // Create a new or replacement leaf.
6359
6360
6361 const leafNode = {
6362 type: 'leaf',
6363 value,
6364 parent: node,
6365 branchKey
6366 }; // Install the leaf and call handlers
6367
6368 (_node3 = node) === null || _node3 === void 0 ? void 0 : _node3.branches.set(branchKey, leafNode);
6369 this._root = (_this$_root2 = this._root) !== null && _this$_root2 !== void 0 ? _this$_root2 : leafNode;
6370 this._numLeafs++;
6371
6372 this._onSet(leafNode);
6373
6374 handlers === null || handlers === void 0 ? void 0 : (_handlers$onNodeVisit2 = handlers.onNodeVisit) === null || _handlers$onNodeVisit2 === void 0 ? void 0 : _handlers$onNodeVisit2.call(handlers, leafNode);
6375 };
6376
6377 try {
6378 addLeaf();
6379 } catch (error) {
6380 // If the cache was stale or observed inconsistent values, such as with
6381 // Fast Refresh, then clear it and rebuild with the new values.
6382 if (error instanceof ChangedPathError) {
6383 this.clear();
6384 addLeaf();
6385 } else {
6386 throw error;
6387 }
6388 }
6389 } // Returns true if leaf was actually deleted from the tree
6390
6391
6392 delete(leaf) {
6393 const root = this.root();
6394
6395 if (!root) {
6396 return false;
6397 }
6398
6399 if (leaf === root) {
6400 this._root = null;
6401 this._numLeafs = 0;
6402 return true;
6403 } // Iterate up from the leaf deleteing it from it's parent's branches.
6404
6405
6406 let node = leaf.parent;
6407 let branchKey = leaf.branchKey;
6408
6409 while (node) {
6410 var _node4;
6411
6412 node.branches.delete(branchKey); // Stop iterating if we hit the root.
6413
6414 if (node === root) {
6415 if (node.branches.size === 0) {
6416 this._root = null;
6417 this._numLeafs = 0;
6418 } else {
6419 this._numLeafs--;
6420 }
6421
6422 return true;
6423 } // Stop iterating if there are other branches since we don't need to
6424 // remove any more nodes.
6425
6426
6427 if (node.branches.size > 0) {
6428 break;
6429 } // Iterate up to our parent
6430
6431
6432 branchKey = (_node4 = node) === null || _node4 === void 0 ? void 0 : _node4.branchKey;
6433 node = node.parent;
6434 } // Confirm that the leaf we are deleting is actually attached to our tree
6435
6436
6437 for (; node !== root; node = node.parent) {
6438 if (node == null) {
6439 return false;
6440 }
6441 }
6442
6443 this._numLeafs--;
6444 return true;
6445 }
6446
6447 clear() {
6448 this._numLeafs = 0;
6449 this._root = null;
6450 }
6451
6452 invalidCacheError() {
6453 const CHANGED_PATH_ERROR_MESSAGE = isFastRefreshEnabled$2() ? 'Possible Fast Refresh module reload detected. ' + 'This may also be caused by an selector returning inconsistent values. ' + 'Resetting cache.' : 'Invalid cache values. This happens when selectors do not return ' + 'consistent values for the same input dependency values. That may also ' + 'be caused when using Fast Refresh to change a selector implementation. ' + 'Resetting cache.';
6454 Recoil_recoverableViolation(CHANGED_PATH_ERROR_MESSAGE + (this._name != null ? ` - ${this._name}` : ''));
6455 throw new ChangedPathError();
6456 }
6457
6458}
6459
6460var Recoil_TreeCache = {
6461 TreeCache
6462};
6463
6464var Recoil_TreeCache_1 = Recoil_TreeCache.TreeCache;
6465
6466var Recoil_TreeCache$1 = /*#__PURE__*/Object.freeze({
6467 __proto__: null,
6468 TreeCache: Recoil_TreeCache_1
6469});
6470
6471class LRUCache {
6472 constructor(options) {
6473 var _options$mapKey;
6474
6475 _defineProperty(this, "_maxSize", void 0);
6476
6477 _defineProperty(this, "_size", void 0);
6478
6479 _defineProperty(this, "_head", void 0);
6480
6481 _defineProperty(this, "_tail", void 0);
6482
6483 _defineProperty(this, "_map", void 0);
6484
6485 _defineProperty(this, "_keyMapper", void 0);
6486
6487 this._maxSize = options.maxSize;
6488 this._size = 0;
6489 this._head = null;
6490 this._tail = null;
6491 this._map = new Map();
6492 this._keyMapper = (_options$mapKey = options.mapKey) !== null && _options$mapKey !== void 0 ? _options$mapKey : v => v;
6493 }
6494
6495 head() {
6496 return this._head;
6497 }
6498
6499 tail() {
6500 return this._tail;
6501 }
6502
6503 size() {
6504 return this._size;
6505 }
6506
6507 maxSize() {
6508 return this._maxSize;
6509 }
6510
6511 has(key) {
6512 return this._map.has(this._keyMapper(key));
6513 }
6514
6515 get(key) {
6516 const mappedKey = this._keyMapper(key);
6517
6518 const node = this._map.get(mappedKey);
6519
6520 if (!node) {
6521 return undefined;
6522 }
6523
6524 this.set(key, node.value);
6525 return node.value;
6526 }
6527
6528 set(key, val) {
6529 const mappedKey = this._keyMapper(key);
6530
6531 const existingNode = this._map.get(mappedKey);
6532
6533 if (existingNode) {
6534 this.delete(key);
6535 }
6536
6537 const head = this.head();
6538 const node = {
6539 key,
6540 right: head,
6541 left: null,
6542 value: val
6543 };
6544
6545 if (head) {
6546 head.left = node;
6547 } else {
6548 this._tail = node;
6549 }
6550
6551 this._map.set(mappedKey, node);
6552
6553 this._head = node;
6554 this._size++;
6555
6556 this._maybeDeleteLRU();
6557 }
6558
6559 _maybeDeleteLRU() {
6560 if (this.size() > this.maxSize()) {
6561 this.deleteLru();
6562 }
6563 }
6564
6565 deleteLru() {
6566 const tail = this.tail();
6567
6568 if (tail) {
6569 this.delete(tail.key);
6570 }
6571 }
6572
6573 delete(key) {
6574 const mappedKey = this._keyMapper(key);
6575
6576 if (!this._size || !this._map.has(mappedKey)) {
6577 return;
6578 }
6579
6580 const node = Recoil_nullthrows(this._map.get(mappedKey));
6581 const right = node.right;
6582 const left = node.left;
6583
6584 if (right) {
6585 right.left = node.left;
6586 }
6587
6588 if (left) {
6589 left.right = node.right;
6590 }
6591
6592 if (node === this.head()) {
6593 this._head = right;
6594 }
6595
6596 if (node === this.tail()) {
6597 this._tail = left;
6598 }
6599
6600 this._map.delete(mappedKey);
6601
6602 this._size--;
6603 }
6604
6605 clear() {
6606 this._size = 0;
6607 this._head = null;
6608 this._tail = null;
6609 this._map = new Map();
6610 }
6611
6612}
6613
6614var Recoil_LRUCache = {
6615 LRUCache
6616};
6617
6618var Recoil_LRUCache_1 = Recoil_LRUCache.LRUCache;
6619
6620var Recoil_LRUCache$1 = /*#__PURE__*/Object.freeze({
6621 __proto__: null,
6622 LRUCache: Recoil_LRUCache_1
6623});
6624
6625const {
6626 LRUCache: LRUCache$1
6627} = Recoil_LRUCache$1;
6628
6629const {
6630 TreeCache: TreeCache$1
6631} = Recoil_TreeCache$1;
6632
6633function treeCacheLRU({
6634 name,
6635 maxSize,
6636 mapNodeValue = v => v
6637}) {
6638 const lruCache = new LRUCache$1({
6639 maxSize
6640 });
6641 const cache = new TreeCache$1({
6642 name,
6643 mapNodeValue,
6644 onHit: node => {
6645 lruCache.set(node, true);
6646 },
6647 onSet: node => {
6648 const lruNode = lruCache.tail();
6649 lruCache.set(node, true);
6650
6651 if (lruNode && cache.size() > maxSize) {
6652 // $FlowFixMe[incompatible-call]
6653 cache.delete(lruNode.key);
6654 }
6655 }
6656 });
6657 return cache;
6658}
6659
6660var Recoil_treeCacheLRU = treeCacheLRU;
6661
6662const TIME_WARNING_THRESHOLD_MS = 15;
6663
6664function stringify(x, opt, key) {
6665 // A optimization to avoid the more expensive JSON.stringify() for simple strings
6666 // This may lose protection for u2028 and u2029, though.
6667 if (typeof x === 'string' && !x.includes('"') && !x.includes('\\')) {
6668 return `"${x}"`;
6669 } // Handle primitive types
6670
6671
6672 switch (typeof x) {
6673 case 'undefined':
6674 return '';
6675 // JSON.stringify(undefined) returns undefined, but we always want to return a string
6676
6677 case 'boolean':
6678 return x ? 'true' : 'false';
6679
6680 case 'number':
6681 case 'symbol':
6682 // case 'bigint': // BigInt is not supported in www
6683 return String(x);
6684
6685 case 'string':
6686 // Add surrounding quotes and escape internal quotes
6687 return JSON.stringify(x);
6688
6689 case 'function':
6690 if ((opt === null || opt === void 0 ? void 0 : opt.allowFunctions) !== true) {
6691 throw Recoil_err('Attempt to serialize function in a Recoil cache key');
6692 }
6693
6694 return `__FUNCTION(${x.name})__`;
6695 }
6696
6697 if (x === null) {
6698 return 'null';
6699 } // Fallback case for unknown types
6700
6701
6702 if (typeof x !== 'object') {
6703 var _JSON$stringify;
6704
6705 return (_JSON$stringify = JSON.stringify(x)) !== null && _JSON$stringify !== void 0 ? _JSON$stringify : '';
6706 } // Deal with all promises as equivalent for now.
6707
6708
6709 if (Recoil_isPromise(x)) {
6710 return '__PROMISE__';
6711 } // Arrays handle recursive stringification
6712
6713
6714 if (Array.isArray(x)) {
6715 // $FlowFixMe[missing-local-annot]
6716 return `[${x.map((v, i) => stringify(v, opt, i.toString()))}]`;
6717 } // If an object defines a toJSON() method, then use that to override the
6718 // serialization. This matches the behavior of JSON.stringify().
6719 // Pass the key for compatibility.
6720 // Immutable.js collections define this method to allow us to serialize them.
6721
6722
6723 if (typeof x.toJSON === 'function') {
6724 // flowlint-next-line unclear-type: off
6725 return stringify(x.toJSON(key), opt, key);
6726 } // For built-in Maps, sort the keys in a stable order instead of the
6727 // default insertion order. Support non-string keys.
6728
6729
6730 if (x instanceof Map) {
6731 const obj = {};
6732
6733 for (const [k, v] of x) {
6734 // Stringify will escape any nested quotes
6735 obj[typeof k === 'string' ? k : stringify(k, opt)] = v;
6736 }
6737
6738 return stringify(obj, opt, key);
6739 } // For built-in Sets, sort the keys in a stable order instead of the
6740 // default insertion order.
6741
6742
6743 if (x instanceof Set) {
6744 return stringify( // $FlowFixMe[missing-local-annot]
6745 Array.from(x).sort((a, b) => stringify(a, opt).localeCompare(stringify(b, opt))), opt, key);
6746 } // Anything else that is iterable serialize as an Array.
6747
6748
6749 if (Symbol !== undefined && x[Symbol.iterator] != null && typeof x[Symbol.iterator] === 'function') {
6750 // flowlint-next-line unclear-type: off
6751 return stringify(Array.from(x), opt, key);
6752 } // For all other Objects, sort the keys in a stable order.
6753
6754
6755 return `{${Object.keys(x).filter(k => x[k] !== undefined).sort() // stringify the key to add quotes and escape any nested slashes or quotes.
6756 .map(k => `${stringify(k, opt)}:${stringify(x[k], opt, k)}`).join(',')}}`;
6757} // Utility similar to JSON.stringify() except:
6758// * Serialize built-in Sets as an Array
6759// * Serialize built-in Maps as an Object. Supports non-string keys.
6760// * Serialize other iterables as arrays
6761// * Sort the keys of Objects and Maps to have a stable order based on string conversion.
6762// This overrides their default insertion order.
6763// * Still uses toJSON() of any object to override serialization
6764// * Support Symbols (though don't guarantee uniqueness)
6765// * We could support BigInt, but Flow doesn't seem to like it.
6766// See Recoil_stableStringify-test.js for examples
6767
6768
6769function stableStringify(x, opt = {
6770 allowFunctions: false
6771}) {
6772 if (process.env.NODE_ENV !== "production") {
6773 if (typeof window !== 'undefined') {
6774 const startTime = window.performance ? window.performance.now() : 0;
6775 const str = stringify(x, opt);
6776 const endTime = window.performance ? window.performance.now() : 0;
6777
6778 if (endTime - startTime > TIME_WARNING_THRESHOLD_MS) {
6779 /* eslint-disable fb-www/no-console */
6780 console.groupCollapsed(`Recoil: Spent ${endTime - startTime}ms computing a cache key`);
6781 console.warn(x, str);
6782 console.groupEnd();
6783 /* eslint-enable fb-www/no-console */
6784 }
6785
6786 return str;
6787 }
6788 }
6789
6790 return stringify(x, opt);
6791}
6792
6793var Recoil_stableStringify = stableStringify;
6794
6795const {
6796 TreeCache: TreeCache$2
6797} = Recoil_TreeCache$1;
6798
6799
6800
6801
6802
6803
6804
6805
6806
6807const defaultPolicy = {
6808 equality: 'reference',
6809 eviction: 'keep-all',
6810 maxSize: Infinity
6811};
6812
6813function treeCacheFromPolicy({
6814 equality = defaultPolicy.equality,
6815 eviction = defaultPolicy.eviction,
6816 maxSize = defaultPolicy.maxSize
6817} = defaultPolicy, name) {
6818 const valueMapper = getValueMapper(equality);
6819 return getTreeCache(eviction, maxSize, valueMapper, name);
6820}
6821
6822function getValueMapper(equality) {
6823 switch (equality) {
6824 case 'reference':
6825 return val => val;
6826
6827 case 'value':
6828 return val => Recoil_stableStringify(val);
6829 }
6830
6831 throw Recoil_err(`Unrecognized equality policy ${equality}`);
6832}
6833
6834function getTreeCache(eviction, maxSize, mapNodeValue, name) {
6835 switch (eviction) {
6836 case 'keep-all':
6837 return new TreeCache$2({
6838 name,
6839 mapNodeValue
6840 });
6841
6842 case 'lru':
6843 return Recoil_treeCacheLRU({
6844 name,
6845 maxSize: Recoil_nullthrows(maxSize),
6846 mapNodeValue
6847 });
6848
6849 case 'most-recent':
6850 return Recoil_treeCacheLRU({
6851 name,
6852 maxSize: 1,
6853 mapNodeValue
6854 });
6855 }
6856
6857 throw Recoil_err(`Unrecognized eviction policy ${eviction}`);
6858}
6859
6860var Recoil_treeCacheFromPolicy = treeCacheFromPolicy;
6861
6862/**
6863 * Copyright (c) Meta Platforms, Inc. and affiliates.
6864 *
6865 * This source code is licensed under the MIT license found in the
6866 * LICENSE file in the root directory of this source tree.
6867 *
6868 *
6869 * @format
6870 * @oncall recoil
6871 */
6872
6873function isNode(object) {
6874 var _ownerDocument, _doc$defaultView;
6875
6876 if (typeof window === 'undefined') {
6877 return false;
6878 }
6879
6880 const doc = object != null ? (_ownerDocument = object.ownerDocument) !== null && _ownerDocument !== void 0 ? _ownerDocument : object : document;
6881 const defaultView = (_doc$defaultView = doc.defaultView) !== null && _doc$defaultView !== void 0 ? _doc$defaultView : window;
6882 return !!(object != null && (typeof defaultView.Node === 'function' ? object instanceof defaultView.Node : typeof object === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string'));
6883}
6884
6885var Recoil_isNode = isNode;
6886
6887const {
6888 isReactNative: isReactNative$1,
6889 isWindow: isWindow$1
6890} = Recoil_Environment;
6891
6892
6893
6894
6895
6896function shouldNotBeFrozen(value) {
6897 // Primitives and functions:
6898 if (value === null || typeof value !== 'object') {
6899 return true;
6900 } // React elements:
6901
6902
6903 switch (typeof value.$$typeof) {
6904 case 'symbol':
6905 return true;
6906
6907 case 'number':
6908 return true;
6909 } // Immutable structures:
6910
6911
6912 if (value['@@__IMMUTABLE_ITERABLE__@@'] != null || value['@@__IMMUTABLE_KEYED__@@'] != null || value['@@__IMMUTABLE_INDEXED__@@'] != null || value['@@__IMMUTABLE_ORDERED__@@'] != null || value['@@__IMMUTABLE_RECORD__@@'] != null) {
6913 return true;
6914 } // DOM nodes:
6915
6916
6917 if (Recoil_isNode(value)) {
6918 return true;
6919 }
6920
6921 if (Recoil_isPromise(value)) {
6922 return true;
6923 }
6924
6925 if (value instanceof Error) {
6926 return true;
6927 }
6928
6929 if (ArrayBuffer.isView(value)) {
6930 return true;
6931 } // Some environments, just as Jest, don't work with the instanceof check
6932
6933
6934 if (!isReactNative$1 && isWindow$1(value)) {
6935 return true;
6936 }
6937
6938 return false;
6939} // Recursively freeze a value to enforce it is read-only.
6940// This may also have minimal performance improvements for enumerating
6941// objects (based on browser implementations, of course)
6942
6943
6944function deepFreezeValue(value) {
6945 if (typeof value !== 'object' || shouldNotBeFrozen(value)) {
6946 return;
6947 }
6948
6949 Object.freeze(value); // Make all properties read-only
6950
6951 for (const key in value) {
6952 // $FlowIssue[method-unbinding] added when improving typing for this parameters
6953 if (Object.prototype.hasOwnProperty.call(value, key)) {
6954 const prop = value[key]; // Prevent infinite recurssion for circular references.
6955
6956 if (typeof prop === 'object' && prop != null && !Object.isFrozen(prop)) {
6957 deepFreezeValue(prop);
6958 }
6959 }
6960 }
6961
6962 Object.seal(value); // This also makes existing properties non-configurable.
6963}
6964
6965var Recoil_deepFreezeValue = deepFreezeValue;
6966
6967/**
6968 * Copyright (c) Meta Platforms, Inc. and affiliates.
6969 *
6970 * This source code is licensed under the MIT license found in the
6971 * LICENSE file in the root directory of this source tree.
6972 *
6973 * This is a stub for some integration into FB internal stuff
6974 *
6975 *
6976 * @format
6977 * @oncall recoil
6978 */
6979function startPerfBlock(_id) {
6980 return () => null;
6981}
6982
6983var Recoil_PerformanceTimings = {
6984 startPerfBlock
6985};
6986
6987const {
6988 isLoadable: isLoadable$1,
6989 loadableWithError: loadableWithError$1,
6990 loadableWithPromise: loadableWithPromise$1,
6991 loadableWithValue: loadableWithValue$2
6992} = Recoil_Loadable$1;
6993
6994const {
6995 WrappedValue: WrappedValue$1
6996} = Recoil_Wrapper$1;
6997
6998
6999
7000const {
7001 getNodeLoadable: getNodeLoadable$2,
7002 peekNodeLoadable: peekNodeLoadable$1,
7003 setNodeValue: setNodeValue$3
7004} = Recoil_FunctionalCore;
7005
7006const {
7007 saveDepsToStore: saveDepsToStore$1
7008} = Recoil_Graph;
7009
7010const {
7011 DEFAULT_VALUE: DEFAULT_VALUE$6,
7012 getConfigDeletionHandler: getConfigDeletionHandler$1,
7013 getNode: getNode$6,
7014 registerNode: registerNode$1
7015} = Recoil_Node;
7016
7017const {
7018 isRecoilValue: isRecoilValue$3
7019} = Recoil_RecoilValue$1;
7020
7021const {
7022 markRecoilValueModified: markRecoilValueModified$1
7023} = Recoil_RecoilValueInterface;
7024
7025const {
7026 retainedByOptionWithDefault: retainedByOptionWithDefault$1
7027} = Recoil_Retention;
7028
7029const {
7030 recoilCallback: recoilCallback$1
7031} = Recoil_useRecoilCallback;
7032
7033
7034
7035
7036
7037
7038
7039
7040
7041
7042
7043
7044
7045
7046
7047
7048
7049
7050
7051const {
7052 startPerfBlock: startPerfBlock$1
7053} = Recoil_PerformanceTimings;
7054
7055
7056
7057class Canceled {}
7058
7059const CANCELED = new Canceled();
7060/**
7061 * An ExecutionID is an arbitrary ID that lets us distinguish executions from
7062 * each other. This is necessary as we need a way of solving this problem:
7063 * "given 3 async executions, only update state for the 'latest' execution when
7064 * it finishes running regardless of when the other 2 finish". ExecutionIDs
7065 * provide a convenient way of identifying executions so that we can track and
7066 * manage them over time.
7067 */
7068
7069const dependencyStack = []; // for detecting circular dependencies.
7070
7071const waitingStores = new Map();
7072
7073const getNewExecutionID = (() => {
7074 let executionID = 0;
7075 return () => executionID++;
7076})();
7077/* eslint-disable no-redeclare */
7078
7079
7080function selector(options) {
7081 let recoilValue = null;
7082 const {
7083 key,
7084 get,
7085 cachePolicy_UNSTABLE: cachePolicy
7086 } = options;
7087 const set = options.set != null ? options.set : undefined; // flow
7088
7089 if (process.env.NODE_ENV !== "production") {
7090 if (typeof key !== 'string') {
7091 throw Recoil_err('A key option with a unique string value must be provided when creating a selector.');
7092 }
7093
7094 if (typeof get !== 'function') {
7095 throw Recoil_err('Selectors must specify a get callback option to get the selector value.');
7096 }
7097 } // This is every discovered dependency across all executions
7098
7099
7100 const discoveredDependencyNodeKeys = new Set();
7101 const cache = Recoil_treeCacheFromPolicy(cachePolicy !== null && cachePolicy !== void 0 ? cachePolicy : {
7102 equality: 'reference',
7103 eviction: 'keep-all'
7104 }, key);
7105 const retainedBy = retainedByOptionWithDefault$1(options.retainedBy_UNSTABLE);
7106 const executionInfoMap = new Map();
7107 let liveStoresCount = 0;
7108
7109 function selectorIsLive() {
7110 return !Recoil_gkx('recoil_memory_managament_2020') || liveStoresCount > 0;
7111 }
7112
7113 function selectorInit(store) {
7114 store.getState().knownSelectors.add(key);
7115 liveStoresCount++;
7116 return () => {
7117 liveStoresCount--;
7118 };
7119 }
7120
7121 function selectorShouldDeleteConfigOnRelease() {
7122 return getConfigDeletionHandler$1(key) !== undefined && !selectorIsLive();
7123 }
7124
7125 function resolveAsync(store, state, executionID, loadable, depValues) {
7126 setCache(state, loadable, depValues);
7127 notifyStoresOfResolvedAsync(store, executionID);
7128 }
7129
7130 function notifyStoresOfResolvedAsync(store, executionID) {
7131 if (isLatestExecution(store, executionID)) {
7132 clearExecutionInfo(store);
7133 }
7134
7135 notifyWaitingStores(executionID, true);
7136 }
7137 /**
7138 * Notify stores to pull the selector again if a new async dep was discovered.
7139 * 1) Async selector adds a new dep but doesn't resolve yet.
7140 * Note that deps for an async selector are based on the state when the
7141 * evaluation started, in order to provide a consistent picture of state.
7142 * 2) But, new value of dep based on the current state might cause the selector
7143 * to resolve or resolve differently.
7144 * 3) Therefore, this notification will pull the selector based on the current
7145 * state for the components
7146 */
7147
7148
7149 function notifyStoresOfNewAsyncDep(store, executionID) {
7150 if (isLatestExecution(store, executionID)) {
7151 const executionInfo = Recoil_nullthrows(getExecutionInfo(store));
7152 executionInfo.stateVersions.clear();
7153 notifyWaitingStores(executionID, false);
7154 }
7155 }
7156
7157 function notifyWaitingStores(executionID, clearWaitlist) {
7158 const stores = waitingStores.get(executionID);
7159
7160 if (stores != null) {
7161 for (const waitingStore of stores) {
7162 markRecoilValueModified$1(waitingStore, Recoil_nullthrows(recoilValue));
7163 }
7164
7165 if (clearWaitlist) {
7166 waitingStores.delete(executionID);
7167 }
7168 }
7169 }
7170
7171 function markStoreWaitingForResolvedAsync(store, executionID) {
7172 let stores = waitingStores.get(executionID);
7173
7174 if (stores == null) {
7175 waitingStores.set(executionID, stores = new Set());
7176 }
7177
7178 stores.add(store);
7179 }
7180 /**
7181 * This function attaches a then() and a catch() to a promise that was
7182 * returned from a selector's get() (either explicitly or implicitly by
7183 * running a function that uses the "async" keyword). If a selector's get()
7184 * returns a promise, we have two possibilities:
7185 *
7186 * 1. The promise will resolve, in which case it will have completely finished
7187 * executing without any remaining pending dependencies. No more retries
7188 * are needed and we can proceed with updating the cache and notifying
7189 * subscribers (if it is the latest execution, otherwise only the cache
7190 * will be updated and subscriptions will not be fired). This is the case
7191 * handled by the attached then() handler.
7192 *
7193 * 2. The promise will throw because it either has an error or it came across
7194 * an async dependency that has not yet resolved, in which case we will
7195 * call wrapDepdencyPromise(), whose responsibility is to handle dependency
7196 * promises. This case is handled by the attached catch() handler.
7197 *
7198 * Both branches will eventually resolve to the final result of the selector
7199 * (or an error if a real error occurred).
7200 *
7201 * The execution will run to completion even if it is stale, and its value
7202 * will be cached. But stale executions will not update global state or update
7203 * executionInfo as that is the responsibility of the 'latest' execution.
7204 *
7205 * Note this function should not be passed a promise that was thrown--AKA a
7206 * dependency promise. Dependency promises should be passed to
7207 * wrapPendingDependencyPromise()).
7208 */
7209
7210
7211 function wrapResultPromise(store, promise, state, depValues, executionID, loadingDepsState) {
7212 return promise.then(value => {
7213 if (!selectorIsLive()) {
7214 // The selector was released since the request began; ignore the response.
7215 clearExecutionInfo(store);
7216 throw CANCELED;
7217 }
7218
7219 const loadable = loadableWithValue$2(value);
7220 resolveAsync(store, state, executionID, loadable, depValues);
7221 return value;
7222 }).catch(errorOrPromise => {
7223 if (!selectorIsLive()) {
7224 // The selector was released since the request began; ignore the response.
7225 clearExecutionInfo(store);
7226 throw CANCELED;
7227 }
7228
7229 if (Recoil_isPromise(errorOrPromise)) {
7230 return wrapPendingDependencyPromise(store, errorOrPromise, state, depValues, executionID, loadingDepsState);
7231 }
7232
7233 const loadable = loadableWithError$1(errorOrPromise);
7234 resolveAsync(store, state, executionID, loadable, depValues);
7235 throw errorOrPromise;
7236 });
7237 }
7238 /**
7239 * This function attaches a then() and a catch() to a promise that was
7240 * thrown from a selector's get(). If a selector's get() throws a promise,
7241 * we have two possibilities:
7242 *
7243 * 1. The promise will resolve, meaning one of our selector's dependencies is
7244 * now available and we should "retry" our get() by running it again. This
7245 * is the case handled by the attached then() handler.
7246 *
7247 * 2. The promise will throw because something went wrong with the dependency
7248 * promise (in other words a real error occurred). This case is handled by
7249 * the attached catch() handler. If the dependency promise throws, it is
7250 * _always_ a real error and not another dependency promise (any dependency
7251 * promises would have been handled upstream).
7252 *
7253 * The then() branch will eventually resolve to the final result of the
7254 * selector (or an error if a real error occurs), and the catch() will always
7255 * resolve to an error because the dependency promise is a promise that was
7256 * wrapped upstream, meaning it will only resolve to its real value or to a
7257 * real error.
7258 *
7259 * The execution will run to completion even if it is stale, and its value
7260 * will be cached. But stale executions will not update global state or update
7261 * executionInfo as that is the responsibility of the 'latest' execution.
7262 *
7263 * Note this function should not be passed a promise that was returned from
7264 * get(). The intention is that this function is only passed promises that
7265 * were thrown due to a pending dependency. Promises returned by get() should
7266 * be passed to wrapResultPromise() instead.
7267 */
7268
7269
7270 function wrapPendingDependencyPromise(store, promise, state, existingDeps, executionID, loadingDepsState) {
7271 return promise.then(resolvedDep => {
7272 if (!selectorIsLive()) {
7273 // The selector was released since the request began; ignore the response.
7274 clearExecutionInfo(store);
7275 throw CANCELED;
7276 } // Check if we are handling a pending Recoil dependency or if the user
7277 // threw their own Promise to "suspend" a selector evaluation. We need
7278 // to check that the loadingDepPromise actually matches the promise that
7279 // we caught in case the selector happened to catch the promise we threw
7280 // for a pending Recoil dependency from `getRecoilValue()` and threw
7281 // their own promise instead.
7282
7283
7284 if (loadingDepsState.loadingDepKey != null && loadingDepsState.loadingDepPromise === promise) {
7285 /**
7286 * Note for async atoms, this means we are changing the atom's value
7287 * in the store for the given version. This should be alright because
7288 * the version of state is now stale and a new version will have
7289 * already been triggered by the atom being resolved (see this logic
7290 * in Recoil_atom.js)
7291 */
7292 state.atomValues.set(loadingDepsState.loadingDepKey, loadableWithValue$2(resolvedDep));
7293 } else {
7294 /**
7295 * If resolvedDepKey is not defined, the promise was a user-thrown
7296 * promise. User-thrown promises are an advanced feature and they
7297 * should be avoided in almost all cases. Using `loadable.map()` inside
7298 * of selectors for loading loadables and then throwing that mapped
7299 * loadable's promise is an example of a user-thrown promise.
7300 *
7301 * When we hit a user-thrown promise, we have to bail out of an optimization
7302 * where we bypass calculating selector cache keys for selectors that
7303 * have been previously seen for a given state (these selectors are saved in
7304 * state.atomValues) to avoid stale state as we have no way of knowing
7305 * what state changes happened (if any) in result to the promise resolving.
7306 *
7307 * Ideally we would only bail out selectors that are in the chain of
7308 * dependencies for this selector, but there's currently no way to get
7309 * a full list of a selector's downstream nodes because the state that
7310 * is executing may be a discarded tree (so store.getGraph(state.version)
7311 * will be empty), and the full dep tree may not be in the selector
7312 * caches in the case where the selector's cache was cleared. To solve
7313 * for this we would have to keep track of all running selector
7314 * executions and their downstream deps. Because this only covers edge
7315 * cases, that complexity might not be justifyable.
7316 */
7317 store.getState().knownSelectors.forEach(nodeKey => {
7318 state.atomValues.delete(nodeKey);
7319 });
7320 }
7321 /**
7322 * Optimization: Now that the dependency has resolved, let's try hitting
7323 * the cache in case the dep resolved to a value we have previously seen.
7324 *
7325 * TODO:
7326 * Note this optimization is not perfect because it only prevents re-executions
7327 * _after_ the point where an async dependency is found. Any code leading
7328 * up to the async dependency may have run unnecessarily. The ideal case
7329 * would be to wait for the async dependency to resolve first, check the
7330 * cache, and prevent _any_ execution of the selector if the resulting
7331 * value of the dependency leads to a path that is found in the cache.
7332 * The ideal case is more difficult to implement as it would require that
7333 * we capture and wait for the the async dependency right after checking
7334 * the cache. The current approach takes advantage of the fact that running
7335 * the selector already has a code path that lets us exit early when
7336 * an async dep resolves.
7337 */
7338
7339
7340 const cachedLoadable = getLoadableFromCacheAndUpdateDeps(store, state);
7341
7342 if (cachedLoadable && cachedLoadable.state !== 'loading') {
7343 /**
7344 * This has to notify stores of a resolved async, even if there is no
7345 * current pending execution for the following case:
7346 * 1) A component renders with this pending loadable.
7347 * 2) The upstream dependency resolves.
7348 * 3) While processing some other selector it reads this one, such as
7349 * while traversing its dependencies. At this point it gets the
7350 * new resolved value synchronously and clears the current
7351 * execution ID. The component wasn't getting the value itself,
7352 * though, so it still has the pending loadable.
7353 * 4) When this code executes the current execution id was cleared
7354 * and it wouldn't notify the component of the new value.
7355 *
7356 * I think this is only an issue with "early" rendering since the
7357 * components got their value using the in-progress execution.
7358 * We don't have a unit test for this case yet. I'm not sure it is
7359 * necessary with recoil_transition_support mode.
7360 */
7361 if (isLatestExecution(store, executionID) || getExecutionInfo(store) == null) {
7362 notifyStoresOfResolvedAsync(store, executionID);
7363 }
7364
7365 if (cachedLoadable.state === 'hasValue') {
7366 return cachedLoadable.contents;
7367 } else {
7368 throw cachedLoadable.contents;
7369 }
7370 }
7371 /**
7372 * If this execution is stale, let's check to see if there is some in
7373 * progress execution with a matching state. If we find a match, then
7374 * we can take the value from that in-progress execution. Note this may
7375 * sound like an edge case, but may be very common in cases where a
7376 * loading dependency resolves from loading to having a value (thus
7377 * possibly triggering a re-render), and React re-renders before the
7378 * chained .then() functions run, thus starting a new execution as the
7379 * dep has changed value. Without this check we will run the selector
7380 * twice (once in the new execution and once again in this .then(), so
7381 * this check is necessary to keep unnecessary re-executions to a
7382 * minimum).
7383 *
7384 * Also note this code does not check across all executions that may be
7385 * running. It only optimizes for the _latest_ execution per store as
7386 * we currently do not maintain a list of all currently running executions.
7387 * This means in some cases we may run selectors more than strictly
7388 * necessary when there are multiple executions running for the same
7389 * selector. This may be a valid tradeoff as checking for dep changes
7390 * across all in-progress executions may take longer than just
7391 * re-running the selector. This will be app-dependent, and maybe in the
7392 * future we can make the behavior configurable. An ideal fix may be
7393 * to extend the tree cache to support caching loading states.
7394 */
7395
7396
7397 if (!isLatestExecution(store, executionID)) {
7398 const executionInfo = getInProgressExecutionInfo(store, state);
7399
7400 if (executionInfo != null) {
7401 /**
7402 * Returning promise here without wrapping as the wrapper logic was
7403 * already done upstream when this promise was generated.
7404 */
7405 return executionInfo.loadingLoadable.contents;
7406 }
7407 } // Retry the selector evaluation now that the dependency has resolved
7408
7409
7410 const [loadable, depValues] = evaluateSelectorGetter(store, state, executionID);
7411
7412 if (loadable.state !== 'loading') {
7413 resolveAsync(store, state, executionID, loadable, depValues);
7414 }
7415
7416 if (loadable.state === 'hasError') {
7417 throw loadable.contents;
7418 }
7419
7420 return loadable.contents;
7421 }).catch(error => {
7422 // The selector was released since the request began; ignore the response.
7423 if (error instanceof Canceled) {
7424 throw CANCELED;
7425 }
7426
7427 if (!selectorIsLive()) {
7428 clearExecutionInfo(store);
7429 throw CANCELED;
7430 }
7431
7432 const loadable = loadableWithError$1(error);
7433 resolveAsync(store, state, executionID, loadable, existingDeps);
7434 throw error;
7435 });
7436 }
7437
7438 function updateDeps(store, state, deps, executionID) {
7439 var _store$getState, _store$getState$curre, _store$getState2, _store$getState2$next;
7440
7441 if (isLatestExecution(store, executionID) || state.version === ((_store$getState = store.getState()) === null || _store$getState === void 0 ? void 0 : (_store$getState$curre = _store$getState.currentTree) === null || _store$getState$curre === void 0 ? void 0 : _store$getState$curre.version) || state.version === ((_store$getState2 = store.getState()) === null || _store$getState2 === void 0 ? void 0 : (_store$getState2$next = _store$getState2.nextTree) === null || _store$getState2$next === void 0 ? void 0 : _store$getState2$next.version)) {
7442 var _store$getState$nextT, _store$getState3, _store$getState3$next;
7443
7444 saveDepsToStore$1(key, deps, store, (_store$getState$nextT = (_store$getState3 = store.getState()) === null || _store$getState3 === void 0 ? void 0 : (_store$getState3$next = _store$getState3.nextTree) === null || _store$getState3$next === void 0 ? void 0 : _store$getState3$next.version) !== null && _store$getState$nextT !== void 0 ? _store$getState$nextT : store.getState().currentTree.version);
7445 }
7446
7447 for (const nodeKey of deps) {
7448 discoveredDependencyNodeKeys.add(nodeKey);
7449 }
7450 }
7451
7452 function evaluateSelectorGetter(store, state, executionID) {
7453 const endPerfBlock = startPerfBlock$1(key); // TODO T63965866: use execution ID here
7454
7455 let duringSynchronousExecution = true;
7456 let duringAsynchronousExecution = true;
7457
7458 const finishEvaluation = () => {
7459 endPerfBlock();
7460 duringAsynchronousExecution = false;
7461 };
7462
7463 let result;
7464 let resultIsError = false;
7465 let loadable;
7466 const loadingDepsState = {
7467 loadingDepKey: null,
7468 loadingDepPromise: null
7469 };
7470 /**
7471 * Starting a fresh set of deps that we'll be using to update state. We're
7472 * starting a new set versus adding it in existing state deps because
7473 * the version of state that we update deps for may be a more recent version
7474 * than the version the selector was called with. This is because the latest
7475 * execution will update the deps of the current/latest version of state
7476 * (This is safe to do because the fact that the selector is the latest
7477 * execution means the deps we discover below are our best guess at the
7478 * deps for the current/latest state in the store)
7479 */
7480
7481 const depValues = new Map();
7482
7483 function getRecoilValue({
7484 key: depKey
7485 }) {
7486 const depLoadable = getNodeLoadable$2(store, state, depKey);
7487 depValues.set(depKey, depLoadable); // We need to update asynchronous dependencies as we go so the selector
7488 // knows if it has to restart evaluation if one of them is updated before
7489 // the asynchronous selector completely resolves.
7490
7491 if (!duringSynchronousExecution) {
7492 updateDeps(store, state, new Set(depValues.keys()), executionID);
7493 notifyStoresOfNewAsyncDep(store, executionID);
7494 }
7495
7496 switch (depLoadable.state) {
7497 case 'hasValue':
7498 return depLoadable.contents;
7499
7500 case 'hasError':
7501 throw depLoadable.contents;
7502
7503 case 'loading':
7504 loadingDepsState.loadingDepKey = depKey;
7505 loadingDepsState.loadingDepPromise = depLoadable.contents;
7506 throw depLoadable.contents;
7507 }
7508
7509 throw Recoil_err('Invalid Loadable state');
7510 }
7511
7512 const getCallback = fn => {
7513 return (...args) => {
7514 if (duringAsynchronousExecution) {
7515 throw Recoil_err('Callbacks from getCallback() should only be called asynchronously after the selector is evalutated. It can be used for selectors to return objects with callbacks that can work with Recoil state without a subscription.');
7516 }
7517
7518 !(recoilValue != null) ? process.env.NODE_ENV !== "production" ? Recoil_invariant(false, 'Recoil Value can never be null') : Recoil_invariant(false) : void 0;
7519 return recoilCallback$1(store, fn, args, {
7520 node: recoilValue
7521 } // flowlint-line unclear-type:off
7522 );
7523 };
7524 };
7525
7526 try {
7527 result = get({
7528 get: getRecoilValue,
7529 getCallback
7530 });
7531 result = isRecoilValue$3(result) ? getRecoilValue(result) : result;
7532
7533 if (isLoadable$1(result)) {
7534 if (result.state === 'hasError') {
7535 resultIsError = true;
7536 }
7537
7538 result = result.contents;
7539 }
7540
7541 if (Recoil_isPromise(result)) {
7542 result = wrapResultPromise(store, result, state, depValues, executionID, loadingDepsState).finally(finishEvaluation);
7543 } else {
7544 finishEvaluation();
7545 }
7546
7547 result = result instanceof WrappedValue$1 ? result.value : result;
7548 } catch (errorOrDepPromise) {
7549 result = errorOrDepPromise;
7550
7551 if (Recoil_isPromise(result)) {
7552 result = wrapPendingDependencyPromise(store, result, state, depValues, executionID, loadingDepsState).finally(finishEvaluation);
7553 } else {
7554 resultIsError = true;
7555 finishEvaluation();
7556 }
7557 }
7558
7559 if (resultIsError) {
7560 loadable = loadableWithError$1(result);
7561 } else if (Recoil_isPromise(result)) {
7562 loadable = loadableWithPromise$1(result);
7563 } else {
7564 loadable = loadableWithValue$2(result);
7565 }
7566
7567 duringSynchronousExecution = false;
7568 updateExecutionInfoDepValues(store, executionID, depValues);
7569 updateDeps(store, state, new Set(depValues.keys()), executionID);
7570 return [loadable, depValues];
7571 }
7572
7573 function getLoadableFromCacheAndUpdateDeps(store, state) {
7574 // First, look up in the state cache
7575 // If it's here, then the deps in the store should already be valid.
7576 let cachedLoadable = state.atomValues.get(key);
7577
7578 if (cachedLoadable != null) {
7579 return cachedLoadable;
7580 } // Second, look up in the selector cache and update the deps in the store
7581
7582
7583 const depsAfterCacheLookup = new Set();
7584
7585 try {
7586 cachedLoadable = cache.get(nodeKey => {
7587 !(typeof nodeKey === 'string') ? process.env.NODE_ENV !== "production" ? Recoil_invariant(false, 'Cache nodeKey is type string') : Recoil_invariant(false) : void 0;
7588 return getNodeLoadable$2(store, state, nodeKey).contents;
7589 }, {
7590 onNodeVisit: node => {
7591 if (node.type === 'branch' && node.nodeKey !== key) {
7592 depsAfterCacheLookup.add(node.nodeKey);
7593 }
7594 }
7595 });
7596 } catch (error) {
7597 throw Recoil_err(`Problem with cache lookup for selector "${key}": ${error.message}`);
7598 }
7599
7600 if (cachedLoadable) {
7601 var _getExecutionInfo;
7602
7603 // Cache the results in the state to allow for cheaper lookup than
7604 // iterating the tree cache of dependencies.
7605 state.atomValues.set(key, cachedLoadable);
7606 /**
7607 * Ensure store contains correct dependencies if we hit the cache so that
7608 * the store deps and cache are in sync for a given state. This is important
7609 * because store deps are normally updated when new executions are created,
7610 * but cache hits don't trigger new executions but they still _may_ signify
7611 * a change in deps in the store if the store deps for this state are empty
7612 * or stale.
7613 */
7614
7615 updateDeps(store, state, depsAfterCacheLookup, (_getExecutionInfo = getExecutionInfo(store)) === null || _getExecutionInfo === void 0 ? void 0 : _getExecutionInfo.executionID);
7616 }
7617
7618 return cachedLoadable;
7619 }
7620 /**
7621 * Given a tree state, this function returns a Loadable of the current state.
7622 *
7623 * The selector's get() function will only be re-evaluated if _both_ of the
7624 * following statements are true:
7625 *
7626 * 1. The current dep values from the given state produced a cache key that
7627 * was not found in the cache.
7628 * 2. There is no currently running async execution OR there is an
7629 * async execution that is running, but after comparing the dep values in
7630 * the given state with the dep values that the execution has discovered so
7631 * far we find that at least one dep value has changed, in which case we
7632 * start a new execution (the previously running execution will continue to
7633 * run to completion, but only the new execution will be deemed the
7634 * 'latest' execution, meaning it will be the only execution that will
7635 * update global state when it is finished. Any non-latest executions will
7636 * run to completion and update the selector cache but not global state).
7637 */
7638
7639
7640 function getSelectorLoadableAndUpdateDeps(store, state) {
7641 // First, see if our current state is cached
7642 const cachedVal = getLoadableFromCacheAndUpdateDeps(store, state);
7643
7644 if (cachedVal != null) {
7645 clearExecutionInfo(store);
7646 return cachedVal;
7647 } // Second, check if there is already an ongoing execution based on the current state
7648
7649
7650 const inProgressExecutionInfo = getInProgressExecutionInfo(store, state);
7651
7652 if (inProgressExecutionInfo != null) {
7653 var _inProgressExecutionI;
7654
7655 if (((_inProgressExecutionI = inProgressExecutionInfo.loadingLoadable) === null || _inProgressExecutionI === void 0 ? void 0 : _inProgressExecutionI.state) === 'loading') {
7656 markStoreWaitingForResolvedAsync(store, inProgressExecutionInfo.executionID);
7657 } // FIXME: check after the fact to see if we made the right choice by waiting
7658
7659
7660 return inProgressExecutionInfo.loadingLoadable;
7661 } // Third, start a new evaluation of the selector
7662
7663
7664 const newExecutionID = getNewExecutionID();
7665 const [loadable, newDepValues] = evaluateSelectorGetter(store, state, newExecutionID);
7666 /**
7667 * Conditionally updates the cache with a given loadable.
7668 *
7669 * We only cache loadables that are not loading because our cache keys are
7670 * based on dep values, which are in an unfinished state for loadables that
7671 * have a 'loading' state (new deps may be discovered while the selector
7672 * runs its async code). We never want to cache partial dependencies b/c it
7673 * could lead to errors, such as prematurely returning the result based on a
7674 * partial list of deps-- we need the full list of deps to ensure that we
7675 * are returning the correct result from cache.
7676 */
7677
7678 if (loadable.state === 'loading') {
7679 setExecutionInfo(store, newExecutionID, loadable, newDepValues, state);
7680 markStoreWaitingForResolvedAsync(store, newExecutionID);
7681 } else {
7682 clearExecutionInfo(store);
7683 setCache(state, loadable, newDepValues);
7684 }
7685
7686 return loadable;
7687 }
7688 /**
7689 * Searches execution info across all stores to see if there is an in-progress
7690 * execution whose dependency values match the values of the requesting store.
7691 */
7692
7693
7694 function getInProgressExecutionInfo(store, state) {
7695 // Sort the pending executions so that our current store is checked first.
7696 const pendingExecutions = Recoil_concatIterables([executionInfoMap.has(store) ? [Recoil_nullthrows(executionInfoMap.get(store))] : [], Recoil_mapIterable(Recoil_filterIterable(executionInfoMap, ([s]) => s !== store), ([, execInfo]) => execInfo)]);
7697
7698 function anyDepChanged(execDepValues) {
7699 for (const [depKey, execLoadable] of execDepValues) {
7700 if (!getNodeLoadable$2(store, state, depKey).is(execLoadable)) {
7701 return true;
7702 }
7703 }
7704
7705 return false;
7706 }
7707
7708 for (const execInfo of pendingExecutions) {
7709 if ( // If this execution was already checked to be valid with this version
7710 // of state, then let's use it!
7711 execInfo.stateVersions.get(state.version) || // If the deps for the execution match our current state, then it's valid
7712 !anyDepChanged(execInfo.depValuesDiscoveredSoFarDuringAsyncWork)) {
7713 execInfo.stateVersions.set(state.version, true);
7714 return execInfo;
7715 } else {
7716 execInfo.stateVersions.set(state.version, false);
7717 }
7718 }
7719
7720 return undefined;
7721 }
7722
7723 function getExecutionInfo(store) {
7724 return executionInfoMap.get(store);
7725 }
7726 /**
7727 * This function will update the selector's execution info when the selector
7728 * has either finished running an execution or has started a new execution. If
7729 * the given loadable is in a 'loading' state, the intention is that a new
7730 * execution has started. Otherwise, the intention is that an execution has
7731 * just finished.
7732 */
7733
7734
7735 function setExecutionInfo(store, newExecutionID, loadable, depValues, state) {
7736 executionInfoMap.set(store, {
7737 depValuesDiscoveredSoFarDuringAsyncWork: depValues,
7738 executionID: newExecutionID,
7739 loadingLoadable: loadable,
7740 stateVersions: new Map([[state.version, true]])
7741 });
7742 }
7743
7744 function updateExecutionInfoDepValues(store, executionID, depValues) {
7745 // We only need to bother updating the deps for the latest execution because
7746 // that's all getInProgressExecutionInfo() will be looking for.
7747 if (isLatestExecution(store, executionID)) {
7748 const executionInfo = getExecutionInfo(store);
7749
7750 if (executionInfo != null) {
7751 executionInfo.depValuesDiscoveredSoFarDuringAsyncWork = depValues;
7752 }
7753 }
7754 }
7755
7756 function clearExecutionInfo(store) {
7757 executionInfoMap.delete(store);
7758 }
7759
7760 function isLatestExecution(store, executionID) {
7761 var _getExecutionInfo2;
7762
7763 return executionID === ((_getExecutionInfo2 = getExecutionInfo(store)) === null || _getExecutionInfo2 === void 0 ? void 0 : _getExecutionInfo2.executionID);
7764 }
7765 /**
7766 * FIXME: dep keys should take into account the state of the loadable to
7767 * prevent the edge case where a loadable with an error and a loadable with
7768 * an error as a value are treated as the same thing incorrectly. For example
7769 * these two should be treated differently:
7770 *
7771 * selector({key: '', get: () => new Error('hi')});
7772 * selector({key: '', get () => {throw new Error('hi')}});
7773 *
7774 * With current implementation they are treated the same
7775 */
7776
7777
7778 function depValuesToDepRoute(depValues) {
7779 return Array.from(depValues.entries()).map(([depKey, valLoadable]) => [depKey, valLoadable.contents]);
7780 }
7781
7782 function setCache(state, loadable, depValues) {
7783 if (process.env.NODE_ENV !== "production") {
7784 if (loadable.state !== 'loading' && Boolean(options.dangerouslyAllowMutability) === false) {
7785 Recoil_deepFreezeValue(loadable.contents);
7786 }
7787 }
7788
7789 state.atomValues.set(key, loadable);
7790
7791 try {
7792 cache.set(depValuesToDepRoute(depValues), loadable);
7793 } catch (error) {
7794 throw Recoil_err(`Problem with setting cache for selector "${key}": ${error.message}`);
7795 }
7796 }
7797
7798 function detectCircularDependencies(fn) {
7799 if (dependencyStack.includes(key)) {
7800 const message = `Recoil selector has circular dependencies: ${dependencyStack.slice(dependencyStack.indexOf(key)).join(' \u2192 ')}`;
7801 return loadableWithError$1(Recoil_err(message));
7802 }
7803
7804 dependencyStack.push(key);
7805
7806 try {
7807 return fn();
7808 } finally {
7809 dependencyStack.pop();
7810 }
7811 }
7812
7813 function selectorPeek(store, state) {
7814 const cachedLoadable = state.atomValues.get(key);
7815
7816 if (cachedLoadable != null) {
7817 return cachedLoadable;
7818 }
7819
7820 return cache.get(nodeKey => {
7821 var _peekNodeLoadable;
7822
7823 !(typeof nodeKey === 'string') ? process.env.NODE_ENV !== "production" ? Recoil_invariant(false, 'Cache nodeKey is type string') : Recoil_invariant(false) : void 0;
7824 return (_peekNodeLoadable = peekNodeLoadable$1(store, state, nodeKey)) === null || _peekNodeLoadable === void 0 ? void 0 : _peekNodeLoadable.contents;
7825 });
7826 }
7827
7828 function selectorGet(store, state) {
7829 return detectCircularDependencies(() => getSelectorLoadableAndUpdateDeps(store, state));
7830 }
7831
7832 function invalidateSelector(state) {
7833 state.atomValues.delete(key);
7834 }
7835
7836 function clearSelectorCache(store, treeState) {
7837 !(recoilValue != null) ? process.env.NODE_ENV !== "production" ? Recoil_invariant(false, 'Recoil Value can never be null') : Recoil_invariant(false) : void 0;
7838
7839 for (const nodeKey of discoveredDependencyNodeKeys) {
7840 var _node$clearCache;
7841
7842 const node = getNode$6(nodeKey);
7843 (_node$clearCache = node.clearCache) === null || _node$clearCache === void 0 ? void 0 : _node$clearCache.call(node, store, treeState);
7844 }
7845
7846 discoveredDependencyNodeKeys.clear();
7847 invalidateSelector(treeState);
7848 cache.clear();
7849 markRecoilValueModified$1(store, recoilValue);
7850 }
7851
7852 if (set != null) {
7853 /**
7854 * ES5 strict mode prohibits defining non-top-level function declarations,
7855 * so don't use function declaration syntax here
7856 */
7857 const selectorSet = (store, state, newValue) => {
7858 let syncSelectorSetFinished = false;
7859 const writes = new Map();
7860
7861 function getRecoilValue({
7862 key: depKey
7863 }) {
7864 if (syncSelectorSetFinished) {
7865 throw Recoil_err('Recoil: Async selector sets are not currently supported.');
7866 }
7867
7868 const loadable = getNodeLoadable$2(store, state, depKey);
7869
7870 if (loadable.state === 'hasValue') {
7871 return loadable.contents;
7872 } else if (loadable.state === 'loading') {
7873 const msg = `Getting value of asynchronous atom or selector "${depKey}" in a pending state while setting selector "${key}" is not yet supported.`;
7874 Recoil_recoverableViolation(msg);
7875 throw Recoil_err(msg);
7876 } else {
7877 throw loadable.contents;
7878 }
7879 }
7880
7881 function setRecoilState(recoilState, valueOrUpdater // $FlowFixMe[missing-local-annot]
7882 ) {
7883 if (syncSelectorSetFinished) {
7884 const msg = 'Recoil: Async selector sets are not currently supported.';
7885 Recoil_recoverableViolation(msg);
7886 throw Recoil_err(msg);
7887 }
7888
7889 const setValue = typeof valueOrUpdater === 'function' ? // cast to any because we can't restrict type S from being a function itself without losing support for opaque types
7890 // flowlint-next-line unclear-type:off
7891 valueOrUpdater(getRecoilValue(recoilState)) : valueOrUpdater;
7892 const upstreamWrites = setNodeValue$3(store, state, recoilState.key, setValue);
7893 upstreamWrites.forEach((v, k) => writes.set(k, v));
7894 }
7895
7896 function resetRecoilState(recoilState) {
7897 setRecoilState(recoilState, DEFAULT_VALUE$6);
7898 }
7899
7900 const ret = set({
7901 set: setRecoilState,
7902 get: getRecoilValue,
7903 reset: resetRecoilState
7904 }, newValue); // set should be a void method, but if the user makes it `async`, then it
7905 // will return a Promise, which we don't currently support.
7906
7907 if (ret !== undefined) {
7908 throw Recoil_isPromise(ret) ? Recoil_err('Recoil: Async selector sets are not currently supported.') : Recoil_err('Recoil: selector set should be a void function.');
7909 }
7910
7911 syncSelectorSetFinished = true;
7912 return writes;
7913 };
7914
7915 return recoilValue = registerNode$1({
7916 key,
7917 nodeType: 'selector',
7918 peek: selectorPeek,
7919 get: selectorGet,
7920 set: selectorSet,
7921 init: selectorInit,
7922 invalidate: invalidateSelector,
7923 clearCache: clearSelectorCache,
7924 shouldDeleteConfigOnRelease: selectorShouldDeleteConfigOnRelease,
7925 dangerouslyAllowMutability: options.dangerouslyAllowMutability,
7926 shouldRestoreFromSnapshots: false,
7927 retainedBy
7928 });
7929 } else {
7930 return recoilValue = registerNode$1({
7931 key,
7932 nodeType: 'selector',
7933 peek: selectorPeek,
7934 get: selectorGet,
7935 init: selectorInit,
7936 invalidate: invalidateSelector,
7937 clearCache: clearSelectorCache,
7938 shouldDeleteConfigOnRelease: selectorShouldDeleteConfigOnRelease,
7939 dangerouslyAllowMutability: options.dangerouslyAllowMutability,
7940 shouldRestoreFromSnapshots: false,
7941 retainedBy
7942 });
7943 }
7944}
7945/* eslint-enable no-redeclare */
7946// $FlowIssue[incompatible-use]
7947// $FlowFixMe[missing-local-annot]
7948
7949
7950selector.value = value => new WrappedValue$1(value);
7951
7952var Recoil_selector = selector;
7953
7954// @fb-only: import type {ScopeRules} from 'Recoil_ScopedAtom';
7955// @fb-only: const {scopedAtom} = require('Recoil_ScopedAtom');
7956const {
7957 isLoadable: isLoadable$2,
7958 loadableWithError: loadableWithError$2,
7959 loadableWithPromise: loadableWithPromise$2,
7960 loadableWithValue: loadableWithValue$3
7961} = Recoil_Loadable$1;
7962
7963const {
7964 WrappedValue: WrappedValue$2
7965} = Recoil_Wrapper$1;
7966
7967const {
7968 peekNodeInfo: peekNodeInfo$3
7969} = Recoil_FunctionalCore;
7970
7971const {
7972 DEFAULT_VALUE: DEFAULT_VALUE$7,
7973 DefaultValue: DefaultValue$2,
7974 getConfigDeletionHandler: getConfigDeletionHandler$2,
7975 registerNode: registerNode$2,
7976 setConfigDeletionHandler: setConfigDeletionHandler$1
7977} = Recoil_Node;
7978
7979const {
7980 isRecoilValue: isRecoilValue$4
7981} = Recoil_RecoilValue$1;
7982
7983const {
7984 getRecoilValueAsLoadable: getRecoilValueAsLoadable$4,
7985 markRecoilValueModified: markRecoilValueModified$2,
7986 setRecoilValue: setRecoilValue$4,
7987 setRecoilValueLoadable: setRecoilValueLoadable$2
7988} = Recoil_RecoilValueInterface;
7989
7990const {
7991 retainedByOptionWithDefault: retainedByOptionWithDefault$2
7992} = Recoil_Retention;
7993
7994
7995
7996
7997
7998
7999
8000
8001
8002
8003
8004
8005
8006
8007
8008const unwrap = x => x instanceof WrappedValue$2 ? x.value : x;
8009
8010function baseAtom(options) {
8011 const {
8012 key,
8013 persistence_UNSTABLE: persistence
8014 } = options;
8015 const retainedBy = retainedByOptionWithDefault$2(options.retainedBy_UNSTABLE);
8016 let liveStoresCount = 0;
8017
8018 function unwrapPromise(promise) {
8019 return loadableWithPromise$2(promise.then(value => {
8020 defaultLoadable = loadableWithValue$3(value);
8021 return value;
8022 }).catch(error => {
8023 defaultLoadable = loadableWithError$2(error);
8024 throw error;
8025 }));
8026 }
8027
8028 let defaultLoadable = Recoil_isPromise(options.default) ? unwrapPromise(options.default) : isLoadable$2(options.default) ? options.default.state === 'loading' ? unwrapPromise(options.default.contents) : options.default : // $FlowFixMe[incompatible-call]
8029 loadableWithValue$3(unwrap(options.default));
8030 maybeFreezeValueOrPromise(defaultLoadable.contents);
8031 let cachedAnswerForUnvalidatedValue = undefined; // Cleanup handlers for this atom
8032 // Rely on stable reference equality of the store to use it as a key per <RecoilRoot>
8033
8034 const cleanupEffectsByStore = new Map();
8035
8036 function maybeFreezeValueOrPromise(valueOrPromise) {
8037 if (process.env.NODE_ENV !== "production") {
8038 if (options.dangerouslyAllowMutability !== true) {
8039 if (Recoil_isPromise(valueOrPromise)) {
8040 return valueOrPromise.then(value => {
8041 Recoil_deepFreezeValue(value);
8042 return value;
8043 });
8044 } else {
8045 Recoil_deepFreezeValue(valueOrPromise);
8046 return valueOrPromise;
8047 }
8048 }
8049 }
8050
8051 return valueOrPromise;
8052 }
8053
8054 function wrapPendingPromise(store, promise) {
8055 const wrappedPromise = promise.then(value => {
8056 var _store$getState$nextT, _state$atomValues$get;
8057
8058 const state = (_store$getState$nextT = store.getState().nextTree) !== null && _store$getState$nextT !== void 0 ? _store$getState$nextT : store.getState().currentTree;
8059
8060 if (((_state$atomValues$get = state.atomValues.get(key)) === null || _state$atomValues$get === void 0 ? void 0 : _state$atomValues$get.contents) === wrappedPromise) {
8061 setRecoilValue$4(store, node, value);
8062 }
8063
8064 return value;
8065 }).catch(error => {
8066 var _store$getState$nextT2, _state$atomValues$get2;
8067
8068 const state = (_store$getState$nextT2 = store.getState().nextTree) !== null && _store$getState$nextT2 !== void 0 ? _store$getState$nextT2 : store.getState().currentTree;
8069
8070 if (((_state$atomValues$get2 = state.atomValues.get(key)) === null || _state$atomValues$get2 === void 0 ? void 0 : _state$atomValues$get2.contents) === wrappedPromise) {
8071 setRecoilValueLoadable$2(store, node, loadableWithError$2(error));
8072 }
8073
8074 throw error;
8075 });
8076 return wrappedPromise;
8077 }
8078
8079 function initAtom(store, initState, trigger) {
8080 var _options$effects;
8081
8082 liveStoresCount++;
8083
8084 const cleanupAtom = () => {
8085 var _cleanupEffectsByStor;
8086
8087 liveStoresCount--;
8088 (_cleanupEffectsByStor = cleanupEffectsByStore.get(store)) === null || _cleanupEffectsByStor === void 0 ? void 0 : _cleanupEffectsByStor.forEach(cleanup => cleanup());
8089 cleanupEffectsByStore.delete(store);
8090 };
8091
8092 store.getState().knownAtoms.add(key); // Setup async defaults to notify subscribers when they resolve
8093
8094 if (defaultLoadable.state === 'loading') {
8095 const notifyDefaultSubscribers = () => {
8096 var _store$getState$nextT3;
8097
8098 const state = (_store$getState$nextT3 = store.getState().nextTree) !== null && _store$getState$nextT3 !== void 0 ? _store$getState$nextT3 : store.getState().currentTree;
8099
8100 if (!state.atomValues.has(key)) {
8101 markRecoilValueModified$2(store, node);
8102 }
8103 };
8104
8105 defaultLoadable.contents.finally(notifyDefaultSubscribers);
8106 } ///////////////////
8107 // Run Atom Effects
8108 ///////////////////
8109
8110
8111 const effects = (_options$effects = options.effects) !== null && _options$effects !== void 0 ? _options$effects : options.effects_UNSTABLE;
8112
8113 if (effects != null) {
8114 // This state is scoped by Store, since this is in the initAtom() closure
8115 let initValue = DEFAULT_VALUE$7;
8116 let isDuringInit = true;
8117 let isInitError = false;
8118 let pendingSetSelf = null;
8119
8120 function getLoadable(recoilValue) {
8121 // Normally we can just get the current value of another atom.
8122 // But for our own value we need to check if there is a pending
8123 // initialized value or get the fallback default value.
8124 if (isDuringInit && recoilValue.key === key) {
8125 // Cast T to S
8126 const retValue = initValue; // flowlint-line unclear-type:off
8127
8128 return retValue instanceof DefaultValue$2 ? peekAtom(store, initState) // flowlint-line unclear-type:off
8129 : Recoil_isPromise(retValue) ? loadableWithPromise$2(retValue.then(v => v instanceof DefaultValue$2 ? // Cast T to S
8130 defaultLoadable.toPromise() // flowlint-line unclear-type:off
8131 : v)) : // $FlowFixMe[incompatible-call]
8132 loadableWithValue$3(retValue);
8133 }
8134
8135 return getRecoilValueAsLoadable$4(store, recoilValue);
8136 }
8137
8138 function getPromise(recoilValue) {
8139 return getLoadable(recoilValue).toPromise();
8140 }
8141
8142 function getInfo_UNSTABLE(recoilValue) {
8143 var _store$getState$nextT4;
8144
8145 const info = peekNodeInfo$3(store, (_store$getState$nextT4 = store.getState().nextTree) !== null && _store$getState$nextT4 !== void 0 ? _store$getState$nextT4 : store.getState().currentTree, recoilValue.key);
8146 return isDuringInit && recoilValue.key === key && !(initValue instanceof DefaultValue$2) ? { ...info,
8147 isSet: true,
8148 loadable: getLoadable(recoilValue)
8149 } : info;
8150 }
8151
8152 const setSelf = effect => valueOrUpdater => {
8153 if (isDuringInit) {
8154 const currentLoadable = getLoadable(node);
8155 const currentValue = currentLoadable.state === 'hasValue' ? currentLoadable.contents : DEFAULT_VALUE$7;
8156 initValue = typeof valueOrUpdater === 'function' ? // cast to any because we can't restrict T from being a function without losing support for opaque types
8157 valueOrUpdater(currentValue) // flowlint-line unclear-type:off
8158 : valueOrUpdater;
8159
8160 if (Recoil_isPromise(initValue)) {
8161 initValue = initValue.then(value => {
8162 // Avoid calling onSet() when setSelf() initializes with a Promise
8163 pendingSetSelf = {
8164 effect,
8165 value
8166 };
8167 return value;
8168 });
8169 }
8170 } else {
8171 if (Recoil_isPromise(valueOrUpdater)) {
8172 throw Recoil_err('Setting atoms to async values is not implemented.');
8173 }
8174
8175 if (typeof valueOrUpdater !== 'function') {
8176 pendingSetSelf = {
8177 effect,
8178 value: unwrap(valueOrUpdater)
8179 };
8180 }
8181
8182 setRecoilValue$4(store, node, typeof valueOrUpdater === 'function' ? currentValue => {
8183 const newValue = unwrap( // cast to any because we can't restrict T from being a function without losing support for opaque types
8184 valueOrUpdater(currentValue) // flowlint-line unclear-type:off
8185 ); // $FlowFixMe[incompatible-type]
8186
8187 pendingSetSelf = {
8188 effect,
8189 value: newValue
8190 };
8191 return newValue;
8192 } : unwrap(valueOrUpdater));
8193 }
8194 };
8195
8196 const resetSelf = effect => () => setSelf(effect)(DEFAULT_VALUE$7);
8197
8198 const onSet = effect => handler => {
8199 var _cleanupEffectsByStor2;
8200
8201 const {
8202 release
8203 } = store.subscribeToTransactions(currentStore => {
8204 var _currentTree$atomValu;
8205
8206 // eslint-disable-next-line prefer-const
8207 let {
8208 currentTree,
8209 previousTree
8210 } = currentStore.getState();
8211
8212 if (!previousTree) {
8213 Recoil_recoverableViolation('Transaction subscribers notified without a next tree being present -- this is a bug in Recoil');
8214 previousTree = currentTree; // attempt to trundle on
8215 }
8216
8217 const newLoadable = (_currentTree$atomValu = currentTree.atomValues.get(key)) !== null && _currentTree$atomValu !== void 0 ? _currentTree$atomValu : defaultLoadable;
8218
8219 if (newLoadable.state === 'hasValue') {
8220 var _previousTree$atomVal, _pendingSetSelf, _pendingSetSelf2, _pendingSetSelf3;
8221
8222 const newValue = newLoadable.contents;
8223 const oldLoadable = (_previousTree$atomVal = previousTree.atomValues.get(key)) !== null && _previousTree$atomVal !== void 0 ? _previousTree$atomVal : defaultLoadable;
8224 const oldValue = oldLoadable.state === 'hasValue' ? oldLoadable.contents : DEFAULT_VALUE$7; // TODO This isn't actually valid, use as a placeholder for now.
8225 // Ignore atom value changes that were set via setSelf() in the same effect.
8226 // We will still properly call the handler if there was a subsequent
8227 // set from something other than an atom effect which was batched
8228 // with the `setSelf()` call. However, we may incorrectly ignore
8229 // the handler if the subsequent batched call happens to set the
8230 // atom to the exact same value as the `setSelf()`. But, in that
8231 // case, it was kind of a noop, so the semantics are debatable..
8232
8233 if (((_pendingSetSelf = pendingSetSelf) === null || _pendingSetSelf === void 0 ? void 0 : _pendingSetSelf.effect) !== effect || ((_pendingSetSelf2 = pendingSetSelf) === null || _pendingSetSelf2 === void 0 ? void 0 : _pendingSetSelf2.value) !== newValue) {
8234 handler(newValue, oldValue, !currentTree.atomValues.has(key));
8235 } else if (((_pendingSetSelf3 = pendingSetSelf) === null || _pendingSetSelf3 === void 0 ? void 0 : _pendingSetSelf3.effect) === effect) {
8236 pendingSetSelf = null;
8237 }
8238 }
8239 }, key);
8240 cleanupEffectsByStore.set(store, [...((_cleanupEffectsByStor2 = cleanupEffectsByStore.get(store)) !== null && _cleanupEffectsByStor2 !== void 0 ? _cleanupEffectsByStor2 : []), release]);
8241 };
8242
8243 for (const effect of effects) {
8244 try {
8245 const cleanup = effect({
8246 node,
8247 storeID: store.storeID,
8248 parentStoreID_UNSTABLE: store.parentStoreID,
8249 trigger,
8250 setSelf: setSelf(effect),
8251 resetSelf: resetSelf(effect),
8252 onSet: onSet(effect),
8253 getPromise,
8254 getLoadable,
8255 getInfo_UNSTABLE
8256 });
8257
8258 if (cleanup != null) {
8259 var _cleanupEffectsByStor3;
8260
8261 cleanupEffectsByStore.set(store, [...((_cleanupEffectsByStor3 = cleanupEffectsByStore.get(store)) !== null && _cleanupEffectsByStor3 !== void 0 ? _cleanupEffectsByStor3 : []), cleanup]);
8262 }
8263 } catch (error) {
8264 initValue = error;
8265 isInitError = true;
8266 }
8267 }
8268
8269 isDuringInit = false; // Mutate initial state in place since we know there are no other subscribers
8270 // since we are the ones initializing on first use.
8271
8272 if (!(initValue instanceof DefaultValue$2)) {
8273 var _store$getState$nextT5;
8274
8275 const initLoadable = isInitError ? loadableWithError$2(initValue) : Recoil_isPromise(initValue) ? loadableWithPromise$2(wrapPendingPromise(store, initValue)) : loadableWithValue$3(unwrap(initValue));
8276 maybeFreezeValueOrPromise(initLoadable.contents);
8277 initState.atomValues.set(key, initLoadable); // If there is a pending transaction, then also mutate the next state tree.
8278 // This could happen if the atom was first initialized in an action that
8279 // also updated some other atom's state.
8280
8281 (_store$getState$nextT5 = store.getState().nextTree) === null || _store$getState$nextT5 === void 0 ? void 0 : _store$getState$nextT5.atomValues.set(key, initLoadable);
8282 }
8283 }
8284
8285 return cleanupAtom;
8286 }
8287
8288 function peekAtom(_store, state) {
8289 var _ref, _state$atomValues$get3;
8290
8291 return (_ref = (_state$atomValues$get3 = state.atomValues.get(key)) !== null && _state$atomValues$get3 !== void 0 ? _state$atomValues$get3 : cachedAnswerForUnvalidatedValue) !== null && _ref !== void 0 ? _ref : defaultLoadable;
8292 }
8293
8294 function getAtom(_store, state) {
8295 if (state.atomValues.has(key)) {
8296 // Atom value is stored in state:
8297 return Recoil_nullthrows(state.atomValues.get(key));
8298 } else if (state.nonvalidatedAtoms.has(key)) {
8299 // Atom value is stored but needs validation before use.
8300 // We might have already validated it and have a cached validated value:
8301 if (cachedAnswerForUnvalidatedValue != null) {
8302 return cachedAnswerForUnvalidatedValue;
8303 }
8304
8305 if (persistence == null) {
8306 Recoil_expectationViolation(`Tried to restore a persisted value for atom ${key} but it has no persistence settings.`);
8307 return defaultLoadable;
8308 }
8309
8310 const nonvalidatedValue = state.nonvalidatedAtoms.get(key);
8311 const validatorResult = persistence.validator(nonvalidatedValue, DEFAULT_VALUE$7);
8312 const validatedValueLoadable = validatorResult instanceof DefaultValue$2 ? defaultLoadable : loadableWithValue$3(validatorResult);
8313 cachedAnswerForUnvalidatedValue = validatedValueLoadable;
8314 return cachedAnswerForUnvalidatedValue;
8315 } else {
8316 return defaultLoadable;
8317 }
8318 }
8319
8320 function invalidateAtom() {
8321 cachedAnswerForUnvalidatedValue = undefined;
8322 }
8323
8324 function setAtom(_store, state, newValue) {
8325 // Bail out if we're being set to the existing value, or if we're being
8326 // reset but have no stored value (validated or unvalidated) to reset from:
8327 if (state.atomValues.has(key)) {
8328 const existing = Recoil_nullthrows(state.atomValues.get(key));
8329
8330 if (existing.state === 'hasValue' && newValue === existing.contents) {
8331 return new Map();
8332 }
8333 } else if (!state.nonvalidatedAtoms.has(key) && newValue instanceof DefaultValue$2) {
8334 return new Map();
8335 }
8336
8337 maybeFreezeValueOrPromise(newValue);
8338 cachedAnswerForUnvalidatedValue = undefined; // can be released now if it was previously in use
8339
8340 return new Map().set(key, loadableWithValue$3(newValue));
8341 }
8342
8343 function shouldDeleteConfigOnReleaseAtom() {
8344 return getConfigDeletionHandler$2(key) !== undefined && liveStoresCount <= 0;
8345 }
8346
8347 const node = registerNode$2({
8348 key,
8349 nodeType: 'atom',
8350 peek: peekAtom,
8351 get: getAtom,
8352 set: setAtom,
8353 init: initAtom,
8354 invalidate: invalidateAtom,
8355 shouldDeleteConfigOnRelease: shouldDeleteConfigOnReleaseAtom,
8356 dangerouslyAllowMutability: options.dangerouslyAllowMutability,
8357 persistence_UNSTABLE: options.persistence_UNSTABLE ? {
8358 type: options.persistence_UNSTABLE.type,
8359 backButton: options.persistence_UNSTABLE.backButton
8360 } : undefined,
8361 shouldRestoreFromSnapshots: true,
8362 retainedBy
8363 });
8364 return node;
8365} // prettier-ignore
8366
8367
8368function atom(options) {
8369 if (process.env.NODE_ENV !== "production") {
8370 if (typeof options.key !== 'string') {
8371 throw Recoil_err('A key option with a unique string value must be provided when creating an atom.');
8372 }
8373 }
8374
8375 const { // @fb-only: scopeRules_APPEND_ONLY_READ_THE_DOCS,
8376 ...restOptions
8377 } = options;
8378 const optionsDefault = 'default' in options ? // $FlowIssue[incompatible-type] No way to refine in Flow that property is not defined
8379 options.default : new Promise(() => {});
8380
8381 if (isRecoilValue$4(optionsDefault) // Continue to use atomWithFallback for promise defaults for scoped atoms
8382 // for now, since scoped atoms don't support async defaults
8383 // @fb-only: || (isPromise(optionsDefault) && scopeRules_APPEND_ONLY_READ_THE_DOCS)
8384 // @fb-only: || (isLoadable(optionsDefault) && scopeRules_APPEND_ONLY_READ_THE_DOCS)
8385 ) {
8386 return atomWithFallback({ ...restOptions,
8387 default: optionsDefault // @fb-only: scopeRules_APPEND_ONLY_READ_THE_DOCS,
8388
8389 }); // @fb-only: } else if (scopeRules_APPEND_ONLY_READ_THE_DOCS
8390 // @fb-only: && !isPromise(optionsDefault)
8391 // @fb-only: && !isLoadable(optionsDefault)
8392 // @fb-only: ) {
8393 // @fb-only: return scopedAtom<T>({
8394 // @fb-only: ...restOptions,
8395 // @fb-only: default: unwrap<T>(optionsDefault),
8396 // @fb-only: scopeRules_APPEND_ONLY_READ_THE_DOCS,
8397 // @fb-only: });
8398 } else {
8399 return baseAtom({ ...restOptions,
8400 default: optionsDefault
8401 });
8402 }
8403}
8404
8405function atomWithFallback(options) {
8406 const base = atom({ ...options,
8407 default: DEFAULT_VALUE$7,
8408 persistence_UNSTABLE: options.persistence_UNSTABLE === undefined ? undefined : { ...options.persistence_UNSTABLE,
8409 validator: storedValue => storedValue instanceof DefaultValue$2 ? storedValue : Recoil_nullthrows(options.persistence_UNSTABLE).validator(storedValue, DEFAULT_VALUE$7)
8410 },
8411 // TODO Hack for now.
8412 effects: options.effects,
8413 // flowlint-line unclear-type: off
8414 effects_UNSTABLE: options.effects_UNSTABLE // flowlint-line unclear-type: off
8415
8416 }); // $FlowFixMe[incompatible-call]
8417
8418 const sel = Recoil_selector({
8419 key: `${options.key}__withFallback`,
8420 get: ({
8421 get
8422 }) => {
8423 const baseValue = get(base);
8424 return baseValue instanceof DefaultValue$2 ? options.default : baseValue;
8425 },
8426 // $FlowFixMe[incompatible-call]
8427 set: ({
8428 set
8429 }, newValue) => set(base, newValue),
8430 // This selector does not need to cache as it is a wrapper selector
8431 // and the selector within the wrapper selector will have a cache
8432 // option by default
8433 cachePolicy_UNSTABLE: {
8434 eviction: 'most-recent'
8435 },
8436 dangerouslyAllowMutability: options.dangerouslyAllowMutability
8437 });
8438 setConfigDeletionHandler$1(sel.key, getConfigDeletionHandler$2(options.key));
8439 return sel;
8440} // $FlowFixMe[missing-local-annot]
8441
8442
8443atom.value = value => new WrappedValue$2(value);
8444
8445var Recoil_atom = atom;
8446
8447/**
8448 * Copyright (c) Meta Platforms, Inc. and affiliates.
8449 *
8450 * This source code is licensed under the MIT license found in the
8451 * LICENSE file in the root directory of this source tree.
8452 *
8453 *
8454 * @format
8455 * @oncall recoil
8456 */
8457
8458class MapCache {
8459 constructor(options) {
8460 var _options$mapKey;
8461
8462 _defineProperty(this, "_map", void 0);
8463
8464 _defineProperty(this, "_keyMapper", void 0);
8465
8466 this._map = new Map();
8467 this._keyMapper = (_options$mapKey = options === null || options === void 0 ? void 0 : options.mapKey) !== null && _options$mapKey !== void 0 ? _options$mapKey : v => v;
8468 }
8469
8470 size() {
8471 return this._map.size;
8472 }
8473
8474 has(key) {
8475 return this._map.has(this._keyMapper(key));
8476 }
8477
8478 get(key) {
8479 return this._map.get(this._keyMapper(key));
8480 }
8481
8482 set(key, val) {
8483 this._map.set(this._keyMapper(key), val);
8484 }
8485
8486 delete(key) {
8487 this._map.delete(this._keyMapper(key));
8488 }
8489
8490 clear() {
8491 this._map.clear();
8492 }
8493
8494}
8495
8496var Recoil_MapCache = {
8497 MapCache
8498};
8499
8500var Recoil_MapCache_1 = Recoil_MapCache.MapCache;
8501
8502var Recoil_MapCache$1 = /*#__PURE__*/Object.freeze({
8503 __proto__: null,
8504 MapCache: Recoil_MapCache_1
8505});
8506
8507const {
8508 LRUCache: LRUCache$2
8509} = Recoil_LRUCache$1;
8510
8511const {
8512 MapCache: MapCache$1
8513} = Recoil_MapCache$1;
8514
8515
8516
8517
8518
8519
8520
8521const defaultPolicy$1 = {
8522 equality: 'reference',
8523 eviction: 'none',
8524 maxSize: Infinity
8525};
8526
8527function cacheFromPolicy({
8528 equality = defaultPolicy$1.equality,
8529 eviction = defaultPolicy$1.eviction,
8530 maxSize = defaultPolicy$1.maxSize
8531} = defaultPolicy$1) {
8532 const valueMapper = getValueMapper$1(equality);
8533 const cache = getCache(eviction, maxSize, valueMapper);
8534 return cache;
8535}
8536
8537function getValueMapper$1(equality) {
8538 switch (equality) {
8539 case 'reference':
8540 return val => val;
8541
8542 case 'value':
8543 return val => Recoil_stableStringify(val);
8544 }
8545
8546 throw Recoil_err(`Unrecognized equality policy ${equality}`);
8547}
8548
8549function getCache(eviction, maxSize, mapKey) {
8550 switch (eviction) {
8551 case 'keep-all':
8552 return new MapCache$1({
8553 mapKey
8554 });
8555
8556 case 'lru':
8557 return new LRUCache$2({
8558 mapKey,
8559 maxSize: Recoil_nullthrows(maxSize)
8560 });
8561
8562 case 'most-recent':
8563 return new LRUCache$2({
8564 mapKey,
8565 maxSize: 1
8566 });
8567 }
8568
8569 throw Recoil_err(`Unrecognized eviction policy ${eviction}`);
8570}
8571
8572var Recoil_cacheFromPolicy = cacheFromPolicy;
8573
8574// @fb-only: import type {ScopeRules} from 'Recoil_ScopedAtom';
8575
8576
8577const {
8578 setConfigDeletionHandler: setConfigDeletionHandler$2
8579} = Recoil_Node;
8580
8581
8582
8583
8584
8585// Process scopeRules to handle any entries which are functions taking parameters
8586// prettier-ignore
8587// @fb-only: function mapScopeRules<P>(
8588// @fb-only: scopeRules?: ParameterizedScopeRules<P>,
8589// @fb-only: param: P,
8590// @fb-only: ): ScopeRules | void {
8591// @fb-only: return scopeRules?.map(rule =>
8592// @fb-only: Array.isArray(rule)
8593// @fb-only: ? rule.map(entry => (typeof entry === 'function' ? entry(param) : entry))
8594// @fb-only: : rule,
8595// @fb-only: );
8596// @fb-only: }
8597
8598/*
8599A function which returns an atom based on the input parameter.
8600
8601Each unique parameter returns a unique atom. E.g.,
8602
8603 const f = atomFamily(...);
8604 f({a: 1}) => an atom
8605 f({a: 2}) => a different atom
8606
8607This allows components to persist local, private state using atoms. Each
8608instance of the component may have a different key, which it uses as the
8609parameter for a family of atoms; in this way, each component will have
8610its own atom not shared by other instances. These state keys may be composed
8611into children's state keys as well.
8612*/
8613function atomFamily(options) {
8614 var _options$cachePolicyF, _options$cachePolicyF2;
8615
8616 const atomCache = Recoil_cacheFromPolicy({
8617 equality: (_options$cachePolicyF = (_options$cachePolicyF2 = options.cachePolicyForParams_UNSTABLE) === null || _options$cachePolicyF2 === void 0 ? void 0 : _options$cachePolicyF2.equality) !== null && _options$cachePolicyF !== void 0 ? _options$cachePolicyF : 'value',
8618 eviction: 'keep-all'
8619 }); // Simple atomFamily implementation to cache individual atoms based
8620 // on the parameter value equality.
8621
8622 return params => {
8623 var _stableStringify, _options$effects;
8624
8625 const cachedAtom = atomCache.get(params);
8626
8627 if (cachedAtom != null) {
8628 return cachedAtom;
8629 }
8630
8631 const {
8632 cachePolicyForParams_UNSTABLE,
8633 ...atomOptions
8634 } = options;
8635 const optionsDefault = 'default' in options ? // $FlowIssue[incompatible-type] No way to refine in Flow that property is not defined
8636 options.default : new Promise(() => {});
8637 const newAtom = Recoil_atom({ ...atomOptions,
8638 key: `${options.key}__${(_stableStringify = Recoil_stableStringify(params)) !== null && _stableStringify !== void 0 ? _stableStringify : 'void'}`,
8639 default: typeof optionsDefault === 'function' ? // The default was parameterized
8640 // Flow doesn't know that T isn't a function, so we need to case to any
8641 // $FlowIssue[incompatible-use]
8642 optionsDefault(params) : // Default may be a static value, promise, or RecoilValue
8643 optionsDefault,
8644 retainedBy_UNSTABLE: typeof options.retainedBy_UNSTABLE === 'function' ? options.retainedBy_UNSTABLE(params) : options.retainedBy_UNSTABLE,
8645 effects: typeof options.effects === 'function' ? options.effects(params) : typeof options.effects_UNSTABLE === 'function' ? options.effects_UNSTABLE(params) : (_options$effects = options.effects) !== null && _options$effects !== void 0 ? _options$effects : options.effects_UNSTABLE // prettier-ignore
8646 // @fb-only: scopeRules_APPEND_ONLY_READ_THE_DOCS: mapScopeRules(
8647 // @fb-only: options.scopeRules_APPEND_ONLY_READ_THE_DOCS,
8648 // @fb-only: params,
8649 // @fb-only: ),
8650
8651 });
8652 atomCache.set(params, newAtom);
8653 setConfigDeletionHandler$2(newAtom.key, () => {
8654 atomCache.delete(params);
8655 });
8656 return newAtom;
8657 };
8658}
8659
8660var Recoil_atomFamily = atomFamily;
8661
8662const {
8663 setConfigDeletionHandler: setConfigDeletionHandler$3
8664} = Recoil_Node;
8665
8666
8667
8668
8669
8670 // Keep in mind the parameter needs to be serializable as a cahche key
8671// using Recoil_stableStringify
8672
8673
8674// Add a unique index to each selector in case the cache implementation allows
8675// duplicate keys based on equivalent stringified parameters
8676let nextIndex = 0;
8677/* eslint-disable no-redeclare */
8678
8679// Return a function that returns members of a family of selectors of the same type
8680// E.g.,
8681//
8682// const s = selectorFamily(...);
8683// s({a: 1}) => a selector
8684// s({a: 2}) => a different selector
8685//
8686// By default, the selectors are distinguished by distinct values of the
8687// parameter based on value equality, not reference equality. This allows using
8688// object literals or other equivalent objects at callsites to not create
8689// duplicate cache entries. This behavior may be overridden with the
8690// cacheImplementationForParams option.
8691function selectorFamily(options) {
8692 var _options$cachePolicyF, _options$cachePolicyF2;
8693
8694 const selectorCache = Recoil_cacheFromPolicy({
8695 equality: (_options$cachePolicyF = (_options$cachePolicyF2 = options.cachePolicyForParams_UNSTABLE) === null || _options$cachePolicyF2 === void 0 ? void 0 : _options$cachePolicyF2.equality) !== null && _options$cachePolicyF !== void 0 ? _options$cachePolicyF : 'value',
8696 eviction: 'keep-all'
8697 });
8698 return params => {
8699 var _stableStringify;
8700
8701 // Throw an error with selector key so that it is clear which
8702 // selector is causing an error
8703 let cachedSelector;
8704
8705 try {
8706 cachedSelector = selectorCache.get(params);
8707 } catch (error) {
8708 throw Recoil_err(`Problem with cache lookup for selector ${options.key}: ${error.message}`);
8709 }
8710
8711 if (cachedSelector != null) {
8712 return cachedSelector;
8713 }
8714
8715 const myKey = `${options.key}__selectorFamily/${(_stableStringify = Recoil_stableStringify(params, {
8716 // It is possible to use functions in parameters if the user uses
8717 // a cache with reference equality thanks to the incrementing index.
8718 allowFunctions: true
8719 })) !== null && _stableStringify !== void 0 ? _stableStringify : 'void'}/${nextIndex++}`; // Append index in case values serialize to the same key string
8720
8721 const myGet = callbacks => options.get(params)(callbacks);
8722
8723 const myCachePolicy = options.cachePolicy_UNSTABLE;
8724 const retainedBy = typeof options.retainedBy_UNSTABLE === 'function' ? options.retainedBy_UNSTABLE(params) : options.retainedBy_UNSTABLE;
8725 let newSelector;
8726
8727 if (options.set != null) {
8728 const set = options.set;
8729
8730 const mySet = (callbacks, newValue) => set(params)(callbacks, newValue);
8731
8732 newSelector = Recoil_selector({
8733 key: myKey,
8734 get: myGet,
8735 set: mySet,
8736 cachePolicy_UNSTABLE: myCachePolicy,
8737 dangerouslyAllowMutability: options.dangerouslyAllowMutability,
8738 retainedBy_UNSTABLE: retainedBy
8739 });
8740 } else {
8741 newSelector = Recoil_selector({
8742 key: myKey,
8743 get: myGet,
8744 cachePolicy_UNSTABLE: myCachePolicy,
8745 dangerouslyAllowMutability: options.dangerouslyAllowMutability,
8746 retainedBy_UNSTABLE: retainedBy
8747 });
8748 }
8749
8750 selectorCache.set(params, newSelector);
8751 setConfigDeletionHandler$3(newSelector.key, () => {
8752 selectorCache.delete(params);
8753 });
8754 return newSelector;
8755 };
8756}
8757/* eslint-enable no-redeclare */
8758
8759
8760var Recoil_selectorFamily = selectorFamily;
8761
8762// flowlint-next-line unclear-type:off
8763
8764
8765const constantSelector = Recoil_selectorFamily({
8766 key: '__constant',
8767 get: constant => () => constant,
8768 cachePolicyForParams_UNSTABLE: {
8769 equality: 'reference'
8770 }
8771}); // Function that returns a selector which always produces the
8772// same constant value. It may be called multiple times with the
8773// same value, based on reference equality, and will provide the
8774// same selector.
8775
8776function constSelector(constant) {
8777 return constantSelector(constant);
8778}
8779
8780var Recoil_constSelector = constSelector;
8781
8782// flowlint-next-line unclear-type:off
8783
8784
8785const throwingSelector = Recoil_selectorFamily({
8786 key: '__error',
8787 get: message => () => {
8788 throw Recoil_err(message);
8789 },
8790 // TODO Why?
8791 cachePolicyForParams_UNSTABLE: {
8792 equality: 'reference'
8793 }
8794}); // Function that returns a selector which always throws an error
8795// with the provided message.
8796
8797function errorSelector(message) {
8798 return throwingSelector(message);
8799}
8800
8801var Recoil_errorSelector = errorSelector;
8802
8803/**
8804 * Copyright (c) Meta Platforms, Inc. and affiliates.
8805 *
8806 * This source code is licensed under the MIT license found in the
8807 * LICENSE file in the root directory of this source tree.
8808 *
8809 * Wraps another recoil value and prevents writing to it.
8810 *
8811 *
8812 * @format
8813 * @oncall recoil
8814 */
8815
8816function readOnlySelector(atom) {
8817 // flowlint-next-line unclear-type: off
8818 return atom;
8819}
8820
8821var Recoil_readOnlySelector = readOnlySelector;
8822
8823const {
8824 loadableWithError: loadableWithError$3,
8825 loadableWithPromise: loadableWithPromise$3,
8826 loadableWithValue: loadableWithValue$4
8827} = Recoil_Loadable$1;
8828
8829
8830
8831
8832
8833 /////////////////
8834// TRUTH TABLE
8835/////////////////
8836// Dependencies waitForNone waitForAny waitForAll waitForAllSettled
8837// [loading, loading] [Promise, Promise] Promise Promise Promise
8838// [value, loading] [value, Promise] [value, Promise] Promise Promise
8839// [value, value] [value, value] [value, value] [value, value] [value, value]
8840//
8841// [error, loading] [Error, Promise] [Error, Promise] Error Promise
8842// [error, error] [Error, Error] [Error, Error] Error [error, error]
8843// [value, error] [value, Error] [value, Error] Error [value, error]
8844// Issue parallel requests for all dependencies and return the current
8845// status if they have results, have some error, or are still pending.
8846
8847
8848function concurrentRequests(getRecoilValue, deps) {
8849 const results = Array(deps.length).fill(undefined);
8850 const exceptions = Array(deps.length).fill(undefined);
8851
8852 for (const [i, dep] of deps.entries()) {
8853 try {
8854 results[i] = getRecoilValue(dep);
8855 } catch (e) {
8856 // exceptions can either be Promises of pending results or real errors
8857 exceptions[i] = e;
8858 }
8859 }
8860
8861 return [results, exceptions];
8862}
8863
8864function isError(exp) {
8865 return exp != null && !Recoil_isPromise(exp);
8866}
8867
8868function unwrapDependencies(dependencies) {
8869 return Array.isArray(dependencies) ? dependencies : Object.getOwnPropertyNames(dependencies).map(key => dependencies[key]);
8870}
8871
8872function wrapResults(dependencies,
8873/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's
8874 * LTI update could not be added via codemod */
8875results) {
8876 return Array.isArray(dependencies) ? results : // Object.getOwnPropertyNames() has consistent key ordering with ES6
8877 Object.getOwnPropertyNames(dependencies).reduce((out, key, idx) => ({ ...out,
8878 [key]: results[idx]
8879 }), {});
8880}
8881
8882function wrapLoadables(dependencies, results, exceptions) {
8883 const output = exceptions.map((exception, idx) => exception == null ? loadableWithValue$4(results[idx]) : Recoil_isPromise(exception) ? loadableWithPromise$3(exception) : loadableWithError$3(exception));
8884 return wrapResults(dependencies, output);
8885}
8886
8887function combineAsyncResultsWithSyncResults(syncResults, asyncResults) {
8888 return asyncResults.map((result, idx) =>
8889 /**
8890 * it's important we use === undefined as opposed to == null, because the
8891 * resolved value of the async promise could be `null`, in which case we
8892 * don't want to use syncResults[idx], which would be undefined. If async
8893 * promise resolves to `undefined`, that's ok because `syncResults[idx]`
8894 * will also be `undefined`. That's a little hacky, but it works.
8895 */
8896 result === undefined ? syncResults[idx] : result);
8897} // Selector that requests all dependencies in parallel and immediately returns
8898// current results without waiting.
8899
8900
8901const waitForNone = Recoil_selectorFamily({
8902 key: '__waitForNone',
8903 get: dependencies => ({
8904 get
8905 }) => {
8906 // Issue requests for all dependencies in parallel.
8907 const deps = unwrapDependencies(dependencies);
8908 const [results, exceptions] = concurrentRequests(get, deps); // Always return the current status of the results; never block.
8909
8910 return wrapLoadables(dependencies, results, exceptions);
8911 },
8912 dangerouslyAllowMutability: true
8913}); // Selector that requests all dependencies in parallel and waits for at least
8914// one to be available before returning results. It will only error if all
8915// dependencies have errors.
8916
8917const waitForAny = Recoil_selectorFamily({
8918 key: '__waitForAny',
8919 get: dependencies => ({
8920 get
8921 }) => {
8922 // Issue requests for all dependencies in parallel.
8923 // Exceptions can either be Promises of pending results or real errors
8924 const deps = unwrapDependencies(dependencies);
8925 const [results, exceptions] = concurrentRequests(get, deps); // If any results are available, value or error, return the current status
8926
8927 if (exceptions.some(exp => !Recoil_isPromise(exp))) {
8928 return wrapLoadables(dependencies, results, exceptions);
8929 } // Otherwise, return a promise that will resolve when the next result is
8930 // available, whichever one happens to be next. But, if all pending
8931 // dependencies end up with errors, then reject the promise.
8932
8933
8934 return new Promise(resolve => {
8935 for (const [i, exp] of exceptions.entries()) {
8936 if (Recoil_isPromise(exp)) {
8937 exp.then(result => {
8938 results[i] = result;
8939 exceptions[i] = undefined;
8940 resolve(wrapLoadables(dependencies, results, exceptions));
8941 }).catch(error => {
8942 exceptions[i] = error;
8943 resolve(wrapLoadables(dependencies, results, exceptions));
8944 });
8945 }
8946 }
8947 });
8948 },
8949 dangerouslyAllowMutability: true
8950}); // Selector that requests all dependencies in parallel and waits for all to be
8951// available before returning a value. It will error if any dependencies error.
8952
8953const waitForAll = Recoil_selectorFamily({
8954 key: '__waitForAll',
8955 get: dependencies => ({
8956 get
8957 }) => {
8958 // Issue requests for all dependencies in parallel.
8959 // Exceptions can either be Promises of pending results or real errors
8960 const deps = unwrapDependencies(dependencies);
8961 const [results, exceptions] = concurrentRequests(get, deps); // If all results are available, return the results
8962
8963 if (exceptions.every(exp => exp == null)) {
8964 return wrapResults(dependencies, results);
8965 } // If we have any errors, throw the first error
8966
8967
8968 const error = exceptions.find(isError);
8969
8970 if (error != null) {
8971 throw error;
8972 } // Otherwise, return a promise that will resolve when all results are available
8973
8974
8975 return Promise.all(exceptions).then(exceptionResults => wrapResults(dependencies, combineAsyncResultsWithSyncResults(results, exceptionResults)));
8976 },
8977 dangerouslyAllowMutability: true
8978});
8979const waitForAllSettled = Recoil_selectorFamily({
8980 key: '__waitForAllSettled',
8981 get: dependencies => ({
8982 get
8983 }) => {
8984 // Issue requests for all dependencies in parallel.
8985 // Exceptions can either be Promises of pending results or real errors
8986 const deps = unwrapDependencies(dependencies);
8987 const [results, exceptions] = concurrentRequests(get, deps); // If all results are available, return the results
8988
8989 if (exceptions.every(exp => !Recoil_isPromise(exp))) {
8990 return wrapLoadables(dependencies, results, exceptions);
8991 } // Wait for all results to settle
8992
8993
8994 return Promise.all(exceptions.map((exp, i) => Recoil_isPromise(exp) ? exp.then(result => {
8995 results[i] = result;
8996 exceptions[i] = undefined;
8997 }).catch(error => {
8998 results[i] = undefined;
8999 exceptions[i] = error;
9000 }) : null)) // Then wrap them as loadables
9001 .then(() => wrapLoadables(dependencies, results, exceptions));
9002 },
9003 dangerouslyAllowMutability: true
9004});
9005const noWait = Recoil_selectorFamily({
9006 key: '__noWait',
9007 get: dependency => ({
9008 get
9009 }) => {
9010 try {
9011 return Recoil_selector.value(loadableWithValue$4(get(dependency)));
9012 } catch (exception) {
9013 return Recoil_selector.value(Recoil_isPromise(exception) ? loadableWithPromise$3(exception) : loadableWithError$3(exception));
9014 }
9015 },
9016 dangerouslyAllowMutability: true
9017});
9018var Recoil_WaitFor = {
9019 waitForNone,
9020 waitForAny,
9021 waitForAll,
9022 waitForAllSettled,
9023 noWait
9024};
9025
9026const {
9027 RecoilLoadable
9028} = Recoil_Loadable$1;
9029
9030const {
9031 DefaultValue: DefaultValue$3
9032} = Recoil_Node;
9033
9034const {
9035 RecoilRoot: RecoilRoot$2,
9036 useRecoilStoreID: useRecoilStoreID$1
9037} = Recoil_RecoilRoot;
9038
9039const {
9040 isRecoilValue: isRecoilValue$5
9041} = Recoil_RecoilValue$1;
9042
9043const {
9044 retentionZone: retentionZone$1
9045} = Recoil_RetentionZone;
9046
9047const {
9048 freshSnapshot: freshSnapshot$2
9049} = Recoil_Snapshot$1;
9050
9051const {
9052 useRecoilState: useRecoilState$1,
9053 useRecoilState_TRANSITION_SUPPORT_UNSTABLE: useRecoilState_TRANSITION_SUPPORT_UNSTABLE$1,
9054 useRecoilStateLoadable: useRecoilStateLoadable$1,
9055 useRecoilValue: useRecoilValue$1,
9056 useRecoilValue_TRANSITION_SUPPORT_UNSTABLE: useRecoilValue_TRANSITION_SUPPORT_UNSTABLE$1,
9057 useRecoilValueLoadable: useRecoilValueLoadable$1,
9058 useRecoilValueLoadable_TRANSITION_SUPPORT_UNSTABLE: useRecoilValueLoadable_TRANSITION_SUPPORT_UNSTABLE$1,
9059 useResetRecoilState: useResetRecoilState$1,
9060 useSetRecoilState: useSetRecoilState$1
9061} = Recoil_Hooks;
9062
9063const {
9064 useGotoRecoilSnapshot: useGotoRecoilSnapshot$1,
9065 useRecoilSnapshot: useRecoilSnapshot$1,
9066 useRecoilTransactionObserver: useRecoilTransactionObserver$1
9067} = Recoil_SnapshotHooks;
9068
9069
9070
9071
9072
9073const {
9074 useRecoilCallback: useRecoilCallback$1
9075} = Recoil_useRecoilCallback;
9076
9077
9078
9079
9080
9081
9082
9083
9084
9085
9086
9087
9088
9089
9090
9091
9092
9093
9094
9095
9096
9097const {
9098 noWait: noWait$1,
9099 waitForAll: waitForAll$1,
9100 waitForAllSettled: waitForAllSettled$1,
9101 waitForAny: waitForAny$1,
9102 waitForNone: waitForNone$1
9103} = Recoil_WaitFor;
9104
9105
9106
9107var Recoil_index = {
9108 // Types
9109 DefaultValue: DefaultValue$3,
9110 isRecoilValue: isRecoilValue$5,
9111 RecoilLoadable,
9112 // Global Recoil environment settiongs
9113 RecoilEnv: Recoil_RecoilEnv,
9114 // Recoil Root
9115 RecoilRoot: RecoilRoot$2,
9116 useRecoilStoreID: useRecoilStoreID$1,
9117 useRecoilBridgeAcrossReactRoots_UNSTABLE: Recoil_useRecoilBridgeAcrossReactRoots,
9118 // Atoms/Selectors
9119 atom: Recoil_atom,
9120 selector: Recoil_selector,
9121 // Convenience Atoms/Selectors
9122 atomFamily: Recoil_atomFamily,
9123 selectorFamily: Recoil_selectorFamily,
9124 constSelector: Recoil_constSelector,
9125 errorSelector: Recoil_errorSelector,
9126 readOnlySelector: Recoil_readOnlySelector,
9127 // Concurrency Helpers for Atoms/Selectors
9128 noWait: noWait$1,
9129 waitForNone: waitForNone$1,
9130 waitForAny: waitForAny$1,
9131 waitForAll: waitForAll$1,
9132 waitForAllSettled: waitForAllSettled$1,
9133 // Hooks for Atoms/Selectors
9134 useRecoilValue: useRecoilValue$1,
9135 useRecoilValueLoadable: useRecoilValueLoadable$1,
9136 useRecoilState: useRecoilState$1,
9137 useRecoilStateLoadable: useRecoilStateLoadable$1,
9138 useSetRecoilState: useSetRecoilState$1,
9139 useResetRecoilState: useResetRecoilState$1,
9140 useGetRecoilValueInfo_UNSTABLE: Recoil_useGetRecoilValueInfo,
9141 useRecoilRefresher_UNSTABLE: Recoil_useRecoilRefresher,
9142 useRecoilValueLoadable_TRANSITION_SUPPORT_UNSTABLE: useRecoilValueLoadable_TRANSITION_SUPPORT_UNSTABLE$1,
9143 useRecoilValue_TRANSITION_SUPPORT_UNSTABLE: useRecoilValue_TRANSITION_SUPPORT_UNSTABLE$1,
9144 useRecoilState_TRANSITION_SUPPORT_UNSTABLE: useRecoilState_TRANSITION_SUPPORT_UNSTABLE$1,
9145 // Hooks for complex operations
9146 useRecoilCallback: useRecoilCallback$1,
9147 useRecoilTransaction_UNSTABLE: Recoil_useRecoilTransaction,
9148 // Snapshots
9149 useGotoRecoilSnapshot: useGotoRecoilSnapshot$1,
9150 useRecoilSnapshot: useRecoilSnapshot$1,
9151 useRecoilTransactionObserver_UNSTABLE: useRecoilTransactionObserver$1,
9152 snapshot_UNSTABLE: freshSnapshot$2,
9153 // Memory Management
9154 useRetain: Recoil_useRetain,
9155 retentionZone: retentionZone$1
9156};
9157var Recoil_index_1 = Recoil_index.DefaultValue;
9158var Recoil_index_2 = Recoil_index.isRecoilValue;
9159var Recoil_index_3 = Recoil_index.RecoilLoadable;
9160var Recoil_index_4 = Recoil_index.RecoilEnv;
9161var Recoil_index_5 = Recoil_index.RecoilRoot;
9162var Recoil_index_6 = Recoil_index.useRecoilStoreID;
9163var Recoil_index_7 = Recoil_index.useRecoilBridgeAcrossReactRoots_UNSTABLE;
9164var Recoil_index_8 = Recoil_index.atom;
9165var Recoil_index_9 = Recoil_index.selector;
9166var Recoil_index_10 = Recoil_index.atomFamily;
9167var Recoil_index_11 = Recoil_index.selectorFamily;
9168var Recoil_index_12 = Recoil_index.constSelector;
9169var Recoil_index_13 = Recoil_index.errorSelector;
9170var Recoil_index_14 = Recoil_index.readOnlySelector;
9171var Recoil_index_15 = Recoil_index.noWait;
9172var Recoil_index_16 = Recoil_index.waitForNone;
9173var Recoil_index_17 = Recoil_index.waitForAny;
9174var Recoil_index_18 = Recoil_index.waitForAll;
9175var Recoil_index_19 = Recoil_index.waitForAllSettled;
9176var Recoil_index_20 = Recoil_index.useRecoilValue;
9177var Recoil_index_21 = Recoil_index.useRecoilValueLoadable;
9178var Recoil_index_22 = Recoil_index.useRecoilState;
9179var Recoil_index_23 = Recoil_index.useRecoilStateLoadable;
9180var Recoil_index_24 = Recoil_index.useSetRecoilState;
9181var Recoil_index_25 = Recoil_index.useResetRecoilState;
9182var Recoil_index_26 = Recoil_index.useGetRecoilValueInfo_UNSTABLE;
9183var Recoil_index_27 = Recoil_index.useRecoilRefresher_UNSTABLE;
9184var Recoil_index_28 = Recoil_index.useRecoilValueLoadable_TRANSITION_SUPPORT_UNSTABLE;
9185var Recoil_index_29 = Recoil_index.useRecoilValue_TRANSITION_SUPPORT_UNSTABLE;
9186var Recoil_index_30 = Recoil_index.useRecoilState_TRANSITION_SUPPORT_UNSTABLE;
9187var Recoil_index_31 = Recoil_index.useRecoilCallback;
9188var Recoil_index_32 = Recoil_index.useRecoilTransaction_UNSTABLE;
9189var Recoil_index_33 = Recoil_index.useGotoRecoilSnapshot;
9190var Recoil_index_34 = Recoil_index.useRecoilSnapshot;
9191var Recoil_index_35 = Recoil_index.useRecoilTransactionObserver_UNSTABLE;
9192var Recoil_index_36 = Recoil_index.snapshot_UNSTABLE;
9193var Recoil_index_37 = Recoil_index.useRetain;
9194var Recoil_index_38 = Recoil_index.retentionZone;
9195
9196exports.DefaultValue = Recoil_index_1;
9197exports.RecoilEnv = Recoil_index_4;
9198exports.RecoilLoadable = Recoil_index_3;
9199exports.RecoilRoot = Recoil_index_5;
9200exports.atom = Recoil_index_8;
9201exports.atomFamily = Recoil_index_10;
9202exports.constSelector = Recoil_index_12;
9203exports.default = Recoil_index;
9204exports.errorSelector = Recoil_index_13;
9205exports.isRecoilValue = Recoil_index_2;
9206exports.noWait = Recoil_index_15;
9207exports.readOnlySelector = Recoil_index_14;
9208exports.retentionZone = Recoil_index_38;
9209exports.selector = Recoil_index_9;
9210exports.selectorFamily = Recoil_index_11;
9211exports.snapshot_UNSTABLE = Recoil_index_36;
9212exports.useGetRecoilValueInfo_UNSTABLE = Recoil_index_26;
9213exports.useGotoRecoilSnapshot = Recoil_index_33;
9214exports.useRecoilBridgeAcrossReactRoots_UNSTABLE = Recoil_index_7;
9215exports.useRecoilCallback = Recoil_index_31;
9216exports.useRecoilRefresher_UNSTABLE = Recoil_index_27;
9217exports.useRecoilSnapshot = Recoil_index_34;
9218exports.useRecoilState = Recoil_index_22;
9219exports.useRecoilStateLoadable = Recoil_index_23;
9220exports.useRecoilState_TRANSITION_SUPPORT_UNSTABLE = Recoil_index_30;
9221exports.useRecoilStoreID = Recoil_index_6;
9222exports.useRecoilTransactionObserver_UNSTABLE = Recoil_index_35;
9223exports.useRecoilTransaction_UNSTABLE = Recoil_index_32;
9224exports.useRecoilValue = Recoil_index_20;
9225exports.useRecoilValueLoadable = Recoil_index_21;
9226exports.useRecoilValueLoadable_TRANSITION_SUPPORT_UNSTABLE = Recoil_index_28;
9227exports.useRecoilValue_TRANSITION_SUPPORT_UNSTABLE = Recoil_index_29;
9228exports.useResetRecoilState = Recoil_index_25;
9229exports.useRetain = Recoil_index_37;
9230exports.useSetRecoilState = Recoil_index_24;
9231exports.waitForAll = Recoil_index_18;
9232exports.waitForAllSettled = Recoil_index_19;
9233exports.waitForAny = Recoil_index_17;
9234exports.waitForNone = Recoil_index_16;