valdres 1.0.0-beta.4 → 1.0.0-beta.5

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.
package/dist/index.js CHANGED
@@ -123,17 +123,18 @@ var isPromiseLike = (object) => {
123
123
  };
124
124
 
125
125
  // src/utils/deepFreeze.ts
126
- var deepFreeze = (obj, seen = new WeakSet) => {
126
+ var deepFreeze = (obj, seen) => {
127
127
  if (obj === null || obj === undefined)
128
128
  return obj;
129
129
  if (typeof obj !== "object" && typeof obj !== "function")
130
130
  return obj;
131
- if (seen.has(obj) || Object.isFrozen(obj))
131
+ if (Object.isFrozen(obj) || seen?.has(obj))
132
132
  return obj;
133
- seen.add(obj);
134
133
  if (Array.isArray(obj)) {
135
134
  for (const item of obj) {
136
135
  if (item && typeof item === "object") {
136
+ seen ??= new WeakSet;
137
+ seen.add(obj);
137
138
  deepFreeze(item, seen);
138
139
  }
139
140
  }
@@ -142,6 +143,8 @@ var deepFreeze = (obj, seen = new WeakSet) => {
142
143
  for (const name of propNames) {
143
144
  const value = obj[name];
144
145
  if (value && typeof value === "object") {
146
+ seen ??= new WeakSet;
147
+ seen.add(obj);
145
148
  deepFreeze(value, seen);
146
149
  }
147
150
  }
@@ -149,10 +152,8 @@ var deepFreeze = (obj, seen = new WeakSet) => {
149
152
  return Object.freeze(obj);
150
153
  };
151
154
 
152
- // src/lib/isProd.ts
153
- var isProd = () => {
154
- return false;
155
- };
155
+ // src/lib/IS_PROD.ts
156
+ var IS_PROD = typeof process !== "undefined" && process.env != null && process.env.NODE_ENV === "production";
156
157
 
157
158
  // src/lib/setValueInData.ts
158
159
  var trackScopeValue = (key, data) => {
@@ -172,7 +173,7 @@ var trackScopeValue = (key, data) => {
172
173
  var setValueInData = (atom, value, data) => {
173
174
  const isNewAtomInScope = data.parent && Object.hasOwn(atom, "defaultValue") && !data.values.has(atom);
174
175
  let written;
175
- if (atom.mutable || isProd()) {
176
+ if (atom.mutable || IS_PROD) {
176
177
  data.values.set(atom, value);
177
178
  written = value;
178
179
  } else {
@@ -180,8 +181,14 @@ var setValueInData = (atom, value, data) => {
180
181
  data.values.set(atom, frozenValue);
181
182
  written = frozenValue;
182
183
  }
183
- if (isNewAtomInScope)
184
+ if (isNewAtomInScope) {
184
185
  trackScopeValue(atom, data);
186
+ const subs = data.subscriptions.get(atom);
187
+ if (subs) {
188
+ for (const sub of subs)
189
+ sub.reRoot?.();
190
+ }
191
+ }
185
192
  if (atom.maxAge !== undefined) {
186
193
  data.lastValueWriteAt.set(atom, Date.now());
187
194
  }
@@ -275,8 +282,10 @@ var recursivelyUpdateIndexes = (data, family) => {
275
282
  const childScopesWithFamily = data.scopeValueIndex.get(family);
276
283
  if (!childScopesWithFamily || childScopesWithFamily.size === 0)
277
284
  return;
285
+ const parentIndex = data.values.get(family).__index;
278
286
  for (const scopedData of childScopesWithFamily) {
279
287
  const index = scopedData.values.get(family).__index;
288
+ index.parentIndex = parentIndex;
280
289
  index.rendered = null;
281
290
  index.renderedArray = null;
282
291
  scopedData.values.set(family, renderAtomFamilyIndex(index));
@@ -672,7 +681,7 @@ var addSetToSet = (fromSet, toSet) => {
672
681
  }
673
682
  }
674
683
  };
675
- var propagateDeletedAtoms = (atoms, data, subscriptions = new Set, families = new Map, timestamp = performance.now()) => {
684
+ var propagateDeletedAtoms = (atoms, data, subscriptions = new Set, families = new Map, timestamp = performance.now(), evaluatedSelectors) => {
676
685
  const selectors = new Set;
677
686
  for (const atom of atoms) {
678
687
  addSetToSet(data.stateDependents.get(atom), selectors);
@@ -693,7 +702,7 @@ var propagateDeletedAtoms = (atoms, data, subscriptions = new Set, families = ne
693
702
  deleteFamilyAtomsFromSet(family, familyAtoms, data, timestamp);
694
703
  }
695
704
  }
696
- propagateDirtySelectors(atoms, selectors, data, subscriptions, families);
705
+ propagateDirtySelectors(atoms, selectors, data, subscriptions, families, false, evaluatedSelectors);
697
706
  if (families.size > 0 && data.scopes && data.scopes.size > 0) {
698
707
  const scopeFamilies = new Map;
699
708
  for (const family of families.keys()) {
@@ -710,11 +719,11 @@ var propagateDeletedAtoms = (atoms, data, subscriptions = new Set, families = ne
710
719
  }
711
720
  }
712
721
  for (const [scope, familiesInScope] of scopeFamilies) {
713
- propagateInScope(familiesInScope, scope);
722
+ propagateInScope(familiesInScope, scope, false, evaluatedSelectors);
714
723
  }
715
724
  }
716
725
  };
717
- var propagateAtomUpdate = (atoms, data, isInitOnly = false) => {
726
+ var propagateAtomUpdate = (atoms, data, isInitOnly = false, evaluatedSelectors) => {
718
727
  if (atoms.length === 1) {
719
728
  const atom = atoms[0];
720
729
  if (!isFamilyAtom(atom) && !isAtomFamily(atom)) {
@@ -751,30 +760,37 @@ var propagateAtomUpdate = (atoms, data, isInitOnly = false) => {
751
760
  addFamilyAtomsToSet(family, familyAtoms, data, timestamp);
752
761
  }
753
762
  }
754
- propagateDirtySelectors(atoms, selectors, data, subscriptions, families, isInitOnly);
755
763
  if (data.scopes && data.scopes.size > 0) {
756
- propagateToScopes(atoms, data, isInitOnly);
764
+ for (const atom of atoms) {
765
+ if (isAtomFamily(atom) && !families.has(atom)) {
766
+ recursivelyUpdateIndexes(data, atom);
767
+ }
768
+ }
769
+ }
770
+ propagateDirtySelectors(atoms, selectors, data, subscriptions, families, isInitOnly, evaluatedSelectors);
771
+ if (data.scopes && data.scopes.size > 0) {
772
+ propagateToScopes(atoms, data, isInitOnly, evaluatedSelectors);
757
773
  }
758
774
  };
759
- var propagateInScope = (atoms, data, isInitOnly = false) => {
775
+ var propagateInScope = (atoms, data, isInitOnly = false, evaluatedSelectors) => {
760
776
  const subscriptions = new Set;
761
777
  const families = new Map;
762
778
  const selectors = new Set;
763
779
  for (const atom of atoms) {
764
780
  addSetToSet(data.stateDependents.get(atom), selectors);
765
781
  }
766
- propagateDirtySelectors(atoms, selectors, data, subscriptions, families, isInitOnly);
782
+ propagateDirtySelectors(atoms, selectors, data, subscriptions, families, isInitOnly, evaluatedSelectors);
767
783
  if (data.scopes && data.scopes.size > 0) {
768
- propagateToScopes(atoms, data, isInitOnly);
784
+ propagateToScopes(atoms, data, isInitOnly, evaluatedSelectors);
769
785
  }
770
786
  };
771
- var propagateToScopes = (atoms, data, isInitOnly) => {
787
+ var propagateToScopes = (atoms, data, isInitOnly, evaluatedSelectors) => {
772
788
  if (atoms.length === 1) {
773
789
  const atom = atoms[0];
774
790
  const shadowingScopes = isAtomFamily(atom) ? undefined : data.scopeValueIndex.get(atom);
775
791
  for (const [, scope] of data.scopes) {
776
792
  if (!shadowingScopes || !shadowingScopes.has(scope)) {
777
- propagateInScope(atoms, scope, isInitOnly);
793
+ propagateInScope(atoms, scope, isInitOnly, evaluatedSelectors);
778
794
  }
779
795
  }
780
796
  return;
@@ -794,7 +810,7 @@ var propagateToScopes = (atoms, data, isInitOnly) => {
794
810
  }
795
811
  if (!anyShadowed) {
796
812
  for (const [, scope] of data.scopes) {
797
- propagateInScope(atoms, scope, isInitOnly);
813
+ propagateInScope(atoms, scope, isInitOnly, evaluatedSelectors);
798
814
  }
799
815
  return;
800
816
  }
@@ -811,20 +827,20 @@ var propagateToScopes = (atoms, data, isInitOnly) => {
811
827
  }
812
828
  }
813
829
  if (atomsToUpdateInScope.length > 0) {
814
- propagateInScope(atomsToUpdateInScope, scope, isInitOnly);
830
+ propagateInScope(atomsToUpdateInScope, scope, isInitOnly, evaluatedSelectors);
815
831
  }
816
832
  }
817
833
  };
818
- var propagateDirtySelectors = (updatedAtoms, selectors, data, subscriptions, families, isInitOnly = false) => {
834
+ var propagateDirtySelectors = (updatedAtoms, selectors, data, subscriptions, families, isInitOnly = false, evaluatedSelectors) => {
819
835
  const updatedInitializedAtoms = new Set(updatedAtoms);
820
836
  if (selectors.size > 0) {
821
- propagateSelectorUpdates(selectors, data, subscriptions, updatedInitializedAtoms, isInitOnly);
837
+ propagateSelectorUpdates(selectors, data, subscriptions, updatedInitializedAtoms, isInitOnly, evaluatedSelectors);
822
838
  }
823
839
  if (subscriptions.size > 0) {
824
840
  callSubscribers(subscriptions, families);
825
841
  }
826
842
  };
827
- var propagateDownstreamTopo = (seeds, data, collectedSubscribers, updatedInitializedAtoms, isInitOnly) => {
843
+ var propagateDownstreamTopo = (seeds, data, collectedSubscribers, updatedInitializedAtoms, isInitOnly, evaluatedSelectors) => {
828
844
  const closure = new Set(seeds);
829
845
  {
830
846
  const stack = [...seeds];
@@ -857,13 +873,22 @@ var propagateDownstreamTopo = (seeds, data, collectedSubscribers, updatedInitial
857
873
  ready.push(s);
858
874
  }
859
875
  const needsEval = new Set(seeds);
876
+ let graphMutated = false;
860
877
  const advance = (selector, propagateChange) => {
861
878
  const downstream = data.stateDependents.get(selector);
862
879
  if (!downstream)
863
880
  return;
864
881
  for (const d of downstream) {
865
- if (!closure.has(d))
882
+ if (!closure.has(d)) {
883
+ if (propagateChange) {
884
+ graphMutated = true;
885
+ closure.add(d);
886
+ pending.set(d, 0);
887
+ needsEval.add(d);
888
+ ready.push(d);
889
+ }
866
890
  continue;
891
+ }
867
892
  const c = (pending.get(d) ?? 0) - 1;
868
893
  pending.set(d, c);
869
894
  if (propagateChange)
@@ -876,6 +901,10 @@ var propagateDownstreamTopo = (seeds, data, collectedSubscribers, updatedInitial
876
901
  let head = 0;
877
902
  while (head < ready.length) {
878
903
  const selector = ready[head++];
904
+ if (evaluatedSelectors !== undefined && evaluatedSelectors.has(selector)) {
905
+ advance(selector, false);
906
+ continue;
907
+ }
879
908
  const currentValue = data.values.get(selector);
880
909
  if (isPromiseLike(currentValue) && isInitOnly) {
881
910
  advance(selector, false);
@@ -895,19 +924,24 @@ var propagateDownstreamTopo = (seeds, data, collectedSubscribers, updatedInitial
895
924
  depsChange.added = undefined;
896
925
  depsChange.removed = undefined;
897
926
  const wasValueUpdated = reEvaluateSelector(selector, data, updatedInitializedAtoms, depsChange, currentValue);
927
+ if (evaluatedSelectors !== undefined)
928
+ evaluatedSelectors.add(selector);
898
929
  const added = depsChange.added;
899
930
  const removed = depsChange.removed;
900
- if ((added || removed) && isLive(selector, data)) {
901
- if (added) {
902
- for (const dep of added) {
903
- onLiveDependencyAdded(dep, data);
904
- mountTransitiveDeps(dep, data);
931
+ if (added || removed) {
932
+ graphMutated = true;
933
+ if (isLive(selector, data)) {
934
+ if (added) {
935
+ for (const dep of added) {
936
+ onLiveDependencyAdded(dep, data);
937
+ mountTransitiveDeps(dep, data);
938
+ }
905
939
  }
906
- }
907
- if (removed) {
908
- for (const dep of removed) {
909
- onLiveDependencyRemoved(dep, data);
910
- unmountOrphanedDeps(dep, data);
940
+ if (removed) {
941
+ for (const dep of removed) {
942
+ onLiveDependencyRemoved(dep, data);
943
+ unmountOrphanedDeps(dep, data);
944
+ }
911
945
  }
912
946
  }
913
947
  }
@@ -916,13 +950,74 @@ var propagateDownstreamTopo = (seeds, data, collectedSubscribers, updatedInitial
916
950
  addSetToSet(subscribers, collectedSubscribers);
917
951
  }
918
952
  }
953
+ if (!graphMutated)
954
+ return;
955
+ let stranded;
956
+ for (const s of closure) {
957
+ if (needsEval.has(s) && (pending.get(s) ?? 0) > 0) {
958
+ if (!stranded)
959
+ stranded = new Set;
960
+ stranded.add(s);
961
+ }
962
+ }
963
+ if (!stranded)
964
+ return;
965
+ let work = stranded;
966
+ while (work.size > 0) {
967
+ const next = new Set;
968
+ for (const selector of work) {
969
+ const currentValue = data.values.get(selector);
970
+ if (isPromiseLike(currentValue) && isInitOnly)
971
+ continue;
972
+ const dependents = data.stateDependents.get(selector);
973
+ const subscribers = data.subscriptions.get(selector);
974
+ if (!isPromiseLike(currentValue) && (!dependents || dependents.size === 0) && (!subscribers || subscribers.size === 0)) {
975
+ data.values.delete(selector);
976
+ continue;
977
+ }
978
+ depsChange.added = undefined;
979
+ depsChange.removed = undefined;
980
+ const wasValueUpdated = reEvaluateSelector(selector, data, updatedInitializedAtoms, depsChange, currentValue);
981
+ if (evaluatedSelectors !== undefined)
982
+ evaluatedSelectors.add(selector);
983
+ const added = depsChange.added;
984
+ const removed = depsChange.removed;
985
+ if ((added || removed) && isLive(selector, data)) {
986
+ if (added) {
987
+ for (const dep of added) {
988
+ onLiveDependencyAdded(dep, data);
989
+ mountTransitiveDeps(dep, data);
990
+ }
991
+ }
992
+ if (removed) {
993
+ for (const dep of removed) {
994
+ onLiveDependencyRemoved(dep, data);
995
+ unmountOrphanedDeps(dep, data);
996
+ }
997
+ }
998
+ }
999
+ if (wasValueUpdated) {
1000
+ if (subscribers)
1001
+ addSetToSet(subscribers, collectedSubscribers);
1002
+ const downstream = data.stateDependents.get(selector);
1003
+ if (downstream) {
1004
+ for (const d of downstream)
1005
+ next.add(d);
1006
+ }
1007
+ }
1008
+ }
1009
+ work = next;
1010
+ }
919
1011
  };
920
- var propagateSelectorUpdates = (selectors, data, collectedSubscribers, updatedInitializedAtoms, isInitOnly = false) => {
1012
+ var propagateSelectorUpdates = (selectors, data, collectedSubscribers, updatedInitializedAtoms, isInitOnly = false, evaluatedSelectors) => {
921
1013
  if (selectors.size === 0)
922
1014
  return;
923
1015
  let downstreamSeeds;
924
1016
  const depsChange = {};
925
1017
  for (const selector of selectors) {
1018
+ if (evaluatedSelectors !== undefined && evaluatedSelectors.has(selector)) {
1019
+ continue;
1020
+ }
926
1021
  const currentValue = data.values.get(selector);
927
1022
  if (isPromiseLike(currentValue) && isInitOnly)
928
1023
  continue;
@@ -935,6 +1030,8 @@ var propagateSelectorUpdates = (selectors, data, collectedSubscribers, updatedIn
935
1030
  depsChange.added = undefined;
936
1031
  depsChange.removed = undefined;
937
1032
  const wasValueUpdated = reEvaluateSelector(selector, data, updatedInitializedAtoms, depsChange, currentValue);
1033
+ if (evaluatedSelectors !== undefined)
1034
+ evaluatedSelectors.add(selector);
938
1035
  const added = depsChange.added;
939
1036
  const removed = depsChange.removed;
940
1037
  if ((added || removed) && isLive(selector, data)) {
@@ -964,7 +1061,7 @@ var propagateSelectorUpdates = (selectors, data, collectedSubscribers, updatedIn
964
1061
  }
965
1062
  }
966
1063
  if (downstreamSeeds && downstreamSeeds.size > 0) {
967
- propagateDownstreamTopo(downstreamSeeds, data, collectedSubscribers, updatedInitializedAtoms, isInitOnly);
1064
+ propagateDownstreamTopo(downstreamSeeds, data, collectedSubscribers, updatedInitializedAtoms, isInitOnly, evaluatedSelectors);
968
1065
  }
969
1066
  };
970
1067
 
@@ -1504,14 +1601,18 @@ var installMaxAgeTimer = (state, data) => {
1504
1601
  };
1505
1602
  var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) => {
1506
1603
  let parentUnsubscribe;
1604
+ let dropDelegate;
1507
1605
  if (data.parent && (!data.values.has(state) && isAtom(state) || isAtomFamily(state))) {
1508
1606
  const originalCallback = callback;
1509
1607
  parentUnsubscribe = subscribe(state, originalCallback, requireDeepEqualCheckBeforeCallback, data.parent);
1510
- callback = (arg) => {
1608
+ dropDelegate = () => {
1511
1609
  if (parentUnsubscribe) {
1512
1610
  parentUnsubscribe();
1513
1611
  parentUnsubscribe = undefined;
1514
1612
  }
1613
+ };
1614
+ callback = (arg) => {
1615
+ dropDelegate();
1515
1616
  originalCallback(arg);
1516
1617
  };
1517
1618
  } else if (!data.values.has(state) && isAtom(state)) {
@@ -1533,12 +1634,14 @@ var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) =>
1533
1634
  subscription = {
1534
1635
  callback,
1535
1636
  state,
1536
- requireDeepEqualCheckBeforeCallback
1637
+ requireDeepEqualCheckBeforeCallback,
1638
+ reRoot: dropDelegate
1537
1639
  };
1538
1640
  } else {
1539
1641
  subscription = {
1540
1642
  callback,
1541
- requireDeepEqualCheckBeforeCallback
1643
+ requireDeepEqualCheckBeforeCallback,
1644
+ reRoot: dropDelegate
1542
1645
  };
1543
1646
  }
1544
1647
  subscribers.add(subscription);
@@ -1562,8 +1665,8 @@ var subscribe = (state, callback, requireDeepEqualCheckBeforeCallback, data) =>
1562
1665
  };
1563
1666
  };
1564
1667
 
1565
- // src/lib/setAtoms.ts
1566
- var setAtoms = (pairs, data, initializedAtomsSet, skipOnSet = false) => {
1668
+ // src/lib/writeAtoms.ts
1669
+ var writeAtoms = (pairs, data, initializedAtomsSet, skipOnSet = false, onSetQueue) => {
1567
1670
  const updatedAtoms = [];
1568
1671
  for (let [atom, value] of pairs) {
1569
1672
  const currentValue = getState(atom, data, initializedAtomsSet);
@@ -1571,8 +1674,12 @@ var setAtoms = (pairs, data, initializedAtomsSet, skipOnSet = false) => {
1571
1674
  if (!areEqual) {
1572
1675
  updatedAtoms.push(atom);
1573
1676
  value = setValueInData(atom, value, data);
1574
- if (atom.onSet && !skipOnSet)
1575
- atom.onSet(value, data);
1677
+ if (atom.onSet && !skipOnSet) {
1678
+ if (onSetQueue)
1679
+ onSetQueue.push([atom, value, data]);
1680
+ else
1681
+ atom.onSet(value, data);
1682
+ }
1576
1683
  } else {
1577
1684
  setValueInData(atom, value, data);
1578
1685
  }
@@ -1582,6 +1689,12 @@ var setAtoms = (pairs, data, initializedAtomsSet, skipOnSet = false) => {
1582
1689
  updatedAtoms.push(atom);
1583
1690
  }
1584
1691
  }
1692
+ return updatedAtoms;
1693
+ };
1694
+
1695
+ // src/lib/setAtoms.ts
1696
+ var setAtoms = (pairs, data, initializedAtomsSet, skipOnSet = false) => {
1697
+ const updatedAtoms = writeAtoms(pairs, data, initializedAtomsSet, skipOnSet);
1585
1698
  if (updatedAtoms.length > 0) {
1586
1699
  propagateAtomUpdate(updatedAtoms, data);
1587
1700
  }
@@ -1671,7 +1784,7 @@ class Transaction {
1671
1784
  } else {
1672
1785
  resolved = value;
1673
1786
  }
1674
- if (!atom.mutable && !isProd() && resolved !== null && (typeof resolved === "object" || typeof resolved === "function")) {
1787
+ if (!atom.mutable && !IS_PROD && resolved !== null && (typeof resolved === "object" || typeof resolved === "function")) {
1675
1788
  resolved = deepFreeze(resolved);
1676
1789
  }
1677
1790
  this._atomMap.set(atom, resolved);
@@ -1761,15 +1874,58 @@ class Transaction {
1761
1874
  }
1762
1875
  };
1763
1876
  commit = () => {
1764
- const initializedAtomsSet = new Set;
1765
- setAtoms(this._atomMap, this.data, initializedAtomsSet);
1766
- if (this.deleteSet?.size) {
1767
- deleteAtomFamilyAtoms(this.deleteSet, this.data);
1768
- propagateDeletedAtoms([...this.deleteSet], this.data);
1877
+ if (!this._scopedTransactions) {
1878
+ const initializedAtomsSet = new Set;
1879
+ if (this._deleteSet?.size) {
1880
+ const evaluatedSelectors2 = new Set;
1881
+ const updatedAtoms = writeAtoms(this._atomMap, this.data, initializedAtomsSet);
1882
+ if (updatedAtoms.length > 0) {
1883
+ propagateAtomUpdate(updatedAtoms, this.data, false, evaluatedSelectors2);
1884
+ }
1885
+ deleteAtomFamilyAtoms(this._deleteSet, this.data);
1886
+ propagateDeletedAtoms([...this._deleteSet], this.data, undefined, undefined, undefined, evaluatedSelectors2);
1887
+ } else {
1888
+ setAtoms(this._atomMap, this.data, initializedAtomsSet);
1889
+ }
1890
+ return;
1891
+ }
1892
+ const plan = [];
1893
+ this.collectStores(plan);
1894
+ for (let i = plan.length - 1;i >= 0; i--) {
1895
+ const entry = plan[i];
1896
+ const txn = entry.txn;
1897
+ entry.updatedAtoms = writeAtoms(txn._atomMap, entry.data, new Set, false, entry.onSets);
1898
+ if (txn._deleteSet?.size) {
1899
+ deleteAtomFamilyAtoms(txn._deleteSet, entry.data);
1900
+ entry.deleted = [...txn._deleteSet];
1901
+ }
1769
1902
  }
1903
+ for (const entry of plan) {
1904
+ for (const [atom, value, data] of entry.onSets) {
1905
+ atom.onSet(value, data);
1906
+ }
1907
+ }
1908
+ const evaluatedSelectors = new Set;
1909
+ for (const { data, updatedAtoms, deleted } of plan) {
1910
+ if (updatedAtoms.length > 0) {
1911
+ propagateAtomUpdate(updatedAtoms, data, false, evaluatedSelectors);
1912
+ }
1913
+ if (deleted) {
1914
+ propagateDeletedAtoms(deleted, data, undefined, undefined, undefined, evaluatedSelectors);
1915
+ }
1916
+ }
1917
+ };
1918
+ collectStores = (plan) => {
1919
+ plan.push({
1920
+ txn: this,
1921
+ data: this.data,
1922
+ updatedAtoms: [],
1923
+ deleted: undefined,
1924
+ onSets: []
1925
+ });
1770
1926
  if (this._scopedTransactions) {
1771
1927
  for (const [, scopedTxn] of this._scopedTransactions) {
1772
- scopedTxn.commit();
1928
+ scopedTxn.collectStores(plan);
1773
1929
  }
1774
1930
  }
1775
1931
  };
@@ -2592,9 +2748,9 @@ var isFamilySelector = (state) => isFamilyState(state) && isSelector(state);
2592
2748
 
2593
2749
  // src/index.ts
2594
2750
  if (globalThis.__valdres__) {
2595
- throw new Error(`Error! An instance of valdres is already loaded. Loaded: ${globalThis.__valdres__}. Attempted to load: ${"1.0.0-beta.4"}`);
2751
+ throw new Error(`Error! An instance of valdres is already loaded. Loaded: ${globalThis.__valdres__}. Attempted to load: ${"1.0.0-beta.5"}`);
2596
2752
  } else {
2597
- globalThis.__valdres__ = "1.0.0-beta.4";
2753
+ globalThis.__valdres__ = "1.0.0-beta.5";
2598
2754
  }
2599
2755
  export {
2600
2756
  store,
@@ -0,0 +1 @@
1
+ export declare const IS_PROD: boolean;
@@ -14,4 +14,5 @@ export type AtomFamilyIndex = {
14
14
  export declare const cloneAtomFamilyIndex: (index: AtomFamilyIndex, parentIndexOverride?: AtomFamilyIndex) => AtomFamilyIndex;
15
15
  export declare const createAtomFamilyIndex: (parentIndex?: AtomFamilyIndex) => AtomFamilyIndex;
16
16
  export declare const deleteFamilyAtomsFromSet: (family: Family<any>, familyAtoms: Set<AtomFamilyAtom<any>>, data: StoreData, timestamp: number) => void;
17
+ export declare const recursivelyUpdateIndexes: (data: StoreData, family: Family<any>) => void;
17
18
  export declare const addFamilyAtomsToSet: (family: Family<any>, familyAtoms: Set<AtomFamilyAtom<any>>, data: StoreData, timestamp: number) => void;
@@ -7,7 +7,7 @@ import type { Subscription } from "../types/Subscription";
7
7
  export type { AtomFamilyIndex, } from "./atomFamilyIndex";
8
8
  export { cloneAtomFamilyIndex, createAtomFamilyIndex, renderAtomFamilyIndex, } from "./atomFamilyIndex";
9
9
  type AtomInput = Atom<any> | AtomFamilyAtom<any, any> | AtomFamily<any, any>;
10
- export declare const propagateDeletedAtoms: (atoms: AtomFamilyAtom<any, any>[], data: StoreData, subscriptions?: Set<Subscription>, families?: Map<AtomFamily<any>, Set<AtomFamilyAtom<any>>>, timestamp?: number) => void;
11
- export declare const propagateAtomUpdate: (atoms: AtomInput[], data: StoreData, isInitOnly?: boolean) => void;
12
- export declare const propagateInScope: (atoms: AtomInput[], data: StoreData, isInitOnly?: boolean) => void;
13
- export declare const propagateDirtySelectors: (updatedAtoms: Atom[], selectors: Set<Selector>, data: StoreData, subscriptions: Set<Subscription>, families: Map<AtomFamily<any>, Set<AtomFamilyAtom<any>>>, isInitOnly?: boolean) => void;
10
+ export declare const propagateDeletedAtoms: (atoms: AtomFamilyAtom<any, any>[], data: StoreData, subscriptions?: Set<Subscription>, families?: Map<AtomFamily<any>, Set<AtomFamilyAtom<any>>>, timestamp?: number, evaluatedSelectors?: Set<Selector>) => void;
11
+ export declare const propagateAtomUpdate: (atoms: AtomInput[], data: StoreData, isInitOnly?: boolean, evaluatedSelectors?: Set<Selector>) => void;
12
+ export declare const propagateInScope: (atoms: AtomInput[], data: StoreData, isInitOnly?: boolean, evaluatedSelectors?: Set<Selector>) => void;
13
+ export declare const propagateDirtySelectors: (updatedAtoms: Atom[], selectors: Set<Selector>, data: StoreData, subscriptions: Set<Subscription>, families: Map<AtomFamily<any>, Set<AtomFamilyAtom<any>>>, isInitOnly?: boolean, evaluatedSelectors?: Set<Selector>) => void;
@@ -26,6 +26,7 @@ export declare class Transaction {
26
26
  execute: (callback: TransactionFn, autoCommit?: boolean) => any;
27
27
  private txnCommit;
28
28
  commit: () => void;
29
+ private collectStores;
29
30
  private get selectorCache();
30
31
  private get selectorDependencies();
31
32
  private get deleteSet();
@@ -0,0 +1,21 @@
1
+ import type { Atom } from "../types/Atom";
2
+ import type { StoreData } from "../types/StoreData";
3
+ /** A deferred onSet invocation: the hook, the written value, and the store it
4
+ * was written to. Collected during the write phase of a cross-scope commit so
5
+ * hooks fire only once the whole tree has been written. */
6
+ export type DeferredOnSet = [Atom<any>, any, StoreData];
7
+ /**
8
+ * Write phase for a single store. Applies every value in `pairs` to
9
+ * `data.values`, returning the atoms whose value actually changed (the
10
+ * propagation set), merged with any atoms lazily initialized during the
11
+ * equality checks. This does NOT propagate — see `setAtoms` (single-store
12
+ * fast path) or `Transaction.commit` (cross-scope path) for the notify pass.
13
+ *
14
+ * onSet handling:
15
+ * - `skipOnSet` true → never fire onSet.
16
+ * - `onSetQueue` given → defer onSet by pushing `[atom, value, data]`. The
17
+ * cross-scope commit uses this so a hook never observes a half-applied
18
+ * transaction — it fires only after every store's writes have landed.
19
+ * - otherwise → fire onSet inline (single-store path, unchanged).
20
+ */
21
+ export declare const writeAtoms: (pairs: Map<Atom<any>, any>, data: StoreData, initializedAtomsSet: Set<Atom>, skipOnSet?: boolean, onSetQueue?: DeferredOnSet[]) => Atom[];
@@ -3,9 +3,16 @@ export type AtomFamilySubscription<Value extends any = any, Args extends [any, .
3
3
  state: AtomFamily<Value, Args>;
4
4
  callback: (...args: Args) => void;
5
5
  requireDeepEqualCheckBeforeCallback: boolean;
6
+ /** Present only on a scope subscription that is delegating to an ancestor.
7
+ * Drops the ancestor delegate (idempotent). Called eagerly when the scope
8
+ * shadows the state so an ancestor write in the same transaction commit
9
+ * does not also notify this subscription. */
10
+ reRoot?: () => void;
6
11
  };
7
12
  export type SimpleSubscription = {
8
13
  requireDeepEqualCheckBeforeCallback: boolean;
9
14
  callback: () => void;
15
+ /** See AtomFamilySubscription.reRoot. */
16
+ reRoot?: () => void;
10
17
  };
11
18
  export type Subscription = SimpleSubscription | AtomFamilySubscription;
@@ -1 +1 @@
1
- export declare const deepFreeze: (obj: any, seen?: WeakSet<WeakKey>) => any;
1
+ export declare const deepFreeze: (obj: any, seen?: WeakSet<object>) => any;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "valdres",
3
- "version": "1.0.0-beta.4",
3
+ "version": "1.0.0-beta.5",
4
4
  "license": "MIT",
5
5
  "author": {
6
6
  "name": "Eigil Sagafos"
@@ -1 +0,0 @@
1
- export declare const isProd: () => boolean;