mutts 1.0.6 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/README.md +1 -1
  2. package/dist/browser.d.ts +2 -0
  3. package/dist/browser.esm.js +70 -0
  4. package/dist/browser.esm.js.map +1 -0
  5. package/dist/browser.js +161 -0
  6. package/dist/browser.js.map +1 -0
  7. package/dist/chunks/{index-CDCOjzTy.js → index-BFYK02LG.js} +5760 -4338
  8. package/dist/chunks/index-BFYK02LG.js.map +1 -0
  9. package/dist/chunks/{index-DiP0RXoZ.esm.js → index-CNR6QRUl.esm.js} +5440 -4054
  10. package/dist/chunks/index-CNR6QRUl.esm.js.map +1 -0
  11. package/dist/devtools/panel.js.map +1 -1
  12. package/dist/mutts.umd.js +1 -1
  13. package/dist/mutts.umd.js.map +1 -1
  14. package/dist/mutts.umd.min.js +1 -1
  15. package/dist/mutts.umd.min.js.map +1 -1
  16. package/dist/node.d.ts +2 -0
  17. package/dist/node.esm.js +45 -0
  18. package/dist/node.esm.js.map +1 -0
  19. package/dist/node.js +136 -0
  20. package/dist/node.js.map +1 -0
  21. package/docs/ai/api-reference.md +0 -2
  22. package/docs/reactive/advanced.md +2 -5
  23. package/docs/reactive/collections.md +0 -125
  24. package/docs/reactive/core.md +27 -24
  25. package/docs/reactive/debugging.md +12 -2
  26. package/docs/reactive/project.md +1 -1
  27. package/docs/reactive/scan.md +78 -0
  28. package/docs/reactive.md +2 -1
  29. package/docs/std-decorators.md +1 -0
  30. package/docs/zone.md +88 -0
  31. package/package.json +42 -10
  32. package/src/async/browser.ts +87 -0
  33. package/src/async/index.ts +8 -0
  34. package/src/async/node.ts +46 -0
  35. package/src/decorator.ts +5 -1
  36. package/src/destroyable.ts +1 -1
  37. package/src/index.ts +22 -14
  38. package/src/indexable.ts +42 -0
  39. package/src/mixins.ts +2 -2
  40. package/src/reactive/array.ts +149 -141
  41. package/src/reactive/buffer.ts +168 -0
  42. package/src/reactive/change.ts +2 -2
  43. package/src/reactive/effect-context.ts +15 -91
  44. package/src/reactive/effects.ts +119 -179
  45. package/src/reactive/index.ts +10 -13
  46. package/src/reactive/interface.ts +19 -33
  47. package/src/reactive/map.ts +48 -61
  48. package/src/reactive/memoize.ts +19 -9
  49. package/src/reactive/project.ts +43 -22
  50. package/src/reactive/proxy.ts +16 -41
  51. package/src/reactive/record.ts +3 -3
  52. package/src/reactive/register.ts +5 -7
  53. package/src/reactive/registry.ts +9 -17
  54. package/src/reactive/set.ts +42 -56
  55. package/src/reactive/tracking.ts +1 -29
  56. package/src/reactive/types.ts +46 -23
  57. package/src/utils.ts +80 -37
  58. package/src/zone.ts +127 -0
  59. package/dist/chunks/_tslib-BgjropY9.js +0 -81
  60. package/dist/chunks/_tslib-BgjropY9.js.map +0 -1
  61. package/dist/chunks/_tslib-MCKDzsSq.esm.js +0 -75
  62. package/dist/chunks/_tslib-MCKDzsSq.esm.js.map +0 -1
  63. package/dist/chunks/decorator-BGILvPtN.esm.js +0 -627
  64. package/dist/chunks/decorator-BGILvPtN.esm.js.map +0 -1
  65. package/dist/chunks/decorator-BQ2eBTCj.js +0 -651
  66. package/dist/chunks/decorator-BQ2eBTCj.js.map +0 -1
  67. package/dist/chunks/index-CDCOjzTy.js.map +0 -1
  68. package/dist/chunks/index-DiP0RXoZ.esm.js.map +0 -1
  69. package/dist/decorator.d.ts +0 -107
  70. package/dist/decorator.esm.js +0 -2
  71. package/dist/decorator.esm.js.map +0 -1
  72. package/dist/decorator.js +0 -11
  73. package/dist/decorator.js.map +0 -1
  74. package/dist/destroyable.d.ts +0 -90
  75. package/dist/destroyable.esm.js +0 -109
  76. package/dist/destroyable.esm.js.map +0 -1
  77. package/dist/destroyable.js +0 -116
  78. package/dist/destroyable.js.map +0 -1
  79. package/dist/eventful.d.ts +0 -20
  80. package/dist/eventful.esm.js +0 -66
  81. package/dist/eventful.esm.js.map +0 -1
  82. package/dist/eventful.js +0 -68
  83. package/dist/eventful.js.map +0 -1
  84. package/dist/index.d.ts +0 -19
  85. package/dist/index.esm.js +0 -53
  86. package/dist/index.esm.js.map +0 -1
  87. package/dist/index.js +0 -139
  88. package/dist/index.js.map +0 -1
  89. package/dist/indexable.d.ts +0 -243
  90. package/dist/indexable.esm.js +0 -285
  91. package/dist/indexable.esm.js.map +0 -1
  92. package/dist/indexable.js +0 -291
  93. package/dist/indexable.js.map +0 -1
  94. package/dist/promiseChain.d.ts +0 -21
  95. package/dist/promiseChain.esm.js +0 -78
  96. package/dist/promiseChain.esm.js.map +0 -1
  97. package/dist/promiseChain.js +0 -80
  98. package/dist/promiseChain.js.map +0 -1
  99. package/dist/reactive.d.ts +0 -910
  100. package/dist/reactive.esm.js +0 -5
  101. package/dist/reactive.esm.js.map +0 -1
  102. package/dist/reactive.js +0 -59
  103. package/dist/reactive.js.map +0 -1
  104. package/dist/std-decorators.d.ts +0 -52
  105. package/dist/std-decorators.esm.js +0 -196
  106. package/dist/std-decorators.esm.js.map +0 -1
  107. package/dist/std-decorators.js +0 -204
  108. package/dist/std-decorators.js.map +0 -1
  109. package/src/reactive/mapped.ts +0 -129
  110. package/src/reactive/zone.ts +0 -208
package/dist/node.d.ts ADDED
@@ -0,0 +1,2 @@
1
+
2
+ export { };
@@ -0,0 +1,45 @@
1
+ import { createHook } from 'node:async_hooks';
2
+ import { a as asyncHooks } from './chunks/index-CNR6QRUl.esm.js';
3
+ export { A as AZone, b as ArrayReadForward, D as DecoratorError, c as Destroyable, d as DestructionError, E as Eventful, F as FoolProof, I as Indexable, e as IterableWeakMap, f as IterableWeakSet, R as ReactiveBase, g as ReactiveError, h as ReactiveErrorCode, i as Register, Z as Zone, j as ZoneAggregator, k as ZoneHistory, l as addBatchCleanup, m as allocated, n as allocatedValues, o as arrayEquals, p as asyncZone, q as atomic, r as biDi, s as buildReactivityGraph, t as cache, u as cached, v as callOnGC, w as chainPromise, x as cleanedBy, y as cleanup, z as contentRef, B as debounce, C as decorator, G as deepCompare, H as deepWatch, J as defer, K as deprecated, L as derived, M as describe, N as destructor, O as effect, P as enableDevTools, Q as forwardArray, S as getActivationLog, T as getActiveProjection, U as getAt, V as getState, W as immutables, X as isCached, Y as isConstructor, _ as isDevtoolsEnabled, $ as isNonReactive, a0 as isOwnAccessor, a1 as isReactive, a2 as legacyDecorator, a3 as memoize, a4 as mixin, a5 as modernDecorator, a6 as named, a7 as organize, a8 as organized, a9 as profileInfo, aa as project, ab as reactive, ac as reactiveOptions, ad as register, ae as registerEffectForDebug, af as registerNativeReactivity, ag as registerObjectForDebug, ah as renamed, ai as root, aj as scan, ak as setAt, al as setEffectName, am as setObjectName, an as tag, ao as throttle, ap as touched, aq as touched1, ar as trackEffect, as as unreactive, at as untracked, au as unwrap, av as watch, aw as zip } from './chunks/index-CNR6QRUl.esm.js';
4
+
5
+ const hooks = new Set();
6
+ const restorersPerAsyncId = new Map();
7
+ const undoersPerAsyncId = new Map();
8
+ createHook({
9
+ init(asyncId) {
10
+ const restorers = new Set();
11
+ for (const hook of hooks) {
12
+ restorers.add(hook());
13
+ }
14
+ restorersPerAsyncId.set(asyncId, restorers);
15
+ },
16
+ before(asyncId) {
17
+ const restorers = restorersPerAsyncId.get(asyncId);
18
+ if (restorers) {
19
+ const undoers = new Set();
20
+ for (const restore of restorers) {
21
+ undoers.add(restore());
22
+ }
23
+ undoersPerAsyncId.set(asyncId, undoers);
24
+ }
25
+ },
26
+ after(asyncId) {
27
+ const undoers = undoersPerAsyncId.get(asyncId);
28
+ if (undoers) {
29
+ for (const undo of undoers)
30
+ undo();
31
+ undoersPerAsyncId.delete(asyncId);
32
+ }
33
+ },
34
+ destroy(asyncId) {
35
+ restorersPerAsyncId.delete(asyncId);
36
+ undoersPerAsyncId.delete(asyncId);
37
+ }
38
+ }).enable();
39
+ asyncHooks.addHook = function (hook) {
40
+ hooks.add(hook);
41
+ return () => {
42
+ hooks.delete(hook);
43
+ };
44
+ };
45
+ //# sourceMappingURL=node.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node.esm.js","sources":["../src/async/node.ts"],"sourcesContent":["import { createHook } from 'node:async_hooks'\nimport { Hook, Restorer, asyncHooks } from '.'\n\nconst hooks = new Set<Hook>()\nconst restorersPerAsyncId = new Map<number, Set<Restorer>>()\nconst undoersPerAsyncId = new Map<number, Set<() => void>>()\n\ncreateHook({\n\tinit(asyncId) {\n\t\tconst restorers = new Set<Restorer>()\n\t\tfor (const hook of hooks) {\n\t\t\trestorers.add(hook())\n\t\t}\n\t\trestorersPerAsyncId.set(asyncId, restorers)\n\t},\n\tbefore(asyncId) {\n\t\tconst restorers = restorersPerAsyncId.get(asyncId)\n\t\tif (restorers) {\n\t\t\tconst undoers = new Set<() => void>()\n\t\t\tfor (const restore of restorers) {\n\t\t\t\tundoers.add(restore())\n\t\t\t}\n\t\t\tundoersPerAsyncId.set(asyncId, undoers)\n\t\t}\n\t},\n\tafter(asyncId) {\n\t\tconst undoers = undoersPerAsyncId.get(asyncId)\n\t\tif (undoers) {\n\t\t\tfor (const undo of undoers) undo()\n\t\t\tundoersPerAsyncId.delete(asyncId)\n\t\t}\n\t},\n\tdestroy(asyncId) {\n\t\trestorersPerAsyncId.delete(asyncId)\n\t\tundoersPerAsyncId.delete(asyncId)\n\t}\n}).enable()\n\nasyncHooks.addHook = function (hook: Hook) {\n\thooks.add(hook)\n\treturn () => {\n\t\thooks.delete(hook)\n\t}\n}\n\nexport * from '../index'\n"],"names":[],"mappings":";;;;AAGA,MAAM,KAAK,GAAG,IAAI,GAAG,EAAQ;AAC7B,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAAyB;AAC5D,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAA2B;AAE5D,UAAU,CAAC;AACV,IAAA,IAAI,CAAC,OAAO,EAAA;AACX,QAAA,MAAM,SAAS,GAAG,IAAI,GAAG,EAAY;AACrC,QAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;AACzB,YAAA,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACtB;AACA,QAAA,mBAAmB,CAAC,GAAG,CAAC,OAAO,EAAE,SAAS,CAAC;IAC5C,CAAC;AACD,IAAA,MAAM,CAAC,OAAO,EAAA;QACb,MAAM,SAAS,GAAG,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC;QAClD,IAAI,SAAS,EAAE;AACd,YAAA,MAAM,OAAO,GAAG,IAAI,GAAG,EAAc;AACrC,YAAA,KAAK,MAAM,OAAO,IAAI,SAAS,EAAE;AAChC,gBAAA,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;YACvB;AACA,YAAA,iBAAiB,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC;QACxC;IACD,CAAC;AACD,IAAA,KAAK,CAAC,OAAO,EAAA;QACZ,MAAM,OAAO,GAAG,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC;QAC9C,IAAI,OAAO,EAAE;YACZ,KAAK,MAAM,IAAI,IAAI,OAAO;AAAE,gBAAA,IAAI,EAAE;AAClC,YAAA,iBAAiB,CAAC,MAAM,CAAC,OAAO,CAAC;QAClC;IACD,CAAC;AACD,IAAA,OAAO,CAAC,OAAO,EAAA;AACd,QAAA,mBAAmB,CAAC,MAAM,CAAC,OAAO,CAAC;AACnC,QAAA,iBAAiB,CAAC,MAAM,CAAC,OAAO,CAAC;IAClC;CACA,CAAC,CAAC,MAAM,EAAE;AAEX,UAAU,CAAC,OAAO,GAAG,UAAU,IAAU,EAAA;AACxC,IAAA,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;AACf,IAAA,OAAO,MAAK;AACX,QAAA,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC;AACnB,IAAA,CAAC;AACF,CAAC"}
package/dist/node.js ADDED
@@ -0,0 +1,136 @@
1
+ 'use strict';
2
+
3
+ var node_async_hooks = require('node:async_hooks');
4
+ var index = require('./chunks/index-BFYK02LG.js');
5
+
6
+ const hooks = new Set();
7
+ const restorersPerAsyncId = new Map();
8
+ const undoersPerAsyncId = new Map();
9
+ node_async_hooks.createHook({
10
+ init(asyncId) {
11
+ const restorers = new Set();
12
+ for (const hook of hooks) {
13
+ restorers.add(hook());
14
+ }
15
+ restorersPerAsyncId.set(asyncId, restorers);
16
+ },
17
+ before(asyncId) {
18
+ const restorers = restorersPerAsyncId.get(asyncId);
19
+ if (restorers) {
20
+ const undoers = new Set();
21
+ for (const restore of restorers) {
22
+ undoers.add(restore());
23
+ }
24
+ undoersPerAsyncId.set(asyncId, undoers);
25
+ }
26
+ },
27
+ after(asyncId) {
28
+ const undoers = undoersPerAsyncId.get(asyncId);
29
+ if (undoers) {
30
+ for (const undo of undoers)
31
+ undo();
32
+ undoersPerAsyncId.delete(asyncId);
33
+ }
34
+ },
35
+ destroy(asyncId) {
36
+ restorersPerAsyncId.delete(asyncId);
37
+ undoersPerAsyncId.delete(asyncId);
38
+ }
39
+ }).enable();
40
+ index.asyncHooks.addHook = function (hook) {
41
+ hooks.add(hook);
42
+ return () => {
43
+ hooks.delete(hook);
44
+ };
45
+ };
46
+
47
+ exports.AZone = index.AZone;
48
+ exports.ArrayReadForward = index.ArrayReadForward;
49
+ exports.DecoratorError = index.DecoratorError;
50
+ exports.Destroyable = index.Destroyable;
51
+ exports.DestructionError = index.DestructionError;
52
+ exports.Eventful = index.Eventful;
53
+ exports.FoolProof = index.FoolProof;
54
+ exports.Indexable = index.Indexable;
55
+ exports.IterableWeakMap = index.IterableWeakMap;
56
+ exports.IterableWeakSet = index.IterableWeakSet;
57
+ exports.ReactiveBase = index.ReactiveBase;
58
+ exports.ReactiveError = index.ReactiveError;
59
+ Object.defineProperty(exports, "ReactiveErrorCode", {
60
+ enumerable: true,
61
+ get: function () { return index.ReactiveErrorCode; }
62
+ });
63
+ exports.Register = index.Register;
64
+ exports.Zone = index.Zone;
65
+ exports.ZoneAggregator = index.ZoneAggregator;
66
+ exports.ZoneHistory = index.ZoneHistory;
67
+ exports.addBatchCleanup = index.addBatchCleanup;
68
+ exports.allocated = index.allocated;
69
+ exports.allocatedValues = index.allocatedValues;
70
+ exports.arrayEquals = index.arrayEquals;
71
+ exports.asyncZone = index.asyncZone;
72
+ exports.atomic = index.atomic;
73
+ exports.biDi = index.biDi;
74
+ exports.buildReactivityGraph = index.buildReactivityGraph;
75
+ exports.cache = index.cache;
76
+ exports.cached = index.cached;
77
+ exports.callOnGC = index.callOnGC;
78
+ exports.chainPromise = index.chainPromise;
79
+ exports.cleanedBy = index.cleanedBy;
80
+ exports.cleanup = index.cleanup;
81
+ exports.contentRef = index.contentRef;
82
+ exports.debounce = index.debounce;
83
+ exports.decorator = index.decorator;
84
+ exports.deepCompare = index.deepCompare;
85
+ exports.deepWatch = index.deepWatch;
86
+ exports.defer = index.defer;
87
+ exports.deprecated = index.deprecated;
88
+ exports.derived = index.derived;
89
+ exports.describe = index.describe;
90
+ exports.destructor = index.destructor;
91
+ exports.effect = index.effect;
92
+ exports.enableDevTools = index.enableDevTools;
93
+ exports.forwardArray = index.forwardArray;
94
+ exports.getActivationLog = index.getActivationLog;
95
+ exports.getActiveProjection = index.getActiveProjection;
96
+ exports.getAt = index.getAt;
97
+ exports.getState = index.getState;
98
+ exports.immutables = index.immutables;
99
+ exports.isCached = index.isCached;
100
+ exports.isConstructor = index.isConstructor;
101
+ exports.isDevtoolsEnabled = index.isDevtoolsEnabled;
102
+ exports.isNonReactive = index.isNonReactive;
103
+ exports.isOwnAccessor = index.isOwnAccessor;
104
+ exports.isReactive = index.isReactive;
105
+ exports.legacyDecorator = index.legacyDecorator;
106
+ exports.memoize = index.memoize;
107
+ exports.mixin = index.mixin;
108
+ exports.modernDecorator = index.modernDecorator;
109
+ exports.named = index.named;
110
+ exports.organize = index.organize;
111
+ exports.organized = index.organized;
112
+ exports.profileInfo = index.profileInfo;
113
+ exports.project = index.project;
114
+ exports.reactive = index.reactive;
115
+ exports.reactiveOptions = index.options;
116
+ exports.register = index.register;
117
+ exports.registerEffectForDebug = index.registerEffectForDebug;
118
+ exports.registerNativeReactivity = index.registerNativeReactivity;
119
+ exports.registerObjectForDebug = index.registerObjectForDebug;
120
+ exports.renamed = index.renamed;
121
+ exports.root = index.root;
122
+ exports.scan = index.scan;
123
+ exports.setAt = index.setAt;
124
+ exports.setEffectName = index.setEffectName;
125
+ exports.setObjectName = index.setObjectName;
126
+ exports.tag = index.tag;
127
+ exports.throttle = index.throttle;
128
+ exports.touched = index.touched;
129
+ exports.touched1 = index.touched1;
130
+ exports.trackEffect = index.trackEffect;
131
+ exports.unreactive = index.unreactive;
132
+ exports.untracked = index.untracked;
133
+ exports.unwrap = index.unwrap;
134
+ exports.watch = index.watch;
135
+ exports.zip = index.zip;
136
+ //# sourceMappingURL=node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node.js","sources":["../src/async/node.ts"],"sourcesContent":["import { createHook } from 'node:async_hooks'\nimport { Hook, Restorer, asyncHooks } from '.'\n\nconst hooks = new Set<Hook>()\nconst restorersPerAsyncId = new Map<number, Set<Restorer>>()\nconst undoersPerAsyncId = new Map<number, Set<() => void>>()\n\ncreateHook({\n\tinit(asyncId) {\n\t\tconst restorers = new Set<Restorer>()\n\t\tfor (const hook of hooks) {\n\t\t\trestorers.add(hook())\n\t\t}\n\t\trestorersPerAsyncId.set(asyncId, restorers)\n\t},\n\tbefore(asyncId) {\n\t\tconst restorers = restorersPerAsyncId.get(asyncId)\n\t\tif (restorers) {\n\t\t\tconst undoers = new Set<() => void>()\n\t\t\tfor (const restore of restorers) {\n\t\t\t\tundoers.add(restore())\n\t\t\t}\n\t\t\tundoersPerAsyncId.set(asyncId, undoers)\n\t\t}\n\t},\n\tafter(asyncId) {\n\t\tconst undoers = undoersPerAsyncId.get(asyncId)\n\t\tif (undoers) {\n\t\t\tfor (const undo of undoers) undo()\n\t\t\tundoersPerAsyncId.delete(asyncId)\n\t\t}\n\t},\n\tdestroy(asyncId) {\n\t\trestorersPerAsyncId.delete(asyncId)\n\t\tundoersPerAsyncId.delete(asyncId)\n\t}\n}).enable()\n\nasyncHooks.addHook = function (hook: Hook) {\n\thooks.add(hook)\n\treturn () => {\n\t\thooks.delete(hook)\n\t}\n}\n\nexport * from '../index'\n"],"names":["createHook","asyncHooks"],"mappings":";;;;;AAGA,MAAM,KAAK,GAAG,IAAI,GAAG,EAAQ;AAC7B,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAAyB;AAC5D,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAA2B;AAE5DA,2BAAU,CAAC;AACV,IAAA,IAAI,CAAC,OAAO,EAAA;AACX,QAAA,MAAM,SAAS,GAAG,IAAI,GAAG,EAAY;AACrC,QAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;AACzB,YAAA,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACtB;AACA,QAAA,mBAAmB,CAAC,GAAG,CAAC,OAAO,EAAE,SAAS,CAAC;IAC5C,CAAC;AACD,IAAA,MAAM,CAAC,OAAO,EAAA;QACb,MAAM,SAAS,GAAG,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC;QAClD,IAAI,SAAS,EAAE;AACd,YAAA,MAAM,OAAO,GAAG,IAAI,GAAG,EAAc;AACrC,YAAA,KAAK,MAAM,OAAO,IAAI,SAAS,EAAE;AAChC,gBAAA,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;YACvB;AACA,YAAA,iBAAiB,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC;QACxC;IACD,CAAC;AACD,IAAA,KAAK,CAAC,OAAO,EAAA;QACZ,MAAM,OAAO,GAAG,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC;QAC9C,IAAI,OAAO,EAAE;YACZ,KAAK,MAAM,IAAI,IAAI,OAAO;AAAE,gBAAA,IAAI,EAAE;AAClC,YAAA,iBAAiB,CAAC,MAAM,CAAC,OAAO,CAAC;QAClC;IACD,CAAC;AACD,IAAA,OAAO,CAAC,OAAO,EAAA;AACd,QAAA,mBAAmB,CAAC,MAAM,CAAC,OAAO,CAAC;AACnC,QAAA,iBAAiB,CAAC,MAAM,CAAC,OAAO,CAAC;IAClC;CACA,CAAC,CAAC,MAAM,EAAE;AAEXC,gBAAU,CAAC,OAAO,GAAG,UAAU,IAAU,EAAA;AACxC,IAAA,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;AACf,IAAA,OAAO,MAAK;AACX,QAAA,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC;AACnB,IAAA,CAAC;AACF,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -68,8 +68,6 @@ export interface Register<T, K extends PropertyKey = PropertyKey> extends Iterab
68
68
  }
69
69
 
70
70
  export declare function register<T, K extends PropertyKey = PropertyKey>(keyFn: (item: T) => K, initial?: Iterable<T>): Register<T, K>;
71
- export declare function mapped<T, U>(inputs: readonly T[], compute: (input: T, index: number, output: U[]) => U): readonly U[];
72
- export declare function reduced<T, U, R extends object = any>(inputs: readonly T[], compute: (input: T, factor: R) => readonly U[]): readonly U[];
73
71
  export declare function project<S, R>(source: S, apply: (access: any, target: any) => any): R;
74
72
  export declare function organized<S, T>(source: S, apply: (access: any, target: T) => any, baseTarget?: T): T;
75
73
 
@@ -1161,10 +1161,6 @@ class Example {
1161
1161
  }
1162
1162
  ```
1163
1163
 
1164
- ### Working with `mapped()`
1165
-
1166
- Pair `memoize()` with [`mapped()`](#mapped) to keep derived array elements stable across reorders (see [Identity-preserving mapped arrays](#identity-preserving-mapped-arrays)). Memoizing the mapper ensures each input object is processed at most once and its derived state persists while the input reference lives.
1167
-
1168
1164
  ## Debugging and Development
1169
1165
 
1170
1166
  The `mutts` reactive system includes built-in tools for troubleshooting complex dependency graphs and identifying performance bottlenecks.
@@ -1173,7 +1169,8 @@ For a full guide on debugging, including cycle detection and memoization discrep
1173
1169
 
1174
1170
  ### Quick Summary
1175
1171
 
1176
- - **Cycle Detection**: Automatically catch circular dependencies via `reactiveOptions.cycleHandling`.
1172
+ - **Cycle Detection**: Automatically catch circular dependencies via `reactiveOptions.cycleHandling`. Note: Instant mathematical detection requires choosing a mode other than `'none'`.
1173
+ - **Flat Mode**: The default `reactiveOptions.cycleHandling = 'none'` provides maximum performance in high-frequency update scenarios by disabling graph maintenance.
1177
1174
  - **Memoization Discrepancy**: Detect "missing dependencies" by running computations twice during development using `reactiveOptions.onMemoizationDiscrepancy`.
1178
1175
  - **Global Hooks**: Use `reactiveOptions.touched`, `enter`, and `leave` to observe system activity.
1179
1176
 
@@ -352,115 +352,6 @@ Notes:
352
352
  - Assigning to an index (`list[i] = value`) uses the key function to bind that slot to `value`’s key.
353
353
 
354
354
  ## Class Reactivity
355
- ## Array Mapping
356
-
357
- ### `mapped()`
358
-
359
- Creates a reactive array by mapping over an input array. The mapper receives the current item value, its index, and the previous mapped value for that index.
360
-
361
- ```typescript
362
- import { mapped, reactive } from 'mutts/reactive'
363
-
364
- const input = reactive([1, 2, 3])
365
- const doubles = mapped(input, (value, index, oldValue) => value * 2)
366
-
367
- console.log(doubles) // [2, 4, 6]
368
-
369
- // When input changes, the mapped output updates in place
370
- input.push(4)
371
- console.log(doubles) // [2, 4, 6, 8]
372
- ```
373
-
374
- **Mapper signature:**
375
-
376
- ```typescript
377
- (value: T, index: number, oldValue?: U) => U
378
- ```
379
-
380
- - **value**: current element from the input array
381
- - **index**: current element index
382
- - **oldValue**: previously computed value at the same index (useful for incremental updates)
383
-
384
- **Key features:**
385
-
386
- - **Live reactivity**: Output array updates when the input array changes (push/pop/splice/assignments).
387
- - **Granular recompute**: Only indices that change are recomputed; `oldValue` enables incremental updates.
388
- - **Simple contract**: Mapper works directly with `(value, index, oldValue)` and can freely return reactive objects.
389
-
390
- **Performance characteristics:**
391
-
392
- ```typescript
393
- const users = reactive([
394
- { name: 'John', age: 30 },
395
- { name: 'Jane', age: 25 }
396
- ])
397
-
398
- let computeCount = 0
399
- const processedUsers = mapped(users, (user) => {
400
- computeCount++
401
- return `${user.name} (${user.age})`
402
- })
403
-
404
- console.log(computeCount) // 2 (initial computation)
405
-
406
- // Modify one user - only that index recomputes
407
- users[0].age = 31
408
- console.log(processedUsers[0]) // "John (31)"
409
- console.log(computeCount) // 3
410
- ```
411
-
412
- **Advanced usage:**
413
-
414
- ```typescript
415
- const orders = reactive([
416
- { items: [{ price: 10 }, { price: 20 }] },
417
- { items: [{ price: 15 }] }
418
- ])
419
-
420
- const orderTotals = mapped(orders, (order) => (
421
- order.items.reduce((sum, item) => sum + item.price, 0)
422
- ))
423
- ```
424
-
425
- ### Identity-preserving mapped arrays
426
-
427
- Combine `mapped()` with [`memoize()`](#memoize) when you need to reuse mapped results for the same input identity. The memoized mapper runs at most once per input object, even when the source array is reordered, and it can host additional reactive state that should survive reordering.
428
-
429
- ```typescript
430
- import { effect, mapped, memoize, reactive } from 'mutts/reactive'
431
-
432
- const inputs = reactive([{ name: 'John' }, { name: 'Jane' }])
433
-
434
- const memoizedCard = memoize((user: { name: string }) => {
435
- const view: { name?: string; setName(next: string): void } = {
436
- setName(next) {
437
- user.name = next
438
- },
439
- }
440
-
441
- effect(() => {
442
- view.name = user.name.toUpperCase()
443
- })
444
-
445
- return view
446
- })
447
-
448
- const cards = mapped(inputs, (user) => memoizedCard(user))
449
-
450
- cards[0].setName('Johnny')
451
- console.log(cards[0].name) // 'JOHNNY'
452
-
453
- // Reorder: cached output follows the original object
454
- const first = inputs.shift()!
455
- inputs.push(first)
456
- console.log(cards[1].name) // still 'JOHNNY'
457
- ```
458
-
459
- Use this pattern when:
460
-
461
- - You are mapping an array of reactive objects and want to keep derived objects stable across reorders.
462
- - The mapper returns objects with internal state or nested effects that should survive reordering.
463
- - You prefer to share memoized helpers across multiple mapped arrays.
464
355
 
465
356
  ## Projection
466
357
 
@@ -468,8 +359,6 @@ Use this pattern when:
468
359
 
469
360
  `project()` provides a unified API for transforming reactive collections (arrays, records, and maps) into new reactive collections. Each source entry gets its own reactive effect that recomputes only when that specific entry changes, enabling granular updates perfect for rendering pipelines.
470
361
 
471
- **Note:** `project()` is the modern replacement for `mapped()`. It offers the same per-entry reactivity benefits but works across all collection types with a consistent API.
472
-
473
362
  #### Basic Usage
474
363
 
475
364
  ```typescript
@@ -617,23 +506,10 @@ result[cleanup]() // Stops all effects and cleans up
617
506
  - **Data Transformation**: Convert between collection types while maintaining reactivity
618
507
  - **Performance Optimization**: Avoid full recomputation when only a few entries change
619
508
 
620
- #### Comparison with `mapped()`
621
-
622
- `project()` is designed to eventually replace `mapped()`. Key differences:
623
-
624
- - **Unified API**: Works with arrays, records, and maps (vs. `mapped()` only for arrays)
625
- - **Access Pattern**: Uses an access object with `get()`/`set()` instead of direct value/index parameters
626
- - **Automatic Target Creation**: Creates its own reactive target container (no need to provide a base target)
627
- - **Consistent Behavior**: Same per-entry reactivity model across all collection types
628
-
629
- For new code, prefer `project()` over `mapped()`. Existing `mapped()` code will continue to work, but consider migrating for better consistency and future features.
630
-
631
509
  ## Record Organization
632
510
 
633
511
  ### `organized()`
634
512
 
635
- `organized()` is the record companion to [`mapped()`](#mapped). Instead of iterating over numeric indices, it reacts to property additions, updates, and deletions on any `Record<PropertyKey, T>` (plain objects, dictionaries, even reactive proxies) and lets you build **whatever target structure you need**—a new record, nested buckets, a `Map`, or a more elaborate object with metadata.
636
-
637
513
  ```typescript
638
514
  import { cleanup, organized, reactive } from 'mutts/reactive'
639
515
 
@@ -677,7 +553,6 @@ function organized<
677
553
 
678
554
  Under the hood there is:
679
555
 
680
- - One effect watching `Reflect.ownKeys(source)` (similar to how `mapped()` tracks `length`)
681
556
  - A child effect per key that re-runs whenever that key’s value changes, automatically reusing and replacing the cleanup you returned.
682
557
  - Automatic disposal when keys disappear or when `target[cleanup]()` is invoked.
683
558
 
@@ -105,7 +105,7 @@ const result = memoized(user)
105
105
  **5. Map over arrays:**
106
106
  ```typescript
107
107
  const source = reactive([1, 2, 3])
108
- const doubled = mapped(source, x => x * 2)
108
+ const doubled = project(source, ({ value }) => value * 2)
109
109
  // [2, 4, 6]
110
110
 
111
111
  source.push(4) // doubled automatically becomes [2, 4, 6, 8]
@@ -446,13 +446,13 @@ state.c = 15 // Does NOT trigger effect
446
446
 
447
447
  ### Async Effects and the `access` Parameter
448
448
 
449
- The `effect` function provides a special `access` parameter with `tracked` and `ascend` functions that restore the active effect context for dependency tracking in asynchronous operations. This is crucial because async functions lose the global active effect context when they yield control.
449
+ The `effect` function provides a special `access` parameter with `tracked` and `ascend` functions that restore the active effect context for dependency tracking in asynchronous operations.
450
450
 
451
- #### The Problem with Async Effects
451
+ In modern `mutts`, this is powered by the **Zone system**. When you use `configureAsyncZone()`, the active effect context is automatically preserved across `await` points and timers, making manual use of `tracked` optional for these cases.
452
452
 
453
- When an effect function is synchronous, reactive property access automatically tracks dependencies, however, in async functions, the active effect context is lost when the function yields control.
453
+ #### The Problem with Async Effects
454
454
 
455
- The `access.tracked()` function restores the active effect context for dependency tracking.
455
+ Traditionally, in JavaScript, async functions lose their context when they yield control.
456
456
 
457
457
  #### Understanding the active effect context
458
458
 
@@ -463,37 +463,42 @@ The reactive system uses a global active effect variable to track which effect i
463
463
  effect(() => {
464
464
  // active effect = this effect
465
465
  const value = state.count // ✅ Tracked (active effect is set)
466
- // active effect = this effect (still set)
467
466
  const another = state.name // ✅ Tracked (active effect is still set)
468
467
  })
469
468
 
470
- // Async effect - active effect is lost after await
469
+ // Async effect WITHOUT configureAsyncZone() - context is lost after await
471
470
  effect(async () => {
472
- // active effect = this effect
473
- const value = state.count // ✅ Tracked (active effect is set)
471
+ const value = state.count // ✅ Tracked
474
472
 
475
- await someAsyncOperation() // Function exits, active effect = undefined
473
+ await someAsyncOperation()
476
474
 
477
- // active effect = undefined (lost!)
478
- const another = state.name // ❌ NOT tracked (no active effect)
475
+ // context is lost!
476
+ const another = state.name // ❌ NOT tracked
479
477
  })
480
478
 
481
- // Async effect with access.tracked() - active effect is restored
482
- effect(async ({ tracked }) => {
483
- // active effect = this effect
484
- const value = state.count // ✅ Tracked (active effect is set)
479
+ // Async effect WITH configureAsyncZone() - context is preserved
480
+ effect(async () => {
481
+ const value = state.count // ✅ Tracked
482
+
483
+ await someAsyncOperation()
485
484
 
486
- await someAsyncOperation() // Function exits, active effect = undefined
485
+ // context is automatically restored!
486
+ const another = state.name // ✅ Tracked
487
+ })
488
+
489
+ // Using access.tracked() for manual restoration
490
+ effect(async ({ tracked }) => {
491
+ await someAsyncOperation()
487
492
 
488
- // tracked() temporarily restores active effect for the callback
489
- const another = tracked(() => state.name) // ✅ Tracked (active effect restored)
493
+ // Useful for non-patched APIs or explicit scoping
494
+ const another = tracked(() => state.name) // ✅ Tracked
490
495
  })
491
496
  ```
492
497
 
493
- #### Key Benefits of `access.tracked()` in Async Effects
498
+ #### Key Benefits of the Zone System
494
499
 
495
- 1. **Restored Context**: `access.tracked()` temporarily restores the active effect context for dependency tracking
496
- 2. **Consistent Tracking**: Reactive property access works the same way before and after `await`
500
+ 1. **Automatic Restoration**: With `configureAsyncZone()`, most native async APIs (Promises, timers) automatically preserve the reactive context.
501
+ 2. **Manual Control**: `access.tracked()` allows you to manually "passport" the context into third-party libraries or unmanaged callbacks.
497
502
 
498
503
  ### Using `ascend` for Parent Effect Tracking
499
504
 
@@ -518,8 +523,6 @@ effect(({ ascend }) => {
518
523
  }
519
524
  })
520
525
  ```
521
- <|tool▁calls▁begin|><|tool▁call▁begin|>
522
- grep
523
526
 
524
527
  **When to use `ascend`:**
525
528
  - When creating child effects that should be cleaned up with their parent
@@ -25,7 +25,7 @@ These hooks are called during the execution of effects and computed values.
25
25
 
26
26
  - **`beginChain(targets: Function[]) / endChain()`**: Called when a batch of effects starts and ends its execution.
27
27
  - **`maxEffectChain`**: (Default: `100`) Limits the depth of synchronous effect triggering to prevent stack overflows.
28
- - **`maxTriggerPerBatch`**: (Default: `10`) Limits how many times a single effect can be triggered within the same batch. Useful for detecting aggressive re-computation.
28
+ - **`maxTriggerPerBatch`**: (Default: `10`) Limits how many times a single effect can be triggered within the same batch. Useful for detecting aggressive re-computation or infinite cycles in `cycleHandling: 'none'` mode.
29
29
 
30
30
  ## Cycle Detection
31
31
 
@@ -35,11 +35,21 @@ These hooks are called during the execution of effects and computed values.
35
35
 
36
36
  You can control how cycles are handled via `reactiveOptions.cycleHandling`:
37
37
 
38
- - **`'throw'`** (Default): Throws a `ReactiveError` with a detailed path.
38
+ - **`'none'`** (Default): High-performance FIFO mode. Disables the dependency graph and topological sorting.
39
+ - **`'throw'`**: Throws a `ReactiveError` with a detailed path.
39
40
  - **`'warn'`**: Logs a warning but breaks the cycle to allow the application to continue.
40
41
  - **`'break'`**: Silently breaks the cycle.
41
42
  - **`'strict'`**: Performs a graph check *before* execution to prevent cycles from even starting. This has the highest overhead.
42
43
 
44
+ ### Topological vs. Flat Mode Detection
45
+
46
+ | Mode | `cycleHandling` | Detection Method | Error Code |
47
+ | :--- | :--- | :--- | :--- |
48
+ | **Topological** | `'throw'` (or other) | **Mathematical**: Analyzes the dependency graph. | `CYCLE_DETECTED` |
49
+ | **Flat Mode** | `'none'` (Default) | **Heuristic**: Counts executions per batch. | `MAX_REACTION_EXCEEDED` |
50
+
51
+ In **Topological mode**, the system maintains a transitive closure of all effects, allowing it to know instantly if an effect is its own cause. In **Flat mode**, the system is "blind" to the graph and relies on the execution threshold (`maxTriggerPerBatch`) to interrupt infinite loops.
52
+
43
53
  ## Memoization Discrepancy Detection
44
54
 
45
55
  The most powerful debugging tool in `mutts` is the **Discrepancy Detector**. It helps identify "missing dependencies"—reactive values used inside a computation that the system isn't tracking.
@@ -12,7 +12,7 @@
12
12
 
13
13
  - `memoize` caches results but invalidates on `Map.set`, so large effects still re-run.
14
14
  - `organized` (designed for `Record` sources) creates per-key effects so downstream work reruns only for the touched key; this matches the desired behaviour.
15
- - **Gap:** `organized` operates on plain objects: key enumeration relies on property iteration and `ReflectGet/Set`. Registers and other keyed collections (`Map`, `Register`, custom stores) need the same per-entry orchestration without converting to records.
15
+ - **Gap:** `organized` operates on plain objects: key enumeration relies on property iteration and `FoolProof.get/set`. Registers and other keyed collections (`Map`, `Register`, custom stores) need the same per-entry orchestration without converting to records.
16
16
 
17
17
  ### Completed Evolution: `project` Implementation
18
18
 
@@ -0,0 +1,78 @@
1
+ # Reactive Scan
2
+
3
+ The `scan` function perform a reactive accumulation over an array of items. Unlike a standard `Array.reduce`, it is designed to be highly efficient in a reactive system, particularly when items are moved or changed, by returning a reactive array of all intermediate results.
4
+
5
+ ## Overview
6
+
7
+ In a typical reactive system, calling `array.reduce(...)` inside an `effect` means the entire reduction re-runs every time the array structure or a single item changes.
8
+
9
+ Reactive `scan` solves this by maintaining a chain of **reactive intermediates**. Each item in the source array is linked to an intermediate that depends on the *previous* intermediate's result.
10
+
11
+ ## Key Features
12
+
13
+ - **Fine-Grained Reactivity**: Changing a property on an item only re-computes the accumulated value for that item and its successors.
14
+ - **Move Optimization**: If a subsequence of items moves together (e.g., sorting or splicing), their intermediates are reused. As long as an item's predecessor in the array hasn't changed, its accumulated value is hit from the cache.
15
+ - **Duplicate Support**: Correctly handles multiple occurrences of the same object instance.
16
+ - **Memory Safety**: Uses `WeakMap` for intermediate storage, ensuring data is cleared when source items are garbage collected.
17
+ - **Granular Sync**: Uses per-index effects to sync results, preventing broad dependency tracking of the source array in every calculation.
18
+
19
+ ## Basic Usage
20
+
21
+ ```typescript
22
+ import { reactive, scan } from 'mutts/reactive'
23
+
24
+ const source = reactive([
25
+ { id: 'A', val: 1 },
26
+ { id: 'B', val: 2 },
27
+ { id: 'C', val: 3 },
28
+ ])
29
+
30
+ // result is a reactive array: [1, 3, 6]
31
+ const result = scan(source, (acc, item) => acc + item.val, 0)
32
+
33
+ // Updating an item only re-computes for that position and successors
34
+ source[1].val = 10
35
+ // result stays [1, 11, 14]
36
+ ```
37
+
38
+ ## How it Works
39
+
40
+ The implementation consists of:
41
+ 1. **A Main Effect**: Tracks the structure of the source array (length and item identities). It manages a list of `Intermediate` objects and stays updated on their `prev` links.
42
+ 2. **Intermediates**: Class instances that link `val` and `prev`. They expose an `acc` getter decorated with `@memoize`.
43
+ 3. **Index Sync Effects**: Granular effects (one per result index) that subscribe to `indexToIntermediate[i].acc`.
44
+
45
+ This "Project-like" architecture ensures that the main loop only does structural work, while the actual logic propagation is handled by the dependency chain of the intermediates.
46
+
47
+ ## API Reference
48
+
49
+ ```typescript
50
+ function scan<Input extends object, Output>(
51
+ source: readonly Input[],
52
+ callback: (acc: Output, val: Input) => Output,
53
+ initialValue: Output
54
+ ): ScanResult<Output>
55
+ ```
56
+
57
+ ### Parameters
58
+ - `source`: The source array. All items must be objects (WeakKeys) to enable intermediate caching.
59
+ - `callback`: The accumulator function `(acc, val) => nextAcc`.
60
+ - `initialValue`: The value used as the accumulator for the first item.
61
+
62
+ ### Returns
63
+ A reactive array of accumulated values. It includes a `[cleanup]` symbol that should be called to stop the reactive tracking.
64
+
65
+ ```typescript
66
+ import { cleanup } from 'mutts/reactive'
67
+ // ...
68
+ result[cleanup]()
69
+ ```
70
+
71
+ ## Performance Comparison
72
+
73
+ | Operation | Standard `Array.reduce` in `effect` | Reactive `scan` |
74
+ | :--- | :--- | :--- |
75
+ | **Initial Run** | O(N) calls | O(N) calls |
76
+ | **Modify Item at `i`** | O(N) calls (entire reduction) | O(N-i) calls |
77
+ | **Append Item** | O(N+1) calls | 1 call |
78
+ | **Move Item** | O(N) calls | O(affected chain) |
package/docs/reactive.md CHANGED
@@ -11,7 +11,8 @@ The Mutts Reactive System documentation has been split into focused sections for
11
11
  * **[Reactive Collections](./reactive/collections.md#collections)**: Map, Set, WeakMap, WeakSet
12
12
  * **[Reactive Arrays](./reactive/collections.md#reactivearray)**: Full array method support
13
13
  * **[Register](./reactive/collections.md#register)**: ID-keyed ordered collections
14
- * **[Projections](./reactive/collections.md#projection)**: `project`, `mapped`, `organized`
14
+ * **[Projections](./reactive/collections.md#projection)**: `project`, `organized`
15
+ * **[Scan](./reactive/scan.md)**: Reactive scan and accumulation
15
16
 
16
17
  ## [Advanced Topics](./reactive/advanced.md)
17
18
  * **[Atomic Operations](./reactive/advanced.md#atomic-operations)**: Batching and Bidirectional binding
@@ -1,3 +1,4 @@
1
+ TODO: redo the doc here
1
2
  # Standard decorators
2
3
 
3
4
  A TypeScript library that provides standard decorators that should stop being re-implemented for the 50th time