@estjs/signals 0.0.15 → 0.0.16-beta.1

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.
@@ -3,8 +3,6 @@
3
3
  var shared = require('@estjs/shared');
4
4
 
5
5
  var __defProp = Object.defineProperty;
6
- var __defProps = Object.defineProperties;
7
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
8
6
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
9
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
10
8
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
@@ -20,7 +18,6 @@ var __spreadValues = (a, b) => {
20
18
  }
21
19
  return a;
22
20
  };
23
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
24
21
 
25
22
  // src/constants.ts
26
23
  var TriggerOpTypes = {
@@ -110,6 +107,23 @@ function shallowPropagate(link) {
110
107
  var currentLinkVersion = 0;
111
108
  var activeSub;
112
109
  var isUntracking = false;
110
+ var Dep = class {
111
+ constructor(map, key) {
112
+ this.map = map;
113
+ this.key = key;
114
+ this.isDep = true;
115
+ this.flag = 0 /* NONE */;
116
+ }
117
+ get subLink() {
118
+ return this._subLink;
119
+ }
120
+ set subLink(value) {
121
+ this._subLink = value;
122
+ if (value === void 0) {
123
+ this.map.delete(this.key);
124
+ }
125
+ }
126
+ };
113
127
  function linkReactiveNode(depNode, subNode) {
114
128
  if (isUntracking) {
115
129
  return void 0;
@@ -198,7 +212,9 @@ function unlinkReactiveNode(linkNode, subNode = linkNode.subNode) {
198
212
  toRemove = unlinkReactiveNode(toRemove, depNode);
199
213
  }
200
214
  depNode.depLinkTail = void 0;
201
- depNode.flag |= 16 /* DIRTY */;
215
+ if (!depNode.isDep) {
216
+ depNode.flag |= 16 /* DIRTY */;
217
+ }
202
218
  {
203
219
  if (depNode.depLink) {
204
220
  shared.error(
@@ -329,17 +345,14 @@ function collectTriggeredEffects(dep, effects, version) {
329
345
  if (!dep) {
330
346
  return;
331
347
  }
332
- dep.forEach((effect2) => {
333
- if (effect2.flag & 2 /* WATCHING */ && !effect2._active) {
334
- dep.delete(effect2);
335
- return;
336
- }
348
+ for (let link = dep.subLink; link; link = link.nextSubLink) {
349
+ const effect2 = link.subNode;
337
350
  if (effect2._triggerVersion === version) {
338
- return;
351
+ continue;
339
352
  }
340
353
  effect2._triggerVersion = version;
341
354
  effects.push(effect2);
342
- });
355
+ }
343
356
  }
344
357
  function track(target, key) {
345
358
  if (!activeSub || isUntracking) {
@@ -352,19 +365,10 @@ function track(target, key) {
352
365
  }
353
366
  let dep = depsMap.get(key);
354
367
  if (!dep) {
355
- dep = /* @__PURE__ */ new Set();
368
+ dep = new Dep(depsMap, key);
356
369
  depsMap.set(key, dep);
357
370
  }
358
- const sizeBefore = dep.size ;
359
- dep.add(activeSub);
360
- if (dep.size !== sizeBefore && shared.isFunction(activeSub.onTrack)) {
361
- activeSub.onTrack({
362
- effect: activeSub,
363
- target,
364
- type: "get",
365
- key
366
- });
367
- }
371
+ linkReactiveNode(dep, activeSub);
368
372
  }
369
373
  function trigger(target, type, key, newValue) {
370
374
  var _a5;
@@ -479,8 +483,7 @@ function createArrayInstrumentations() {
479
483
  instrumentations[key] = function(...args) {
480
484
  const arr = toRaw(this);
481
485
  track(arr, ARRAY_ITERATE_KEY);
482
- const res = Array.prototype[key].apply(arr, args);
483
- return res;
486
+ return Array.prototype[key].apply(this, args);
484
487
  };
485
488
  });
486
489
  ["join", "toString", "toLocaleString"].forEach((key) => {
@@ -497,6 +500,9 @@ function createArrayInstrumentations() {
497
500
  track(arr, ARRAY_KEY);
498
501
  const rawIterator = key === Symbol.iterator ? arr[Symbol.iterator]() : arr[key]();
499
502
  return {
503
+ /**
504
+ * Returns the next iterator result.
505
+ */
500
506
  next() {
501
507
  const { value, done } = rawIterator.next();
502
508
  if (done) {
@@ -513,6 +519,9 @@ function createArrayInstrumentations() {
513
519
  done
514
520
  };
515
521
  },
522
+ /**
523
+ * Returns an iterator for the current collection.
524
+ */
516
525
  [Symbol.iterator]() {
517
526
  return this;
518
527
  }
@@ -561,6 +570,9 @@ var arrayHandlers = (shallow) => ({
561
570
  var shallowArrayHandlers = arrayHandlers(true);
562
571
  var deepArrayHandlers = arrayHandlers(false);
563
572
  var collectionHandlers = {
573
+ /**
574
+ * Exposes collection proxy flags and instrumented methods.
575
+ */
564
576
  get(target, key) {
565
577
  if (key === "_IS_REACTIVE" /* IS_REACTIVE */) {
566
578
  return true;
@@ -576,6 +588,9 @@ var collectionHandlers = {
576
588
  }
577
589
  };
578
590
  var weakCollectionHandlers = {
591
+ /**
592
+ * Exposes weak-collection proxy flags and instrumented methods.
593
+ */
579
594
  get(target, key) {
580
595
  if (key === "_IS_REACTIVE" /* IS_REACTIVE */) {
581
596
  return true;
@@ -591,6 +606,9 @@ var weakCollectionHandlers = {
591
606
  }
592
607
  };
593
608
  var collectionInstrumentations = {
609
+ /**
610
+ * Reads a Map entry with dependency tracking.
611
+ */
594
612
  get(key) {
595
613
  const target = toRaw(this);
596
614
  track(target, COLLECTION_KEY);
@@ -600,6 +618,9 @@ var collectionInstrumentations = {
600
618
  }
601
619
  return value;
602
620
  },
621
+ /**
622
+ * Sets the requested value.
623
+ */
603
624
  set(key, value) {
604
625
  const target = toRaw(this);
605
626
  const hadKey = target.has(key);
@@ -611,6 +632,9 @@ var collectionInstrumentations = {
611
632
  }
612
633
  return this;
613
634
  },
635
+ /**
636
+ * Adds the requested value.
637
+ */
614
638
  add(value) {
615
639
  const target = toRaw(this);
616
640
  const rawValue = toRaw(value);
@@ -618,11 +642,12 @@ var collectionInstrumentations = {
618
642
  target.add(rawValue);
619
643
  if (!hadValue) {
620
644
  trigger(target, TriggerOpTypes.ADD, COLLECTION_KEY);
621
- } else {
622
- trigger(target, TriggerOpTypes.SET, COLLECTION_KEY);
623
645
  }
624
646
  return this;
625
647
  },
648
+ /**
649
+ * Returns whether the requested value exists.
650
+ */
626
651
  has(key) {
627
652
  const target = toRaw(this);
628
653
  track(target, COLLECTION_KEY);
@@ -632,6 +657,9 @@ var collectionInstrumentations = {
632
657
  }
633
658
  return hasKey;
634
659
  },
660
+ /**
661
+ * Deletes the requested value.
662
+ */
635
663
  delete(key) {
636
664
  const target = toRaw(this);
637
665
  const hadKey = target.has(key);
@@ -644,6 +672,9 @@ var collectionInstrumentations = {
644
672
  }
645
673
  return result;
646
674
  },
675
+ /**
676
+ * Clears the current collection.
677
+ */
647
678
  clear() {
648
679
  const target = toRaw(this);
649
680
  const hadItems = target.size > 0;
@@ -653,6 +684,9 @@ var collectionInstrumentations = {
653
684
  }
654
685
  return result;
655
686
  },
687
+ /**
688
+ * Iterates over each collection entry.
689
+ */
656
690
  forEach(callback, thisArg) {
657
691
  const target = toRaw(this);
658
692
  const isShallowMode = isShallow(this);
@@ -663,12 +697,18 @@ var collectionInstrumentations = {
663
697
  callback.call(thisArg, wrappedValue, wrappedKey, this);
664
698
  });
665
699
  },
700
+ /**
701
+ * Returns an iterator for the current collection.
702
+ */
666
703
  [Symbol.iterator]() {
667
704
  const target = toRaw(this);
668
705
  const isShallowMode = isShallow(this);
669
706
  track(target, COLLECTION_KEY);
670
707
  const rawIterator = target[Symbol.iterator]();
671
708
  return {
709
+ /**
710
+ * Returns the next iterator result.
711
+ */
672
712
  next() {
673
713
  const { value, done } = rawIterator.next();
674
714
  if (done) {
@@ -688,22 +728,34 @@ var collectionInstrumentations = {
688
728
  done
689
729
  };
690
730
  },
731
+ /**
732
+ * Returns an iterator for the current collection.
733
+ */
691
734
  [Symbol.iterator]() {
692
735
  return this;
693
736
  }
694
737
  };
695
738
  },
739
+ /**
740
+ * Returns the current collection size.
741
+ */
696
742
  get size() {
697
743
  const target = toRaw(this);
698
744
  track(target, COLLECTION_KEY);
699
745
  return target.size;
700
746
  },
747
+ /**
748
+ * Returns an iterator over the current keys.
749
+ */
701
750
  keys() {
702
751
  const target = toRaw(this);
703
752
  const isShallowMode = isShallow(this);
704
753
  track(target, COLLECTION_KEY);
705
754
  const rawIterator = target.keys();
706
755
  return {
756
+ /**
757
+ * Returns the next iterator result.
758
+ */
707
759
  next() {
708
760
  const { value, done } = rawIterator.next();
709
761
  if (done) {
@@ -714,17 +766,26 @@ var collectionInstrumentations = {
714
766
  done
715
767
  };
716
768
  },
769
+ /**
770
+ * Returns an iterator for the current collection.
771
+ */
717
772
  [Symbol.iterator]() {
718
773
  return this;
719
774
  }
720
775
  };
721
776
  },
777
+ /**
778
+ * Returns an iterator over the current values.
779
+ */
722
780
  values() {
723
781
  const target = toRaw(this);
724
782
  const isShallowMode = isShallow(this);
725
783
  track(target, COLLECTION_KEY);
726
784
  const rawIterator = target.values();
727
785
  return {
786
+ /**
787
+ * Returns the next iterator result.
788
+ */
728
789
  next() {
729
790
  const { value, done } = rawIterator.next();
730
791
  if (done) {
@@ -735,17 +796,26 @@ var collectionInstrumentations = {
735
796
  done
736
797
  };
737
798
  },
799
+ /**
800
+ * Returns an iterator for the current collection.
801
+ */
738
802
  [Symbol.iterator]() {
739
803
  return this;
740
804
  }
741
805
  };
742
806
  },
807
+ /**
808
+ * Returns an iterator over the current entries.
809
+ */
743
810
  entries() {
744
811
  const target = toRaw(this);
745
812
  const isShallowMode = isShallow(this);
746
813
  track(target, COLLECTION_KEY);
747
814
  const rawIterator = target.entries();
748
815
  return {
816
+ /**
817
+ * Returns the next iterator result.
818
+ */
749
819
  next() {
750
820
  const { value, done } = rawIterator.next();
751
821
  if (done) {
@@ -759,6 +829,9 @@ var collectionInstrumentations = {
759
829
  done
760
830
  };
761
831
  },
832
+ /**
833
+ * Returns an iterator for the current collection.
834
+ */
762
835
  [Symbol.iterator]() {
763
836
  return this;
764
837
  }
@@ -766,6 +839,9 @@ var collectionInstrumentations = {
766
839
  }
767
840
  };
768
841
  var weakInstrumentations = {
842
+ /**
843
+ * Reads a WeakMap entry with dependency tracking.
844
+ */
769
845
  get(key) {
770
846
  const target = toRaw(this);
771
847
  track(target, WEAK_COLLECTION_KEY);
@@ -778,6 +854,9 @@ var weakInstrumentations = {
778
854
  }
779
855
  return value;
780
856
  },
857
+ /**
858
+ * Sets the requested value.
859
+ */
781
860
  set(key, value) {
782
861
  const target = toRaw(this);
783
862
  const rawKey = toRaw(key);
@@ -790,6 +869,9 @@ var weakInstrumentations = {
790
869
  }
791
870
  return this;
792
871
  },
872
+ /**
873
+ * Adds the requested value.
874
+ */
793
875
  add(value) {
794
876
  const target = toRaw(this);
795
877
  const rawValue = toRaw(value);
@@ -800,6 +882,9 @@ var weakInstrumentations = {
800
882
  }
801
883
  return this;
802
884
  },
885
+ /**
886
+ * Returns whether the requested value exists.
887
+ */
803
888
  has(key) {
804
889
  const target = toRaw(this);
805
890
  track(target, WEAK_COLLECTION_KEY);
@@ -809,6 +894,9 @@ var weakInstrumentations = {
809
894
  }
810
895
  return hasKey;
811
896
  },
897
+ /**
898
+ * Deletes the requested value.
899
+ */
812
900
  delete(key) {
813
901
  const target = toRaw(this);
814
902
  const rawKey = toRaw(key);
@@ -821,6 +909,9 @@ var weakInstrumentations = {
821
909
  }
822
910
  };
823
911
  var objectHandlers = (shallow) => ({
912
+ /**
913
+ * Reads an object property, unwraps signals, and tracks the access.
914
+ */
824
915
  get(target, key, receiver) {
825
916
  if (key === "_RAW" /* RAW */) {
826
917
  return target;
@@ -913,6 +1004,7 @@ var toReactive = (value) => shared.isObject(value) ? reactive(value) : value;
913
1004
  var _a;
914
1005
  _a = "_IS_SIGNAL" /* IS_SIGNAL */;
915
1006
  var SignalImpl = class {
1007
+ // Mark as Signal
916
1008
  /**
917
1009
  * Create a new Signal with the given initial value.
918
1010
  *
@@ -922,12 +1014,12 @@ var SignalImpl = class {
922
1014
  constructor(value, shallow = false) {
923
1015
  this.flag = 1 /* MUTABLE */;
924
1016
  // Mark whether it's shallow reactive
925
- // @ts-ignore: used internally by isSignal typeguard
1017
+ // @ts-ignore
926
1018
  this[_a] = true;
927
1019
  const unwrapped = toRaw(value);
928
1020
  this._rawValue = unwrapped;
929
1021
  this["_IS_SHALLOW" /* IS_SHALLOW */] = shallow;
930
- if (!shared.isObject(unwrapped)) {
1022
+ if (!shouldWrapReactiveValue(unwrapped)) {
931
1023
  this._value = unwrapped;
932
1024
  } else {
933
1025
  if (isReactive(value)) {
@@ -937,10 +1029,19 @@ var SignalImpl = class {
937
1029
  }
938
1030
  }
939
1031
  }
940
- // dep getter, returns itself for dependency collection
1032
+ /**
1033
+ * Returns the dependency node used for tracking.
1034
+ *
1035
+ * @returns {this} The dependency node.
1036
+ */
941
1037
  get dep() {
942
1038
  return this;
943
1039
  }
1040
+ /**
1041
+ * Returns the current value.
1042
+ *
1043
+ * @returns {T} The current value.
1044
+ */
944
1045
  get value() {
945
1046
  const sub = activeSub;
946
1047
  if (sub) {
@@ -955,7 +1056,11 @@ var SignalImpl = class {
955
1056
  }
956
1057
  return this._value;
957
1058
  }
958
- // value setter, triggers update when value changes
1059
+ /**
1060
+ * Updates the current value.
1061
+ *
1062
+ * @param newValue - The new value to set.
1063
+ */
959
1064
  set value(newValue) {
960
1065
  if (isSignal(newValue)) {
961
1066
  {
@@ -973,7 +1078,7 @@ var SignalImpl = class {
973
1078
  this._oldValue = this._rawValue;
974
1079
  this._rawValue = rawValue;
975
1080
  this.flag |= 16 /* DIRTY */;
976
- if (!shared.isObject(rawValue)) {
1081
+ if (!shouldWrapReactiveValue(rawValue)) {
977
1082
  this._value = rawValue;
978
1083
  } else if (isReactive(originalValue)) {
979
1084
  this._value = originalValue;
@@ -986,7 +1091,11 @@ var SignalImpl = class {
986
1091
  propagate(subs);
987
1092
  }
988
1093
  }
989
- // Check if the value should be updated
1094
+ /**
1095
+ * Check if the value should be updated.
1096
+ *
1097
+ * @returns {boolean} True if the value should be updated.
1098
+ */
990
1099
  shouldUpdate() {
991
1100
  this.flag &= -17 /* DIRTY */;
992
1101
  if (!("_oldValue" in this)) {
@@ -996,15 +1105,29 @@ var SignalImpl = class {
996
1105
  this._oldValue = this._rawValue;
997
1106
  return changed;
998
1107
  }
999
- // Get current value without triggering dependency tracking
1108
+ /**
1109
+ * Get current value without triggering dependency tracking.
1110
+ *
1111
+ * @returns {T} The current value.
1112
+ */
1000
1113
  peek() {
1001
1114
  return this._value;
1002
1115
  }
1003
- // set method is an alias for the value setter
1116
+ /**
1117
+ * Sets the requested value.
1118
+ *
1119
+ * @param value - The new value to set.
1120
+ * @returns {void}
1121
+ */
1004
1122
  set(value) {
1005
1123
  this.value = value;
1006
1124
  }
1007
- // Update value using an updater function
1125
+ /**
1126
+ * Update value using an updater function.
1127
+ *
1128
+ * @param updater - A function that receives the current value and returns the new value.
1129
+ * @returns {void}
1130
+ */
1008
1131
  update(updater) {
1009
1132
  const nextValue = updater(this.peek());
1010
1133
  if (isSignal(nextValue)) {
@@ -1019,6 +1142,10 @@ var SignalImpl = class {
1019
1142
  }
1020
1143
  }
1021
1144
  };
1145
+ function shouldWrapReactiveValue(value) {
1146
+ if (!shared.isObject(value)) return false;
1147
+ return shared.isArray(value) || shared.isMap(value) || shared.isSet(value) || shared.isWeakMap(value) || shared.isWeakSet(value) || shared.isPlainObject(value);
1148
+ }
1022
1149
  function signal(value) {
1023
1150
  if (isSignal(value)) {
1024
1151
  {
@@ -1142,25 +1269,24 @@ var _a2;
1142
1269
  _a2 = "_IS_EFFECT" /* IS_EFFECT */;
1143
1270
  var EffectImpl = class {
1144
1271
  /**
1145
- * Create an Effect instance
1272
+ * Create an Effect instance.
1146
1273
  *
1147
- * @param fn - The effect function
1148
- * @param options - Configuration options
1274
+ * @param fn - The effect function.
1275
+ * @param options - Configuration options.
1149
1276
  */
1150
1277
  constructor(fn, options) {
1151
1278
  this.flag = 2 /* WATCHING */ | 16 /* DIRTY */;
1152
- // @ts-ignore: used internally by isEffect typeguard
1279
+ // @ts-ignore
1153
1280
  this[_a2] = true;
1154
- // State management
1281
+ // State management
1155
1282
  this._active = true;
1156
- var _a5;
1157
1283
  this.fn = fn;
1158
1284
  if (options) {
1159
- const scheduler = (_a5 = options.scheduler) != null ? _a5 : options.flush;
1160
- if (scheduler) {
1161
- this._flushScheduler = shared.isFunction(scheduler) ? () => scheduler(this) : createScheduler(() => this.run(), scheduler);
1285
+ this.options = options;
1286
+ const scheduler = options.flush || options.scheduler;
1287
+ if (scheduler && !shared.isFunction(scheduler)) {
1288
+ this._flushScheduler = createScheduler(() => this.run(), scheduler);
1162
1289
  }
1163
- if (options.onStop) this.onStop = options.onStop;
1164
1290
  {
1165
1291
  if (options.onTrack) this.onTrack = options.onTrack;
1166
1292
  if (options.onTrigger) this.onTrigger = options.onTrigger;
@@ -1168,13 +1294,17 @@ var EffectImpl = class {
1168
1294
  }
1169
1295
  }
1170
1296
  /**
1171
- * Check if the Effect is active
1297
+ * Check if the Effect is active.
1298
+ *
1299
+ * @returns {boolean} True if the effect is active.
1172
1300
  */
1173
1301
  get active() {
1174
1302
  return this._active;
1175
1303
  }
1176
1304
  /**
1177
- * Check if the Effect is dirty (needs re-execution)
1305
+ * Check if the Effect is dirty (needs re-execution).
1306
+ *
1307
+ * @returns {boolean} True if the effect is dirty.
1178
1308
  */
1179
1309
  get dirty() {
1180
1310
  const flags = this.flag;
@@ -1191,57 +1321,39 @@ var EffectImpl = class {
1191
1321
  return false;
1192
1322
  }
1193
1323
  /**
1194
- * Pause Effect execution
1324
+ * Pause Effect execution.
1195
1325
  *
1196
1326
  * When an effect is paused:
1197
- * - It stops responding to dependency changes
1198
- * - Notifications are ignored (see notify method)
1199
- * - DIRTY and PENDING flags are still set when dependencies change
1200
- * - The effect remains active and maintains its dependency links
1327
+ * - It stops responding to dependency changes.
1328
+ * - Notifications are ignored (see notify method).
1329
+ * - DIRTY and PENDING flags are still set when dependencies change.
1330
+ * - The effect remains active and maintains its dependency links.
1201
1331
  *
1202
1332
  * Use cases:
1203
- * - Temporarily disable effects during bulk updates
1204
- * - Prevent effects from running during initialization
1205
- * - Control when side effects should execute
1333
+ * - Temporarily disable effects during bulk updates.
1334
+ * - Prevent effects from running during initialization.
1335
+ * - Control when side effects should execute.
1206
1336
  *
1207
- * @example
1208
- * ```typescript
1209
- * const count = signal(0);
1210
- * const runner = effect(() => console.log(count.value));
1211
- *
1212
- * runner.effect.pause();
1213
- * count.value = 1; // Effect won't run
1214
- * count.value = 2; // Effect won't run
1215
- * runner.effect.resume(); // Effect runs once with latest value
1216
- * ```
1337
+ * @returns {void}
1217
1338
  */
1218
1339
  pause() {
1219
1340
  this.flag |= 256 /* PAUSED */;
1220
1341
  }
1221
1342
  /**
1222
- * Resume Effect execution
1343
+ * Resume Effect execution.
1223
1344
  *
1224
1345
  * When an effect is resumed:
1225
- * - The PAUSED flag is cleared
1346
+ * - The PAUSED flag is cleared.
1226
1347
  * - If dependencies changed during pause (DIRTY or PENDING flags set),
1227
- * the effect executes immediately via notify()
1228
- * - If no changes occurred, the effect simply becomes active again
1348
+ * the effect executes immediately via notify().
1349
+ * - If no changes occurred, the effect simply becomes active again.
1229
1350
  *
1230
1351
  * State management:
1231
- * - Clears PAUSED flag atomically
1232
- * - Checks for accumulated DIRTY/PENDING flags
1233
- * - Triggers execution if needed
1234
- *
1235
- * @example
1236
- * ```typescript
1237
- * const count = signal(0);
1238
- * const runner = effect(() => console.log(count.value));
1352
+ * - Clears PAUSED flag atomically.
1353
+ * - Checks for accumulated DIRTY/PENDING flags.
1354
+ * - Triggers execution if needed.
1239
1355
  *
1240
- * runner.effect.pause();
1241
- * count.value = 1; // Queued
1242
- * count.value = 2; // Queued
1243
- * runner.effect.resume(); // Executes once with count.value = 2
1244
- * ```
1356
+ * @returns {void}
1245
1357
  */
1246
1358
  resume() {
1247
1359
  const flags = this.flag;
@@ -1254,17 +1366,17 @@ var EffectImpl = class {
1254
1366
  }
1255
1367
  }
1256
1368
  /**
1257
- * Execute the Effect function
1258
- *
1259
- * Core execution flow:
1260
- * 1. Check if active
1261
- * 2. Clear dirty flag
1262
- * 3. Start tracking dependencies
1263
- * 4. Execute user function
1264
- * 5. End tracking, clean up stale dependencies
1265
-
1266
- * @returns The return value of the effect function
1267
- */
1369
+ * Execute the Effect function.
1370
+ *
1371
+ * Core execution flow:
1372
+ * 1. Check if active
1373
+ * 2. Clear dirty flag
1374
+ * 3. Start tracking dependencies
1375
+ * 4. Execute user function
1376
+ * 5. End tracking, clean up stale dependencies
1377
+ *
1378
+ * @returns {T} The return value of the effect function.
1379
+ */
1268
1380
  run() {
1269
1381
  if (!this._active) {
1270
1382
  return this.fn();
@@ -1283,7 +1395,9 @@ var EffectImpl = class {
1283
1395
  }
1284
1396
  }
1285
1397
  /**
1286
- * Get or create the job function for this effect
1398
+ * Get or create the job function for this effect.
1399
+ *
1400
+ * @returns {() => void} The job function.
1287
1401
  */
1288
1402
  getJob() {
1289
1403
  if (!this._job) {
@@ -1292,27 +1406,34 @@ var EffectImpl = class {
1292
1406
  return this._job;
1293
1407
  }
1294
1408
  /**
1295
- * Notify that the Effect needs to execute
1409
+ * Notify that the Effect needs to execute.
1296
1410
  *
1297
1411
  * Called by dependent reactive values.
1298
1412
  * Decides whether to execute immediately or defer based on scheduling strategy.
1413
+ *
1414
+ * @returns {void}
1299
1415
  */
1300
1416
  notify() {
1301
- var _a5;
1417
+ var _a5, _b2, _c, _d;
1302
1418
  const flags = this.flag;
1303
1419
  if (!this._active || flags & (256 /* PAUSED */ | 512 /* RUNNING */ | 16 /* DIRTY */)) {
1304
1420
  return;
1305
1421
  }
1306
1422
  this.flag = flags | 16 /* DIRTY */;
1307
- if (this == null ? void 0 : this.onTrigger) {
1308
- this.onTrigger({
1423
+ if ((_a5 = this.options) == null ? void 0 : _a5.onTrigger) {
1424
+ this.options.onTrigger({
1309
1425
  effect: this,
1310
1426
  target: {},
1311
1427
  type: "set"
1312
1428
  });
1313
1429
  }
1314
- if (this._flushScheduler) {
1315
- (_a5 = this._flushScheduler) == null ? void 0 : _a5.call(this);
1430
+ const scheduler = ((_b2 = this.options) == null ? void 0 : _b2.flush) || ((_c = this.options) == null ? void 0 : _c.scheduler);
1431
+ if (scheduler) {
1432
+ if (shared.isFunction(scheduler)) {
1433
+ scheduler(this);
1434
+ } else {
1435
+ (_d = this._flushScheduler) == null ? void 0 : _d.call(this);
1436
+ }
1316
1437
  } else if (isBatching()) {
1317
1438
  queueJob(this.getJob());
1318
1439
  } else {
@@ -1320,16 +1441,19 @@ var EffectImpl = class {
1320
1441
  }
1321
1442
  }
1322
1443
  /**
1323
- * Stop the Effect
1444
+ * Stop the Effect.
1324
1445
  *
1325
1446
  * After stopping:
1326
- * - No longer responds to dependency changes
1327
- * - Disconnects all dependency links
1328
- * - Clears cached job function
1329
- * - Calls onStop callback
1330
- * - Verifies complete cleanup in development mode
1447
+ * - No longer responds to dependency changes.
1448
+ * - Disconnects all dependency links.
1449
+ * - Clears cached job function.
1450
+ * - Calls onStop callback.
1451
+ * - Verifies complete cleanup in development mode.
1452
+ *
1453
+ * @returns {void}
1331
1454
  */
1332
1455
  stop() {
1456
+ var _a5;
1333
1457
  if (!this._active) {
1334
1458
  {
1335
1459
  shared.warn("[Effect] Attempting to stop an already stopped effect.");
@@ -1361,8 +1485,8 @@ var EffectImpl = class {
1361
1485
  );
1362
1486
  }
1363
1487
  }
1364
- if (this == null ? void 0 : this.onStop) {
1365
- this.onStop();
1488
+ if ((_a5 = this.options) == null ? void 0 : _a5.onStop) {
1489
+ this.options.onStop();
1366
1490
  }
1367
1491
  }
1368
1492
  };
@@ -1404,16 +1528,16 @@ var _a3;
1404
1528
  _a3 = "_IS_COMPUTED" /* IS_COMPUTED */;
1405
1529
  var ComputedImpl = class {
1406
1530
  /**
1407
- * Create a Computed instance
1531
+ * Create a Computed instance.
1408
1532
  *
1409
- * @param getter - The computation function
1410
- * @param setter - Optional setter function
1411
- * @param onTrack - Optional debug callback for dependency tracking
1412
- * @param onTrigger - Optional debug callback for triggers
1533
+ * @param getter - The computation function.
1534
+ * @param setter - Optional setter function.
1535
+ * @param onTrack - Optional debug callback for dependency tracking.
1536
+ * @param onTrigger - Optional debug callback for triggers.
1413
1537
  */
1414
1538
  constructor(getter, setter, onTrack, onTrigger) {
1415
1539
  this.flag = 1 /* MUTABLE */ | 16 /* DIRTY */;
1416
- // @ts-ignore: used internally by isComputed typeguard
1540
+ //@ts-ignore
1417
1541
  this[_a3] = true;
1418
1542
  // Cache
1419
1543
  // Use symbol sentinel to distinguish "no value" from undefined/null values
@@ -1424,6 +1548,11 @@ var ComputedImpl = class {
1424
1548
  this.onTrigger = onTrigger;
1425
1549
  this.flag |= 16 /* DIRTY */;
1426
1550
  }
1551
+ /**
1552
+ * Returns the current value.
1553
+ *
1554
+ * @returns {T} The current value.
1555
+ */
1427
1556
  get value() {
1428
1557
  if (activeSub) {
1429
1558
  linkReactiveNode(this, activeSub);
@@ -1447,9 +1576,9 @@ var ComputedImpl = class {
1447
1576
  return this._value;
1448
1577
  }
1449
1578
  /**
1450
- * Set value (only effective when setter is provided)
1579
+ * Set value (only effective when setter is provided).
1451
1580
  *
1452
- * @param newValue - The new value
1581
+ * @param newValue - The new value.
1453
1582
  */
1454
1583
  set value(newValue) {
1455
1584
  if (this.setter) {
@@ -1461,9 +1590,9 @@ var ComputedImpl = class {
1461
1590
  }
1462
1591
  }
1463
1592
  /**
1464
- * Read value without tracking dependencies
1593
+ * Read value without tracking dependencies.
1465
1594
  *
1466
- * @returns Current value
1595
+ * @returns {T} The current value.
1467
1596
  */
1468
1597
  peek() {
1469
1598
  if (this._value === NO_VALUE) {
@@ -1474,7 +1603,7 @@ var ComputedImpl = class {
1474
1603
  /**
1475
1604
  * Recompute the value
1476
1605
  *
1477
- * computation logic:
1606
+ * computation logic:
1478
1607
  * 1. Start tracking dependencies
1479
1608
  * 2. Execute getter function
1480
1609
  * 3. Check if value changed using optimized comparison
@@ -1526,11 +1655,11 @@ var ComputedImpl = class {
1526
1655
  }
1527
1656
  }
1528
1657
  /**
1529
- * Check if update is needed
1658
+ * Check if update is needed.
1530
1659
  *
1531
1660
  * Internal use, called by reactive system.
1532
1661
  *
1533
- * @returns true if value changed
1662
+ * @returns {boolean} True if value changed.
1534
1663
  */
1535
1664
  shouldUpdate() {
1536
1665
  const hadValue = this._value !== NO_VALUE;
@@ -1597,6 +1726,9 @@ function createOptionsStore(options) {
1597
1726
  actionCallbacks.forEach((callback) => callback(state2));
1598
1727
  };
1599
1728
  const defaultActions = {
1729
+ /**
1730
+ * Applies a partial patch to the reactive store state.
1731
+ */
1600
1732
  patch$(payload) {
1601
1733
  if (!payload) {
1602
1734
  shared.warn("Patch payload is required");
@@ -1607,6 +1739,9 @@ function createOptionsStore(options) {
1607
1739
  });
1608
1740
  notifySubscribers(reactiveState);
1609
1741
  },
1742
+ /**
1743
+ * Registers a store subscriber callback.
1744
+ */
1610
1745
  subscribe$(callback) {
1611
1746
  if (!callback) {
1612
1747
  shared.warn("Subscribe callback is required");
@@ -1614,9 +1749,15 @@ function createOptionsStore(options) {
1614
1749
  }
1615
1750
  subscriptions.add(callback);
1616
1751
  },
1752
+ /**
1753
+ * Removes a previously registered store subscriber.
1754
+ */
1617
1755
  unsubscribe$(callback) {
1618
1756
  subscriptions.delete(callback);
1619
1757
  },
1758
+ /**
1759
+ * Registers a callback for store action notifications.
1760
+ */
1620
1761
  onAction$(callback) {
1621
1762
  if (!callback) {
1622
1763
  shared.warn("Action callback is required");
@@ -1624,6 +1765,15 @@ function createOptionsStore(options) {
1624
1765
  }
1625
1766
  actionCallbacks.add(callback);
1626
1767
  },
1768
+ /**
1769
+ * Removes a previously registered action callback.
1770
+ */
1771
+ offAction$(callback) {
1772
+ actionCallbacks.delete(callback);
1773
+ },
1774
+ /**
1775
+ * Resets the reactive state back to its initial snapshot.
1776
+ */
1627
1777
  reset$() {
1628
1778
  batch(() => {
1629
1779
  Object.assign(reactiveState, initState);
@@ -1631,15 +1781,31 @@ function createOptionsStore(options) {
1631
1781
  notifySubscribers(reactiveState);
1632
1782
  }
1633
1783
  };
1634
- const store = __spreadValues(__spreadProps(__spreadValues({}, reactiveState), {
1635
- state: reactiveState
1636
- }), defaultActions);
1784
+ const store = {};
1785
+ for (const key of Object.keys(initState)) {
1786
+ Object.defineProperty(store, key, {
1787
+ get: () => reactiveState[key],
1788
+ set: (value) => {
1789
+ reactiveState[key] = value;
1790
+ },
1791
+ enumerable: true,
1792
+ configurable: true
1793
+ });
1794
+ }
1795
+ Object.defineProperty(store, "state", {
1796
+ value: reactiveState,
1797
+ enumerable: true,
1798
+ configurable: true,
1799
+ writable: true
1800
+ });
1801
+ Object.assign(store, defaultActions);
1637
1802
  if (getters) {
1638
1803
  for (const key in getters) {
1639
1804
  const getter = getters[key];
1640
1805
  if (!getter) continue;
1806
+ const getterValue = computed(() => getter.call(store, reactiveState));
1641
1807
  Object.defineProperty(store, key, {
1642
- get: () => computed(() => getter.call(store, reactiveState)).value,
1808
+ get: () => getterValue.value,
1643
1809
  enumerable: true,
1644
1810
  configurable: true
1645
1811
  });
@@ -1649,11 +1815,11 @@ function createOptionsStore(options) {
1649
1815
  for (const key in actions) {
1650
1816
  const action = actions[key];
1651
1817
  if (action) {
1652
- Reflect.set(store, key, (...args) => {
1653
- const result = action.apply(reactiveState, args);
1818
+ store[key] = (...args) => {
1819
+ const result = action.apply(store, args);
1654
1820
  actionCallbacks.forEach((callback) => callback(reactiveState));
1655
1821
  return result;
1656
- });
1822
+ };
1657
1823
  }
1658
1824
  }
1659
1825
  }
@@ -1670,11 +1836,11 @@ function createClassStore(StoreClass) {
1670
1836
  Object.getOwnPropertyNames(StoreClass.prototype).forEach((key) => {
1671
1837
  const descriptor = Object.getOwnPropertyDescriptor(StoreClass.prototype, key);
1672
1838
  if (descriptor) {
1673
- if (typeof descriptor.get === "function") {
1839
+ if (shared.isFunction(descriptor.get)) {
1674
1840
  getters[key] = function() {
1675
1841
  return descriptor.get.call(this);
1676
1842
  };
1677
- } else if (typeof descriptor.value === "function" && key !== "constructor") {
1843
+ } else if (shared.isFunction(descriptor.value) && key !== "constructor") {
1678
1844
  actions[key] = function(...args) {
1679
1845
  return descriptor.value.apply(this, args);
1680
1846
  };
@@ -1699,13 +1865,7 @@ function createStore(storeDefinition) {
1699
1865
  } else {
1700
1866
  options = storeDefinition;
1701
1867
  }
1702
- const store = createOptionsStore(options);
1703
- if (shared.isFunction(storeDefinition) && options.actions) {
1704
- Object.keys(options.actions).forEach((key) => {
1705
- Reflect.set(store, key, options.actions[key].bind(store));
1706
- });
1707
- }
1708
- return store;
1868
+ return createOptionsStore(options);
1709
1869
  };
1710
1870
  }
1711
1871
  var _a4, _b;
@@ -1717,9 +1877,14 @@ var RefImpl = class extends (_b = SignalImpl, _a4 = "_IS_REF" /* IS_REF */, _b)
1717
1877
  */
1718
1878
  constructor(value) {
1719
1879
  super(value, true);
1720
- // @ts-ignore: used internally by isRef typeguard
1880
+ // @ts-ignore
1721
1881
  this[_a4] = true;
1722
1882
  }
1883
+ /**
1884
+ * Returns the current value.
1885
+ *
1886
+ * @returns {T} The current value.
1887
+ */
1723
1888
  get value() {
1724
1889
  const sub = activeSub;
1725
1890
  if (sub) {
@@ -1727,6 +1892,11 @@ var RefImpl = class extends (_b = SignalImpl, _a4 = "_IS_REF" /* IS_REF */, _b)
1727
1892
  }
1728
1893
  return this._value;
1729
1894
  }
1895
+ /**
1896
+ * Updates the current value.
1897
+ *
1898
+ * @param newValue - The new value.
1899
+ */
1730
1900
  set value(newValue) {
1731
1901
  if (isSignal(newValue)) {
1732
1902
  newValue = newValue.peek();
@@ -1757,8 +1927,12 @@ function isRef(value) {
1757
1927
  return !!value && !!value["_IS_REF" /* IS_REF */];
1758
1928
  }
1759
1929
  var INITIAL_WATCHER_VALUE = {};
1760
- var cleanupMap = /* @__PURE__ */ new WeakMap();
1761
- function traverse(value, seen = /* @__PURE__ */ new Set()) {
1930
+ var _traverseSeen = /* @__PURE__ */ new Set();
1931
+ function traverse(value, seen) {
1932
+ if (!seen) {
1933
+ _traverseSeen.clear();
1934
+ seen = _traverseSeen;
1935
+ }
1762
1936
  if (!shared.isObject(value) || seen.has(value)) {
1763
1937
  return value;
1764
1938
  }
@@ -1789,54 +1963,13 @@ function traverse(value, seen = /* @__PURE__ */ new Set()) {
1789
1963
  return value;
1790
1964
  }
1791
1965
  function cloneValue(value) {
1792
- if (!shared.isObject(value)) {
1793
- return value;
1794
- }
1795
- if (Array.isArray(value)) {
1796
- return value.map((item) => cloneValue(item));
1797
- }
1798
- if (shared.isMap(value)) {
1799
- const cloned2 = /* @__PURE__ */ new Map();
1800
- value.forEach((v, k) => {
1801
- cloned2.set(k, cloneValue(v));
1802
- });
1803
- return cloned2;
1804
- }
1805
- if (shared.isSet(value)) {
1806
- const cloned2 = /* @__PURE__ */ new Set();
1807
- value.forEach((v) => {
1808
- cloned2.add(cloneValue(v));
1809
- });
1810
- return cloned2;
1811
- }
1812
- const cloned = {};
1813
- for (const key of Object.keys(value)) {
1814
- cloned[key] = cloneValue(value[key]);
1815
- }
1816
- return cloned;
1966
+ return value;
1817
1967
  }
1818
- function resolveSource(source) {
1819
- if (Array.isArray(source)) {
1820
- return () => source.map((s) => {
1821
- if (isSignal(s) || isComputed(s)) {
1822
- return s.value;
1823
- }
1824
- if (isReactive(s)) {
1825
- return traverse(s);
1826
- }
1827
- if (shared.isFunction(s)) {
1828
- return s();
1829
- }
1830
- return s;
1831
- });
1832
- }
1968
+ function resolveSingleSource(source) {
1833
1969
  if (shared.isFunction(source)) {
1834
1970
  return source;
1835
1971
  }
1836
- if (isSignal(source)) {
1837
- return () => source.value;
1838
- }
1839
- if (shared.isObject(source) && "value" in source) {
1972
+ if (isSignal(source) || isComputed(source)) {
1840
1973
  return () => source.value;
1841
1974
  }
1842
1975
  if (isReactive(source)) {
@@ -1844,6 +1977,13 @@ function resolveSource(source) {
1844
1977
  }
1845
1978
  return () => source;
1846
1979
  }
1980
+ function resolveSource(source) {
1981
+ if (Array.isArray(source)) {
1982
+ const getters = source.map((s) => resolveSingleSource(s));
1983
+ return () => getters.map((g) => g());
1984
+ }
1985
+ return resolveSingleSource(source);
1986
+ }
1847
1987
  function watch(source, callback, options = {}) {
1848
1988
  const { immediate = false, deep = false } = options;
1849
1989
  let oldValue = INITIAL_WATCHER_VALUE;
@@ -1854,7 +1994,7 @@ function watch(source, callback, options = {}) {
1854
1994
  return;
1855
1995
  }
1856
1996
  const newValue = currentEffect.run();
1857
- if (shared.hasChanged(newValue, oldValue)) {
1997
+ if (deep || shared.isObject(newValue) || shared.hasChanged(newValue, oldValue)) {
1858
1998
  callback(newValue, oldValue === INITIAL_WATCHER_VALUE ? void 0 : oldValue);
1859
1999
  oldValue = cloneValue(newValue);
1860
2000
  }
@@ -1879,11 +2019,6 @@ function watch(source, callback, options = {}) {
1879
2019
  }
1880
2020
  return () => {
1881
2021
  runner.stop();
1882
- const cleanups = cleanupMap.get(runner.effect);
1883
- if (cleanups) {
1884
- cleanups.forEach((fn) => fn());
1885
- cleanupMap.delete(runner.effect);
1886
- }
1887
2022
  };
1888
2023
  }
1889
2024