valdres 0.2.0-y.0 → 1.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/dist/index.js +1869 -515
  2. package/dist/types/atomFamily.d.ts +3 -0
  3. package/dist/types/cacheMeta.d.ts +4 -0
  4. package/dist/types/errors/SelectorCircularDependencyError.d.ts +5 -0
  5. package/dist/types/errors/SelectorEvaluationError.d.ts +7 -0
  6. package/dist/types/errors/lib/generateSelectorTrace.d.ts +2 -0
  7. package/dist/types/{src/index.d.ts → index.d.ts} +8 -2
  8. package/dist/types/indexConstructor.d.ts +5 -0
  9. package/dist/types/lib/asyncDependencyTracking.d.ts +25 -0
  10. package/dist/types/lib/atomFamilyIndex.d.ts +17 -0
  11. package/dist/types/lib/createAtomFamily.d.ts +4 -0
  12. package/dist/types/lib/createGlobalAtomFamily.d.ts +4 -0
  13. package/dist/types/{src/lib → lib}/createStoreData.d.ts +5 -2
  14. package/dist/types/lib/deleteFamilyAtom.d.ts +3 -0
  15. package/dist/types/lib/equal.d.ts +1 -0
  16. package/dist/types/lib/familyKey.d.ts +2 -0
  17. package/dist/types/lib/getState.d.ts +8 -0
  18. package/dist/types/lib/initAtom.d.ts +5 -0
  19. package/dist/types/lib/initSelector.d.ts +24 -0
  20. package/dist/types/lib/isFunction.d.ts +1 -0
  21. package/dist/types/lib/isProd.d.ts +1 -0
  22. package/dist/types/lib/maxAgeCleanups.d.ts +4 -0
  23. package/dist/types/lib/mountAtom.d.ts +36 -0
  24. package/dist/types/lib/propagateUpdatedAtoms.d.ts +11 -0
  25. package/dist/types/{src/lib → lib}/setAtom.d.ts +2 -1
  26. package/dist/types/{src/lib → lib}/setAtoms.d.ts +1 -1
  27. package/dist/types/lib/setValueInData.d.ts +7 -0
  28. package/dist/types/lib/stringifyFamilyArgs.d.ts +1 -0
  29. package/dist/types/{src/lib → lib}/subscribe.d.ts +2 -0
  30. package/dist/types/lib/transaction.d.ts +37 -0
  31. package/dist/types/{src/lib → lib}/unsubscribe.d.ts +1 -1
  32. package/dist/types/selector.d.ts +4 -0
  33. package/dist/types/selectorFamily.d.ts +4 -0
  34. package/dist/types/store.d.ts +6 -0
  35. package/dist/types/types/Atom.d.ts +29 -0
  36. package/dist/types/types/AtomFamily.d.ts +11 -0
  37. package/dist/types/types/AtomFamilyAtom.d.ts +7 -0
  38. package/dist/types/types/AtomFamilyDefaultValue.d.ts +5 -0
  39. package/dist/types/types/AtomFamilySelector.d.ts +6 -0
  40. package/dist/types/types/AtomOnInit.d.ts +9 -0
  41. package/dist/types/types/AtomOnMount.d.ts +14 -0
  42. package/dist/types/types/AtomOptions.d.ts +15 -0
  43. package/dist/types/types/EqualFunc.d.ts +3 -0
  44. package/dist/types/types/Family.d.ts +3 -0
  45. package/dist/types/types/GetValue.d.ts +9 -0
  46. package/dist/types/{src/types → types}/GlobalAtom.d.ts +6 -0
  47. package/dist/types/types/GlobalAtomSetSelfFunc.d.ts +2 -0
  48. package/dist/types/types/Reactive.d.ts +3 -0
  49. package/dist/types/types/Selector.d.ts +16 -0
  50. package/dist/types/types/SelectorFamily.d.ts +7 -0
  51. package/dist/types/{src/types → types}/SelectorOptions.d.ts +1 -1
  52. package/dist/types/types/SetAtomValue.d.ts +1 -0
  53. package/dist/types/types/State.d.ts +4 -0
  54. package/dist/types/types/Store.d.ts +31 -0
  55. package/dist/types/types/StoreData.d.ts +28 -0
  56. package/dist/types/types/SubscribeFn.d.ts +9 -0
  57. package/dist/types/types/Subscription.d.ts +11 -0
  58. package/dist/types/types/TransactionFn.d.ts +2 -0
  59. package/dist/types/{src/types → types}/TransactionInterface.d.ts +2 -0
  60. package/dist/types/utils/deepFreeze.d.ts +1 -0
  61. package/dist/types/utils/isAtomFamily.d.ts +2 -0
  62. package/dist/types/utils/isFamily.d.ts +1 -0
  63. package/dist/types/utils/isFamilyAtom.d.ts +2 -0
  64. package/dist/types/utils/isFamilySelector.d.ts +2 -0
  65. package/dist/types/utils/isFamilyState.d.ts +3 -0
  66. package/dist/types/utils/isGlobalAtom.d.ts +2 -0
  67. package/dist/types/utils/isSelectorFamily.d.ts +2 -0
  68. package/dist/types/utils/resolveReactive.d.ts +4 -0
  69. package/package.json +7 -19
  70. package/dist/types/src/atomFamily.d.ts +0 -4
  71. package/dist/types/src/createStoreWithSelectorSet.d.ts +0 -2
  72. package/dist/types/src/lib/atomFamilyAtom.d.ts +0 -8
  73. package/dist/types/src/lib/createAtomFamily.d.ts +0 -4
  74. package/dist/types/src/lib/createGlobalAtomFamily.d.ts +0 -5
  75. package/dist/types/src/lib/equal.d.ts +0 -1
  76. package/dist/types/src/lib/getState.d.ts +0 -7
  77. package/dist/types/src/lib/initAtom.d.ts +0 -5
  78. package/dist/types/src/lib/initSelector.d.ts +0 -3
  79. package/dist/types/src/lib/isFunction.d.ts +0 -1
  80. package/dist/types/src/lib/propagateUpdatedAtoms.d.ts +0 -4
  81. package/dist/types/src/lib/transaction.d.ts +0 -3
  82. package/dist/types/src/lib/updateSelectorSubscribers.d.ts +0 -3
  83. package/dist/types/src/lib/updateStateSubscribers.d.ts +0 -3
  84. package/dist/types/src/selector.d.ts +0 -4
  85. package/dist/types/src/selectorFamily.d.ts +0 -4
  86. package/dist/types/src/store.d.ts +0 -1
  87. package/dist/types/src/types/Atom.d.ts +0 -14
  88. package/dist/types/src/types/AtomFamily.d.ts +0 -12
  89. package/dist/types/src/types/AtomFamilyAtom.d.ts +0 -6
  90. package/dist/types/src/types/AtomFamilyDefaultValue.d.ts +0 -5
  91. package/dist/types/src/types/AtomFamilyGlobalAtom.d.ts +0 -3
  92. package/dist/types/src/types/AtomFamilySelector.d.ts +0 -6
  93. package/dist/types/src/types/AtomOnInit.d.ts +0 -2
  94. package/dist/types/src/types/AtomOptions.d.ts +0 -13
  95. package/dist/types/src/types/EqualFunc.d.ts +0 -1
  96. package/dist/types/src/types/Family.d.ts +0 -3
  97. package/dist/types/src/types/GetValue.d.ts +0 -8
  98. package/dist/types/src/types/GlobalAtomSetSelfFunc.d.ts +0 -1
  99. package/dist/types/src/types/Selector.d.ts +0 -11
  100. package/dist/types/src/types/SelectorFamily.d.ts +0 -6
  101. package/dist/types/src/types/SetAtomValue.d.ts +0 -1
  102. package/dist/types/src/types/State.d.ts +0 -4
  103. package/dist/types/src/types/Store.d.ts +0 -24
  104. package/dist/types/src/types/StoreData.d.ts +0 -17
  105. package/dist/types/src/types/SubscribeFn.d.ts +0 -9
  106. package/dist/types/src/types/Subscription.d.ts +0 -1
  107. package/dist/types/src/types/TransactionFn.d.ts +0 -2
  108. package/dist/types/src/utils/isAtomFamily.d.ts +0 -2
  109. package/dist/types/src/utils/isFamily.d.ts +0 -1
  110. package/dist/types/src/utils/isFamilyAtom.d.ts +0 -2
  111. package/dist/types/src/utils/isFamilySelector.d.ts +0 -2
  112. package/dist/types/src/utils/isFamilyState.d.ts +0 -3
  113. package/dist/types/src/utils/isSelectorFamily.d.ts +0 -2
  114. /package/dist/types/{src/atom.d.ts → atom.d.ts} +0 -0
  115. /package/dist/types/{src/globalStore.d.ts → globalStore.d.ts} +0 -0
  116. /package/dist/types/{src/lib → lib}/globalAtom.d.ts +0 -0
  117. /package/dist/types/{src/lib → lib}/resetAtom.d.ts +0 -0
  118. /package/dist/types/{src/lib → lib}/stableStringify.d.ts +0 -0
  119. /package/dist/types/{src/lib → lib}/storeFromStoreData.d.ts +0 -0
  120. /package/dist/types/{src/types → types}/AtomDefaultValue.d.ts +0 -0
  121. /package/dist/types/{src/types → types}/AtomOnSet.d.ts +0 -0
  122. /package/dist/types/{src/types → types}/FamilyKey.d.ts +0 -0
  123. /package/dist/types/{src/types → types}/GlobalAtomGetSelfFunc.d.ts +0 -0
  124. /package/dist/types/{src/types → types}/GlobalAtomResetSelfFunc.d.ts +0 -0
  125. /package/dist/types/{src/types → types}/ResetAtom.d.ts +0 -0
  126. /package/dist/types/{src/types → types}/SetAtom.d.ts +0 -0
  127. /package/dist/types/{src/utils → utils}/isAtom.d.ts +0 -0
  128. /package/dist/types/{src/utils → utils}/isPromiseLike.d.ts +0 -0
  129. /package/dist/types/{src/utils → utils}/isSelector.d.ts +0 -0
package/dist/index.js CHANGED
@@ -1,12 +1,13 @@
1
- // src/index.ts
2
- import { version } from "../package.json";
3
-
4
1
  // src/lib/equal.ts
5
2
  var hasElementType = typeof Element !== "undefined";
6
3
  var hasMap = typeof Map === "function";
7
4
  var hasSet = typeof Set === "function";
8
5
  var hasArrayBuffer = typeof ArrayBuffer === "function" && !!ArrayBuffer.isView;
9
- var deepEqualFn = (a, b) => {
6
+ var deepEqualFn = (a, b, updatedAtomsSet) => {
7
+ if (updatedAtomsSet) {
8
+ if (updatedAtomsSet.has(a) || updatedAtomsSet.has(b))
9
+ return false;
10
+ }
10
11
  if (a === b)
11
12
  return true;
12
13
  if (a && b && typeof a == "object" && typeof b == "object") {
@@ -18,7 +19,7 @@ var deepEqualFn = (a, b) => {
18
19
  if (length != b.length)
19
20
  return false;
20
21
  for (i = length;i-- !== 0; )
21
- if (!deepEqualFn(a[i], b[i]))
22
+ if (!deepEqualFn(a[i], b[i], updatedAtomsSet))
22
23
  return false;
23
24
  return true;
24
25
  }
@@ -32,7 +33,7 @@ var deepEqualFn = (a, b) => {
32
33
  return false;
33
34
  it = a.entries();
34
35
  while (!(i = it.next()).done)
35
- if (!deepEqualFn(i.value[1], b.get(i.value[0])))
36
+ if (!deepEqualFn(i.value[1], b.get(i.value[0]), updatedAtomsSet))
36
37
  return false;
37
38
  return true;
38
39
  }
@@ -40,9 +41,12 @@ var deepEqualFn = (a, b) => {
40
41
  if (a.size !== b.size)
41
42
  return false;
42
43
  it = a.entries();
43
- while (!(i = it.next()).done)
44
+ while (!(i = it.next()).done) {
44
45
  if (!b.has(i.value[0]))
45
46
  return false;
47
+ if (updatedAtomsSet?.has(i.value[0]))
48
+ return false;
49
+ }
46
50
  return true;
47
51
  }
48
52
  if (hasArrayBuffer && ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {
@@ -73,16 +77,16 @@ var deepEqualFn = (a, b) => {
73
77
  if ((keys[i] === "_owner" || keys[i] === "__v" || keys[i] === "__o") && a.$$typeof) {
74
78
  continue;
75
79
  }
76
- if (!deepEqualFn(a[keys[i]], b[keys[i]]))
80
+ if (!deepEqualFn(a[keys[i]], b[keys[i]], updatedAtomsSet))
77
81
  return false;
78
82
  }
79
83
  return true;
80
84
  }
81
85
  return a !== a && b !== b;
82
86
  };
83
- var equal = (a, b) => {
87
+ var equal = (a, b, updatedAtomsSet) => {
84
88
  try {
85
- return deepEqualFn(a, b);
89
+ return deepEqualFn(a, b, updatedAtomsSet);
86
90
  } catch (error) {
87
91
  if ((error.message || "").match(/stack|recursion/i)) {
88
92
  console.warn("react-fast-compare cannot handle circular refs");
@@ -95,154 +99,203 @@ var equal = (a, b) => {
95
99
  // src/utils/isAtom.ts
96
100
  var isAtom = (state) => Object.hasOwn(state, "defaultValue");
97
101
 
102
+ // src/utils/isGlobalAtom.ts
103
+ var isGlobalAtom = (state) => Object.hasOwn(state, "stores");
104
+
105
+ // src/utils/isSelector.ts
106
+ var isSelector = (state) => state && Object.hasOwn(state, "get");
107
+
108
+ // src/utils/isAtomFamily.ts
109
+ var isAtomFamily = (state) => state && Object.hasOwn(state, "__valdresAtomFamilyMap");
110
+
98
111
  // src/utils/isFamilyState.ts
99
112
  var isFamilyState = (state) => state && Object.hasOwn(state, "family");
100
113
 
101
114
  // src/utils/isFamilyAtom.ts
102
115
  var isFamilyAtom = (state) => isFamilyState(state) && isAtom(state);
103
116
 
104
- // src/lib/updateStateSubscribers.ts
105
- var updateStateSubscribers = (state, data) => {
106
- const subscribtions = data.subscriptions.get(state);
107
- if (subscribtions?.size) {
108
- for (const subscribtion of subscribtions) {
109
- subscribtion.callback();
110
- }
111
- }
112
- if (isFamilyState(state)) {
113
- const familySubscriptions = data.subscriptions.get(state.family);
114
- if (familySubscriptions?.size) {
115
- for (const subscribtion of familySubscriptions) {
116
- subscribtion.callback(state.familyKey);
117
- }
118
- }
119
- }
120
- };
117
+ // src/utils/isSelectorFamily.ts
118
+ var isSelectorFamily = (state) => state && Object.hasOwn(state, "__valdresSelectorFamilyMap");
121
119
 
122
120
  // src/utils/isPromiseLike.ts
123
121
  var isPromiseLike = (object) => {
124
122
  return object && object.then && typeof object.then === "function";
125
123
  };
126
124
 
127
- // src/utils/isAtomFamily.ts
128
- var isAtomFamily = (state) => state && Object.hasOwn(state, "__valdresAtomFamilyMap");
129
-
130
- // src/utils/isSelector.ts
131
- var isSelector = (state) => state && Object.hasOwn(state, "get");
132
-
133
- // src/utils/isSelectorFamily.ts
134
- var isSelectorFamily = (state) => state && Object.hasOwn(state, "__valdresSelectorFamilyMap");
125
+ // src/utils/deepFreeze.ts
126
+ var deepFreeze = (obj, seen = new WeakSet) => {
127
+ if (obj === null || obj === undefined)
128
+ return obj;
129
+ if (typeof obj !== "object" && typeof obj !== "function")
130
+ return obj;
131
+ if (seen.has(obj) || Object.isFrozen(obj))
132
+ return obj;
133
+ seen.add(obj);
134
+ if (Array.isArray(obj)) {
135
+ for (const item of obj) {
136
+ if (item && typeof item === "object") {
137
+ deepFreeze(item, seen);
138
+ }
139
+ }
140
+ } else {
141
+ const propNames = Object.getOwnPropertyNames(obj);
142
+ for (const name of propNames) {
143
+ const value = obj[name];
144
+ if (value && typeof value === "object") {
145
+ deepFreeze(value, seen);
146
+ }
147
+ }
148
+ }
149
+ return Object.freeze(obj);
150
+ };
135
151
 
136
- // src/lib/isFunction.ts
137
- var isFunction = (value) => typeof value === "function";
152
+ // src/lib/isProd.ts
153
+ var isProd = () => {
154
+ return false;
155
+ };
138
156
 
139
- // src/lib/setAtom.ts
140
- var setAtom = (atom, newValue, data, skipOnSet = false) => {
141
- const currentValue = getState(atom, data);
142
- if (isFunction(newValue)) {
143
- newValue = newValue(currentValue);
144
- if (isPromiseLike(newValue) || isPromiseLike(currentValue))
145
- throw new Error("Todo, how should we handle this?");
157
+ // src/lib/setValueInData.ts
158
+ var trackScopeValue = (key, data) => {
159
+ const parent = data.parent;
160
+ let set = parent.scopeValueIndex.get(key);
161
+ if (!set) {
162
+ set = new Set;
163
+ parent.scopeValueIndex.set(key, set);
146
164
  }
147
- if (atom.equal(currentValue, newValue))
148
- return newValue;
149
- data.values.set(atom, newValue);
150
- if (atom.onSet && !skipOnSet)
151
- atom.onSet(newValue, data);
152
- if (currentValue?.__isEmptyAtomPromise__) {
153
- currentValue.__resolveEmptyAtomPromise__(newValue);
165
+ set.add(data);
166
+ data.scopeIndexKeys.add(key);
167
+ };
168
+ var setValueInData = (atom, value, data) => {
169
+ const isNewAtomInScope = "parent" in data && Object.hasOwn(atom, "defaultValue") && !data.values.has(atom);
170
+ let written;
171
+ if (atom.mutable || isProd()) {
172
+ data.values.set(atom, value);
173
+ written = value;
174
+ } else {
175
+ const frozenValue = value !== null && (typeof value === "object" || typeof value === "function") ? deepFreeze(value) : value;
176
+ data.values.set(atom, frozenValue);
177
+ written = frozenValue;
178
+ }
179
+ if (isNewAtomInScope)
180
+ trackScopeValue(atom, data);
181
+ if (atom.maxAge !== undefined) {
182
+ data.lastValueWriteAt.set(atom, Date.now());
154
183
  }
155
- propagateUpdatedAtoms([atom], data);
156
- return newValue;
184
+ return written;
157
185
  };
158
186
 
159
- // src/lib/initAtom.ts
160
- var getAtomInitValue = (atom, data) => {
161
- if (atom.defaultValue === undefined) {
162
- let promiseResolve;
163
- const promise = new Promise((resolve) => {
164
- promiseResolve = resolve;
165
- });
166
- promise.__isEmptyAtomPromise__ = true;
167
- promise.__resolveEmptyAtomPromise__ = promiseResolve;
168
- return promise;
169
- } else if (typeof atom.defaultValue === "function") {
170
- const value = atom.defaultValue();
171
- if (isPromiseLike(value)) {
172
- value.then((resolvedValue) => {
173
- data.values.set(atom, resolvedValue);
174
- propagateUpdatedAtoms([atom], data);
175
- });
176
- }
177
- return value;
178
- } else if (isSelector(atom.defaultValue)) {
179
- return getState(atom.defaultValue, data);
180
- } else {
181
- return atom.defaultValue;
187
+ // src/lib/atomFamilyIndex.ts
188
+ var getAtomFamilyRenderedMap = (index) => {
189
+ if (index.rendered)
190
+ return index.rendered;
191
+ const result = new Map(index.parentIndex ? getAtomFamilyRenderedMap(index.parentIndex) : undefined);
192
+ for (const [atom, timestamp] of index.created) {
193
+ result.set(atom, timestamp);
194
+ }
195
+ for (const [atom, timestamp] of index.deleted) {
196
+ result.delete(atom);
182
197
  }
198
+ index.rendered = result;
199
+ return result;
183
200
  };
184
- var initAtom = (atom, data) => {
185
- let value = getAtomInitValue(atom, data);
186
- data.values.set(atom, value);
187
- if (isFamilyAtom(atom)) {
188
- const currentKeySet = getState(atom.family.__keysAtom, data);
189
- if (!currentKeySet.has(atom.familyKey)) {
190
- const newSet = new Set(currentKeySet);
191
- newSet.add(atom.familyKey);
192
- setAtom(atom.family.__keysAtom, newSet, data);
193
- }
201
+ var getSortedKeysByValues = (map) => {
202
+ return Array.from(map.entries()).sort((a, b) => a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0).map((entry) => entry[0]);
203
+ };
204
+ var renderAtomFamilyIndex = (index) => {
205
+ if (index.renderedArray) {
206
+ return index.renderedArray;
194
207
  }
195
- if (atom.onInit)
196
- atom.onInit((newVal) => {
197
- value = newVal;
198
- setAtom(atom, newVal, data, true);
199
- }, data);
200
- return value;
208
+ const renderedMap = getAtomFamilyRenderedMap(index);
209
+ const array = getSortedKeysByValues(renderedMap);
210
+ array.__index = index;
211
+ index.renderedArray = array;
212
+ return array;
201
213
  };
202
-
203
- // src/lib/getState.ts
204
- function getState(state, data, circularDependencySet) {
205
- if (data.values.has(state))
206
- return data.values.get(state);
207
- if (isAtom(state)) {
208
- if ("parent" in data)
209
- return getState(state, data.parent, circularDependencySet);
210
- return initAtom(state, data);
214
+ var cloneAtomFamilyIndex = (index, parentIndexOverride) => {
215
+ return {
216
+ created: new Map(index.created),
217
+ deleted: new Map(index.deleted),
218
+ rendered: null,
219
+ renderedArray: null,
220
+ parentIndex: parentIndexOverride || index.parentIndex
221
+ };
222
+ };
223
+ var createAtomFamilyIndex = (parentIndex) => {
224
+ return {
225
+ created: new Map,
226
+ deleted: new Map,
227
+ rendered: null,
228
+ renderedArray: null,
229
+ parentIndex
230
+ };
231
+ };
232
+ var deleteFamilyAtomsFromSet = (family, familyAtoms, data, timestamp) => {
233
+ if (familyAtoms.size === 0)
234
+ return;
235
+ const index = findFamilyIndex(family, data);
236
+ for (const atom of familyAtoms) {
237
+ index.deleted.set(atom, timestamp);
211
238
  }
212
- if (isSelector(state))
213
- return initSelector(state, data, circularDependencySet);
214
- if (isAtomFamily(state)) {
215
- if ("parent" in data) {
216
- const closestData = findClosestStoreWithAtomInitialized(state.__keysAtom, data);
217
- return getState(state.__keysSelector, closestData, circularDependencySet);
218
- }
219
- return getState(state.__keysSelector, data, circularDependencySet);
239
+ index.rendered = null;
240
+ index.renderedArray = null;
241
+ data.values.set(family, renderAtomFamilyIndex(index));
242
+ recursivelyUpdateIndexes(data, family);
243
+ };
244
+ var initFamilyIndex = (family, data) => {
245
+ if (data.values.has(family))
246
+ return data.values.get(family).__index;
247
+ let parentIndex;
248
+ if ("parent" in data) {
249
+ parentIndex = initFamilyIndex(family, data.parent);
250
+ if (!parentIndex)
251
+ throw new Error("Parent index is missing");
220
252
  }
221
- if (isSelectorFamily(state)) {
222
- const array = Array.from(state.__valdresSelectorFamilyMap.keys());
223
- if (equal(array, state._keyArray))
224
- return state._keyArray;
225
- state._keyArray = array;
226
- return array;
253
+ const index = createAtomFamilyIndex(parentIndex);
254
+ data.values.set(family, renderAtomFamilyIndex(index));
255
+ if ("parent" in data) {
256
+ trackScopeValue(family, data);
227
257
  }
228
- throw new Error("Invalid object passed to get");
229
- }
230
- var findClosestStoreWithAtomInitialized = (atom, data) => {
231
- if ("parent" in data === false)
232
- return data;
233
- if (data.values.has(atom))
234
- return data;
235
- return findClosestStoreWithAtomInitialized(atom, data.parent);
258
+ return index;
236
259
  };
237
-
238
- // src/lib/initSelector.ts
239
- class SuspendAndWaitForResolveError extends Error {
240
- promise;
241
- constructor(promise) {
242
- super();
243
- this.promise = promise;
260
+ var findFamilyIndex = (family, data) => {
261
+ if (!data.values.has(family)) {
262
+ initFamilyIndex(family, data);
244
263
  }
245
- }
264
+ const value = data.values.get(family);
265
+ if (!value?.__index) {
266
+ throw new Error("Family index is missing");
267
+ }
268
+ return value.__index;
269
+ };
270
+ var recursivelyUpdateIndexes = (data, family) => {
271
+ const childScopesWithFamily = data.scopeValueIndex.get(family);
272
+ if (!childScopesWithFamily || childScopesWithFamily.size === 0)
273
+ return;
274
+ for (const scopedData of childScopesWithFamily) {
275
+ const index = scopedData.values.get(family).__index;
276
+ index.rendered = null;
277
+ index.renderedArray = null;
278
+ scopedData.values.set(family, renderAtomFamilyIndex(index));
279
+ recursivelyUpdateIndexes(scopedData, family);
280
+ }
281
+ };
282
+ var addFamilyAtomsToSet = (family, familyAtoms, data, timestamp) => {
283
+ if (familyAtoms.size === 0)
284
+ return;
285
+ const index = findFamilyIndex(family, data);
286
+ if (!index)
287
+ throw new Error("index not found");
288
+ for (const atom of familyAtoms) {
289
+ index.created.set(atom, timestamp);
290
+ index.deleted.delete(atom);
291
+ }
292
+ index.rendered = null;
293
+ index.renderedArray = null;
294
+ data.values.set(family, renderAtomFamilyIndex(index));
295
+ recursivelyUpdateIndexes(data, family);
296
+ };
297
+
298
+ // src/errors/lib/generateSelectorTrace.ts
246
299
  var generateSelectorTrace = (selectors) => {
247
300
  const lastIndex = selectors.length - 1;
248
301
  return [...selectors].reverse().map((selector, index) => {
@@ -258,205 +311,844 @@ var generateSelectorTrace = (selectors) => {
258
311
  `);
259
312
  };
260
313
 
261
- class CircularDependencyError extends Error {
314
+ // src/errors/SelectorEvaluationError.ts
315
+ class SelectorEvaluationError extends Error {
262
316
  selectors;
263
- constructor() {
317
+ constructor(cause) {
264
318
  super();
319
+ this.cause = cause;
265
320
  this.selectors = [];
266
321
  }
267
322
  track(selector) {
268
323
  this.selectors.push(selector);
269
324
  }
325
+ get message() {
326
+ const firstSelectorName = this.selectors[0].name ?? "Anonymous Selector";
327
+ return `Selector eval crashed in '${firstSelectorName}'
328
+ ${generateSelectorTrace(this.selectors)}`;
329
+ }
330
+ }
331
+
332
+ // src/errors/SelectorCircularDependencyError.ts
333
+ class SelectorCircularDependencyError extends SelectorEvaluationError {
334
+ constructor() {
335
+ super();
336
+ }
270
337
  get message() {
271
338
  const firstSelectorName = this.selectors[0].name ?? "Anonymous Selector";
272
339
  return `Circular dependency detected in '${firstSelectorName}'
273
340
  ${generateSelectorTrace(this.selectors)}`;
274
341
  }
275
342
  }
276
- var getOrInitConsumersSet = (state, data) => {
277
- const set = data.stateConsumers.get(state);
343
+
344
+ // src/lib/asyncDependencyTracking.ts
345
+ var pendingAsyncDeps = new WeakMap;
346
+ var latestEvalContext = new WeakMap;
347
+
348
+ class SuspendAndWaitForResolveError extends Error {
349
+ promise;
350
+ constructor(promise) {
351
+ super();
352
+ this.promise = promise;
353
+ }
354
+ }
355
+ var isSuspendError = (e) => {
356
+ return e instanceof SuspendAndWaitForResolveError;
357
+ };
358
+ var getOrInitDependentsSet = (state, data) => {
359
+ const set = data.stateDependents.get(state);
278
360
  if (set)
279
361
  return set;
280
362
  const newSet = new Set;
281
- data.stateConsumers.set(state, newSet);
363
+ data.stateDependents.set(state, newSet);
282
364
  return newSet;
283
365
  };
284
- var evaluateSelector = (selector, data, circularDependencyMap = new WeakSet) => {
285
- const updatedDependencies = new Set;
286
- if (circularDependencyMap.has(selector)) {
287
- throw new CircularDependencyError;
366
+ var lateGet = (state, selector, data) => {
367
+ let deps = data.stateDependencies.get(selector);
368
+ if (!deps) {
369
+ deps = new Set;
370
+ data.stateDependencies.set(selector, deps);
371
+ }
372
+ const isNewDep = !deps.has(state);
373
+ if (isNewDep) {
374
+ deps.add(state);
375
+ const dependents = getOrInitDependentsSet(state, data);
376
+ dependents.add(selector);
377
+ }
378
+ const lateInitSet = new Set;
379
+ try {
380
+ return getState(state, data, lateInitSet);
381
+ } finally {
382
+ if (isNewDep && isTransitivelySubscribed(selector, data)) {
383
+ mountTransitiveDeps(state, data);
384
+ }
288
385
  }
289
- circularDependencyMap.add(selector);
386
+ };
387
+ var cleanUpRejectedPromise = (selector, data, promise) => {
388
+ if (data.values.has(selector) && data.values.get(selector) !== promise)
389
+ return;
390
+ data.values.delete(selector);
391
+ };
392
+
393
+ // src/lib/initSelector.ts
394
+ class NeedsInitError {
395
+ selector;
396
+ constructor(selector) {
397
+ this.selector = selector;
398
+ }
399
+ }
400
+ var _evalDepth = 0;
401
+ var _inTrampoline = false;
402
+ var MAX_EVAL_DEPTH = 100;
403
+ var sharedCircularDepSet = new WeakSet;
404
+ var neverAbortedSignal = new AbortController().signal;
405
+ var syncOptionsCache = new WeakMap;
406
+ var evaluateSelector = (selector, data, initializedAtomsSet, circularDependencySet = sharedCircularDepSet, addedDepsOut, removedDepsOut) => {
407
+ const currentDependencies = data.stateDependencies.get(selector);
408
+ const updatedDepsArray = [];
409
+ let depsChanged = false;
410
+ let evaluationComplete = false;
411
+ const prevCtx = latestEvalContext.get(selector);
412
+ if (prevCtx)
413
+ prevCtx.revoked = true;
414
+ const evalCtx = { revoked: false };
415
+ latestEvalContext.set(selector, evalCtx);
416
+ if (circularDependencySet.has(selector)) {
417
+ throw new SelectorCircularDependencyError;
418
+ }
419
+ circularDependencySet.add(selector);
420
+ const prev = data.abortControllers.get(selector);
421
+ let options;
422
+ if (prev === false) {
423
+ let cached = syncOptionsCache.get(data);
424
+ if (!cached) {
425
+ cached = { signal: neverAbortedSignal, storeId: data.id };
426
+ syncOptionsCache.set(data, cached);
427
+ }
428
+ options = cached;
429
+ } else {
430
+ if (prev)
431
+ prev.abort();
432
+ const abortController = new AbortController;
433
+ data.abortControllers.set(selector, abortController);
434
+ options = { signal: abortController.signal, storeId: data.id };
435
+ }
436
+ let allDepsThisEval;
290
437
  let result;
291
438
  try {
292
439
  result = selector.get((state) => {
293
- const value = getState(state, data, circularDependencyMap);
294
- updatedDependencies.add(state);
440
+ if (evaluationComplete) {
441
+ if (!evalCtx.revoked && allDepsThisEval) {
442
+ allDepsThisEval.add(state);
443
+ }
444
+ if (evalCtx.revoked) {
445
+ return getState(state, data, new Set);
446
+ }
447
+ return lateGet(state, selector, data);
448
+ }
449
+ const value = getState(state, data, initializedAtomsSet, circularDependencySet);
450
+ updatedDepsArray.push(state);
451
+ if (!depsChanged && (!currentDependencies || !currentDependencies.has(state))) {
452
+ depsChanged = true;
453
+ }
295
454
  if (isPromiseLike(value))
296
455
  throw new SuspendAndWaitForResolveError(value);
297
456
  return value;
298
- }, data.id);
457
+ }, options);
299
458
  } catch (error) {
459
+ if (error instanceof NeedsInitError) {
460
+ circularDependencySet.delete(selector);
461
+ throw error;
462
+ }
300
463
  if (error instanceof SuspendAndWaitForResolveError) {
301
464
  result = error;
302
- } else {
465
+ } else if (error instanceof SelectorEvaluationError) {
303
466
  throw error;
467
+ } else {
468
+ throw new SelectorEvaluationError(error);
304
469
  }
305
470
  }
306
- const currentDependencies = data.stateDependencies.get(selector) ?? new Set;
307
- const added = updatedDependencies?.difference(currentDependencies);
308
- const removed = currentDependencies?.difference(updatedDependencies);
309
- for (const state of added) {
310
- const set = getOrInitConsumersSet(state, data);
311
- set.add(selector);
471
+ evaluationComplete = true;
472
+ const isAsyncResult = result instanceof SuspendAndWaitForResolveError || isPromiseLike(result);
473
+ if (!isAsyncResult && !depsChanged && currentDependencies && currentDependencies.size !== updatedDepsArray.length) {
474
+ depsChanged = true;
475
+ }
476
+ if (depsChanged || !currentDependencies) {
477
+ const updatedDependencies = new Set(updatedDepsArray);
478
+ if (isAsyncResult && currentDependencies) {
479
+ for (const dep of currentDependencies) {
480
+ updatedDependencies.add(dep);
481
+ }
482
+ }
483
+ const prev2 = currentDependencies ?? new Set;
484
+ for (const state of updatedDependencies) {
485
+ if (!prev2.has(state)) {
486
+ const set = getOrInitDependentsSet(state, data);
487
+ set.add(selector);
488
+ if (addedDepsOut)
489
+ addedDepsOut.add(state);
490
+ }
491
+ }
492
+ if (!isAsyncResult) {
493
+ for (const state of prev2) {
494
+ if (!updatedDependencies.has(state)) {
495
+ const set = getOrInitDependentsSet(state, data);
496
+ set.delete(selector);
497
+ if (removedDepsOut)
498
+ removedDepsOut.add(state);
499
+ }
500
+ }
501
+ }
502
+ data.stateDependencies.set(selector, updatedDependencies);
312
503
  }
313
- for (const state of removed) {
314
- const set = getOrInitConsumersSet(state, data);
315
- set.delete(selector);
504
+ if (isPromiseLike(result)) {
505
+ allDepsThisEval = new Set(updatedDepsArray);
506
+ pendingAsyncDeps.set(result, allDepsThisEval);
316
507
  }
317
- data.stateDependencies.set(selector, updatedDependencies);
508
+ circularDependencySet.delete(selector);
318
509
  return result;
319
510
  };
320
511
  var handleSelectorResult = (value, selector, data) => {
321
512
  if (value instanceof SuspendAndWaitForResolveError) {
322
- value.promise.then(() => initSelector(selector, data));
323
- return value.promise;
513
+ data.abortControllers.delete(selector);
514
+ const promise = value.promise;
515
+ promise.then(() => {
516
+ if (!data.stateDependencies.has(selector))
517
+ return;
518
+ if (data.values.has(selector) && data.values.get(selector) !== promise)
519
+ return;
520
+ const initializedAtomsSet = new Set;
521
+ const res = initSelector(selector, data, initializedAtomsSet);
522
+ if (initializedAtomsSet.size > 0) {
523
+ propagateUpdatedAtoms([...initializedAtomsSet], data);
524
+ }
525
+ return res;
526
+ }).catch(() => {
527
+ cleanUpRejectedPromise(selector, data, promise);
528
+ });
529
+ return promise;
324
530
  } else if (isPromiseLike(value)) {
325
531
  value.then((resolved) => {
326
- data.values.set(selector, resolved);
327
- updateStateSubscribers(selector, data);
328
- console.log("Should we reEvaluate?");
532
+ if (!data.stateDependencies.has(selector)) {
533
+ pendingAsyncDeps.delete(value);
534
+ return;
535
+ }
536
+ if (data.values.has(selector) && data.values.get(selector) !== value) {
537
+ pendingAsyncDeps.delete(value);
538
+ return;
539
+ }
540
+ const evalDeps = pendingAsyncDeps.get(value);
541
+ if (evalDeps) {
542
+ pendingAsyncDeps.delete(value);
543
+ const currentDeps = data.stateDependencies.get(selector);
544
+ if (currentDeps) {
545
+ for (const dep of currentDeps) {
546
+ if (!evalDeps.has(dep)) {
547
+ currentDeps.delete(dep);
548
+ const dependents2 = data.stateDependents.get(dep);
549
+ if (dependents2)
550
+ dependents2.delete(selector);
551
+ unmountOrphanedDeps(dep, data);
552
+ }
553
+ }
554
+ }
555
+ }
556
+ setValueInData(selector, resolved, data);
557
+ const dependents = data.stateDependents.get(selector);
558
+ const subs = data.subscriptions.get(selector);
559
+ if (subs && subs.size > 0 || dependents && dependents.size > 0) {
560
+ propagateDirtySelectors([], new Set(dependents), data, new Set(subs), new Map);
561
+ }
562
+ }).catch(() => {
563
+ pendingAsyncDeps.delete(value);
564
+ cleanUpRejectedPromise(selector, data, value);
329
565
  });
330
566
  return value;
331
567
  } else {
568
+ data.abortControllers.set(selector, false);
332
569
  return value;
333
570
  }
334
571
  };
335
- var initSelector = (selector, data, circularDependencySet = new WeakSet) => {
572
+ var initSelectorDirect = (selector, data, initializedAtomsSet, circularDependencySet) => {
573
+ const existingValue = data.values.get(selector);
574
+ const updatedValue = evaluate(selector, data, initializedAtomsSet, circularDependencySet);
575
+ const areEqual = isPromiseLike(existingValue) || isPromiseLike(updatedValue) ? existingValue === updatedValue : selector.equal(existingValue, updatedValue);
576
+ if (areEqual) {
577
+ return false;
578
+ } else {
579
+ setValueInData(selector, updatedValue, data);
580
+ return true;
581
+ }
582
+ };
583
+ var initSelectorTrampoline = (selector, data, initializedAtomsSet, circularDependencySet) => {
584
+ const stack = [selector];
585
+ const inStack = new Set([selector]);
586
+ while (stack.length > 0) {
587
+ const current = stack[stack.length - 1];
588
+ if (data.values.has(current)) {
589
+ stack.pop();
590
+ inStack.delete(current);
591
+ continue;
592
+ }
593
+ try {
594
+ initSelectorDirect(current, data, initializedAtomsSet, circularDependencySet);
595
+ stack.pop();
596
+ inStack.delete(current);
597
+ } catch (e) {
598
+ if (e instanceof NeedsInitError) {
599
+ if (inStack.has(e.selector)) {
600
+ throw new SelectorCircularDependencyError;
601
+ }
602
+ stack.push(e.selector);
603
+ inStack.add(e.selector);
604
+ } else {
605
+ throw e;
606
+ }
607
+ }
608
+ }
609
+ };
610
+ var initSelector = (selector, data, initializedAtomsSet, circularDependencySet = sharedCircularDepSet) => {
611
+ const isTopLevel = _evalDepth === 0 && !_inTrampoline;
612
+ _evalDepth++;
613
+ const existingValue = data.values.get(selector);
614
+ try {
615
+ return initSelectorDirect(selector, data, initializedAtomsSet, circularDependencySet);
616
+ } catch (e) {
617
+ if (e instanceof NeedsInitError && isTopLevel) {
618
+ _inTrampoline = true;
619
+ try {
620
+ initSelectorTrampoline(selector, data, initializedAtomsSet, circularDependencySet);
621
+ } finally {
622
+ _inTrampoline = false;
623
+ }
624
+ const newValue = data.values.get(selector);
625
+ const areEqual = isPromiseLike(existingValue) || isPromiseLike(newValue) ? existingValue === newValue : selector.equal(existingValue, newValue);
626
+ return !areEqual;
627
+ }
628
+ throw e;
629
+ } finally {
630
+ _evalDepth--;
631
+ }
632
+ };
633
+ var evaluate = (selector, data, initializedAtomsSet, circularDependencySet) => {
336
634
  let tmpValue;
337
635
  try {
338
- tmpValue = evaluateSelector(selector, data, circularDependencySet);
636
+ tmpValue = evaluateSelector(selector, data, initializedAtomsSet, circularDependencySet);
339
637
  } catch (e) {
340
- if (e instanceof CircularDependencyError)
638
+ if (e instanceof SelectorEvaluationError)
341
639
  e.track(selector);
342
640
  throw e;
343
641
  }
344
- const value = handleSelectorResult(tmpValue, selector, data);
345
- if (data.expiredValues.has(selector)) {
346
- const expiredValue = data.expiredValues.get(selector);
347
- if (selector.equal(expiredValue, value)) {
348
- data.values.set(selector, expiredValue);
349
- return expiredValue;
642
+ return handleSelectorResult(tmpValue, selector, data);
643
+ };
644
+
645
+ // src/lib/propagateUpdatedAtoms.ts
646
+ var reEvaluteSelector = (selector, data, updatedAtoms) => {
647
+ const existingValue = data.values.get(selector);
648
+ const addedDeps = new Set;
649
+ const removedDeps = new Set;
650
+ try {
651
+ const rawValue = evaluateSelector(selector, data, updatedAtoms, undefined, addedDeps, removedDeps);
652
+ const udpatedValue = handleSelectorResult(rawValue, selector, data);
653
+ const areEqual = isPromiseLike(existingValue) || isPromiseLike(udpatedValue) ? existingValue === udpatedValue : selector.equal(existingValue, udpatedValue, updatedAtoms);
654
+ if (areEqual) {
655
+ return [false, false, undefined, addedDeps, removedDeps];
656
+ } else {
657
+ setValueInData(selector, udpatedValue, data);
658
+ return [true, false, undefined, addedDeps, removedDeps];
350
659
  }
660
+ } catch (error) {
661
+ data.values.delete(selector);
662
+ return [true, true, error, addedDeps, removedDeps];
351
663
  }
352
- data.values.set(selector, value);
353
- return value;
354
664
  };
355
-
356
- // src/lib/updateSelectorSubscribers.ts
357
- var updateSelectorSubscribers = (selector, data) => {
358
- const subscribtions = data.subscriptions.get(selector);
359
- const familySubscriptions = selector.family && data.subscriptions.get(selector.family);
360
- if (!subscribtions?.size && !familySubscriptions?.size)
361
- return;
362
- if (subscribtions?.size && data.subscriptionsRequireEqualCheck.get(selector) || familySubscriptions?.size && selector.family && data.subscriptionsRequireEqualCheck.get(selector.family)) {
363
- try {
364
- const oldValue = data.expiredValues.get(selector);
365
- const newValue = initSelector(selector, data);
366
- if (selector.equal(newValue, oldValue))
665
+ var callSubscribers = (subscriptions, families) => {
666
+ let firstError;
667
+ let hasError = false;
668
+ for (const subscription of subscriptions) {
669
+ if ("state" in subscription) {
670
+ const updatedFamilyAtoms = families?.get(subscription.state);
671
+ if (updatedFamilyAtoms) {
672
+ for (const atom of updatedFamilyAtoms) {
673
+ try {
674
+ subscription.callback(...atom.familyArgs);
675
+ } catch (error) {
676
+ if (!hasError) {
677
+ firstError = error;
678
+ hasError = true;
679
+ }
680
+ }
681
+ }
682
+ }
683
+ } else {
684
+ try {
685
+ subscription.callback();
686
+ } catch (error) {
687
+ if (!hasError) {
688
+ firstError = error;
689
+ hasError = true;
690
+ }
691
+ }
692
+ }
693
+ }
694
+ if (hasError)
695
+ throw firstError;
696
+ };
697
+ var addSetToSet = (fromSet, toSet) => {
698
+ if (fromSet && fromSet.size > 0) {
699
+ for (const item of fromSet) {
700
+ toSet.add(item);
701
+ }
702
+ }
703
+ };
704
+ var propagateDeletedAtoms = (atoms, data, subscriptions = new Set, families = new Map, timestamp = performance.now()) => {
705
+ const selectors = new Set;
706
+ for (const atom of atoms) {
707
+ addSetToSet(data.stateDependents.get(atom), selectors);
708
+ addSetToSet(data.subscriptions.get(atom), subscriptions);
709
+ if (isFamilyAtom(atom)) {
710
+ if (!families.has(atom.family)) {
711
+ families.set(atom.family, new Set);
712
+ }
713
+ families.get(atom.family).add(atom);
714
+ }
715
+ }
716
+ if (families.size > 0) {
717
+ for (const [family, familyAtoms] of families) {
718
+ addSetToSet(data.stateDependents.get(family), selectors);
719
+ addSetToSet(data.subscriptions.get(family), subscriptions);
720
+ if (familyAtoms.size === 0)
721
+ throw new Error("Should not be possible");
722
+ deleteFamilyAtomsFromSet(family, familyAtoms, data, timestamp);
723
+ }
724
+ }
725
+ propagateDirtySelectors(atoms, selectors, data, subscriptions, families);
726
+ if (families.size > 0 && data.scopes && data.scopes.size > 0) {
727
+ const scopeFamilies = new Map;
728
+ for (const family of families.keys()) {
729
+ const scopesWithFamily = data.scopeValueIndex.get(family);
730
+ if (scopesWithFamily) {
731
+ for (const scope of scopesWithFamily) {
732
+ let list = scopeFamilies.get(scope);
733
+ if (!list) {
734
+ list = [];
735
+ scopeFamilies.set(scope, list);
736
+ }
737
+ list.push(family);
738
+ }
739
+ }
740
+ }
741
+ for (const [scope, familiesInScope] of scopeFamilies) {
742
+ propagateUpdatedAtoms(familiesInScope, scope, undefined, undefined, false, timestamp, true);
743
+ }
744
+ }
745
+ };
746
+ var propagateUpdatedAtoms = (atoms, data, subscriptions, families, isRecursive = false, timestamp = performance.now(), selectorsOnly = false, isInitOnly = false) => {
747
+ if (atoms.length === 1 && !isRecursive && !selectorsOnly) {
748
+ const atom = atoms[0];
749
+ if (!isFamilyAtom(atom) && !isAtomFamily(atom)) {
750
+ const dependents = data.stateDependents.get(atom);
751
+ if ((!dependents || dependents.size === 0) && (!data.scopes || data.scopes.size === 0)) {
752
+ const subs = data.subscriptions.get(atom);
753
+ if (subs && subs.size > 0) {
754
+ callSubscribers(subs);
755
+ }
367
756
  return;
368
- } catch (e) {
757
+ }
369
758
  }
370
759
  }
371
- if (subscribtions?.size) {
372
- for (const subscribtion of subscribtions) {
373
- subscribtion.callback();
760
+ if (!subscriptions)
761
+ subscriptions = new Set;
762
+ if (!families)
763
+ families = new Map;
764
+ const selectors = new Set;
765
+ for (const atom of atoms) {
766
+ addSetToSet(data.stateDependents.get(atom), selectors);
767
+ if (!selectorsOnly) {
768
+ addSetToSet(data.subscriptions.get(atom), subscriptions);
769
+ if (isFamilyAtom(atom)) {
770
+ if (!families.has(atom.family)) {
771
+ families.set(atom.family, new Set);
772
+ }
773
+ families.get(atom.family).add(atom);
774
+ }
374
775
  }
375
776
  }
376
- if (familySubscriptions?.size) {
377
- for (const subscribtion of familySubscriptions) {
378
- subscribtion.callback(selector.familyKey);
777
+ if (families.size > 0) {
778
+ for (const [family, familyAtoms] of families) {
779
+ addSetToSet(data.stateDependents.get(family), selectors);
780
+ addSetToSet(data.subscriptions.get(family), subscriptions);
781
+ if (familyAtoms.size === 0)
782
+ throw new Error("Should not be possible");
783
+ addFamilyAtomsToSet(family, familyAtoms, data, timestamp);
784
+ }
785
+ }
786
+ if (!isRecursive) {
787
+ propagateDirtySelectors(atoms, selectors, data, subscriptions, families, isInitOnly);
788
+ if (data.scopes && data.scopes.size > 0) {
789
+ if (atoms.length === 1) {
790
+ const atom = atoms[0];
791
+ const shadowingScopes = isAtomFamily(atom) ? undefined : data.scopeValueIndex.get(atom);
792
+ for (const [, scope] of data.scopes) {
793
+ if (!shadowingScopes || !shadowingScopes.has(scope)) {
794
+ propagateUpdatedAtoms(atoms, scope, undefined, undefined, false, timestamp, true, isInitOnly);
795
+ }
796
+ }
797
+ } else {
798
+ let anyShadowed = false;
799
+ let atomShadows;
800
+ for (const atom of atoms) {
801
+ if (!isAtomFamily(atom)) {
802
+ const s = data.scopeValueIndex.get(atom);
803
+ if (s && s.size > 0) {
804
+ if (!atomShadows)
805
+ atomShadows = new Map;
806
+ atomShadows.set(atom, s);
807
+ anyShadowed = true;
808
+ }
809
+ }
810
+ }
811
+ if (!anyShadowed) {
812
+ for (const [, scope] of data.scopes) {
813
+ propagateUpdatedAtoms(atoms, scope, undefined, undefined, false, timestamp, true, isInitOnly);
814
+ }
815
+ } else {
816
+ for (const [, scope] of data.scopes) {
817
+ const atomsToUpdateInScope = [];
818
+ for (const atom of atoms) {
819
+ if (isAtomFamily(atom)) {
820
+ atomsToUpdateInScope.push(atom);
821
+ } else {
822
+ const s = atomShadows.get(atom);
823
+ if (!s || !s.has(scope)) {
824
+ atomsToUpdateInScope.push(atom);
825
+ }
826
+ }
827
+ }
828
+ if (atomsToUpdateInScope.length > 0) {
829
+ propagateUpdatedAtoms(atomsToUpdateInScope, scope, undefined, undefined, false, timestamp, true, isInitOnly);
830
+ }
831
+ }
832
+ }
833
+ }
379
834
  }
380
835
  }
381
836
  };
382
-
383
- // src/lib/propagateUpdatedAtoms.ts
384
- var recursivlyResetSelectorTree = (selectors, data, clearedSelectors) => {
385
- for (const selector of selectors) {
386
- if (!clearedSelectors.has(selector)) {
387
- clearedSelectors.add(selector);
388
- data.expiredValues.set(selector, data.values.get(selector));
389
- data.values.delete(selector);
390
- const consumers = data.stateConsumers.get(selector);
391
- if (consumers?.size) {
392
- recursivlyResetSelectorTree(consumers, data, clearedSelectors);
837
+ var propagateDirtySelectors = (updatedAtoms, selectors, data, subscriptions, families, isInitOnly = false) => {
838
+ const updatedInitializedAtoms = new Set(updatedAtoms);
839
+ if (selectors.size > 0) {
840
+ propagateSelectorUpdates(selectors, data, subscriptions, updatedInitializedAtoms, isInitOnly);
841
+ }
842
+ if (subscriptions.size > 0) {
843
+ callSubscribers(subscriptions, families);
844
+ }
845
+ };
846
+ var propagateSelectorUpdates = (selectors, data, collectedSubscribers, updatedInitializedAtoms, isInitOnly = false) => {
847
+ let currentSelectors = selectors;
848
+ while (currentSelectors.size > 0) {
849
+ const selectorsForNextPass = new Set;
850
+ for (const selector of currentSelectors) {
851
+ const currentValue = data.values.get(selector);
852
+ if (isPromiseLike(currentValue) && isInitOnly) {
853
+ continue;
854
+ }
855
+ const dependents = data.stateDependents.get(selector);
856
+ const subscribers = data.subscriptions.get(selector);
857
+ if (!isPromiseLike(currentValue) && (!dependents || dependents.size === 0) && (!subscribers || subscribers.size === 0)) {
858
+ data.values.delete(selector);
859
+ } else {
860
+ const [wasValueUpdated, didEvalCrash, error, addedDeps, removedDeps] = reEvaluteSelector(selector, data, updatedInitializedAtoms);
861
+ if ((addedDeps.size > 0 || removedDeps.size > 0) && isTransitivelySubscribed(selector, data)) {
862
+ for (const dep of addedDeps) {
863
+ mountTransitiveDeps(dep, data);
864
+ }
865
+ for (const dep of removedDeps) {
866
+ unmountOrphanedDeps(dep, data);
867
+ }
868
+ }
869
+ if (!wasValueUpdated)
870
+ continue;
871
+ addSetToSet(data.stateDependents.get(selector), selectorsForNextPass);
872
+ addSetToSet(subscribers, collectedSubscribers);
393
873
  }
394
874
  }
875
+ currentSelectors = selectorsForNextPass;
395
876
  }
396
877
  };
397
- var propagateUpdatedAtoms = (atoms, data) => {
398
- const clearedSelectors = new Set;
399
- for (const atom of atoms) {
400
- const consumers = data.stateConsumers.get(atom);
401
- if (consumers && consumers.size) {
402
- recursivlyResetSelectorTree(consumers, data, clearedSelectors);
878
+
879
+ // src/lib/isFunction.ts
880
+ var isFunction = (value) => typeof value === "function";
881
+
882
+ // src/lib/setAtom.ts
883
+ var handlePromise = (atom, promise, currentValue, data, skipOnSet) => {
884
+ const emptyAtomPromise = currentValue?.__isEmptyAtomPromise__ ? currentValue : currentValue?.__emptyAtomPromiseOrigin__ ?? null;
885
+ if (emptyAtomPromise) {
886
+ promise.__emptyAtomPromiseOrigin__ = emptyAtomPromise;
887
+ }
888
+ setValueInData(atom, promise, data);
889
+ promise.then((resolvedValue) => {
890
+ if (data.values.get(atom) !== promise)
891
+ return;
892
+ setValueInData(atom, resolvedValue, data);
893
+ if (atom.onSet && !skipOnSet)
894
+ atom.onSet(resolvedValue, data);
895
+ if (emptyAtomPromise) {
896
+ emptyAtomPromise.__resolveEmptyAtomPromise__(resolvedValue);
403
897
  }
404
- if (isFamilyAtom(atom)) {
405
- const consumersFamily = data.stateConsumers.get(atom.family);
406
- if (consumersFamily?.size) {
407
- recursivlyResetSelectorTree(consumersFamily, data, clearedSelectors);
898
+ propagateUpdatedAtoms([atom], data);
899
+ }).catch(() => {
900
+ if (data.values.get(atom) !== promise)
901
+ return;
902
+ setValueInData(atom, currentValue, data);
903
+ propagateUpdatedAtoms([atom], data);
904
+ });
905
+ };
906
+ var setAtom = (atom, newValue, data, skipOnSet = false) => {
907
+ let initializedAtomsSet;
908
+ let currentValue;
909
+ if (data.values.has(atom)) {
910
+ currentValue = data.values.get(atom);
911
+ } else {
912
+ initializedAtomsSet = new Set;
913
+ currentValue = getState(atom, data, initializedAtomsSet);
914
+ }
915
+ if (isFunction(newValue)) {
916
+ newValue = newValue(currentValue);
917
+ }
918
+ if (isPromiseLike(newValue)) {
919
+ const promise = Promise.resolve(newValue);
920
+ if (currentValue === promise)
921
+ return promise;
922
+ handlePromise(atom, promise, currentValue, data, skipOnSet);
923
+ if (initializedAtomsSet && initializedAtomsSet.size > 0) {
924
+ initializedAtomsSet.add(atom);
925
+ propagateUpdatedAtoms([...initializedAtomsSet], data);
926
+ } else {
927
+ propagateUpdatedAtoms([atom], data);
928
+ }
929
+ return promise;
930
+ }
931
+ let syncValue = newValue;
932
+ const areEqual = isPromiseLike(currentValue) ? currentValue === syncValue : atom.equal(currentValue, syncValue);
933
+ if (areEqual)
934
+ return syncValue;
935
+ syncValue = setValueInData(atom, syncValue, data);
936
+ if (atom.onSet && !skipOnSet)
937
+ atom.onSet(syncValue, data);
938
+ if (currentValue?.__isEmptyAtomPromise__) {
939
+ currentValue.__resolveEmptyAtomPromise__(syncValue);
940
+ }
941
+ if (initializedAtomsSet && initializedAtomsSet.size > 0) {
942
+ initializedAtomsSet.add(atom);
943
+ propagateUpdatedAtoms([...initializedAtomsSet], data);
944
+ } else {
945
+ propagateUpdatedAtoms([atom], data);
946
+ }
947
+ return syncValue;
948
+ };
949
+
950
+ // src/lib/initAtom.ts
951
+ var getAtomInitValue = (atom, data, initializedAtomsSet) => {
952
+ if (atom.defaultValue === undefined) {
953
+ let promiseResolve;
954
+ const promise = new Promise((resolve) => {
955
+ promiseResolve = resolve;
956
+ });
957
+ promise.__isEmptyAtomPromise__ = true;
958
+ promise.__resolveEmptyAtomPromise__ = promiseResolve;
959
+ return promise;
960
+ } else if (typeof atom.defaultValue === "function") {
961
+ const value = atom.defaultValue();
962
+ if (isPromiseLike(value)) {
963
+ value.then((resolvedValue) => {
964
+ if (data.values.get(atom) !== value)
965
+ return;
966
+ setValueInData(atom, resolvedValue, data);
967
+ propagateUpdatedAtoms([atom], data);
968
+ }, () => {
969
+ if (data.values.get(atom) === value) {
970
+ data.values.delete(atom);
971
+ }
972
+ });
973
+ }
974
+ return value;
975
+ } else if (isSelector(atom.defaultValue)) {
976
+ return getState(atom.defaultValue, data, initializedAtomsSet);
977
+ } else {
978
+ return atom.defaultValue;
979
+ }
980
+ };
981
+ var initAtom = (atom, data, initializedAtomsSet) => {
982
+ const tmpVal = getAtomInitValue(atom, data, initializedAtomsSet);
983
+ let value = setValueInData(atom, tmpVal, data);
984
+ if (atom.onInit)
985
+ atom.onInit((newVal) => {
986
+ value = newVal;
987
+ setAtom(atom, newVal, data, true);
988
+ }, data);
989
+ };
990
+
991
+ // src/lib/getState.ts
992
+ function getState(state, data, initializedAtomsSet, circularDependencySet) {
993
+ if (data.values.has(state))
994
+ return data.values.get(state);
995
+ if (isAtom(state)) {
996
+ if ("parent" in data)
997
+ return getState(state, data.parent, initializedAtomsSet, circularDependencySet);
998
+ if (isFamilyAtom(state)) {
999
+ const familyValue = data.values.get(state.family);
1000
+ if (familyValue?.__index) {
1001
+ if (isAtomDeletedInFamilyIndex(state, familyValue.__index)) {
1002
+ return state.defaultValue;
1003
+ }
408
1004
  }
409
1005
  }
1006
+ initAtom(state, data, initializedAtomsSet);
1007
+ initializedAtomsSet.add(state);
1008
+ return data.values.get(state);
410
1009
  }
411
- for (const selector of clearedSelectors) {
412
- updateSelectorSubscribers(selector, data);
1010
+ if (isSelector(state)) {
1011
+ if (_evalDepth >= MAX_EVAL_DEPTH) {
1012
+ throw new NeedsInitError(state);
1013
+ }
1014
+ initSelector(state, data, initializedAtomsSet, circularDependencySet);
1015
+ return data.values.get(state);
413
1016
  }
414
- for (const atom of atoms) {
415
- updateStateSubscribers(atom, data);
1017
+ if (isAtomFamily(state)) {
1018
+ if ("parent" in data) {
1019
+ const closestData = findClosestStoreWithAtomInitialized(state, data);
1020
+ return getState(state, closestData, initializedAtomsSet, circularDependencySet);
1021
+ }
1022
+ data.values.set(state, renderAtomFamilyIndex(createAtomFamilyIndex()));
1023
+ initializedAtomsSet.add(state);
1024
+ return data.values.get(state);
416
1025
  }
1026
+ if (isSelectorFamily(state)) {
1027
+ const array = Array.from(state.__valdresSelectorFamilyMap.keys());
1028
+ if (equal(array, state._keyArray))
1029
+ return state._keyArray;
1030
+ state._keyArray = array;
1031
+ return array;
1032
+ }
1033
+ throw new Error("Invalid object passed to get");
1034
+ }
1035
+ var findClosestStoreWithAtomInitialized = (atom, data) => {
1036
+ if ("parent" in data === false)
1037
+ return data;
1038
+ if (data.values.has(atom))
1039
+ return data;
1040
+ return findClosestStoreWithAtomInitialized(atom, data.parent);
1041
+ };
1042
+ var isAtomDeletedInFamilyIndex = (atom, index) => {
1043
+ if (index.deleted.has(atom))
1044
+ return true;
1045
+ if (index.created.has(atom))
1046
+ return false;
1047
+ if (index.parentIndex)
1048
+ return isAtomDeletedInFamilyIndex(atom, index.parentIndex);
1049
+ return false;
1050
+ };
1051
+
1052
+ // src/utils/resolveReactive.ts
1053
+ var isReactive = (value) => typeof value === "object" && value !== null && (isAtom(value) || isSelector(value));
1054
+ var resolveReactive = (value, data) => {
1055
+ if (typeof value === "object" && value !== null && (isAtom(value) || isSelector(value))) {
1056
+ if (data.values.has(value))
1057
+ return data.values.get(value);
1058
+ return getState(value, data, new Set);
1059
+ }
1060
+ return value;
417
1061
  };
418
1062
 
419
1063
  // src/lib/createStoreData.ts
420
- var generateId = () => (Math.random() + 1).toString(36).substring(7);
421
- var generateStoreData = (id = generateId()) => {
1064
+ var nextId = 0;
1065
+ var generateId = () => "__valdres_store_" + nextId++;
1066
+ function makeLazyGetter(key) {
422
1067
  return {
423
- id,
424
- values: new WeakMap,
425
- expiredValues: new WeakMap,
426
- subscriptions: new WeakMap,
427
- subscriptionsRequireEqualCheck: new WeakMap,
428
- stateConsumers: new WeakMap,
429
- stateDependencies: new WeakMap,
430
- scopes: {}
1068
+ get() {
1069
+ const map = new WeakMap;
1070
+ Object.defineProperty(this, key, {
1071
+ value: map,
1072
+ writable: true,
1073
+ configurable: true
1074
+ });
1075
+ return map;
1076
+ },
1077
+ configurable: true
431
1078
  };
432
- };
433
- function createStoreData(id, parent) {
1079
+ }
1080
+ var lazyProto = Object.create(Object.prototype);
1081
+ Object.defineProperties(lazyProto, {
1082
+ subscriptions: makeLazyGetter("subscriptions"),
1083
+ subscriptionsRequireEqualCheck: makeLazyGetter("subscriptionsRequireEqualCheck"),
1084
+ stateDependents: makeLazyGetter("stateDependents"),
1085
+ stateDependencies: makeLazyGetter("stateDependencies"),
1086
+ mounts: makeLazyGetter("mounts"),
1087
+ abortControllers: makeLazyGetter("abortControllers"),
1088
+ lastValueWriteAt: makeLazyGetter("lastValueWriteAt")
1089
+ });
1090
+ function createStoreData(id, parent, options) {
1091
+ const data = Object.create(lazyProto);
1092
+ data.id = id ?? generateId();
1093
+ data.values = new WeakMap;
1094
+ data.scopes = new Map;
1095
+ data.scopeValueIndex = new WeakMap;
1096
+ if (options?.batchUpdates) {
1097
+ data.batchUpdates = true;
1098
+ }
434
1099
  if (parent) {
435
- return {
436
- ...generateStoreData(id),
437
- parent,
438
- scopeConsumers: parent ? new Set : undefined
439
- };
440
- } else {
441
- return generateStoreData(id);
1100
+ data.parent = parent;
1101
+ data.scopeConsumers = new Set;
1102
+ data.scopeIndexKeys = new Set;
442
1103
  }
1104
+ return data;
443
1105
  }
444
1106
 
1107
+ // src/lib/deleteFamilyAtom.ts
1108
+ var deleteFamilyAtom = (atom, data) => {
1109
+ data.values.delete(atom);
1110
+ if (atom.family) {
1111
+ atom.family.release(...atom.familyArgs);
1112
+ }
1113
+ propagateDeletedAtoms([atom], data);
1114
+ };
1115
+
445
1116
  // src/lib/resetAtom.ts
446
1117
  var resetAtom = (atom, data) => {
447
- let value = getAtomInitValue(atom, data);
448
- data.values.set(atom, value);
1118
+ const initializedAtomsSet = new Set;
1119
+ let value = getAtomInitValue(atom, data, initializedAtomsSet);
1120
+ setValueInData(atom, value, data);
449
1121
  if (!isPromiseLike(value)) {
450
1122
  propagateUpdatedAtoms([atom], data);
451
1123
  }
1124
+ if (initializedAtomsSet.size > 0) {
1125
+ throw new Error("Todo - propagateUpdatedAtoms on reset");
1126
+ }
452
1127
  return value;
453
1128
  };
454
1129
 
455
1130
  // src/utils/isFamily.ts
456
1131
  var isFamily = (state) => isAtomFamily(state) || isSelectorFamily(state);
457
1132
 
1133
+ // src/lib/maxAgeCleanups.ts
1134
+ var maxAgeCleanups = new WeakMap;
1135
+ var setMaxAgeCleanup = (data, state, cleanup) => {
1136
+ let storeMap = maxAgeCleanups.get(data);
1137
+ if (!storeMap) {
1138
+ storeMap = new WeakMap;
1139
+ maxAgeCleanups.set(data, storeMap);
1140
+ }
1141
+ storeMap.set(state, cleanup);
1142
+ };
1143
+ var getMaxAgeCleanup = (data, state) => {
1144
+ return maxAgeCleanups.get(data)?.get(state);
1145
+ };
1146
+ var deleteMaxAgeCleanup = (data, state) => {
1147
+ maxAgeCleanups.get(data)?.delete(state);
1148
+ };
1149
+
458
1150
  // src/lib/unsubscribe.ts
459
- var unsubscribe = (state, subscription, data, mount, maxAgeCleanup) => {
1151
+ var unsubscribe = (state, subscription, data) => {
460
1152
  const subscribers = data.subscriptions.get(state);
461
1153
  if (subscribers) {
462
1154
  subscribers.delete(subscription);
@@ -472,26 +1164,246 @@ var unsubscribe = (state, subscription, data, mount, maxAgeCleanup) => {
472
1164
  data.subscriptionsRequireEqualCheck.delete(state);
473
1165
  }
474
1166
  }
475
- if (subscribers.size === 0) {
476
- if (maxAgeCleanup)
477
- maxAgeCleanup();
478
- data.subscriptions.delete(state);
1167
+ if (subscribers.size === 0) {
1168
+ const maxAgeCleanup = getMaxAgeCleanup(data, state);
1169
+ if (maxAgeCleanup) {
1170
+ maxAgeCleanup();
1171
+ deleteMaxAgeCleanup(data, state);
1172
+ }
1173
+ data.subscriptions.delete(state);
1174
+ unmountOrphanedDeps(state, data);
1175
+ cleanupOrphanedDeps(state, data);
1176
+ }
1177
+ }
1178
+ };
1179
+ var cleanupOrphanedDeps = (state, data, visited = new Set) => {
1180
+ if (visited.has(state))
1181
+ return;
1182
+ visited.add(state);
1183
+ if (isTransitivelySubscribed(state, data))
1184
+ return;
1185
+ const deps = data.stateDependencies.get(state);
1186
+ if (deps) {
1187
+ for (const dep of deps) {
1188
+ const depDependents = data.stateDependents.get(dep);
1189
+ if (depDependents) {
1190
+ depDependents.delete(state);
1191
+ }
1192
+ }
1193
+ data.stateDependencies.delete(state);
1194
+ data.values.delete(state);
1195
+ data.abortControllers.delete(state);
1196
+ }
1197
+ const dependents = data.stateDependents.get(state);
1198
+ if (dependents) {
1199
+ for (const dep of [...dependents]) {
1200
+ cleanupOrphanedDeps(dep, data, visited);
1201
+ }
1202
+ }
1203
+ };
1204
+
1205
+ // src/lib/subscribe.ts
1206
+ var initSubscribers = (state, data) => {
1207
+ const set = new Set;
1208
+ data.subscriptions.set(state, set);
1209
+ return set;
1210
+ };
1211
+ var installMaxAgeTimer = (state, data) => {
1212
+ if (!state.maxAge)
1213
+ return;
1214
+ const globalState = isGlobalAtom(state) ? state : undefined;
1215
+ const existing = globalState?.maxAgeInterval;
1216
+ if (existing) {
1217
+ existing.refCount++;
1218
+ const metaAtom2 = state.__cacheMeta ??= { equal, defaultValue: null };
1219
+ for (const s of globalState.stores) {
1220
+ if (s !== data && s.values.has(metaAtom2)) {
1221
+ setValueInData(metaAtom2, s.values.get(metaAtom2), data);
1222
+ propagateUpdatedAtoms([metaAtom2], data);
1223
+ break;
1224
+ }
1225
+ }
1226
+ setMaxAgeCleanup(data, state, () => {
1227
+ if (existing.refCount <= 0)
1228
+ return;
1229
+ existing.refCount--;
1230
+ if (existing.refCount === 0) {
1231
+ existing.cleanup();
1232
+ if (globalState.maxAgeInterval === existing) {
1233
+ globalState.maxAgeInterval = undefined;
1234
+ }
1235
+ }
1236
+ });
1237
+ return;
1238
+ }
1239
+ const pendingTimeouts = new Set;
1240
+ let revalidating = false;
1241
+ let cancelled = false;
1242
+ let lastSuccessTime = Date.now();
1243
+ const NO_VALUE = Symbol();
1244
+ let lastGoodValue = NO_VALUE;
1245
+ let currentInterval;
1246
+ const getMaxAge = () => resolveReactive(state.maxAge, data);
1247
+ const getSWR = () => state.staleWhileRevalidate !== undefined ? resolveReactive(state.staleWhileRevalidate, data) : Infinity;
1248
+ const getStaleIfError = () => state.staleIfError !== undefined ? resolveReactive(state.staleIfError, data) : Infinity;
1249
+ const metaAtom = state.__cacheMeta ??= { equal, defaultValue: null };
1250
+ const updateMeta = () => {
1251
+ const meta = {
1252
+ isRevalidating: revalidating,
1253
+ lastSuccessAt: lastSuccessTime,
1254
+ maxAge: getMaxAge(),
1255
+ staleWhileRevalidate: getSWR(),
1256
+ staleIfError: getStaleIfError()
1257
+ };
1258
+ if (globalState) {
1259
+ for (const store of globalState.stores) {
1260
+ setValueInData(metaAtom, meta, store);
1261
+ propagateUpdatedAtoms([metaAtom], store);
1262
+ }
1263
+ } else {
1264
+ setValueInData(metaAtom, meta, data);
1265
+ propagateUpdatedAtoms([metaAtom], data);
1266
+ }
1267
+ };
1268
+ const isPastStaleIfErrorWindow = () => {
1269
+ const elapsed = Date.now() - lastSuccessTime;
1270
+ return elapsed >= getMaxAge() + getStaleIfError();
1271
+ };
1272
+ const setAndPropagate = (atom, val) => {
1273
+ if (globalState) {
1274
+ for (const store of globalState.stores) {
1275
+ setValueInData(atom, val, store);
1276
+ propagateUpdatedAtoms([atom], store);
1277
+ }
1278
+ } else {
1279
+ setValueInData(atom, val, data);
1280
+ propagateUpdatedAtoms([atom], data);
1281
+ }
1282
+ };
1283
+ const getValueStore = () => {
1284
+ if (globalState) {
1285
+ for (const s of globalState.stores)
1286
+ return s;
1287
+ }
1288
+ return data;
1289
+ };
1290
+ const tick = () => {
1291
+ if (revalidating)
1292
+ return;
1293
+ if (typeof state.defaultValue !== "function")
1294
+ return;
1295
+ const valueStore = getValueStore();
1296
+ if (valueStore.values.has(state)) {
1297
+ const currentValue = valueStore.values.get(state);
1298
+ if (!isPromiseLike(currentValue)) {
1299
+ lastGoodValue = currentValue;
1300
+ }
479
1301
  }
480
- if (mount) {
481
- if (subscribers.size === mount.mountSubscriptions.size) {
482
- if (typeof mount.onUnmount === "function") {
483
- mount.onUnmount();
1302
+ const value = state.defaultValue();
1303
+ if (isPromiseLike(value)) {
1304
+ revalidating = true;
1305
+ updateMeta();
1306
+ const swr = getSWR();
1307
+ const handleResolve = (resolved) => {
1308
+ if (cancelled)
1309
+ return;
1310
+ revalidating = false;
1311
+ lastSuccessTime = Date.now();
1312
+ lastGoodValue = resolved;
1313
+ setAndPropagate(state, resolved);
1314
+ updateMeta();
1315
+ };
1316
+ const handleReject = () => {
1317
+ if (cancelled)
1318
+ return;
1319
+ revalidating = false;
1320
+ if (!isPastStaleIfErrorWindow() && lastGoodValue !== NO_VALUE) {
1321
+ setAndPropagate(state, lastGoodValue);
1322
+ } else {
1323
+ setAndPropagate(state, value);
1324
+ }
1325
+ updateMeta();
1326
+ };
1327
+ if (swr > 0) {
1328
+ let timeoutRef;
1329
+ if (Number.isFinite(swr)) {
1330
+ timeoutRef = setTimeout(() => {
1331
+ pendingTimeouts.delete(timeoutRef);
1332
+ if (cancelled || !revalidating)
1333
+ return;
1334
+ setAndPropagate(state, value);
1335
+ }, swr);
1336
+ pendingTimeouts.add(timeoutRef);
484
1337
  }
1338
+ value.then((resolved) => {
1339
+ if (timeoutRef !== undefined) {
1340
+ clearTimeout(timeoutRef);
1341
+ pendingTimeouts.delete(timeoutRef);
1342
+ }
1343
+ handleResolve(resolved);
1344
+ }, () => {
1345
+ if (timeoutRef !== undefined) {
1346
+ clearTimeout(timeoutRef);
1347
+ pendingTimeouts.delete(timeoutRef);
1348
+ }
1349
+ handleReject();
1350
+ });
1351
+ } else {
1352
+ setAndPropagate(state, value);
1353
+ value.then(handleResolve, handleReject);
485
1354
  }
1355
+ } else {
1356
+ lastSuccessTime = Date.now();
1357
+ lastGoodValue = value;
1358
+ setAndPropagate(state, value);
1359
+ updateMeta();
486
1360
  }
1361
+ };
1362
+ const startInterval = () => {
1363
+ currentInterval = setInterval(tick, getMaxAge());
1364
+ };
1365
+ startInterval();
1366
+ updateMeta();
1367
+ const configUnsubs = [];
1368
+ if (isReactive(state.maxAge)) {
1369
+ configUnsubs.push(subscribe(state.maxAge, () => {
1370
+ clearInterval(currentInterval);
1371
+ startInterval();
1372
+ updateMeta();
1373
+ }, false, data));
1374
+ }
1375
+ if (state.staleWhileRevalidate && isReactive(state.staleWhileRevalidate)) {
1376
+ configUnsubs.push(subscribe(state.staleWhileRevalidate, () => updateMeta(), false, data));
1377
+ }
1378
+ if (state.staleIfError && isReactive(state.staleIfError)) {
1379
+ configUnsubs.push(subscribe(state.staleIfError, () => updateMeta(), false, data));
1380
+ }
1381
+ const cleanup = () => {
1382
+ cancelled = true;
1383
+ clearInterval(currentInterval);
1384
+ for (const t of pendingTimeouts)
1385
+ clearTimeout(t);
1386
+ pendingTimeouts.clear();
1387
+ for (const unsub of configUnsubs)
1388
+ unsub();
1389
+ };
1390
+ if (globalState) {
1391
+ const entry = { cleanup, refCount: 1 };
1392
+ globalState.maxAgeInterval = entry;
1393
+ setMaxAgeCleanup(data, state, () => {
1394
+ if (entry.refCount <= 0)
1395
+ return;
1396
+ entry.refCount--;
1397
+ if (entry.refCount === 0) {
1398
+ entry.cleanup();
1399
+ if (globalState.maxAgeInterval === entry) {
1400
+ globalState.maxAgeInterval = undefined;
1401
+ }
1402
+ }
1403
+ });
1404
+ } else {
1405
+ setMaxAgeCleanup(data, state, cleanup);
487
1406
  }
488
- };
489
-
490
- // src/lib/subscribe.ts
491
- var initSubscribers = (state, data) => {
492
- const set = new Set;
493
- data.subscriptions.set(state, set);
494
- return set;
495
1407
  };
496
1408
  var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) => {
497
1409
  let parentUnsubscribe;
@@ -506,14 +1418,21 @@ var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) =>
506
1418
  originalCallback(arg);
507
1419
  };
508
1420
  } else if (!data.values.has(state) && isAtom(state)) {
509
- initAtom(state, data);
1421
+ const initializedAtomsSet = new Set;
1422
+ initAtom(state, data, initializedAtomsSet);
1423
+ if (initializedAtomsSet.size) {
1424
+ throw new Error("This should not be possible");
1425
+ }
510
1426
  }
511
1427
  if (isSelector(state) && !data.values.has(state)) {
512
- initSelector(state, data);
1428
+ initSelector(state, data, new Set, new WeakSet);
513
1429
  }
514
1430
  const subscribers = data.subscriptions.get(state) || initSubscribers(state, data);
515
1431
  let subscription;
516
1432
  if (isFamily(state)) {
1433
+ if (isSelectorFamily(state)) {
1434
+ throw new Error("Subscribe to selectorFammily is currently not supported");
1435
+ }
517
1436
  subscription = {
518
1437
  callback,
519
1438
  state,
@@ -526,45 +1445,12 @@ var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) =>
526
1445
  };
527
1446
  }
528
1447
  subscribers.add(subscription);
529
- let mount;
530
- let maxAgeCleanup;
531
1448
  if (subscribers.size === 1) {
532
1449
  if (isAtom(state) && state.maxAge) {
533
- let timeout;
534
- const interval = setInterval(() => {
535
- let value = getAtomInitValue(state, data);
536
- if (isPromiseLike(value)) {
537
- if (state.staleWhileRevalidate) {
538
- const oldValue = data.values.get(state);
539
- timeout = setTimeout(() => {
540
- const nowValue = data.values.get(state);
541
- console.log("todo", oldValue);
542
- }, state.staleWhileRevalidate);
543
- value.then((res) => clearTimeout(timeout));
544
- }
545
- } else {
546
- data.values.set(state, value);
547
- propagateUpdatedAtoms([state], data);
548
- }
549
- }, state.maxAge);
550
- maxAgeCleanup = () => {
551
- clearInterval(interval);
552
- if (timeout)
553
- clearTimeout(timeout);
554
- };
1450
+ installMaxAgeTimer(state, data);
555
1451
  }
556
- if (state.onMount) {
557
- const store = storeFromStoreData(data);
558
- const mountSubscriptions = new Set;
559
- const originalSub = store.sub;
560
- store.sub = (state2, callback2) => {
561
- mountSubscriptions.add(callback2);
562
- return originalSub(state2, callback2);
563
- };
564
- mount = {
565
- onUnmount: state.onMount(store, state),
566
- mountSubscriptions
567
- };
1452
+ if (!isFamily(state)) {
1453
+ mountTransitiveDeps(state, data);
568
1454
  }
569
1455
  }
570
1456
  if (requireDeepEqualCheckBeforeCallback && data.subscriptionsRequireEqualCheck.get(state) !== true) {
@@ -574,140 +1460,273 @@ var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) =>
574
1460
  if (parentUnsubscribe) {
575
1461
  parentUnsubscribe();
576
1462
  }
577
- unsubscribe(state, subscription, data, mount, maxAgeCleanup);
1463
+ unsubscribe(state, subscription, data);
578
1464
  };
579
1465
  };
580
1466
 
581
1467
  // src/lib/setAtoms.ts
582
- var setAtoms = (pairs, data) => {
1468
+ var setAtoms = (pairs, data, initializedAtomsSet) => {
583
1469
  const updatedAtoms = [];
584
1470
  for (let [atom, value] of pairs) {
585
- const currentValue = getState(atom, data);
586
- if (!atom.equal(currentValue, value)) {
1471
+ const currentValue = getState(atom, data, initializedAtomsSet);
1472
+ const areEqual = isPromiseLike(currentValue) || isPromiseLike(value) ? currentValue === value : atom.equal(currentValue, value);
1473
+ if (!areEqual) {
587
1474
  updatedAtoms.push(atom);
1475
+ value = setValueInData(atom, value, data);
588
1476
  if (atom.onSet)
589
1477
  atom.onSet(value, data);
590
- data.values.set(atom, value);
1478
+ } else {
1479
+ setValueInData(atom, value, data);
1480
+ }
1481
+ }
1482
+ if (initializedAtomsSet.size > 0) {
1483
+ for (const atom of initializedAtomsSet) {
1484
+ updatedAtoms.push(atom);
591
1485
  }
592
1486
  }
593
- propagateUpdatedAtoms(updatedAtoms, data);
1487
+ if (updatedAtoms.length > 0) {
1488
+ propagateUpdatedAtoms(updatedAtoms, data);
1489
+ }
594
1490
  };
595
1491
 
596
1492
  // src/lib/transaction.ts
597
- var findDependencies = (state, data, result = new Set) => {
598
- const consumers = data.stateConsumers.get(state);
599
- if (consumers?.size) {
600
- for (const consumer of consumers) {
601
- if (!result.has(consumer)) {
602
- result.add(consumer);
603
- findDependencies(consumer, data, result);
604
- }
605
- }
606
- }
607
- return result;
1493
+ var deleteAtomFamilyAtoms = (set, data) => {
1494
+ set.forEach((atom) => {
1495
+ data.values.delete(atom);
1496
+ });
608
1497
  };
609
- var recursivlyResetTxnSelectorCache = (state, txnSubscribers, txnSelectorCache) => {
610
- for (const dep of txnSubscribers.get(state)) {
611
- txnSelectorCache.delete(dep);
612
- if (txnSubscribers.get(dep)?.size) {
613
- recursivlyResetTxnSelectorCache(dep, txnSubscribers, txnSelectorCache);
1498
+
1499
+ class Transaction {
1500
+ data;
1501
+ parentTransaction;
1502
+ dirty;
1503
+ _scopedTransactions;
1504
+ _initializedAtomsSet;
1505
+ _deleteSet;
1506
+ _selectorDependencies;
1507
+ _selectorCache;
1508
+ _atomMap;
1509
+ constructor(data, parentTransaction, childTransaction) {
1510
+ this.data = data;
1511
+ this.parentTransaction = parentTransaction;
1512
+ this.dirty = false;
1513
+ this._atomMap = new Map;
1514
+ if (childTransaction) {
1515
+ this._scopedTransactions = new Map([
1516
+ [childTransaction.data.id, childTransaction]
1517
+ ]);
614
1518
  }
615
1519
  }
616
- };
617
- var captureScopedTransaction = (scopedData) => {
618
- let txn;
619
- transaction((scopedTxn) => {
620
- txn = scopedTxn;
621
- }, scopedData, false);
622
- return txn;
623
- };
624
- var transaction = (callback, data, autoCommit = true) => {
625
- let txnAtomMap = new Map;
626
- let txnSelectorCache = new Map;
627
- let txnSubscribers = new Map;
628
- let dirtySelectors = new Set;
629
- let scopedTransactions;
630
- const txnGet = (state) => {
631
- if (isAtom(state)) {
632
- return txnAtomMap.has(state) ? txnAtomMap.get(state) : getState(state, data);
1520
+ hasTxnOrData = (state) => {
1521
+ if (this._atomMap.has(state))
1522
+ return true;
1523
+ if (this.data.values.has(state))
1524
+ return true;
1525
+ if (this.parentTransaction)
1526
+ return this.parentTransaction.hasTxnOrData(state);
1527
+ return false;
1528
+ };
1529
+ valueFromTxnOrData = (state) => {
1530
+ if (this._atomMap.has(state)) {
1531
+ return this._atomMap.get(state);
1532
+ }
1533
+ if (this.data.values.has(state)) {
1534
+ return this.data.values.get(state);
1535
+ }
1536
+ if (this.parentTransaction) {
1537
+ return this.parentTransaction.valueFromTxnOrData(state);
1538
+ }
1539
+ };
1540
+ get = (state) => {
1541
+ if (isAtom(state) || isAtomFamily(state)) {
1542
+ if (this.hasTxnOrData(state)) {
1543
+ return this.valueFromTxnOrData(state);
1544
+ }
1545
+ return getState(state, this.data, this.initializedAtomsSet);
633
1546
  } else if (isSelector(state)) {
634
- if (txnSelectorCache.has(state)) {
635
- return txnSelectorCache.get(state);
1547
+ if (this.dirty) {
1548
+ this.selectorCache.clear();
1549
+ this.selectorDependencies.clear();
1550
+ this.dirty = false;
1551
+ } else if (this.selectorCache.has(state)) {
1552
+ return this.selectorCache.get(state);
636
1553
  }
637
- const deps = new Set;
638
1554
  const res = state.get((s) => {
639
- deps.add(s);
640
- return txnGet(s);
641
- }, data.id);
642
- for (const dep of deps) {
643
- if (!txnSubscribers.has(dep)) {
644
- txnSubscribers.set(dep, new Set);
1555
+ if (!this.selectorDependencies.has(s)) {
1556
+ this.selectorDependencies.add(s);
645
1557
  }
646
- txnSubscribers.get(dep).add(state);
647
- }
648
- txnSelectorCache.set(state, res);
1558
+ return this.get(s);
1559
+ }, this.data.id);
1560
+ this.selectorCache.set(state, res);
649
1561
  return res;
650
- } else if (isFamily(state)) {
651
- return txnAtomMap.has(state) ? txnAtomMap.get(state) : getState(state.__keysSelector, data);
652
1562
  } else {
653
1563
  throw new Error("Unsupported state");
654
1564
  }
655
1565
  };
656
- const txnSet = (atom, value) => {
1566
+ set = (atom, value) => {
657
1567
  if (!isAtom(atom))
658
1568
  throw new Error("Not an atom");
659
1569
  if (isFunction(value)) {
660
- const currentValue = txnGet(atom);
1570
+ const currentValue = this.get(atom);
661
1571
  value = value(currentValue);
662
1572
  }
663
- for (const selector of findDependencies(atom, data)) {
664
- dirtySelectors.add(selector);
665
- txnSelectorCache.delete(selector);
1573
+ if (!atom.mutable && !isProd() && value !== null && (typeof value === "object" || typeof value === "function")) {
1574
+ value = deepFreeze(value);
666
1575
  }
667
- if (txnSubscribers.get(atom)?.size) {
668
- recursivlyResetTxnSelectorCache(atom, txnSubscribers, txnSelectorCache);
1576
+ this._atomMap.set(atom, value);
1577
+ if (!this.dirty)
1578
+ this.dirty = true;
1579
+ if (isFamilyAtom(atom)) {
1580
+ if (!this._atomMap.has(atom.family)) {
1581
+ this.cloneFamilyIntoTxn(atom.family);
1582
+ }
1583
+ const index = this._atomMap.get(atom.family).__index;
1584
+ index.created.set(atom, performance.now());
1585
+ index.deleted.delete(atom);
1586
+ index.rendered = null;
1587
+ index.renderedArray = null;
1588
+ this.recursivelyUpdateAtomFamilyIndexes(atom.family);
669
1589
  }
670
- txnAtomMap.set(atom, value);
671
1590
  return value;
672
1591
  };
673
- const txnReset = (atom) => {
674
- const value = getAtomInitValue(atom, data);
675
- txnAtomMap.set(atom, value);
1592
+ batchSetFamilyAtoms = (family, pairs) => {
1593
+ if (!this._atomMap.has(family)) {
1594
+ this.cloneFamilyIntoTxn(family);
1595
+ }
1596
+ const index = this._atomMap.get(family).__index;
1597
+ for (const [atom, value] of pairs) {
1598
+ if (atom.family !== family) {
1599
+ throw new Error("Atom does not belong to the provided family");
1600
+ }
1601
+ index.created.set(atom, performance.now());
1602
+ if (index.deleted.has(atom))
1603
+ index.deleted.delete(atom);
1604
+ this._atomMap.set(atom, value);
1605
+ }
1606
+ index.rendered = null;
1607
+ index.renderedArray = null;
1608
+ this.recursivelyUpdateAtomFamilyIndexes(family);
1609
+ };
1610
+ del = (atom) => {
1611
+ if (!this._atomMap.has(atom.family)) {
1612
+ this.cloneFamilyIntoTxn(atom.family);
1613
+ }
1614
+ const index = this._atomMap.get(atom.family).__index;
1615
+ index.created.delete(atom);
1616
+ index.deleted.set(atom, performance.now());
1617
+ index.rendered = null;
1618
+ index.renderedArray = null;
1619
+ this._atomMap.set(atom.family, renderAtomFamilyIndex(index));
1620
+ this.recursivelyUpdateAtomFamilyIndexes(atom.family);
1621
+ if (this.data.values.has(atom)) {
1622
+ this.deleteSet.add(atom);
1623
+ }
1624
+ if (this._atomMap.has(atom)) {
1625
+ this._atomMap.delete(atom);
1626
+ }
1627
+ };
1628
+ scope = (scopeId, callback) => {
1629
+ if (this.data.scopes.has(scopeId)) {
1630
+ return this.scopedTransaction(scopeId).execute(callback, false);
1631
+ } else {
1632
+ throw new Error(`Scope '${scopeId}' not found. Registered scopes: ${[...this.data.scopes.keys()].join(", ")}`);
1633
+ }
1634
+ };
1635
+ parentScope = (callback) => {
1636
+ if (!this.parentTransaction) {
1637
+ this.parentTransaction = new Transaction(this.data.parent, undefined, this);
1638
+ }
1639
+ return this.parentTransaction.execute(callback, false);
1640
+ };
1641
+ reset = (atom) => {
1642
+ const value = getAtomInitValue(atom, this.data, this.initializedAtomsSet);
1643
+ this._atomMap.set(atom, value);
676
1644
  return value;
677
1645
  };
678
- const commit = () => {
679
- setAtoms(txnAtomMap, data);
680
- dirtySelectors.clear();
681
- if (scopedTransactions) {
682
- for (const scopedTxn of Object.values(scopedTransactions)) {
1646
+ execute = (callback, autoCommit = true) => {
1647
+ const result = callback(this);
1648
+ if (autoCommit)
1649
+ this.txnCommit();
1650
+ return result;
1651
+ };
1652
+ txnCommit = () => {
1653
+ if (this.parentTransaction) {
1654
+ this.parentTransaction.txnCommit();
1655
+ } else {
1656
+ this.commit();
1657
+ }
1658
+ };
1659
+ commit = () => {
1660
+ const initializedAtomsSet = new Set;
1661
+ setAtoms(this._atomMap, this.data, initializedAtomsSet);
1662
+ if (this.deleteSet?.size) {
1663
+ deleteAtomFamilyAtoms(this.deleteSet, this.data);
1664
+ propagateDeletedAtoms([...this.deleteSet], this.data);
1665
+ }
1666
+ if (this._scopedTransactions) {
1667
+ for (const [, scopedTxn] of this._scopedTransactions) {
683
1668
  scopedTxn.commit();
684
1669
  }
685
1670
  }
686
1671
  };
687
- const result = callback({
688
- set: txnSet,
689
- get: txnGet,
690
- reset: txnReset,
691
- commit,
692
- scope: (scopeId, callback2) => {
693
- if (scopeId in data.scopes) {
694
- const scopedData = data.scopes[scopeId];
695
- if (scopedTransactions === undefined) {
696
- scopedTransactions = {};
697
- }
698
- if (scopedTransactions[scopeId] === undefined) {
699
- scopedTransactions[scopeId] = captureScopedTransaction(scopedData);
700
- }
701
- return callback2(scopedTransactions[scopeId]);
702
- } else {
703
- throw new Error(`Scope '${scopeId}' not found. Registered scopes: ${Object.keys(data.scopes).join(", ")}`);
1672
+ get selectorCache() {
1673
+ if (!this._selectorCache)
1674
+ this._selectorCache = new Map;
1675
+ return this._selectorCache;
1676
+ }
1677
+ get selectorDependencies() {
1678
+ if (!this._selectorDependencies)
1679
+ this._selectorDependencies = new Set;
1680
+ return this._selectorDependencies;
1681
+ }
1682
+ get deleteSet() {
1683
+ if (!this._deleteSet)
1684
+ this._deleteSet = new Set;
1685
+ return this._deleteSet;
1686
+ }
1687
+ get initializedAtomsSet() {
1688
+ if (!this._initializedAtomsSet)
1689
+ this._initializedAtomsSet = new Set;
1690
+ return this._initializedAtomsSet;
1691
+ }
1692
+ scopedTransaction(scopeId) {
1693
+ if (!this._scopedTransactions)
1694
+ this._scopedTransactions = new Map;
1695
+ if (!this._scopedTransactions.has(scopeId)) {
1696
+ const scopedData = this.data.scopes.get(scopeId);
1697
+ const scopedTransaction = new Transaction(scopedData, this);
1698
+ this._scopedTransactions.set(scopeId, scopedTransaction);
1699
+ }
1700
+ return this._scopedTransactions.get(scopeId);
1701
+ }
1702
+ cloneFamilyIntoTxn(family, parentIndex, moveUpIfParent = true) {
1703
+ if (moveUpIfParent && this.parentTransaction)
1704
+ return this.parentTransaction.cloneFamilyIntoTxn(family, parentIndex, moveUpIfParent);
1705
+ const currentFamilyList = this.get(family);
1706
+ const clonedIndex = cloneAtomFamilyIndex(currentFamilyList.__index, parentIndex);
1707
+ if (this._scopedTransactions?.size) {
1708
+ for (const [, scopedTxn] of this._scopedTransactions) {
1709
+ scopedTxn.cloneFamilyIntoTxn(family, clonedIndex, false);
704
1710
  }
705
- },
706
- data
707
- });
708
- if (autoCommit)
709
- commit();
710
- return result;
1711
+ }
1712
+ this._atomMap.set(family, renderAtomFamilyIndex(clonedIndex));
1713
+ }
1714
+ recursivelyUpdateAtomFamilyIndexes(atomFamily) {
1715
+ const currentIndex = this._atomMap.get(atomFamily).__index;
1716
+ currentIndex.rendered = null;
1717
+ currentIndex.renderedArray = null;
1718
+ const updatedValue = renderAtomFamilyIndex(currentIndex);
1719
+ this._atomMap.set(atomFamily, updatedValue);
1720
+ if (this._scopedTransactions?.size) {
1721
+ for (const [, scopedTxn] of this._scopedTransactions) {
1722
+ scopedTxn.recursivelyUpdateAtomFamilyIndexes(atomFamily);
1723
+ }
1724
+ }
1725
+ }
1726
+ }
1727
+ var transaction = (callback, data) => {
1728
+ const txn = new Transaction(data);
1729
+ return txn.execute(callback);
711
1730
  };
712
1731
 
713
1732
  // src/lib/storeFromStoreData.ts
@@ -718,35 +1737,150 @@ Only \`atom\` cam be set.
718
1737
  var InvalidStateSetError = `Invalid state object passed to set().
719
1738
  Only \`atom\` can be set.
720
1739
  `;
1740
+ var isCachedValueStale = (state, data) => {
1741
+ const atom = state;
1742
+ const maxAge = atom.maxAge;
1743
+ if (maxAge === undefined)
1744
+ return false;
1745
+ if (isGlobalAtom(atom)) {
1746
+ if (atom.maxAgeInterval !== undefined)
1747
+ return false;
1748
+ } else {
1749
+ const subs = data.subscriptions.get(state);
1750
+ if (subs && subs.size > 0)
1751
+ return false;
1752
+ }
1753
+ const lastWrite = data.lastValueWriteAt.get(state);
1754
+ if (lastWrite === undefined)
1755
+ return false;
1756
+ const ttl = typeof maxAge === "number" ? maxAge : resolveReactive(maxAge, data);
1757
+ return Date.now() - lastWrite > ttl;
1758
+ };
721
1759
  function storeFromStoreData(data, detach) {
722
- const get = (state) => getState(state, data);
723
- const set = (state, value) => {
1760
+ const _initSet = new Set;
1761
+ let _pendingTxn = null;
1762
+ const flushPendingTxn = () => {
1763
+ if (_pendingTxn) {
1764
+ const txnToCommit = _pendingTxn;
1765
+ _pendingTxn = null;
1766
+ txnToCommit.commit();
1767
+ }
1768
+ };
1769
+ const ensurePendingTxn = () => {
1770
+ if (!_pendingTxn) {
1771
+ _pendingTxn = new Transaction(data);
1772
+ queueMicrotask(() => {
1773
+ try {
1774
+ flushPendingTxn();
1775
+ } catch (error) {
1776
+ setTimeout(() => {
1777
+ throw error;
1778
+ }, 0);
1779
+ }
1780
+ });
1781
+ }
1782
+ return _pendingTxn;
1783
+ };
1784
+ const getDefault = (state) => {
1785
+ if (data.values.has(state)) {
1786
+ if (!isCachedValueStale(state, data)) {
1787
+ return data.values.get(state);
1788
+ }
1789
+ data.values.delete(state);
1790
+ data.lastValueWriteAt.delete(state);
1791
+ }
1792
+ let res;
1793
+ try {
1794
+ res = getState(state, data, _initSet);
1795
+ } finally {
1796
+ if (_initSet.size) {
1797
+ const atoms = [..._initSet];
1798
+ _initSet.clear();
1799
+ propagateUpdatedAtoms(atoms, data, undefined, undefined, false, undefined, false, true);
1800
+ }
1801
+ }
1802
+ return res;
1803
+ };
1804
+ const getBatched = (state) => {
1805
+ if (_pendingTxn) {
1806
+ return _pendingTxn.get(state);
1807
+ }
1808
+ return getDefault(state);
1809
+ };
1810
+ const get = data.batchUpdates ? getBatched : getDefault;
1811
+ const setDefault = (state, value) => {
724
1812
  if (isAtom(state))
725
1813
  return setAtom(state, value, data);
726
1814
  if (isSelector(state))
727
1815
  throw new Error(SelectorProvidedToSetError);
728
1816
  throw new Error(InvalidStateSetError);
729
1817
  };
730
- const reset = (atom) => resetAtom(atom, data);
1818
+ const setBatched = (state, value) => {
1819
+ if (isAtom(state)) {
1820
+ return ensurePendingTxn().set(state, value);
1821
+ }
1822
+ if (isSelector(state))
1823
+ throw new Error(SelectorProvidedToSetError);
1824
+ throw new Error(InvalidStateSetError);
1825
+ };
1826
+ const set = data.batchUpdates ? setBatched : setDefault;
1827
+ const reset = (atom) => {
1828
+ if (data.batchUpdates)
1829
+ flushPendingTxn();
1830
+ return resetAtom(atom, data);
1831
+ };
1832
+ const del = (atom) => {
1833
+ if (data.batchUpdates)
1834
+ flushPendingTxn();
1835
+ return deleteFamilyAtom(atom, data);
1836
+ };
731
1837
  const sub = (state, callback, deepEqualCheckBeforeCallback = true) => subscribe(state, callback, deepEqualCheckBeforeCallback, data);
732
- const txn = (callback) => transaction(callback, data);
733
- const scope = (scopeId) => {
734
- let scopedStoreData;
735
- if (scopeId in data.scopes) {
736
- scopedStoreData = data.scopes[scopeId];
1838
+ const txn = (callback) => {
1839
+ if (data.batchUpdates)
1840
+ flushPendingTxn();
1841
+ return transaction(callback, data);
1842
+ };
1843
+ const scope = (scopeId, callback) => {
1844
+ if (callback) {
1845
+ if (!data.scopes.has(scopeId)) {
1846
+ throw new Error(`Scope ${scopeId} does not exist`);
1847
+ }
1848
+ const scopedStoreData = data.scopes.get(scopeId);
1849
+ const scopedStore = storeFromStoreData(scopedStoreData);
1850
+ const res = callback(scopedStore);
1851
+ return res;
737
1852
  } else {
738
- scopedStoreData = createStoreData(scopeId, data);
739
- data.scopes[scopeId] = scopedStoreData;
740
- }
741
- const detach2 = () => {
742
- scopedStoreData.scopeConsumers.delete(detach2);
743
- if (scopedStoreData.scopeConsumers.size === 0) {
744
- delete data.scopes[scopeId];
1853
+ let scopedStoreData;
1854
+ if (data.scopes.has(scopeId)) {
1855
+ scopedStoreData = data.scopes.get(scopeId);
1856
+ } else {
1857
+ scopedStoreData = createStoreData(scopeId, data, data.batchUpdates ? { batchUpdates: true } : undefined);
1858
+ data.scopes.set(scopeId, scopedStoreData);
745
1859
  }
746
- };
747
- scopedStoreData.scopeConsumers.add(detach2);
748
- const newStore = storeFromStoreData(data.scopes[scopeId], detach2);
749
- return newStore;
1860
+ const detach2 = (expectedToDestroy = false) => {
1861
+ scopedStoreData.scopeConsumers.delete(detach2);
1862
+ if (scopedStoreData.scopeConsumers.size === 0) {
1863
+ data.scopes.delete(scopeId);
1864
+ for (const key of scopedStoreData.scopeIndexKeys) {
1865
+ const set2 = data.scopeValueIndex.get(key);
1866
+ if (set2) {
1867
+ set2.delete(scopedStoreData);
1868
+ if (set2.size === 0)
1869
+ data.scopeValueIndex.delete(key);
1870
+ }
1871
+ }
1872
+ scopedStoreData.scopeIndexKeys.clear();
1873
+ return true;
1874
+ }
1875
+ if (expectedToDestroy) {
1876
+ console.warn(`Scope ${scopeId} still has ${scopedStoreData.scopeConsumers.size} consumers, will not detach`);
1877
+ }
1878
+ return false;
1879
+ };
1880
+ scopedStoreData.scopeConsumers.add(detach2);
1881
+ const newStore = storeFromStoreData(data.scopes.get(scopeId), detach2);
1882
+ return newStore;
1883
+ }
750
1884
  };
751
1885
  if (detach) {
752
1886
  return {
@@ -755,6 +1889,7 @@ function storeFromStoreData(data, detach) {
755
1889
  sub,
756
1890
  txn,
757
1891
  reset,
1892
+ del,
758
1893
  data,
759
1894
  scope,
760
1895
  detach
@@ -766,15 +1901,121 @@ function storeFromStoreData(data, detach) {
766
1901
  sub,
767
1902
  txn,
768
1903
  reset,
1904
+ del,
769
1905
  data,
770
1906
  scope
771
1907
  };
772
1908
  }
773
1909
  }
774
1910
 
1911
+ // src/lib/mountAtom.ts
1912
+ var isTransitivelySubscribed = (state, data, visited = new Set) => {
1913
+ const stack = [state];
1914
+ while (stack.length > 0) {
1915
+ const current = stack.pop();
1916
+ if (visited.has(current))
1917
+ continue;
1918
+ visited.add(current);
1919
+ const subs = data.subscriptions.get(current);
1920
+ if (subs && subs.size > 0)
1921
+ return true;
1922
+ const dependents = data.stateDependents.get(current);
1923
+ if (dependents) {
1924
+ for (const dep of dependents) {
1925
+ if (!visited.has(dep))
1926
+ stack.push(dep);
1927
+ }
1928
+ }
1929
+ }
1930
+ return false;
1931
+ };
1932
+ var mountAtom = (state, data) => {
1933
+ const onMountFn = state.__valdresOnMount ?? state.onMount;
1934
+ if (!onMountFn || data.mounts.has(state))
1935
+ return;
1936
+ const mountEntry = {};
1937
+ data.mounts.set(state, mountEntry);
1938
+ const store = data.storeRef ?? storeFromStoreData(data);
1939
+ try {
1940
+ mountEntry.cleanup = onMountFn(store, state);
1941
+ } catch (error) {
1942
+ data.mounts.delete(state);
1943
+ throw error;
1944
+ }
1945
+ };
1946
+ var unmountAtom = (state, data) => {
1947
+ const mount = data.mounts.get(state);
1948
+ if (!mount)
1949
+ return;
1950
+ data.mounts.delete(state);
1951
+ if (typeof mount.cleanup === "function") {
1952
+ mount.cleanup();
1953
+ }
1954
+ };
1955
+ var mountTransitiveDeps = (state, data, visited = new Set) => {
1956
+ let firstError = null;
1957
+ const stack = [state];
1958
+ while (stack.length > 0) {
1959
+ const current = stack.pop();
1960
+ if (visited.has(current))
1961
+ continue;
1962
+ visited.add(current);
1963
+ if (current.__valdresOnMount || current.onMount) {
1964
+ try {
1965
+ mountAtom(current, data);
1966
+ } catch (error) {
1967
+ if (!firstError)
1968
+ firstError = { value: error };
1969
+ }
1970
+ }
1971
+ const deps = data.stateDependencies.get(current);
1972
+ if (deps) {
1973
+ for (const dep of deps) {
1974
+ if (!visited.has(dep))
1975
+ stack.push(dep);
1976
+ }
1977
+ }
1978
+ }
1979
+ if (firstError) {
1980
+ throw firstError.value;
1981
+ }
1982
+ };
1983
+ var unmountOrphanedDeps = (state, data, visited = new Set) => {
1984
+ let firstError = null;
1985
+ const stack = [state];
1986
+ while (stack.length > 0) {
1987
+ const current = stack.pop();
1988
+ if (visited.has(current))
1989
+ continue;
1990
+ visited.add(current);
1991
+ if ((current.__valdresOnMount || current.onMount) && data.mounts.has(current)) {
1992
+ if (!isTransitivelySubscribed(current, data)) {
1993
+ try {
1994
+ unmountAtom(current, data);
1995
+ } catch (error) {
1996
+ if (!firstError)
1997
+ firstError = { value: error };
1998
+ }
1999
+ }
2000
+ }
2001
+ const deps = data.stateDependencies.get(current);
2002
+ if (deps) {
2003
+ for (const dep of deps) {
2004
+ if (!visited.has(dep))
2005
+ stack.push(dep);
2006
+ }
2007
+ }
2008
+ }
2009
+ if (firstError) {
2010
+ throw firstError.value;
2011
+ }
2012
+ };
2013
+
775
2014
  // src/store.ts
776
- var store = (id) => {
777
- const data = createStoreData(id);
2015
+ var store = (idOrOptions) => {
2016
+ const id = typeof idOrOptions === "string" ? idOrOptions : idOrOptions?.id;
2017
+ const options = typeof idOrOptions === "object" ? idOrOptions : undefined;
2018
+ const data = createStoreData(id, undefined, options);
778
2019
  return storeFromStoreData(data);
779
2020
  };
780
2021
 
@@ -787,61 +2028,114 @@ var globalStore = Object.assign(store("valdres-global-store"), {
787
2028
  // src/lib/globalAtom.ts
788
2029
  var globalAtom = (defaultValue, options) => {
789
2030
  const stores = new Set;
790
- let value;
791
- let initialized = false;
792
- let onReset;
793
2031
  if (options.onSet)
794
2032
  throw new Error("onSet on globalAtom is currently not supported");
795
2033
  const onInit = (setSelf2, data) => {
796
2034
  setSelf2(globalStore.get(atom));
797
- if (!initialized && options.onInit) {
798
- onReset = options.onInit((newVal) => {
799
- setSelf2(newVal);
800
- value = newVal;
801
- }, data);
802
- initialized = true;
803
- }
804
2035
  stores.add(data);
805
2036
  };
806
2037
  const onSet = (newValue, currentStore) => {
807
- value = newValue;
808
2038
  if (stores.size > 1) {
809
2039
  for (const store2 of stores) {
810
2040
  if (store2.id !== currentStore.id) {
811
- setAtom(atom, value, store2, true);
2041
+ setAtom(atom, newValue, store2, true);
812
2042
  }
813
2043
  }
814
2044
  }
815
2045
  };
2046
+ let mountCount = 0;
2047
+ let userCleanup;
2048
+ const userOnMount = options.onMount;
2049
+ const onMount = userOnMount ? (...args) => {
2050
+ mountCount++;
2051
+ if (mountCount === 1) {
2052
+ try {
2053
+ userCleanup = userOnMount(...args);
2054
+ } catch (error) {
2055
+ mountCount--;
2056
+ userCleanup = undefined;
2057
+ throw error;
2058
+ }
2059
+ }
2060
+ return () => {
2061
+ if (mountCount <= 0)
2062
+ return;
2063
+ mountCount--;
2064
+ if (mountCount === 0 && typeof userCleanup === "function") {
2065
+ const cleanup = userCleanup;
2066
+ userCleanup = undefined;
2067
+ cleanup();
2068
+ }
2069
+ };
2070
+ } : undefined;
816
2071
  const getSelf = () => globalStore.get(atom);
817
2072
  const setSelf = (newValue) => globalStore.set(atom, newValue);
818
2073
  const resetSelf = () => {
819
- value = undefined;
820
- initialized = false;
821
- for (const store2 of stores) {
822
- if (store2.stateDependencies.has(atom)) {
823
- throw new Error("TODO: Reset support for stateDependencies");
2074
+ const snapshot = [...stores];
2075
+ const subscribedStores = [];
2076
+ for (const s of snapshot) {
2077
+ if (isTransitivelySubscribed(atom, s)) {
2078
+ subscribedStores.push(s);
824
2079
  }
825
- store2.values.delete(atom);
826
- store2.expiredValues.delete(atom);
827
- propagateUpdatedAtoms([atom], store2);
2080
+ }
2081
+ let firstError;
2082
+ const recordError = (e) => {
2083
+ if (!firstError)
2084
+ firstError = e;
2085
+ };
2086
+ for (const s of snapshot) {
2087
+ try {
2088
+ unmountAtom(atom, s);
2089
+ } catch (e) {
2090
+ recordError(e);
2091
+ }
2092
+ }
2093
+ if (atom.maxAgeInterval) {
2094
+ atom.maxAgeInterval.cleanup();
2095
+ atom.maxAgeInterval.refCount = 0;
2096
+ atom.maxAgeInterval = undefined;
2097
+ }
2098
+ for (const store2 of snapshot) {
828
2099
  stores.delete(store2);
829
- onReset?.();
2100
+ store2.values.delete(atom);
2101
+ try {
2102
+ propagateUpdatedAtoms([atom], store2);
2103
+ } catch (e) {
2104
+ recordError(e);
2105
+ }
2106
+ }
2107
+ for (const s of subscribedStores) {
2108
+ stores.add(s);
2109
+ if (atom.maxAge && (s.subscriptions.get(atom)?.size ?? 0) > 0) {
2110
+ installMaxAgeTimer(atom, s);
2111
+ }
2112
+ try {
2113
+ mountAtom(atom, s);
2114
+ } catch (e) {
2115
+ recordError(e);
2116
+ }
830
2117
  }
2118
+ if (firstError)
2119
+ throw firstError;
2120
+ };
2121
+ const detach = (storeData) => {
2122
+ stores.delete(storeData);
831
2123
  };
832
2124
  const atom = {
833
2125
  equal,
834
2126
  ...options,
835
2127
  defaultValue,
836
- name: options?.name,
837
2128
  onInit,
838
2129
  onSet,
2130
+ onMount,
839
2131
  setSelf,
840
2132
  getSelf,
841
2133
  resetSelf,
2134
+ detach,
842
2135
  get stores() {
843
2136
  return stores;
844
- }
2137
+ },
2138
+ maxAgeInterval: undefined
845
2139
  };
846
2140
  return atom;
847
2141
  };
@@ -859,17 +2153,6 @@ function atom(defaultValue, options) {
859
2153
  ...options
860
2154
  };
861
2155
  }
862
- // src/lib/atomFamilyAtom.ts
863
- function atomFamilyAtom(defaultValue, options) {
864
- if (options.global) {
865
- return globalAtom(defaultValue, options);
866
- }
867
- return {
868
- ...options,
869
- defaultValue
870
- };
871
- }
872
-
873
2156
  // src/lib/stableStringify.ts
874
2157
  var stableStringifyRecurse = (x, key) => {
875
2158
  if (typeof x === "string" && !x.includes('"') && !x.includes("\\")) {
@@ -924,57 +2207,73 @@ var stableStringify = (x) => {
924
2207
  return stableStringifyRecurse(x);
925
2208
  };
926
2209
 
927
- // src/selector.ts
928
- var selector = (get, options) => {
929
- if (!options)
930
- return { equal, get };
931
- return { equal, ...options, get };
2210
+ // src/lib/stringifyFamilyArgs.ts
2211
+ var stringifyFamilyArgs = (args) => {
2212
+ return args.length === 1 ? stableStringify(args[0]) : stableStringify(args);
932
2213
  };
933
2214
 
934
- // src/lib/createAtomFamily.ts
935
- var createOptions = (options = {}, family, familyKey, keyStringified) => {
936
- if (options.name) {
937
- return {
938
- equal,
939
- ...options,
940
- name: options?.name + "_" + keyStringified,
941
- family,
942
- familyKey
943
- };
944
- } else {
945
- return { equal, ...options, family, familyKey };
2215
+ // src/lib/familyKey.ts
2216
+ var familyKey = (args) => {
2217
+ if (args.length === 1) {
2218
+ const a = args[0];
2219
+ const t = typeof a;
2220
+ if (t === "string" || t === "number" || t === "boolean")
2221
+ return a;
946
2222
  }
2223
+ return stringifyFamilyArgs(args);
947
2224
  };
948
- var handleDefaultValue = (defaultValue, key) => {
949
- if (isSelectorFamily(defaultValue))
950
- return defaultValue(key);
951
- if (typeof defaultValue === "function")
952
- return () => defaultValue(key);
953
- return defaultValue;
954
- };
2225
+
2226
+ // src/lib/createAtomFamily.ts
955
2227
  var createAtomFamily = (defaultValue, options) => {
956
2228
  const map = new Map;
957
- const keysAtom = atom(new Set);
958
- const atomFamily = Object.assign((key) => {
959
- const keyStringified = stableStringify(key);
960
- if (map.has(keyStringified)) {
961
- return map.get(keyStringified);
962
- }
963
- const familyAtom = atomFamilyAtom(handleDefaultValue(defaultValue, key), createOptions(options, atomFamily, Object.freeze(key), keyStringified));
964
- map.set(keyStringified, familyAtom);
2229
+ const isSelectorFamilyDefault = isSelectorFamily(defaultValue);
2230
+ const isFunctionDefault = !isSelectorFamilyDefault && typeof defaultValue === "function";
2231
+ const hasName = !!options?.name;
2232
+ const isGlobal = !!options?.global;
2233
+ const atomFamily = (...args) => {
2234
+ const key = familyKey(args);
2235
+ const cached = map.get(key);
2236
+ if (cached !== undefined)
2237
+ return cached;
2238
+ let dv;
2239
+ if (isSelectorFamilyDefault) {
2240
+ dv = defaultValue(...args);
2241
+ } else if (isFunctionDefault) {
2242
+ dv = () => defaultValue(...args);
2243
+ } else {
2244
+ dv = defaultValue;
2245
+ }
2246
+ const memberName = hasName ? options.name + "_" + key : undefined;
2247
+ let familyAtom;
2248
+ if (isGlobal) {
2249
+ familyAtom = globalAtom(dv, {
2250
+ ...options,
2251
+ name: memberName
2252
+ });
2253
+ } else {
2254
+ familyAtom = {
2255
+ equal,
2256
+ ...options,
2257
+ defaultValue: dv,
2258
+ name: memberName
2259
+ };
2260
+ }
2261
+ familyAtom.family = atomFamily;
2262
+ familyAtom.familyArgs = args;
2263
+ familyAtom.familyArgsStringified = key;
2264
+ map.set(key, familyAtom);
965
2265
  return familyAtom;
966
- }, {
967
- __valdresAtomFamilyMap: map,
968
- release: (key) => map.delete(key),
969
- __keysAtom: keysAtom,
970
- __keysSelector: selector((get) => Array.from(get(keysAtom)))
971
- });
972
- if (options?.name)
2266
+ };
2267
+ if (hasName)
973
2268
  Object.defineProperty(atomFamily, "name", {
974
2269
  value: options.name,
975
2270
  writable: false
976
2271
  });
977
- return atomFamily;
2272
+ return Object.assign(atomFamily, {
2273
+ __valdresAtomFamilyMap: map,
2274
+ release: (...args) => map.delete(familyKey(args)),
2275
+ equal
2276
+ });
978
2277
  };
979
2278
 
980
2279
  // src/lib/createGlobalAtomFamily.ts
@@ -995,49 +2294,100 @@ function atomFamily(defaultValue, options) {
995
2294
  return createGlobalAtomFamily(defaultValue, options);
996
2295
  return createAtomFamily(defaultValue, options);
997
2296
  }
998
- // src/createStoreWithSelectorSet.ts
999
- var setSelector = (selector2, values, store2) => {
1000
- return selector2.set(store2.set, store2.get, store2.reset, ...values);
1001
- };
1002
- var createStoreWithSelectorSet = (id) => {
1003
- const data = createStoreData(id);
1004
- const store2 = storeFromStoreData(data);
1005
- store2.set = (state, value, ...rest) => {
1006
- if (isAtom(state))
1007
- return setAtom(state, value, data);
1008
- if (isSelector(state))
1009
- return setSelector(state, [value, ...rest], store2);
1010
- throw new Error("Invalid state object");
2297
+ // src/selector.ts
2298
+ var selector = (get, options) => {
2299
+ if (get.constructor?.name === "AsyncFunction") {
2300
+ throw new Error("selector() does not accept async functions. " + "Use a sync function that returns a Promise instead.");
2301
+ }
2302
+ if (!options)
2303
+ return { equal, get };
2304
+ return { equal, ...options, get };
2305
+ };
2306
+
2307
+ // src/cacheMeta.ts
2308
+ var cacheMeta = (sourceAtom) => {
2309
+ if (sourceAtom.__cacheMetaSelector)
2310
+ return sourceAtom.__cacheMetaSelector;
2311
+ if (!sourceAtom.__cacheMeta) {
2312
+ sourceAtom.__cacheMeta = { equal, defaultValue: null };
2313
+ }
2314
+ sourceAtom.__cacheMetaSelector = selector((get) => get(sourceAtom.__cacheMeta));
2315
+ return sourceAtom.__cacheMetaSelector;
2316
+ };
2317
+ // src/indexConstructor.ts
2318
+ var index = (family, callback, options) => {
2319
+ const map = new Map;
2320
+ const index2 = (term) => {
2321
+ const termKey = stableStringify(term);
2322
+ if (map.has(termKey))
2323
+ return map.get(termKey);
2324
+ const termIndexSelectorSet = new Set;
2325
+ const termIndexSelectorMap = new Map;
2326
+ const termIndexSelector = selector((get) => {
2327
+ const allFamilyAtoms = new Set(get(family));
2328
+ const deletedAtoms = termIndexSelectorSet.symmetricDifference(allFamilyAtoms);
2329
+ const addedAtoms = allFamilyAtoms.difference(termIndexSelectorSet);
2330
+ if (deletedAtoms.size || addedAtoms.size) {
2331
+ deletedAtoms.forEach((atom2) => {
2332
+ termIndexSelectorSet.delete(atom2);
2333
+ termIndexSelectorMap.delete(atom2);
2334
+ });
2335
+ addedAtoms.forEach((atom2) => {
2336
+ termIndexSelectorSet.add(atom2);
2337
+ termIndexSelectorMap.set(atom2, selector((get2) => callback(get2(atom2), term), {
2338
+ name: `index:callback:selector:${atom2.name}`
2339
+ }));
2340
+ });
2341
+ return new Set(termIndexSelectorSet);
2342
+ } else {
2343
+ return termIndexSelectorSet;
2344
+ }
2345
+ }, { name: `index:${options?.name}(${termKey})` });
2346
+ const filteredSelector = selector((get) => {
2347
+ const set = get(termIndexSelector);
2348
+ const res = [];
2349
+ set.forEach((atom2) => {
2350
+ if (get(termIndexSelectorMap.get(atom2))) {
2351
+ res.push(atom2);
2352
+ }
2353
+ });
2354
+ return res;
2355
+ }, {
2356
+ name: `index:${options?.name}:${termKey}:termSelector`
2357
+ });
2358
+ map.set(termKey, filteredSelector);
2359
+ return filteredSelector;
1011
2360
  };
1012
- store2.kind = "storeWithSelectorSet";
1013
- return store2;
2361
+ return Object.assign(index2, {
2362
+ map,
2363
+ callback
2364
+ });
1014
2365
  };
1015
2366
  // src/selectorFamily.ts
1016
- var createOptions2 = (options = {}, family, familyKey, keyStringified) => {
1017
- if (options.name) {
1018
- return {
2367
+ var selectorFamily = (callback, options) => {
2368
+ const map = new Map;
2369
+ const hasName = !!options?.name;
2370
+ const selectorFamily2 = (...args) => {
2371
+ const key = familyKey(args);
2372
+ const cached = map.get(key);
2373
+ if (cached !== undefined)
2374
+ return cached;
2375
+ const get = (selectorArgs) => callback(...args)(selectorArgs);
2376
+ const newSelector = {
1019
2377
  equal,
1020
2378
  ...options,
1021
- name: options?.name + "_" + keyStringified,
1022
- family,
1023
- familyKey
2379
+ get,
2380
+ family: selectorFamily2,
2381
+ familyArgs: args,
2382
+ familyArgsStringified: key,
2383
+ name: hasName ? options.name + "_" + key : undefined
1024
2384
  };
1025
- } else {
1026
- return { equal, ...options, family, familyKey };
1027
- }
1028
- };
1029
- var selectorFamily = (get, options) => {
1030
- const map = new Map;
1031
- const selectorFamily2 = (key) => {
1032
- const keyStringified = stableStringify(key);
1033
- if (map.has(keyStringified))
1034
- return map.get(keyStringified);
1035
- const newSelector = selector((selectorArgs) => get(key)(selectorArgs), createOptions2(options, selectorFamily2, key, keyStringified));
1036
- map.set(keyStringified, newSelector);
2385
+ map.set(key, newSelector);
1037
2386
  return newSelector;
1038
2387
  };
1039
2388
  selectorFamily2.__valdresSelectorFamilyMap = map;
1040
- if (options?.name)
2389
+ selectorFamily2.release = (...args) => map.delete(familyKey(args));
2390
+ if (hasName)
1041
2391
  Object.defineProperty(selectorFamily2, "name", {
1042
2392
  value: options.name,
1043
2393
  writable: false
@@ -1049,14 +2399,15 @@ var isFamilySelector = (state) => isFamilyState(state) && isSelector(state);
1049
2399
 
1050
2400
  // src/index.ts
1051
2401
  if (globalThis.__valdres__) {
1052
- throw new Error(`Error! An instance of valdres is already loaded. Loaded: ${globalThis.__valdres__}. Attempted to load: ${version}`);
2402
+ throw new Error(`Error! An instance of valdres is already loaded. Loaded: ${globalThis.__valdres__}. Attempted to load: ${"1.0.0-beta.0"}`);
1053
2403
  } else {
1054
- globalThis.__valdres__ = version;
2404
+ globalThis.__valdres__ = "1.0.0-beta.0";
1055
2405
  }
1056
2406
  export {
1057
2407
  store,
1058
2408
  selectorFamily,
1059
2409
  selector,
2410
+ isSuspendError,
1060
2411
  isSelectorFamily,
1061
2412
  isSelector,
1062
2413
  isPromiseLike,
@@ -1066,8 +2417,11 @@ export {
1066
2417
  isFamily,
1067
2418
  isAtomFamily,
1068
2419
  isAtom,
2420
+ index,
1069
2421
  globalStore,
1070
- createStoreWithSelectorSet,
2422
+ deepFreeze,
2423
+ cacheMeta,
1071
2424
  atomFamily,
1072
- atom
2425
+ atom,
2426
+ Transaction
1073
2427
  };