@estjs/signals 0.0.17-beta.7 → 0.0.18-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.
@@ -307,6 +307,17 @@ function isValidLink(checkLink, sub) {
307
307
  }
308
308
  var targetMap = /* @__PURE__ */ new WeakMap();
309
309
  var triggerVersion = 0;
310
+ var triggerEffects = [];
311
+ var triggerDepth = 0;
312
+ function startTriggerEffects() {
313
+ const effects = triggerDepth === 0 ? triggerEffects : [];
314
+ triggerDepth++;
315
+ return effects;
316
+ }
317
+ function endTriggerEffects(effects) {
318
+ effects.length = 0;
319
+ triggerDepth--;
320
+ }
310
321
  function collectTriggeredEffects(dep, effects, version) {
311
322
  if (!dep) {
312
323
  return;
@@ -337,46 +348,127 @@ function track(target, key) {
337
348
  linkReactiveNode(dep, activeSub);
338
349
  }
339
350
  function trigger(target, type, key, newValue) {
340
- var _a5;
351
+ var _a6;
341
352
  const depsMap = targetMap.get(target);
342
353
  if (!depsMap) {
343
354
  return;
344
355
  }
345
- const effects = [];
356
+ const effects = startTriggerEffects();
346
357
  const version = ++triggerVersion;
347
- if (key !== void 0) {
348
- if (Array.isArray(key)) {
349
- for (const element of key) {
350
- collectTriggeredEffects(depsMap.get(element), effects, version);
358
+ try {
359
+ if (key !== void 0) {
360
+ if (shared.isArray(key)) {
361
+ for (const element of key) {
362
+ collectTriggeredEffects(depsMap.get(element), effects, version);
363
+ }
364
+ } else {
365
+ collectTriggeredEffects(depsMap.get(key), effects, version);
351
366
  }
352
- } else {
353
- collectTriggeredEffects(depsMap.get(key), effects, version);
354
367
  }
368
+ if (type === "ADD" || type === "DELETE" || type === "CLEAR") {
369
+ const iterationKey = shared.isArray(target) ? ARRAY_ITERATE_KEY : ITERATE_KEY;
370
+ collectTriggeredEffects(depsMap.get(iterationKey), effects, version);
371
+ }
372
+ for (const effect2 of effects) {
373
+ if (shared.isFunction(effect2.onTrigger)) {
374
+ effect2.onTrigger({
375
+ effect: effect2,
376
+ target,
377
+ type,
378
+ key,
379
+ newValue
380
+ });
381
+ }
382
+ if (effect2.flag & 2 /* WATCHING */) {
383
+ (_a6 = effect2.notify) == null ? void 0 : _a6.call(effect2);
384
+ } else if (effect2.flag & 1 /* MUTABLE */) {
385
+ effect2.flag |= 16 /* DIRTY */;
386
+ if (effect2.subLink) {
387
+ propagate(effect2.subLink);
388
+ }
389
+ }
390
+ }
391
+ } finally {
392
+ endTriggerEffects(effects);
355
393
  }
356
- if (type === "ADD" || type === "DELETE" || type === "CLEAR") {
357
- const iterationKey = Array.isArray(target) ? ARRAY_ITERATE_KEY : ITERATE_KEY;
358
- collectTriggeredEffects(depsMap.get(iterationKey), effects, version);
359
- }
360
- for (const effect2 of effects) {
361
- if (shared.isFunction(effect2.onTrigger)) {
362
- effect2.onTrigger({
363
- effect: effect2,
364
- target,
365
- type,
366
- key,
367
- newValue
368
- });
394
+ }
395
+ function trackNode(node) {
396
+ if (!activeSub || isUntracking) return;
397
+ linkReactiveNode(node, activeSub);
398
+ }
399
+ function triggerNode(node) {
400
+ var _a6;
401
+ const link = node.subLink;
402
+ if (!link) return;
403
+ const effects = startTriggerEffects();
404
+ const version = ++triggerVersion;
405
+ try {
406
+ for (let current = link; current; current = current.nextSubLink) {
407
+ const effect2 = current.subNode;
408
+ if (effect2._triggerVersion === version) {
409
+ continue;
410
+ }
411
+ effect2._triggerVersion = version;
412
+ effects.push(effect2);
369
413
  }
370
- if (effect2.flag & 2 /* WATCHING */) {
371
- (_a5 = effect2.notify) == null ? void 0 : _a5.call(effect2);
372
- } else if (effect2.flag & 1 /* MUTABLE */) {
373
- effect2.flag |= 16 /* DIRTY */;
374
- if (effect2.subLink) {
375
- propagate(effect2.subLink);
414
+ for (const effect2 of effects) {
415
+ if (effect2.flag & 2 /* WATCHING */) {
416
+ (_a6 = effect2.notify) == null ? void 0 : _a6.call(effect2);
417
+ } else if (effect2.flag & 1 /* MUTABLE */) {
418
+ effect2.flag |= 16 /* DIRTY */;
419
+ if (effect2.subLink) {
420
+ propagate(effect2.subLink);
421
+ }
376
422
  }
377
423
  }
424
+ } finally {
425
+ endTriggerEffects(effects);
378
426
  }
379
427
  }
428
+ var ReactiveProperty = class {
429
+ constructor(_target, _key) {
430
+ this._target = _target;
431
+ this._key = _key;
432
+ this.flag = 1 /* MUTABLE */;
433
+ }
434
+ /**
435
+ * Read the property value and track the dependency.
436
+ *
437
+ * Uses trackNode(this) — bypasses targetMap/Dep. The ReactiveProperty itself
438
+ * IS the depNode, so linkReactiveNode connects the active subscriber directly
439
+ * to this node's subLink chain.
440
+ *
441
+ * Nested proxy wrapping and signal auto-unwrapping are handled by the caller
442
+ * (the reactive proxy get trap), keeping this method self-contained and free
443
+ * of a circular dependency on the rest of reactive.ts.
444
+ */
445
+ getValue() {
446
+ trackNode(this);
447
+ return this._target[this._key];
448
+ }
449
+ /**
450
+ * Update the property value and notify subscribers.
451
+ *
452
+ * Uses triggerNode(this) — directly walks the subLink chain, bypassing
453
+ * targetMap + collectTriggeredEffects.
454
+ *
455
+ * @param rawValue - The new (already unrawed) value.
456
+ * @param oldValue - The previous value, read BEFORE Reflect.set.
457
+ */
458
+ setValue(rawValue, oldValue) {
459
+ if (Object.is(oldValue, rawValue)) {
460
+ return;
461
+ }
462
+ triggerNode(this);
463
+ }
464
+ /**
465
+ * Invalidate this property (called on delete).
466
+ * Notifies subscribers that the value is gone.
467
+ */
468
+ invalidate() {
469
+ triggerNode(this);
470
+ }
471
+ };
380
472
  var reactiveCaches = /* @__PURE__ */ new WeakMap();
381
473
  var shallowReactiveCaches = /* @__PURE__ */ new WeakMap();
382
474
  function toRaw(value) {
@@ -435,7 +527,7 @@ function createArrayInstrumentations() {
435
527
  const isShallowMode = isShallow(this);
436
528
  track(arr, ARRAY_ITERATE_KEY);
437
529
  const res = Array.prototype[key].apply(arr, args);
438
- if (!Array.isArray(res)) {
530
+ if (!shared.isArray(res)) {
439
531
  return res;
440
532
  }
441
533
  return res.map((item) => shared.isObject(item) ? reactiveImpl(item, isShallowMode) : item);
@@ -470,7 +562,7 @@ function createArrayInstrumentations() {
470
562
  if (done) {
471
563
  return { value, done };
472
564
  }
473
- if (Array.isArray(value)) {
565
+ if (shared.isArray(value)) {
474
566
  return {
475
567
  value: value.map((v) => shared.isObject(v) ? reactiveImpl(v, isShallowMode) : v),
476
568
  done
@@ -532,6 +624,32 @@ var arrayHandlers = (shallow) => ({
532
624
  }
533
625
  }
534
626
  return result;
627
+ },
628
+ has: (target, key) => {
629
+ const result = Reflect.has(target, key);
630
+ if (typeof key !== "symbol") {
631
+ if (shared.isStringNumber(key)) {
632
+ track(target, key);
633
+ }
634
+ track(target, ARRAY_KEY);
635
+ }
636
+ return result;
637
+ },
638
+ deleteProperty: (target, key) => {
639
+ const hadKey = shared.hasOwn(target, key);
640
+ const result = Reflect.deleteProperty(target, key);
641
+ if (hadKey && result) {
642
+ if (shared.isStringNumber(key)) {
643
+ trigger(target, TriggerOpTypes.DELETE, [key, ARRAY_ITERATE_KEY, ARRAY_KEY]);
644
+ } else {
645
+ trigger(target, TriggerOpTypes.DELETE, key);
646
+ }
647
+ }
648
+ return result;
649
+ },
650
+ ownKeys: (target) => {
651
+ track(target, ARRAY_ITERATE_KEY);
652
+ return Reflect.ownKeys(target);
535
653
  }
536
654
  });
537
655
  var shallowArrayHandlers = arrayHandlers(true);
@@ -698,7 +816,7 @@ var collectionInstrumentations = {
698
816
  if (isShallowMode) {
699
817
  return { value, done };
700
818
  }
701
- if (Array.isArray(value)) {
819
+ if (shared.isArray(value)) {
702
820
  return {
703
821
  value: value.map((v) => shared.isObject(v) ? reactiveImpl(v) : v),
704
822
  done
@@ -889,9 +1007,43 @@ var weakInstrumentations = {
889
1007
  return result;
890
1008
  }
891
1009
  };
1010
+ var targetPropertyMaps = /* @__PURE__ */ new WeakMap();
1011
+ function getTargetDepSize(target, key) {
1012
+ var _a6, _b2;
1013
+ const rawTarget = (_a6 = target["_RAW" /* RAW */]) != null ? _a6 : target;
1014
+ const prop = (_b2 = targetPropertyMaps.get(rawTarget)) == null ? void 0 : _b2.get(key);
1015
+ if (!(prop == null ? void 0 : prop.subLink)) return 0;
1016
+ let size = 0;
1017
+ for (let link = prop.subLink; link; link = link.nextSubLink) size++;
1018
+ return size;
1019
+ }
1020
+ function getPropertyMap(target) {
1021
+ let map = targetPropertyMaps.get(target);
1022
+ if (!map) {
1023
+ map = /* @__PURE__ */ new Map();
1024
+ targetPropertyMaps.set(target, map);
1025
+ }
1026
+ return map;
1027
+ }
1028
+ function trackProperty(target, key) {
1029
+ if (!activeSub) {
1030
+ return target[key];
1031
+ }
1032
+ const pm = getPropertyMap(target);
1033
+ let prop = pm.get(key);
1034
+ if (!prop) {
1035
+ prop = new ReactiveProperty(target, key);
1036
+ pm.set(key, prop);
1037
+ }
1038
+ return prop.getValue();
1039
+ }
892
1040
  var objectHandlers = (shallow) => ({
893
1041
  /**
894
1042
  * Reads an object property, unwraps signals, and tracks the access.
1043
+ *
1044
+ * Own properties use the per-property signal fast path (trackNode),
1045
+ * which bypasses the targetMap → Map → Dep indirection.
1046
+ * Prototype-chain properties fall back to the standard track() path.
895
1047
  */
896
1048
  get(target, key, receiver) {
897
1049
  if (key === "_RAW" /* RAW */) {
@@ -903,6 +1055,14 @@ var objectHandlers = (shallow) => ({
903
1055
  if (key === "_IS_SHALLOW" /* IS_SHALLOW */) {
904
1056
  return shallow;
905
1057
  }
1058
+ if (activeSub && shared.hasOwn(target, key)) {
1059
+ const result = trackProperty(target, key);
1060
+ const unwrapped = isSignal(result) ? result.value : result;
1061
+ if (shared.isObject(unwrapped) && !shallow) {
1062
+ return reactiveImpl(unwrapped);
1063
+ }
1064
+ return unwrapped;
1065
+ }
906
1066
  const value = Reflect.get(target, key, receiver);
907
1067
  const valueUnwrapped = isSignal(value) ? value.value : value;
908
1068
  track(target, key);
@@ -916,6 +1076,14 @@ var objectHandlers = (shallow) => ({
916
1076
  const oldValue = Reflect.get(target, key, receiver);
917
1077
  const rawValue = toRaw(value);
918
1078
  const result = Reflect.set(target, key, rawValue, receiver);
1079
+ if (hadKey) {
1080
+ const pm = targetPropertyMaps.get(target);
1081
+ const prop = pm == null ? void 0 : pm.get(key);
1082
+ if (prop) {
1083
+ prop.setValue(rawValue, oldValue);
1084
+ return result;
1085
+ }
1086
+ }
919
1087
  if (hasStoredValueChanged(rawValue, oldValue)) {
920
1088
  trigger(target, hadKey ? TriggerOpTypes.SET : TriggerOpTypes.ADD, key, rawValue);
921
1089
  }
@@ -925,6 +1093,12 @@ var objectHandlers = (shallow) => ({
925
1093
  const hadKey = shared.hasOwn(target, key);
926
1094
  const result = Reflect.deleteProperty(target, key);
927
1095
  if (hadKey && result) {
1096
+ const pm = targetPropertyMaps.get(target);
1097
+ const prop = pm == null ? void 0 : pm.get(key);
1098
+ if (prop) {
1099
+ pm.delete(key);
1100
+ prop.invalidate();
1101
+ }
928
1102
  trigger(target, TriggerOpTypes.DELETE, key, void 0);
929
1103
  }
930
1104
  return result;
@@ -1156,6 +1330,7 @@ function isSignal(value) {
1156
1330
  }
1157
1331
  var queue = /* @__PURE__ */ new Set();
1158
1332
  var activePreFlushCbs = /* @__PURE__ */ new Set();
1333
+ var activePostFlushCbs = /* @__PURE__ */ new Set();
1159
1334
  var p = Promise.resolve();
1160
1335
  var isFlushPending = false;
1161
1336
  var RECURSION_LIMIT = 100;
@@ -1176,6 +1351,10 @@ function queuePreFlushCb(cb) {
1176
1351
  activePreFlushCbs.add(cb);
1177
1352
  queueFlush();
1178
1353
  }
1354
+ function queuePostFlushJob(cb) {
1355
+ activePostFlushCbs.add(cb);
1356
+ queueFlush();
1357
+ }
1179
1358
  function flushJobs() {
1180
1359
  isFlushPending = false;
1181
1360
  flushPreFlushCbs();
@@ -1188,7 +1367,7 @@ function flushJobs() {
1188
1367
  `[Scheduler] Maximum recursive flush count (${RECURSION_LIMIT}) exceeded. This usually means an effect or watch callback is mutating a reactive dependency it also reads, causing an infinite update loop. The remaining queued jobs have been dropped to keep the app responsive.`
1189
1368
  );
1190
1369
  }
1191
- return;
1370
+ break;
1192
1371
  }
1193
1372
  const jobs = [...queue];
1194
1373
  queue.clear();
@@ -1202,6 +1381,7 @@ function flushJobs() {
1202
1381
  }
1203
1382
  }
1204
1383
  }
1384
+ flushPostFlushCbs();
1205
1385
  }
1206
1386
  function flushPreFlushCbs() {
1207
1387
  const callbacks = Array.from(activePreFlushCbs);
@@ -1216,6 +1396,20 @@ function flushPreFlushCbs() {
1216
1396
  }
1217
1397
  }
1218
1398
  }
1399
+ function flushPostFlushCbs() {
1400
+ if (activePostFlushCbs.size === 0) return;
1401
+ const callbacks = Array.from(activePostFlushCbs);
1402
+ activePostFlushCbs.clear();
1403
+ for (const callback of callbacks) {
1404
+ try {
1405
+ callback();
1406
+ } catch (_error) {
1407
+ {
1408
+ shared.error("Error executing post-flush callback:", _error);
1409
+ }
1410
+ }
1411
+ }
1412
+ }
1219
1413
  function createScheduler(effect2, flush) {
1220
1414
  switch (flush) {
1221
1415
  case "sync":
@@ -1268,7 +1462,7 @@ var EffectScope = class {
1268
1462
  constructor(detached = false, parent = void 0) {
1269
1463
  this.detached = detached;
1270
1464
  this.parent = parent;
1271
- this._active = true;
1465
+ this._state = 0 /* Active */;
1272
1466
  // Use Sets instead of arrays for O(1) add/delete instead of O(n) indexOf+splice
1273
1467
  this.effects = /* @__PURE__ */ new Set();
1274
1468
  this.scopes = /* @__PURE__ */ new Set();
@@ -1279,36 +1473,46 @@ var EffectScope = class {
1279
1473
  }
1280
1474
  }
1281
1475
  get active() {
1282
- return this._active;
1476
+ return this._state !== 2 /* Disposed */;
1477
+ }
1478
+ /** Whether the scope is paused. */
1479
+ get isPaused() {
1480
+ return this._state === 1 /* Paused */;
1481
+ }
1482
+ /** Whether the scope has been stopped / disposed. */
1483
+ get isDisposed() {
1484
+ return this._state === 2 /* Disposed */;
1283
1485
  }
1284
1486
  pause() {
1285
- var _a5;
1286
- if (!this._active) {
1487
+ var _a6;
1488
+ if (this._state !== 0 /* Active */) {
1287
1489
  return;
1288
1490
  }
1491
+ this._state = 1 /* Paused */;
1289
1492
  for (const scope of this.scopes) {
1290
1493
  scope.pause();
1291
1494
  }
1292
1495
  for (const effect2 of this.effects) {
1293
- (_a5 = effect2.pause) == null ? void 0 : _a5.call(effect2);
1496
+ (_a6 = effect2.pause) == null ? void 0 : _a6.call(effect2);
1294
1497
  }
1295
1498
  }
1296
1499
  resume() {
1297
- var _a5;
1298
- if (!this._active) {
1500
+ var _a6;
1501
+ if (this._state !== 1 /* Paused */) {
1299
1502
  return;
1300
1503
  }
1504
+ this._state = 0 /* Active */;
1301
1505
  for (const scope of this.scopes) {
1302
1506
  scope.resume();
1303
1507
  }
1304
1508
  for (const effect2 of this.effects) {
1305
- (_a5 = effect2.resume) == null ? void 0 : _a5.call(effect2);
1509
+ (_a6 = effect2.resume) == null ? void 0 : _a6.call(effect2);
1306
1510
  }
1307
1511
  }
1308
1512
  run(fn) {
1309
- if (!this._active) {
1513
+ if (this._state === 2 /* Disposed */) {
1310
1514
  {
1311
- shared.warn("cannot run an inactive effect scope.");
1515
+ shared.warn("cannot run a disposed effect scope.");
1312
1516
  }
1313
1517
  return;
1314
1518
  }
@@ -1321,27 +1525,42 @@ var EffectScope = class {
1321
1525
  }
1322
1526
  }
1323
1527
  stop(fromParent = false) {
1324
- if (!this._active) {
1528
+ if (this._state === 2 /* Disposed */) {
1325
1529
  return;
1326
1530
  }
1327
- this._active = false;
1328
- for (const scope of this.scopes) {
1329
- scope.stop(true);
1330
- }
1331
- this.scopes.clear();
1332
- const effects = Array.from(this.effects);
1333
- this.effects.clear();
1334
- for (const effect2 of effects) {
1335
- effect2.stop();
1336
- }
1337
- for (let i = 0; i < this.cleanups.length; i++) {
1338
- this.cleanups[i]();
1339
- }
1340
- this.cleanups.length = 0;
1341
- if (!fromParent && this.parent) {
1342
- this.parent.scopes.delete(this);
1531
+ this._state = 2 /* Disposed */;
1532
+ try {
1533
+ for (const scope of this.scopes) {
1534
+ try {
1535
+ scope.stop(true);
1536
+ } catch (error_) {
1537
+ if (true) shared.error("[EffectScope] child scope disposal threw:", error_);
1538
+ }
1539
+ }
1540
+ this.scopes.clear();
1541
+ const effects = Array.from(this.effects);
1542
+ this.effects.clear();
1543
+ for (const effect2 of effects) {
1544
+ try {
1545
+ effect2.stop();
1546
+ } catch (error_) {
1547
+ if (true) shared.error("[EffectScope] effect disposal threw:", error_);
1548
+ }
1549
+ }
1550
+ for (let i = 0; i < this.cleanups.length; i++) {
1551
+ try {
1552
+ this.cleanups[i]();
1553
+ } catch (error_) {
1554
+ if (true) shared.error("[EffectScope] cleanup threw:", error_);
1555
+ }
1556
+ }
1557
+ this.cleanups.length = 0;
1558
+ } finally {
1559
+ if (!fromParent && this.parent) {
1560
+ this.parent.scopes.delete(this);
1561
+ }
1562
+ this.parent = void 0;
1343
1563
  }
1344
- this.parent = void 0;
1345
1564
  }
1346
1565
  _record(effect2) {
1347
1566
  this.effects.add(effect2);
@@ -1509,9 +1728,9 @@ var EffectImpl = class {
1509
1728
  const prevSub = startTracking(this);
1510
1729
  try {
1511
1730
  return this.fn();
1512
- } catch (error5) {
1731
+ } catch (error6) {
1513
1732
  this.flag |= 16 /* DIRTY */;
1514
- throw error5;
1733
+ throw error6;
1515
1734
  } finally {
1516
1735
  this.flag &= -513 /* RUNNING */;
1517
1736
  endTracking(this, prevSub);
@@ -1537,13 +1756,13 @@ var EffectImpl = class {
1537
1756
  * @returns {void}
1538
1757
  */
1539
1758
  notify() {
1540
- var _a5, _b2, _c, _d;
1759
+ var _a6, _b2, _c, _d;
1541
1760
  const flags = this.flag;
1542
1761
  if (!this._active || flags & (256 /* PAUSED */ | 512 /* RUNNING */ | 16 /* DIRTY */)) {
1543
1762
  return;
1544
1763
  }
1545
1764
  this.flag = flags | 16 /* DIRTY */;
1546
- if ((_a5 = this.options) == null ? void 0 : _a5.onTrigger) {
1765
+ if ((_a6 = this.options) == null ? void 0 : _a6.onTrigger) {
1547
1766
  this.options.onTrigger({
1548
1767
  effect: this,
1549
1768
  target: {},
@@ -1576,7 +1795,7 @@ var EffectImpl = class {
1576
1795
  * @returns {void}
1577
1796
  */
1578
1797
  stop() {
1579
- var _a5;
1798
+ var _a6;
1580
1799
  if (!this._active) {
1581
1800
  return;
1582
1801
  }
@@ -1606,7 +1825,7 @@ var EffectImpl = class {
1606
1825
  );
1607
1826
  }
1608
1827
  }
1609
- if ((_a5 = this.options) == null ? void 0 : _a5.onStop) {
1828
+ if ((_a6 = this.options) == null ? void 0 : _a6.onStop) {
1610
1829
  this.options.onStop();
1611
1830
  }
1612
1831
  }
@@ -1753,7 +1972,7 @@ var ComputedImpl = class {
1753
1972
  const hadValue = oldValue !== NO_VALUE;
1754
1973
  const prevSub = startTracking(this);
1755
1974
  try {
1756
- const newValue = this.getter();
1975
+ const newValue = this.getter(hadValue ? oldValue : void 0);
1757
1976
  const flags = this.flag;
1758
1977
  const subs = this.subLink;
1759
1978
  const clearMask = ~(16 /* DIRTY */ | 32 /* PENDING */);
@@ -1873,13 +2092,13 @@ function cloneInitialState(value, seen = /* @__PURE__ */ new WeakMap()) {
1873
2092
  if (seen.has(value)) {
1874
2093
  return seen.get(value);
1875
2094
  }
1876
- if (value instanceof Date) {
2095
+ if (shared.isDate(value)) {
1877
2096
  return new Date(value.getTime());
1878
2097
  }
1879
- if (value instanceof RegExp) {
2098
+ if (shared.isRegExp(value)) {
1880
2099
  return new RegExp(value.source, value.flags);
1881
2100
  }
1882
- if (value instanceof Map) {
2101
+ if (shared.isMap(value)) {
1883
2102
  const clone2 = /* @__PURE__ */ new Map();
1884
2103
  seen.set(value, clone2);
1885
2104
  value.forEach((mapValue, mapKey) => {
@@ -1887,7 +2106,7 @@ function cloneInitialState(value, seen = /* @__PURE__ */ new WeakMap()) {
1887
2106
  });
1888
2107
  return clone2;
1889
2108
  }
1890
- if (value instanceof Set) {
2109
+ if (shared.isSet(value)) {
1891
2110
  const clone2 = /* @__PURE__ */ new Set();
1892
2111
  seen.set(value, clone2);
1893
2112
  value.forEach((setValue) => {
@@ -1895,7 +2114,7 @@ function cloneInitialState(value, seen = /* @__PURE__ */ new WeakMap()) {
1895
2114
  });
1896
2115
  return clone2;
1897
2116
  }
1898
- if (Array.isArray(value)) {
2117
+ if (shared.isArray(value)) {
1899
2118
  const clone2 = [];
1900
2119
  seen.set(value, clone2);
1901
2120
  value.forEach((item, index) => {
@@ -1904,7 +2123,7 @@ function cloneInitialState(value, seen = /* @__PURE__ */ new WeakMap()) {
1904
2123
  return clone2;
1905
2124
  }
1906
2125
  const prototype = Object.getPrototypeOf(value);
1907
- if (prototype !== Object.prototype && prototype !== null) {
2126
+ if (prototype !== Object.prototype && !shared.isNull(prototype)) {
1908
2127
  return value;
1909
2128
  }
1910
2129
  const clone = Object.create(prototype);
@@ -1935,11 +2154,58 @@ function createOptionsStore(options) {
1935
2154
  };
1936
2155
  }
1937
2156
  set.add(callback);
1938
- return () => set.delete(callback);
2157
+ const unsubscribe = () => set.delete(callback);
2158
+ onScopeDispose(
2159
+ unsubscribe,
2160
+ /* failSilently */
2161
+ true
2162
+ );
2163
+ return unsubscribe;
2164
+ };
2165
+ let activeTransaction = null;
2166
+ const flushTransaction = (transaction) => {
2167
+ if (transaction.depth === 0 && transaction.pending === 0 && !transaction.notified) {
2168
+ transaction.notified = true;
2169
+ notify(reactiveState);
2170
+ }
1939
2171
  };
1940
2172
  const commit = (mutate) => {
1941
- batch(mutate);
1942
- notify(reactiveState);
2173
+ const transaction = activeTransaction != null ? activeTransaction : {
2174
+ depth: 0,
2175
+ pending: 0,
2176
+ notified: false
2177
+ };
2178
+ const previousTransaction = activeTransaction;
2179
+ transaction.depth++;
2180
+ let result;
2181
+ try {
2182
+ activeTransaction = transaction;
2183
+ result = batch(mutate);
2184
+ } catch (error6) {
2185
+ transaction.depth--;
2186
+ activeTransaction = previousTransaction;
2187
+ throw error6;
2188
+ }
2189
+ activeTransaction = previousTransaction;
2190
+ if (shared.isPromise(result)) {
2191
+ transaction.pending++;
2192
+ transaction.depth--;
2193
+ return result.then(
2194
+ (value) => {
2195
+ transaction.pending--;
2196
+ flushTransaction(transaction);
2197
+ return value;
2198
+ },
2199
+ (error6) => {
2200
+ transaction.pending--;
2201
+ flushTransaction(transaction);
2202
+ throw error6;
2203
+ }
2204
+ );
2205
+ }
2206
+ transaction.depth--;
2207
+ flushTransaction(transaction);
2208
+ return result;
1943
2209
  };
1944
2210
  const defaultActions = {
1945
2211
  $patch(payload) {
@@ -1962,7 +2228,15 @@ function createOptionsStore(options) {
1962
2228
  actionCallbacks.delete(callback);
1963
2229
  },
1964
2230
  $reset() {
1965
- commit(() => Object.assign(reactiveState, initState));
2231
+ commit(() => {
2232
+ const fresh = cloneInitialState(initState);
2233
+ for (const key of Object.keys(reactiveState)) {
2234
+ if (!Object.prototype.hasOwnProperty.call(fresh, key)) {
2235
+ delete reactiveState[key];
2236
+ }
2237
+ }
2238
+ Object.assign(reactiveState, fresh);
2239
+ });
1966
2240
  }
1967
2241
  };
1968
2242
  const store = {};
@@ -1980,7 +2254,7 @@ function createOptionsStore(options) {
1980
2254
  value: reactiveState,
1981
2255
  enumerable: true,
1982
2256
  configurable: true,
1983
- writable: true
2257
+ writable: false
1984
2258
  });
1985
2259
  Object.assign(store, defaultActions);
1986
2260
  if (getters) {
@@ -2000,9 +2274,7 @@ function createOptionsStore(options) {
2000
2274
  const action = actions[key];
2001
2275
  if (action) {
2002
2276
  store[key] = (...args) => {
2003
- const result = action.apply(store, args);
2004
- actionCallbacks.forEach((callback) => callback(reactiveState));
2005
- return result;
2277
+ return commit(() => action.apply(store, args));
2006
2278
  };
2007
2279
  }
2008
2280
  }
@@ -2074,6 +2346,12 @@ var RefImpl = class extends (_b = SignalImpl, _a4 = "_IS_REF" /* IS_REF */, _b)
2074
2346
  if (sub) {
2075
2347
  linkReactiveNode(this, sub);
2076
2348
  }
2349
+ if (this.flag & 16 /* DIRTY */ && this.shouldUpdate()) {
2350
+ const subs = this.subLink;
2351
+ if (subs) {
2352
+ shallowPropagate(subs);
2353
+ }
2354
+ }
2077
2355
  return this._value;
2078
2356
  }
2079
2357
  /**
@@ -2089,6 +2367,7 @@ var RefImpl = class extends (_b = SignalImpl, _a4 = "_IS_REF" /* IS_REF */, _b)
2089
2367
  newValue = newValue.value;
2090
2368
  }
2091
2369
  if (shared.hasChanged(this._value, newValue)) {
2370
+ this._oldValue = this._rawValue;
2092
2371
  this._rawValue = newValue;
2093
2372
  this._value = newValue;
2094
2373
  this.flag |= 16 /* DIRTY */;
@@ -2110,6 +2389,45 @@ function ref(value = void 0) {
2110
2389
  function isRef(value) {
2111
2390
  return !!value && !!value["_IS_REF" /* IS_REF */];
2112
2391
  }
2392
+ var _a5;
2393
+ _a5 = "_IS_COMPUTED" /* IS_COMPUTED */;
2394
+ var ObjectPropertyRef = class {
2395
+ constructor(obj, key, defaultValue) {
2396
+ this.obj = obj;
2397
+ this.key = key;
2398
+ this.defaultValue = defaultValue;
2399
+ this[_a5] = true;
2400
+ }
2401
+ get value() {
2402
+ const value = this.obj[this.key];
2403
+ return value !== void 0 ? value : this.defaultValue;
2404
+ }
2405
+ set value(value) {
2406
+ this.obj[this.key] = value;
2407
+ }
2408
+ peek() {
2409
+ return untrack(() => this.value);
2410
+ }
2411
+ };
2412
+ function unref(value) {
2413
+ if (isSignal(value) || isRef(value) || isComputed(value)) {
2414
+ return value.value;
2415
+ }
2416
+ if (shared.isFunction(value)) {
2417
+ return value();
2418
+ }
2419
+ return value;
2420
+ }
2421
+ function toRef(obj, key, defaultValue) {
2422
+ return new ObjectPropertyRef(obj, key, defaultValue);
2423
+ }
2424
+ function toRefs(obj) {
2425
+ const result = {};
2426
+ for (const key of Object.keys(obj)) {
2427
+ result[key] = toRef(obj, key);
2428
+ }
2429
+ return result;
2430
+ }
2113
2431
  var INITIAL_WATCHER_VALUE = {};
2114
2432
  var _traverseSeen = /* @__PURE__ */ new Set();
2115
2433
  var _traverseBusy = false;
@@ -2120,7 +2438,7 @@ function traverseValue(value, seen) {
2120
2438
  seen.add(value);
2121
2439
  if (isSignal(value) || isComputed(value)) {
2122
2440
  traverseValue(value.value, seen);
2123
- } else if (Array.isArray(value)) {
2441
+ } else if (shared.isArray(value)) {
2124
2442
  for (const element of value) {
2125
2443
  traverseValue(element, seen);
2126
2444
  }
@@ -2170,7 +2488,7 @@ function resolveSingleSource(source) {
2170
2488
  return () => source;
2171
2489
  }
2172
2490
  function resolveSource(source) {
2173
- if (Array.isArray(source)) {
2491
+ if (shared.isArray(source)) {
2174
2492
  const getters = source.map((s) => resolveSingleSource(s));
2175
2493
  return () => getters.map((g) => g());
2176
2494
  }
@@ -2181,7 +2499,7 @@ function watch(source, callback, options = {}) {
2181
2499
  let oldValue = INITIAL_WATCHER_VALUE;
2182
2500
  let lastValue;
2183
2501
  let active = true;
2184
- const isSingleReactive = !Array.isArray(source) && isReactive(source);
2502
+ const isSingleReactive = !shared.isArray(source) && isReactive(source);
2185
2503
  const needTraverse = deep && !isSingleReactive;
2186
2504
  const getter = resolveSource(source);
2187
2505
  let cleanup;
@@ -2190,8 +2508,8 @@ function watch(source, callback, options = {}) {
2190
2508
  cleanup = void 0;
2191
2509
  try {
2192
2510
  fn();
2193
- } catch (error5) {
2194
- shared.warn("[watch] cleanup handler threw:", error5);
2511
+ } catch (error6) {
2512
+ shared.warn("[watch] cleanup handler threw:", error6);
2195
2513
  }
2196
2514
  };
2197
2515
  };
@@ -2250,6 +2568,7 @@ exports.effectScope = effectScope;
2250
2568
  exports.endBatch = endBatch;
2251
2569
  exports.getBatchDepth = getBatchDepth;
2252
2570
  exports.getCurrentScope = getCurrentScope;
2571
+ exports.getTargetDepSize = getTargetDepSize;
2253
2572
  exports.isBatching = isBatching;
2254
2573
  exports.isComputed = isComputed;
2255
2574
  exports.isEffect = isEffect;
@@ -2261,6 +2580,7 @@ exports.memoEffect = memoEffect;
2261
2580
  exports.nextTick = nextTick;
2262
2581
  exports.onScopeDispose = onScopeDispose;
2263
2582
  exports.queueJob = queueJob;
2583
+ exports.queuePostFlushJob = queuePostFlushJob;
2264
2584
  exports.queuePreFlushCb = queuePreFlushCb;
2265
2585
  exports.reactive = reactive;
2266
2586
  exports.ref = ref;
@@ -2272,6 +2592,9 @@ exports.startBatch = startBatch;
2272
2592
  exports.stop = stop;
2273
2593
  exports.toRaw = toRaw;
2274
2594
  exports.toReactive = toReactive;
2595
+ exports.toRef = toRef;
2596
+ exports.toRefs = toRefs;
2275
2597
  exports.trigger = trigger;
2598
+ exports.unref = unref;
2276
2599
  exports.untrack = untrack;
2277
2600
  exports.watch = watch;