valdres 0.2.0-alpha.6 → 0.2.0-alpha.61

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