valdres 0.2.0-alpha.7 → 0.2.0-alpha.71

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