valdres 0.2.0-alpha.5 → 0.2.0-alpha.50

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 (94) hide show
  1. package/dist/index.js +742 -274
  2. package/dist/{index.d.ts → types/index.d.ts} +15 -3
  3. package/dist/types/src/atom.d.ts +16 -0
  4. package/dist/types/src/atomFamily.d.ts +4 -0
  5. package/dist/types/src/createStoreWithSelectorSet.d.ts +2 -0
  6. package/dist/types/src/globalStore.d.ts +4 -0
  7. package/dist/types/src/lib/atomFamilyAtom.d.ts +8 -0
  8. package/dist/types/src/lib/createAtomFamily.d.ts +4 -0
  9. package/dist/types/src/lib/createGlobalAtomFamily.d.ts +5 -0
  10. package/dist/types/src/lib/createStoreData.d.ts +3 -0
  11. package/dist/types/src/lib/equal.d.ts +1 -0
  12. package/dist/types/src/lib/getState.d.ts +7 -0
  13. package/dist/types/src/lib/globalAtom.d.ts +4 -0
  14. package/dist/{src → types/src}/lib/initAtom.d.ts +2 -1
  15. package/dist/{src → types/src}/lib/initSelector.d.ts +1 -2
  16. package/dist/types/src/lib/propagateUpdatedAtoms.d.ts +4 -0
  17. package/dist/types/src/lib/setAtom.d.ts +3 -0
  18. package/dist/types/src/lib/storeFromStoreData.d.ts +4 -0
  19. package/dist/{src → types/src}/lib/subscribe.d.ts +1 -1
  20. package/dist/types/src/lib/transaction.d.ts +3 -0
  21. package/dist/types/src/lib/unsubscribe.d.ts +5 -0
  22. package/dist/{src → types/src}/lib/updateStateSubscribers.d.ts +1 -1
  23. package/dist/types/src/selector.d.ts +4 -0
  24. package/dist/types/src/selectorFamily.d.ts +4 -0
  25. package/dist/types/src/store.d.ts +1 -0
  26. package/dist/types/src/types/Atom.d.ts +14 -0
  27. package/dist/types/src/types/AtomDefaultValue.d.ts +2 -0
  28. package/dist/types/src/types/AtomFamily.d.ts +12 -0
  29. package/dist/types/src/types/AtomFamilyAtom.d.ts +6 -0
  30. package/dist/types/src/types/AtomFamilyDefaultValue.d.ts +5 -0
  31. package/dist/types/src/types/AtomFamilyGlobalAtom.d.ts +3 -0
  32. package/dist/types/src/types/AtomFamilySelector.d.ts +6 -0
  33. package/dist/types/src/types/AtomOnInit.d.ts +2 -0
  34. package/dist/types/src/types/AtomOnSet.d.ts +2 -0
  35. package/dist/types/src/types/AtomOptions.d.ts +13 -0
  36. package/dist/types/src/types/EqualFunc.d.ts +1 -0
  37. package/dist/{src → types/src}/types/Family.d.ts +1 -1
  38. package/dist/types/src/types/FamilyKey.d.ts +3 -0
  39. package/dist/types/src/types/GetValue.d.ts +8 -0
  40. package/dist/types/src/types/GlobalAtom.d.ts +11 -0
  41. package/dist/types/src/types/GlobalAtomGetSelfFunc.d.ts +1 -0
  42. package/dist/types/src/types/GlobalAtomResetSelfFunc.d.ts +1 -0
  43. package/dist/types/src/types/GlobalAtomSetSelfFunc.d.ts +1 -0
  44. package/dist/types/src/types/Selector.d.ts +11 -0
  45. package/dist/types/src/types/SelectorFamily.d.ts +6 -0
  46. package/dist/types/src/types/SelectorOptions.d.ts +5 -0
  47. package/dist/types/src/types/SetAtom.d.ts +3 -0
  48. package/dist/types/src/types/SetAtomValue.d.ts +1 -0
  49. package/dist/types/src/types/State.d.ts +4 -0
  50. package/dist/types/src/types/Store.d.ts +24 -0
  51. package/dist/{src → types/src}/types/StoreData.d.ts +9 -1
  52. package/dist/types/src/types/Subscription.d.ts +1 -0
  53. package/dist/types/src/types/TransactionFn.d.ts +2 -0
  54. package/dist/{src/types/Store.d.ts → types/src/types/TransactionInterface.d.ts} +4 -7
  55. package/dist/types/src/utils/isAtom.d.ts +2 -0
  56. package/dist/types/src/utils/isAtomFamily.d.ts +2 -0
  57. package/dist/types/src/utils/isFamily.d.ts +1 -0
  58. package/dist/types/src/utils/isFamilyAtom.d.ts +2 -0
  59. package/dist/types/src/utils/isFamilySelector.d.ts +2 -0
  60. package/dist/types/src/utils/isFamilyState.d.ts +3 -0
  61. package/dist/types/src/utils/isSelector.d.ts +2 -0
  62. package/dist/types/src/utils/isSelectorFamily.d.ts +2 -0
  63. package/package.json +12 -10
  64. package/dist/src/atom.d.ts +0 -9
  65. package/dist/src/atomFamily.d.ts +0 -4
  66. package/dist/src/createStore.d.ts +0 -2
  67. package/dist/src/getDefaultStore.d.ts +0 -2
  68. package/dist/src/lib/createStoreData.d.ts +0 -2
  69. package/dist/src/lib/getState.d.ts +0 -3
  70. package/dist/src/lib/propagateUpdatedAtoms.d.ts +0 -3
  71. package/dist/src/lib/setAtom.d.ts +0 -3
  72. package/dist/src/lib/storeFromStoreData.d.ts +0 -3
  73. package/dist/src/lib/transaction.d.ts +0 -8
  74. package/dist/src/lib/unsubscribe.d.ts +0 -3
  75. package/dist/src/selector.d.ts +0 -3
  76. package/dist/src/selectorFamily.d.ts +0 -2
  77. package/dist/src/types/Atom.d.ts +0 -10
  78. package/dist/src/types/AtomFamily.d.ts +0 -5
  79. package/dist/src/types/GetValue.d.ts +0 -2
  80. package/dist/src/types/Selector.d.ts +0 -8
  81. package/dist/src/types/SelectorFamily.d.ts +0 -5
  82. package/dist/src/types/SetAtom.d.ts +0 -2
  83. package/dist/src/types/State.d.ts +0 -3
  84. package/dist/src/types/TransactionFn.d.ts +0 -4
  85. package/dist/src/utils/isAtom.d.ts +0 -2
  86. package/dist/src/utils/isFamily.d.ts +0 -1
  87. package/dist/src/utils/isSelector.d.ts +0 -2
  88. /package/dist/{src → types/src}/lib/resetAtom.d.ts +0 -0
  89. /package/dist/{src → types/src}/lib/setAtoms.d.ts +0 -0
  90. /package/dist/{src → types/src}/lib/stableStringify.d.ts +0 -0
  91. /package/dist/{src → types/src}/lib/updateSelectorSubscribers.d.ts +0 -0
  92. /package/dist/{src → types/src}/types/ResetAtom.d.ts +0 -0
  93. /package/dist/{src → types/src}/types/SubscribeFn.d.ts +0 -0
  94. /package/dist/{src → types/src}/utils/isPromiseLike.d.ts +0 -0
package/dist/index.js CHANGED
@@ -1,108 +1,102 @@
1
- // src/atom.ts
2
- var atom = (defaultValue, options) => {
3
- if (!options)
4
- return { defaultValue };
5
- return {
6
- defaultValue,
7
- ...options
8
- };
9
- };
10
- // src/utils/isPromiseLike.ts
11
- var isPromiseLike = (object) => {
12
- return object && object.then && typeof object.then === "function";
13
- };
14
-
15
- // src/lib/stableStringify.ts
16
- var stableStringifyRecurse = (x, key) => {
17
- if (typeof x === "string" && !x.includes('"') && !x.includes("\\")) {
18
- return `"${x}"`;
19
- }
20
- switch (typeof x) {
21
- case "undefined":
22
- return "";
23
- case "boolean":
24
- return x ? "true" : "false";
25
- case "number":
26
- case "symbol":
27
- return String(x);
28
- case "string":
29
- return JSON.stringify(x);
30
- case "function":
31
- return `__FUNCTION(${x.toString()})__`;
32
- }
33
- if (x === null) {
34
- return "null";
35
- }
36
- if (typeof x !== "object") {
37
- return JSON.stringify(x) ?? "";
38
- }
39
- if (isPromiseLike(x)) {
40
- return "__PROMISE__";
41
- }
42
- if (Array.isArray(x)) {
43
- return `[${x.map((v, i) => stableStringifyRecurse(v, i.toString()))}]`;
44
- }
45
- if (typeof x.toJSON === "function") {
46
- return stableStringifyRecurse(x.toJSON(key), key);
47
- }
48
- if (x instanceof Map) {
49
- const obj = {};
50
- for (const [k, v] of x) {
51
- obj[typeof k === "string" ? k : stringify(k, opt)] = v;
1
+ // src/lib/equal.ts
2
+ var hasElementType = typeof Element !== "undefined";
3
+ var hasMap = typeof Map === "function";
4
+ var hasSet = typeof Set === "function";
5
+ var hasArrayBuffer = typeof ArrayBuffer === "function" && !!ArrayBuffer.isView;
6
+ var deepEqualFn = (a, b) => {
7
+ if (a === b)
8
+ return true;
9
+ if (a && b && typeof a == "object" && typeof b == "object") {
10
+ if (a.constructor !== b.constructor)
11
+ return false;
12
+ var length, i, keys;
13
+ if (Array.isArray(a)) {
14
+ length = a.length;
15
+ if (length != b.length)
16
+ return false;
17
+ for (i = length;i-- !== 0; )
18
+ if (!deepEqualFn(a[i], b[i]))
19
+ return false;
20
+ return true;
52
21
  }
53
- return stableStringifyRecurse(obj, key);
54
- }
55
- if (x instanceof Set) {
56
- return stableStringifyRecurse(Array.from(x).sort((a, b) => stableStringifyRecurse(a).localeCompare(stableStringifyRecurse(b))), key);
57
- }
58
- if (Symbol !== undefined && x[Symbol.iterator] != null && typeof x[Symbol.iterator] === "function") {
59
- return stableStringifyRecurse(Array.from(x), key);
22
+ var it;
23
+ if (hasMap && a instanceof Map && b instanceof Map) {
24
+ if (a.size !== b.size)
25
+ return false;
26
+ it = a.entries();
27
+ while (!(i = it.next()).done)
28
+ if (!b.has(i.value[0]))
29
+ return false;
30
+ it = a.entries();
31
+ while (!(i = it.next()).done)
32
+ if (!deepEqualFn(i.value[1], b.get(i.value[0])))
33
+ return false;
34
+ return true;
35
+ }
36
+ if (hasSet && a instanceof Set && b instanceof Set) {
37
+ if (a.size !== b.size)
38
+ return false;
39
+ it = a.entries();
40
+ while (!(i = it.next()).done)
41
+ if (!b.has(i.value[0]))
42
+ return false;
43
+ return true;
44
+ }
45
+ if (hasArrayBuffer && ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {
46
+ length = a.length;
47
+ if (length != b.length)
48
+ return false;
49
+ for (i = length;i-- !== 0; )
50
+ if (a[i] !== b[i])
51
+ return false;
52
+ return true;
53
+ }
54
+ if (a.constructor === RegExp)
55
+ return a.source === b.source && a.flags === b.flags;
56
+ if (a.valueOf !== Object.prototype.valueOf && typeof a.valueOf === "function" && typeof b.valueOf === "function")
57
+ return a.valueOf() === b.valueOf();
58
+ if (a.toString !== Object.prototype.toString && typeof a.toString === "function" && typeof b.toString === "function")
59
+ return a.toString() === b.toString();
60
+ keys = Object.keys(a);
61
+ length = keys.length;
62
+ if (length !== Object.keys(b).length)
63
+ return false;
64
+ for (i = length;i-- !== 0; )
65
+ if (!Object.prototype.hasOwnProperty.call(b, keys[i]))
66
+ return false;
67
+ if (hasElementType && a instanceof Element)
68
+ return false;
69
+ for (i = length;i-- !== 0; ) {
70
+ if ((keys[i] === "_owner" || keys[i] === "__v" || keys[i] === "__o") && a.$$typeof) {
71
+ continue;
72
+ }
73
+ if (!deepEqualFn(a[keys[i]], b[keys[i]]))
74
+ return false;
75
+ }
76
+ return true;
60
77
  }
61
- return `{${Object.keys(x).filter((k) => x[k] !== undefined).sort().map((k) => `${stableStringifyRecurse(k)}:${stableStringifyRecurse(x[k], k)}`).join(",")}}`;
78
+ return a !== a && b !== b;
62
79
  };
63
- var stableStringify = (x) => {
64
- if (typeof x === "string" || typeof x === "boolean" || typeof x === "number")
65
- return x;
66
- return stableStringifyRecurse(x);
67
- };
68
-
69
- // src/atomFamily.ts
70
- var atomFamily = (defaultValue, debugLabel) => {
71
- const map = new Map;
72
- const atomFamily2 = (key, defaultOverride) => {
73
- const keyStringified = stableStringify(key);
74
- if (map.has(keyStringified)) {
75
- return map.get(keyStringified);
80
+ var equal = (a, b) => {
81
+ try {
82
+ return deepEqualFn(a, b);
83
+ } catch (error) {
84
+ if ((error.message || "").match(/stack|recursion/i)) {
85
+ console.warn("react-fast-compare cannot handle circular refs");
86
+ return false;
76
87
  }
77
- const atomDebugLabel = debugLabel && debugLabel + "_" + keyStringified;
78
- const newAtom = atom(typeof defaultValue === "function" ? () => defaultValue(key) : defaultValue, {
79
- label: atomDebugLabel
80
- });
81
- newAtom.family = atomFamily2;
82
- newAtom.familyKey = Object.freeze(key);
83
- map.set(keyStringified, newAtom);
84
- return newAtom;
85
- };
86
- atomFamily2._map = map;
87
- return atomFamily2;
88
+ throw error;
89
+ }
88
90
  };
89
- // src/lib/createStoreData.ts
90
- var generateId = () => (Math.random() + 1).toString(36).substring(7);
91
- var createStoreData = (id = generateId()) => ({
92
- id,
93
- values: new WeakMap,
94
- expiredValues: new WeakMap,
95
- subscriptions: new WeakMap,
96
- subscriptionsRequireEqualCheck: new WeakMap,
97
- stateConsumers: new WeakMap,
98
- stateDependencies: new WeakMap
99
- });
100
91
 
101
92
  // src/utils/isAtom.ts
102
93
  var isAtom = (state) => Object.hasOwn(state, "defaultValue");
103
94
 
104
- // src/utils/isSelector.ts
105
- var isSelector = (state) => Object.hasOwn(state, "get");
95
+ // src/utils/isFamilyState.ts
96
+ var isFamilyState = (state) => state && Object.hasOwn(state, "family");
97
+
98
+ // src/utils/isFamilyAtom.ts
99
+ var isFamilyAtom = (state) => isFamilyState(state) && isAtom(state);
106
100
 
107
101
  // src/lib/updateStateSubscribers.ts
108
102
  var updateStateSubscribers = (state, data) => {
@@ -112,7 +106,7 @@ var updateStateSubscribers = (state, data) => {
112
106
  subscribtion.callback();
113
107
  }
114
108
  }
115
- if (state.family) {
109
+ if (isFamilyState(state)) {
116
110
  const familySubscriptions = data.subscriptions.get(state.family);
117
111
  if (familySubscriptions?.size) {
118
112
  for (const subscribtion of familySubscriptions) {
@@ -122,11 +116,119 @@ var updateStateSubscribers = (state, data) => {
122
116
  }
123
117
  };
124
118
 
125
- // src/lib/updateSelectorSubscribers.ts
126
- import equal2 from "fast-deep-equal";
119
+ // src/utils/isPromiseLike.ts
120
+ var isPromiseLike = (object) => {
121
+ return object && object.then && typeof object.then === "function";
122
+ };
123
+
124
+ // src/utils/isAtomFamily.ts
125
+ var isAtomFamily = (state) => state && Object.hasOwn(state, "__valdresAtomFamilyMap");
126
+
127
+ // src/utils/isSelector.ts
128
+ var isSelector = (state) => state && Object.hasOwn(state, "get");
129
+
130
+ // src/utils/isSelectorFamily.ts
131
+ var isSelectorFamily = (state) => state && Object.hasOwn(state, "__valdresSelectorFamilyMap");
132
+
133
+ // src/lib/setAtom.ts
134
+ var setAtom = (atom, newValue, data, skipOnSet = false) => {
135
+ const currentValue = getState(atom, data);
136
+ if (typeof newValue === "function") {
137
+ newValue = newValue(currentValue);
138
+ if (isPromiseLike(newValue) || isPromiseLike(currentValue))
139
+ throw new Error("Todo, how should we handle this?");
140
+ }
141
+ if (atom.equal(currentValue, newValue))
142
+ return;
143
+ data.values.set(atom, newValue);
144
+ if (atom.onSet && !skipOnSet)
145
+ atom.onSet(newValue, data);
146
+ if (currentValue?.__isEmptyAtomPromise__) {
147
+ currentValue.__resolveEmptyAtomPromise__(newValue);
148
+ }
149
+ propagateUpdatedAtoms([atom], data);
150
+ };
151
+
152
+ // src/lib/initAtom.ts
153
+ var getAtomInitValue = (atom, data) => {
154
+ if (atom.defaultValue === undefined) {
155
+ let promiseResolve;
156
+ const promise = new Promise((resolve) => {
157
+ promiseResolve = resolve;
158
+ });
159
+ promise.__isEmptyAtomPromise__ = true;
160
+ promise.__resolveEmptyAtomPromise__ = promiseResolve;
161
+ return promise;
162
+ } else if (typeof atom.defaultValue === "function") {
163
+ const value = atom.defaultValue();
164
+ if (isPromiseLike(value)) {
165
+ value.then((resolvedValue) => {
166
+ data.values.set(atom, resolvedValue);
167
+ propagateUpdatedAtoms([atom], data);
168
+ });
169
+ }
170
+ return value;
171
+ } else if (isSelector(atom.defaultValue)) {
172
+ return getState(atom.defaultValue, data);
173
+ } else {
174
+ return atom.defaultValue;
175
+ }
176
+ };
177
+ var initAtom = (atom, data) => {
178
+ let value = getAtomInitValue(atom, data);
179
+ data.values.set(atom, value);
180
+ if (isFamilyAtom(atom)) {
181
+ const currentKeySet = getState(atom.family.__keysAtom, data);
182
+ if (!currentKeySet.has(atom.familyKey)) {
183
+ const newSet = new Set(currentKeySet);
184
+ newSet.add(atom.familyKey);
185
+ setAtom(atom.family.__keysAtom, newSet, data);
186
+ }
187
+ }
188
+ if (atom.onInit)
189
+ atom.onInit((newVal) => {
190
+ value = newVal;
191
+ setAtom(atom, newVal, data, true);
192
+ }, data);
193
+ return value;
194
+ };
195
+
196
+ // src/lib/getState.ts
197
+ function getState(state, data, circularDependencySet) {
198
+ if (data.values.has(state))
199
+ return data.values.get(state);
200
+ if (isAtom(state)) {
201
+ if ("parent" in data)
202
+ return getState(state, data.parent, circularDependencySet);
203
+ return initAtom(state, data);
204
+ }
205
+ if (isSelector(state))
206
+ return initSelector(state, data, circularDependencySet);
207
+ if (isAtomFamily(state)) {
208
+ if ("parent" in data) {
209
+ const closestData = findClosestStoreWithAtomInitialized(state.__keysAtom, data);
210
+ return getState(state.__keysSelector, closestData, circularDependencySet);
211
+ }
212
+ return getState(state.__keysSelector, data, circularDependencySet);
213
+ }
214
+ if (isSelectorFamily(state)) {
215
+ const array = Array.from(state.__valdresSelectorFamilyMap.keys());
216
+ if (equal(array, state._keyArray))
217
+ return state._keyArray;
218
+ state._keyArray = array;
219
+ return array;
220
+ }
221
+ throw new Error("Invalid object passed to get");
222
+ }
223
+ var findClosestStoreWithAtomInitialized = (atom, data) => {
224
+ if ("parent" in data === false)
225
+ return data;
226
+ if (data.values.has(atom))
227
+ return data;
228
+ return findClosestStoreWithAtomInitialized(atom, data.parent);
229
+ };
127
230
 
128
231
  // src/lib/initSelector.ts
129
- import equal from "fast-deep-equal";
130
232
  class SuspendAndWaitForResolveError extends Error {
131
233
  promise;
132
234
  constructor(promise) {
@@ -134,6 +236,36 @@ class SuspendAndWaitForResolveError extends Error {
134
236
  this.promise = promise;
135
237
  }
136
238
  }
239
+ var generateSelectorTrace = (selectors) => {
240
+ const lastIndex = selectors.length - 1;
241
+ return [...selectors].reverse().map((selector, index) => {
242
+ const name = selector.name ?? "Anonymous Selector";
243
+ if (index === 0) {
244
+ return `[START] ${name}`;
245
+ } else if (index === lastIndex) {
246
+ return `[CRASH] ${name}`;
247
+ } else {
248
+ return ` ${" ".repeat(index)}${name}`;
249
+ }
250
+ }).join(`
251
+ `);
252
+ };
253
+
254
+ class CircularDependencyError extends Error {
255
+ selectors;
256
+ constructor() {
257
+ super();
258
+ this.selectors = [];
259
+ }
260
+ track(selector) {
261
+ this.selectors.push(selector);
262
+ }
263
+ get message() {
264
+ const firstSelectorName = this.selectors[0].name ?? "Anonymous Selector";
265
+ return `Circular dependency detected in '${firstSelectorName}'
266
+ ${generateSelectorTrace(this.selectors)}`;
267
+ }
268
+ }
137
269
  var getOrInitConsumersSet = (state, data) => {
138
270
  const set = data.stateConsumers.get(state);
139
271
  if (set)
@@ -142,18 +274,21 @@ var getOrInitConsumersSet = (state, data) => {
142
274
  data.stateConsumers.set(state, newSet);
143
275
  return newSet;
144
276
  };
145
- var evaluateSelector = (selector, data) => {
146
- const currentDependencies = data.stateDependencies.get(selector) ?? new Set;
277
+ var evaluateSelector = (selector, data, circularDependencyMap = new WeakSet) => {
147
278
  const updatedDependencies = new Set;
279
+ if (circularDependencyMap.has(selector)) {
280
+ throw new CircularDependencyError;
281
+ }
282
+ circularDependencyMap.add(selector);
148
283
  let result;
149
284
  try {
150
285
  result = selector.get((state) => {
151
- const value = getState2(state, data);
286
+ const value = getState(state, data, circularDependencyMap);
152
287
  updatedDependencies.add(state);
153
288
  if (isPromiseLike(value))
154
289
  throw new SuspendAndWaitForResolveError(value);
155
290
  return value;
156
- });
291
+ }, data.id);
157
292
  } catch (error) {
158
293
  if (error instanceof SuspendAndWaitForResolveError) {
159
294
  result = error;
@@ -161,6 +296,7 @@ var evaluateSelector = (selector, data) => {
161
296
  throw error;
162
297
  }
163
298
  }
299
+ const currentDependencies = data.stateDependencies.get(selector) ?? new Set;
164
300
  const added = updatedDependencies?.difference(currentDependencies);
165
301
  const removed = currentDependencies?.difference(updatedDependencies);
166
302
  for (const state of added) {
@@ -182,18 +318,26 @@ var handleSelectorResult = (value, selector, data) => {
182
318
  value.then((resolved) => {
183
319
  data.values.set(selector, resolved);
184
320
  updateStateSubscribers(selector, data);
321
+ console.log("Should we reEvaluate?");
185
322
  });
186
323
  return value;
187
324
  } else {
188
325
  return value;
189
326
  }
190
327
  };
191
- var initSelector = (selector, data) => {
192
- const tmpValue = evaluateSelector(selector, data);
328
+ var initSelector = (selector, data, circularDependencySet = new WeakSet) => {
329
+ let tmpValue;
330
+ try {
331
+ tmpValue = evaluateSelector(selector, data, circularDependencySet);
332
+ } catch (e) {
333
+ if (e instanceof CircularDependencyError)
334
+ e.track(selector);
335
+ throw e;
336
+ }
193
337
  const value = handleSelectorResult(tmpValue, selector, data);
194
338
  if (data.expiredValues.has(selector)) {
195
339
  const expiredValue = data.expiredValues.get(selector);
196
- if (equal(expiredValue, value)) {
340
+ if (selector.equal(expiredValue, value)) {
197
341
  data.values.set(selector, expiredValue);
198
342
  return expiredValue;
199
343
  }
@@ -208,11 +352,11 @@ var updateSelectorSubscribers = (selector, data) => {
208
352
  const familySubscriptions = selector.family && data.subscriptions.get(selector.family);
209
353
  if (!subscribtions?.size && !familySubscriptions?.size)
210
354
  return;
211
- if (subscribtions?.size && data.subscriptionsRequireEqualCheck.get(selector) || familySubscriptions?.size && data.subscriptionsRequireEqualCheck.get(selector.family)) {
355
+ if (subscribtions?.size && data.subscriptionsRequireEqualCheck.get(selector) || familySubscriptions?.size && selector.family && data.subscriptionsRequireEqualCheck.get(selector.family)) {
212
356
  try {
213
357
  const oldValue = data.expiredValues.get(selector);
214
358
  const newValue = initSelector(selector, data);
215
- if (equal2(newValue, oldValue))
359
+ if (selector.equal(newValue, oldValue))
216
360
  return;
217
361
  } catch (e) {
218
362
  }
@@ -245,13 +389,13 @@ var recursivlyResetSelectorTree = (selectors, data, clearedSelectors) => {
245
389
  };
246
390
  var propagateUpdatedAtoms = (atoms, data) => {
247
391
  const clearedSelectors = new Set;
248
- for (const atom3 of atoms) {
249
- const consumers = data.stateConsumers.get(atom3);
392
+ for (const atom of atoms) {
393
+ const consumers = data.stateConsumers.get(atom);
250
394
  if (consumers && consumers.size) {
251
395
  recursivlyResetSelectorTree(consumers, data, clearedSelectors);
252
396
  }
253
- if (atom3.family) {
254
- const consumersFamily = data.stateConsumers.get(atom3.family);
397
+ if (isFamilyAtom(atom)) {
398
+ const consumersFamily = data.stateConsumers.get(atom.family);
255
399
  if (consumersFamily?.size) {
256
400
  recursivlyResetSelectorTree(consumersFamily, data, clearedSelectors);
257
401
  }
@@ -260,94 +404,52 @@ var propagateUpdatedAtoms = (atoms, data) => {
260
404
  for (const selector of clearedSelectors) {
261
405
  updateSelectorSubscribers(selector, data);
262
406
  }
263
- for (const atom3 of atoms) {
264
- updateStateSubscribers(atom3, data);
407
+ for (const atom of atoms) {
408
+ updateStateSubscribers(atom, data);
265
409
  }
266
410
  };
267
411
 
268
- // src/lib/setAtom.ts
269
- import equal3 from "fast-deep-equal";
270
- var setAtom = (atom3, newValue, data) => {
271
- const currentValue = getState2(atom3, data);
272
- if (typeof newValue === "function") {
273
- newValue = newValue(currentValue);
274
- if (isPromiseLike(newValue) || isPromiseLike(currentValue))
275
- throw new Error("Todo, how should we handle this?");
276
- }
277
- if (equal3(currentValue, newValue))
278
- return;
279
- data.values.set(atom3, newValue);
280
- if (currentValue?.__isEmptyAtomPromise__) {
281
- currentValue.__resolveEmptyAtomPromise__(newValue);
282
- }
283
- propagateUpdatedAtoms([atom3], data);
412
+ // src/lib/createStoreData.ts
413
+ var generateId = () => (Math.random() + 1).toString(36).substring(7);
414
+ var generateStoreData = (id = generateId()) => {
415
+ return {
416
+ id,
417
+ values: new WeakMap,
418
+ expiredValues: new WeakMap,
419
+ subscriptions: new WeakMap,
420
+ subscriptionsRequireEqualCheck: new WeakMap,
421
+ stateConsumers: new WeakMap,
422
+ stateDependencies: new WeakMap,
423
+ scopes: {}
424
+ };
284
425
  };
285
-
286
- // src/lib/initAtom.ts
287
- var getAtomInitValue = (atom3, data) => {
288
- if (atom3.defaultValue === undefined) {
289
- let promiseResolve;
290
- const promise = new Promise((resolve) => {
291
- promiseResolve = resolve;
292
- });
293
- promise.__isEmptyAtomPromise__ = true;
294
- promise.__resolveEmptyAtomPromise__ = promiseResolve;
295
- return promise;
296
- } else if (typeof atom3.defaultValue === "function") {
297
- const value = atom3.defaultValue();
298
- if (isPromiseLike(value)) {
299
- value.then((resolvedValue) => {
300
- data.values.set(atom3, resolvedValue);
301
- propagateUpdatedAtoms([atom3], data);
302
- });
303
- }
304
- return value;
426
+ function createStoreData(id, parent) {
427
+ if (parent) {
428
+ return {
429
+ ...generateStoreData(id),
430
+ parent,
431
+ scopeConsumers: parent ? new Set : undefined
432
+ };
305
433
  } else {
306
- return atom3.defaultValue;
434
+ return generateStoreData(id);
307
435
  }
308
- };
309
- var initAtom = (atom3, data) => {
310
- const value = getAtomInitValue(atom3, data);
311
- data.values.set(atom3, value);
312
- if (atom3.onInit)
313
- atom3.onInit((newVal) => {
314
- setAtom(atom3, newVal, data);
315
- });
316
- return value;
317
- };
318
-
319
- // src/utils/isFamily.ts
320
- var isFamily = (state) => Object.hasOwn(state, "_map");
321
-
322
- // src/lib/getState.ts
323
- var getState2 = (state, data) => {
324
- if (data.values.has(state))
325
- return data.values.get(state);
326
- if (isAtom(state))
327
- return initAtom(state, data);
328
- if (isSelector(state))
329
- return initSelector(state, data);
330
- if (isFamily(state)) {
331
- const res = [];
332
- for (const atom3 of state._map.values()) {
333
- res.push([atom3.familyKey, getState2(atom3, data)]);
334
- }
335
- return res;
336
- }
337
- throw new Error("Invalid object passed to get");
338
- };
436
+ }
339
437
 
340
438
  // src/lib/resetAtom.ts
341
- var resetAtom = (atom3, data) => {
342
- const res = initAtom(atom3, data);
343
- if (!isPromiseLike(res)) {
344
- propagateUpdatedAtoms([atom3], data);
439
+ var resetAtom = (atom, data) => {
440
+ let value = getAtomInitValue(atom, data);
441
+ data.values.set(atom, value);
442
+ if (!isPromiseLike(value)) {
443
+ propagateUpdatedAtoms([atom], data);
345
444
  }
346
- return res;
445
+ return value;
347
446
  };
348
447
 
448
+ // src/utils/isFamily.ts
449
+ var isFamily = (state) => isAtomFamily(state) || isSelectorFamily(state);
450
+
349
451
  // src/lib/unsubscribe.ts
350
- var unsubscribe = (state, subscription, data, mount) => {
452
+ var unsubscribe = (state, subscription, data, mount, maxAgeCleanup) => {
351
453
  const subscribers = data.subscriptions.get(state);
352
454
  if (subscribers) {
353
455
  subscribers.delete(subscription);
@@ -363,10 +465,15 @@ var unsubscribe = (state, subscription, data, mount) => {
363
465
  data.subscriptionsRequireEqualCheck.delete(state);
364
466
  }
365
467
  }
468
+ if (subscribers.size === 0) {
469
+ if (maxAgeCleanup)
470
+ maxAgeCleanup();
471
+ data.subscriptions.delete(state);
472
+ }
366
473
  if (mount) {
367
474
  if (subscribers.size === mount.mountSubscriptions.size) {
368
- if (state.onUnmount) {
369
- state.onUnmount(mount.onMountRes);
475
+ if (typeof mount.onUnmount === "function") {
476
+ mount.onUnmount();
370
477
  }
371
478
  }
372
479
  }
@@ -380,10 +487,24 @@ var initSubscribers = (state, data) => {
380
487
  return set;
381
488
  };
382
489
  var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) => {
383
- const subscribers = data.subscriptions.get(state) || initSubscribers(state, data);
490
+ let parentUnsubscribe;
491
+ if ("parent" in data && !data.values.has(state) && isAtom(state)) {
492
+ const originalCallback = callback;
493
+ parentUnsubscribe = subscribe(state, originalCallback, requireDeepEqualCheckBeforeCallback, data.parent);
494
+ callback = () => {
495
+ if (parentUnsubscribe) {
496
+ parentUnsubscribe();
497
+ parentUnsubscribe = undefined;
498
+ }
499
+ originalCallback();
500
+ };
501
+ } else if (!data.values.has(state) && isAtom(state)) {
502
+ initAtom(state, data);
503
+ }
384
504
  if (isSelector(state) && !data.values.has(state)) {
385
505
  initSelector(state, data);
386
506
  }
507
+ const subscribers = data.subscriptions.get(state) || initSubscribers(state, data);
387
508
  let subscription;
388
509
  if (isFamily(state)) {
389
510
  subscription = {
@@ -399,34 +520,67 @@ var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) =>
399
520
  }
400
521
  subscribers.add(subscription);
401
522
  let mount;
402
- if (subscribers.size === 1 && state.onMount) {
403
- const store = storeFromStoreData2(data);
404
- const mountSubscriptions = new Set;
405
- const originalSub = store.sub;
406
- store.sub = (state2, callback2) => {
407
- mountSubscriptions.add(callback2);
408
- return originalSub(state2, callback2);
409
- };
410
- mount = {
411
- onMountRes: state.onMount(store, state),
412
- mountSubscriptions
413
- };
523
+ let maxAgeCleanup;
524
+ if (subscribers.size === 1) {
525
+ if (isAtom(state) && state.maxAge) {
526
+ let timeout;
527
+ const interval = setInterval(() => {
528
+ let value = getAtomInitValue(state, data);
529
+ if (isPromiseLike(value)) {
530
+ if (state.staleWhileRevalidate) {
531
+ const oldValue = data.values.get(state);
532
+ timeout = setTimeout(() => {
533
+ const nowValue = data.values.get(state);
534
+ console.log("todo", oldValue);
535
+ }, state.staleWhileRevalidate);
536
+ value.then((res) => clearTimeout(timeout));
537
+ }
538
+ } else {
539
+ data.values.set(state, value);
540
+ propagateUpdatedAtoms([state], data);
541
+ }
542
+ }, state.maxAge);
543
+ maxAgeCleanup = () => {
544
+ clearInterval(interval);
545
+ if (timeout)
546
+ clearTimeout(timeout);
547
+ };
548
+ }
549
+ if (state.onMount) {
550
+ const store = storeFromStoreData(data);
551
+ const mountSubscriptions = new Set;
552
+ const originalSub = store.sub;
553
+ store.sub = (state2, callback2) => {
554
+ mountSubscriptions.add(callback2);
555
+ return originalSub(state2, callback2);
556
+ };
557
+ mount = {
558
+ onUnmount: state.onMount(store, state),
559
+ mountSubscriptions
560
+ };
561
+ }
414
562
  }
415
563
  if (requireDeepEqualCheckBeforeCallback && data.subscriptionsRequireEqualCheck.get(state) !== true) {
416
564
  data.subscriptionsRequireEqualCheck.set(state, true);
417
565
  }
418
- return () => unsubscribe(state, subscription, data, mount);
566
+ return () => {
567
+ if (parentUnsubscribe) {
568
+ parentUnsubscribe();
569
+ }
570
+ unsubscribe(state, subscription, data, mount, maxAgeCleanup);
571
+ };
419
572
  };
420
573
 
421
574
  // src/lib/setAtoms.ts
422
- import equal4 from "fast-deep-equal";
423
575
  var setAtoms = (pairs, data) => {
424
576
  const updatedAtoms = [];
425
- for (let [atom3, value] of pairs) {
426
- const currentValue = getState2(atom3, data);
427
- if (!equal4(currentValue, value)) {
428
- updatedAtoms.push(atom3);
429
- data.values.set(atom3, value);
577
+ for (let [atom, value] of pairs) {
578
+ const currentValue = getState(atom, data);
579
+ if (!atom.equal(currentValue, value)) {
580
+ updatedAtoms.push(atom);
581
+ if (atom.onSet)
582
+ atom.onSet(value, data);
583
+ data.values.set(atom, value);
430
584
  }
431
585
  }
432
586
  propagateUpdatedAtoms(updatedAtoms, data);
@@ -453,14 +607,22 @@ var recursivlyResetTxnSelectorCache = (state, txnSubscribers, txnSelectorCache)
453
607
  }
454
608
  }
455
609
  };
456
- var transaction = (callback, data) => {
610
+ var captureScopedTransaction = (scopedData) => {
611
+ let txn;
612
+ transaction((scopedTxn) => {
613
+ txn = scopedTxn;
614
+ }, scopedData, false);
615
+ return txn;
616
+ };
617
+ var transaction = (callback, data, autoCommit = true) => {
457
618
  let txnAtomMap = new Map;
458
619
  let txnSelectorCache = new Map;
459
620
  let txnSubscribers = new Map;
460
621
  let dirtySelectors = new Set;
622
+ let scopedTransactions;
461
623
  const txnGet = (state) => {
462
624
  if (isAtom(state)) {
463
- return txnAtomMap.has(state) ? txnAtomMap.get(state) : getState2(state, data);
625
+ return txnAtomMap.has(state) ? txnAtomMap.get(state) : getState(state, data);
464
626
  } else if (isSelector(state)) {
465
627
  if (txnSelectorCache.has(state)) {
466
628
  return txnSelectorCache.get(state);
@@ -469,7 +631,7 @@ var transaction = (callback, data) => {
469
631
  const res = state.get((s) => {
470
632
  deps.add(s);
471
633
  return txnGet(s);
472
- });
634
+ }, data.id);
473
635
  for (const dep of deps) {
474
636
  if (!txnSubscribers.has(dep)) {
475
637
  txnSubscribers.set(dep, new Set);
@@ -478,119 +640,425 @@ var transaction = (callback, data) => {
478
640
  }
479
641
  txnSelectorCache.set(state, res);
480
642
  return res;
643
+ } else if (isFamily(state)) {
644
+ return txnAtomMap.has(state) ? txnAtomMap.get(state) : getState(state.__keysSelector, data);
481
645
  } else {
482
646
  throw new Error("Unsupported state");
483
647
  }
484
648
  };
485
- const txnSet = (atom3, value) => {
486
- if (!isAtom(atom3))
649
+ const txnSet = (atom, value) => {
650
+ if (!isAtom(atom))
487
651
  throw new Error("Not an atom");
488
652
  if (typeof value === "function") {
489
- const currentValue = txnGet(atom3);
653
+ const currentValue = txnGet(atom);
490
654
  value = value(currentValue);
491
655
  }
492
- for (const selector of findDependencies(atom3, data)) {
656
+ for (const selector of findDependencies(atom, data)) {
493
657
  dirtySelectors.add(selector);
494
658
  txnSelectorCache.delete(selector);
495
659
  }
496
- if (txnSubscribers.get(atom3)?.size) {
497
- recursivlyResetTxnSelectorCache(atom3, txnSubscribers, txnSelectorCache);
660
+ if (txnSubscribers.get(atom)?.size) {
661
+ recursivlyResetTxnSelectorCache(atom, txnSubscribers, txnSelectorCache);
498
662
  }
499
- txnAtomMap.set(atom3, value);
663
+ txnAtomMap.set(atom, value);
500
664
  };
501
- const txnReset = (atom3) => {
502
- const value = getAtomInitValue(atom3, data);
503
- txnAtomMap.set(atom3, value);
665
+ const txnReset = (atom) => {
666
+ const value = getAtomInitValue(atom, data);
667
+ txnAtomMap.set(atom, value);
504
668
  return value;
505
669
  };
506
670
  const commit = () => {
507
671
  setAtoms(txnAtomMap, data);
508
672
  dirtySelectors.clear();
673
+ if (scopedTransactions) {
674
+ for (const scopedTxn of Object.values(scopedTransactions)) {
675
+ scopedTxn.commit();
676
+ }
677
+ }
509
678
  };
510
- const result = callback(txnSet, txnGet, txnReset, commit);
511
- commit();
679
+ const result = callback({
680
+ set: txnSet,
681
+ get: txnGet,
682
+ reset: txnReset,
683
+ commit,
684
+ scope: (scopeId, callback2) => {
685
+ if (scopeId in data.scopes) {
686
+ const scopedData = data.scopes[scopeId];
687
+ if (scopedTransactions === undefined) {
688
+ scopedTransactions = {};
689
+ }
690
+ if (scopedTransactions[scopeId] === undefined) {
691
+ scopedTransactions[scopeId] = captureScopedTransaction(scopedData);
692
+ }
693
+ return callback2(scopedTransactions[scopeId]);
694
+ } else {
695
+ throw new Error(`Scope '${scopeId}' not found. Registered scopes: ${Object.keys(data.scopes).join(", ")}`);
696
+ }
697
+ }
698
+ });
699
+ if (autoCommit)
700
+ commit();
512
701
  return result;
513
702
  };
514
703
 
515
704
  // src/lib/storeFromStoreData.ts
516
- var storeFromStoreData2 = (data) => {
517
- const get = (state) => getState2(state, data);
705
+ var SelectorProvidedToSetError = `Invalid state object passed to set().
706
+ You provided a \`selector\`.
707
+ Only \`atom\` cam be set.
708
+ `;
709
+ var InvalidStateSetError = `Invalid state object passed to set().
710
+ Only \`atom\` can be set.
711
+ `;
712
+ function storeFromStoreData(data, detach) {
713
+ const get = (state) => getState(state, data);
518
714
  const set = (state, value) => {
519
- if (isAtom(state)) {
715
+ if (isAtom(state))
520
716
  return setAtom(state, value, data);
717
+ if (isSelector(state))
718
+ throw new Error(SelectorProvidedToSetError);
719
+ throw new Error(InvalidStateSetError);
720
+ };
721
+ const reset = (atom) => resetAtom(atom, data);
722
+ const sub = (state, callback, deepEqualCheckBeforeCallback = true) => subscribe(state, callback, deepEqualCheckBeforeCallback, data);
723
+ const txn = (callback) => transaction(callback, data);
724
+ const scope = (scopeId) => {
725
+ let scopedStoreData;
726
+ if (scopeId in data.scopes) {
727
+ scopedStoreData = data.scopes[scopeId];
521
728
  } else {
522
- if (isSelector(state)) {
523
- if (state.set) {
524
- txn((set2, get2) => state.set({ get: get2, set: set2 }, value));
525
- return;
526
- } else {
527
- throw new Error("set on selector is not supported");
729
+ scopedStoreData = createStoreData(scopeId, data);
730
+ data.scopes[scopeId] = scopedStoreData;
731
+ }
732
+ const detach2 = () => {
733
+ scopedStoreData.scopeConsumers.delete(detach2);
734
+ if (scopedStoreData.scopeConsumers.size === 0) {
735
+ delete data.scopes[scopeId];
736
+ }
737
+ };
738
+ scopedStoreData.scopeConsumers.add(detach2);
739
+ const newStore = storeFromStoreData(data.scopes[scopeId], detach2);
740
+ return newStore;
741
+ };
742
+ if (detach) {
743
+ return {
744
+ get,
745
+ set,
746
+ sub,
747
+ txn,
748
+ reset,
749
+ data,
750
+ scope,
751
+ detach
752
+ };
753
+ } else {
754
+ return {
755
+ get,
756
+ set,
757
+ sub,
758
+ txn,
759
+ reset,
760
+ data,
761
+ scope
762
+ };
763
+ }
764
+ }
765
+
766
+ // src/store.ts
767
+ var store = (id) => {
768
+ const data = createStoreData(id);
769
+ return storeFromStoreData(data);
770
+ };
771
+ // package.json
772
+ var version = "0.2.0-alpha.49";
773
+
774
+ // src/globalStore.ts
775
+ if (globalThis.__valdres__) {
776
+ throw new Error(`Error! An instance of valdres is already loaded`);
777
+ } else {
778
+ globalThis.__valdres__ = version;
779
+ }
780
+ var globalStore = Object.assign(store("valdres-global-store"), {
781
+ atoms: new Map,
782
+ atomFamilies: new Map
783
+ });
784
+
785
+ // src/lib/globalAtom.ts
786
+ var globalAtom = (defaultValue, options) => {
787
+ const stores = new Set;
788
+ let value;
789
+ let initialized = false;
790
+ let onReset;
791
+ if (options.onSet)
792
+ throw new Error("onSet on globalAtom is currently not supported");
793
+ const onInit = (setSelf2, data) => {
794
+ setSelf2(globalStore.get(atom));
795
+ if (!initialized && options.onInit) {
796
+ onReset = options.onInit((newVal) => {
797
+ setSelf2(newVal);
798
+ value = newVal;
799
+ }, data);
800
+ initialized = true;
801
+ }
802
+ stores.add(data);
803
+ };
804
+ const onSet = (newValue, currentStore) => {
805
+ value = newValue;
806
+ if (stores.size > 1) {
807
+ for (const store2 of stores) {
808
+ if (store2.id !== currentStore.id) {
809
+ setAtom(atom, value, store2, true);
528
810
  }
529
811
  }
530
- throw new Error("Invalid state object passed to set");
531
812
  }
532
813
  };
533
- const reset = (atom3) => resetAtom(atom3, data);
534
- const sub = (state, callback, deepEqualCheckBeforeCallback = true) => subscribe(state, callback, deepEqualCheckBeforeCallback, data);
535
- const txn = (callback) => transaction(callback, data);
814
+ const getSelf = () => globalStore.get(atom);
815
+ const setSelf = (newValue) => globalStore.set(atom, newValue);
816
+ const resetSelf = () => {
817
+ value = undefined;
818
+ initialized = false;
819
+ for (const store2 of stores) {
820
+ if (store2.stateDependencies.has(atom)) {
821
+ throw new Error("TODO: Reset support for stateDependencies");
822
+ }
823
+ store2.values.delete(atom);
824
+ store2.expiredValues.delete(atom);
825
+ propagateUpdatedAtoms([atom], store2);
826
+ stores.delete(store2);
827
+ onReset?.();
828
+ }
829
+ };
830
+ const atom = {
831
+ equal,
832
+ ...options,
833
+ defaultValue,
834
+ name: options?.name,
835
+ onInit,
836
+ onSet,
837
+ setSelf,
838
+ getSelf,
839
+ resetSelf,
840
+ get stores() {
841
+ return stores;
842
+ }
843
+ };
844
+ return atom;
845
+ };
846
+
847
+ // src/atom.ts
848
+ function atom(defaultValue, options) {
849
+ if (!options)
850
+ return { equal, defaultValue };
851
+ if (options.global) {
852
+ return globalAtom(defaultValue, options);
853
+ }
536
854
  return {
537
- get,
538
- set,
539
- sub,
540
- txn,
541
- reset,
542
- data
855
+ equal,
856
+ defaultValue,
857
+ ...options
543
858
  };
859
+ }
860
+ // src/lib/atomFamilyAtom.ts
861
+ function atomFamilyAtom(defaultValue, options) {
862
+ if (options.global) {
863
+ return globalAtom(defaultValue, options);
864
+ }
865
+ return {
866
+ ...options,
867
+ defaultValue
868
+ };
869
+ }
870
+
871
+ // src/lib/stableStringify.ts
872
+ var stableStringifyRecurse = (x, key) => {
873
+ if (typeof x === "string" && !x.includes('"') && !x.includes("\\")) {
874
+ return `"${x}"`;
875
+ }
876
+ switch (typeof x) {
877
+ case "undefined":
878
+ return "";
879
+ case "boolean":
880
+ return x ? "true" : "false";
881
+ case "number":
882
+ case "symbol":
883
+ return String(x);
884
+ case "string":
885
+ return JSON.stringify(x);
886
+ case "function":
887
+ return `__FUNCTION(${x.toString()})__`;
888
+ }
889
+ if (x === null) {
890
+ return "null";
891
+ }
892
+ if (typeof x !== "object") {
893
+ return JSON.stringify(x) ?? "";
894
+ }
895
+ if (isPromiseLike(x)) {
896
+ return "__PROMISE__";
897
+ }
898
+ if (Array.isArray(x)) {
899
+ return `[${x.map((v, i) => stableStringifyRecurse(v, i.toString()))}]`;
900
+ }
901
+ if (typeof x.toJSON === "function") {
902
+ return stableStringifyRecurse(x.toJSON(key), key);
903
+ }
904
+ if (x instanceof Map) {
905
+ const obj = {};
906
+ for (const [k, v] of x) {
907
+ obj[typeof k === "string" ? k : stringify(k, opt)] = v;
908
+ }
909
+ return stableStringifyRecurse(obj, key);
910
+ }
911
+ if (x instanceof Set) {
912
+ return stableStringifyRecurse(Array.from(x).sort((a, b) => stableStringifyRecurse(a).localeCompare(stableStringifyRecurse(b))), key);
913
+ }
914
+ if (Symbol !== undefined && x[Symbol.iterator] != null && typeof x[Symbol.iterator] === "function") {
915
+ return stableStringifyRecurse(Array.from(x), key);
916
+ }
917
+ return `{${Object.keys(x).filter((k) => x[k] !== undefined).sort().map((k) => `${stableStringifyRecurse(k)}:${stableStringifyRecurse(x[k], k)}`).join(",")}}`;
918
+ };
919
+ var stableStringify = (x) => {
920
+ if (typeof x === "string" || typeof x === "boolean" || typeof x === "number")
921
+ return x;
922
+ return stableStringifyRecurse(x);
544
923
  };
545
924
 
546
- // src/createStore.ts
547
- var createStore = (id) => {
548
- const data = createStoreData(id);
549
- return storeFromStoreData2(data);
925
+ // src/selector.ts
926
+ var selector = (get, options) => {
927
+ if (!options)
928
+ return { equal, get };
929
+ return { equal, ...options, get };
930
+ };
931
+
932
+ // src/lib/createAtomFamily.ts
933
+ var createOptions = (options = {}, family, familyKey, keyStringified) => {
934
+ if (options.name) {
935
+ return {
936
+ equal,
937
+ ...options,
938
+ name: options?.name + "_" + keyStringified,
939
+ family,
940
+ familyKey
941
+ };
942
+ } else {
943
+ return { equal, ...options, family, familyKey };
944
+ }
945
+ };
946
+ var handleDefaultValue = (defaultValue, key) => {
947
+ if (isSelectorFamily(defaultValue))
948
+ return defaultValue(key);
949
+ if (typeof defaultValue === "function")
950
+ return () => defaultValue(key);
951
+ return defaultValue;
952
+ };
953
+ var createAtomFamily = (defaultValue, options) => {
954
+ const map = new Map;
955
+ const keysAtom = atom(new Set);
956
+ const atomFamily = Object.assign((key) => {
957
+ const keyStringified = stableStringify(key);
958
+ if (map.has(keyStringified)) {
959
+ return map.get(keyStringified);
960
+ }
961
+ const familyAtom = atomFamilyAtom(handleDefaultValue(defaultValue, key), createOptions(options, atomFamily, Object.freeze(key), keyStringified));
962
+ map.set(keyStringified, familyAtom);
963
+ return familyAtom;
964
+ }, {
965
+ __valdresAtomFamilyMap: map,
966
+ release: (key) => map.delete(key),
967
+ __keysAtom: keysAtom,
968
+ __keysSelector: selector((get) => Array.from(get(keysAtom)))
969
+ });
970
+ if (options?.name)
971
+ Object.defineProperty(atomFamily, "name", {
972
+ value: options.name,
973
+ writable: false
974
+ });
975
+ return atomFamily;
976
+ };
977
+
978
+ // src/lib/createGlobalAtomFamily.ts
979
+ var createGlobalAtomFamily = (defaultValue, options) => {
980
+ if (!options.name)
981
+ throw new Error(`Missing name for global atomFamiliy`);
982
+ if (globalStore.atomFamilies.has(options.name)) {
983
+ return globalStore.atomFamilies.get(options.name);
984
+ }
985
+ const family = createAtomFamily(defaultValue, options);
986
+ globalStore.atomFamilies.set(options.name, family);
987
+ return family;
550
988
  };
551
- // src/getDefaultStore.ts
552
- if (!globalThis._valdresStore) {
553
- globalThis._valdresStore = createStore("default");
989
+
990
+ // src/atomFamily.ts
991
+ function atomFamily(defaultValue, options) {
992
+ if (options?.global)
993
+ return createGlobalAtomFamily(defaultValue, options);
994
+ return createAtomFamily(defaultValue, options);
554
995
  }
555
- var getDefaultStore = () => globalThis._valdresStore;
556
- var resetDefaultStore = () => globalThis._valdresStore = createStore();
557
- // src/selector.ts
558
- var selector = (get, debugLabel) => ({
559
- get,
560
- debugLabel
561
- });
996
+ // src/createStoreWithSelectorSet.ts
997
+ var setSelector = (selector2, values, store2) => {
998
+ return selector2.set(store2.set, store2.get, store2.reset, ...values);
999
+ };
1000
+ var createStoreWithSelectorSet = (id) => {
1001
+ const data = createStoreData(id);
1002
+ const store2 = storeFromStoreData(data);
1003
+ store2.set = (state, value, ...rest) => {
1004
+ if (isAtom(state))
1005
+ return setAtom(state, value, data);
1006
+ if (isSelector(state))
1007
+ return setSelector(state, [value, ...rest], store2);
1008
+ throw new Error("Invalid state object");
1009
+ };
1010
+ store2.kind = "storeWithSelectorSet";
1011
+ return store2;
1012
+ };
562
1013
  // src/selectorFamily.ts
563
- var selectorFamily = (get, debugLabel) => {
1014
+ var createOptions2 = (options = {}, family, familyKey, keyStringified) => {
1015
+ if (options.name) {
1016
+ return {
1017
+ equal,
1018
+ ...options,
1019
+ name: options?.name + "_" + keyStringified,
1020
+ family,
1021
+ familyKey
1022
+ };
1023
+ } else {
1024
+ return { equal, ...options, family, familyKey };
1025
+ }
1026
+ };
1027
+ var selectorFamily = (get, options) => {
564
1028
  const map = new Map;
565
1029
  const selectorFamily2 = (key) => {
566
- let keyStringified;
567
- try {
568
- keyStringified = stableStringify(key);
569
- } catch (e) {
570
- console.log(`errro`, { key, debugLabel, e });
571
- throw e;
572
- }
1030
+ const keyStringified = stableStringify(key);
573
1031
  if (map.has(keyStringified))
574
1032
  return map.get(keyStringified);
575
- const selectorDebugLabel = debugLabel ? debugLabel + "_" + keyStringified : undefined;
576
- const newSelector = selector((selectorArgs) => get(key)(selectorArgs), selectorDebugLabel);
577
- newSelector.family = selectorFamily2;
1033
+ const newSelector = selector((selectorArgs) => get(key)(selectorArgs), createOptions2(options, selectorFamily2, key, keyStringified));
578
1034
  map.set(keyStringified, newSelector);
579
1035
  return newSelector;
580
1036
  };
581
- selectorFamily2._map = map;
1037
+ selectorFamily2.__valdresSelectorFamilyMap = map;
1038
+ if (options?.name)
1039
+ Object.defineProperty(selectorFamily2, "name", {
1040
+ value: options.name,
1041
+ writable: false
1042
+ });
582
1043
  return selectorFamily2;
583
1044
  };
1045
+ // src/utils/isFamilySelector.ts
1046
+ var isFamilySelector = (state) => isFamilyState(state) && isSelector(state);
584
1047
  export {
1048
+ store,
585
1049
  selectorFamily,
586
1050
  selector,
587
- resetDefaultStore,
1051
+ isSelectorFamily,
588
1052
  isSelector,
589
1053
  isPromiseLike,
1054
+ isFamilyState,
1055
+ isFamilySelector,
1056
+ isFamilyAtom,
590
1057
  isFamily,
1058
+ isAtomFamily,
591
1059
  isAtom,
592
- getDefaultStore,
593
- createStore,
1060
+ globalStore,
1061
+ createStoreWithSelectorSet,
594
1062
  atomFamily,
595
1063
  atom
596
1064
  };