valdres 0.2.0-alpha.6 → 0.2.0-alpha.60

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 +760 -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 +4 -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;
305
- }
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;
441
+ return generateStoreData(id);
337
442
  }
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,27 @@ 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, parentGet) => {
618
+ let txn;
619
+ transaction((scopedTxn) => {
620
+ txn = scopedTxn;
621
+ }, scopedData, false, parentGet);
622
+ return txn;
623
+ };
624
+ var transaction = (callback, data, autoCommit = true, parentScopeGet) => {
625
+ const txnAtomMap = new Map;
626
+ const txnSelectorCache = new Map;
627
+ const txnSubscribers = new Map;
628
+ const dirtySelectors = new Set;
629
+ let scopedTransactions;
462
630
  const txnGet = (state) => {
463
631
  if (isAtom(state)) {
464
- return txnAtomMap.has(state) ? txnAtomMap.get(state) : getState2(state, data);
632
+ if (txnAtomMap.has(state)) {
633
+ return txnAtomMap.get(state);
634
+ } else if (parentScopeGet) {
635
+ return parentScopeGet(state);
636
+ }
637
+ return getState(state, data);
465
638
  } else if (isSelector(state)) {
466
639
  if (txnSelectorCache.has(state)) {
467
640
  return txnSelectorCache.get(state);
@@ -470,7 +643,7 @@ var transaction = (callback, data) => {
470
643
  const res = state.get((s) => {
471
644
  deps.add(s);
472
645
  return txnGet(s);
473
- });
646
+ }, data.id);
474
647
  for (const dep of deps) {
475
648
  if (!txnSubscribers.has(dep)) {
476
649
  txnSubscribers.set(dep, new Set);
@@ -479,127 +652,435 @@ var transaction = (callback, data) => {
479
652
  }
480
653
  txnSelectorCache.set(state, res);
481
654
  return res;
655
+ } else if (isAtomFamily(state)) {
656
+ return txnGet(state.__keysSelector);
482
657
  } else {
483
658
  throw new Error("Unsupported state");
484
659
  }
485
660
  };
486
- const txnSet = (atom3, value) => {
487
- if (!isAtom(atom3))
661
+ const txnSet = (atom, value) => {
662
+ if (!isAtom(atom))
488
663
  throw new Error("Not an atom");
489
- if (typeof value === "function") {
490
- const currentValue = txnGet(atom3);
664
+ if (isFunction(value)) {
665
+ const currentValue = txnGet(atom);
491
666
  value = value(currentValue);
492
667
  }
493
- for (const selector of findDependencies(atom3, data)) {
668
+ for (const selector of findDependencies(atom, data)) {
494
669
  dirtySelectors.add(selector);
495
670
  txnSelectorCache.delete(selector);
496
671
  }
497
- if (txnSubscribers.get(atom3)?.size) {
498
- recursivlyResetTxnSelectorCache(atom3, txnSubscribers, txnSelectorCache);
672
+ if (txnSubscribers.get(atom)?.size) {
673
+ recursivlyResetTxnSelectorCache(atom, txnSubscribers, txnSelectorCache);
674
+ }
675
+ txnAtomMap.set(atom, value);
676
+ if (isFamilyAtom(atom)) {
677
+ const currentKeySet = txnGet(atom.family.__keysAtom);
678
+ if (!currentKeySet.has(atom.familyKey)) {
679
+ const newSet = new Set(currentKeySet);
680
+ newSet.add(atom.familyKey);
681
+ txnSet(atom.family.__keysAtom, newSet);
682
+ }
499
683
  }
500
- txnAtomMap.set(atom3, value);
684
+ return value;
501
685
  };
502
- const txnReset = (atom3) => {
503
- const value = getAtomInitValue(atom3, data);
504
- txnAtomMap.set(atom3, value);
686
+ const txnReset = (atom) => {
687
+ const value = getAtomInitValue(atom, data);
688
+ txnAtomMap.set(atom, value);
505
689
  return value;
506
690
  };
507
691
  const commit = () => {
508
692
  setAtoms(txnAtomMap, data);
509
693
  dirtySelectors.clear();
694
+ if (scopedTransactions) {
695
+ for (const scopedTxn of Object.values(scopedTransactions)) {
696
+ scopedTxn.commit();
697
+ }
698
+ }
510
699
  };
511
- const result = callback(txnSet, txnGet, txnReset, commit);
512
- commit();
700
+ const result = callback({
701
+ set: txnSet,
702
+ get: txnGet,
703
+ reset: txnReset,
704
+ commit,
705
+ scope: (scopeId, callback2) => {
706
+ if (scopeId in data.scopes) {
707
+ const scopedData = data.scopes[scopeId];
708
+ if (scopedTransactions === undefined) {
709
+ scopedTransactions = {};
710
+ }
711
+ if (scopedTransactions[scopeId] === undefined) {
712
+ scopedTransactions[scopeId] = captureScopedTransaction(scopedData, txnGet);
713
+ }
714
+ return callback2(scopedTransactions[scopeId]);
715
+ } else {
716
+ throw new Error(`Scope '${scopeId}' not found. Registered scopes: ${Object.keys(data.scopes).join(", ")}`);
717
+ }
718
+ },
719
+ data
720
+ });
721
+ if (autoCommit)
722
+ commit();
513
723
  return result;
514
724
  };
515
725
 
516
726
  // src/lib/storeFromStoreData.ts
517
- var storeFromStoreData2 = (data) => {
518
- const get = (state) => getState2(state, data);
727
+ var SelectorProvidedToSetError = `Invalid state object passed to set().
728
+ You provided a \`selector\`.
729
+ Only \`atom\` cam be set.
730
+ `;
731
+ var InvalidStateSetError = `Invalid state object passed to set().
732
+ Only \`atom\` can be set.
733
+ `;
734
+ function storeFromStoreData(data, detach) {
735
+ const get = (state) => getState(state, data);
519
736
  const set = (state, value) => {
520
- if (!isAtom(state))
521
- throw new Error("Invalid state object");
522
- return setAtom(state, value, data);
737
+ if (isAtom(state))
738
+ return setAtom(state, value, data);
739
+ if (isSelector(state))
740
+ throw new Error(SelectorProvidedToSetError);
741
+ throw new Error(InvalidStateSetError);
523
742
  };
524
- const reset = (atom3) => resetAtom(atom3, data);
743
+ const reset = (atom) => resetAtom(atom, data);
525
744
  const sub = (state, callback, deepEqualCheckBeforeCallback = true) => subscribe(state, callback, deepEqualCheckBeforeCallback, data);
526
745
  const txn = (callback) => transaction(callback, data);
746
+ const scope = (scopeId) => {
747
+ let scopedStoreData;
748
+ if (scopeId in data.scopes) {
749
+ scopedStoreData = data.scopes[scopeId];
750
+ } else {
751
+ scopedStoreData = createStoreData(scopeId, data);
752
+ data.scopes[scopeId] = scopedStoreData;
753
+ }
754
+ const detach2 = () => {
755
+ scopedStoreData.scopeConsumers.delete(detach2);
756
+ if (scopedStoreData.scopeConsumers.size === 0) {
757
+ delete data.scopes[scopeId];
758
+ }
759
+ };
760
+ scopedStoreData.scopeConsumers.add(detach2);
761
+ const newStore = storeFromStoreData(data.scopes[scopeId], detach2);
762
+ return newStore;
763
+ };
764
+ if (detach) {
765
+ return {
766
+ get,
767
+ set,
768
+ sub,
769
+ txn,
770
+ reset,
771
+ data,
772
+ scope,
773
+ detach
774
+ };
775
+ } else {
776
+ return {
777
+ get,
778
+ set,
779
+ sub,
780
+ txn,
781
+ reset,
782
+ data,
783
+ scope
784
+ };
785
+ }
786
+ }
787
+
788
+ // src/store.ts
789
+ var store = (id) => {
790
+ const data = createStoreData(id);
791
+ return storeFromStoreData(data);
792
+ };
793
+
794
+ // src/globalStore.ts
795
+ var globalStore = Object.assign(store("valdres-global-store"), {
796
+ atoms: new Map,
797
+ atomFamilies: new Map
798
+ });
799
+
800
+ // src/lib/globalAtom.ts
801
+ var globalAtom = (defaultValue, options) => {
802
+ const stores = new Set;
803
+ let value;
804
+ let initialized = false;
805
+ let onReset;
806
+ if (options.onSet)
807
+ throw new Error("onSet on globalAtom is currently not supported");
808
+ const onInit = (setSelf2, data) => {
809
+ setSelf2(globalStore.get(atom));
810
+ if (!initialized && options.onInit) {
811
+ onReset = options.onInit((newVal) => {
812
+ setSelf2(newVal);
813
+ value = newVal;
814
+ }, data);
815
+ initialized = true;
816
+ }
817
+ stores.add(data);
818
+ };
819
+ const onSet = (newValue, currentStore) => {
820
+ value = newValue;
821
+ if (stores.size > 1) {
822
+ for (const store2 of stores) {
823
+ if (store2.id !== currentStore.id) {
824
+ setAtom(atom, value, store2, true);
825
+ }
826
+ }
827
+ }
828
+ };
829
+ const getSelf = () => globalStore.get(atom);
830
+ const setSelf = (newValue) => globalStore.set(atom, newValue);
831
+ const resetSelf = () => {
832
+ value = undefined;
833
+ initialized = false;
834
+ for (const store2 of stores) {
835
+ if (store2.stateDependencies.has(atom)) {
836
+ throw new Error("TODO: Reset support for stateDependencies");
837
+ }
838
+ store2.values.delete(atom);
839
+ store2.expiredValues.delete(atom);
840
+ propagateUpdatedAtoms([atom], store2);
841
+ stores.delete(store2);
842
+ onReset?.();
843
+ }
844
+ };
845
+ const atom = {
846
+ equal,
847
+ ...options,
848
+ defaultValue,
849
+ name: options?.name,
850
+ onInit,
851
+ onSet,
852
+ setSelf,
853
+ getSelf,
854
+ resetSelf,
855
+ get stores() {
856
+ return stores;
857
+ }
858
+ };
859
+ return atom;
860
+ };
861
+
862
+ // src/atom.ts
863
+ function atom(defaultValue, options) {
864
+ if (!options)
865
+ return { equal, defaultValue };
866
+ if (options.global) {
867
+ return globalAtom(defaultValue, options);
868
+ }
527
869
  return {
528
- get,
529
- set,
530
- sub,
531
- txn,
532
- reset,
533
- data
870
+ equal,
871
+ defaultValue,
872
+ ...options
873
+ };
874
+ }
875
+ // src/lib/atomFamilyAtom.ts
876
+ function atomFamilyAtom(defaultValue, options) {
877
+ if (options.global) {
878
+ return globalAtom(defaultValue, options);
879
+ }
880
+ return {
881
+ ...options,
882
+ defaultValue
534
883
  };
884
+ }
885
+
886
+ // src/lib/stableStringify.ts
887
+ var stableStringifyRecurse = (x, key) => {
888
+ if (typeof x === "string" && !x.includes('"') && !x.includes("\\")) {
889
+ return `"${x}"`;
890
+ }
891
+ switch (typeof x) {
892
+ case "undefined":
893
+ return "";
894
+ case "boolean":
895
+ return x ? "true" : "false";
896
+ case "number":
897
+ case "symbol":
898
+ return String(x);
899
+ case "string":
900
+ return JSON.stringify(x);
901
+ case "function":
902
+ return `__FUNCTION(${x.toString()})__`;
903
+ }
904
+ if (x === null) {
905
+ return "null";
906
+ }
907
+ if (typeof x !== "object") {
908
+ return JSON.stringify(x) ?? "";
909
+ }
910
+ if (isPromiseLike(x)) {
911
+ return "__PROMISE__";
912
+ }
913
+ if (Array.isArray(x)) {
914
+ return `[${x.map((v, i) => stableStringifyRecurse(v, i.toString()))}]`;
915
+ }
916
+ if (typeof x.toJSON === "function") {
917
+ return stableStringifyRecurse(x.toJSON(key), key);
918
+ }
919
+ if (x instanceof Map) {
920
+ const obj = {};
921
+ for (const [k, v] of x) {
922
+ obj[typeof k === "string" ? k : stringify(k, opt)] = v;
923
+ }
924
+ return stableStringifyRecurse(obj, key);
925
+ }
926
+ if (x instanceof Set) {
927
+ return stableStringifyRecurse(Array.from(x).sort((a, b) => stableStringifyRecurse(a).localeCompare(stableStringifyRecurse(b))), key);
928
+ }
929
+ if (Symbol !== undefined && x[Symbol.iterator] != null && typeof x[Symbol.iterator] === "function") {
930
+ return stableStringifyRecurse(Array.from(x), key);
931
+ }
932
+ return `{${Object.keys(x).filter((k) => x[k] !== undefined).sort().map((k) => `${stableStringifyRecurse(k)}:${stableStringifyRecurse(x[k], k)}`).join(",")}}`;
933
+ };
934
+ var stableStringify = (x) => {
935
+ if (typeof x === "string" || typeof x === "boolean" || typeof x === "number")
936
+ return x;
937
+ return stableStringifyRecurse(x);
535
938
  };
536
939
 
537
- // src/createStore.ts
538
- var createStore = (id) => {
539
- const data = createStoreData(id);
540
- return storeFromStoreData2(data);
940
+ // src/selector.ts
941
+ var selector = (get, options) => {
942
+ if (!options)
943
+ return { equal, get };
944
+ return { equal, ...options, get };
541
945
  };
946
+
947
+ // src/lib/createAtomFamily.ts
948
+ var createOptions = (options = {}, family, familyKey, keyStringified) => {
949
+ if (options.name) {
950
+ return {
951
+ equal,
952
+ ...options,
953
+ name: options?.name + "_" + keyStringified,
954
+ family,
955
+ familyKey
956
+ };
957
+ } else {
958
+ return { equal, ...options, family, familyKey };
959
+ }
960
+ };
961
+ var handleDefaultValue = (defaultValue, key) => {
962
+ if (isSelectorFamily(defaultValue))
963
+ return defaultValue(key);
964
+ if (typeof defaultValue === "function")
965
+ return () => defaultValue(key);
966
+ return defaultValue;
967
+ };
968
+ var createAtomFamily = (defaultValue, options) => {
969
+ const map = new Map;
970
+ const keysAtom = atom(new Set);
971
+ const atomFamily = Object.assign((key) => {
972
+ const keyStringified = stableStringify(key);
973
+ if (map.has(keyStringified)) {
974
+ return map.get(keyStringified);
975
+ }
976
+ const familyAtom = atomFamilyAtom(handleDefaultValue(defaultValue, key), createOptions(options, atomFamily, Object.freeze(key), keyStringified));
977
+ map.set(keyStringified, familyAtom);
978
+ return familyAtom;
979
+ }, {
980
+ __valdresAtomFamilyMap: map,
981
+ release: (key) => map.delete(key),
982
+ __keysAtom: keysAtom,
983
+ __keysSelector: selector((get) => Array.from(get(keysAtom)))
984
+ });
985
+ if (options?.name)
986
+ Object.defineProperty(atomFamily, "name", {
987
+ value: options.name,
988
+ writable: false
989
+ });
990
+ return atomFamily;
991
+ };
992
+
993
+ // src/lib/createGlobalAtomFamily.ts
994
+ var createGlobalAtomFamily = (defaultValue, options) => {
995
+ if (!options.name)
996
+ throw new Error(`Missing name for global atomFamiliy`);
997
+ if (globalStore.atomFamilies.has(options.name)) {
998
+ return globalStore.atomFamilies.get(options.name);
999
+ }
1000
+ const family = createAtomFamily(defaultValue, options);
1001
+ globalStore.atomFamilies.set(options.name, family);
1002
+ return family;
1003
+ };
1004
+
1005
+ // src/atomFamily.ts
1006
+ function atomFamily(defaultValue, options) {
1007
+ if (options?.global)
1008
+ return createGlobalAtomFamily(defaultValue, options);
1009
+ return createAtomFamily(defaultValue, options);
1010
+ }
542
1011
  // src/createStoreWithSelectorSet.ts
543
- var setSelector = (selector, values, store) => {
544
- return selector.set(store.set, store.get, store.reset, ...values);
1012
+ var setSelector = (selector2, values, store2) => {
1013
+ return selector2.set(store2.set, store2.get, store2.reset, ...values);
545
1014
  };
546
1015
  var createStoreWithSelectorSet = (id) => {
547
1016
  const data = createStoreData(id);
548
- const store = storeFromStoreData2(data);
549
- store.set = (state, value, ...rest) => {
1017
+ const store2 = storeFromStoreData(data);
1018
+ store2.set = (state, value, ...rest) => {
550
1019
  if (isAtom(state))
551
1020
  return setAtom(state, value, data);
552
1021
  if (isSelector(state))
553
- return setSelector(state, [value, ...rest], store);
1022
+ return setSelector(state, [value, ...rest], store2);
554
1023
  throw new Error("Invalid state object");
555
1024
  };
556
- store.kind = "storeWithSelectorSet";
557
- return store;
1025
+ store2.kind = "storeWithSelectorSet";
1026
+ return store2;
558
1027
  };
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
1028
  // src/selectorFamily.ts
571
- var selectorFamily = (get, debugLabel) => {
1029
+ var createOptions2 = (options = {}, family, familyKey, keyStringified) => {
1030
+ if (options.name) {
1031
+ return {
1032
+ equal,
1033
+ ...options,
1034
+ name: options?.name + "_" + keyStringified,
1035
+ family,
1036
+ familyKey
1037
+ };
1038
+ } else {
1039
+ return { equal, ...options, family, familyKey };
1040
+ }
1041
+ };
1042
+ var selectorFamily = (get, options) => {
572
1043
  const map = new Map;
573
1044
  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
- }
1045
+ const keyStringified = stableStringify(key);
581
1046
  if (map.has(keyStringified))
582
1047
  return map.get(keyStringified);
583
- const selectorDebugLabel = debugLabel ? debugLabel + "_" + keyStringified : undefined;
584
- const newSelector = selector((selectorArgs) => get(key)(selectorArgs), selectorDebugLabel);
585
- newSelector.family = selectorFamily2;
1048
+ const newSelector = selector((selectorArgs) => get(key)(selectorArgs), createOptions2(options, selectorFamily2, key, keyStringified));
586
1049
  map.set(keyStringified, newSelector);
587
1050
  return newSelector;
588
1051
  };
589
- selectorFamily2._map = map;
1052
+ selectorFamily2.__valdresSelectorFamilyMap = map;
1053
+ if (options?.name)
1054
+ Object.defineProperty(selectorFamily2, "name", {
1055
+ value: options.name,
1056
+ writable: false
1057
+ });
590
1058
  return selectorFamily2;
591
1059
  };
1060
+ // src/utils/isFamilySelector.ts
1061
+ var isFamilySelector = (state) => isFamilyState(state) && isSelector(state);
1062
+
1063
+ // src/index.ts
1064
+ if (globalThis.__valdres__) {
1065
+ throw new Error(`Error! An instance of valdres is already loaded. Loaded: ${globalThis.__valdres__}. Attempted to load: ${version}`);
1066
+ } else {
1067
+ globalThis.__valdres__ = version;
1068
+ }
592
1069
  export {
1070
+ store,
593
1071
  selectorFamily,
594
1072
  selector,
595
- resetDefaultStore,
1073
+ isSelectorFamily,
596
1074
  isSelector,
597
1075
  isPromiseLike,
1076
+ isFamilyState,
1077
+ isFamilySelector,
1078
+ isFamilyAtom,
598
1079
  isFamily,
1080
+ isAtomFamily,
599
1081
  isAtom,
600
- getDefaultStore,
1082
+ globalStore,
601
1083
  createStoreWithSelectorSet,
602
- createStore,
603
1084
  atomFamily,
604
1085
  atom
605
1086
  };