@solidjs/signals 0.13.5 → 0.13.7

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/dev.js CHANGED
@@ -151,6 +151,7 @@ let clock = 0;
151
151
  let activeTransition = null;
152
152
  let scheduled = false;
153
153
  let projectionWriteActive = false;
154
+ let inTrackedQueueCallback = false;
154
155
  let _enforceLoadingBoundary = false;
155
156
  let _hitUnhandledAsync = false;
156
157
  let stashedOptimisticReads = null;
@@ -192,6 +193,9 @@ function queueStashedOptimisticEffects(node) {
192
193
  function setProjectionWriteActive(value) {
193
194
  projectionWriteActive = value;
194
195
  }
196
+ function setTrackedQueueCallback(value) {
197
+ inTrackedQueueCallback = value;
198
+ }
195
199
  function mergeTransitionState(target, outgoing) {
196
200
  outgoing._done = target;
197
201
  target._actions.push(...outgoing._actions);
@@ -242,20 +246,6 @@ function schedule() {
242
246
  scheduled = true;
243
247
  if (!globalQueue._running && !projectionWriteActive) queueMicrotask(flush);
244
248
  }
245
- function addTransitionBlocker(node) {
246
- if (activeTransition && !activeTransition._asyncNodes.includes(node)) {
247
- activeTransition._asyncNodes.push(node);
248
- }
249
- }
250
- function removeTransitionBlocker(node) {
251
- const remove = list => {
252
- if (!list) return;
253
- const index = list.indexOf(node);
254
- if (index >= 0) list.splice(index, 1);
255
- };
256
- remove(node._transition?._asyncNodes);
257
- remove(activeTransition?._asyncNodes);
258
- }
259
249
  class Queue {
260
250
  _parent = null;
261
251
  _queues = [[], []];
@@ -532,6 +522,14 @@ function reassignPendingTransition(pendingNodes) {
532
522
  }
533
523
  const globalQueue = new GlobalQueue();
534
524
  function flush() {
525
+ if (globalQueue._running) {
526
+ if (inTrackedQueueCallback) {
527
+ throw new Error(
528
+ "Cannot call flush() from inside onSettled or createTrackedEffect. flush() is not reentrant there."
529
+ );
530
+ }
531
+ return;
532
+ }
535
533
  let count = 0;
536
534
  while (scheduled || activeTransition) {
537
535
  if (++count === 1e5) throw new Error("Potential Infinite Loop Detected.");
@@ -552,6 +550,21 @@ function transitionComplete(transition) {
552
550
  break;
553
551
  }
554
552
  }
553
+ if (done) {
554
+ for (let i = 0; i < transition._optimisticNodes.length; i++) {
555
+ const node = transition._optimisticNodes[i];
556
+ if (
557
+ hasActiveOverride(node) &&
558
+ "_statusFlags" in node &&
559
+ node._statusFlags & STATUS_PENDING &&
560
+ node._error instanceof NotReadyError &&
561
+ node._error.source !== node
562
+ ) {
563
+ done = false;
564
+ break;
565
+ }
566
+ }
567
+ }
555
568
  done && (transition._done = true);
556
569
  return done;
557
570
  }
@@ -642,6 +655,209 @@ function assignOrMergeLane(el, sourceLane) {
642
655
  }
643
656
  el._optimisticLane = sourceLane;
644
657
  }
658
+ function unlinkSubs(link) {
659
+ const dep = link._dep;
660
+ const nextDep = link._nextDep;
661
+ const nextSub = link._nextSub;
662
+ const prevSub = link._prevSub;
663
+ if (nextSub !== null) nextSub._prevSub = prevSub;
664
+ else dep._subsTail = prevSub;
665
+ if (prevSub !== null) prevSub._nextSub = nextSub;
666
+ else {
667
+ dep._subs = nextSub;
668
+ if (nextSub === null) {
669
+ dep._unobserved?.();
670
+ dep._fn && !dep._preventAutoDisposal && !(dep._flags & REACTIVE_ZOMBIE) && unobserved(dep);
671
+ }
672
+ }
673
+ return nextDep;
674
+ }
675
+ function unobserved(el) {
676
+ deleteFromHeap(el, el._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue);
677
+ let dep = el._deps;
678
+ while (dep !== null) {
679
+ dep = unlinkSubs(dep);
680
+ }
681
+ el._deps = null;
682
+ disposeChildren(el, true);
683
+ }
684
+ function link(dep, sub) {
685
+ const prevDep = sub._depsTail;
686
+ if (prevDep !== null && prevDep._dep === dep) return;
687
+ let nextDep = null;
688
+ const isRecomputing = sub._flags & REACTIVE_RECOMPUTING_DEPS;
689
+ if (isRecomputing) {
690
+ nextDep = prevDep !== null ? prevDep._nextDep : sub._deps;
691
+ if (nextDep !== null && nextDep._dep === dep) {
692
+ sub._depsTail = nextDep;
693
+ return;
694
+ }
695
+ }
696
+ const prevSub = dep._subsTail;
697
+ if (prevSub !== null && prevSub._sub === sub && (!isRecomputing || isValidLink(prevSub, sub)))
698
+ return;
699
+ const newLink =
700
+ (sub._depsTail =
701
+ dep._subsTail =
702
+ { _dep: dep, _sub: sub, _nextDep: nextDep, _prevSub: prevSub, _nextSub: null });
703
+ if (prevDep !== null) prevDep._nextDep = newLink;
704
+ else sub._deps = newLink;
705
+ if (prevSub !== null) prevSub._nextSub = newLink;
706
+ else dep._subs = newLink;
707
+ }
708
+ function isValidLink(checkLink, sub) {
709
+ const depsTail = sub._depsTail;
710
+ if (depsTail !== null) {
711
+ let link = sub._deps;
712
+ do {
713
+ if (link === checkLink) return true;
714
+ if (link === depsTail) break;
715
+ link = link._nextDep;
716
+ } while (link !== null);
717
+ }
718
+ return false;
719
+ }
720
+ const PENDING_OWNER = {};
721
+ function markDisposal(el) {
722
+ let child = el._firstChild;
723
+ while (child) {
724
+ child._flags |= REACTIVE_ZOMBIE;
725
+ if (child._flags & REACTIVE_IN_HEAP) {
726
+ deleteFromHeap(child, dirtyQueue);
727
+ insertIntoHeap(child, zombieQueue);
728
+ }
729
+ markDisposal(child);
730
+ child = child._nextSibling;
731
+ }
732
+ }
733
+ function dispose(node) {
734
+ let toRemove = node._deps || null;
735
+ do {
736
+ toRemove = unlinkSubs(toRemove);
737
+ } while (toRemove !== null);
738
+ node._deps = null;
739
+ node._depsTail = null;
740
+ disposeChildren(node, true);
741
+ }
742
+ function disposeChildren(node, self = false, zombie) {
743
+ if (node._flags & REACTIVE_DISPOSED) return;
744
+ if (self) node._flags = REACTIVE_DISPOSED;
745
+ if (self && node._fn) node._inFlight = null;
746
+ let child = zombie ? node._pendingFirstChild : node._firstChild;
747
+ while (child) {
748
+ const nextChild = child._nextSibling;
749
+ if (child._deps) {
750
+ const n = child;
751
+ deleteFromHeap(n, n._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue);
752
+ let toRemove = n._deps;
753
+ do {
754
+ toRemove = unlinkSubs(toRemove);
755
+ } while (toRemove !== null);
756
+ n._deps = null;
757
+ n._depsTail = null;
758
+ }
759
+ disposeChildren(child, true);
760
+ child = nextChild;
761
+ }
762
+ if (zombie) {
763
+ node._pendingFirstChild = null;
764
+ } else {
765
+ node._firstChild = null;
766
+ node._childCount = 0;
767
+ }
768
+ runDisposal(node, zombie);
769
+ }
770
+ function runDisposal(node, zombie) {
771
+ let disposal = zombie ? node._pendingDisposal : node._disposal;
772
+ if (!disposal) return;
773
+ if (Array.isArray(disposal)) {
774
+ for (let i = 0; i < disposal.length; i++) {
775
+ const callable = disposal[i];
776
+ callable.call(callable);
777
+ }
778
+ } else {
779
+ disposal.call(disposal);
780
+ }
781
+ zombie ? (node._pendingDisposal = null) : (node._disposal = null);
782
+ }
783
+ function childId(owner, consume) {
784
+ let counter = owner;
785
+ while (counter._transparent && counter._parent) counter = counter._parent;
786
+ if (counter.id != null)
787
+ return formatId(counter.id, consume ? counter._childCount++ : counter._childCount);
788
+ throw new Error("Cannot get child id from owner without an id");
789
+ }
790
+ function getNextChildId(owner) {
791
+ return childId(owner, true);
792
+ }
793
+ function peekNextChildId(owner) {
794
+ return childId(owner, false);
795
+ }
796
+ function formatId(prefix, id) {
797
+ const num = id.toString(36),
798
+ len = num.length - 1;
799
+ return prefix + (len ? String.fromCharCode(64 + len) : "") + num;
800
+ }
801
+ function getObserver() {
802
+ if (pendingCheckActive || latestReadActive) return PENDING_OWNER;
803
+ return tracking ? context : null;
804
+ }
805
+ function getOwner() {
806
+ return context;
807
+ }
808
+ function cleanup(fn) {
809
+ if (!context) return fn;
810
+ if (!context._disposal) context._disposal = fn;
811
+ else if (Array.isArray(context._disposal)) context._disposal.push(fn);
812
+ else context._disposal = [context._disposal, fn];
813
+ return fn;
814
+ }
815
+ function isDisposed(node) {
816
+ return !!(node._flags & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE));
817
+ }
818
+ function createOwner(options) {
819
+ const parent = context;
820
+ const transparent = options?.transparent ?? false;
821
+ const owner = {
822
+ id:
823
+ options?.id ??
824
+ (transparent ? parent?.id : parent?.id != null ? getNextChildId(parent) : undefined),
825
+ _transparent: transparent || undefined,
826
+ _root: true,
827
+ _parentComputed: parent?._root ? parent._parentComputed : parent,
828
+ _firstChild: null,
829
+ _nextSibling: null,
830
+ _disposal: null,
831
+ _queue: parent?._queue ?? globalQueue,
832
+ _context: parent?._context || defaultContext,
833
+ _childCount: 0,
834
+ _pendingDisposal: null,
835
+ _pendingFirstChild: null,
836
+ _parent: parent,
837
+ dispose(self = true) {
838
+ disposeChildren(owner, self);
839
+ }
840
+ };
841
+ if (parent?._childrenForbidden) {
842
+ throw new Error(
843
+ "Cannot create reactive primitives inside createTrackedEffect or owner-backed onSettled"
844
+ );
845
+ }
846
+ if (parent) {
847
+ const lastChild = parent._firstChild;
848
+ if (lastChild === null) {
849
+ parent._firstChild = owner;
850
+ } else {
851
+ owner._nextSibling = lastChild;
852
+ parent._firstChild = owner;
853
+ }
854
+ }
855
+ return owner;
856
+ }
857
+ function createRoot(init, options) {
858
+ const owner = createOwner(options);
859
+ return runWithOwner(owner, () => init(owner.dispose));
860
+ }
645
861
  function addPendingSource(el, source) {
646
862
  if (el._pendingSource === source || el._pendingSources?.has(source)) return false;
647
863
  if (!el._pendingSource) {
@@ -806,6 +1022,17 @@ function handleAsync(el, result, setter) {
806
1022
  if (iterator) {
807
1023
  const it = result[Symbol.asyncIterator]();
808
1024
  let hadSyncValue = false;
1025
+ let completed = false;
1026
+ cleanup(() => {
1027
+ if (completed) return;
1028
+ completed = true;
1029
+ try {
1030
+ const returned = it.return?.();
1031
+ if (returned && typeof returned.then === "function") {
1032
+ returned.then(undefined, () => {});
1033
+ }
1034
+ } catch {}
1035
+ });
809
1036
  const iterate = () => {
810
1037
  let syncResult,
811
1038
  resolved = false,
@@ -815,14 +1042,21 @@ function handleAsync(el, result, setter) {
815
1042
  if (isSync) {
816
1043
  syncResult = r;
817
1044
  resolved = true;
1045
+ if (r.done) completed = true;
1046
+ } else if (el._inFlight !== result) {
1047
+ return;
818
1048
  } else if (!r.done) asyncWrite(r.value, iterate);
819
1049
  else {
1050
+ completed = true;
820
1051
  schedule();
821
1052
  flush();
822
1053
  }
823
1054
  },
824
1055
  e => {
825
- if (!isSync) handleError(e);
1056
+ if (!isSync && el._inFlight === result) {
1057
+ completed = true;
1058
+ handleError(e);
1059
+ }
826
1060
  }
827
1061
  );
828
1062
  isSync = false;
@@ -843,7 +1077,6 @@ function handleAsync(el, result, setter) {
843
1077
  }
844
1078
  function clearStatus(el, clearUninitialized = false) {
845
1079
  clearPendingSources(el);
846
- removeTransitionBlocker(el);
847
1080
  el._blocked = false;
848
1081
  el._statusFlags = clearUninitialized ? 0 : el._statusFlags & STATUS_UNINITIALIZED;
849
1082
  setPendingError(el);
@@ -867,11 +1100,9 @@ function notifyStatus(el, status, error, blockStatus, lane) {
867
1100
  if (status === STATUS_PENDING && pendingSource) {
868
1101
  addPendingSource(el, pendingSource);
869
1102
  el._statusFlags = STATUS_PENDING | (el._statusFlags & STATUS_UNINITIALIZED);
870
- setPendingError(el, el._pendingSource ?? el._pendingSources?.values().next().value, error);
871
- if (pendingSource === el) addTransitionBlocker(el);
1103
+ setPendingError(el, pendingSource, error);
872
1104
  } else {
873
1105
  clearPendingSources(el);
874
- removeTransitionBlocker(el);
875
1106
  el._statusFlags =
876
1107
  status | (status !== STATUS_ERROR ? el._statusFlags & STATUS_UNINITIALIZED : 0);
877
1108
  el._error = error;
@@ -884,6 +1115,9 @@ function notifyStatus(el, status, error, blockStatus, lane) {
884
1115
  const downstreamBlockStatus = blockStatus || startsBlocking;
885
1116
  const downstreamLane = blockStatus || isOptimisticBoundary ? undefined : lane;
886
1117
  if (el._notifyStatus) {
1118
+ if (blockStatus && status === STATUS_PENDING) {
1119
+ return;
1120
+ }
887
1121
  if (downstreamBlockStatus) {
888
1122
  el._notifyStatus(status, error);
889
1123
  } else {
@@ -901,7 +1135,7 @@ function notifyStatus(el, status, error, blockStatus, lane) {
901
1135
  (status !== STATUS_PENDING &&
902
1136
  (sub._error !== error || sub._pendingSource || sub._pendingSources))
903
1137
  ) {
904
- !sub._transition && globalQueue._pendingNodes.push(sub);
1138
+ if (!downstreamBlockStatus && !sub._transition) globalQueue._pendingNodes.push(sub);
905
1139
  notifyStatus(sub, status, error, downstreamBlockStatus, downstreamLane);
906
1140
  }
907
1141
  });
@@ -929,208 +1163,6 @@ function enableExternalSource(config) {
929
1163
  externalSourceConfig = { factory: factory, untrack: untrackFn };
930
1164
  }
931
1165
  }
932
- const PENDING_OWNER = {};
933
- function markDisposal(el) {
934
- let child = el._firstChild;
935
- while (child) {
936
- child._flags |= REACTIVE_ZOMBIE;
937
- if (child._flags & REACTIVE_IN_HEAP) {
938
- deleteFromHeap(child, dirtyQueue);
939
- insertIntoHeap(child, zombieQueue);
940
- }
941
- markDisposal(child);
942
- child = child._nextSibling;
943
- }
944
- }
945
- function dispose(node) {
946
- let toRemove = node._deps || null;
947
- do {
948
- toRemove = unlinkSubs(toRemove);
949
- } while (toRemove !== null);
950
- node._deps = null;
951
- node._depsTail = null;
952
- disposeChildren(node, true);
953
- }
954
- function disposeChildren(node, self = false, zombie) {
955
- if (node._flags & REACTIVE_DISPOSED) return;
956
- if (self) node._flags = REACTIVE_DISPOSED;
957
- let child = zombie ? node._pendingFirstChild : node._firstChild;
958
- while (child) {
959
- const nextChild = child._nextSibling;
960
- if (child._deps) {
961
- const n = child;
962
- deleteFromHeap(n, n._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue);
963
- let toRemove = n._deps;
964
- do {
965
- toRemove = unlinkSubs(toRemove);
966
- } while (toRemove !== null);
967
- n._deps = null;
968
- n._depsTail = null;
969
- }
970
- disposeChildren(child, true);
971
- child = nextChild;
972
- }
973
- if (zombie) {
974
- node._pendingFirstChild = null;
975
- } else {
976
- node._firstChild = null;
977
- node._childCount = 0;
978
- }
979
- runDisposal(node, zombie);
980
- }
981
- function runDisposal(node, zombie) {
982
- let disposal = zombie ? node._pendingDisposal : node._disposal;
983
- if (!disposal) return;
984
- if (Array.isArray(disposal)) {
985
- for (let i = 0; i < disposal.length; i++) {
986
- const callable = disposal[i];
987
- callable.call(callable);
988
- }
989
- } else {
990
- disposal.call(disposal);
991
- }
992
- zombie ? (node._pendingDisposal = null) : (node._disposal = null);
993
- }
994
- function childId(owner, consume) {
995
- let counter = owner;
996
- while (counter._transparent && counter._parent) counter = counter._parent;
997
- if (counter.id != null)
998
- return formatId(counter.id, consume ? counter._childCount++ : counter._childCount);
999
- throw new Error("Cannot get child id from owner without an id");
1000
- }
1001
- function getNextChildId(owner) {
1002
- return childId(owner, true);
1003
- }
1004
- function peekNextChildId(owner) {
1005
- return childId(owner, false);
1006
- }
1007
- function formatId(prefix, id) {
1008
- const num = id.toString(36),
1009
- len = num.length - 1;
1010
- return prefix + (len ? String.fromCharCode(64 + len) : "") + num;
1011
- }
1012
- function getObserver() {
1013
- if (pendingCheckActive || latestReadActive) return PENDING_OWNER;
1014
- return tracking ? context : null;
1015
- }
1016
- function getOwner() {
1017
- return context;
1018
- }
1019
- function cleanup(fn) {
1020
- if (!context) return fn;
1021
- if (!context._disposal) context._disposal = fn;
1022
- else if (Array.isArray(context._disposal)) context._disposal.push(fn);
1023
- else context._disposal = [context._disposal, fn];
1024
- return fn;
1025
- }
1026
- function isDisposed(node) {
1027
- return !!(node._flags & (REACTIVE_DISPOSED | REACTIVE_ZOMBIE));
1028
- }
1029
- function createOwner(options) {
1030
- const parent = context;
1031
- const transparent = options?.transparent ?? false;
1032
- const owner = {
1033
- id:
1034
- options?.id ??
1035
- (transparent ? parent?.id : parent?.id != null ? getNextChildId(parent) : undefined),
1036
- _transparent: transparent || undefined,
1037
- _root: true,
1038
- _parentComputed: parent?._root ? parent._parentComputed : parent,
1039
- _firstChild: null,
1040
- _nextSibling: null,
1041
- _disposal: null,
1042
- _queue: parent?._queue ?? globalQueue,
1043
- _context: parent?._context || defaultContext,
1044
- _childCount: 0,
1045
- _pendingDisposal: null,
1046
- _pendingFirstChild: null,
1047
- _parent: parent,
1048
- dispose(self = true) {
1049
- disposeChildren(owner, self);
1050
- }
1051
- };
1052
- if (parent?._childrenForbidden) {
1053
- throw new Error(
1054
- "Cannot create reactive primitives inside createTrackedEffect or owner-backed onSettled"
1055
- );
1056
- }
1057
- if (parent) {
1058
- const lastChild = parent._firstChild;
1059
- if (lastChild === null) {
1060
- parent._firstChild = owner;
1061
- } else {
1062
- owner._nextSibling = lastChild;
1063
- parent._firstChild = owner;
1064
- }
1065
- }
1066
- return owner;
1067
- }
1068
- function createRoot(init, options) {
1069
- const owner = createOwner(options);
1070
- return runWithOwner(owner, () => init(owner.dispose));
1071
- }
1072
- function unlinkSubs(link) {
1073
- const dep = link._dep;
1074
- const nextDep = link._nextDep;
1075
- const nextSub = link._nextSub;
1076
- const prevSub = link._prevSub;
1077
- if (nextSub !== null) nextSub._prevSub = prevSub;
1078
- else dep._subsTail = prevSub;
1079
- if (prevSub !== null) prevSub._nextSub = nextSub;
1080
- else {
1081
- dep._subs = nextSub;
1082
- if (nextSub === null) {
1083
- dep._unobserved?.();
1084
- dep._fn && !dep._preventAutoDisposal && !(dep._flags & REACTIVE_ZOMBIE) && unobserved(dep);
1085
- }
1086
- }
1087
- return nextDep;
1088
- }
1089
- function unobserved(el) {
1090
- deleteFromHeap(el, el._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue);
1091
- let dep = el._deps;
1092
- while (dep !== null) {
1093
- dep = unlinkSubs(dep);
1094
- }
1095
- el._deps = null;
1096
- disposeChildren(el, true);
1097
- }
1098
- function link(dep, sub) {
1099
- const prevDep = sub._depsTail;
1100
- if (prevDep !== null && prevDep._dep === dep) return;
1101
- let nextDep = null;
1102
- const isRecomputing = sub._flags & REACTIVE_RECOMPUTING_DEPS;
1103
- if (isRecomputing) {
1104
- nextDep = prevDep !== null ? prevDep._nextDep : sub._deps;
1105
- if (nextDep !== null && nextDep._dep === dep) {
1106
- sub._depsTail = nextDep;
1107
- return;
1108
- }
1109
- }
1110
- const prevSub = dep._subsTail;
1111
- if (prevSub !== null && prevSub._sub === sub && (!isRecomputing || isValidLink(prevSub, sub)))
1112
- return;
1113
- const newLink =
1114
- (sub._depsTail =
1115
- dep._subsTail =
1116
- { _dep: dep, _sub: sub, _nextDep: nextDep, _prevSub: prevSub, _nextSub: null });
1117
- if (prevDep !== null) prevDep._nextDep = newLink;
1118
- else sub._deps = newLink;
1119
- if (prevSub !== null) prevSub._nextSub = newLink;
1120
- else dep._subs = newLink;
1121
- }
1122
- function isValidLink(checkLink, sub) {
1123
- const depsTail = sub._depsTail;
1124
- if (depsTail !== null) {
1125
- let link = sub._deps;
1126
- do {
1127
- if (link === checkLink) return true;
1128
- if (link === depsTail) break;
1129
- link = link._nextDep;
1130
- } while (link !== null);
1131
- }
1132
- return false;
1133
- }
1134
1166
  GlobalQueue._update = recompute;
1135
1167
  GlobalQueue._dispose = disposeChildren;
1136
1168
  let tracking = false;
@@ -1199,6 +1231,7 @@ function recompute(el, create = false) {
1199
1231
  if (el._transition && (!isEffect || activeTransition) && activeTransition !== el._transition)
1200
1232
  globalQueue.initTransition(el._transition);
1201
1233
  deleteFromHeap(el, el._flags & REACTIVE_ZOMBIE ? zombieQueue : dirtyQueue);
1234
+ el._inFlight = null;
1202
1235
  if (el._transition || isEffect === EFFECT_TRACKED) disposeChildren(el);
1203
1236
  else {
1204
1237
  markDisposal(el);
@@ -1503,6 +1536,11 @@ function read(el) {
1503
1536
  ) {
1504
1537
  foundPending = true;
1505
1538
  }
1539
+ let c = context;
1540
+ if (c?._root) c = c._parentComputed;
1541
+ if (c && tracking) link(el, c);
1542
+ read(getPendingSignal(el));
1543
+ read(getPendingSignal(firewall));
1506
1544
  } else {
1507
1545
  if (read(getPendingSignal(el))) foundPending = true;
1508
1546
  if (firewall && read(getPendingSignal(firewall))) foundPending = true;
@@ -1559,6 +1597,9 @@ function read(el) {
1559
1597
  if (!tracking && el !== c) link(el, c);
1560
1598
  throw owner._error;
1561
1599
  }
1600
+ } else if (c && owner !== el && owner._statusFlags & STATUS_UNINITIALIZED) {
1601
+ if (!tracking && el !== c) link(el, c);
1602
+ throw owner._error;
1562
1603
  } else if (!c && owner._statusFlags & STATUS_UNINITIALIZED) {
1563
1604
  throw owner._error;
1564
1605
  }
@@ -1874,7 +1915,13 @@ function runEffect() {
1874
1915
  this._cleanup?.();
1875
1916
  this._cleanup = undefined;
1876
1917
  try {
1877
- this._cleanup = this._effectFn(this._value, this._prevValue);
1918
+ const cleanup = this._effectFn(this._value, this._prevValue);
1919
+ if (true && cleanup !== undefined && typeof cleanup !== "function") {
1920
+ throw new Error(
1921
+ `${this._name || "effect"} callback returned an invalid cleanup value. Return a cleanup function or undefined.`
1922
+ );
1923
+ }
1924
+ this._cleanup = cleanup;
1878
1925
  } catch (error) {
1879
1926
  this._error = new StatusError(this, error);
1880
1927
  this._statusFlags |= STATUS_ERROR;
@@ -1888,14 +1935,25 @@ function runEffect() {
1888
1935
  function trackedEffect(fn, options) {
1889
1936
  const run = () => {
1890
1937
  if (!node._modified || node._flags & REACTIVE_DISPOSED) return;
1891
- node._modified = false;
1892
- recompute(node);
1938
+ setTrackedQueueCallback(true);
1939
+ try {
1940
+ node._modified = false;
1941
+ recompute(node);
1942
+ } finally {
1943
+ setTrackedQueueCallback(false);
1944
+ }
1893
1945
  };
1894
1946
  const node = computed(
1895
1947
  () => {
1896
1948
  node._cleanup?.();
1897
1949
  node._cleanup = undefined;
1898
- node._cleanup = staleValues(fn) || undefined;
1950
+ const cleanup = staleValues(fn);
1951
+ if (cleanup !== undefined && typeof cleanup !== "function") {
1952
+ throw new Error(
1953
+ `${node._name || "trackedEffect"} callback returned an invalid cleanup value. Return a cleanup function or undefined.`
1954
+ );
1955
+ }
1956
+ node._cleanup = cleanup;
1899
1957
  },
1900
1958
  undefined,
1901
1959
  { ...options, lazy: true }
@@ -2015,7 +2073,13 @@ function createReaction(effectFn, options) {
2015
2073
  () => (tracking(), getOwner()),
2016
2074
  node => {
2017
2075
  cl?.();
2018
- cl = (effectFn.effect || effectFn)?.();
2076
+ const cleanup = (effectFn.effect || effectFn)?.();
2077
+ if (true && cleanup !== undefined && typeof cleanup !== "function") {
2078
+ throw new Error(
2079
+ "Reaction callback returned an invalid cleanup value. Return a cleanup function or undefined."
2080
+ );
2081
+ }
2082
+ cl = cleanup;
2019
2083
  dispose(node);
2020
2084
  },
2021
2085
  effectFn.error,
@@ -2055,9 +2119,14 @@ function createOptimistic(first, second, third) {
2055
2119
  function onSettled(callback) {
2056
2120
  const owner = getOwner();
2057
2121
  owner && !owner._childrenForbidden
2058
- ? createTrackedEffect(() => untrack(callback))
2122
+ ? createTrackedEffect(() => untrack(callback), { name: "onSettled" })
2059
2123
  : globalQueue.enqueue(EFFECT_USER, () => {
2060
2124
  const cleanup = callback();
2125
+ if (cleanup !== undefined && typeof cleanup !== "function") {
2126
+ throw new Error(
2127
+ "onSettled callback returned an invalid cleanup value. Return a cleanup function or undefined."
2128
+ );
2129
+ }
2061
2130
  cleanup?.();
2062
2131
  });
2063
2132
  }