mutts 1.0.10 → 1.0.12

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.
Files changed (61) hide show
  1. package/README.md +3 -3
  2. package/dist/browser.cjs +244 -3199
  3. package/dist/browser.cjs.map +1 -1
  4. package/dist/browser.d.ts +2 -2
  5. package/dist/browser.dev.cjs +51 -50
  6. package/dist/browser.dev.cjs.map +1 -1
  7. package/dist/browser.dev.d.ts +2 -2
  8. package/dist/browser.dev.esm.js +2 -2
  9. package/dist/browser.esm.js +15 -13
  10. package/dist/browser.esm.js.map +1 -1
  11. package/dist/chunks/{index-CaaQQlPJ.esm.js → index-BUop6B2U.esm.js} +384 -981
  12. package/dist/chunks/index-BUop6B2U.esm.js.map +1 -0
  13. package/dist/chunks/index-yK0HVxHv.cjs +2612 -0
  14. package/dist/chunks/index-yK0HVxHv.cjs.map +1 -0
  15. package/dist/chunks/{node-nKJBk8iJ.esm.js → node-Bo7WU5S2.esm.js} +2 -2
  16. package/dist/chunks/{node-nKJBk8iJ.esm.js.map → node-Bo7WU5S2.esm.js.map} +1 -1
  17. package/dist/chunks/{async-node-3PrbVAbB.cjs → node-Dd0esp5F.cjs} +4 -4
  18. package/dist/chunks/node-Dd0esp5F.cjs.map +1 -0
  19. package/dist/chunks/{proxy-Dtg-bJ3T.cjs → proxy-BvM4yewA.cjs} +441 -342
  20. package/dist/chunks/proxy-BvM4yewA.cjs.map +1 -0
  21. package/dist/chunks/{proxy-r7lARftl.esm.js → proxy-D2C49sXH.esm.js} +401 -330
  22. package/dist/chunks/proxy-D2C49sXH.esm.js.map +1 -0
  23. package/dist/debug.cjs +17 -4
  24. package/dist/debug.cjs.map +1 -1
  25. package/dist/debug.d.ts +2 -2
  26. package/dist/debug.esm.js +17 -3
  27. package/dist/debug.esm.js.map +1 -1
  28. package/dist/index.d.ts +84 -209
  29. package/dist/mutts.umd.js +842 -1362
  30. package/dist/mutts.umd.js.map +1 -1
  31. package/dist/mutts.umd.min.js +1 -1
  32. package/dist/mutts.umd.min.js.map +1 -1
  33. package/dist/node.cjs +51 -49
  34. package/dist/node.cjs.map +1 -1
  35. package/dist/node.d.ts +2 -2
  36. package/dist/node.dev.cjs +51 -49
  37. package/dist/node.dev.cjs.map +1 -1
  38. package/dist/node.dev.d.ts +2 -2
  39. package/dist/node.dev.esm.js +3 -3
  40. package/dist/node.esm.js +3 -3
  41. package/dist/{types-W5vD6m2n.d.ts → types-Bx2PhORg.d.ts} +38 -47
  42. package/docs/ai/api-reference.md +0 -14
  43. package/docs/ai/manual.md +2 -22
  44. package/docs/reactive/advanced.md +13 -14
  45. package/docs/reactive/attend.md +1 -2
  46. package/docs/reactive/collections.md +2 -149
  47. package/docs/reactive/core.md +218 -96
  48. package/docs/reactive/debugging.md +2 -2
  49. package/docs/reactive/resource.md +1 -1
  50. package/docs/reactive.md +1 -3
  51. package/docs/zone.md +1 -1
  52. package/package.json +18 -9
  53. package/dist/chunks/async-browser-BU_IfxYD.cjs +0 -216
  54. package/dist/chunks/async-browser-BU_IfxYD.cjs.map +0 -1
  55. package/dist/chunks/async-core-CRLKP3l-.cjs +0 -29
  56. package/dist/chunks/async-core-CRLKP3l-.cjs.map +0 -1
  57. package/dist/chunks/async-node-3PrbVAbB.cjs.map +0 -1
  58. package/dist/chunks/index-CaaQQlPJ.esm.js.map +0 -1
  59. package/dist/chunks/proxy-Dtg-bJ3T.cjs.map +0 -1
  60. package/dist/chunks/proxy-r7lARftl.esm.js.map +0 -1
  61. package/docs/reactive/scan.md +0 -324
@@ -1,4 +1,4 @@
1
- import { r as decorator, x as flavored, a3 as markWithRoot, O as named, a4 as rootFunctionSymbol, S as proxyToObject, a5 as getRoot, a6 as dependant, U as options, a0 as untracked, s as deepCompare, a7 as optionCall, W as root, u as effect, $ as touched1, K as isReactive, T as reactive, _ as touched, o as cleanedBy, C as getState, a8 as keysOf, a9 as __runInitializers, aa as __esDecorate, ab as FoolProof, ac as objectsWithDeepWatchers, ad as effectToDeepWatchedObjects, ae as deepWatchers, H as isNonReactive, a1 as unwrap, af as registerDeepWatcher, w as flavorOptions, X as stopped, ag as nonReactiveClass, ah as unreactiveProps, ai as addUnreactiveProps, aj as nonReactiveObjects, ak as __setFunctionName, al as __classPrivateFieldGet, am as __classPrivateFieldSet, l as atomic, an as contentRef, ao as notifyPropertyChange, ap as metaProtos, aq as wrapProtos, ar as objectParents, as as watchers, at as effectToReactiveObjects, P as objectToProxy } from './proxy-r7lARftl.esm.js';
1
+ import { t as decorator, B as flavored, O as isReactive, $ as reactive, x as effect, a4 as touched, S as link, G as getState, aa as dependant, a5 as touched1, ab as keysOf, ac as markWithRoot, ad as objectsWithDeepWatchers, ae as effectToDeepWatchedObjects, a7 as untracked, af as deepWatchers, a0 as options, L as isNonReactive, a8 as unwrap, ag as registerDeepWatcher, V as named, ah as rootFunctionSymbol, _ as proxyToObject, ai as getRoot, u as deepCompare, aj as optionCall, a2 as root, ak as FoolProof, z as flavorOptions, al as effectHistory, p as captured, am as unreactiveProperties, g as addUnreactiveProps, an as __runInitializers, ao as __esDecorate, n as atomic, ap as batch, aq as contentRef, ar as notifyPropertyChange, as as metaProtos, at as wrapProtos, au as objectParents, av as watchers, aw as effectToReactiveObjects, W as objectToProxy } from './proxy-D2C49sXH.esm.js';
2
2
 
3
3
  // Integrated with `using` statement via Symbol.dispose
4
4
  const fr = new FinalizationRegistry((f) => f());
@@ -744,211 +744,6 @@ function chainPromise(given) {
744
744
  return chained;
745
745
  }
746
746
 
747
- const memoizedRegistry = new WeakMap();
748
- const wrapperRegistry = new WeakMap();
749
- function getBranch(tree, key) {
750
- tree.branches ?? (tree.branches = new WeakMap());
751
- let branch = tree.branches.get(key);
752
- if (!branch) {
753
- branch = {};
754
- tree.branches.set(key, branch);
755
- }
756
- return branch;
757
- }
758
- function memoizeFunction(fn, opts) {
759
- const fnRoot = getRoot(fn);
760
- const existing = memoizedRegistry.get(fnRoot);
761
- if (existing)
762
- return existing;
763
- const cacheRoot = {};
764
- const memoized = markWithRoot(function memoized(...args) {
765
- if (args.some((arg) => !(arg && ['object', 'symbol', 'function'].includes(typeof arg)))) {
766
- if (opts?.lenient)
767
- return fn.apply(this, args);
768
- throw new Error('memoize expects non-null object arguments');
769
- }
770
- let node = cacheRoot;
771
- // Note: decorators add `this` as first argument
772
- for (const arg of args) {
773
- node = getBranch(node, arg);
774
- }
775
- dependant(node, 'memoize');
776
- if ('result' in node) {
777
- if (options.onMemoizationDiscrepancy) {
778
- const wasVerification = options.isVerificationRun;
779
- options.isVerificationRun = true;
780
- try {
781
- const fresh = untracked(() => fn.apply(this, args));
782
- if (!deepCompare(node.result, fresh)) {
783
- optionCall('onMemoizationDiscrepancy', node.result, fresh, fn, args, 'calculation');
784
- }
785
- }
786
- finally {
787
- options.isVerificationRun = wasVerification;
788
- }
789
- }
790
- return node.result;
791
- }
792
- // Create memoize internal effect to track dependencies and invalidate cache
793
- // Use untracked to prevent the effect creation from being affected by parent effects
794
- node.cleanup = root(() => effect.named('memoize')(() => {
795
- // Execute the function and track its dependencies
796
- // The function execution will automatically track dependencies on reactive objects
797
- node.result = fn.apply(this, args);
798
- return (reason) => {
799
- // When dependencies change, clear the cache and notify consumers
800
- delete node.result;
801
- touched1(node, { type: 'invalidate', prop: args }, 'memoize');
802
- // Lazy memoization: stop the effect so it doesn't re-run immediately.
803
- // It will be re-created on next access.
804
- if (node.cleanup) {
805
- node.cleanup({ type: 'invalidate', cause: reason });
806
- node.cleanup = undefined;
807
- }
808
- };
809
- }, { opaque: true }));
810
- if (options.onMemoizationDiscrepancy) {
811
- const wasVerification = options.isVerificationRun;
812
- options.isVerificationRun = true;
813
- try {
814
- const fresh = untracked(() => fn.apply(this, args));
815
- if (!deepCompare(node.result, fresh)) {
816
- optionCall('onMemoizationDiscrepancy', node.result, fresh, fn, args, 'comparison');
817
- }
818
- }
819
- finally {
820
- options.isVerificationRun = wasVerification;
821
- }
822
- }
823
- return node.result;
824
- }, fn);
825
- memoizedRegistry.set(fnRoot, memoized);
826
- memoizedRegistry.set(memoized, memoized);
827
- return memoized;
828
- }
829
- function memoizeObject(target, opts) {
830
- const existing = memoizedRegistry.get(target);
831
- if (existing)
832
- return existing;
833
- const proxy = new Proxy(target, {
834
- get(source, prop, receiver) {
835
- // 1. Walk prototype chain to find descriptor
836
- let current = source;
837
- let desc;
838
- while (current) {
839
- desc = Object.getOwnPropertyDescriptor(current, prop);
840
- if (desc)
841
- break;
842
- current = Object.getPrototypeOf(current);
843
- }
844
- if (!desc)
845
- return Reflect.get(source, prop, receiver);
846
- // 2. If getter, memoize
847
- if (desc.get) {
848
- const originalGetter = desc.get;
849
- let wrapper = wrapperRegistry.get(originalGetter);
850
- if (!wrapper) {
851
- wrapper = markWithRoot(named(`${String(source?.constructor?.name ?? 'Object')}.${String(prop)}`, (that) => {
852
- return originalGetter.call(that);
853
- }), {
854
- propertyKey: prop,
855
- });
856
- const origRoot = originalGetter[rootFunctionSymbol];
857
- if (origRoot)
858
- wrapper[rootFunctionSymbol] = origRoot;
859
- wrapperRegistry.set(originalGetter, wrapper);
860
- }
861
- const memoized = memoizeFunction(wrapper, opts);
862
- return memoized(receiver);
863
- }
864
- // 3. Otherwise forward
865
- return Reflect.get(source, prop, receiver);
866
- },
867
- // Forward set to the target (source) to ensure it acts as the receiver for reactivity notifications
868
- set(source, prop, value, _receiver) {
869
- // By strictly passing `source` as receiver, we ensure that if `source` is a reactive proxy,
870
- // it recognizes itself and triggers change notifications.
871
- return Reflect.set(source, prop, value, source);
872
- },
873
- });
874
- proxyToObject.set(proxy, target);
875
- memoizedRegistry.set(target, proxy);
876
- return proxy;
877
- }
878
- /**
879
- * Decorator and function wrapper for memoizing computed values based on reactive dependencies.
880
- *
881
- * When used as a decorator on getters or methods, it caches the result and automatically
882
- * invalidates the cache when reactive dependencies change.
883
- *
884
- * When used as a function wrapper, it memoizes based on object arguments (WeakMap-based cache).
885
- *
886
- * @example
887
- * ```typescript
888
- * class User {
889
- * @memoize
890
- * get fullName() {
891
- * return `${this.firstName} ${this.lastName}`
892
- * }
893
- * }
894
- *
895
- * // Or as a function wrapper
896
- * const expensive = memoize((obj: SomeObject) => {
897
- * return heavyComputation(obj)
898
- * })
899
- * ```
900
- */
901
- function makeMemoizeDecorator(memoizeOpts) {
902
- return decorator({
903
- getter(original, target, propertyKey) {
904
- return function () {
905
- let wrapper = wrapperRegistry.get(original);
906
- if (!wrapper) {
907
- wrapper = markWithRoot(named(`${String(target?.constructor?.name ?? target?.name ?? 'Object')}.${String(propertyKey)}`, (that) => {
908
- return original.call(that);
909
- }), {
910
- method: original,
911
- propertyKey,
912
- });
913
- const origRoot = original[rootFunctionSymbol];
914
- if (origRoot)
915
- wrapper[rootFunctionSymbol] = origRoot;
916
- wrapperRegistry.set(original, wrapper);
917
- }
918
- const memoized = memoizeFunction(wrapper, memoizeOpts);
919
- return memoized(this);
920
- };
921
- },
922
- method(original, target, name) {
923
- return function (...args) {
924
- let wrapper = wrapperRegistry.get(original);
925
- if (!wrapper) {
926
- wrapper = markWithRoot(named(`${String(target?.constructor?.name ?? target?.name ?? 'Object')}.${String(name)}`, (that, ...args) => {
927
- return original.call(that, ...args);
928
- }), {
929
- method: original,
930
- propertyKey: name,
931
- });
932
- const origRoot = original[rootFunctionSymbol];
933
- if (origRoot)
934
- wrapper[rootFunctionSymbol] = origRoot;
935
- wrapperRegistry.set(original, wrapper);
936
- }
937
- const memoized = memoizeFunction(wrapper, memoizeOpts);
938
- return memoized(this, ...args);
939
- };
940
- },
941
- default: (target) => typeof target === 'object'
942
- ? memoizeObject(target, memoizeOpts)
943
- : memoizeFunction(target, memoizeOpts),
944
- });
945
- }
946
- const memoize = flavored(makeMemoizeDecorator(), {
947
- get lenient() {
948
- return makeMemoizeDecorator({ lenient: true });
949
- },
950
- });
951
-
952
747
  function attend(source, callback) {
953
748
  const enumerate = typeof source === 'function'
954
749
  ? source
@@ -960,14 +755,14 @@ function attend(source, callback) {
960
755
  ? () => source.values()
961
756
  : () => Object.keys(source);
962
757
  const keyEffects = new Map();
963
- const outer = effect(({ ascend }) => {
758
+ const outer = effect.named('attend')(({ ascend }) => {
964
759
  const keys = new Set();
965
760
  for (const key of enumerate())
966
761
  keys.add(key);
967
762
  for (const key of keys) {
968
763
  if (keyEffects.has(key))
969
764
  continue;
970
- keyEffects.set(key, ascend(() => effect(() => callback(key))));
765
+ keyEffects.set(key, ascend(() => effect.named(`attend:${key}`)((access) => callback(key, access))));
971
766
  }
972
767
  for (const key of Array.from(keyEffects.keys())) {
973
768
  if (!keys.has(key)) {
@@ -983,146 +778,10 @@ function attend(source, callback) {
983
778
  keyEffects.clear();
984
779
  };
985
780
  }
986
- /**
987
- * Perform a reactive scan over an array of items.
988
- *
989
- * This implementation is highly optimized for performance and fine-grained reactivity:
990
- * - **Incremental Updates**: Changes to an item only trigger re-computation from that
991
- * point onwards in the result chain.
992
- * - **Move Optimization**: If items are moved within the array, their accumulated
993
- * values are reused as long as their predecessor remains the same.
994
- * - **Duplicate Support**: Correctly handles multiple occurrences of the same object
995
- * instance using an internal occurrence tracking mechanism.
996
- * - **Memory Efficient**: Uses `WeakMap` for caching intermediates, which are
997
- * automatically cleared when source items are garbage collected.
998
- *
999
- * @example
1000
- * ```typescript
1001
- * const source = reactive([{ val: 1 }, { val: 2 }, { val: 3 }])
1002
- * const sum = scan(source, (acc, item) => acc + item.val, 0)
1003
- *
1004
- * expect([...sum]).toEqual([1, 3, 6])
1005
- *
1006
- * // Modifying an item only re-computes subsequent sums
1007
- * source[1].val = 10
1008
- * expect([...sum]).toEqual([1, 11, 14])
1009
- * ```
1010
- *
1011
- * @param source The source array of objects (will be made reactive)
1012
- * @param callback The accumulator function called with (accumulator, currentItem)
1013
- * @param initialValue The starting value for the accumulation
1014
- * @returns A reactive array of accumulated values, with a [cleanup] property to stop the tracking
1015
- */
1016
- function scan(source, callback, initialValue) {
1017
- const observedSource = reactive(source);
1018
- const rawResult = [];
1019
- const result = reactive(rawResult);
1020
- // Track effects for each index to dispose them when the array shrinks
1021
- const indexEffects = new Map();
1022
- // Mapping from index to its current intermediate object
1023
- const indexToIntermediate = reactive([]);
1024
- const intermediaries = new WeakMap();
1025
- let Intermediate = (() => {
1026
- var _a;
1027
- let _instanceExtraInitializers = [];
1028
- let _get_acc_decorators;
1029
- return _a = class Intermediate {
1030
- constructor(val, prev) {
1031
- this.val = (__runInitializers(this, _instanceExtraInitializers), val);
1032
- this.prev = prev;
1033
- }
1034
- get acc() {
1035
- const prevAcc = this.prev ? this.prev.acc : initialValue;
1036
- return callback(prevAcc, this.val);
1037
- }
1038
- },
1039
- (() => {
1040
- const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
1041
- _get_acc_decorators = [memoize];
1042
- __esDecorate(_a, null, _get_acc_decorators, { kind: "getter", name: "acc", static: false, private: false, access: { has: obj => "acc" in obj, get: obj => obj.acc }, metadata: _metadata }, null, _instanceExtraInitializers);
1043
- if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
1044
- })(),
1045
- _a;
1046
- })();
1047
- function disposeIndex(index) {
1048
- const stop = indexEffects.get(index);
1049
- if (stop) {
1050
- stop();
1051
- indexEffects.delete(index);
1052
- Reflect.deleteProperty(indexToIntermediate, index);
1053
- Reflect.deleteProperty(result, index);
1054
- }
1055
- }
1056
- const mainEffect = effect(function scanMainEffect({ ascend }) {
1057
- const length = observedSource.length;
1058
- const occurrenceCount = new Map();
1059
- let prev;
1060
- for (let i = 0; i < length; i++)
1061
- if (i in observedSource) {
1062
- const val = observedSource[i];
1063
- if (!(val &&
1064
- (typeof val === 'object' || typeof val === 'function' || typeof val === 'symbol'))) {
1065
- throw new Error('scan: items must be objects (WeakKey) for intermediate caching');
1066
- }
1067
- const count = occurrenceCount.get(val) ?? 0;
1068
- occurrenceCount.set(val, count + 1);
1069
- let list = intermediaries.get(val);
1070
- if (!list) {
1071
- list = [];
1072
- intermediaries.set(val, list);
1073
- }
1074
- let intermediate = list[count];
1075
- if (!intermediate) {
1076
- intermediate = reactive(new Intermediate(val, prev));
1077
- list[count] = intermediate;
1078
- }
1079
- else {
1080
- // Update the link.
1081
- if (untracked(() => intermediate.prev) !== prev) {
1082
- intermediate.prev = prev;
1083
- }
1084
- }
1085
- // Update the reactive mapping for this index
1086
- if (indexToIntermediate[i] !== intermediate) {
1087
- indexToIntermediate[i] = intermediate;
1088
- }
1089
- // If we don't have an effect for this index yet, create one
1090
- if (!indexEffects.has(i)) {
1091
- ascend(() => {
1092
- const index = i;
1093
- const stop = effect(function scanIndexSyncEffect() {
1094
- const inter = indexToIntermediate[index];
1095
- if (inter) {
1096
- const accValue = inter.acc;
1097
- result[index] = accValue;
1098
- }
1099
- });
1100
- indexEffects.set(index, stop);
1101
- });
1102
- }
1103
- prev = intermediate;
1104
- }
1105
- // Cleanup trailing indices
1106
- for (const index of Array.from(indexEffects.keys())) {
1107
- if (index >= length)
1108
- disposeIndex(index);
1109
- }
1110
- // Ensure result length matches source length
1111
- if (rawResult.length !== length) {
1112
- FoolProof.set(result, 'length', length, result);
1113
- }
1114
- });
1115
- return cleanedBy(result, ((reason) => {
1116
- mainEffect(reason);
1117
- for (const stop of indexEffects.values())
1118
- stop(reason);
1119
- indexEffects.clear();
1120
- }));
1121
- }
1122
781
  function lift(cb) {
1123
782
  let result;
1124
783
  let rawResult;
1125
- const liftCleanup = effect.named('lift')(markWithRoot((access) => {
784
+ const liftCleanup = effect.named(`lift:${cb.name}`)(markWithRoot((access) => {
1126
785
  const source = cb(access);
1127
786
  if (!source || typeof source !== 'object')
1128
787
  throw new Error('lift callback must return an array or object');
@@ -1135,11 +794,8 @@ function lift(cb) {
1135
794
  throw new Error('lift callback must return the same type as the previous result');
1136
795
  if (Array.isArray(source)) {
1137
796
  const res = result;
1138
- const patches = arrayDiff(res, source);
1139
- for (let i = patches.length - 1; i >= 0; i--) {
1140
- const { indexA, sliceA, sliceB } = patches[i];
797
+ for (const { indexA, sliceA, sliceB } of arrayDiff(res, source).sort((a, b) => a.indexA - b.indexA))
1141
798
  res.splice(indexA, sliceA.length, ...sliceB);
1142
- }
1143
799
  }
1144
800
  else {
1145
801
  for (const key of Object.keys(source)) {
@@ -1166,7 +822,7 @@ function lift(cb) {
1166
822
  }
1167
823
  }
1168
824
  }, cb));
1169
- return cleanedBy(result, liftCleanup);
825
+ return link(result, liftCleanup);
1170
826
  }
1171
827
  /**
1172
828
  * Reactively maps an array source through `fn`, producing a lazy reactive output array.
@@ -1187,7 +843,7 @@ function lift(cb) {
1187
843
  */
1188
844
  function morphArray(source, fn, options) {
1189
845
  if (typeof source !== 'function' && !isReactive(source) && options?.pure === true) {
1190
- return source.map(fn);
846
+ return source.map((i) => fn(i));
1191
847
  }
1192
848
  let track;
1193
849
  const itemEffects = new Map();
@@ -1209,17 +865,14 @@ function morphArray(source, fn, options) {
1209
865
  }
1210
866
  else {
1211
867
  const indexRef = { value: key };
1212
- let stop;
1213
- track(() => {
1214
- stop = effect.opaque(() => {
1215
- cache[indexRef.value] = fn(input);
1216
- return (reason) => {
1217
- delete cache[indexRef.value];
1218
- touched1(cache, { type: 'invalidate', prop: 'morph' }, String(key));
1219
- stop({ type: 'invalidate', cause: reason });
1220
- };
1221
- });
1222
- });
868
+ const stop = track(() => effect.named(`morph:${fn.name}:${key}`).opaque((access) => {
869
+ cache[indexRef.value] = fn(input, access);
870
+ return (reason) => {
871
+ delete cache[indexRef.value];
872
+ touched1(cache, { type: 'invalidate', prop: 'morph' }, String(key));
873
+ stop?.({ type: 'invalidate', cause: reason });
874
+ };
875
+ }));
1223
876
  itemEffects.set(key, { stop, index: indexRef });
1224
877
  }
1225
878
  }
@@ -1236,7 +889,7 @@ function morphArray(source, fn, options) {
1236
889
  return Reflect.has(input, prop);
1237
890
  },
1238
891
  });
1239
- const stopMain = effect.named('morph:array')(({ ascend }) => {
892
+ const stopMain = effect.named(`morph:${fn.name}`)(({ ascend }) => {
1240
893
  track = ascend;
1241
894
  const newInput = [...(typeof source === 'function' ? source() : source)];
1242
895
  const diffs = arrayDiff(input, newInput).toSorted((a, b) => b.indexA - a.indexA);
@@ -1251,7 +904,7 @@ function morphArray(source, fn, options) {
1251
904
  // We need to move entries in the Map.
1252
905
  const entries = Array.from(itemEffects.entries()).sort((a, b) => a[0] - b[0]);
1253
906
  // Remove entries that will be shifted
1254
- for (const [idx, entry] of entries) {
907
+ for (const [idx, _entry] of entries) {
1255
908
  if (idx >= diff.indexA + diff.sliceA.length) {
1256
909
  itemEffects.delete(idx);
1257
910
  }
@@ -1283,7 +936,7 @@ function morphArray(source, fn, options) {
1283
936
  }
1284
937
  input = newInput;
1285
938
  });
1286
- return cleanedBy(proxy, (reason) => {
939
+ return link(proxy, (reason) => {
1287
940
  stopMain(reason);
1288
941
  for (const entry of itemEffects.values())
1289
942
  entry.stop(reason);
@@ -1305,7 +958,7 @@ function morphMap(source, fn, options) {
1305
958
  if (!isReactive(source) && options?.pure === true) {
1306
959
  const res = new Map();
1307
960
  for (const [k, v] of source)
1308
- res.set(k, fn(v));
961
+ res.set(k, fn(v, k));
1309
962
  return res;
1310
963
  }
1311
964
  let track;
@@ -1322,15 +975,15 @@ function morphMap(source, fn, options) {
1322
975
  function computeItem(key, val) {
1323
976
  const isPure = options?.pure === true || (typeof options?.pure === 'function' && options.pure(val));
1324
977
  if (isPure) {
1325
- cache.set(key, track(() => fn(val)));
978
+ cache.set(key, track(() => fn(val, key)));
1326
979
  }
1327
980
  else {
1328
- const stop = track(() => effect.opaque(() => {
1329
- cache.set(key, fn(source.get(key)));
981
+ const stop = track(() => effect.named(`morph:${fn.name}:${key}`).opaque((access) => {
982
+ cache.set(key, fn(source.get(key), key, access));
1330
983
  return (reason) => {
1331
984
  cache.delete(key);
1332
985
  touched1(cache, { type: 'invalidate', prop: 'morph' }, String(key));
1333
- stop({ type: 'invalidate', cause: reason });
986
+ stop?.({ type: 'invalidate', cause: reason });
1334
987
  };
1335
988
  }));
1336
989
  itemEffects.set(key, stop);
@@ -1374,7 +1027,7 @@ function morphMap(source, fn, options) {
1374
1027
  },
1375
1028
  });
1376
1029
  let stateSnapshot = getState(source);
1377
- const stopMain = effect.named('morph:map')(({ ascend }) => {
1030
+ const stopMain = effect.named(`morph:${fn.name}`)(({ ascend }) => {
1378
1031
  track = ascend;
1379
1032
  dependant(source, keysOf);
1380
1033
  while ('evolution' in stateSnapshot) {
@@ -1390,7 +1043,7 @@ function morphMap(source, fn, options) {
1390
1043
  }
1391
1044
  }
1392
1045
  });
1393
- return cleanedBy(proxy, (reason) => {
1046
+ return link(proxy, (reason) => {
1394
1047
  stopMain(reason);
1395
1048
  for (const stop of itemEffects.values())
1396
1049
  stop(reason);
@@ -1412,7 +1065,7 @@ function morphRecord(source, fn, options) {
1412
1065
  if (!isReactive(source) && options?.pure === true) {
1413
1066
  const res = {};
1414
1067
  for (const k of Object.keys(source))
1415
- res[k] = fn(source[k]);
1068
+ res[k] = fn(source[k], k);
1416
1069
  return res;
1417
1070
  }
1418
1071
  let track;
@@ -1428,15 +1081,15 @@ function morphRecord(source, fn, options) {
1428
1081
  function computeItem(key, val) {
1429
1082
  const isPure = options?.pure === true || (typeof options?.pure === 'function' && options.pure(val));
1430
1083
  if (isPure) {
1431
- cache[key] = track(() => fn(val));
1084
+ cache[key] = track(() => fn(val, key));
1432
1085
  }
1433
1086
  else {
1434
- const stop = track(() => effect.opaque(() => {
1435
- cache[key] = fn(source[key]);
1087
+ const stop = track(() => effect.named(`morph:${fn.name}:${key}`).opaque((access) => {
1088
+ cache[key] = fn(source[key], key, access);
1436
1089
  return (reason) => {
1437
1090
  delete cache[key];
1438
1091
  touched1(cache, { type: 'invalidate', prop: 'morph' }, String(key));
1439
- stop({ type: 'invalidate', cause: reason });
1092
+ stop?.({ type: 'invalidate', cause: reason });
1440
1093
  };
1441
1094
  }));
1442
1095
  itemEffects.set(key, stop);
@@ -1463,7 +1116,7 @@ function morphRecord(source, fn, options) {
1463
1116
  },
1464
1117
  });
1465
1118
  let stateSnapshot = getState(source);
1466
- const stopMain = effect.named('morph:record')(({ ascend }) => {
1119
+ const stopMain = effect.named(`morph:${fn.name}`)(({ ascend }) => {
1467
1120
  track = ascend;
1468
1121
  // Track only structural changes on source
1469
1122
  dependant(source, keysOf);
@@ -1480,7 +1133,7 @@ function morphRecord(source, fn, options) {
1480
1133
  }
1481
1134
  }
1482
1135
  });
1483
- return cleanedBy(proxy, (reason) => {
1136
+ return link(proxy, (reason) => {
1484
1137
  stopMain(reason);
1485
1138
  for (const stop of itemEffects.values())
1486
1139
  stop(reason);
@@ -1539,7 +1192,7 @@ function deepWatch(target, callback, { immediate = false } = {}) {
1539
1192
  const wrappedCallback = markWithRoot((() => callback(target)), callback);
1540
1193
  registerDeepWatcher();
1541
1194
  // Use the existing effect system to register dependencies
1542
- return effect(() => {
1195
+ return effect.named('deepWatch')(() => {
1543
1196
  // Mark the target object as having deep watchers
1544
1197
  objectsWithDeepWatchers.add(target);
1545
1198
  // Track which objects this effect is watching for cleanup
@@ -1575,35 +1228,24 @@ function deepWatch(target, callback, { immediate = false } = {}) {
1575
1228
  }
1576
1229
  }
1577
1230
  // Also handle array indices and length
1578
- // biome-ignore lint/suspicious/useIsArray: Check for both native arrays and reactive arrays
1579
- if (Array.isArray(obj) || obj instanceof Array) {
1580
- // Access array length to register dependency on length changes
1581
- const length = obj.length;
1582
- // Access all current array elements to register dependencies
1583
- for (let i = 0; i < length; i++) {
1584
- // Access the array element to register dependency
1585
- const value = obj[i];
1586
- // Make the value reactive if it's an object
1587
- const reactiveValue = typeof value === 'object' && value !== null ? reactive(value) : value;
1588
- traverseAndTrack(reactiveValue, depth + 1);
1589
- }
1590
- }
1591
- // Handle Set values (deep watch values only, not keys since Sets don't have separate keys)
1592
- else if (obj instanceof Set) {
1593
- // Access all Set values to register dependencies
1231
+ // Handle arrays and collections using iterators to ensure proxy tracking is triggered
1232
+ if (typeof obj[Symbol.iterator] === 'function') {
1233
+ // Access the iterator to track additions/removals/collection changes
1594
1234
  for (const value of obj) {
1595
1235
  // Make the value reactive if it's an object
1596
1236
  const reactiveValue = typeof value === 'object' && value !== null ? reactive(value) : value;
1597
1237
  traverseAndTrack(reactiveValue, depth + 1);
1598
1238
  }
1599
- }
1600
- // Handle Map values (deep watch values only, not keys)
1601
- else if (obj instanceof Map) {
1602
- // Access all Map values to register dependencies
1603
- for (const [_key, value] of obj) {
1604
- // Make the value reactive if it's an object
1605
- const reactiveValue = typeof value === 'object' && value !== null ? reactive(value) : value;
1606
- traverseAndTrack(reactiveValue, depth + 1);
1239
+ // Explicitly depend on length so array mutations changing count trigger re-evaluation
1240
+ if ('length' in obj) {
1241
+ dependant(obj, 'length');
1242
+ }
1243
+ // For Maps, also ensure we track values explicitly if the iterator yields entries
1244
+ if (obj instanceof Map) {
1245
+ for (const value of obj.values()) {
1246
+ const reactiveValue = typeof value === 'object' && value !== null ? reactive(value) : value;
1247
+ traverseAndTrack(reactiveValue, depth + 1);
1248
+ }
1607
1249
  }
1608
1250
  }
1609
1251
  // Note: WeakSet and WeakMap cannot be iterated, so we can't deep watch their contents
@@ -1640,12 +1282,217 @@ function deepWatch(target, callback, { immediate = false } = {}) {
1640
1282
  objectsWithDeepWatchers.delete(obj);
1641
1283
  }
1642
1284
  }
1643
- // Clean up the tracking data
1644
- effectToDeepWatchedObjects.delete(wrappedCallback);
1285
+ // Clean up the tracking data
1286
+ effectToDeepWatchedObjects.delete(wrappedCallback);
1287
+ }
1288
+ };
1289
+ });
1290
+ }
1291
+
1292
+ const memoizedRegistry = new WeakMap();
1293
+ const wrapperRegistry = new WeakMap();
1294
+ function getBranch(tree, key) {
1295
+ tree.branches ?? (tree.branches = new WeakMap());
1296
+ let branch = tree.branches.get(key);
1297
+ if (!branch) {
1298
+ branch = {};
1299
+ tree.branches.set(key, branch);
1300
+ }
1301
+ return branch;
1302
+ }
1303
+ function memoizeFunction(fn, opts) {
1304
+ const fnRoot = getRoot(fn);
1305
+ const existing = memoizedRegistry.get(fnRoot);
1306
+ if (existing)
1307
+ return existing;
1308
+ const cacheRoot = {};
1309
+ const memoized = markWithRoot(function memoized(...args) {
1310
+ if (args.some((arg) => !(arg && ['object', 'symbol', 'function'].includes(typeof arg)))) {
1311
+ if (opts?.lenient)
1312
+ return fn.apply(this, args);
1313
+ throw new Error('memoize expects non-null object arguments');
1314
+ }
1315
+ let node = cacheRoot;
1316
+ // Note: decorators add `this` as first argument
1317
+ for (const arg of args) {
1318
+ node = getBranch(node, arg);
1319
+ }
1320
+ dependant(node, 'memoize');
1321
+ if ('result' in node) {
1322
+ if (options.onMemoizationDiscrepancy) {
1323
+ const wasVerification = options.isVerificationRun;
1324
+ options.isVerificationRun = true;
1325
+ try {
1326
+ const fresh = untracked(() => fn.apply(this, args));
1327
+ if (!deepCompare(node.result, fresh)) {
1328
+ optionCall('onMemoizationDiscrepancy', node.result, fresh, fn, args, 'calculation');
1329
+ }
1330
+ }
1331
+ finally {
1332
+ options.isVerificationRun = wasVerification;
1333
+ }
1334
+ }
1335
+ return node.result;
1336
+ }
1337
+ // Create memoize internal effect to track dependencies and invalidate cache
1338
+ // Use untracked to prevent the effect creation from being affected by parent effects
1339
+ node.cleanup = root(() => effect.named('memoize')(() => {
1340
+ // Execute the function and track its dependencies
1341
+ // The function execution will automatically track dependencies on reactive objects
1342
+ node.result = fn.apply(this, args);
1343
+ return (reason) => {
1344
+ // When dependencies change, clear the cache and notify consumers
1345
+ delete node.result;
1346
+ touched1(node, { type: 'invalidate', prop: args }, 'memoize');
1347
+ // Lazy memoization: stop the effect so it doesn't re-run immediately.
1348
+ // It will be re-created on next access.
1349
+ if (node.cleanup) {
1350
+ node.cleanup({ type: 'invalidate', cause: reason });
1351
+ node.cleanup = undefined;
1352
+ }
1353
+ };
1354
+ }, { opaque: true }));
1355
+ if (options.onMemoizationDiscrepancy) {
1356
+ const wasVerification = options.isVerificationRun;
1357
+ options.isVerificationRun = true;
1358
+ try {
1359
+ const fresh = untracked(() => fn.apply(this, args));
1360
+ if (!deepCompare(node.result, fresh)) {
1361
+ optionCall('onMemoizationDiscrepancy', node.result, fresh, fn, args, 'comparison');
1362
+ }
1363
+ }
1364
+ finally {
1365
+ options.isVerificationRun = wasVerification;
1366
+ }
1367
+ }
1368
+ return node.result;
1369
+ }, fn);
1370
+ memoizedRegistry.set(fnRoot, memoized);
1371
+ memoizedRegistry.set(memoized, memoized);
1372
+ return memoized;
1373
+ }
1374
+ function memoizeObject(target, opts) {
1375
+ const existing = memoizedRegistry.get(target);
1376
+ if (existing)
1377
+ return existing;
1378
+ const proxy = new Proxy(target, {
1379
+ get(source, prop, receiver) {
1380
+ // 1. Walk prototype chain to find descriptor
1381
+ let current = source;
1382
+ let desc;
1383
+ while (current) {
1384
+ desc = Object.getOwnPropertyDescriptor(current, prop);
1385
+ if (desc)
1386
+ break;
1387
+ current = Object.getPrototypeOf(current);
1388
+ }
1389
+ if (!desc)
1390
+ return Reflect.get(source, prop, receiver);
1391
+ // 2. If getter, memoize
1392
+ if (desc.get) {
1393
+ const originalGetter = desc.get;
1394
+ let wrapper = wrapperRegistry.get(originalGetter);
1395
+ if (!wrapper) {
1396
+ wrapper = markWithRoot(named(`${String(source?.constructor?.name ?? 'Object')}.${String(prop)}`, (that) => {
1397
+ return originalGetter.call(that);
1398
+ }), {
1399
+ propertyKey: prop,
1400
+ });
1401
+ const origRoot = originalGetter[rootFunctionSymbol];
1402
+ if (origRoot)
1403
+ wrapper[rootFunctionSymbol] = origRoot;
1404
+ wrapperRegistry.set(originalGetter, wrapper);
1405
+ }
1406
+ const memoized = memoizeFunction(wrapper, opts);
1407
+ return memoized(receiver);
1645
1408
  }
1646
- };
1409
+ // 3. Otherwise forward
1410
+ return Reflect.get(source, prop, receiver);
1411
+ },
1412
+ // Forward set to the target (source) to ensure it acts as the receiver for reactivity notifications
1413
+ set(source, prop, value, _receiver) {
1414
+ // By strictly passing `source` as receiver, we ensure that if `source` is a reactive proxy,
1415
+ // it recognizes itself and triggers change notifications.
1416
+ return Reflect.set(source, prop, value, source);
1417
+ },
1418
+ });
1419
+ proxyToObject.set(proxy, target);
1420
+ memoizedRegistry.set(target, proxy);
1421
+ return proxy;
1422
+ }
1423
+ /**
1424
+ * Decorator and function wrapper for memoizing computed values based on reactive dependencies.
1425
+ *
1426
+ * When used as a decorator on getters or methods, it caches the result and automatically
1427
+ * invalidates the cache when reactive dependencies change.
1428
+ *
1429
+ * When used as a function wrapper, it memoizes based on object arguments (WeakMap-based cache).
1430
+ *
1431
+ * @example
1432
+ * ```typescript
1433
+ * class User {
1434
+ * @memoize
1435
+ * get fullName() {
1436
+ * return `${this.firstName} ${this.lastName}`
1437
+ * }
1438
+ * }
1439
+ *
1440
+ * // Or as a function wrapper
1441
+ * const expensive = memoize((obj: SomeObject) => {
1442
+ * return heavyComputation(obj)
1443
+ * })
1444
+ * ```
1445
+ */
1446
+ function makeMemoizeDecorator(memoizeOpts) {
1447
+ return decorator({
1448
+ getter(original, target, propertyKey) {
1449
+ return function () {
1450
+ let wrapper = wrapperRegistry.get(original);
1451
+ if (!wrapper) {
1452
+ wrapper = markWithRoot(named(`${String(target?.constructor?.name ?? target?.name ?? 'Object')}.${String(propertyKey)}`, (that) => {
1453
+ return original.call(that);
1454
+ }), {
1455
+ method: original,
1456
+ propertyKey,
1457
+ });
1458
+ const origRoot = original[rootFunctionSymbol];
1459
+ if (origRoot)
1460
+ wrapper[rootFunctionSymbol] = origRoot;
1461
+ wrapperRegistry.set(original, wrapper);
1462
+ }
1463
+ const memoized = memoizeFunction(wrapper, memoizeOpts);
1464
+ return memoized(this);
1465
+ };
1466
+ },
1467
+ method(original, target, name) {
1468
+ return function (...args) {
1469
+ let wrapper = wrapperRegistry.get(original);
1470
+ if (!wrapper) {
1471
+ wrapper = markWithRoot(named(`${String(target?.constructor?.name ?? target?.name ?? 'Object')}.${String(name)}`, (that, ...args) => {
1472
+ return original.call(that, ...args);
1473
+ }), {
1474
+ method: original,
1475
+ propertyKey: name,
1476
+ });
1477
+ const origRoot = original[rootFunctionSymbol];
1478
+ if (origRoot)
1479
+ wrapper[rootFunctionSymbol] = origRoot;
1480
+ wrapperRegistry.set(original, wrapper);
1481
+ }
1482
+ const memoized = memoizeFunction(wrapper, memoizeOpts);
1483
+ return memoized(this, ...args);
1484
+ };
1485
+ },
1486
+ default: (target) => typeof target === 'object'
1487
+ ? memoizeObject(target, memoizeOpts)
1488
+ : memoizeFunction(target, memoizeOpts),
1647
1489
  });
1648
1490
  }
1491
+ const memoize = flavored(makeMemoizeDecorator(), {
1492
+ get lenient() {
1493
+ return makeMemoizeDecorator({ lenient: true });
1494
+ },
1495
+ });
1649
1496
 
1650
1497
  /**
1651
1498
  * Organizes a source object's properties into a target object using a callback function.
@@ -1721,7 +1568,7 @@ function organized(source, apply, baseTarget = {}) {
1721
1568
  });
1722
1569
  return apply(accessBase, target);
1723
1570
  });
1724
- return cleanedBy(target, (reason) => stop(reason));
1571
+ return link(target, (reason) => stop(reason));
1725
1572
  }
1726
1573
  /**
1727
1574
  * Organizes a property on a target object
@@ -1764,7 +1611,7 @@ changed, options = {}) {
1764
1611
  function watchObject(value, changed, { immediate = false, deep = false } = {}) {
1765
1612
  if (deep)
1766
1613
  return deepWatch(value, changed, { immediate });
1767
- return effect(function watchObjectEffect() {
1614
+ return effect.named('watch:object')(() => {
1768
1615
  dependant(value);
1769
1616
  if (immediate)
1770
1617
  changed(value);
@@ -1774,7 +1621,7 @@ function watchObject(value, changed, { immediate = false, deep = false } = {}) {
1774
1621
  function watchCallBack(value, changed, { immediate = false, deep = false } = {}) {
1775
1622
  let oldValue = unsetYet;
1776
1623
  let deepCleanup;
1777
- const cbCleanup = effect(markWithRoot(function watchCallBackEffect(access) {
1624
+ const cbCleanup = effect.named('watch:callback')(markWithRoot((access) => {
1778
1625
  const newValue = value(access);
1779
1626
  if (oldValue !== newValue) {
1780
1627
  const old = oldValue;
@@ -1792,12 +1639,10 @@ function watchCallBack(value, changed, { immediate = false, deep = false } = {})
1792
1639
  deepCleanup = deepWatch(newValue, (value) => changed(value, value));
1793
1640
  }
1794
1641
  }, value));
1795
- return Object.defineProperties(() => {
1642
+ return (() => {
1796
1643
  cbCleanup();
1797
1644
  if (deepCleanup)
1798
1645
  deepCleanup();
1799
- }, {
1800
- [stopped]: { get: () => cbCleanup[stopped] },
1801
1646
  });
1802
1647
  }
1803
1648
  //#endregion
@@ -1812,7 +1657,7 @@ function watchCallBack(value, changed, { immediate = false, deep = false } = {})
1812
1657
  function when(predicate, timeout) {
1813
1658
  return new Promise((resolve, reject) => {
1814
1659
  let timer;
1815
- const stop = effect(function whenEffect(access) {
1660
+ const stop = effect.named('watch:when')((access) => {
1816
1661
  try {
1817
1662
  const value = predicate(access);
1818
1663
  if (value) {
@@ -1849,7 +1694,7 @@ function shallowNonReactive(obj) {
1849
1694
  obj = unwrap(obj);
1850
1695
  if (isNonReactive(obj))
1851
1696
  return obj;
1852
- nonReactiveObjects.add(obj);
1697
+ obj[unreactiveProperties] = true;
1853
1698
  return obj;
1854
1699
  }
1855
1700
  function unreactiveApplication(arg1, ...args) {
@@ -1857,13 +1702,19 @@ function unreactiveApplication(arg1, ...args) {
1857
1702
  ? shallowNonReactive(arg1)
1858
1703
  : ((original) => {
1859
1704
  // Copy the parent's unreactive properties if they exist
1860
- const parentSet = unreactiveProps.get(original.prototype);
1861
- const set = new Set(parentSet || []);
1862
- // Add all arguments (including the first one)
1863
- set.add(arg1);
1864
- for (const arg of args)
1865
- set.add(arg);
1866
- addUnreactiveProps(original.prototype, set);
1705
+ const parentMarker = original.prototype[unreactiveProperties];
1706
+ // If parent is fully unreactive, child is too
1707
+ if (parentMarker === true) {
1708
+ original.prototype[unreactiveProperties] = true;
1709
+ }
1710
+ else {
1711
+ const set = new Set(parentMarker || []);
1712
+ // Add all arguments (including the first one)
1713
+ set.add(arg1);
1714
+ for (const arg of args)
1715
+ set.add(arg);
1716
+ addUnreactiveProps(original.prototype, set);
1717
+ }
1867
1718
  return original; // Return the class
1868
1719
  });
1869
1720
  }
@@ -1873,11 +1724,26 @@ function unreactiveApplication(arg1, ...args) {
1873
1724
  */
1874
1725
  const unreactive = decorator({
1875
1726
  class(original) {
1876
- // Called without arguments, mark entire class as non-reactive
1877
- nonReactiveClass(original);
1727
+ original.prototype[unreactiveProperties] = true;
1878
1728
  },
1879
1729
  default: unreactiveApplication,
1880
1730
  });
1731
+ //#endregion
1732
+ //#region resource
1733
+ function lazyInit(resource, load) {
1734
+ const creation = effectHistory.active;
1735
+ let fresh = true;
1736
+ return new Proxy(resource, {
1737
+ [Symbol.toStringTag]: 'LazyInit',
1738
+ get(target, prop) {
1739
+ if (fresh) {
1740
+ captured(creation, load)();
1741
+ fresh = false;
1742
+ }
1743
+ return target[prop];
1744
+ },
1745
+ });
1746
+ }
1881
1747
  /**
1882
1748
  * Creates a reactive resource that automatically tracks async state.
1883
1749
  * @param fetcher - Async function that returns the value. Reactive dependencies are tracked.
@@ -1885,521 +1751,59 @@ const unreactive = decorator({
1885
1751
  * @returns Reactive Resource object with value, loading, error, latest properties
1886
1752
  */
1887
1753
  function resource(fetcher, options = {}) {
1888
- const state = reactive({
1754
+ const resource = reactive({
1889
1755
  value: options.initialValue,
1890
1756
  loading: true,
1891
1757
  error: undefined,
1892
1758
  latest: options.initialValue,
1893
- reload: () => {
1759
+ reload() {
1894
1760
  reloadSignal.value++;
1895
1761
  },
1896
1762
  });
1897
1763
  const reloadSignal = reactive({ value: 0 });
1764
+ // Solve race conditions: make sure a new fast request is not overloaded by a slow old one
1898
1765
  let counter = 0;
1899
- const stop = effect(function resourceEffect(access) {
1900
- // Track reload signal to enable manual reloading
1901
- if (reloadSignal.value) ;
1902
- const id = ++counter;
1903
- state.loading = true;
1904
- state.error = undefined;
1905
- try {
1906
- const result = fetcher(access);
1907
- if (result instanceof Promise) {
1908
- result.then((val) => {
1909
- if (id === counter) {
1910
- state.value = val;
1911
- state.latest = val;
1912
- state.loading = false;
1913
- }
1914
- }, (err) => {
1915
- if (id === counter) {
1916
- state.error = err;
1917
- state.loading = false;
1918
- }
1919
- });
1920
- }
1921
- else {
1922
- state.value = result;
1923
- state.latest = result;
1924
- state.loading = false;
1925
- }
1926
- }
1927
- catch (err) {
1928
- state.error = err;
1929
- state.loading = false;
1930
- }
1931
- });
1932
- state.stop = stop;
1933
- return state;
1934
- }
1935
- //#endregion
1936
-
1937
- // Helper to work around TypeScript limitation: base class expressions cannot reference class type parameters
1938
- function getRegisterBase() {
1939
- class RegisterBase extends Indexable(ArrayReadForward, {
1940
- get(index) {
1941
- return this[getAt](index);
1942
- },
1943
- set(index, value) {
1944
- this[setAt](index, value);
1945
- },
1946
- getLength() {
1947
- return this.length;
1948
- },
1949
- setLength(value) {
1950
- this.length = value;
1951
- },
1952
- }) {
1953
- toArray() {
1954
- return Array.from(this);
1955
- }
1956
- }
1957
- return RegisterBase;
1958
- }
1959
- let RegisterClass = (() => {
1960
- var _RegisterClass_instances, _RegisterClass_keyFn, _RegisterClass_keys, _RegisterClass_values, _RegisterClass_usage, _RegisterClass_valueInfo, _RegisterClass_keyEffects, _RegisterClass_ascend, _RegisterClass_events, _RegisterClass_rekeyValue;
1961
- let _classDecorators = [unreactive];
1962
- let _classDescriptor;
1963
- let _classExtraInitializers = [];
1964
- let _classThis;
1965
- let _classSuper = getRegisterBase();
1966
- _classThis = class extends _classSuper {
1967
- get [(_RegisterClass_keyFn = new WeakMap(), _RegisterClass_keys = new WeakMap(), _RegisterClass_values = new WeakMap(), _RegisterClass_usage = new WeakMap(), _RegisterClass_valueInfo = new WeakMap(), _RegisterClass_keyEffects = new WeakMap(), _RegisterClass_ascend = new WeakMap(), _RegisterClass_events = new WeakMap(), _RegisterClass_instances = new WeakSet(), forwardArray)]() {
1968
- return this.toArray();
1969
- }
1970
- on(eventOrEvents, cb) {
1971
- // @ts-expect-error Delegate to Eventful
1972
- return __classPrivateFieldGet(this, _RegisterClass_events, "f").on(eventOrEvents, cb);
1973
- }
1974
- off(eventOrEvents, cb) {
1975
- // @ts-expect-error Delegate to Eventful
1976
- __classPrivateFieldGet(this, _RegisterClass_events, "f").off(eventOrEvents, cb);
1977
- }
1978
- /**
1979
- * Register a global hook that receives all events
1980
- */
1981
- hook(cb) {
1982
- return __classPrivateFieldGet(this, _RegisterClass_events, "f").hook(cb);
1983
- }
1984
- constructor(keyFn, initial) {
1985
- super();
1986
- _RegisterClass_instances.add(this);
1987
- _RegisterClass_keyFn.set(this, void 0);
1988
- _RegisterClass_keys.set(this, void 0);
1989
- _RegisterClass_values.set(this, void 0);
1990
- _RegisterClass_usage.set(this, new Map());
1991
- _RegisterClass_valueInfo.set(this, new Map());
1992
- _RegisterClass_keyEffects.set(this, new Set());
1993
- _RegisterClass_ascend.set(this, void 0);
1994
- _RegisterClass_events.set(this, new Eventful()
1995
- /**
1996
- * Register event listeners for CRUD operations
1997
- */
1998
- );
1999
- /* Moved below initialization */
2000
- let ascendGet;
2001
- effect(({ ascend }) => {
2002
- ascendGet = ascend;
2003
- });
2004
- __classPrivateFieldSet(this, _RegisterClass_ascend, ascendGet, "f");
2005
- if (typeof keyFn !== 'function')
2006
- throw new Error('Register requires a key function');
2007
- __classPrivateFieldSet(this, _RegisterClass_keyFn, keyFn, "f");
2008
- __classPrivateFieldSet(this, _RegisterClass_keys, reactive([]), "f");
2009
- __classPrivateFieldSet(this, _RegisterClass_values, reactive(new Map()), "f");
2010
- if (initial)
2011
- this.push(...initial);
2012
- }
2013
- ensureKey(value) {
2014
- let info = __classPrivateFieldGet(this, _RegisterClass_valueInfo, "f").get(value);
2015
- if (info)
2016
- return info.key;
2017
- info = { key: undefined };
2018
- __classPrivateFieldGet(this, _RegisterClass_valueInfo, "f").set(value, info);
2019
- __classPrivateFieldGet(this, _RegisterClass_ascend, "f").call(this, () => {
2020
- const stop = effect(({ reaction }) => {
2021
- const nextKey = __classPrivateFieldGet(this, _RegisterClass_keyFn, "f").call(this, value);
2022
- this.assertValidKey(nextKey);
2023
- const previousKey = info.key;
2024
- if (reaction && previousKey !== undefined && !Object.is(nextKey, previousKey))
2025
- __classPrivateFieldGet(this, _RegisterClass_instances, "m", _RegisterClass_rekeyValue).call(this, value, previousKey, nextKey);
2026
- info.key = nextKey;
2027
- });
2028
- info.stop = stop;
2029
- __classPrivateFieldGet(this, _RegisterClass_keyEffects, "f").add(stop);
2030
- });
2031
- if (info.key === undefined)
2032
- throw new Error('Register key function must return a property key');
2033
- return info.key;
2034
- }
2035
- assertValidKey(key) {
2036
- const type = typeof key;
2037
- if (type !== 'string' && type !== 'number' && type !== 'symbol')
2038
- throw new Error('Register key function must return a property key');
2039
- }
2040
- setKeyValue(key, value, index) {
2041
- const existing = __classPrivateFieldGet(this, _RegisterClass_values, "f").get(key);
2042
- if (existing !== undefined && existing !== value) {
2043
- this.cleanupValue(existing);
2044
- __classPrivateFieldGet(this, _RegisterClass_values, "f").set(key, value);
2045
- if (index !== undefined) {
2046
- __classPrivateFieldGet(this, _RegisterClass_events, "f").emit('update', existing, value, key, index);
2047
- }
2048
- }
2049
- else {
2050
- __classPrivateFieldGet(this, _RegisterClass_values, "f").set(key, value);
2051
- }
2052
- }
2053
- cleanupValue(value) {
2054
- const info = __classPrivateFieldGet(this, _RegisterClass_valueInfo, "f").get(value);
2055
- if (!info)
2056
- return;
2057
- const stop = info.stop;
2058
- if (stop) {
2059
- info.stop = undefined;
2060
- __classPrivateFieldGet(this, _RegisterClass_keyEffects, "f").delete(stop);
2061
- stop();
2062
- }
2063
- __classPrivateFieldGet(this, _RegisterClass_valueInfo, "f").delete(value);
2064
- }
2065
- disposeKeyEffects() {
2066
- for (const value of Array.from(__classPrivateFieldGet(this, _RegisterClass_valueInfo, "f").keys()))
2067
- this.cleanupValue(value);
2068
- __classPrivateFieldGet(this, _RegisterClass_keyEffects, "f").clear();
2069
- }
2070
- incrementUsage(key) {
2071
- const count = __classPrivateFieldGet(this, _RegisterClass_usage, "f").get(key) ?? 0;
2072
- __classPrivateFieldGet(this, _RegisterClass_usage, "f").set(key, count + 1);
2073
- }
2074
- decrementUsage(key, index) {
2075
- const count = __classPrivateFieldGet(this, _RegisterClass_usage, "f").get(key);
2076
- if (!count)
2077
- return;
2078
- if (count <= 1) {
2079
- const value = __classPrivateFieldGet(this, _RegisterClass_values, "f").get(key);
2080
- __classPrivateFieldGet(this, _RegisterClass_usage, "f").delete(key);
2081
- __classPrivateFieldGet(this, _RegisterClass_values, "f").delete(key);
2082
- if (value !== undefined) {
2083
- this.cleanupValue(value);
2084
- const idx = index ?? __classPrivateFieldGet(this, _RegisterClass_keys, "f").indexOf(key);
2085
- __classPrivateFieldGet(this, _RegisterClass_events, "f").emit('delete', value, key, idx);
2086
- }
2087
- }
2088
- else {
2089
- __classPrivateFieldGet(this, _RegisterClass_usage, "f").set(key, count - 1);
2090
- }
2091
- }
2092
- normalizeIndex(index, allowEnd = false) {
2093
- const length = this.length;
2094
- let resolved = index;
2095
- if (resolved < 0)
2096
- resolved = Math.max(length + resolved, 0);
2097
- if (resolved > length) {
2098
- if (allowEnd)
2099
- resolved = length;
2100
- else
2101
- throw new RangeError('Index out of bounds');
2102
- }
2103
- if (!allowEnd && resolved === length)
2104
- throw new RangeError('Index out of bounds');
2105
- return resolved;
2106
- }
2107
- assignAt(index, key, value) {
2108
- const oldKey = __classPrivateFieldGet(this, _RegisterClass_keys, "f")[index];
2109
- if (oldKey !== undefined && Object.is(oldKey, key)) {
2110
- const oldValue = __classPrivateFieldGet(this, _RegisterClass_values, "f").get(key);
2111
- this.setKeyValue(key, value);
2112
- if (oldValue !== undefined && oldValue !== value) {
2113
- __classPrivateFieldGet(this, _RegisterClass_events, "f").emit('update', oldValue, value, key, index);
2114
- }
2115
- return;
2116
- }
2117
- if (oldKey !== undefined)
2118
- this.decrementUsage(oldKey);
2119
- __classPrivateFieldGet(this, _RegisterClass_keys, "f")[index] = key;
2120
- this.incrementUsage(key);
2121
- this.setKeyValue(key, value);
2122
- __classPrivateFieldGet(this, _RegisterClass_events, "f").emit('add', value, key, index);
2123
- }
2124
- insertKeyValue(index, key, value) {
2125
- __classPrivateFieldGet(this, _RegisterClass_keys, "f").splice(index, 0, key);
2126
- this.incrementUsage(key);
2127
- this.setKeyValue(key, value);
2128
- __classPrivateFieldGet(this, _RegisterClass_events, "f").emit('add', value, key, index);
2129
- }
2130
- rebuildFrom(values) {
2131
- this.disposeKeyEffects();
2132
- __classPrivateFieldGet(this, _RegisterClass_keys, "f").splice(0, __classPrivateFieldGet(this, _RegisterClass_keys, "f").length);
2133
- __classPrivateFieldGet(this, _RegisterClass_usage, "f").clear();
2134
- __classPrivateFieldGet(this, _RegisterClass_values, "f").clear();
2135
- for (const value of values) {
2136
- const key = this.ensureKey(value);
2137
- __classPrivateFieldGet(this, _RegisterClass_keys, "f").push(key);
2138
- this.incrementUsage(key);
2139
- __classPrivateFieldGet(this, _RegisterClass_values, "f").set(key, value);
2140
- }
2141
- }
2142
- get length() {
2143
- return __classPrivateFieldGet(this, _RegisterClass_keys, "f").length;
2144
- }
2145
- [(_RegisterClass_rekeyValue = function _RegisterClass_rekeyValue(value, oldKey, newKey) {
2146
- if (Object.is(oldKey, newKey))
2147
- return;
2148
- const existingValue = __classPrivateFieldGet(this, _RegisterClass_values, "f").get(newKey);
2149
- if (existingValue !== undefined && existingValue !== value)
2150
- throw new Error(`Register key collision for key ${String(newKey)}`);
2151
- const count = __classPrivateFieldGet(this, _RegisterClass_usage, "f").get(oldKey);
2152
- if (!count)
2153
- return;
2154
- const existingCount = __classPrivateFieldGet(this, _RegisterClass_usage, "f").get(newKey) ?? 0;
2155
- this.setKeyValue(newKey, value);
2156
- let index = -1;
2157
- for (let i = 0; i < __classPrivateFieldGet(this, _RegisterClass_keys, "f").length; i++)
2158
- if (Object.is(__classPrivateFieldGet(this, _RegisterClass_keys, "f")[i], oldKey)) {
2159
- __classPrivateFieldGet(this, _RegisterClass_keys, "f")[i] = newKey;
2160
- if (index === -1)
2161
- index = i;
2162
- }
2163
- __classPrivateFieldGet(this, _RegisterClass_usage, "f").set(newKey, existingCount + count);
2164
- __classPrivateFieldGet(this, _RegisterClass_usage, "f").delete(oldKey);
2165
- __classPrivateFieldGet(this, _RegisterClass_values, "f").delete(oldKey);
2166
- const updatedInfo = __classPrivateFieldGet(this, _RegisterClass_valueInfo, "f").get(value);
2167
- if (updatedInfo)
2168
- updatedInfo.key = newKey;
2169
- if (index !== -1) {
2170
- __classPrivateFieldGet(this, _RegisterClass_events, "f").emit('rekey', value, oldKey, newKey, index);
2171
- }
2172
- }, getAt)](index) {
2173
- const key = __classPrivateFieldGet(this, _RegisterClass_keys, "f")[index];
2174
- return key === undefined ? undefined : __classPrivateFieldGet(this, _RegisterClass_values, "f").get(key);
2175
- }
2176
- [setAt](index, value) {
2177
- const key = this.ensureKey(value);
2178
- if (index === this.length) {
2179
- this.insertKeyValue(index, key, value);
2180
- return;
2181
- }
2182
- const normalized = this.normalizeIndex(index);
2183
- this.assignAt(normalized, key, value);
2184
- }
2185
- push(...items) {
2186
- for (const item of items) {
2187
- const key = this.ensureKey(item);
2188
- this.insertKeyValue(this.length, key, item);
2189
- }
2190
- return this.length;
2191
- }
2192
- pop() {
2193
- if (!this.length)
2194
- return undefined;
2195
- return this.removeAt(this.length - 1);
2196
- }
2197
- shift() {
2198
- if (!this.length)
2199
- return undefined;
2200
- return this.removeAt(0);
2201
- }
2202
- unshift(...items) {
2203
- let index = 0;
2204
- for (const item of items) {
2205
- const key = this.ensureKey(item);
2206
- this.insertKeyValue(index++, key, item);
2207
- }
2208
- return this.length;
2209
- }
2210
- splice(start, deleteCount, ...items) {
2211
- const normalizedStart = this.normalizeIndex(start, true);
2212
- const maxDeletions = this.length - normalizedStart;
2213
- const actualDelete = Math.min(deleteCount === undefined ? maxDeletions : Math.max(deleteCount, 0), maxDeletions);
2214
- const keysToInsert = [];
2215
- for (const item of items)
2216
- keysToInsert.push(this.ensureKey(item));
2217
- const removedKeys = __classPrivateFieldGet(this, _RegisterClass_keys, "f").splice(normalizedStart, actualDelete, ...keysToInsert);
2218
- const removedValues = [];
2219
- for (let i = 0; i < removedKeys.length; i++) {
2220
- const key = removedKeys[i];
2221
- if (key === undefined)
2222
- continue;
2223
- const value = __classPrivateFieldGet(this, _RegisterClass_values, "f").get(key);
2224
- this.decrementUsage(key, normalizedStart + i);
2225
- removedValues.push(value);
2226
- }
2227
- for (let i = 0; i < keysToInsert.length; i++) {
2228
- const key = keysToInsert[i];
2229
- const value = items[i];
2230
- this.incrementUsage(key);
2231
- this.setKeyValue(key, value);
2232
- }
2233
- return removedValues;
2234
- }
2235
- clear() {
2236
- __classPrivateFieldGet(this, _RegisterClass_keys, "f").length = 0;
2237
- __classPrivateFieldGet(this, _RegisterClass_usage, "f").clear();
2238
- __classPrivateFieldGet(this, _RegisterClass_values, "f").clear();
2239
- this.disposeKeyEffects();
2240
- }
2241
- get(key) {
2242
- return __classPrivateFieldGet(this, _RegisterClass_values, "f").get(key);
2243
- }
2244
- set(key, value) {
2245
- if (__classPrivateFieldGet(this, _RegisterClass_values, "f").has(key))
2246
- this.setKeyValue(key, value);
2247
- }
2248
- remove(key) {
2249
- let index = this.indexOfKey(key);
2250
- while (index !== -1) {
2251
- this.removeAt(index);
2252
- index = this.indexOfKey(key);
2253
- }
2254
- }
2255
- removeAt(index) {
2256
- const [key] = __classPrivateFieldGet(this, _RegisterClass_keys, "f").splice(index, 1);
2257
- if (key === undefined)
2258
- return undefined;
2259
- const value = __classPrivateFieldGet(this, _RegisterClass_values, "f").get(key);
2260
- this.decrementUsage(key, index);
2261
- return value;
2262
- }
2263
- /**
2264
- * Keep only the items for which the predicate returns true.
2265
- * Items for which the predicate returns false are removed.
2266
- *
2267
- * The predicate is evaluated once per distinct key; duplicate keys
2268
- * will follow the same keep/remove decision.
2269
- */
2270
- keep(predicate) {
2271
- const decisions = new Map();
2272
- for (const [index, key] of __classPrivateFieldGet(this, _RegisterClass_keys, "f").entries()) {
2273
- if (decisions.has(key)) {
2274
- if (!decisions.get(key))
2275
- this.removeAt(index);
2276
- continue;
2277
- }
2278
- const value = __classPrivateFieldGet(this, _RegisterClass_values, "f").get(key);
2279
- const shouldKeep = predicate(value);
2280
- decisions.set(key, shouldKeep);
2281
- if (!shouldKeep)
2282
- this.removeAt(index);
2283
- }
2284
- }
2285
- hasKey(key) {
2286
- return __classPrivateFieldGet(this, _RegisterClass_usage, "f").has(key);
2287
- }
2288
- indexOfKey(key) {
2289
- return __classPrivateFieldGet(this, _RegisterClass_keys, "f").indexOf(key);
2290
- }
2291
- mapKeys() {
2292
- return __classPrivateFieldGet(this, _RegisterClass_values, "f").keys();
2293
- }
2294
- update(...values) {
2295
- for (const value of values) {
2296
- const key = this.ensureKey(value);
2297
- if (__classPrivateFieldGet(this, _RegisterClass_values, "f").has(key)) {
2298
- const index = __classPrivateFieldGet(this, _RegisterClass_keys, "f").indexOf(key);
2299
- this.setKeyValue(key, value, index);
1766
+ return lazyInit(resource, () => {
1767
+ link(resource, effect.named('watch:resource')((access) => {
1768
+ // Track reload signal to enable manual reloading
1769
+ void reloadSignal.value;
1770
+ const id = ++counter;
1771
+ resource.loading = true;
1772
+ resource.error = undefined;
1773
+ try {
1774
+ const result = fetcher(access);
1775
+ if (result instanceof Promise) {
1776
+ resource.promise = result
1777
+ .then((val) => {
1778
+ if (id === counter) {
1779
+ resource.value = val;
1780
+ resource.latest = val;
1781
+ resource.loading = false;
1782
+ }
1783
+ })
1784
+ .catch((err) => {
1785
+ if (id === counter) {
1786
+ resource.error = err;
1787
+ resource.loading = false;
1788
+ }
1789
+ });
2300
1790
  }
2301
- }
2302
- }
2303
- upsert(insert, ...values) {
2304
- for (const value of values) {
2305
- const key = this.ensureKey(value);
2306
- if (__classPrivateFieldGet(this, _RegisterClass_values, "f").has(key))
2307
- this.setKeyValue(key, value);
2308
- else
2309
- insert(value);
2310
- }
2311
- }
2312
- entries() {
2313
- const self = this;
2314
- function* iterator() {
2315
- for (let i = 0; i < __classPrivateFieldGet(self, _RegisterClass_keys, "f").length; i++) {
2316
- const val = __classPrivateFieldGet(self, _RegisterClass_values, "f").get(__classPrivateFieldGet(self, _RegisterClass_keys, "f")[i]);
2317
- if (val !== undefined)
2318
- yield [i, val];
1791
+ else {
1792
+ resource.promise = Promise.resolve();
1793
+ resource.value = result;
1794
+ resource.latest = result;
1795
+ resource.loading = false;
2319
1796
  }
2320
1797
  }
2321
- return iterator();
2322
- }
2323
- [Symbol.iterator]() {
2324
- const self = this;
2325
- function* iterator() {
2326
- for (const key of __classPrivateFieldGet(self, _RegisterClass_keys, "f")) {
2327
- const value = __classPrivateFieldGet(self, _RegisterClass_values, "f").get(key);
2328
- if (value !== undefined)
2329
- yield value;
2330
- }
1798
+ catch (err) {
1799
+ resource.promise = Promise.reject(err);
1800
+ resource.error = err;
1801
+ resource.loading = false;
2331
1802
  }
2332
- return iterator();
2333
- }
2334
- toString() {
2335
- return `[Register length=${this.length}]`;
2336
- }
2337
- at(index) {
2338
- const resolved = index < 0 ? this.length + index : index;
2339
- if (resolved < 0 || resolved >= this.length)
2340
- return undefined;
2341
- return this[getAt](resolved);
2342
- }
2343
- reverse() {
2344
- __classPrivateFieldGet(this, _RegisterClass_keys, "f").reverse();
2345
- return this;
2346
- }
2347
- sort(compareFn) {
2348
- const fwdCompareFn = compareFn
2349
- ? (a, b) => compareFn(__classPrivateFieldGet(this, _RegisterClass_values, "f").get(a), __classPrivateFieldGet(this, _RegisterClass_values, "f").get(b))
2350
- : undefined;
2351
- __classPrivateFieldGet(this, _RegisterClass_keys, "f").sort(fwdCompareFn);
2352
- return this;
2353
- }
2354
- fill(value, start = 0, end = this.length) {
2355
- const values = this.toArray();
2356
- values.fill(value, start, end);
2357
- this.rebuildFrom(values);
2358
- return this;
2359
- }
2360
- copyWithin(target, start, end) {
2361
- const values = this.toArray();
2362
- values.copyWithin(target, start, end);
2363
- this.rebuildFrom(values);
2364
- return this;
2365
- }
2366
- };
2367
- __setFunctionName(_classThis, "RegisterClass");
2368
- (() => {
2369
- const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
2370
- __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
2371
- _classThis = _classDescriptor.value;
2372
- if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
2373
- __runInitializers(_classThis, _classExtraInitializers);
2374
- })();
2375
- return _classThis;
2376
- })();
2377
- const Register = RegisterClass;
2378
- /**
2379
- * Creates a reactive Register - an ordered, array-like collection with stable key-based identity.
2380
- *
2381
- * Register combines array semantics (indexable access, ordering, iteration) with Map-like
2382
- * key-based lookups. Items with the same key share the same value instance, making it ideal
2383
- * for UI lists keyed by IDs or when you need to preserve identity across reorders.
2384
- *
2385
- * @param keyFn - Function that extracts the key from each item
2386
- * @param initial - Optional initial items to populate the register
2387
- * @returns A reactive Register instance
2388
- *
2389
- * @example
2390
- * ```typescript
2391
- * const users = register(
2392
- * (user: User) => user.id,
2393
- * [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]
2394
- * )
2395
- *
2396
- * users.push({ id: 3, name: 'Charlie' })
2397
- * const bob = users.get(2) // Get by key
2398
- * ```
2399
- */
2400
- function register(keyFn, initial) {
2401
- return new RegisterClass(keyFn, initial);
1803
+ }));
1804
+ });
2402
1805
  }
1806
+ //#endregion
2403
1807
 
2404
1808
  /**
2405
1809
  * Converts an iterator to a generator that yields reactive values
@@ -2482,6 +1886,7 @@ let ReactiveArrayWrapper = (() => {
2482
1886
  let _classSuper = Array;
2483
1887
  let _instanceExtraInitializers = [];
2484
1888
  let _fill_decorators;
1889
+ let _copyWithin_decorators;
2485
1890
  let _pop_decorators;
2486
1891
  let _push_decorators;
2487
1892
  let _reverse_decorators;
@@ -2506,6 +1911,9 @@ let ReactiveArrayWrapper = (() => {
2506
1911
  fill(value, start, end) {
2507
1912
  return super.fill(unwrap(value), start, end);
2508
1913
  }
1914
+ copyWithin(target, start, end) {
1915
+ return super.copyWithin(target, start, end);
1916
+ }
2509
1917
  filter(predicate, thisArg) {
2510
1918
  return reactive(super.filter((v, i, a) => predicate.call(thisArg, reactive(v), i, a), thisArg));
2511
1919
  }
@@ -2607,7 +2015,7 @@ let ReactiveArrayWrapper = (() => {
2607
2015
  dependant(this, keysOf);
2608
2016
  return makeReactiveIterator(super.values());
2609
2017
  }
2610
- [(_fill_decorators = [atomic], _pop_decorators = [atomic], _push_decorators = [atomic], _reverse_decorators = [atomic], _shift_decorators = [atomic], _sort_decorators = [atomic], _splice_decorators = [atomic], _unshift_decorators = [atomic], Symbol.iterator)]() {
2018
+ [(_fill_decorators = [atomic], _copyWithin_decorators = [atomic], _pop_decorators = [atomic], _push_decorators = [atomic], _reverse_decorators = [atomic], _shift_decorators = [atomic], _sort_decorators = [atomic], _splice_decorators = [atomic], _unshift_decorators = [atomic], Symbol.iterator)]() {
2611
2019
  dependant(this, keysOf);
2612
2020
  return makeReactiveIterator(super[Symbol.iterator]());
2613
2021
  }
@@ -2620,7 +2028,6 @@ let ReactiveArrayWrapper = (() => {
2620
2028
  : undefined;
2621
2029
  return reactive(super.toSorted(wrappedCompare));
2622
2030
  }
2623
- // biome-ignore lint/complexity/noArguments: Needed to distinguish fn() from fn(undefined)
2624
2031
  toSpliced(start, deleteCount, ...items) {
2625
2032
  if (arguments.length > 2)
2626
2033
  return reactive(super.toSpliced(start, deleteCount, ...items.map(unwrap)));
@@ -2641,6 +2048,7 @@ let ReactiveArrayWrapper = (() => {
2641
2048
  (() => {
2642
2049
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
2643
2050
  __esDecorate(_a, null, _fill_decorators, { kind: "method", name: "fill", static: false, private: false, access: { has: obj => "fill" in obj, get: obj => obj.fill }, metadata: _metadata }, null, _instanceExtraInitializers);
2051
+ __esDecorate(_a, null, _copyWithin_decorators, { kind: "method", name: "copyWithin", static: false, private: false, access: { has: obj => "copyWithin" in obj, get: obj => obj.copyWithin }, metadata: _metadata }, null, _instanceExtraInitializers);
2644
2052
  __esDecorate(_a, null, _pop_decorators, { kind: "method", name: "pop", static: false, private: false, access: { has: obj => "pop" in obj, get: obj => obj.pop }, metadata: _metadata }, null, _instanceExtraInitializers);
2645
2053
  __esDecorate(_a, null, _push_decorators, { kind: "method", name: "push", static: false, private: false, access: { has: obj => "push" in obj, get: obj => obj.push }, metadata: _metadata }, null, _instanceExtraInitializers);
2646
2054
  __esDecorate(_a, null, _reverse_decorators, { kind: "method", name: "reverse", static: false, private: false, access: { has: obj => "reverse" in obj, get: obj => obj.reverse }, metadata: _metadata }, null, _instanceExtraInitializers);
@@ -2661,18 +2069,18 @@ class ReactiveWeakMap extends WeakMap {
2661
2069
  // Implement WeakMap interface methods with reactivity
2662
2070
  delete(key) {
2663
2071
  const hadKey = this.has(key);
2664
- const result = this.delete(key);
2072
+ const result = super.delete(key);
2665
2073
  if (hadKey)
2666
2074
  touched1(contentRef(this), { type: 'del', prop: key }, key);
2667
2075
  return result;
2668
2076
  }
2669
2077
  get(key) {
2670
2078
  dependant(contentRef(this), key);
2671
- return reactive(this.get(key));
2079
+ return reactive(super.get(key));
2672
2080
  }
2673
2081
  has(key) {
2674
2082
  dependant(contentRef(this), key);
2675
- return this.has(key);
2083
+ return super.has(key);
2676
2084
  }
2677
2085
  set(key, value) {
2678
2086
  const hadKey = this.has(key);
@@ -2693,16 +2101,18 @@ class ReactiveMap extends Map {
2693
2101
  // Implement Map interface methods with reactivity
2694
2102
  get size() {
2695
2103
  dependant(this, 'size'); // The ReactiveMap instance still goes through proxy
2696
- return this.size;
2104
+ return super.size;
2697
2105
  }
2698
2106
  clear() {
2699
2107
  const hadEntries = this.size > 0;
2700
- this.clear();
2108
+ super.clear();
2701
2109
  if (hadEntries) {
2702
2110
  const evolution = { type: 'bunch', method: 'clear' };
2703
2111
  // Clear triggers all effects since all keys are affected
2704
- touched1(this, evolution, 'size');
2705
- touched(contentRef(this), evolution);
2112
+ batch(() => {
2113
+ touched1(this, evolution, 'size');
2114
+ touched(contentRef(this), evolution);
2115
+ });
2706
2116
  }
2707
2117
  }
2708
2118
  entries() {
@@ -2737,32 +2147,36 @@ class ReactiveMap extends Map {
2737
2147
  // Implement Map methods with reactivity
2738
2148
  delete(key) {
2739
2149
  const hadKey = this.has(key);
2740
- const result = this.delete(key);
2150
+ const result = super.delete(key);
2741
2151
  if (hadKey) {
2742
2152
  const evolution = { type: 'del', prop: key };
2743
- touched1(contentRef(this), evolution, key);
2744
- touched1(this, evolution, 'size');
2153
+ batch(() => {
2154
+ touched1(contentRef(this), evolution, key);
2155
+ touched1(this, evolution, 'size');
2156
+ });
2745
2157
  }
2746
2158
  return result;
2747
2159
  }
2748
2160
  get(key) {
2749
2161
  dependant(contentRef(this), key);
2750
- return reactive(this.get(key));
2162
+ return reactive(super.get(key));
2751
2163
  }
2752
2164
  has(key) {
2753
2165
  dependant(contentRef(this), key);
2754
- return this.has(key);
2166
+ return super.has(key);
2755
2167
  }
2756
2168
  set(key, value) {
2757
2169
  const hadKey = this.has(key);
2758
2170
  const oldValue = this.get(key);
2759
2171
  const reactiveValue = reactive(value);
2760
- this.set(key, reactiveValue);
2172
+ super.set(key, reactiveValue);
2761
2173
  if (!hadKey || oldValue !== reactiveValue) {
2762
- notifyPropertyChange(contentRef(this), key, oldValue, reactiveValue, hadKey);
2763
- // Also notify size change for Map (WeakMap doesn't track size)
2764
- const evolution = { type: hadKey ? 'set' : 'add', prop: key };
2765
- touched1(this, evolution, 'size');
2174
+ batch(() => {
2175
+ notifyPropertyChange(contentRef(this), key, oldValue, reactiveValue, hadKey);
2176
+ // Also notify size change for Map (WeakMap doesn't track size)
2177
+ const evolution = { type: hadKey ? 'set' : 'add', prop: key };
2178
+ touched1(this, evolution, 'size');
2179
+ });
2766
2180
  }
2767
2181
  return this;
2768
2182
  }
@@ -2775,7 +2189,7 @@ class ReactiveMap extends Map {
2775
2189
  class ReactiveWeakSet extends WeakSet {
2776
2190
  add(value) {
2777
2191
  const had = this.has(value);
2778
- this.add(value);
2192
+ super.add(value);
2779
2193
  if (!had) {
2780
2194
  // touch the specific value and the collection view
2781
2195
  touched1(contentRef(this), { type: 'add', prop: value }, value);
@@ -2785,14 +2199,14 @@ class ReactiveWeakSet extends WeakSet {
2785
2199
  }
2786
2200
  delete(value) {
2787
2201
  const had = this.has(value);
2788
- const res = this.delete(value);
2202
+ const res = super.delete(value);
2789
2203
  if (had)
2790
2204
  touched1(contentRef(this), { type: 'del', prop: value }, value);
2791
2205
  return res;
2792
2206
  }
2793
2207
  has(value) {
2794
2208
  dependant(contentRef(this), value);
2795
- return this.has(value);
2209
+ return super.has(value);
2796
2210
  }
2797
2211
  }
2798
2212
  /**
@@ -2808,31 +2222,37 @@ class ReactiveSet extends Set {
2808
2222
  add(value) {
2809
2223
  const had = this.has(value);
2810
2224
  const reactiveValue = reactive(value);
2811
- this.add(reactiveValue);
2225
+ super.add(reactiveValue);
2812
2226
  if (!had) {
2813
2227
  const evolution = { type: 'add', prop: reactiveValue };
2814
2228
  // touch for value-specific and aggregate dependencies
2815
- touched1(contentRef(this), evolution, reactiveValue);
2816
- touched1(this, evolution, 'size');
2229
+ batch(() => {
2230
+ touched1(contentRef(this), evolution, reactiveValue);
2231
+ touched1(this, evolution, 'size');
2232
+ });
2817
2233
  }
2818
2234
  return this;
2819
2235
  }
2820
2236
  clear() {
2821
2237
  const hadEntries = this.size > 0;
2822
- this.clear();
2238
+ super.clear();
2823
2239
  if (hadEntries) {
2824
2240
  const evolution = { type: 'bunch', method: 'clear' };
2825
- touched1(this, evolution, 'size');
2826
- touched(contentRef(this), evolution);
2241
+ batch(() => {
2242
+ touched1(this, evolution, 'size');
2243
+ touched(contentRef(this), evolution);
2244
+ });
2827
2245
  }
2828
2246
  }
2829
2247
  delete(value) {
2830
2248
  const had = this.has(value);
2831
- const res = this.delete(value);
2249
+ const res = super.delete(value);
2832
2250
  if (had) {
2833
2251
  const evolution = { type: 'del', prop: value };
2834
- touched1(contentRef(this), evolution, value);
2835
- touched1(this, evolution, 'size');
2252
+ batch(() => {
2253
+ touched1(contentRef(this), evolution, value);
2254
+ touched1(this, evolution, 'size');
2255
+ });
2836
2256
  }
2837
2257
  return res;
2838
2258
  }
@@ -2871,14 +2291,12 @@ class ReactiveSet extends Set {
2871
2291
  }
2872
2292
 
2873
2293
  // Register native collection types to use specialized reactive wrappers
2874
- console.time('mutts-reactive-init');
2875
2294
  metaProtos.set(Array, ReactiveArray.prototype);
2876
2295
  metaProtos.set(Set, ReactiveSet.prototype);
2877
2296
  metaProtos.set(WeakSet, ReactiveWeakSet.prototype);
2878
2297
  metaProtos.set(Map, ReactiveMap.prototype);
2879
2298
  metaProtos.set(WeakMap, ReactiveWeakMap.prototype);
2880
2299
  wrapProtos.set(Array, ReactiveArrayWrapper.prototype);
2881
- console.timeEnd('mutts-reactive-init');
2882
2300
  /**
2883
2301
  * Object containing internal reactive system state for debugging and profiling
2884
2302
  */
@@ -2891,7 +2309,6 @@ const profileInfo = {
2891
2309
  objectsWithDeepWatchers,
2892
2310
  deepWatchers,
2893
2311
  effectToDeepWatchedObjects,
2894
- nonReactiveObjects,
2895
2312
  };
2896
2313
 
2897
2314
  // In order to avoid async re-entrance, we could use zone.js or something like that.
@@ -3057,8 +2474,7 @@ const deprecated = Object.assign(decorator({
3057
2474
  },
3058
2475
  }), {
3059
2476
  warn: (target, propertyKey, message) => {
3060
- // biome-ignore lint/suspicious/noConsole: To be overridden
3061
- console.warn(`${target.constructor.name}.${String(propertyKey)} is deprecated${message ? `: ${message}` : ''}`);
2477
+ options.warn(`${target.constructor.name}.${String(propertyKey)} is deprecated${message ? `: ${message}` : ''}`);
3062
2478
  },
3063
2479
  });
3064
2480
  /**
@@ -3121,12 +2537,11 @@ function throttle(delay) {
3121
2537
  });
3122
2538
  }
3123
2539
 
3124
- var version$1 = "1.0.10";
2540
+ var version$1 = "1.0.12";
3125
2541
  var pkg = {
3126
2542
  version: version$1};
3127
2543
 
3128
2544
  const { version } = pkg;
3129
- // Singleton verification
3130
2545
  const GLOBAL_MUTTS_KEY = '__MUTTS_INSTANCE__';
3131
2546
  const globalScope = (typeof globalThis !== 'undefined'
3132
2547
  ? globalThis
@@ -3136,28 +2551,16 @@ const globalScope = (typeof globalThis !== 'undefined'
3136
2551
  ? global
3137
2552
  : false);
3138
2553
  if (globalScope) {
3139
- // Detect the source of this instance safely across different environments
3140
2554
  let source = 'mutts/index';
3141
- // biome-ignore lint/security/noGlobalEval: Intentional eval for cross-env import.meta detection
3142
- const viteEval = eval;
3143
2555
  try {
3144
2556
  if (typeof __filename !== 'undefined')
3145
2557
  source = __filename;
3146
- else {
3147
- // Using eval to avoid SyntaxError in CJS environments where import.meta is not allowed
3148
- const meta = viteEval('import.meta');
3149
- if (meta && meta.url)
3150
- source = meta.url;
2558
+ else if (typeof import.meta !== 'undefined' && import.meta.url) {
2559
+ source = import.meta.url;
3151
2560
  }
3152
2561
  }
3153
- catch (e) {
3154
- // Fallback for environments where neither is available or accessible
3155
- }
3156
- const currentSourceInfo = {
3157
- version,
3158
- source,
3159
- timestamp: Date.now(),
3160
- };
2562
+ catch (_e) { }
2563
+ const currentSourceInfo = { version, source, timestamp: Date.now() };
3161
2564
  if (globalScope[GLOBAL_MUTTS_KEY]) {
3162
2565
  const existing = globalScope[GLOBAL_MUTTS_KEY];
3163
2566
  throw new Error(`[Mutts] Multiple instances detected!\n` +
@@ -3170,5 +2573,5 @@ if (globalScope) {
3170
2573
  globalScope[GLOBAL_MUTTS_KEY] = currentSourceInfo;
3171
2574
  }
3172
2575
 
3173
- export { ArrayReadForward as A, setAt as B, throttle as C, Destroyable as D, Eventful as E, unreactive as F, watch as G, when as H, Indexable as I, Register as R, DestructionError as a, allocated as b, allocatedValues as c, arrayDiff as d, attend as e, cache as f, cached as g, callOnGC as h, chainPromise as i, debounce as j, deepWatch as k, deprecated as l, descriptor as m, destructor as n, forwardArray as o, getAt as p, isCached as q, lift as r, memoize as s, morph as t, organize as u, organized as v, profileInfo as w, register as x, resource as y, scan as z };
3174
- //# sourceMappingURL=index-CaaQQlPJ.esm.js.map
2576
+ export { ArrayReadForward as A, unreactive as B, watch as C, Destroyable as D, Eventful as E, when as F, Indexable as I, DestructionError as a, allocated as b, allocatedValues as c, arrayDiff as d, attend as e, cache as f, cached as g, callOnGC as h, chainPromise as i, debounce as j, deepWatch as k, deprecated as l, descriptor as m, destructor as n, forwardArray as o, getAt as p, isCached as q, lift as r, memoize as s, morph as t, organize as u, organized as v, profileInfo as w, resource as x, setAt as y, throttle as z };
2577
+ //# sourceMappingURL=index-BUop6B2U.esm.js.map