@estjs/signals 0.0.15 → 0.0.16-beta.2

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