mutts 1.0.10 → 1.0.12

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