mutts 1.0.11 → 1.0.13

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 (59) hide show
  1. package/README.md +5 -2
  2. package/dist/browser.cjs +237 -2596
  3. package/dist/browser.cjs.map +1 -1
  4. package/dist/browser.d.ts +1407 -2
  5. package/dist/browser.dev.cjs +44 -43
  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 +3 -3
  10. package/dist/chunks/index-CAdnMJev.cjs +2735 -0
  11. package/dist/chunks/index-CAdnMJev.cjs.map +1 -0
  12. package/dist/chunks/{index-Sf74wXTV.esm.js → index-XsYTUhHx.esm.js} +200 -77
  13. package/dist/chunks/index-XsYTUhHx.esm.js.map +1 -0
  14. package/dist/chunks/{async-node-3PrbVAbB.cjs → node-DrrphEPf.cjs} +4 -4
  15. package/dist/chunks/node-DrrphEPf.cjs.map +1 -0
  16. package/dist/chunks/{node-Bo7WU5S2.esm.js → node-NEZvVo4M.esm.js} +2 -2
  17. package/dist/chunks/{node-Bo7WU5S2.esm.js.map → node-NEZvVo4M.esm.js.map} +1 -1
  18. package/dist/chunks/{proxy-D2C49sXH.esm.js → proxy-BtmPFjSr.esm.js} +307 -66
  19. package/dist/chunks/proxy-BtmPFjSr.esm.js.map +1 -0
  20. package/dist/chunks/{proxy-Cc79Lrzj.cjs → proxy-DBHj3kGK.cjs} +341 -70
  21. package/dist/chunks/proxy-DBHj3kGK.cjs.map +1 -0
  22. package/dist/debug.cjs +537 -167
  23. package/dist/debug.cjs.map +1 -1
  24. package/dist/debug.d.ts +96 -80
  25. package/dist/debug.esm.js +533 -166
  26. package/dist/debug.esm.js.map +1 -1
  27. package/dist/devtools/panel.js.map +1 -1
  28. package/dist/mutts.umd.js +508 -140
  29. package/dist/mutts.umd.js.map +1 -1
  30. package/dist/mutts.umd.min.js +1 -1
  31. package/dist/mutts.umd.min.js.map +1 -1
  32. package/dist/node.cjs +44 -42
  33. package/dist/node.cjs.map +1 -1
  34. package/dist/node.d.ts +2 -2
  35. package/dist/node.dev.cjs +44 -42
  36. package/dist/node.dev.cjs.map +1 -1
  37. package/dist/node.dev.d.ts +2 -2
  38. package/dist/node.dev.esm.js +3 -3
  39. package/dist/node.esm.js +3 -3
  40. package/dist/{types-Bx2PhORg.d.ts → types.d.ts} +12 -0
  41. package/docs/ai/api-reference.md +102 -12
  42. package/docs/ai/manual.md +60 -24
  43. package/docs/debug-getReason.md +161 -0
  44. package/docs/flavored.md +98 -1
  45. package/docs/reactive/advanced.md +15 -2
  46. package/docs/reactive/attend.md +32 -0
  47. package/docs/reactive/core.md +40 -6
  48. package/docs/reactive/debugging.md +25 -2
  49. package/docs/reactive.md +2 -0
  50. package/package.json +2 -3
  51. package/dist/chunks/async-browser-Dgr5CreQ.cjs +0 -218
  52. package/dist/chunks/async-browser-Dgr5CreQ.cjs.map +0 -1
  53. package/dist/chunks/async-core-CRLKP3l-.cjs +0 -29
  54. package/dist/chunks/async-core-CRLKP3l-.cjs.map +0 -1
  55. package/dist/chunks/async-node-3PrbVAbB.cjs.map +0 -1
  56. package/dist/chunks/index-Sf74wXTV.esm.js.map +0 -1
  57. package/dist/chunks/proxy-Cc79Lrzj.cjs.map +0 -1
  58. package/dist/chunks/proxy-D2C49sXH.esm.js.map +0 -1
  59. package/dist/index.d.ts +0 -1322
@@ -0,0 +1,2735 @@
1
+ 'use strict';
2
+
3
+ var proxy = require('./proxy-DBHj3kGK.cjs');
4
+
5
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
6
+ // Integrated with `using` statement via Symbol.dispose
7
+ const fr = new FinalizationRegistry((f) => f());
8
+ /**
9
+ * Symbol for marking destructor methods
10
+ */
11
+ const destructor = Symbol('destructor');
12
+ /**
13
+ * Symbol for accessing allocated values in destroyable objects
14
+ */
15
+ const allocatedValues = Symbol('allocated');
16
+ /**
17
+ * Error thrown when attempting to access a destroyed object
18
+ */
19
+ class DestructionError extends Error {
20
+ static throw(msg) {
21
+ return () => {
22
+ throw new DestructionError(msg);
23
+ };
24
+ }
25
+ constructor(msg) {
26
+ super(`Object is destroyed. ${msg}`);
27
+ this.name = 'DestroyedAccessError';
28
+ }
29
+ }
30
+ const destroyedHandler = {
31
+ [Symbol.toStringTag]: 'MutTs Destroyable',
32
+ get: DestructionError.throw('Cannot access destroyed object'),
33
+ set: DestructionError.throw('Cannot access destroyed object'),
34
+ };
35
+ function Destroyable(base, destructorObj) {
36
+ var _a;
37
+ if (base && typeof base !== 'function') {
38
+ destructorObj = base;
39
+ base = undefined;
40
+ }
41
+ if (!base) {
42
+ base = class {
43
+ };
44
+ }
45
+ return _a = class Destroyable extends base {
46
+ static destroy(obj) {
47
+ const destructor = _a.destructors.get(obj);
48
+ if (!destructor)
49
+ return false;
50
+ fr.unregister(obj[allocatedValues]);
51
+ _a.destructors.delete(obj);
52
+ Object.setPrototypeOf(obj, new Proxy({}, destroyedHandler));
53
+ // Clear all own properties
54
+ for (const key of Object.getOwnPropertyNames(obj)) {
55
+ delete obj[key];
56
+ }
57
+ destructor();
58
+ return true;
59
+ }
60
+ static isDestroyable(obj) {
61
+ return _a.destructors.has(obj);
62
+ }
63
+ constructor(...args) {
64
+ super(...args);
65
+ const allocated = {};
66
+ this[allocatedValues] = allocated;
67
+ // @ts-expect-error `this` is an AbstractDestroyable
68
+ const myDestructor = destructorObj?.destructor ?? this[destructor];
69
+ if (!myDestructor) {
70
+ throw new DestructionError('Destructor is not defined');
71
+ }
72
+ function destruction() {
73
+ myDestructor(allocated);
74
+ }
75
+ _a.destructors.set(this, destruction);
76
+ fr.register(this, destruction, allocated);
77
+ }
78
+ },
79
+ _a.destructors = new WeakMap(),
80
+ _a;
81
+ }
82
+ /**
83
+ * Decorator that marks properties to be stored in the allocated object and passed to the destructor
84
+ * Use with accessor properties or explicit get/set pairs
85
+ */
86
+ const allocated = proxy.decorator({
87
+ setter(original, _target, propertyKey) {
88
+ return function (value) {
89
+ this[allocatedValues][propertyKey] = value;
90
+ return original.call(this, value);
91
+ };
92
+ },
93
+ });
94
+ /**
95
+ * Registers a callback to be called when an object is garbage collected
96
+ * @param cb - The callback function to execute on garbage collection
97
+ * @returns The object whose reference can be collected
98
+ */
99
+ function callOnGC(cb) {
100
+ let called = false;
101
+ const forward = () => {
102
+ if (called)
103
+ return;
104
+ called = true;
105
+ cb();
106
+ };
107
+ fr.register(forward, cb, cb);
108
+ return forward;
109
+ }
110
+
111
+ /** Max edit distance before bailing out to a single "replace all" patch */
112
+ const BAILOUT_D = 256;
113
+ /**
114
+ * Myers' diff producing grouped patches: `{indexA, indexB, sliceA, sliceB}[]`.
115
+ * - O(N) for identical or prefix/suffix-only differences
116
+ * - O(ND) for small D, with a hard bailout at D=BAILOUT_D → single replacement patch
117
+ */
118
+ function arrayDiff(A, B) {
119
+ let start = 0;
120
+ let endA = A.length;
121
+ let endB = B.length;
122
+ // Trim common prefix
123
+ while (start < endA && start < endB && A[start] === B[start])
124
+ start++;
125
+ // Trim common suffix
126
+ while (endA > start && endB > start && A[endA - 1] === B[endB - 1]) {
127
+ endA--;
128
+ endB--;
129
+ }
130
+ const lenA = endA - start;
131
+ const lenB = endB - start;
132
+ if (lenA === 0 && lenB === 0)
133
+ return [];
134
+ if (lenA === 0)
135
+ return [{ indexA: start, indexB: start, sliceA: [], sliceB: B.slice(start, endB) }];
136
+ if (lenB === 0)
137
+ return [{ indexA: start, indexB: start, sliceA: A.slice(start, endA), sliceB: [] }];
138
+ // Myers with bailout
139
+ const maxD = Math.min(lenA + lenB, BAILOUT_D);
140
+ const vSize = 2 * maxD + 1;
141
+ const vOffset = maxD;
142
+ const V = new Int32Array(vSize);
143
+ V[vOffset + 1] = 0;
144
+ const history = [];
145
+ for (let d = 0; d <= maxD; d++) {
146
+ for (let k = -d; k <= d; k += 2) {
147
+ let x;
148
+ if (k === -d || (k !== d && V[vOffset + k - 1] < V[vOffset + k + 1])) {
149
+ x = V[vOffset + k + 1];
150
+ }
151
+ else {
152
+ x = V[vOffset + k - 1] + 1;
153
+ }
154
+ let y = x - k;
155
+ while (x < lenA && y < lenB && A[start + x] === B[start + y]) {
156
+ x++;
157
+ y++;
158
+ }
159
+ V[vOffset + k] = x;
160
+ if (x >= lenA && y >= lenB)
161
+ return buildPatches(history, A, B, start, x, y, d, k, vOffset);
162
+ }
163
+ history.push(new Int32Array(V));
164
+ }
165
+ // Bailout: too many differences
166
+ return [
167
+ { indexA: start, indexB: start, sliceA: A.slice(start, endA), sliceB: B.slice(start, endB) },
168
+ ];
169
+ }
170
+ function buildPatches(history, A, B, offset, finalX, finalY, finalD, finalK, vOffset) {
171
+ // Backtrack from (finalX, finalY) at step finalD to step 0, collecting ops in reverse
172
+ const ops = []; // 0=eq, 1=ins, 2=del
173
+ let x = finalX;
174
+ let y = finalY;
175
+ let k = finalK;
176
+ for (let d = finalD; d > 0; d--) {
177
+ const prev = history[d - 1];
178
+ let prevK;
179
+ let down;
180
+ if (k === -d) {
181
+ prevK = k + 1;
182
+ down = true;
183
+ }
184
+ else if (k === d) {
185
+ prevK = k - 1;
186
+ down = false;
187
+ }
188
+ else if (prev[vOffset + k - 1] < prev[vOffset + k + 1]) {
189
+ prevK = k + 1;
190
+ down = true;
191
+ }
192
+ else {
193
+ prevK = k - 1;
194
+ down = false;
195
+ }
196
+ const prevXEnd = prev[vOffset + prevK];
197
+ const prevYEnd = prevXEnd - prevK;
198
+ const xStart = down ? prevXEnd : prevXEnd + 1;
199
+ const yStart = down ? prevYEnd + 1 : prevXEnd + 1 - k;
200
+ // Diagonal matches (pushed in reverse)
201
+ while (x > xStart && y > yStart) {
202
+ ops.push(0);
203
+ x--;
204
+ y--;
205
+ }
206
+ // The edit step
207
+ if (down) {
208
+ ops.push(1); // ins
209
+ y--;
210
+ }
211
+ else {
212
+ ops.push(2); // del
213
+ x--;
214
+ }
215
+ k = prevK;
216
+ }
217
+ // Walk ops forward (they were pushed in reverse), grouping contiguous edits
218
+ const patches = [];
219
+ let currA = offset;
220
+ let currB = offset;
221
+ let sliceA = [];
222
+ let sliceB = [];
223
+ let patchA = -1;
224
+ let patchB = -1;
225
+ const flush = () => {
226
+ if (patchA !== -1) {
227
+ patches.push({ indexA: patchA, indexB: patchB, sliceA, sliceB });
228
+ sliceA = [];
229
+ sliceB = [];
230
+ patchA = -1;
231
+ }
232
+ };
233
+ for (let i = ops.length - 1; i >= 0; i--) {
234
+ const op = ops[i];
235
+ if (op === 0) {
236
+ flush();
237
+ currA++;
238
+ currB++;
239
+ }
240
+ else if (op === 1) {
241
+ if (patchA === -1) {
242
+ patchA = currA;
243
+ patchB = currB;
244
+ }
245
+ sliceB.push(B[currB++]);
246
+ }
247
+ else {
248
+ if (patchA === -1) {
249
+ patchA = currA;
250
+ patchB = currB;
251
+ }
252
+ sliceA.push(A[currA++]);
253
+ }
254
+ }
255
+ flush();
256
+ return patches;
257
+ }
258
+
259
+ var _a, _b;
260
+ const events = Symbol('events');
261
+ const hooks = Symbol('hooks');
262
+ function getEventMap(target) {
263
+ return target[events];
264
+ }
265
+ function getHookSet(target) {
266
+ return target[hooks];
267
+ }
268
+ const eventBehavior = {
269
+ on(eventOrEvents, cb) {
270
+ const self = this;
271
+ const eventMap = getEventMap(self);
272
+ if (typeof eventOrEvents === 'object') {
273
+ for (const e of Object.keys(eventOrEvents)) {
274
+ this.on(e, eventOrEvents[e]);
275
+ }
276
+ }
277
+ else if (cb !== undefined) {
278
+ const callbacks = eventMap.get(eventOrEvents) ?? new Set();
279
+ if (!callbacks.has(cb))
280
+ callbacks.add(cb);
281
+ eventMap.set(eventOrEvents, callbacks);
282
+ }
283
+ return () => this.off(eventOrEvents, cb);
284
+ },
285
+ off(eventOrEvents, cb) {
286
+ const self = this;
287
+ const eventMap = getEventMap(self);
288
+ if (typeof eventOrEvents === 'object') {
289
+ for (const e of Object.keys(eventOrEvents)) {
290
+ this.off(e, eventOrEvents[e]);
291
+ }
292
+ }
293
+ else if (cb !== null && cb !== undefined) {
294
+ const callbacks = eventMap.get(eventOrEvents);
295
+ if (callbacks) {
296
+ callbacks.delete(cb);
297
+ if (!callbacks.size)
298
+ eventMap.delete(eventOrEvents);
299
+ }
300
+ }
301
+ else {
302
+ // Remove all listeners for this event
303
+ eventMap.delete(eventOrEvents);
304
+ }
305
+ },
306
+ emit(event, ...args) {
307
+ const self = this;
308
+ const callbacks = getEventMap(self).get(event);
309
+ if (callbacks)
310
+ for (const cb of callbacks)
311
+ cb.apply(this, args);
312
+ for (const cb of getHookSet(self))
313
+ cb.call(this, event, ...args);
314
+ },
315
+ };
316
+ function perEvent(eventful, fct, use) {
317
+ const cache = new Map();
318
+ return new Proxy(fct, {
319
+ get(target, prop) {
320
+ if (typeof prop !== 'string')
321
+ return target[prop];
322
+ if (use && !getEventMap(eventful).has(prop) && !getHookSet(eventful).size)
323
+ return () => { };
324
+ // Return cached function or create and cache
325
+ let cached = cache.get(prop);
326
+ if (!cached) {
327
+ cached = (...args) => fct.apply(eventful, [prop, ...args]);
328
+ cache.set(prop, cached);
329
+ }
330
+ return cached;
331
+ },
332
+ });
333
+ }
334
+ /**
335
+ * A type-safe event system that provides a clean API for event handling
336
+ * @template Events - The event map defining event names and their handler signatures
337
+ */
338
+ class Eventful {
339
+ constructor() {
340
+ this[_a] = new Map();
341
+ this[_b] = new Set();
342
+ this.on = perEvent(this, eventBehavior.on);
343
+ this.off = perEvent(this, eventBehavior.off);
344
+ this.emit = perEvent(this, eventBehavior.emit, 'use');
345
+ }
346
+ hook(cb) {
347
+ this[hooks].add(cb);
348
+ return () => {
349
+ this[hooks].delete(cb);
350
+ };
351
+ }
352
+ }
353
+ _a = events, _b = hooks;
354
+
355
+ /**
356
+ * Symbol for defining custom getter logic for numeric index access
357
+ */
358
+ const getAt = Symbol('getAt');
359
+ /**
360
+ * Symbol for defining custom setter logic for numeric index access
361
+ */
362
+ const setAt = Symbol('setAt');
363
+ function Indexable(base, accessor) {
364
+ if (base && typeof base !== 'function') {
365
+ accessor = base;
366
+ base = undefined;
367
+ }
368
+ if (!base) {
369
+ //@ts-expect-error
370
+ base = class {
371
+ };
372
+ }
373
+ if (!accessor) {
374
+ accessor = {
375
+ get(index) {
376
+ if (typeof this[getAt] !== 'function') {
377
+ throw new Error('Indexable class must have an [getAt] method');
378
+ }
379
+ return this[getAt](index);
380
+ },
381
+ set(index, value) {
382
+ if (typeof this[setAt] !== 'function') {
383
+ throw new Error('Indexable class has read-only numeric index access');
384
+ }
385
+ this[setAt](index, value);
386
+ },
387
+ };
388
+ }
389
+ class Indexable extends base {
390
+ }
391
+ Object.setPrototypeOf(Indexable.prototype, new Proxy(base.prototype, {
392
+ //@ts-expect-error
393
+ [Symbol.toStringTag]: 'MutTs Indexable',
394
+ get(target, prop, receiver) {
395
+ if (prop in target) {
396
+ const getter = Object.getOwnPropertyDescriptor(target, prop)?.get;
397
+ return getter ? getter.call(receiver) : target[prop];
398
+ }
399
+ if (typeof prop === 'string') {
400
+ if (prop === 'length' && accessor.getLength)
401
+ return accessor.getLength.call(receiver);
402
+ const numProp = Number(prop);
403
+ if (!Number.isNaN(numProp)) {
404
+ return accessor.get.call(receiver, numProp);
405
+ }
406
+ }
407
+ return undefined;
408
+ },
409
+ set(target, prop, value, receiver) {
410
+ if (prop in target) {
411
+ const setter = Object.getOwnPropertyDescriptor(target, prop)?.set;
412
+ if (setter)
413
+ setter.call(receiver, value);
414
+ else
415
+ target[prop] = value;
416
+ return true;
417
+ }
418
+ if (typeof prop === 'string') {
419
+ if (prop === 'length' && accessor.setLength) {
420
+ accessor.setLength.call(receiver, value);
421
+ return true;
422
+ }
423
+ const numProp = Number(prop);
424
+ if (!Number.isNaN(numProp)) {
425
+ if (!accessor.set)
426
+ throw new Error('Indexable class has read-only numeric index access');
427
+ accessor.set.call(receiver, numProp, value);
428
+ return true;
429
+ }
430
+ }
431
+ Object.defineProperty(receiver, prop, {
432
+ value,
433
+ writable: true,
434
+ enumerable: true,
435
+ configurable: true,
436
+ });
437
+ return true;
438
+ },
439
+ has(target, prop) {
440
+ if (prop in target)
441
+ return true;
442
+ if (typeof prop === 'string') {
443
+ if (prop === 'length' && accessor.getLength)
444
+ return true;
445
+ const numProp = Number(prop);
446
+ if (!Number.isNaN(numProp))
447
+ return true;
448
+ }
449
+ return false;
450
+ },
451
+ ownKeys(target) {
452
+ const keys = Reflect.ownKeys(target);
453
+ if (accessor.getLength) {
454
+ keys.push('length');
455
+ const len = accessor.getLength.call(this);
456
+ for (let i = 0; i < len; i++)
457
+ keys.push(String(i));
458
+ }
459
+ return keys;
460
+ },
461
+ getOwnPropertyDescriptor(target, prop) {
462
+ if (prop in target)
463
+ return Object.getOwnPropertyDescriptor(target, prop);
464
+ if (typeof prop === 'string') {
465
+ if (prop === 'length' && accessor.getLength) {
466
+ return {
467
+ enumerable: false,
468
+ configurable: true,
469
+ get: () => accessor.getLength.call(this),
470
+ };
471
+ }
472
+ const numProp = Number(prop);
473
+ if (!Number.isNaN(numProp)) {
474
+ return {
475
+ enumerable: true,
476
+ configurable: true,
477
+ get: () => accessor.get.call(this, numProp),
478
+ set: accessor.set
479
+ ? (v) => accessor.set.call(this, numProp, v)
480
+ : undefined,
481
+ };
482
+ }
483
+ }
484
+ return undefined;
485
+ },
486
+ }));
487
+ return Indexable;
488
+ }
489
+ /**
490
+ * Symbol for accessing the forwarded array in ArrayReadForward
491
+ */
492
+ const forwardArray = Symbol('forwardArray');
493
+ /**
494
+ * A read-only array forwarder that implements all reading/iterating methods of Array
495
+ * but does not implement modification methods.
496
+ *
497
+ * The constructor takes a callback that returns an array, and all methods forward
498
+ * their behavior to the result of that callback.
499
+ */
500
+ class ArrayReadForward {
501
+ get [forwardArray]() {
502
+ throw new Error('ArrayReadForward is not implemented');
503
+ }
504
+ /**
505
+ * Get the length of the array
506
+ */
507
+ get length() {
508
+ return this[forwardArray].length;
509
+ }
510
+ /**
511
+ * Iterator protocol support
512
+ */
513
+ [Symbol.iterator]() {
514
+ return this[forwardArray][Symbol.iterator]();
515
+ }
516
+ // Reading/Iterating methods
517
+ /**
518
+ * Creates a new array with the results of calling a provided function on every element
519
+ */
520
+ map(callbackfn, thisArg) {
521
+ return this[forwardArray].map(callbackfn, thisArg);
522
+ }
523
+ filter(predicate, thisArg) {
524
+ return this[forwardArray].filter(predicate, thisArg);
525
+ }
526
+ reduce(callbackfn, initialValue) {
527
+ return initialValue !== undefined
528
+ ? this[forwardArray].reduce(callbackfn, initialValue)
529
+ : this[forwardArray].reduce(callbackfn);
530
+ }
531
+ reduceRight(callbackfn, initialValue) {
532
+ return initialValue !== undefined
533
+ ? this[forwardArray].reduceRight(callbackfn, initialValue)
534
+ : this[forwardArray].reduceRight(callbackfn);
535
+ }
536
+ /**
537
+ * Executes a provided function once for each array element
538
+ */
539
+ forEach(callbackfn, thisArg) {
540
+ this[forwardArray].forEach(callbackfn, thisArg);
541
+ }
542
+ find(predicate, thisArg) {
543
+ return this[forwardArray].find(predicate, thisArg);
544
+ }
545
+ /**
546
+ * Returns the index of the first element in the array that satisfies the provided testing function
547
+ */
548
+ findIndex(predicate, thisArg) {
549
+ return this[forwardArray].findIndex(predicate, thisArg);
550
+ }
551
+ findLast(predicate, thisArg) {
552
+ return this[forwardArray].findLast(predicate, thisArg);
553
+ }
554
+ /**
555
+ * Returns the index of the last element in the array that satisfies the provided testing function
556
+ */
557
+ findLastIndex(predicate, thisArg) {
558
+ return this[forwardArray].findLastIndex(predicate, thisArg);
559
+ }
560
+ /**
561
+ * Determines whether an array includes a certain value among its entries
562
+ */
563
+ includes(searchElement, fromIndex) {
564
+ return this[forwardArray].includes(searchElement, fromIndex);
565
+ }
566
+ /**
567
+ * Returns the first index at which a given element can be found in the array
568
+ */
569
+ indexOf(searchElement, fromIndex) {
570
+ return this[forwardArray].indexOf(searchElement, fromIndex);
571
+ }
572
+ /**
573
+ * Returns the last index at which a given element can be found in the array
574
+ */
575
+ lastIndexOf(searchElement, fromIndex) {
576
+ return this[forwardArray].lastIndexOf(searchElement, fromIndex);
577
+ }
578
+ /**
579
+ * Returns a shallow copy of a portion of an array into a new array object
580
+ */
581
+ slice(start, end) {
582
+ return this[forwardArray].slice(start, end);
583
+ }
584
+ concat(...items) {
585
+ return this[forwardArray].concat(...items);
586
+ }
587
+ /**
588
+ * Tests whether all elements in the array pass the test implemented by the provided function
589
+ */
590
+ every(predicate, thisArg) {
591
+ return this[forwardArray].every(predicate, thisArg);
592
+ }
593
+ /**
594
+ * Tests whether at least one element in the array passes the test implemented by the provided function
595
+ */
596
+ some(predicate, thisArg) {
597
+ return this[forwardArray].some(predicate, thisArg);
598
+ }
599
+ /**
600
+ * Joins all elements of an array into a string
601
+ */
602
+ join(separator) {
603
+ return this[forwardArray].join(separator);
604
+ }
605
+ /**
606
+ * Returns a new array iterator that contains the keys for each index in the array
607
+ */
608
+ keys() {
609
+ return this[forwardArray].keys();
610
+ }
611
+ /**
612
+ * Returns a new array iterator that contains the values for each index in the array
613
+ */
614
+ values() {
615
+ return this[forwardArray].values();
616
+ }
617
+ /**
618
+ * Returns a new array iterator that contains the key/value pairs for each index in the array
619
+ */
620
+ entries() {
621
+ return this[forwardArray].entries();
622
+ }
623
+ /**
624
+ * Returns a string representation of the array
625
+ */
626
+ toString() {
627
+ return this[forwardArray].toString();
628
+ }
629
+ /**
630
+ * Returns a localized string representing the array
631
+ */
632
+ toLocaleString(locales, options) {
633
+ return this[forwardArray].toLocaleString(locales, options);
634
+ }
635
+ /**
636
+ * Returns the element at the specified index, or undefined if the index is out of bounds
637
+ */
638
+ at(index) {
639
+ return this[forwardArray].at(index);
640
+ }
641
+ /**
642
+ * Returns a new array with all sub-array elements concatenated into it recursively up to the specified depth
643
+ */
644
+ flat(depth) {
645
+ return this[forwardArray].flat(depth);
646
+ }
647
+ /**
648
+ * Returns a new array formed by applying a given callback function to each element of the array,
649
+ * and then flattening the result by one level
650
+ */
651
+ flatMap(callback, thisArg) {
652
+ return this[forwardArray].flatMap(callback, thisArg);
653
+ }
654
+ /**
655
+ * Returns a new array with elements in reversed order (ES2023)
656
+ */
657
+ toReversed() {
658
+ return this[forwardArray].toReversed?.() ?? [...this[forwardArray]].reverse();
659
+ }
660
+ /**
661
+ * Returns a new array with elements sorted (ES2023)
662
+ */
663
+ toSorted(compareFn) {
664
+ return this[forwardArray].toSorted?.(compareFn) ?? [...this[forwardArray]].sort(compareFn);
665
+ }
666
+ /**
667
+ * Returns a new array with some elements removed and/or replaced at a given index (ES2023)
668
+ */
669
+ toSpliced(start, deleteCount, ...items) {
670
+ if (deleteCount === undefined)
671
+ return this[forwardArray].toSpliced(start);
672
+ return this[forwardArray].toSpliced(start, deleteCount, ...items);
673
+ }
674
+ /**
675
+ * Returns a new array with the element at the given index replaced with the given value (ES2023)
676
+ */
677
+ with(index, value) {
678
+ return this[forwardArray].with(index, value);
679
+ }
680
+ get [Symbol.unscopables]() {
681
+ return this[forwardArray][Symbol.unscopables];
682
+ }
683
+ }
684
+
685
+ const forward = (name, target) => (...args) => {
686
+ return target[name](...args);
687
+ };
688
+ const alreadyChained = new WeakMap();
689
+ const originals = new WeakMap();
690
+ function cache$1(target, rv) {
691
+ originals.set(rv, target);
692
+ alreadyChained.set(target, rv);
693
+ }
694
+ const promiseProxyHandler = {
695
+ //@ts-expect-error
696
+ [Symbol.toStringTag]: 'MutTs PromiseChain function',
697
+ get(target, prop) {
698
+ if (prop === Symbol.toStringTag)
699
+ return 'PromiseProxy';
700
+ if (typeof prop === 'string' && ['then', 'catch', 'finally'].includes(prop))
701
+ return target[prop];
702
+ return chainPromise(target.then((r) => r[prop]));
703
+ },
704
+ };
705
+ const promiseForward = (target) => ({
706
+ // biome-ignore lint/suspicious/noThenProperty: This one is the whole point
707
+ then: forward('then', target),
708
+ catch: forward('catch', target),
709
+ finally: forward('finally', target),
710
+ });
711
+ const objectProxyHandler = {
712
+ //@ts-expect-error
713
+ [Symbol.toStringTag]: 'MutTs PromiseChain object',
714
+ get(target, prop, receiver) {
715
+ const getter = Object.getOwnPropertyDescriptor(target, prop)?.get;
716
+ const rv = getter ? getter.call(receiver) : target[prop];
717
+ // Allows fct.call or fct.apply to bypass the chain system
718
+ if (typeof target === 'function')
719
+ return rv;
720
+ return chainPromise(rv);
721
+ },
722
+ apply(target, thisArg, args) {
723
+ return chainPromise(target.apply(thisArg, args));
724
+ },
725
+ };
726
+ function chainObject(given) {
727
+ const rv = new Proxy(given, objectProxyHandler);
728
+ cache$1(given, rv);
729
+ return rv;
730
+ }
731
+ function chainable(x) {
732
+ return x && ['function', 'object'].includes(typeof x);
733
+ }
734
+ /**
735
+ * Transforms a promise or value into a chainable object
736
+ * Allows calling methods directly on promise results without awaiting them first
737
+ * @param given - The promise or value to make chainable
738
+ * @returns A chainable version of the input
739
+ */
740
+ function chainPromise(given) {
741
+ if (!chainable(given))
742
+ return given;
743
+ if (alreadyChained.has(given))
744
+ return alreadyChained.get(given);
745
+ if (!(given instanceof Promise))
746
+ return chainObject(given);
747
+ // @ts-expect-error It's ok as we check if it's an object above
748
+ given = given.then((r) => (chainable(r) ? chainObject(r) : r));
749
+ const target = Object.assign(function (...args) {
750
+ return chainPromise(given.then((r) => {
751
+ return this?.then
752
+ ? this.then((t) => r.apply(t, args))
753
+ : r.apply(this, args);
754
+ }));
755
+ }, promiseForward(given));
756
+ const chained = new Proxy(target, promiseProxyHandler);
757
+ cache$1(given, chained);
758
+ return chained;
759
+ }
760
+
761
+ const attend = proxy.captioned(function attend(source, callback) {
762
+ const enumerate = typeof source === 'function'
763
+ ? source
764
+ : Array.isArray(source)
765
+ ? () => Array.from({ length: source.length }, (_, i) => i)
766
+ : source instanceof Map
767
+ ? () => source.keys()
768
+ : source instanceof Set
769
+ ? () => source.values()
770
+ : () => Object.keys(source);
771
+ const keyEffects = new Map();
772
+ const callbackLabel = callback.name ? callback.name : '';
773
+ const outer = proxy.effect `attend`(({ ascend }) => {
774
+ const keys = new Set();
775
+ for (const key of enumerate())
776
+ keys.add(key);
777
+ for (const key of keys) {
778
+ if (keyEffects.has(key))
779
+ continue;
780
+ const indexRef = { value: key };
781
+ keyEffects.set(key, ascend(() => proxy.effect `attend${callbackLabel ? `:${callbackLabel}` : ''}:${key}`((access) => callback(indexRef.value, access))));
782
+ }
783
+ for (const key of Array.from(keyEffects.keys())) {
784
+ if (!keys.has(key)) {
785
+ keyEffects.get(key)();
786
+ keyEffects.delete(key);
787
+ }
788
+ }
789
+ });
790
+ return (reason) => {
791
+ outer(reason);
792
+ for (const stop of keyEffects.values())
793
+ stop(reason);
794
+ keyEffects.clear();
795
+ };
796
+ }, {
797
+ name: 'attend',
798
+ callbackIndex: 1,
799
+ warn: (message) => proxy.options.warn(`[reactive] ${message}`),
800
+ });
801
+ /**
802
+ * Lifts a callback that returns an object into a reactive object that automatically
803
+ * synchronizes with the source object returned by the callback.
804
+ *
805
+ * The returned reactive object will update whenever the callback's dependencies change,
806
+ * efficiently syncing only the properties that differ from the previous result using
807
+ * Object.assign(). Properties that no longer exist in the source are automatically removed.
808
+ *
809
+ * @example
810
+ * ```typescript
811
+ * const user = reactive({ name: 'John', age: 30 })
812
+ * const profile = lift(() => ({
813
+ * displayName: user.name.toUpperCase(),
814
+ * isAdult: user.age >= 18,
815
+ * description: `${user.name} is ${user.age} years old`
816
+ * }))
817
+ *
818
+ * console.log(profile.displayName) // JOHN
819
+ * console.log(profile.isAdult) // true
820
+ *
821
+ * user.name = 'Jane'
822
+ * console.log(profile.displayName) // JANE
823
+ * console.log(profile.description) // Jane is 30 years old
824
+ * ```
825
+ *
826
+ * @param cb Callback function that returns an object
827
+ * @returns A reactive object synchronized with the callback's result, with a [cleanup] property to stop tracking
828
+ */
829
+ const lift = proxy.captioned(function lift(cb) {
830
+ let result;
831
+ let rawResult;
832
+ const resultName = `lift:${cb.name || 'anonymous'}`;
833
+ const liftCleanup = proxy.effect `lift:${cb.name}`(proxy.markWithRoot((access) => {
834
+ const source = cb(access);
835
+ if (!source || typeof source !== 'object')
836
+ throw new Error('lift callback must return an array or object');
837
+ const sourceProto = Object.getPrototypeOf(source);
838
+ if (!result) {
839
+ rawResult = proxy.tag(resultName, Array.isArray(source) ? [] : Object.create(sourceProto));
840
+ result = proxy.reactive(rawResult);
841
+ }
842
+ if (sourceProto !== Object.getPrototypeOf(result))
843
+ throw new Error('lift callback must return the same type as the previous result');
844
+ if (Array.isArray(source)) {
845
+ const res = result;
846
+ for (const { indexA, sliceA, sliceB } of arrayDiff(res, source).sort((a, b) => a.indexA - b.indexA))
847
+ res.splice(indexA, sliceA.length, ...sliceB);
848
+ }
849
+ else {
850
+ const recordResult = rawResult;
851
+ for (const key of Object.keys(source)) {
852
+ const had = key in rawResult;
853
+ const newDesc = Object.getOwnPropertyDescriptor(source, key);
854
+ if (had) {
855
+ const oldDesc = Object.getOwnPropertyDescriptor(rawResult, key);
856
+ const sameAccessor = oldDesc && newDesc.get && oldDesc.get === newDesc.get;
857
+ Object.defineProperty(rawResult, key, newDesc);
858
+ if (!sameAccessor &&
859
+ recordResult[key] !==
860
+ (oldDesc ? (oldDesc.get ? oldDesc.get() : oldDesc.value) : undefined))
861
+ proxy.touched1(rawResult, { type: 'set', prop: key }, key);
862
+ }
863
+ else {
864
+ Object.defineProperty(rawResult, key, newDesc);
865
+ proxy.touched1(rawResult, { type: 'add', prop: key }, key);
866
+ }
867
+ }
868
+ for (const key of Object.keys(rawResult))
869
+ if (!(key in source)) {
870
+ delete recordResult[key];
871
+ proxy.touched1(rawResult, { type: 'del', prop: key }, key);
872
+ }
873
+ }
874
+ }, cb));
875
+ return proxy.link(result, liftCleanup);
876
+ }, {
877
+ name: 'lift',
878
+ warn: (message) => proxy.options.warn(`[reactive] ${message}`),
879
+ });
880
+ /**
881
+ * Reactively maps an array source through `fn`, producing a lazy reactive output array.
882
+ *
883
+ * Each source item gets its own isolated effect (via `root()`) so that changes to one item
884
+ * only recompute that item's projection. Structural changes (push, splice, reorder) are detected
885
+ * via `arrayDiff` and surgically applied to the output cache.
886
+ *
887
+ * The source can be a reactive array or a function returning an array. When a function is provided,
888
+ * the function is re-evaluated inside an effect whenever its dependencies change.
889
+ *
890
+ * Output elements are computed lazily — accessing `result[i]` triggers computation if not yet cached.
891
+ *
892
+ * @param source - A reactive array or a function returning an array
893
+ * @param fn - Mapping function applied to each element
894
+ * @param options - Optional purity hints to skip per-item effects
895
+ * @returns A readonly reactive array with a `[cleanup]` method to dispose all effects
896
+ */
897
+ function morphArray(source, fn, options) {
898
+ if (typeof source !== 'function' && !proxy.isReactive(source) && options?.pure === true) {
899
+ return source.map((i) => fn(i));
900
+ }
901
+ let track;
902
+ const itemEffects = new Map();
903
+ const cache = proxy.tag(`morph:${fn.name || 'anonymous'}`, []);
904
+ let input = [];
905
+ function stopItem(key) {
906
+ const entry = itemEffects.get(key);
907
+ if (entry) {
908
+ const activeEffect = proxy.getActiveEffect();
909
+ let chain;
910
+ if (activeEffect) {
911
+ const node = proxy.getEffectNode(activeEffect);
912
+ chain = node.currentReason;
913
+ }
914
+ entry.stop(proxy.chainExternalReason({ type: 'stopped', chain }));
915
+ itemEffects.delete(key);
916
+ }
917
+ }
918
+ function computeItem(key, input) {
919
+ const isPure = options?.pure === true || (typeof options?.pure === 'function' && options.pure(input));
920
+ if (isPure) {
921
+ track(() => {
922
+ cache[key] = fn(input);
923
+ });
924
+ }
925
+ else {
926
+ const indexRef = { value: key };
927
+ const stop = track(() => proxy.effect.opaque `morph:${fn.name}:${key}`((access) => {
928
+ cache[indexRef.value] = fn(input, access);
929
+ return (reason) => {
930
+ delete cache[indexRef.value];
931
+ proxy.touched1(cache, { type: 'invalidate', prop: 'morph' }, String(key));
932
+ const activeEffect = proxy.getActiveEffect();
933
+ let chain;
934
+ if (activeEffect) {
935
+ const node = proxy.getEffectNode(activeEffect);
936
+ chain = node.currentReason;
937
+ }
938
+ stop?.({
939
+ type: 'invalidate',
940
+ cause: proxy.chainExternalReason(reason ?? { type: 'stopped', chain }),
941
+ chain: proxy.chainExternalReason(chain),
942
+ });
943
+ };
944
+ }));
945
+ itemEffects.set(key, { stop, index: indexRef });
946
+ }
947
+ }
948
+ const proxy$1 = proxy.reactive(cache, {
949
+ get(cache, prop) {
950
+ const n = typeof prop === 'string' ? Number(prop) : NaN;
951
+ if (Number.isNaN(n))
952
+ return cache[prop];
953
+ if (!(n in cache))
954
+ computeItem(n, input[n]);
955
+ return cache[n];
956
+ },
957
+ has(_cache, prop) {
958
+ return Reflect.has(input, prop);
959
+ },
960
+ });
961
+ const stopMain = proxy.effect `morph:${fn.name}`(({ ascend }) => {
962
+ track = ascend;
963
+ const newInput = [...(typeof source === 'function' ? source() : source)];
964
+ const diffs = arrayDiff(input, newInput).toSorted((a, b) => b.indexA - a.indexA);
965
+ if (diffs.length > 0) {
966
+ for (const diff of diffs) {
967
+ // Stop items in removed range
968
+ for (let i = diff.indexA; i < diff.indexA + diff.sliceA.length; i++)
969
+ stopItem(i);
970
+ // Shift existing itemEffects in the Map to match the new indices
971
+ const shift = diff.sliceB.length - diff.sliceA.length;
972
+ if (shift !== 0) {
973
+ // We need to move entries in the Map.
974
+ const entries = Array.from(itemEffects.entries()).sort((a, b) => a[0] - b[0]);
975
+ // Remove entries that will be shifted
976
+ for (const [idx, _entry] of entries) {
977
+ if (idx >= diff.indexA + diff.sliceA.length) {
978
+ itemEffects.delete(idx);
979
+ }
980
+ }
981
+ // Re-add them with shifted indices
982
+ for (const [idx, entry] of entries) {
983
+ if (idx >= diff.indexA + diff.sliceA.length) {
984
+ const newIdx = idx + shift;
985
+ entry.index.value = newIdx;
986
+ itemEffects.set(newIdx, entry);
987
+ }
988
+ }
989
+ }
990
+ // Splice the cache
991
+ cache.splice(diff.indexA, diff.sliceA.length, ...new Array(diff.sliceB.length).fill(undefined));
992
+ // Make holes for lazy computation
993
+ for (let i = diff.indexA; i < diff.indexA + diff.sliceB.length; i++)
994
+ delete cache[i];
995
+ }
996
+ const invalidates = new Set([proxy.keysOf]);
997
+ if (input.length !== newInput.length)
998
+ invalidates.add('length');
999
+ for (const diff of diffs) {
1000
+ const max = Math.max(diff.sliceA.length, diff.sliceB.length);
1001
+ for (let i = 0; i < max; i++)
1002
+ invalidates.add(String(diff.indexA + i));
1003
+ }
1004
+ proxy.touched(cache, { type: 'bunch', method: 'morph-input' }, invalidates);
1005
+ }
1006
+ input = newInput;
1007
+ });
1008
+ return proxy.link(proxy$1, (reason) => {
1009
+ stopMain(reason);
1010
+ for (const entry of itemEffects.values())
1011
+ entry.stop(reason);
1012
+ itemEffects.clear();
1013
+ });
1014
+ }
1015
+ /**
1016
+ * Reactively maps a `Map` source through `fn`, producing a reactive output Map.
1017
+ *
1018
+ * Each key gets its own isolated effect so that value changes for one key only recompute
1019
+ * that key's projection. Key additions and removals are tracked via `keysOf` dependency.
1020
+ *
1021
+ * @param source - A reactive Map
1022
+ * @param fn - Mapping function applied to each value
1023
+ * @param options - Optional purity hints to skip per-key effects
1024
+ * @returns A reactive Map with a `[cleanup]` method to dispose all effects
1025
+ */
1026
+ function morphMap(source, fn, options) {
1027
+ if (!proxy.isReactive(source) && options?.pure === true) {
1028
+ const res = new Map();
1029
+ for (const [k, v] of source)
1030
+ res.set(k, fn(v, k));
1031
+ return res;
1032
+ }
1033
+ let track;
1034
+ const itemEffects = new Map();
1035
+ const cache = proxy.tag(`morph:${fn.name || 'anonymous'}`, new Map());
1036
+ Object.defineProperty(cache, 'constructor', { value: Object, enumerable: false });
1037
+ function stopItem(key) {
1038
+ const stop = itemEffects.get(key);
1039
+ if (stop) {
1040
+ const activeEffect = proxy.getActiveEffect();
1041
+ let chain;
1042
+ if (activeEffect) {
1043
+ const node = proxy.getEffectNode(activeEffect);
1044
+ chain = node.currentReason;
1045
+ }
1046
+ stop({ type: 'stopped', chain });
1047
+ itemEffects.delete(key);
1048
+ }
1049
+ }
1050
+ function computeItem(key, val) {
1051
+ const isPure = options?.pure === true || (typeof options?.pure === 'function' && options.pure(val));
1052
+ if (isPure) {
1053
+ cache.set(key, track(() => fn(val, key)));
1054
+ }
1055
+ else {
1056
+ const stop = track(() => proxy.effect.opaque `morph:${fn.name}:${key}`((access) => {
1057
+ const next = source.get(key);
1058
+ if (next === undefined && !source.has(key))
1059
+ return;
1060
+ cache.set(key, fn(next, key, access));
1061
+ return (reason) => {
1062
+ cache.delete(key);
1063
+ proxy.touched1(cache, { type: 'invalidate', prop: 'morph' }, String(key));
1064
+ const activeEffect = proxy.getActiveEffect();
1065
+ let chain;
1066
+ if (activeEffect) {
1067
+ const node = proxy.getEffectNode(activeEffect);
1068
+ chain = node.currentReason;
1069
+ }
1070
+ stop?.({
1071
+ type: 'invalidate',
1072
+ cause: proxy.chainExternalReason(reason ?? { type: 'stopped', chain }),
1073
+ chain: proxy.chainExternalReason(chain),
1074
+ });
1075
+ };
1076
+ }));
1077
+ itemEffects.set(key, stop);
1078
+ }
1079
+ }
1080
+ const proxy$1 = proxy.reactive(cache, {
1081
+ get(cache, prop) {
1082
+ if (prop === 'get')
1083
+ return (key) => {
1084
+ if (!cache.has(key) && source.has(key))
1085
+ computeItem(key, source.get(key));
1086
+ return cache.get(key);
1087
+ };
1088
+ if (prop === 'has')
1089
+ return (key) => {
1090
+ return source.has(key);
1091
+ };
1092
+ if (prop === 'keys')
1093
+ return () => {
1094
+ return source.keys();
1095
+ };
1096
+ if (prop === 'values')
1097
+ return function* () {
1098
+ for (const key of source.keys()) {
1099
+ yield proxy$1.get(key);
1100
+ }
1101
+ };
1102
+ if (prop === 'entries')
1103
+ return function* () {
1104
+ for (const key of source.keys()) {
1105
+ yield [key, proxy$1.get(key)];
1106
+ }
1107
+ };
1108
+ if (prop === Symbol.iterator)
1109
+ return function* () {
1110
+ for (const key of source.keys()) {
1111
+ yield [key, proxy$1.get(key)];
1112
+ }
1113
+ };
1114
+ return cache[prop];
1115
+ },
1116
+ });
1117
+ let stateSnapshot = proxy.getState(source);
1118
+ const stopMain = proxy.effect `morph:${fn.name}`(({ ascend }) => {
1119
+ track = ascend;
1120
+ proxy.dependant(source, proxy.keysOf);
1121
+ while ('evolution' in stateSnapshot) {
1122
+ const { evolution } = stateSnapshot;
1123
+ stateSnapshot = stateSnapshot.next;
1124
+ if (evolution.type === 'add') {
1125
+ proxy.touched1(cache, evolution, evolution.prop);
1126
+ }
1127
+ else if (evolution.type === 'del') {
1128
+ stopItem(evolution.prop);
1129
+ cache.delete(evolution.prop);
1130
+ proxy.touched1(cache, evolution, evolution.prop);
1131
+ }
1132
+ }
1133
+ });
1134
+ return proxy.link(proxy$1, (reason) => {
1135
+ stopMain(reason);
1136
+ for (const stop of itemEffects.values())
1137
+ stop(reason);
1138
+ itemEffects.clear();
1139
+ });
1140
+ }
1141
+ /**
1142
+ * Reactively maps a record/object source through `fn`, producing a reactive output record.
1143
+ *
1144
+ * Each key gets its own isolated effect so that value changes for one key only recompute
1145
+ * that key's projection. Key additions and removals are tracked automatically.
1146
+ *
1147
+ * @param source - A reactive record
1148
+ * @param fn - Mapping function applied to each value
1149
+ * @param options - Optional purity hints to skip per-key effects
1150
+ * @returns A reactive record with a `[cleanup]` method to dispose all effects
1151
+ */
1152
+ function morphRecord(source, fn, options) {
1153
+ if (!proxy.isReactive(source) && options?.pure === true) {
1154
+ const res = {};
1155
+ for (const k of Object.keys(source))
1156
+ res[k] = fn(source[k], k);
1157
+ return res;
1158
+ }
1159
+ let track;
1160
+ const itemEffects = new Map();
1161
+ const cache = {};
1162
+ function stopItem(key) {
1163
+ const stop = itemEffects.get(key);
1164
+ if (stop) {
1165
+ const activeEffect = proxy.getActiveEffect();
1166
+ let chain;
1167
+ if (activeEffect) {
1168
+ const node = proxy.getEffectNode(activeEffect);
1169
+ chain = node.currentReason;
1170
+ }
1171
+ stop({ type: 'stopped', chain });
1172
+ itemEffects.delete(key);
1173
+ }
1174
+ }
1175
+ function computeItem(key, val) {
1176
+ const isPure = options?.pure === true || (typeof options?.pure === 'function' && options.pure(val));
1177
+ if (isPure) {
1178
+ cache[key] = track(() => fn(val, key));
1179
+ }
1180
+ else {
1181
+ const stop = track(() => proxy.effect.opaque `morph:${fn.name}:${key}`((access) => {
1182
+ cache[key] = fn(source[key], key, access);
1183
+ return (reason) => {
1184
+ delete cache[key];
1185
+ proxy.touched1(cache, { type: 'invalidate', prop: 'morph' }, String(key));
1186
+ const activeEffect = proxy.getActiveEffect();
1187
+ let chain;
1188
+ if (activeEffect) {
1189
+ const node = proxy.getEffectNode(activeEffect);
1190
+ chain = node.currentReason;
1191
+ }
1192
+ stop?.({
1193
+ type: 'invalidate',
1194
+ cause: proxy.chainExternalReason(reason ?? { type: 'stopped', chain }),
1195
+ chain: proxy.chainExternalReason(chain),
1196
+ });
1197
+ };
1198
+ }));
1199
+ itemEffects.set(key, stop);
1200
+ }
1201
+ }
1202
+ function get(prop) {
1203
+ if (!(prop in cache) && prop in source)
1204
+ computeItem(prop, source[prop]);
1205
+ return cache[prop];
1206
+ }
1207
+ const proxy$1 = proxy.reactive(cache, {
1208
+ get(_, prop) {
1209
+ return get(prop);
1210
+ },
1211
+ has(_, prop) {
1212
+ return prop in source;
1213
+ },
1214
+ ownKeys() {
1215
+ return Reflect.ownKeys(source);
1216
+ },
1217
+ getOwnPropertyDescriptor(_cache, prop) {
1218
+ if (prop in source)
1219
+ return { configurable: true, enumerable: true, get: () => get(prop) };
1220
+ },
1221
+ });
1222
+ let stateSnapshot = proxy.getState(source);
1223
+ const stopMain = proxy.effect `morph:${fn.name}`(({ ascend }) => {
1224
+ track = ascend;
1225
+ // Track only structural changes on source
1226
+ proxy.dependant(source, proxy.keysOf);
1227
+ while ('evolution' in stateSnapshot) {
1228
+ const { evolution } = stateSnapshot;
1229
+ stateSnapshot = stateSnapshot.next;
1230
+ if (evolution.type === 'add') {
1231
+ proxy.touched1(cache, evolution, evolution.prop);
1232
+ }
1233
+ else if (evolution.type === 'del') {
1234
+ stopItem(evolution.prop);
1235
+ delete cache[evolution.prop];
1236
+ proxy.touched1(cache, evolution, evolution.prop);
1237
+ }
1238
+ }
1239
+ });
1240
+ return proxy.link(proxy$1, (reason) => {
1241
+ stopMain(reason);
1242
+ for (const stop of itemEffects.values())
1243
+ stop(reason);
1244
+ itemEffects.clear();
1245
+ });
1246
+ }
1247
+ /**
1248
+ * Reactively maps a collection (array, Map, or record) through a per-entry function.
1249
+ *
1250
+ * Each entry in the source gets its own reactive context — when only one entry's dependencies
1251
+ * change, only that entry's projection recomputes. Structural changes (additions, removals,
1252
+ * reorders) are detected via diffing and applied surgically.
1253
+ *
1254
+ * Use `morph.pure(source, fn)` when `fn` has no reactive reads (skips per-item effects).
1255
+ *
1256
+ * @example
1257
+ * ```ts
1258
+ * const users = reactive([{ name: 'John' }, { name: 'Jane' }])
1259
+ * const names = morph(users, u => u.name.toUpperCase())
1260
+ * // names[0] = 'JOHN', names[1] = 'JANE'
1261
+ * // Changing users[0].name only recomputes names[0]
1262
+ * ```
1263
+ */
1264
+ const morph = proxy.captioned(proxy.flavored(function morph(source, fn, options) {
1265
+ if (Array.isArray(source) || typeof source === 'function')
1266
+ return morphArray(source, fn, options);
1267
+ if (source instanceof Map)
1268
+ return morphMap(source, fn, options);
1269
+ return morphRecord(source, fn, options);
1270
+ }, {
1271
+ get pure() {
1272
+ return (source, fn, _opt) => this(source, fn, { pure: true });
1273
+ },
1274
+ }), {
1275
+ name: 'morph',
1276
+ callbackIndex: 1,
1277
+ warn: (message) => proxy.options.warn(`[reactive] ${message}`),
1278
+ });
1279
+
1280
+ /**
1281
+ * Deep watch an object and all its nested properties
1282
+ * @param target - The object to watch deeply
1283
+ * @param callback - The callback to call when any nested property changes
1284
+ * @param options - Options for the deep watch
1285
+ * @returns A cleanup function to stop watching
1286
+ */
1287
+ /**
1288
+ * Sets up deep watching for an object, tracking all nested property changes
1289
+ * @param target - The object to watch
1290
+ * @param callback - The callback to call when changes occur
1291
+ * @param options - Options for deep watching
1292
+ * @returns A cleanup function to stop deep watching
1293
+ */
1294
+ function deepWatch(target, callback, { immediate = false } = {}) {
1295
+ if (target === null || target === undefined)
1296
+ return undefined;
1297
+ if (typeof target !== 'object')
1298
+ throw new Error('Target of deep watching must be an object');
1299
+ // Create a wrapper callback that matches EffectTrigger signature
1300
+ const wrappedCallback = proxy.markWithRoot((() => callback(target)), callback);
1301
+ proxy.registerDeepWatcher();
1302
+ // Use the existing effect system to register dependencies
1303
+ return proxy.effect `deepWatch`(() => {
1304
+ // Mark the target object as having deep watchers
1305
+ proxy.objectsWithDeepWatchers.add(target);
1306
+ // Track which objects this effect is watching for cleanup
1307
+ let effectObjects = proxy.effectToDeepWatchedObjects.get(wrappedCallback);
1308
+ if (!effectObjects) {
1309
+ effectObjects = new Set();
1310
+ proxy.effectToDeepWatchedObjects.set(wrappedCallback, effectObjects);
1311
+ }
1312
+ effectObjects.add(target);
1313
+ // Traverse the object graph and register dependencies
1314
+ // This will re-run every time the effect runs, ensuring we catch all changes
1315
+ const visited = new WeakSet();
1316
+ function traverseAndTrack(obj, depth = 0) {
1317
+ // Prevent infinite recursion and excessive depth
1318
+ if (!obj || visited.has(obj) || typeof obj !== 'object' || depth > proxy.options.maxDeepWatchDepth)
1319
+ return;
1320
+ // Do not traverse into unreactive objects
1321
+ if (proxy.isNonReactive(obj))
1322
+ return;
1323
+ visited.add(obj);
1324
+ // Mark this object as having deep watchers
1325
+ proxy.objectsWithDeepWatchers.add(obj);
1326
+ effectObjects.add(obj);
1327
+ // Traverse all properties to register dependencies
1328
+ // unwrap to avoid kicking dependency
1329
+ for (const key in proxy.unwrap(obj)) {
1330
+ if (Object.hasOwn(obj, key)) {
1331
+ // Access the property to register dependency
1332
+ const value = obj[key];
1333
+ // Make the value reactive if it's an object
1334
+ const reactiveValue = typeof value === 'object' && value !== null ? proxy.reactive(value) : value;
1335
+ traverseAndTrack(reactiveValue, depth + 1);
1336
+ }
1337
+ }
1338
+ // Also handle array indices and length
1339
+ // Handle arrays and collections using iterators to ensure proxy tracking is triggered
1340
+ if (typeof obj[Symbol.iterator] === 'function') {
1341
+ // Access the iterator to track additions/removals/collection changes
1342
+ for (const value of obj) {
1343
+ // Make the value reactive if it's an object
1344
+ const reactiveValue = typeof value === 'object' && value !== null ? proxy.reactive(value) : value;
1345
+ traverseAndTrack(reactiveValue, depth + 1);
1346
+ }
1347
+ // Explicitly depend on length so array mutations changing count trigger re-evaluation
1348
+ if ('length' in obj) {
1349
+ proxy.dependant(obj, 'length');
1350
+ }
1351
+ // For Maps, also ensure we track values explicitly if the iterator yields entries
1352
+ if (obj instanceof Map) {
1353
+ for (const value of obj.values()) {
1354
+ const reactiveValue = typeof value === 'object' && value !== null ? proxy.reactive(value) : value;
1355
+ traverseAndTrack(reactiveValue, depth + 1);
1356
+ }
1357
+ }
1358
+ }
1359
+ // Note: WeakSet and WeakMap cannot be iterated, so we can't deep watch their contents
1360
+ // They will only trigger when the collection itself is replaced
1361
+ }
1362
+ // Traverse the target object to register all dependencies
1363
+ // This will register dependencies on all current properties and array elements
1364
+ traverseAndTrack(target);
1365
+ // Only call the callback if immediate is true or if it's not the first run
1366
+ if (immediate) {
1367
+ proxy.untracked `deepWatch:callback`(() => callback(target));
1368
+ }
1369
+ immediate = true;
1370
+ // Return a cleanup function that properly removes deep watcher tracking
1371
+ return () => {
1372
+ // Get the objects this effect was watching
1373
+ const effectObjects = proxy.effectToDeepWatchedObjects.get(wrappedCallback);
1374
+ if (effectObjects) {
1375
+ // Remove deep watcher tracking from all objects this effect was watching
1376
+ for (const obj of effectObjects) {
1377
+ // Check if this object still has other deep watchers
1378
+ const watchers = proxy.deepWatchers.get(obj);
1379
+ if (watchers) {
1380
+ // Remove this effect's callback from the watchers
1381
+ watchers.delete(wrappedCallback);
1382
+ // If no more watchers, remove the object from deep watchers tracking
1383
+ if (watchers.size === 0) {
1384
+ proxy.deepWatchers.delete(obj);
1385
+ proxy.objectsWithDeepWatchers.delete(obj);
1386
+ }
1387
+ }
1388
+ else {
1389
+ // No watchers found, remove from deep watchers tracking
1390
+ proxy.objectsWithDeepWatchers.delete(obj);
1391
+ }
1392
+ }
1393
+ // Clean up the tracking data
1394
+ proxy.effectToDeepWatchedObjects.delete(wrappedCallback);
1395
+ }
1396
+ };
1397
+ });
1398
+ }
1399
+
1400
+ const memoizedRegistry = new WeakMap();
1401
+ const wrapperRegistry = new WeakMap();
1402
+ function getBranch(tree, key) {
1403
+ tree.branches ?? (tree.branches = new WeakMap());
1404
+ let branch = tree.branches.get(key);
1405
+ if (!branch) {
1406
+ branch = {};
1407
+ tree.branches.set(key, branch);
1408
+ }
1409
+ return branch;
1410
+ }
1411
+ function memoizeFunction(fn, opts) {
1412
+ const fnRoot = proxy.getRoot(fn);
1413
+ const existing = memoizedRegistry.get(fnRoot);
1414
+ if (existing)
1415
+ return existing;
1416
+ const cacheRoot = {};
1417
+ const memoized = proxy.markWithRoot(function memoized(...args) {
1418
+ if (args.some((arg) => !(arg && ['object', 'symbol', 'function'].includes(typeof arg)))) {
1419
+ if (opts?.lenient)
1420
+ return fn.apply(this, args);
1421
+ throw new Error('memoize expects non-null object arguments');
1422
+ }
1423
+ let node = cacheRoot;
1424
+ // Note: decorators add `this` as first argument
1425
+ for (const arg of args) {
1426
+ node = getBranch(node, arg);
1427
+ }
1428
+ proxy.dependant(node, 'memoize');
1429
+ if ('result' in node) {
1430
+ if (proxy.options.onMemoizationDiscrepancy) {
1431
+ const wasVerification = proxy.options.isVerificationRun;
1432
+ proxy.options.isVerificationRun = true;
1433
+ try {
1434
+ const fresh = proxy.untracked `memoize:verify-calculation`(() => fn.apply(this, args));
1435
+ if (!proxy.deepCompare(node.result, fresh)) {
1436
+ proxy.optionCall('onMemoizationDiscrepancy', node.result, fresh, fn, args, 'calculation');
1437
+ }
1438
+ }
1439
+ finally {
1440
+ proxy.options.isVerificationRun = wasVerification;
1441
+ }
1442
+ }
1443
+ return node.result;
1444
+ }
1445
+ // Create memoize internal effect to track dependencies and invalidate cache
1446
+ // Use untracked to prevent the effect creation from being affected by parent effects
1447
+ node.cleanup = proxy.root `memoize:root`(() => proxy.effect `memoize`(() => {
1448
+ // Execute the function and track its dependencies
1449
+ // The function execution will automatically track dependencies on reactive objects
1450
+ node.result = fn.apply(this, args);
1451
+ return (reason) => {
1452
+ // When dependencies change, clear the cache and notify consumers
1453
+ delete node.result;
1454
+ proxy.touched1(node, { type: 'invalidate', prop: args }, 'memoize');
1455
+ // Lazy memoization: stop the effect so it doesn't re-run immediately.
1456
+ // It will be re-created on next access.
1457
+ if (node.cleanup) {
1458
+ const activeEffect = proxy.getActiveEffect();
1459
+ let chain;
1460
+ if (activeEffect) {
1461
+ const effectNode = proxy.getEffectNode(activeEffect);
1462
+ chain = effectNode.currentReason;
1463
+ }
1464
+ node.cleanup({
1465
+ type: 'invalidate',
1466
+ cause: proxy.chainExternalReason(reason ?? { type: 'stopped', chain }),
1467
+ chain: proxy.chainExternalReason(chain),
1468
+ });
1469
+ node.cleanup = undefined;
1470
+ }
1471
+ };
1472
+ }, { opaque: true }));
1473
+ if (proxy.options.onMemoizationDiscrepancy) {
1474
+ const wasVerification = proxy.options.isVerificationRun;
1475
+ proxy.options.isVerificationRun = true;
1476
+ try {
1477
+ const fresh = proxy.untracked `memoize:verify-comparison`(() => fn.apply(this, args));
1478
+ if (!proxy.deepCompare(node.result, fresh)) {
1479
+ proxy.optionCall('onMemoizationDiscrepancy', node.result, fresh, fn, args, 'comparison');
1480
+ }
1481
+ }
1482
+ finally {
1483
+ proxy.options.isVerificationRun = wasVerification;
1484
+ }
1485
+ }
1486
+ return node.result;
1487
+ }, fn);
1488
+ memoizedRegistry.set(fnRoot, memoized);
1489
+ memoizedRegistry.set(memoized, memoized);
1490
+ return memoized;
1491
+ }
1492
+ function memoizeObject(target, opts) {
1493
+ const existing = memoizedRegistry.get(target);
1494
+ if (existing)
1495
+ return existing;
1496
+ const proxy$1 = new Proxy(target, {
1497
+ get(source, prop, receiver) {
1498
+ // 1. Walk prototype chain to find descriptor
1499
+ let current = source;
1500
+ let desc;
1501
+ while (current) {
1502
+ desc = Object.getOwnPropertyDescriptor(current, prop);
1503
+ if (desc)
1504
+ break;
1505
+ current = Object.getPrototypeOf(current);
1506
+ }
1507
+ if (!desc)
1508
+ return Reflect.get(source, prop, receiver);
1509
+ // 2. If getter, memoize
1510
+ if (desc.get) {
1511
+ const originalGetter = desc.get;
1512
+ let wrapper = wrapperRegistry.get(originalGetter);
1513
+ if (!wrapper) {
1514
+ wrapper = proxy.markWithRoot(proxy.named(`${String(source?.constructor?.name ?? 'Object')}.${String(prop)}`, (that) => {
1515
+ return originalGetter.call(that);
1516
+ }), {
1517
+ propertyKey: prop,
1518
+ });
1519
+ const origRoot = originalGetter[proxy.rootFunctionSymbol];
1520
+ if (origRoot)
1521
+ wrapper[proxy.rootFunctionSymbol] = origRoot;
1522
+ wrapperRegistry.set(originalGetter, wrapper);
1523
+ }
1524
+ const memoized = memoizeFunction(wrapper, opts);
1525
+ return memoized(receiver);
1526
+ }
1527
+ // 3. Otherwise forward
1528
+ return Reflect.get(source, prop, receiver);
1529
+ },
1530
+ // Forward set to the target (source) to ensure it acts as the receiver for reactivity notifications
1531
+ set(source, prop, value, _receiver) {
1532
+ // By strictly passing `source` as receiver, we ensure that if `source` is a reactive proxy,
1533
+ // it recognizes itself and triggers change notifications.
1534
+ return Reflect.set(source, prop, value, source);
1535
+ },
1536
+ });
1537
+ proxy.proxyToObject.set(proxy$1, target);
1538
+ memoizedRegistry.set(target, proxy$1);
1539
+ return proxy$1;
1540
+ }
1541
+ /**
1542
+ * Decorator and function wrapper for memoizing computed values based on reactive dependencies.
1543
+ *
1544
+ * When used as a decorator on getters or methods, it caches the result and automatically
1545
+ * invalidates the cache when reactive dependencies change.
1546
+ *
1547
+ * When used as a function wrapper, it memoizes based on object arguments (WeakMap-based cache).
1548
+ *
1549
+ * @example
1550
+ * ```typescript
1551
+ * class User {
1552
+ * @memoize
1553
+ * get fullName() {
1554
+ * return `${this.firstName} ${this.lastName}`
1555
+ * }
1556
+ * }
1557
+ *
1558
+ * // Or as a function wrapper
1559
+ * const expensive = memoize((obj: SomeObject) => {
1560
+ * return heavyComputation(obj)
1561
+ * })
1562
+ * ```
1563
+ */
1564
+ function makeMemoizeDecorator(memoizeOpts) {
1565
+ return proxy.decorator({
1566
+ getter(original, target, propertyKey) {
1567
+ return function () {
1568
+ let wrapper = wrapperRegistry.get(original);
1569
+ if (!wrapper) {
1570
+ wrapper = proxy.markWithRoot(proxy.named(`${String(target?.constructor?.name ?? target?.name ?? 'Object')}.${String(propertyKey)}`, (that) => {
1571
+ return original.call(that);
1572
+ }), {
1573
+ method: original,
1574
+ propertyKey,
1575
+ });
1576
+ const origRoot = original[proxy.rootFunctionSymbol];
1577
+ if (origRoot)
1578
+ wrapper[proxy.rootFunctionSymbol] = origRoot;
1579
+ wrapperRegistry.set(original, wrapper);
1580
+ }
1581
+ const memoized = memoizeFunction(wrapper, memoizeOpts);
1582
+ return memoized(this);
1583
+ };
1584
+ },
1585
+ method(original, target, name) {
1586
+ return function (...args) {
1587
+ let wrapper = wrapperRegistry.get(original);
1588
+ if (!wrapper) {
1589
+ wrapper = proxy.markWithRoot(proxy.named(`${String(target?.constructor?.name ?? target?.name ?? 'Object')}.${String(name)}`, (that, ...args) => {
1590
+ return original.call(that, ...args);
1591
+ }), {
1592
+ method: original,
1593
+ propertyKey: name,
1594
+ });
1595
+ const origRoot = original[proxy.rootFunctionSymbol];
1596
+ if (origRoot)
1597
+ wrapper[proxy.rootFunctionSymbol] = origRoot;
1598
+ wrapperRegistry.set(original, wrapper);
1599
+ }
1600
+ const memoized = memoizeFunction(wrapper, memoizeOpts);
1601
+ return memoized(this, ...args);
1602
+ };
1603
+ },
1604
+ default: (target) => typeof target === 'object'
1605
+ ? memoizeObject(target, memoizeOpts)
1606
+ : memoizeFunction(target, memoizeOpts),
1607
+ });
1608
+ }
1609
+ const memoize = proxy.flavored(makeMemoizeDecorator(), {
1610
+ get lenient() {
1611
+ return makeMemoizeDecorator({ lenient: true });
1612
+ },
1613
+ });
1614
+
1615
+ /**
1616
+ * Organizes a source object's properties into a target object using a callback function.
1617
+ * This creates a reactive mapping between source properties and a target object,
1618
+ * automatically handling property additions, updates, and removals.
1619
+ *
1620
+ * @template Source - The type of the source object
1621
+ * @template Target - The type of the target object (defaults to Record<PropertyKey, any>)
1622
+ *
1623
+ * @param {Source} source - The source object to organize
1624
+ * @param {OrganizedCallback<Source, Target>} apply - Callback function that defines how each source property is mapped to the target
1625
+ * @param {Target} [baseTarget={}] - Optional base target object to use (will be made reactive if not already)
1626
+ *
1627
+ * @returns {OrganizedResult<Target>} The target object with cleanup capability
1628
+ *
1629
+ * @example
1630
+ * // Organize user permissions into role-based access
1631
+ * const user = reactive({ isAdmin: true, canEdit: false });
1632
+ * const permissions = organized(
1633
+ * user,
1634
+ * (access, target) => {
1635
+ * if (access.key === 'isAdmin') {
1636
+ * target.hasFullAccess = access.value;
1637
+ * }
1638
+ * target[`can${access.key.charAt(0).toUpperCase() + access.key.slice(1)}`] = access.value;
1639
+ * }
1640
+ * );
1641
+ *
1642
+ * @example
1643
+ * // Transform object structure with cleanup
1644
+ * const source = reactive({ firstName: 'John', lastName: 'Doe' });
1645
+ * const formatted = organized(
1646
+ * source,
1647
+ * (access, target) => {
1648
+ * if (access.key === 'firstName' || access.key === 'lastName') {
1649
+ * target.fullName = `${source.firstName} ${source.lastName}`.trim();
1650
+ * }
1651
+ * }
1652
+ * );
1653
+ *
1654
+ * @example
1655
+ * // Using with cleanup in a component
1656
+ * effect(() => {
1657
+ * const data = fetchData();
1658
+ * const organizedData = organized(data, (access, target) => {
1659
+ * // Transform data
1660
+ * });
1661
+ *
1662
+ * // The cleanup will be called automatically when the effect is disposed
1663
+ * return () => organizedData[cleanup]();
1664
+ * });
1665
+ */
1666
+ function organized(source, apply, baseTarget = {}) {
1667
+ const observedSource = proxy.reactive(source);
1668
+ const target = proxy.reactive(baseTarget);
1669
+ const stop = attend `organized:entries`(function enumerateObservedSourceKeys() {
1670
+ const keys = [];
1671
+ for (const key in observedSource)
1672
+ keys.push(key);
1673
+ return keys;
1674
+ }, function applyObservedSourceKey(key) {
1675
+ const sourceKey = key;
1676
+ const accessBase = {
1677
+ key: sourceKey,
1678
+ get: () => proxy.FoolProof.get(observedSource, sourceKey, observedSource),
1679
+ set: (value) => proxy.FoolProof.set(observedSource, sourceKey, value, observedSource),
1680
+ };
1681
+ Object.defineProperty(accessBase, 'value', {
1682
+ get: accessBase.get,
1683
+ set: accessBase.set,
1684
+ configurable: true,
1685
+ enumerable: true,
1686
+ });
1687
+ return apply(accessBase, target);
1688
+ });
1689
+ return proxy.link(target, (reason) => stop(reason));
1690
+ }
1691
+ /**
1692
+ * Organizes a property on a target object
1693
+ * Shortcut for defineProperty/delete with touched signal
1694
+ * @param target - The target object
1695
+ * @param property - The property to organize
1696
+ * @param access - The access object
1697
+ * @returns The property descriptor
1698
+ */
1699
+ function organize(target, property, access) {
1700
+ Object.defineProperty(target, property, {
1701
+ get: access.get,
1702
+ set: access.set,
1703
+ configurable: true,
1704
+ enumerable: true,
1705
+ });
1706
+ proxy.touched1(target, { type: 'set', prop: property }, property);
1707
+ return () => delete target[property];
1708
+ }
1709
+
1710
+ //#region watch
1711
+ const unsetYet = Symbol('unset-yet');
1712
+ const watch = proxy.captioned(proxy.flavored(function watch(value, //object | ((dep: DependencyAccess) => object),
1713
+ changed, options = {}) {
1714
+ return typeof value === 'function'
1715
+ ? watchCallBack(value, changed, options)
1716
+ : typeof value === 'object' && value !== null
1717
+ ? watchObject(value, changed, options)
1718
+ : (() => {
1719
+ throw new Error('watch: value must be a function or an object');
1720
+ })();
1721
+ }, {
1722
+ get deep() {
1723
+ return proxy.flavorOptions(this, { deep: true });
1724
+ },
1725
+ get immediate() {
1726
+ return proxy.flavorOptions(this, { immediate: true });
1727
+ },
1728
+ }), {
1729
+ name: 'watch',
1730
+ warn: (message) => proxy.options.warn(`[reactive] ${message}`),
1731
+ });
1732
+ function watchObject(value, changed, { immediate = false, deep = false } = {}) {
1733
+ if (deep)
1734
+ return deepWatch(value, changed, { immediate });
1735
+ return proxy.effect `watch:object`(() => {
1736
+ proxy.dependant(value);
1737
+ if (immediate)
1738
+ changed(value);
1739
+ immediate = true;
1740
+ });
1741
+ }
1742
+ function watchCallBack(value, changed, { immediate = false, deep = false } = {}) {
1743
+ let oldValue = unsetYet;
1744
+ let deepCleanup;
1745
+ const cbCleanup = proxy.effect `watch:callback`(proxy.markWithRoot((access) => {
1746
+ const newValue = value(access);
1747
+ if (oldValue !== newValue) {
1748
+ const old = oldValue;
1749
+ if (old === unsetYet) {
1750
+ if (immediate)
1751
+ proxy.untracked `watch:changed`(() => changed(newValue));
1752
+ }
1753
+ else
1754
+ proxy.untracked `watch:changed`(() => changed(newValue, old));
1755
+ }
1756
+ oldValue = newValue;
1757
+ if (deep) {
1758
+ if (deepCleanup)
1759
+ deepCleanup();
1760
+ deepCleanup = deepWatch(newValue, (value) => changed(value, value));
1761
+ }
1762
+ }, value));
1763
+ return (() => {
1764
+ cbCleanup();
1765
+ if (deepCleanup)
1766
+ deepCleanup();
1767
+ });
1768
+ }
1769
+ //#endregion
1770
+ //#region when
1771
+ /**
1772
+ * Returns a promise that resolves when the predicate returns a truthy value.
1773
+ * The predicate is evaluated reactively — it re-runs whenever its dependencies change.
1774
+ * @param predicate - Reactive function that returns a value; resolves when truthy
1775
+ * @param timeout - Optional timeout in milliseconds — rejects if condition is not met within this duration
1776
+ * @returns Promise that resolves with the first truthy return value
1777
+ */
1778
+ function when(predicate, timeout) {
1779
+ return new Promise((resolve, reject) => {
1780
+ let timer;
1781
+ const stop = proxy.effect `watch:when`((access) => {
1782
+ try {
1783
+ const value = predicate(access);
1784
+ if (value) {
1785
+ if (timer !== undefined)
1786
+ clearTimeout(timer);
1787
+ timer = undefined;
1788
+ queueMicrotask(() => stop());
1789
+ resolve(value);
1790
+ }
1791
+ }
1792
+ catch (error) {
1793
+ if (timer !== undefined)
1794
+ clearTimeout(timer);
1795
+ timer = undefined;
1796
+ reject(error);
1797
+ }
1798
+ });
1799
+ if (timeout !== undefined) {
1800
+ timer = setTimeout(() => {
1801
+ stop();
1802
+ timer = undefined;
1803
+ reject(new Error(`when: timed out after ${timeout}ms`));
1804
+ }, timeout);
1805
+ }
1806
+ });
1807
+ }
1808
+ //#endregion
1809
+ //#region nonReactive
1810
+ /**
1811
+ * Mark an object as non-reactive. This object and all its properties will never be made reactive.
1812
+ * @param obj - The object to mark as non-reactive
1813
+ */
1814
+ function shallowNonReactive(obj) {
1815
+ obj = proxy.unwrap(obj);
1816
+ if (proxy.isNonReactive(obj))
1817
+ return obj;
1818
+ obj[proxy.unreactiveProperties] = true;
1819
+ return obj;
1820
+ }
1821
+ function unreactiveApplication(arg1, ...args) {
1822
+ return typeof arg1 === 'object'
1823
+ ? shallowNonReactive(arg1)
1824
+ : ((original) => {
1825
+ // Copy the parent's unreactive properties if they exist
1826
+ const parentMarker = original.prototype[proxy.unreactiveProperties];
1827
+ // If parent is fully unreactive, child is too
1828
+ if (parentMarker === true) {
1829
+ original.prototype[proxy.unreactiveProperties] = true;
1830
+ }
1831
+ else {
1832
+ const set = new Set(parentMarker || []);
1833
+ // Add all arguments (including the first one)
1834
+ set.add(arg1);
1835
+ for (const arg of args)
1836
+ set.add(arg);
1837
+ proxy.addUnreactiveProps(original.prototype, set);
1838
+ }
1839
+ return original; // Return the class
1840
+ });
1841
+ }
1842
+ /**
1843
+ * Decorator that marks classes or properties as non-reactive
1844
+ * Prevents objects from being made reactive
1845
+ */
1846
+ const unreactive = proxy.decorator({
1847
+ class(original) {
1848
+ original.prototype[proxy.unreactiveProperties] = true;
1849
+ },
1850
+ default: unreactiveApplication,
1851
+ });
1852
+ //#endregion
1853
+ //#region resource
1854
+ function lazyInit(resource, load) {
1855
+ const creation = proxy.effectHistory.active;
1856
+ let fresh = true;
1857
+ return new Proxy(resource, {
1858
+ [Symbol.toStringTag]: 'LazyInit',
1859
+ get(target, prop) {
1860
+ if (fresh) {
1861
+ proxy.captured(creation, load)();
1862
+ fresh = false;
1863
+ }
1864
+ return target[prop];
1865
+ },
1866
+ });
1867
+ }
1868
+ /**
1869
+ * Creates a reactive resource that automatically tracks async state.
1870
+ * @param fetcher - Async function that returns the value. Reactive dependencies are tracked.
1871
+ * @param options - Resource options (initialValue)
1872
+ * @returns Reactive Resource object with value, loading, error, latest properties
1873
+ */
1874
+ function resource(fetcher, options = {}) {
1875
+ const resource = proxy.reactive({
1876
+ value: options.initialValue,
1877
+ loading: true,
1878
+ error: undefined,
1879
+ latest: options.initialValue,
1880
+ reload() {
1881
+ reloadSignal.value++;
1882
+ },
1883
+ });
1884
+ const reloadSignal = proxy.reactive({ value: 0 });
1885
+ // Solve race conditions: make sure a new fast request is not overloaded by a slow old one
1886
+ let counter = 0;
1887
+ return lazyInit(resource, () => {
1888
+ proxy.link(resource, proxy.effect `watch:resource`((access) => {
1889
+ // Track reload signal to enable manual reloading
1890
+ void reloadSignal.value;
1891
+ const id = ++counter;
1892
+ resource.loading = true;
1893
+ resource.error = undefined;
1894
+ try {
1895
+ const result = fetcher(access);
1896
+ if (result instanceof Promise) {
1897
+ resource.promise = result
1898
+ .then((val) => {
1899
+ if (id === counter) {
1900
+ resource.value = val;
1901
+ resource.latest = val;
1902
+ resource.loading = false;
1903
+ }
1904
+ })
1905
+ .catch((err) => {
1906
+ if (id === counter) {
1907
+ resource.error = err;
1908
+ resource.loading = false;
1909
+ }
1910
+ });
1911
+ }
1912
+ else {
1913
+ resource.promise = Promise.resolve();
1914
+ resource.value = result;
1915
+ resource.latest = result;
1916
+ resource.loading = false;
1917
+ }
1918
+ }
1919
+ catch (err) {
1920
+ resource.promise = Promise.reject(err);
1921
+ resource.error = err;
1922
+ resource.loading = false;
1923
+ }
1924
+ }));
1925
+ });
1926
+ }
1927
+ //#endregion
1928
+
1929
+ /**
1930
+ * Converts an iterator to a generator that yields reactive values
1931
+ */
1932
+ function* makeReactiveIterator(iterator) {
1933
+ let result = iterator.next();
1934
+ while (!result.done) {
1935
+ yield proxy.reactive(result.value);
1936
+ result = iterator.next();
1937
+ }
1938
+ }
1939
+ /**
1940
+ * Converts an iterator of key-value pairs to a generator that yields reactive key-value pairs
1941
+ */
1942
+ function* makeReactiveEntriesIterator(iterator) {
1943
+ let result = iterator.next();
1944
+ while (!result.done) {
1945
+ const [key, value] = result.value;
1946
+ yield [proxy.reactive(key), proxy.reactive(value)];
1947
+ result = iterator.next();
1948
+ }
1949
+ }
1950
+
1951
+ function* index(i, { length = true } = {}) {
1952
+ if (length)
1953
+ yield 'length';
1954
+ yield i;
1955
+ }
1956
+ class Indexer extends Array {
1957
+ get(i) {
1958
+ proxy.dependant(this, i);
1959
+ return proxy.reactive(this[i]);
1960
+ }
1961
+ // Returns undefined intentionally: signals the proxy handler that notifications
1962
+ // were already dispatched via touched(), preventing double notification
1963
+ set(i, value) {
1964
+ const added = i >= this.length;
1965
+ this[i] = value;
1966
+ proxy.touched(this, { type: 'set', prop: i }, index(i, { length: added }));
1967
+ }
1968
+ }
1969
+ const indexLess = { get: proxy.FoolProof.get, set: proxy.FoolProof.set };
1970
+ // Fast numeric-string check: first char is a digit (0-9)
1971
+ function asIndex(prop) {
1972
+ const c = prop.charCodeAt(0);
1973
+ if (c < 48 || c > 57)
1974
+ return -1; // not 0-9
1975
+ const n = +prop; // coerce — faster than parseInt, handles "0", "12", etc.
1976
+ return n === (n | 0) && n >= 0 ? n : -1;
1977
+ }
1978
+ Object.assign(proxy.FoolProof, {
1979
+ get(obj, prop, receiver) {
1980
+ if (Array.isArray(obj) && typeof prop === 'string') {
1981
+ const i = asIndex(prop);
1982
+ if (i >= 0)
1983
+ return Indexer.prototype.get.call(obj, i);
1984
+ }
1985
+ return indexLess.get(obj, prop, receiver);
1986
+ },
1987
+ set(obj, prop, value, receiver) {
1988
+ if (Array.isArray(obj) && typeof prop === 'string') {
1989
+ const i = asIndex(prop);
1990
+ if (i >= 0)
1991
+ return Indexer.prototype.set.call(obj, i, value);
1992
+ }
1993
+ return indexLess.set(obj, prop, value, receiver);
1994
+ },
1995
+ });
1996
+ class ReactiveArray extends Array {
1997
+ toJSON() {
1998
+ return this;
1999
+ }
2000
+ }
2001
+ /**
2002
+ * This is a wrapper class for Array that adds reactive behavior.
2003
+ * It extends Array and overrides methods to add reactive behavior, while making sure that the internal representation is not reactive.
2004
+ */
2005
+ let ReactiveArrayWrapper = (() => {
2006
+ var _a;
2007
+ let _classSuper = Array;
2008
+ let _instanceExtraInitializers = [];
2009
+ let _fill_decorators;
2010
+ let _copyWithin_decorators;
2011
+ let _pop_decorators;
2012
+ let _push_decorators;
2013
+ let _reverse_decorators;
2014
+ let _shift_decorators;
2015
+ let _sort_decorators;
2016
+ let _splice_decorators;
2017
+ let _unshift_decorators;
2018
+ return _a = class ReactiveArrayWrapper extends _classSuper {
2019
+ at(index) {
2020
+ return proxy.reactive(super.at(index));
2021
+ }
2022
+ concat(...items) {
2023
+ return proxy.reactive(super.concat(...items.map(proxy.unwrap)));
2024
+ }
2025
+ entries() {
2026
+ proxy.dependant(this, proxy.keysOf);
2027
+ return makeReactiveEntriesIterator(super.entries());
2028
+ }
2029
+ every(predicate, thisArg) {
2030
+ return super.every((v, i, a) => predicate.call(thisArg, proxy.reactive(v), i, a), thisArg);
2031
+ }
2032
+ fill(value, start, end) {
2033
+ return super.fill(proxy.unwrap(value), start, end);
2034
+ }
2035
+ copyWithin(target, start, end) {
2036
+ return super.copyWithin(target, start, end);
2037
+ }
2038
+ filter(predicate, thisArg) {
2039
+ return proxy.reactive(super.filter((v, i, a) => predicate.call(thisArg, proxy.reactive(v), i, a), thisArg));
2040
+ }
2041
+ find(predicate, thisArg) {
2042
+ return proxy.reactive(super.find((v, i, a) => predicate.call(thisArg, proxy.reactive(v), i, a), thisArg));
2043
+ }
2044
+ findIndex(predicate, thisArg) {
2045
+ return super.findIndex((v, i, a) => predicate.call(thisArg, proxy.reactive(v), i, a), thisArg);
2046
+ }
2047
+ findLast(predicate, thisArg) {
2048
+ return proxy.reactive(super.findLast((v, i, a) => predicate.call(thisArg, proxy.reactive(v), i, a), thisArg));
2049
+ }
2050
+ findLastIndex(predicate, thisArg) {
2051
+ return super.findLastIndex((v, i, a) => predicate.call(thisArg, proxy.reactive(v), i, a), thisArg);
2052
+ }
2053
+ flat(depth) {
2054
+ proxy.dependant(this, proxy.keysOf);
2055
+ return proxy.reactive(super.flat(depth));
2056
+ }
2057
+ flatMap(callbackfn, thisArg) {
2058
+ return proxy.reactive(super.flatMap((v, i, a) => proxy.unwrap(callbackfn.call(thisArg, proxy.reactive(v), i, a)), thisArg));
2059
+ }
2060
+ forEach(callbackfn, thisArg) {
2061
+ super.forEach((v, i, a) => {
2062
+ callbackfn.call(thisArg, proxy.reactive(v), i, a);
2063
+ }, thisArg);
2064
+ }
2065
+ includes(searchElement, fromIndex) {
2066
+ return arguments.length > 1
2067
+ ? super.includes(proxy.unwrap(searchElement), fromIndex)
2068
+ : super.includes(proxy.unwrap(searchElement));
2069
+ }
2070
+ indexOf(searchElement, fromIndex) {
2071
+ return arguments.length > 1
2072
+ ? super.indexOf(proxy.unwrap(searchElement), fromIndex)
2073
+ : super.indexOf(proxy.unwrap(searchElement));
2074
+ }
2075
+ join(separator) {
2076
+ return super.join(separator);
2077
+ }
2078
+ keys() {
2079
+ proxy.dependant(this, 'length');
2080
+ return super.keys();
2081
+ }
2082
+ lastIndexOf(searchElement, fromIndex) {
2083
+ return arguments.length > 1
2084
+ ? super.lastIndexOf(proxy.unwrap(searchElement), fromIndex)
2085
+ : super.lastIndexOf(proxy.unwrap(searchElement));
2086
+ }
2087
+ map(callbackfn, thisArg) {
2088
+ return proxy.reactive(super.map((v, i, a) => proxy.unwrap(callbackfn.call(thisArg, proxy.reactive(v), i, a)), thisArg));
2089
+ }
2090
+ pop() {
2091
+ return proxy.reactive(super.pop());
2092
+ }
2093
+ push(...items) {
2094
+ return super.push(...items.map(proxy.unwrap));
2095
+ }
2096
+ reduce(callbackfn, initialValue) {
2097
+ return proxy.reactive(arguments.length > 1
2098
+ ? super.reduce((acc, v, i, a) => proxy.unwrap(callbackfn(acc, proxy.reactive(v), i, a)), initialValue)
2099
+ : super.reduce((acc, v, i, a) => proxy.unwrap(callbackfn(acc, proxy.reactive(v), i, a))));
2100
+ }
2101
+ reduceRight(callbackfn, initialValue) {
2102
+ return proxy.reactive(arguments.length > 1
2103
+ ? super.reduceRight((acc, v, i, a) => proxy.unwrap(callbackfn(acc, proxy.reactive(v), i, a)), initialValue)
2104
+ : super.reduceRight((acc, v, i, a) => proxy.unwrap(callbackfn(acc, proxy.reactive(v), i, a))));
2105
+ }
2106
+ reverse() {
2107
+ return proxy.reactive(super.reverse());
2108
+ }
2109
+ shift() {
2110
+ return proxy.reactive(super.shift());
2111
+ }
2112
+ slice(start, end) {
2113
+ return proxy.reactive(super.slice(start, end));
2114
+ }
2115
+ some(predicate, thisArg) {
2116
+ return super.some((v, i, a) => predicate.call(thisArg, proxy.reactive(v), i, a), thisArg);
2117
+ }
2118
+ sort(compareFn) {
2119
+ const wrappedCompare = compareFn
2120
+ ? (a, b) => compareFn(proxy.reactive(a), proxy.reactive(b))
2121
+ : undefined;
2122
+ return super.sort(wrappedCompare);
2123
+ }
2124
+ splice(start, deleteCount, ...items) {
2125
+ if (arguments.length > 2)
2126
+ return proxy.reactive(super.splice(start, deleteCount, ...items.map(proxy.unwrap)));
2127
+ if (arguments.length === 2)
2128
+ return proxy.reactive(super.splice(start, deleteCount));
2129
+ if (arguments.length === 1)
2130
+ return proxy.reactive(super.splice(start));
2131
+ return proxy.reactive([]);
2132
+ }
2133
+ unshift(...items) {
2134
+ return super.unshift(...items.map(proxy.unwrap));
2135
+ }
2136
+ values() {
2137
+ proxy.dependant(this, proxy.keysOf);
2138
+ return makeReactiveIterator(super.values());
2139
+ }
2140
+ [(_fill_decorators = [proxy.atomic], _copyWithin_decorators = [proxy.atomic], _pop_decorators = [proxy.atomic], _push_decorators = [proxy.atomic], _reverse_decorators = [proxy.atomic], _shift_decorators = [proxy.atomic], _sort_decorators = [proxy.atomic], _splice_decorators = [proxy.atomic], _unshift_decorators = [proxy.atomic], Symbol.iterator)]() {
2141
+ proxy.dependant(this, proxy.keysOf);
2142
+ return makeReactiveIterator(super[Symbol.iterator]());
2143
+ }
2144
+ toReversed() {
2145
+ return proxy.reactive(super.toReversed());
2146
+ }
2147
+ toSorted(compareFn) {
2148
+ const wrappedCompare = compareFn
2149
+ ? (a, b) => compareFn(proxy.reactive(a), proxy.reactive(b))
2150
+ : undefined;
2151
+ return proxy.reactive(super.toSorted(wrappedCompare));
2152
+ }
2153
+ toSpliced(start, deleteCount, ...items) {
2154
+ if (arguments.length > 2)
2155
+ return proxy.reactive(super.toSpliced(start, deleteCount, ...items.map(proxy.unwrap)));
2156
+ if (arguments.length === 2)
2157
+ return proxy.reactive(super.toSpliced(start, deleteCount));
2158
+ if (arguments.length === 1)
2159
+ return proxy.reactive(super.toSpliced(start));
2160
+ return proxy.reactive([...this]);
2161
+ }
2162
+ with(index, value) {
2163
+ return proxy.reactive(super.with(index, proxy.unwrap(value)));
2164
+ }
2165
+ constructor() {
2166
+ super(...arguments);
2167
+ proxy.__runInitializers(this, _instanceExtraInitializers);
2168
+ }
2169
+ },
2170
+ (() => {
2171
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
2172
+ proxy.__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);
2173
+ proxy.__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);
2174
+ proxy.__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);
2175
+ proxy.__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);
2176
+ proxy.__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);
2177
+ proxy.__esDecorate(_a, null, _shift_decorators, { kind: "method", name: "shift", static: false, private: false, access: { has: obj => "shift" in obj, get: obj => obj.shift }, metadata: _metadata }, null, _instanceExtraInitializers);
2178
+ proxy.__esDecorate(_a, null, _sort_decorators, { kind: "method", name: "sort", static: false, private: false, access: { has: obj => "sort" in obj, get: obj => obj.sort }, metadata: _metadata }, null, _instanceExtraInitializers);
2179
+ proxy.__esDecorate(_a, null, _splice_decorators, { kind: "method", name: "splice", static: false, private: false, access: { has: obj => "splice" in obj, get: obj => obj.splice }, metadata: _metadata }, null, _instanceExtraInitializers);
2180
+ proxy.__esDecorate(_a, null, _unshift_decorators, { kind: "method", name: "unshift", static: false, private: false, access: { has: obj => "unshift" in obj, get: obj => obj.unshift }, metadata: _metadata }, null, _instanceExtraInitializers);
2181
+ if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
2182
+ })(),
2183
+ _a;
2184
+ })();
2185
+
2186
+ /**
2187
+ * Reactive wrapper around JavaScript's WeakMap class
2188
+ * Only tracks individual key operations, no size tracking (WeakMap limitation)
2189
+ */
2190
+ class ReactiveWeakMap extends WeakMap {
2191
+ // Implement WeakMap interface methods with reactivity
2192
+ delete(key) {
2193
+ const hadKey = this.has(key);
2194
+ const result = super.delete(key);
2195
+ if (hadKey)
2196
+ proxy.touched1(proxy.contentRef(this), { type: 'del', prop: key }, key);
2197
+ return result;
2198
+ }
2199
+ get(key) {
2200
+ proxy.dependant(proxy.contentRef(this), key);
2201
+ return proxy.reactive(super.get(key));
2202
+ }
2203
+ has(key) {
2204
+ proxy.dependant(proxy.contentRef(this), key);
2205
+ return super.has(key);
2206
+ }
2207
+ set(key, value) {
2208
+ const hadKey = this.has(key);
2209
+ const oldValue = this.get(key);
2210
+ const reactiveValue = proxy.reactive(value);
2211
+ this.set(key, reactiveValue);
2212
+ if (!hadKey || oldValue !== reactiveValue) {
2213
+ proxy.notifyPropertyChange(proxy.contentRef(this), key, oldValue, reactiveValue, hadKey);
2214
+ }
2215
+ return this;
2216
+ }
2217
+ }
2218
+ /**
2219
+ * Reactive wrapper around JavaScript's Map class
2220
+ * Tracks size changes, individual key operations, and collection-wide operations
2221
+ */
2222
+ class ReactiveMap extends Map {
2223
+ // Implement Map interface methods with reactivity
2224
+ get size() {
2225
+ proxy.dependant(this, 'size'); // The ReactiveMap instance still goes through proxy
2226
+ return super.size;
2227
+ }
2228
+ clear() {
2229
+ const hadEntries = this.size > 0;
2230
+ super.clear();
2231
+ if (hadEntries) {
2232
+ const evolution = { type: 'bunch', method: 'clear' };
2233
+ // Clear triggers all effects since all keys are affected
2234
+ proxy.batch(() => {
2235
+ proxy.touched1(this, evolution, 'size');
2236
+ proxy.touched(proxy.contentRef(this), evolution);
2237
+ });
2238
+ }
2239
+ }
2240
+ entries() {
2241
+ proxy.dependant(proxy.contentRef(this));
2242
+ return makeReactiveEntriesIterator(this.entries());
2243
+ }
2244
+ forEach(callbackfn, thisArg) {
2245
+ proxy.dependant(proxy.contentRef(this));
2246
+ this.forEach(callbackfn, thisArg);
2247
+ }
2248
+ keys() {
2249
+ proxy.dependant(proxy.contentRef(this), proxy.keysOf);
2250
+ return this.keys();
2251
+ }
2252
+ values() {
2253
+ proxy.dependant(proxy.contentRef(this));
2254
+ return makeReactiveIterator(this.values());
2255
+ }
2256
+ [Symbol.iterator]() {
2257
+ proxy.dependant(proxy.contentRef(this));
2258
+ const it = Map.prototype[Symbol.iterator].call(this);
2259
+ const nativeNext = it.next.bind(it);
2260
+ it.next = () => {
2261
+ const result = nativeNext();
2262
+ if (result.done)
2263
+ return result;
2264
+ const [key, value] = result.value;
2265
+ return { value: [proxy.reactive(key), proxy.reactive(value)], done: false };
2266
+ };
2267
+ return it;
2268
+ }
2269
+ // Implement Map methods with reactivity
2270
+ delete(key) {
2271
+ const hadKey = this.has(key);
2272
+ const result = super.delete(key);
2273
+ if (hadKey) {
2274
+ const evolution = { type: 'del', prop: key };
2275
+ proxy.batch(() => {
2276
+ proxy.touched1(proxy.contentRef(this), evolution, key);
2277
+ proxy.touched1(this, evolution, 'size');
2278
+ });
2279
+ }
2280
+ return result;
2281
+ }
2282
+ get(key) {
2283
+ proxy.dependant(proxy.contentRef(this), key);
2284
+ return proxy.reactive(super.get(key));
2285
+ }
2286
+ has(key) {
2287
+ proxy.dependant(proxy.contentRef(this), key);
2288
+ return super.has(key);
2289
+ }
2290
+ set(key, value) {
2291
+ const hadKey = this.has(key);
2292
+ const oldValue = this.get(key);
2293
+ const reactiveValue = proxy.reactive(value);
2294
+ super.set(key, reactiveValue);
2295
+ if (!hadKey || oldValue !== reactiveValue) {
2296
+ proxy.batch(() => {
2297
+ proxy.notifyPropertyChange(proxy.contentRef(this), key, oldValue, reactiveValue, hadKey);
2298
+ // Also notify size change for Map (WeakMap doesn't track size)
2299
+ const evolution = { type: hadKey ? 'set' : 'add', prop: key };
2300
+ proxy.touched1(this, evolution, 'size');
2301
+ });
2302
+ }
2303
+ return this;
2304
+ }
2305
+ }
2306
+
2307
+ /**
2308
+ * Reactive wrapper around JavaScript's WeakSet class
2309
+ * Only tracks individual value operations, no size tracking (WeakSet limitation)
2310
+ */
2311
+ class ReactiveWeakSet extends WeakSet {
2312
+ add(value) {
2313
+ const had = this.has(value);
2314
+ super.add(value);
2315
+ if (!had) {
2316
+ // touch the specific value and the collection view
2317
+ proxy.touched1(proxy.contentRef(this), { type: 'add', prop: value }, value);
2318
+ // no size/allProps for WeakSet
2319
+ }
2320
+ return this;
2321
+ }
2322
+ delete(value) {
2323
+ const had = this.has(value);
2324
+ const res = super.delete(value);
2325
+ if (had)
2326
+ proxy.touched1(proxy.contentRef(this), { type: 'del', prop: value }, value);
2327
+ return res;
2328
+ }
2329
+ has(value) {
2330
+ proxy.dependant(proxy.contentRef(this), value);
2331
+ return super.has(value);
2332
+ }
2333
+ }
2334
+ /**
2335
+ * Reactive wrapper around JavaScript's Set class
2336
+ * Tracks size changes, individual value operations, and collection-wide operations
2337
+ */
2338
+ class ReactiveSet extends Set {
2339
+ get size() {
2340
+ // size depends on the wrapper instance, like Map counterpart
2341
+ proxy.dependant(this, 'size');
2342
+ return this.size;
2343
+ }
2344
+ add(value) {
2345
+ const had = this.has(value);
2346
+ const reactiveValue = proxy.reactive(value);
2347
+ super.add(reactiveValue);
2348
+ if (!had) {
2349
+ const evolution = { type: 'add', prop: reactiveValue };
2350
+ // touch for value-specific and aggregate dependencies
2351
+ proxy.batch(() => {
2352
+ proxy.touched1(proxy.contentRef(this), evolution, reactiveValue);
2353
+ proxy.touched1(this, evolution, 'size');
2354
+ });
2355
+ }
2356
+ return this;
2357
+ }
2358
+ clear() {
2359
+ const hadEntries = this.size > 0;
2360
+ super.clear();
2361
+ if (hadEntries) {
2362
+ const evolution = { type: 'bunch', method: 'clear' };
2363
+ proxy.batch(() => {
2364
+ proxy.touched1(this, evolution, 'size');
2365
+ proxy.touched(proxy.contentRef(this), evolution);
2366
+ });
2367
+ }
2368
+ }
2369
+ delete(value) {
2370
+ const had = this.has(value);
2371
+ const res = super.delete(value);
2372
+ if (had) {
2373
+ const evolution = { type: 'del', prop: value };
2374
+ proxy.batch(() => {
2375
+ proxy.touched1(proxy.contentRef(this), evolution, value);
2376
+ proxy.touched1(this, evolution, 'size');
2377
+ });
2378
+ }
2379
+ return res;
2380
+ }
2381
+ has(value) {
2382
+ proxy.dependant(proxy.contentRef(this), value);
2383
+ return this.has(value);
2384
+ }
2385
+ entries() {
2386
+ proxy.dependant(proxy.contentRef(this));
2387
+ return makeReactiveEntriesIterator(this.entries());
2388
+ }
2389
+ forEach(callbackfn, thisArg) {
2390
+ proxy.dependant(proxy.contentRef(this));
2391
+ this.forEach(callbackfn, thisArg);
2392
+ }
2393
+ keys() {
2394
+ proxy.dependant(proxy.contentRef(this));
2395
+ return makeReactiveIterator(this.keys());
2396
+ }
2397
+ values() {
2398
+ proxy.dependant(proxy.contentRef(this));
2399
+ return makeReactiveIterator(this.values());
2400
+ }
2401
+ [Symbol.iterator]() {
2402
+ proxy.dependant(proxy.contentRef(this));
2403
+ const it = Set.prototype[Symbol.iterator].call(this);
2404
+ const nativeNext = it.next.bind(it);
2405
+ it.next = () => {
2406
+ const result = nativeNext();
2407
+ if (result.done)
2408
+ return result;
2409
+ return { value: proxy.reactive(result.value), done: false };
2410
+ };
2411
+ return it;
2412
+ }
2413
+ }
2414
+
2415
+ // Register native collection types to use specialized reactive wrappers
2416
+ proxy.metaProtos.set(Array, ReactiveArray.prototype);
2417
+ proxy.metaProtos.set(Set, ReactiveSet.prototype);
2418
+ proxy.metaProtos.set(WeakSet, ReactiveWeakSet.prototype);
2419
+ proxy.metaProtos.set(Map, ReactiveMap.prototype);
2420
+ proxy.metaProtos.set(WeakMap, ReactiveWeakMap.prototype);
2421
+ proxy.wrapProtos.set(Array, ReactiveArrayWrapper.prototype);
2422
+ /**
2423
+ * Object containing internal reactive system state for debugging and profiling
2424
+ */
2425
+ const profileInfo = {
2426
+ objectToProxy: proxy.objectToProxy,
2427
+ proxyToObject: proxy.proxyToObject,
2428
+ effectToReactiveObjects: proxy.effectToReactiveObjects,
2429
+ watchers: proxy.watchers,
2430
+ objectParents: proxy.objectParents,
2431
+ objectsWithDeepWatchers: proxy.objectsWithDeepWatchers,
2432
+ deepWatchers: proxy.deepWatchers,
2433
+ effectToDeepWatchedObjects: proxy.effectToDeepWatchedObjects,
2434
+ };
2435
+
2436
+ // In order to avoid async re-entrance, we could use zone.js or something like that.
2437
+ const syncCalculating = [];
2438
+ /**
2439
+ * Decorator that caches the result of a getter method and only recomputes when dependencies change
2440
+ * Prevents circular dependencies and provides automatic cache invalidation
2441
+ */
2442
+ const cached = proxy.decorator({
2443
+ getter(original, _target, propertyKey) {
2444
+ return function () {
2445
+ const alreadyCalculating = syncCalculating.findIndex((c) => c.object === this && c.prop === propertyKey);
2446
+ if (alreadyCalculating > -1)
2447
+ throw new Error(`Circular dependency detected: ${syncCalculating
2448
+ .slice(alreadyCalculating)
2449
+ .map((c) => `${c.object.constructor.name}.${String(c.prop)}`)
2450
+ .join(' -> ')} -> again`);
2451
+ syncCalculating.push({ object: this, prop: propertyKey });
2452
+ try {
2453
+ const rv = original.call(this);
2454
+ cache(this, propertyKey, rv);
2455
+ return rv;
2456
+ }
2457
+ finally {
2458
+ syncCalculating.pop();
2459
+ }
2460
+ };
2461
+ },
2462
+ });
2463
+ /**
2464
+ * Checks if a property is cached (has a cached value)
2465
+ * @param object - The object to check
2466
+ * @param propertyKey - The property key to check
2467
+ * @returns True if the property has a cached value
2468
+ */
2469
+ function isCached(object, propertyKey) {
2470
+ return !!Object.getOwnPropertyDescriptor(object, propertyKey);
2471
+ }
2472
+ /**
2473
+ * Caches a value for a property on an object
2474
+ * @param object - The object to cache the value on
2475
+ * @param propertyKey - The property key to cache
2476
+ * @param value - The value to cache
2477
+ */
2478
+ function cache(object, propertyKey, value) {
2479
+ Object.defineProperty(object, propertyKey, { value });
2480
+ }
2481
+ function descriptorBase(descriptor) {
2482
+ return function descriptorDecorator(...properties) {
2483
+ return (Base) => {
2484
+ return class extends Base {
2485
+ constructor(...args) {
2486
+ super(...args);
2487
+ for (const key of properties) {
2488
+ const existing = Object.getOwnPropertyDescriptor(this, key);
2489
+ Object.defineProperty(this, key, Object.assign(existing || {}, descriptor));
2490
+ }
2491
+ }
2492
+ };
2493
+ };
2494
+ };
2495
+ }
2496
+ /**
2497
+ * Creates a decorator that modifies property descriptors for specified properties
2498
+ * @param descriptor - The descriptor properties to apply
2499
+ * @returns A class decorator that applies the descriptor to specified properties
2500
+ */
2501
+ const descriptor = Object.assign(descriptorBase, {
2502
+ /**
2503
+ * enumerable: true
2504
+ */
2505
+ get enumerable() {
2506
+ return descriptorBase({ enumerable: true });
2507
+ },
2508
+ /**
2509
+ * enumerable: false
2510
+ */
2511
+ get hidden() {
2512
+ return descriptorBase({ enumerable: false });
2513
+ },
2514
+ /**
2515
+ * configurable: true
2516
+ */
2517
+ get configurable() {
2518
+ return descriptorBase({ configurable: true });
2519
+ },
2520
+ /**
2521
+ * configurable: false
2522
+ */
2523
+ get frozen() {
2524
+ return descriptorBase({ configurable: false });
2525
+ },
2526
+ /**
2527
+ * writable: true
2528
+ */
2529
+ get writable() {
2530
+ return descriptorBase({ writable: true });
2531
+ },
2532
+ /**
2533
+ * writable: false
2534
+ */
2535
+ get readonly() {
2536
+ return descriptorBase({ writable: false });
2537
+ },
2538
+ });
2539
+ /**
2540
+ * Decorator that marks methods, properties, or classes as deprecated
2541
+ * Provides warning messages when deprecated items are used
2542
+ */
2543
+ const deprecated = Object.assign(proxy.decorator({
2544
+ method(original, _target, propertyKey) {
2545
+ return function (...args) {
2546
+ deprecated.warn(this, propertyKey);
2547
+ return original.apply(this, args);
2548
+ };
2549
+ },
2550
+ getter(original, _target, propertyKey) {
2551
+ return function () {
2552
+ deprecated.warn(this, propertyKey);
2553
+ return original.call(this);
2554
+ };
2555
+ },
2556
+ setter(original, _target, propertyKey) {
2557
+ return function (value) {
2558
+ deprecated.warn(this, propertyKey);
2559
+ return original.call(this, value);
2560
+ };
2561
+ },
2562
+ class(original) {
2563
+ return class extends original {
2564
+ constructor(...args) {
2565
+ super(...args);
2566
+ deprecated.warn(this, 'constructor');
2567
+ }
2568
+ };
2569
+ },
2570
+ default(message) {
2571
+ return proxy.decorator({
2572
+ method(original, _target, propertyKey) {
2573
+ return function (...args) {
2574
+ deprecated.warn(this, propertyKey, message);
2575
+ return original.apply(this, args);
2576
+ };
2577
+ },
2578
+ getter(original, _target, propertyKey) {
2579
+ return function () {
2580
+ deprecated.warn(this, propertyKey, message);
2581
+ return original.call(this);
2582
+ };
2583
+ },
2584
+ setter(original, _target, propertyKey) {
2585
+ return function (value) {
2586
+ deprecated.warn(this, propertyKey, message);
2587
+ return original.call(this, value);
2588
+ };
2589
+ },
2590
+ class(original) {
2591
+ return class extends original {
2592
+ constructor(...args) {
2593
+ super(...args);
2594
+ deprecated.warn(this, 'constructor', message);
2595
+ }
2596
+ };
2597
+ },
2598
+ });
2599
+ },
2600
+ }), {
2601
+ warn: (target, propertyKey, message) => {
2602
+ proxy.options.warn(`${target.constructor.name}.${String(propertyKey)} is deprecated${message ? `: ${message}` : ''}`);
2603
+ },
2604
+ });
2605
+ /**
2606
+ * Creates a debounced method decorator that delays execution until after the delay period has passed
2607
+ * @param delay - The delay in milliseconds
2608
+ * @returns A method decorator that debounces method calls
2609
+ */
2610
+ function debounce(delay) {
2611
+ return proxy.decorator({
2612
+ method(original, _target, _propertyKey) {
2613
+ let timeoutId = null;
2614
+ return function (...args) {
2615
+ // Clear existing timeout
2616
+ if (timeoutId) {
2617
+ clearTimeout(timeoutId);
2618
+ }
2619
+ // Set new timeout
2620
+ timeoutId = setTimeout(() => {
2621
+ original.apply(this, args);
2622
+ timeoutId = null;
2623
+ }, delay);
2624
+ };
2625
+ },
2626
+ });
2627
+ }
2628
+ /**
2629
+ * Creates a throttled method decorator that limits execution to once per delay period
2630
+ * @param delay - The delay in milliseconds
2631
+ * @returns A method decorator that throttles method calls
2632
+ */
2633
+ function throttle(delay) {
2634
+ return proxy.decorator({
2635
+ method(original, _target, _propertyKey) {
2636
+ let lastCallTime = 0;
2637
+ let timeoutId = null;
2638
+ return function (...args) {
2639
+ const now = Date.now();
2640
+ // If enough time has passed since last call, execute immediately
2641
+ if (now - lastCallTime >= delay) {
2642
+ // Clear any pending timeout since we're executing now
2643
+ if (timeoutId) {
2644
+ clearTimeout(timeoutId);
2645
+ timeoutId = null;
2646
+ }
2647
+ lastCallTime = now;
2648
+ return original.apply(this, args);
2649
+ }
2650
+ // Otherwise, schedule execution for when the delay period ends
2651
+ if (!timeoutId) {
2652
+ const remainingTime = delay - (now - lastCallTime);
2653
+ const scheduledArgs = [...args]; // Capture args at scheduling time
2654
+ timeoutId = setTimeout(() => {
2655
+ lastCallTime = Date.now();
2656
+ original.apply(this, scheduledArgs);
2657
+ timeoutId = null;
2658
+ }, remainingTime);
2659
+ }
2660
+ };
2661
+ },
2662
+ });
2663
+ }
2664
+
2665
+ var version$1 = "1.0.13";
2666
+ var pkg = {
2667
+ version: version$1};
2668
+
2669
+ const { version } = pkg;
2670
+ const GLOBAL_MUTTS_KEY = '__MUTTS_INSTANCE__';
2671
+ const runtimeGlobals = globalThis;
2672
+ const globalScope = (typeof globalThis !== 'undefined'
2673
+ ? globalThis
2674
+ : runtimeGlobals.window
2675
+ ? runtimeGlobals.window
2676
+ : runtimeGlobals.global
2677
+ ? runtimeGlobals.global
2678
+ : false);
2679
+ if (globalScope) {
2680
+ let source = 'mutts/index';
2681
+ try {
2682
+ if (runtimeGlobals.__filename)
2683
+ source = runtimeGlobals.__filename;
2684
+ else if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunks/index-CAdnMJev.cjs', document.baseURI).href)) }) !== 'undefined' && (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunks/index-CAdnMJev.cjs', document.baseURI).href))) {
2685
+ source = (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunks/index-CAdnMJev.cjs', document.baseURI).href));
2686
+ }
2687
+ }
2688
+ catch (_e) { }
2689
+ const currentSourceInfo = { version, source, timestamp: Date.now() };
2690
+ if (globalScope[GLOBAL_MUTTS_KEY]) {
2691
+ const existing = globalScope[GLOBAL_MUTTS_KEY];
2692
+ throw new Error(`[Mutts] Multiple instances detected!\n` +
2693
+ `Existing instance: ${JSON.stringify(existing, null, 2)}\n` +
2694
+ `New instance: ${JSON.stringify(currentSourceInfo, null, 2)}\n` +
2695
+ `This usually happens when 'mutts' is both installed as a dependency and bundled, ` +
2696
+ `or when different versions are loaded. ` +
2697
+ `Please check your build configuration (aliases, externals) to ensure a single source of truth.`);
2698
+ }
2699
+ globalScope[GLOBAL_MUTTS_KEY] = currentSourceInfo;
2700
+ }
2701
+
2702
+ exports.ArrayReadForward = ArrayReadForward;
2703
+ exports.Destroyable = Destroyable;
2704
+ exports.DestructionError = DestructionError;
2705
+ exports.Eventful = Eventful;
2706
+ exports.Indexable = Indexable;
2707
+ exports.allocated = allocated;
2708
+ exports.allocatedValues = allocatedValues;
2709
+ exports.arrayDiff = arrayDiff;
2710
+ exports.attend = attend;
2711
+ exports.cache = cache;
2712
+ exports.cached = cached;
2713
+ exports.callOnGC = callOnGC;
2714
+ exports.chainPromise = chainPromise;
2715
+ exports.debounce = debounce;
2716
+ exports.deepWatch = deepWatch;
2717
+ exports.deprecated = deprecated;
2718
+ exports.descriptor = descriptor;
2719
+ exports.destructor = destructor;
2720
+ exports.forwardArray = forwardArray;
2721
+ exports.getAt = getAt;
2722
+ exports.isCached = isCached;
2723
+ exports.lift = lift;
2724
+ exports.memoize = memoize;
2725
+ exports.morph = morph;
2726
+ exports.organize = organize;
2727
+ exports.organized = organized;
2728
+ exports.profileInfo = profileInfo;
2729
+ exports.resource = resource;
2730
+ exports.setAt = setAt;
2731
+ exports.throttle = throttle;
2732
+ exports.unreactive = unreactive;
2733
+ exports.watch = watch;
2734
+ exports.when = when;
2735
+ //# sourceMappingURL=index-CAdnMJev.cjs.map