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