r-state-tree 0.4.7 → 0.6.0

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.
@@ -1,5 +1,5 @@
1
- import { batch, Signal, signal, computed as computed$1, untracked, effect } from "@preact/signals-core";
2
- import { Signal as Signal2, batch as batch2, effect as effect2, signal as signal2, untracked as untracked2 } from "@preact/signals-core";
1
+ import { batch, signal as signal$1, Signal, computed as computed$1, untracked, effect } from "@preact/signals-core";
2
+ import { Signal as Signal2, batch as batch2, effect as effect2, untracked as untracked2 } from "@preact/signals-core";
3
3
  var lib = {};
4
4
  var hasRequiredLib;
5
5
  function requireLib() {
@@ -25,7 +25,6 @@ var StoreCfgTypes = /* @__PURE__ */ ((StoreCfgTypes2) => {
25
25
  return StoreCfgTypes2;
26
26
  })(StoreCfgTypes || {});
27
27
  var ObservableCfgTypes = /* @__PURE__ */ ((ObservableCfgTypes2) => {
28
- ObservableCfgTypes2["observable"] = "observable";
29
28
  ObservableCfgTypes2["computed"] = "computed";
30
29
  return ObservableCfgTypes2;
31
30
  })(ObservableCfgTypes || {});
@@ -66,26 +65,29 @@ function isPropertyKey(val) {
66
65
  return typeof val === "string" || typeof val === "number" || typeof val === "symbol";
67
66
  }
68
67
  function getPropertyType(key, obj) {
69
- const hasMetadata = obj.constructor[Symbol.metadata] !== void 0;
68
+ const ctor = obj.constructor;
69
+ const hasMetadata = ctor != null && ctor[Symbol.metadata] !== void 0;
70
70
  const descriptor = getPropertyDescriptor$1(obj, key);
71
71
  if (descriptor?.value && typeof descriptor.value === "function") {
72
72
  return "action";
73
73
  }
74
- const isGetter = descriptor && (typeof descriptor.get === "function" || typeof descriptor.set === "function");
74
+ const isAccessor = descriptor && (typeof descriptor.get === "function" || typeof descriptor.set === "function");
75
75
  if (!hasMetadata) {
76
- if (isGetter) {
76
+ if (descriptor?.get) {
77
77
  return "computed";
78
78
  }
79
+ if (isAccessor) {
80
+ return null;
81
+ }
79
82
  return "observable";
80
83
  }
81
84
  const metadata = obj.constructor[Symbol.metadata];
82
- if (metadata && metadata[key]) {
83
- const config = metadata[key];
85
+ const config = metadata?.[key];
86
+ if (config) {
84
87
  switch (config.type) {
85
88
  case ObservableCfgTypes.computed:
86
89
  return "computed";
87
90
  case ModelCfgTypes.state:
88
- case ObservableCfgTypes.observable:
89
91
  case ModelCfgTypes.id:
90
92
  case ModelCfgTypes.modelRef:
91
93
  case CommonCfgTypes.child:
@@ -93,7 +95,7 @@ function getPropertyType(key, obj) {
93
95
  return "observable";
94
96
  }
95
97
  }
96
- return null;
98
+ return isAccessor ? null : "observable";
97
99
  }
98
100
  function getPropertyDescriptor$1(obj, key) {
99
101
  let node = obj;
@@ -122,7 +124,7 @@ class Administration {
122
124
  atom;
123
125
  valuesMap;
124
126
  isObserved = false;
125
- forceObservedAtoms;
127
+ forceObservedAtom;
126
128
  constructor(source2) {
127
129
  this.atom = createObservedAtom();
128
130
  this.source = source2;
@@ -132,13 +134,9 @@ class Administration {
132
134
  );
133
135
  }
134
136
  flushChange() {
135
- if (this.forceObservedAtoms?.length) {
136
- batch(() => {
137
- for (let i = 0; i < this.forceObservedAtoms.length; i++) {
138
- this.forceObservedAtoms[i].reportChanged();
139
- }
140
- });
141
- this.forceObservedAtoms = void 0;
137
+ if (this.forceObservedAtom) {
138
+ this.forceObservedAtom.reportChanged();
139
+ this.forceObservedAtom = void 0;
142
140
  }
143
141
  }
144
142
  getNode() {
@@ -147,9 +145,7 @@ class Administration {
147
145
  reportChanged() {
148
146
  this.atom.reportChanged();
149
147
  }
150
- reportObserveDeep() {
151
- }
152
- reportObserved(deep = false) {
148
+ reportObserved() {
153
149
  const entry = circularRefSet == null;
154
150
  if (entry) {
155
151
  circularRefSet = /* @__PURE__ */ new WeakSet();
@@ -157,15 +153,10 @@ class Administration {
157
153
  return;
158
154
  }
159
155
  circularRefSet.add(this);
160
- const atom = createAtom();
161
- if (!this.forceObservedAtoms) {
162
- this.forceObservedAtoms = [];
163
- }
164
- this.forceObservedAtoms.push(atom);
165
- atom.reportObserved();
166
- if (deep) {
167
- this.reportObserveDeep();
156
+ if (!this.forceObservedAtom) {
157
+ this.forceObservedAtom = createAtom();
168
158
  }
159
+ this.forceObservedAtom.reportObserved();
169
160
  if (entry) {
170
161
  circularRefSet = null;
171
162
  }
@@ -228,6 +219,9 @@ class NodeMap {
228
219
  reportChanged(key, value) {
229
220
  return this.get(key)?.reportChanged(value);
230
221
  }
222
+ keys() {
223
+ return this.map?.keys() ?? [];
224
+ }
231
225
  }
232
226
  class AtomMap extends NodeMap {
233
227
  createNode() {
@@ -245,31 +239,34 @@ class ObjectAdministration extends Administration {
245
239
  valuesMap;
246
240
  computedMap;
247
241
  types;
242
+ isWriting = false;
248
243
  static proxyTraps = {
249
244
  has(target, name) {
250
245
  const adm = getAdministration(target);
251
- if (!(name in Object.prototype) && isPropertyKey(name))
246
+ if (isPropertyKey(name) && (!(name in Object.prototype) || Object.prototype.hasOwnProperty.call(adm.source, name)))
252
247
  return adm.has(name);
253
248
  return Reflect.has(adm.source, name);
254
249
  },
255
250
  get(target, name) {
256
251
  const adm = getAdministration(target);
257
- if (!(name in Object.prototype) && isPropertyKey(name) && (typeof adm.source !== "function" || name !== "prototype")) {
258
- return adm.read(name);
252
+ if (isPropertyKey(name) && (!(name in Object.prototype) || Object.prototype.hasOwnProperty.call(adm.source, name)) && (typeof adm.source !== "function" || name !== "prototype")) {
253
+ return adm.read(name, arguments[2]);
259
254
  }
260
- return Reflect.get(adm.source, name, adm.proxy);
255
+ return Reflect.get(adm.source, name, arguments[2]);
261
256
  },
262
257
  set(target, name, value) {
263
258
  if (!isPropertyKey(name)) return false;
264
259
  const adm = getAdministration(target);
265
- adm.write(name, value);
266
- return true;
260
+ const receiver = arguments[3];
261
+ if (receiver === adm.proxy) {
262
+ return adm.write(name, value);
263
+ }
264
+ return Reflect.set(adm.source, name, value, receiver);
267
265
  },
268
266
  deleteProperty(target, name) {
269
267
  if (!isPropertyKey(name)) return false;
270
268
  const adm = getAdministration(target);
271
- adm.remove(name);
272
- return true;
269
+ return adm.remove(name);
273
270
  },
274
271
  ownKeys(target) {
275
272
  const adm = getAdministration(target);
@@ -278,21 +275,47 @@ class ObjectAdministration extends Administration {
278
275
  adm.atom.reportObserved();
279
276
  });
280
277
  return Reflect.ownKeys(adm.source);
278
+ },
279
+ defineProperty(target, name, descriptor) {
280
+ const adm = getAdministration(target);
281
+ if (adm.isWriting) {
282
+ return Reflect.defineProperty(adm.source, name, descriptor);
283
+ }
284
+ const result = Reflect.defineProperty(adm.source, name, descriptor);
285
+ if (result) {
286
+ batch(() => {
287
+ adm.types.delete(name);
288
+ adm.flushChange();
289
+ adm.keysAtom.reportChanged();
290
+ adm.hasMap.reportChanged(name);
291
+ if ("value" in descriptor) {
292
+ if (isObservable(descriptor.value)) {
293
+ adm.explicitObservables.add(name);
294
+ } else {
295
+ adm.explicitObservables.delete(name);
296
+ }
297
+ adm.valuesMap.reportChanged(name, descriptor.value);
298
+ } else {
299
+ adm.valuesMap.reportChanged(name, void 0);
300
+ }
301
+ });
302
+ }
303
+ return result;
281
304
  }
282
305
  };
283
306
  constructor(source2 = {}) {
284
307
  super(source2);
285
308
  this.keysAtom = createAtom();
286
309
  this.hasMap = new AtomMap(this.atom);
287
- this.valuesMap = new SignalMap();
310
+ this.valuesMap = new SignalMap(this.atom);
288
311
  this.types = /* @__PURE__ */ new Map();
289
312
  }
290
313
  get(key) {
291
314
  return Reflect.get(this.source, key, this.proxy);
292
315
  }
293
316
  set(key, value) {
294
- batch(() => {
295
- Reflect.set(this.source, key, value, this.proxy);
317
+ return batch(() => {
318
+ return Reflect.set(this.source, key, value, this.proxy);
296
319
  });
297
320
  }
298
321
  getComputed(key) {
@@ -320,17 +343,6 @@ class ObjectAdministration extends Administration {
320
343
  }
321
344
  return type;
322
345
  }
323
- reportObserveDeep() {
324
- Object.getOwnPropertyNames(this.source).forEach((name) => {
325
- const type = this.getType(name);
326
- if (type === "observable") {
327
- const value = this.source[name];
328
- if (value && typeof value === "object") {
329
- getAdministration(getObservable(value))?.reportObserved();
330
- }
331
- }
332
- });
333
- }
334
346
  reportChanged() {
335
347
  this.types.clear();
336
348
  super.reportChanged();
@@ -345,10 +357,10 @@ class ObjectAdministration extends Administration {
345
357
  }
346
358
  return resolveNode(this.valuesMap.getOrCreate(key, this.source[key]));
347
359
  }
348
- read(key) {
360
+ read(key, receiver = this.proxy) {
349
361
  const type = this.getType(key);
350
362
  if (type === null) {
351
- return this.get(key);
363
+ return Reflect.get(this.source, key, receiver);
352
364
  }
353
365
  switch (type) {
354
366
  case "observable":
@@ -361,35 +373,66 @@ class ObjectAdministration extends Administration {
361
373
  this.hasMap.reportObserved(key);
362
374
  }
363
375
  if (type === "observable") {
364
- return getObservable(this.get(key));
376
+ const value = Reflect.get(this.source, key, receiver);
377
+ const shouldWrap = this.explicitObservables.has(key) || isObservable(value);
378
+ if (shouldWrap && value && typeof value === "object" && !Object.isFrozen(value)) {
379
+ const desc = getPropertyDescriptor$1(this.source, key);
380
+ if (desc && !desc.configurable && !desc.writable) {
381
+ return value;
382
+ }
383
+ const existingAdm = getAdministration(value);
384
+ if (existingAdm) {
385
+ return existingAdm.proxy;
386
+ }
387
+ }
388
+ return value;
365
389
  }
366
- return getAction(this.get(key));
390
+ return getAction(
391
+ Reflect.get(this.source, key, receiver)
392
+ );
367
393
  }
368
394
  case "computed": {
369
- return this.callComputed(key);
395
+ if (receiver === this.proxy) {
396
+ return this.callComputed(key);
397
+ }
398
+ this.atom.reportObserved();
399
+ return Reflect.get(this.source, key, receiver);
370
400
  }
371
401
  default:
372
402
  throw new Error(`unknown type passed to configure`);
373
403
  }
374
404
  }
405
+ explicitObservables = /* @__PURE__ */ new Set();
375
406
  write(key, newValue) {
376
407
  const type = this.getType(key);
377
408
  if (type === null) {
378
- this.set(key, newValue);
379
- return;
409
+ return this.set(key, newValue);
380
410
  }
381
411
  if (type === "computed") {
382
- batch(() => this.set(key, newValue));
383
- return;
412
+ return batch(() => this.set(key, newValue));
384
413
  }
385
414
  const had = key in this.source;
386
415
  const oldValue = this.get(key);
387
416
  const targetValue = getSource(newValue);
417
+ const oldExplicit = this.explicitObservables.has(key);
418
+ const newExplicit = isObservable(newValue);
419
+ if (newExplicit) {
420
+ this.explicitObservables.add(key);
421
+ } else {
422
+ this.explicitObservables.delete(key);
423
+ }
388
424
  if (type === "action" && typeof newValue !== "function" || type === "observable" && typeof newValue === "function") {
389
425
  this.types.delete(key);
390
426
  }
391
- if (!had || (isObservable(oldValue) ? oldValue !== newValue : oldValue !== targetValue)) {
392
- this.set(key, targetValue);
427
+ const changed = !had || !isObservable(oldValue) && oldExplicit !== newExplicit || (isObservable(oldValue) ? oldValue !== newValue : oldValue !== targetValue);
428
+ if (changed) {
429
+ this.isWriting = true;
430
+ try {
431
+ const result = this.set(key, targetValue);
432
+ if (!result) return false;
433
+ } finally {
434
+ this.isWriting = false;
435
+ }
393
436
  batch(() => {
394
437
  this.flushChange();
395
438
  if (!had) {
@@ -398,7 +441,9 @@ class ObjectAdministration extends Administration {
398
441
  }
399
442
  this.valuesMap.reportChanged(key, newValue);
400
443
  });
444
+ return true;
401
445
  }
446
+ return true;
402
447
  }
403
448
  has(key) {
404
449
  this.atom.reportObserved();
@@ -408,39 +453,27 @@ class ObjectAdministration extends Administration {
408
453
  return key in this.source;
409
454
  }
410
455
  remove(key) {
411
- if (!(key in this.source)) return;
412
- delete this.source[key];
413
- batch(() => {
414
- this.flushChange();
415
- this.valuesMap.reportChanged(key, void 0);
416
- this.keysAtom.reportChanged();
417
- this.hasMap.reportChanged(key);
418
- this.valuesMap.delete(key);
419
- });
456
+ if (!(key in this.source)) return true;
457
+ const result = Reflect.deleteProperty(this.source, key);
458
+ if (result) {
459
+ batch(() => {
460
+ this.flushChange();
461
+ this.valuesMap.reportChanged(key, void 0);
462
+ this.keysAtom.reportChanged();
463
+ this.hasMap.reportChanged(key);
464
+ this.valuesMap.delete(key);
465
+ });
466
+ }
467
+ return result;
420
468
  }
421
469
  }
422
470
  class PreactObjectAdministration extends ObjectAdministration {
423
- static proxyTraps = Object.assign(
424
- {},
425
- ObjectAdministration.proxyTraps,
426
- {
427
- get(target, prop, proxy) {
428
- if (!(prop in target) && (typeof prop === "string" || typeof prop === "number") && String(prop)[0] === "$") {
429
- return getSignal(proxy, prop.substring(1));
430
- }
431
- return ObjectAdministration.proxyTraps.get?.apply(
432
- null,
433
- arguments
434
- );
435
- }
436
- }
437
- );
438
471
  }
439
472
  function createObservedAtom() {
440
473
  let value = 0;
441
474
  const callbacks = /* @__PURE__ */ new Set();
442
475
  let observing = false;
443
- const signal22 = new Signal(value, {
476
+ const signal2 = new Signal(value, {
444
477
  watched() {
445
478
  callbacks.forEach((callback) => callback(true));
446
479
  observing = true;
@@ -451,12 +484,12 @@ function createObservedAtom() {
451
484
  }
452
485
  });
453
486
  return {
454
- node: signal22,
487
+ node: signal2,
455
488
  reportObserved() {
456
- return signal22.value;
489
+ return signal2.value;
457
490
  },
458
491
  reportChanged() {
459
- return signal22.value = ++value;
492
+ return signal2.value = ++value;
460
493
  },
461
494
  get observing() {
462
495
  return observing;
@@ -470,7 +503,7 @@ function createObservedAtom() {
470
503
  };
471
504
  }
472
505
  function createSignal(initialValue) {
473
- const s = signal(initialValue);
506
+ const s = signal$1(initialValue);
474
507
  return {
475
508
  node: s,
476
509
  reportChanged(value) {
@@ -489,7 +522,7 @@ function createSignal(initialValue) {
489
522
  }
490
523
  function createAtom() {
491
524
  let value = 0;
492
- const s = signal(value);
525
+ const s = signal$1(value);
493
526
  return {
494
527
  node: s,
495
528
  reportChanged() {
@@ -572,12 +605,11 @@ function createComputed(fn, context = null) {
572
605
  }
573
606
  };
574
607
  }
575
- function observable(value, context) {
576
- if (context && typeof context === "object" && "kind" in context) {
577
- context.metadata[context.name] = { type: "observable" };
578
- return value;
579
- }
580
- return getObservable(value);
608
+ function observable(obj) {
609
+ return getObservable(obj);
610
+ }
611
+ function signal(value) {
612
+ return signal$1(value);
581
613
  }
582
614
  function computed(value, context) {
583
615
  if (context && typeof context === "object" && "kind" in context) {
@@ -589,29 +621,24 @@ function computed(value, context) {
589
621
  function source(obj) {
590
622
  return getSource(obj);
591
623
  }
592
- class Observable {
593
- constructor() {
594
- return getObservableClassInstance(this);
595
- }
596
- }
597
624
  function reportChanged(obj) {
598
625
  const adm = getAdministration(obj);
599
626
  adm.reportChanged();
600
627
  return obj;
601
628
  }
602
- function reportObserved(obj, opts) {
629
+ function reportObserved(obj) {
603
630
  const adm = getAdministration(obj);
604
- adm.reportObserved(opts?.deep);
631
+ adm.reportObserved();
605
632
  return obj;
606
633
  }
607
634
  const signalMap = /* @__PURE__ */ new WeakMap();
608
635
  function getSignal(obj, key) {
609
636
  const node = getInternalNode(obj, key);
610
637
  if (node instanceof Signal) {
611
- let signal22 = signalMap.get(node);
612
- if (!signal22) {
613
- signal22 = new Signal();
614
- Object.defineProperties(signal22, {
638
+ let signal2 = signalMap.get(node);
639
+ if (!signal2) {
640
+ signal2 = new Signal();
641
+ Object.defineProperties(signal2, {
615
642
  value: {
616
643
  get() {
617
644
  return obj[key];
@@ -626,9 +653,9 @@ function getSignal(obj, key) {
626
653
  }
627
654
  }
628
655
  });
629
- signalMap.set(node, signal22);
656
+ signalMap.set(node, signal2);
630
657
  }
631
- return signal22;
658
+ return signal2;
632
659
  }
633
660
  return node;
634
661
  }
@@ -637,17 +664,36 @@ class CollectionAdministration extends Administration {
637
664
  hasMap;
638
665
  valuesMap;
639
666
  keysAtom;
667
+ isWeak;
668
+ strongTracking = null;
669
+ weakTracking = null;
640
670
  static proxyTraps = {
641
671
  get(target, name) {
642
672
  const adm = getAdministration(target);
643
- if (name === "size" && "size" in adm.source) {
673
+ if (name === "size" && !adm.isWeak && "size" in adm.source) {
644
674
  return adm.size;
645
675
  }
646
676
  const val = adm.source[name];
647
677
  const collectionMethods = adm.constructor.methods;
648
- if (collectionMethods.hasOwnProperty(name) && typeof val === "function") {
678
+ if (collectionMethods.hasOwnProperty(name)) {
679
+ if (adm.isWeak && !isValidWeakMethod(name)) {
680
+ return val;
681
+ }
649
682
  return collectionMethods[name];
650
683
  }
684
+ if (typeof val === "function") {
685
+ return function() {
686
+ if (process.env.NODE_ENV !== "production") {
687
+ console.warn(
688
+ `r-state-tree: Calling uninstrumented collection method "${String(
689
+ name
690
+ )}". Reactivity is not guaranteed for this call.`
691
+ );
692
+ }
693
+ const result = val.apply(adm.source, arguments);
694
+ return result === adm.source ? adm.proxy : result;
695
+ };
696
+ }
651
697
  return val;
652
698
  }
653
699
  };
@@ -662,17 +708,71 @@ class CollectionAdministration extends Administration {
662
708
  entries: createMethod$1("entries"),
663
709
  keys: createMethod$1("keys"),
664
710
  values: createMethod$1("values"),
665
- [Symbol.iterator]: createMethod$1(Symbol.iterator)
711
+ [Symbol.iterator]: createMethod$1(Symbol.iterator),
712
+ // New ES methods
713
+ union: createGenericMethod("union"),
714
+ intersection: createGenericMethod("intersection"),
715
+ difference: createGenericMethod("difference"),
716
+ symmetricDifference: createGenericMethod("symmetricDifference"),
717
+ isSubsetOf: createGenericMethod("isSubsetOf"),
718
+ isSupersetOf: createGenericMethod("isSupersetOf"),
719
+ isDisjointFrom: createGenericMethod("isDisjointFrom")
666
720
  };
667
721
  constructor(source2) {
668
722
  super(source2);
669
723
  this.hasMap = new AtomMap(this.atom);
670
- this.valuesMap = new SignalMap();
724
+ this.valuesMap = new SignalMap(this.atom);
671
725
  this.keysAtom = createAtom();
672
726
  this.isMap = typeof source2.set === "function" && typeof source2.get === "function";
727
+ this.isWeak = source2 instanceof WeakMap || source2 instanceof WeakSet;
728
+ if (this.isWeak) {
729
+ this.weakTracking = /* @__PURE__ */ new WeakSet();
730
+ } else {
731
+ this.strongTracking = /* @__PURE__ */ new Set();
732
+ }
733
+ }
734
+ trackExplicitObservable(key) {
735
+ if (this.isWeak) {
736
+ if (isNonPrimitive(key)) {
737
+ this.weakTracking.add(key);
738
+ }
739
+ } else {
740
+ this.strongTracking.add(key);
741
+ }
742
+ }
743
+ untrackExplicitObservable(key) {
744
+ if (this.isWeak) {
745
+ if (isNonPrimitive(key)) {
746
+ this.weakTracking.delete(key);
747
+ }
748
+ } else {
749
+ this.strongTracking.delete(key);
750
+ }
751
+ }
752
+ hasExplicitObservable(key) {
753
+ if (this.isWeak) {
754
+ return isNonPrimitive(key) && this.weakTracking.has(key);
755
+ }
756
+ return this.strongTracking.has(key);
757
+ }
758
+ getProxyVariant(key) {
759
+ if (!isNonPrimitive(key)) return void 0;
760
+ const adm = getAdministration(key);
761
+ if (adm && adm.proxy && adm.proxy !== key) {
762
+ return adm.proxy;
763
+ }
764
+ return void 0;
765
+ }
766
+ getExistingKey(key) {
767
+ const target = getSource(key);
768
+ if (this.source.has(target)) return target;
769
+ if (this.source.has(key)) return key;
770
+ const proxy = this.getProxyVariant(key);
771
+ if (proxy !== void 0 && this.source.has(proxy)) return proxy;
772
+ return void 0;
673
773
  }
674
774
  hasEntry(key) {
675
- return this.source.has(getSource(key)) || this.source.has(key);
775
+ return this.getExistingKey(key) !== void 0;
676
776
  }
677
777
  onCollectionChange(key) {
678
778
  batch(() => {
@@ -681,13 +781,6 @@ class CollectionAdministration extends Administration {
681
781
  this.flushChange();
682
782
  });
683
783
  }
684
- reportObserveDeep() {
685
- this.source.forEach?.((value) => {
686
- if (value && typeof value === "object") {
687
- getAdministration(getObservable(value))?.reportObserved();
688
- }
689
- });
690
- }
691
784
  getNode(key) {
692
785
  if (key == null) {
693
786
  return resolveNode(this.atom);
@@ -708,13 +801,12 @@ class CollectionAdministration extends Administration {
708
801
  this.keysAtom.reportObserved();
709
802
  this.atom.reportObserved();
710
803
  this.source.forEach((value, key) => {
711
- const observed = getObservable(this.isMap ? key : value);
712
- callbackFn.call(
713
- thisArg,
714
- this.isMap ? this.get(key) : observed,
715
- observed,
716
- this.proxy
717
- );
804
+ if (this.isMap) {
805
+ callbackFn.call(thisArg, this.get(key), key, this.proxy);
806
+ return;
807
+ }
808
+ const wrapped = this.wrapSetValue(key);
809
+ callbackFn.call(thisArg, wrapped, wrapped, this.proxy);
718
810
  });
719
811
  }
720
812
  get size() {
@@ -723,43 +815,68 @@ class CollectionAdministration extends Administration {
723
815
  return this.source.size;
724
816
  }
725
817
  add(value) {
818
+ const target = getSource(value);
819
+ if (isObservable(value)) {
820
+ this.trackExplicitObservable(target);
821
+ } else {
822
+ this.untrackExplicitObservable(target);
823
+ this.untrackExplicitObservable(value);
824
+ }
726
825
  if (!this.hasEntry(value)) {
727
- const target = getSource(value);
728
826
  this.source.add(target);
729
827
  this.onCollectionChange(target);
730
828
  }
731
829
  return this;
732
830
  }
733
831
  delete(value) {
734
- if (this.hasEntry(value)) {
735
- const target = getSource(value);
736
- this.source.delete(target);
737
- this.source.delete(value);
738
- this.onCollectionChange(target);
739
- return true;
832
+ const existingKey = this.getExistingKey(value);
833
+ if (existingKey === void 0) return false;
834
+ const target = getSource(value);
835
+ this.untrackExplicitObservable(target);
836
+ this.untrackExplicitObservable(value);
837
+ const proxy = this.getProxyVariant(value);
838
+ if (proxy !== void 0) this.untrackExplicitObservable(proxy);
839
+ this.source.delete(existingKey);
840
+ this.source.delete(target);
841
+ this.source.delete(value);
842
+ if (proxy !== void 0) this.source.delete(proxy);
843
+ this.onCollectionChange(target);
844
+ return true;
845
+ }
846
+ wrapSetValue(value) {
847
+ if (this.hasExplicitObservable(value)) {
848
+ if (value && typeof value === "object" && !Object.isFrozen(value)) {
849
+ const existingAdm = getAdministration(value);
850
+ if (existingAdm) return existingAdm.proxy;
851
+ }
740
852
  }
741
- return false;
853
+ return value;
742
854
  }
743
855
  has(value) {
744
856
  this.atom.reportObserved();
745
- if (this.atom.observing || true) {
746
- const target = getSource(value);
747
- this.hasMap.reportObserved(target);
748
- }
857
+ const target = getSource(value);
858
+ this.hasMap.reportObserved(target);
749
859
  return this.hasEntry(value);
750
860
  }
751
861
  entries() {
862
+ this.keysAtom.reportObserved();
863
+ this.atom.reportObserved();
752
864
  const self = this;
753
- const keys = this.keys();
865
+ const iterator = this.source.entries();
754
866
  return {
755
867
  [Symbol.iterator]: function() {
756
868
  return this;
757
869
  },
758
870
  next() {
759
- const { done, value } = keys.next();
871
+ const { done, value } = iterator.next();
872
+ if (done) return { done: true, value: void 0 };
873
+ const [key, val] = value;
760
874
  return {
761
- done,
762
- value: done ? void 0 : [value, self.isMap ? self.get(value) : value]
875
+ done: false,
876
+ value: [
877
+ self.isMap ? key : self.wrapSetValue(key),
878
+ self.isMap ? self.get(key) : self.wrapSetValue(val)
879
+ ]
763
880
  };
764
881
  }
765
882
  };
@@ -767,19 +884,19 @@ class CollectionAdministration extends Administration {
767
884
  keys() {
768
885
  this.keysAtom.reportObserved();
769
886
  this.atom.reportObserved();
770
- let nextIndex = 0;
771
- const observableKeys = Array.from(this.source.keys()).map(
772
- (o) => getObservable(o)
773
- );
887
+ const self = this;
888
+ const iterator = this.source.keys();
774
889
  return {
775
890
  [Symbol.iterator]: function() {
776
891
  return this;
777
892
  },
778
893
  next() {
779
- return nextIndex < observableKeys.length ? {
780
- value: observableKeys[nextIndex++],
781
- done: false
782
- } : { done: true, value: void 0 };
894
+ const { done, value } = iterator.next();
895
+ if (done) return { done: true, value: void 0 };
896
+ return {
897
+ done: false,
898
+ value: self.isMap ? value : self.wrapSetValue(value)
899
+ };
783
900
  }
784
901
  };
785
902
  }
@@ -787,28 +904,54 @@ class CollectionAdministration extends Administration {
787
904
  const targetKey = getSource(key);
788
905
  const sourceMap = this.source;
789
906
  const has = this.has(key);
790
- const value = sourceMap.get(targetKey) ?? sourceMap.get(key);
791
- if (has) {
907
+ if (!has) return void 0;
908
+ const existingKey = this.getExistingKey(key);
909
+ const value = sourceMap.get(existingKey);
910
+ this.valuesMap.reportObserved(targetKey, value);
911
+ if (key !== targetKey) {
792
912
  this.valuesMap.reportObserved(key, value);
793
- return getObservable(value);
794
913
  }
795
- return void 0;
914
+ const proxyKey = this.getProxyVariant(key);
915
+ if (proxyKey !== void 0 && proxyKey !== key && proxyKey !== targetKey) {
916
+ this.valuesMap.reportObserved(proxyKey, value);
917
+ }
918
+ if (this.hasExplicitObservable(targetKey) || this.hasExplicitObservable(key) || proxyKey !== void 0 && this.hasExplicitObservable(proxyKey)) {
919
+ if (value && typeof value === "object" && !Object.isFrozen(value)) {
920
+ const existingAdm = getAdministration(value);
921
+ if (existingAdm) return existingAdm.proxy;
922
+ }
923
+ }
924
+ return value;
796
925
  }
797
926
  set(key, value) {
798
927
  const targetKey = getSource(key);
799
928
  const targetValue = getSource(value);
800
929
  const sourceMap = this.source;
801
- const hasKey = this.hasEntry(key);
802
- const oldValue = sourceMap.get(targetKey) ?? sourceMap.get(key);
803
- if (!hasKey || isObservable(oldValue) ? oldValue !== value : oldValue !== targetValue) {
930
+ if (isObservable(value)) {
931
+ this.trackExplicitObservable(targetKey);
932
+ } else {
933
+ this.untrackExplicitObservable(targetKey);
934
+ this.untrackExplicitObservable(key);
935
+ }
936
+ const existingKey = this.getExistingKey(key);
937
+ const hasKey = existingKey !== void 0;
938
+ const oldValue = hasKey ? sourceMap.get(existingKey) : void 0;
939
+ if (!hasKey || (isObservable(oldValue) ? oldValue !== value : oldValue !== targetValue)) {
804
940
  batch(() => {
805
941
  this.flushChange();
806
- if (sourceMap.has(key)) {
807
- sourceMap.set(key, targetValue);
942
+ if (existingKey !== void 0) {
943
+ sourceMap.set(existingKey, targetValue);
808
944
  } else {
809
945
  sourceMap.set(targetKey, targetValue);
810
946
  }
811
- this.valuesMap.reportChanged(key, value);
947
+ this.valuesMap.reportChanged(targetKey, value);
948
+ if (key !== targetKey) {
949
+ this.valuesMap.reportChanged(key, value);
950
+ }
951
+ const proxyKey = this.getProxyVariant(key);
952
+ if (proxyKey !== void 0 && proxyKey !== key && proxyKey !== targetKey) {
953
+ this.valuesMap.reportChanged(proxyKey, value);
954
+ }
812
955
  if (!hasKey) {
813
956
  this.hasMap.reportChanged(targetKey);
814
957
  this.keysAtom.reportChanged();
@@ -818,20 +961,22 @@ class CollectionAdministration extends Administration {
818
961
  return this;
819
962
  }
820
963
  values() {
821
- const self = this;
822
- const keys = this.keys();
964
+ this.keysAtom.reportObserved();
965
+ this.atom.reportObserved();
823
966
  if (!this.isMap) {
824
- return keys;
967
+ return this.keys();
825
968
  }
969
+ const entries = this.entries();
826
970
  return {
827
971
  [Symbol.iterator]: function() {
828
972
  return this;
829
973
  },
830
974
  next() {
831
- const { done, value } = keys.next();
975
+ const { done, value } = entries.next();
976
+ if (done) return { done: true, value: void 0 };
832
977
  return {
833
- done,
834
- value: done ? void 0 : self.get(value)
978
+ done: false,
979
+ value: value[1]
835
980
  };
836
981
  }
837
982
  };
@@ -841,53 +986,177 @@ class CollectionAdministration extends Administration {
841
986
  }
842
987
  [Symbol.toStringTag] = "Set";
843
988
  }
989
+ function isValidWeakMethod(name) {
990
+ const n = name;
991
+ return n === "get" || n === "set" || n === "add" || n === "has" || n === "delete";
992
+ }
993
+ function createGenericMethod(name) {
994
+ return function() {
995
+ const adm = getAdministration(this);
996
+ const method = adm.source[name];
997
+ if (typeof method !== "function") return method;
998
+ if (["union", "intersection", "difference", "symmetricDifference"].includes(
999
+ name
1000
+ )) {
1001
+ const other = arguments[0];
1002
+ const result2 = /* @__PURE__ */ new Set();
1003
+ if (name === "union") {
1004
+ for (const item of this) result2.add(item);
1005
+ for (const item of other) result2.add(item);
1006
+ } else if (name === "intersection") {
1007
+ for (const item of this) {
1008
+ if (other.has(item)) result2.add(item);
1009
+ }
1010
+ } else if (name === "difference") {
1011
+ for (const item of this) {
1012
+ if (!other.has(item)) result2.add(item);
1013
+ }
1014
+ } else if (name === "symmetricDifference") {
1015
+ for (const item of this) {
1016
+ if (!other.has(item)) result2.add(item);
1017
+ }
1018
+ for (const item of other) {
1019
+ if (!this.has(item)) result2.add(item);
1020
+ }
1021
+ }
1022
+ return result2;
1023
+ }
1024
+ adm.keysAtom.reportObserved();
1025
+ adm.atom.reportObserved();
1026
+ const args = new Array(arguments.length);
1027
+ for (let i = 0; i < arguments.length; i++) {
1028
+ const arg = arguments[i];
1029
+ args[i] = getSource(arg);
1030
+ if (isObservable(arg)) {
1031
+ reportObserved(arg);
1032
+ }
1033
+ }
1034
+ const result = method.apply(adm.source, args);
1035
+ if (result === adm.source) return adm.proxy;
1036
+ return result;
1037
+ };
1038
+ }
844
1039
  function createMethod$1(method) {
845
1040
  return function() {
846
1041
  const adm = getAdministration(this);
847
- return adm[method].apply(adm, arguments);
1042
+ const result = adm[method].apply(adm, arguments);
1043
+ if (method === "add" || method === "set") {
1044
+ return this;
1045
+ }
1046
+ return result;
848
1047
  };
849
1048
  }
1049
+ function isArrayIndexKey(key) {
1050
+ if (typeof key === "symbol") return false;
1051
+ const keyStr = String(key);
1052
+ const num = Number(keyStr);
1053
+ return Number.isInteger(num) && num >= 0 && num < 4294967295 && // 2^32 - 1
1054
+ String(num) === keyStr;
1055
+ }
850
1056
  class ArrayAdministration extends Administration {
851
1057
  valuesMap;
852
1058
  keysAtom;
1059
+ explicitObservables = /* @__PURE__ */ new Set();
1060
+ syncExplicitObservablesFromSource() {
1061
+ for (let i = 0; i < this.source.length; i++) {
1062
+ const value = this.source[i];
1063
+ if (isObservable(value)) {
1064
+ this.explicitObservables.add(i);
1065
+ }
1066
+ }
1067
+ }
853
1068
  static proxyTraps = {
854
- get(target, name) {
1069
+ get(target, name, receiver) {
855
1070
  const adm = getAdministration(target);
856
1071
  if (name === "length") {
857
1072
  return adm.getArrayLength();
858
1073
  }
859
- if (typeof name === "number") {
860
- return adm.get(name);
861
- }
862
- if (typeof name === "string" && String(parseInt(name)) === name) {
863
- return adm.get(parseInt(name));
1074
+ if (isArrayIndexKey(name)) {
1075
+ return adm.get(Number(name));
864
1076
  }
865
1077
  const arrayMethods = adm.constructor.methods;
866
1078
  if (arrayMethods.hasOwnProperty(name)) {
867
1079
  return arrayMethods[name];
868
1080
  }
869
- return adm.source[name];
1081
+ return Reflect.get(adm.source, name, receiver);
870
1082
  },
871
1083
  set(target, name, value) {
872
1084
  const adm = getAdministration(target);
873
1085
  if (name === "length") {
874
- adm.setArrayLength(value);
875
- } else if (typeof name === "number") {
876
- adm.set(name, value);
877
- } else if (typeof name === "string" && String(parseInt(name)) === name) {
878
- adm.set(parseInt(name), value);
1086
+ return adm.setArrayLength(value);
1087
+ } else if (isArrayIndexKey(name)) {
1088
+ return adm.set(Number(name), value);
879
1089
  } else {
880
- adm.source[name] = value;
1090
+ return Reflect.set(adm.source, name, value, arguments[3]);
881
1091
  }
882
- return true;
1092
+ },
1093
+ defineProperty(target, name, descriptor) {
1094
+ const adm = getAdministration(target);
1095
+ const result = Reflect.defineProperty(adm.source, name, descriptor);
1096
+ if (result) {
1097
+ batch(() => {
1098
+ adm.flushChange();
1099
+ if (name === "length") {
1100
+ adm.keysAtom.reportChanged();
1101
+ adm.atom.reportChanged();
1102
+ } else if (isArrayIndexKey(name)) {
1103
+ const index = Number(name);
1104
+ adm.keysAtom.reportChanged();
1105
+ adm.onArrayChanged(false, index, 1);
1106
+ } else {
1107
+ adm.atom.reportChanged();
1108
+ }
1109
+ });
1110
+ }
1111
+ return result;
1112
+ },
1113
+ deleteProperty(target, name) {
1114
+ const adm = getAdministration(target);
1115
+ const isIndex = isArrayIndexKey(name);
1116
+ const had = name in adm.source;
1117
+ const result = Reflect.deleteProperty(adm.source, name);
1118
+ if (result && had && isIndex) {
1119
+ const index = Number(name);
1120
+ adm.onArrayChanged(true, index, 1);
1121
+ adm.explicitObservables.delete(index);
1122
+ }
1123
+ return result;
1124
+ },
1125
+ ownKeys(target) {
1126
+ const adm = getAdministration(target);
1127
+ batch(() => {
1128
+ adm.keysAtom.reportObserved();
1129
+ adm.atom.reportObserved();
1130
+ });
1131
+ return Reflect.ownKeys(adm.source);
1132
+ },
1133
+ has(target, name) {
1134
+ const adm = getAdministration(target);
1135
+ if (isArrayIndexKey(name)) {
1136
+ const index = Number(name);
1137
+ adm.atom.reportObserved();
1138
+ adm.valuesMap.reportObserved(index, adm.source[index]);
1139
+ return index in adm.source;
1140
+ }
1141
+ return Reflect.has(adm.source, name);
883
1142
  }
884
1143
  };
885
1144
  static methods = {
886
1145
  fill(value, start, end) {
887
1146
  const adm = getAdministration(this);
888
- const oldLength = adm.source.length;
889
- adm.source.fill(value, start, end);
890
- adm.onArrayChanged(oldLength !== adm.source.length, start, end);
1147
+ const shouldTrack = isObservable(value);
1148
+ const targetValue = getSource(value);
1149
+ adm.source.fill(targetValue, start, end);
1150
+ const length = adm.source.length;
1151
+ const from = start == null ? 0 : start < 0 ? Math.max(length + start, 0) : start;
1152
+ const to = end == null ? length : end < 0 ? Math.max(length + end, 0) : Math.min(end, length);
1153
+ for (let i = from; i < to; i++) {
1154
+ if (shouldTrack) adm.explicitObservables.add(i);
1155
+ else adm.explicitObservables.delete(i);
1156
+ }
1157
+ if (from < to) {
1158
+ adm.onArrayChanged(false, from, to - from);
1159
+ }
891
1160
  return this;
892
1161
  },
893
1162
  splice(index, deleteCount, ...newItems) {
@@ -923,16 +1192,43 @@ class ArrayAdministration extends Administration {
923
1192
  },
924
1193
  reverse() {
925
1194
  const adm = getAdministration(this);
1195
+ adm.syncExplicitObservablesFromSource();
1196
+ const flags = new Array(adm.source.length);
1197
+ for (let i = 0; i < flags.length; i++) {
1198
+ flags[i] = adm.explicitObservables.has(i);
1199
+ }
926
1200
  adm.source.reverse();
1201
+ flags.reverse();
1202
+ adm.explicitObservables.clear();
1203
+ for (let i = 0; i < flags.length; i++) {
1204
+ if (flags[i]) adm.explicitObservables.add(i);
1205
+ }
927
1206
  adm.onArrayChanged(false, 0, adm.source.length);
928
1207
  return this;
929
1208
  },
930
1209
  sort(compareFn) {
931
1210
  const adm = getAdministration(this);
932
- adm.onArrayChanged();
933
- adm.source.sort(
934
- compareFn && ((a, b) => compareFn(getObservable(a), getObservable(b)))
935
- );
1211
+ adm.syncExplicitObservablesFromSource();
1212
+ const pairs = new Array(adm.source.length);
1213
+ for (let i = 0; i < adm.source.length; i++) {
1214
+ pairs[i] = {
1215
+ value: this[i],
1216
+ stored: adm.source[i],
1217
+ observed: adm.explicitObservables.has(i)
1218
+ };
1219
+ }
1220
+ const comparator = compareFn ?? ((a, b) => {
1221
+ const as = String(a);
1222
+ const bs = String(b);
1223
+ return as < bs ? -1 : as > bs ? 1 : 0;
1224
+ });
1225
+ pairs.sort((a, b) => comparator(a.value, b.value));
1226
+ adm.explicitObservables.clear();
1227
+ for (let i = 0; i < pairs.length; i++) {
1228
+ adm.source[i] = pairs[i].stored;
1229
+ if (pairs[i].observed) adm.explicitObservables.add(i);
1230
+ }
1231
+ adm.onArrayChanged(false, 0, adm.source.length);
936
1232
  return this;
937
1233
  },
938
1234
  join: createStringMethod("join"),
@@ -944,7 +1240,22 @@ class ArrayAdministration extends Administration {
944
1240
  slice: createCopyMethod("slice"),
945
1241
  concat: createCopyMethod("concat"),
946
1242
  flat: createCopyMethod("flat"),
947
- copyWithin: createCopyMethod("copyWithin"),
1243
+ copyWithin(target, start, end) {
1244
+ const adm = getAdministration(this);
1245
+ adm.syncExplicitObservablesFromSource();
1246
+ const flags = new Array(adm.source.length);
1247
+ for (let i = 0; i < flags.length; i++) {
1248
+ flags[i] = adm.explicitObservables.has(i);
1249
+ }
1250
+ adm.source.copyWithin(target, start, end);
1251
+ flags.copyWithin(target, start, end);
1252
+ adm.explicitObservables.clear();
1253
+ for (let i = 0; i < flags.length; i++) {
1254
+ if (flags[i]) adm.explicitObservables.add(i);
1255
+ }
1256
+ adm.onArrayChanged(false, 0, adm.source.length);
1257
+ return this;
1258
+ },
948
1259
  every: createMapMethod("every"),
949
1260
  forEach: createMapMethod("forEach"),
950
1261
  map: createMapMethod("map"),
@@ -958,17 +1269,9 @@ class ArrayAdministration extends Administration {
958
1269
  };
959
1270
  constructor(source2 = []) {
960
1271
  super(source2);
961
- this.valuesMap = new SignalMap();
1272
+ this.valuesMap = new SignalMap(this.atom);
962
1273
  this.keysAtom = createAtom();
963
1274
  }
964
- reportObserveDeep() {
965
- for (let i = 0; i < this.source.length; i++) {
966
- const value = this.source[i];
967
- if (value && typeof value === "object") {
968
- getAdministration(getObservable(value))?.reportObserved();
969
- }
970
- }
971
- }
972
1275
  getNode(key) {
973
1276
  if (key == null) {
974
1277
  return this.atom;
@@ -978,49 +1281,98 @@ class ArrayAdministration extends Administration {
978
1281
  get(index) {
979
1282
  this.atom.reportObserved();
980
1283
  this.valuesMap.reportObserved(index, this.source[index]);
981
- return getObservable(this.source[index]);
1284
+ return this._getEffectiveValue(index);
1285
+ }
1286
+ _getEffectiveValue(index) {
1287
+ const value = this.source[index];
1288
+ if (value && typeof value === "object" && !Object.isFrozen(value)) {
1289
+ if (this.explicitObservables.has(index)) {
1290
+ const existingAdm = getAdministration(value);
1291
+ if (existingAdm) {
1292
+ if (existingAdm.proxy !== value) {
1293
+ const desc = Object.getOwnPropertyDescriptor(this.source, index);
1294
+ if (desc && !desc.configurable && !desc.writable) {
1295
+ if (process.env.NODE_ENV !== "production") {
1296
+ console.warn(
1297
+ `r-state-tree: cannot return an observable proxy for arr[${index}] because it is a non-configurable, non-writable data property; returning the raw value to uphold Proxy invariants.`
1298
+ );
1299
+ }
1300
+ this.explicitObservables.delete(index);
1301
+ return value;
1302
+ }
1303
+ }
1304
+ return existingAdm.proxy;
1305
+ }
1306
+ }
1307
+ }
1308
+ return value;
982
1309
  }
983
1310
  set(index, newValue) {
984
1311
  const values = this.source;
985
1312
  const targetValue = getSource(newValue);
986
- if (index < values.length) {
1313
+ const oldLength = values.length;
1314
+ let changed = true;
1315
+ if (index < oldLength) {
987
1316
  const oldValue = values[index];
988
- const changed = isObservable(oldValue) ? newValue !== oldValue : targetValue !== oldValue;
989
- if (changed) {
990
- values[index] = targetValue;
991
- this.onArrayChanged(false, index, 1);
992
- }
993
- } else if (index === values.length) {
994
- this.spliceWithArray(index, 0, [newValue]);
1317
+ const oldExplicit = this.explicitObservables.has(index);
1318
+ const newExplicit = isObservable(newValue);
1319
+ changed = !isObservable(oldValue) && oldExplicit !== newExplicit || (isObservable(oldValue) ? newValue !== oldValue : targetValue !== oldValue);
1320
+ }
1321
+ if (!changed) return true;
1322
+ const result = Reflect.set(values, index, targetValue);
1323
+ if (!result) return false;
1324
+ const newLength = values.length;
1325
+ const lengthChanged = newLength !== oldLength;
1326
+ if (isObservable(newValue)) {
1327
+ this.explicitObservables.add(index);
995
1328
  } else {
996
- throw new Error(
997
- `Index out of bounds, ${index} is larger than ${values.length}`
998
- );
1329
+ this.explicitObservables.delete(index);
999
1330
  }
1331
+ this.onArrayChanged(lengthChanged, index, 1);
1332
+ return true;
1000
1333
  }
1001
1334
  getArrayLength() {
1002
1335
  this.atom.reportObserved();
1003
1336
  this.keysAtom.reportObserved();
1004
1337
  return this.source.length;
1005
1338
  }
1006
- setArrayLength(newLength) {
1007
- if (typeof newLength !== "number" || newLength < 0)
1008
- throw new Error("Out of range: " + newLength);
1339
+ setArrayLength(input) {
1340
+ const num = Number(input);
1341
+ const coerced = num >>> 0;
1342
+ if (coerced !== num) {
1343
+ throw new RangeError("Invalid array length");
1344
+ }
1345
+ const newLength = coerced;
1009
1346
  const currentLength = this.source.length;
1010
- if (newLength === currentLength) return;
1011
- else if (newLength > currentLength) {
1012
- const newItems = new Array(newLength - currentLength);
1013
- for (let i = 0; i < newLength - currentLength; i++)
1014
- newItems[i] = void 0;
1015
- this.spliceWithArray(currentLength, 0, newItems);
1016
- } else this.spliceWithArray(newLength, currentLength - newLength);
1347
+ if (newLength === currentLength) return true;
1348
+ const result = Reflect.set(this.source, "length", newLength);
1349
+ if (!result) return false;
1350
+ if (newLength < currentLength) {
1351
+ const toRemove = [];
1352
+ for (const index of this.explicitObservables) {
1353
+ if (index >= newLength) {
1354
+ toRemove.push(index);
1355
+ }
1356
+ }
1357
+ for (const index of toRemove) {
1358
+ this.explicitObservables.delete(index);
1359
+ }
1360
+ this.onArrayChanged(true, newLength, currentLength - newLength);
1361
+ } else {
1362
+ this.onArrayChanged(true, currentLength, newLength - currentLength);
1363
+ }
1364
+ return true;
1017
1365
  }
1018
1366
  spliceWithArray(index, deleteCount, newItems) {
1019
1367
  const length = this.source.length;
1020
1368
  const newTargetItems = [];
1369
+ const newObservableIndices = [];
1021
1370
  if (newItems) {
1022
1371
  for (let i = 0; i < newItems.length; i++) {
1023
1372
  newTargetItems[i] = getSource(newItems[i]);
1373
+ if (isObservable(newItems[i])) {
1374
+ newObservableIndices.push(i);
1375
+ }
1024
1376
  }
1025
1377
  }
1026
1378
  if (index === void 0) index = 0;
@@ -1029,15 +1381,39 @@ class ArrayAdministration extends Administration {
1029
1381
  if (arguments.length === 1) deleteCount = length - index;
1030
1382
  else if (deleteCount === void 0 || deleteCount === null) deleteCount = 0;
1031
1383
  else deleteCount = Math.max(0, Math.min(deleteCount, length - index));
1032
- const res = this.spliceItemsIntoValues(index, deleteCount, newTargetItems);
1384
+ const removedItems = [];
1385
+ for (let i = index; i < index + deleteCount; i++) {
1386
+ removedItems.push(this._getEffectiveValue(i));
1387
+ }
1388
+ for (let i = index; i < index + deleteCount; i++) {
1389
+ this.explicitObservables.delete(i);
1390
+ }
1391
+ const shift = (newItems?.length ?? 0) - deleteCount;
1392
+ if (shift !== 0) {
1393
+ const newExplicitObservables = /* @__PURE__ */ new Set();
1394
+ for (const idx of this.explicitObservables) {
1395
+ if (idx < index) {
1396
+ newExplicitObservables.add(idx);
1397
+ } else if (idx >= index + deleteCount) {
1398
+ newExplicitObservables.add(idx + shift);
1399
+ }
1400
+ }
1401
+ this.explicitObservables.clear();
1402
+ for (const idx of newExplicitObservables) {
1403
+ this.explicitObservables.add(idx);
1404
+ }
1405
+ }
1406
+ for (const relativeIdx of newObservableIndices) {
1407
+ this.explicitObservables.add(index + relativeIdx);
1408
+ }
1409
+ this.spliceItemsIntoValues(index, deleteCount, newTargetItems);
1033
1410
  if (deleteCount !== 0 || newTargetItems.length !== 0) {
1034
- this.onArrayChanged(
1035
- length !== this.source.length,
1036
- index,
1037
- Math.max(deleteCount ?? 0, newItems?.length ?? 0)
1038
- );
1411
+ const shift2 = (newItems?.length ?? 0) - deleteCount;
1412
+ const reindexing = shift2 !== 0 && index + deleteCount < length;
1413
+ const count = reindexing ? Number.POSITIVE_INFINITY : Math.max(deleteCount ?? 0, newItems?.length ?? 0);
1414
+ this.onArrayChanged(length !== this.source.length, index, count);
1039
1415
  }
1040
- return res;
1416
+ return removedItems;
1041
1417
  }
1042
1418
  spliceItemsIntoValues(index, deleteCount, newItems) {
1043
1419
  return this.source.splice.apply(
@@ -1052,9 +1428,16 @@ class ArrayAdministration extends Administration {
1052
1428
  }
1053
1429
  if (index == null) {
1054
1430
  this.atom.reportChanged();
1055
- } else {
1056
- for (let i = index; i < index + count; i++) {
1057
- this.valuesMap.reportChanged(i, this.source[i]);
1431
+ } else if (count !== void 0 && count > 0) {
1432
+ const observedKeys = this.valuesMap.keys();
1433
+ const end = index + count;
1434
+ for (const key of observedKeys) {
1435
+ if (typeof key === "number" && key >= index && key < end) {
1436
+ const node = this.valuesMap.get(key);
1437
+ if (node) {
1438
+ node.reportChanged(this._getEffectiveValue(key));
1439
+ }
1440
+ }
1058
1441
  }
1059
1442
  }
1060
1443
  this.flushChange();
@@ -1070,7 +1453,7 @@ function createMethod(method, func) {
1070
1453
  function createStringMethod(method) {
1071
1454
  return createMethod(method, function() {
1072
1455
  const adm = getAdministration(this);
1073
- adm.reportObserved(false);
1456
+ adm.reportObserved();
1074
1457
  const sourceArr = getSource(this);
1075
1458
  return sourceArr[method].apply(sourceArr, arguments);
1076
1459
  });
@@ -1078,7 +1461,7 @@ function createStringMethod(method) {
1078
1461
  function createSearchMethod(method) {
1079
1462
  return createMethod(method, function() {
1080
1463
  const adm = getAdministration(this);
1081
- adm.reportObserved(false);
1464
+ adm.reportObserved();
1082
1465
  const target = arguments[0];
1083
1466
  const source2 = getSource(target);
1084
1467
  const sourceArr = getSource(this);
@@ -1094,10 +1477,38 @@ function createSearchMethod(method) {
1094
1477
  function createCopyMethod(method) {
1095
1478
  return createMethod(method, function() {
1096
1479
  const adm = getAdministration(this);
1097
- adm.reportObserved(false);
1098
- return getObservable(
1099
- adm.source[method].apply(adm.source, arguments)
1100
- );
1480
+ adm.reportObserved();
1481
+ const observedInput = [];
1482
+ observedInput.length = adm.source.length;
1483
+ const keys = Object.keys(adm.source);
1484
+ for (let i = 0; i < keys.length; i++) {
1485
+ const key = keys[i];
1486
+ const idx = Number(key);
1487
+ if (!Number.isNaN(idx)) {
1488
+ observedInput[idx] = this[idx];
1489
+ }
1490
+ }
1491
+ const args = Array.from(arguments);
1492
+ if (method === "concat") {
1493
+ for (let i = 0; i < args.length; i++) {
1494
+ const arg = args[i];
1495
+ if (Array.isArray(arg) && isObservable(arg)) {
1496
+ const argAdm = getAdministration(arg);
1497
+ const argObserved = [];
1498
+ argObserved.length = argAdm.source.length;
1499
+ const argKeys = Object.keys(argAdm.source);
1500
+ for (let j = 0; j < argKeys.length; j++) {
1501
+ const argKey = argKeys[j];
1502
+ const argIdx = Number(argKey);
1503
+ if (!Number.isNaN(argIdx)) {
1504
+ argObserved[argIdx] = arg[argIdx];
1505
+ }
1506
+ }
1507
+ args[i] = argObserved;
1508
+ }
1509
+ }
1510
+ }
1511
+ return Array.prototype[method].apply(observedInput, args);
1101
1512
  });
1102
1513
  }
1103
1514
  function createMapMethod(method) {
@@ -1105,14 +1516,9 @@ function createMapMethod(method) {
1105
1516
  method,
1106
1517
  function(callback, thisArg) {
1107
1518
  const adm = getAdministration(this);
1108
- adm.reportObserved(false);
1109
- return adm.source[method]((element, index) => {
1110
- return callback.call(
1111
- thisArg,
1112
- element && typeof element === "object" ? getObservable(element) : element,
1113
- index,
1114
- this
1115
- );
1519
+ adm.reportObserved();
1520
+ return adm.source[method]((_element, index) => {
1521
+ return callback.call(thisArg, this[index], index, this);
1116
1522
  });
1117
1523
  }
1118
1524
  );
@@ -1122,28 +1528,17 @@ function createFilterMethod(method) {
1122
1528
  method,
1123
1529
  function(callback, thisArg) {
1124
1530
  const adm = getAdministration(this);
1125
- adm.reportObserved(false);
1126
- return getObservable(
1127
- adm.source[method]((element, index) => {
1128
- return callback.call(
1129
- thisArg,
1130
- element && typeof element === "object" ? getObservable(element) : element,
1131
- index,
1132
- this
1133
- );
1134
- })
1135
- );
1531
+ adm.reportObserved();
1532
+ return adm.source[method]((_element, index) => {
1533
+ return callback.call(thisArg, this[index], index, this);
1534
+ });
1136
1535
  }
1137
1536
  );
1138
1537
  }
1139
1538
  function createReduceMethod(method) {
1140
1539
  return createMethod(method, function() {
1141
1540
  const adm = getAdministration(this);
1142
- adm.reportObserved(false);
1143
- const callback = arguments[0];
1144
- arguments[0] = (accumulator, currentValue, index) => {
1145
- return callback(accumulator, getObservable(currentValue), index, this);
1146
- };
1541
+ adm.reportObserved();
1147
1542
  return adm.source[method].apply(adm.source, arguments);
1148
1543
  });
1149
1544
  }
@@ -1170,6 +1565,7 @@ function addDateSetMethod(method) {
1170
1565
  const adm = getAdministration(this);
1171
1566
  const res = adm.source[method].apply(adm.source, arguments);
1172
1567
  adm.atom.reportChanged();
1568
+ adm.flushChange();
1173
1569
  return res;
1174
1570
  };
1175
1571
  }
@@ -1205,9 +1601,15 @@ function getAction(fn) {
1205
1601
  }
1206
1602
  function getObservableClassInstance(value) {
1207
1603
  const adm = new PreactObjectAdministration(value);
1604
+ administrationMap.set(adm.proxy, adm);
1208
1605
  administrationMap.set(adm.source, adm);
1209
1606
  return adm.proxy;
1210
1607
  }
1608
+ class Observable {
1609
+ constructor() {
1610
+ return getObservableClassInstance(this);
1611
+ }
1612
+ }
1211
1613
  function createObservableWithCustomAdministration(value, Adm) {
1212
1614
  const adm = new Adm(value);
1213
1615
  administrationMap.set(adm.proxy, adm);
@@ -1218,28 +1620,47 @@ function getObservable(value) {
1218
1620
  if (!value) {
1219
1621
  return value;
1220
1622
  }
1221
- const adm = getAdministration(value);
1222
- if (adm) {
1223
- return adm.proxy;
1623
+ const existingAdm = getAdministration(value);
1624
+ if (existingAdm) {
1625
+ return existingAdm.proxy;
1224
1626
  }
1225
- if ((typeof value === "object" || typeof value === "function") && !Object.isFrozen(value)) {
1627
+ if (typeof value === "function") {
1628
+ if (process.env.NODE_ENV !== "production") {
1629
+ console.warn(
1630
+ `r-state-tree: functions are not observable containers. The function will be returned unchanged. Note: functions read from observable objects are still automatically batched as actions.`
1631
+ );
1632
+ }
1633
+ return value;
1634
+ }
1635
+ if (typeof value === "object") {
1226
1636
  const obj = value;
1227
- let Adm = PreactObjectAdministration;
1228
- if (Array.isArray(obj)) {
1229
- Adm = ArrayAdministration;
1230
- } else if (obj instanceof Map || obj instanceof WeakMap) {
1637
+ let Adm = null;
1638
+ if (obj instanceof Map || obj instanceof WeakMap) {
1231
1639
  Adm = CollectionAdministration;
1232
1640
  } else if (obj instanceof Set || obj instanceof WeakSet) {
1233
1641
  Adm = CollectionAdministration;
1234
1642
  } else if (obj instanceof Date) {
1235
1643
  Adm = DateAdministration;
1236
- } else if (!isPlainObject(value)) {
1237
- return value;
1644
+ } else if (!Object.isFrozen(obj)) {
1645
+ if (Array.isArray(obj)) {
1646
+ Adm = ArrayAdministration;
1647
+ } else if (isPlainObject(obj)) {
1648
+ Adm = PreactObjectAdministration;
1649
+ }
1650
+ }
1651
+ if (Adm) {
1652
+ const adm = new Adm(obj);
1653
+ administrationMap.set(adm.proxy, adm);
1654
+ administrationMap.set(adm.source, adm);
1655
+ return adm.proxy;
1656
+ }
1657
+ if (process.env.NODE_ENV !== "production" && !Object.isFrozen(obj)) {
1658
+ const proto = Object.getPrototypeOf(obj);
1659
+ const typeName = proto?.constructor?.name && proto.constructor.name !== "Object" ? `instance of ${proto.constructor.name}` : "non-plain object";
1660
+ console.warn(
1661
+ `r-state-tree: observable() was called with a ${typeName}. This object will NOT be made observable because proxying arbitrary class instances can break #private fields and built-in brand checks. To make a class observable, use 'class MyClass extends Observable'.`
1662
+ );
1238
1663
  }
1239
- const adm2 = new Adm(obj);
1240
- administrationMap.set(adm2.proxy, adm2);
1241
- administrationMap.set(adm2.source, adm2);
1242
- return adm2.proxy;
1243
1664
  }
1244
1665
  return value;
1245
1666
  }
@@ -1268,19 +1689,77 @@ function getPropertyDescriptor(obj, key) {
1268
1689
  }
1269
1690
  return void 0;
1270
1691
  }
1271
- function clone(val) {
1272
- if (Array.isArray(val)) {
1273
- return val.map((v) => clone(v));
1274
- } else if (val && typeof val === "object") {
1275
- const keys = Object.keys(val);
1276
- const cloned = {};
1277
- for (let i = 0; i < keys.length; i++) {
1278
- const key = keys[i];
1279
- cloned[key] = clone(val[key]);
1692
+ function clone(val, path = "") {
1693
+ if (val === null || val === void 0) {
1694
+ return val;
1695
+ }
1696
+ if (typeof val !== "object") {
1697
+ if (typeof val === "string" || typeof val === "number" || typeof val === "boolean") {
1698
+ return val;
1699
+ }
1700
+ const atPath = path ? ` at path "${path}"` : "";
1701
+ if (typeof val === "bigint") {
1702
+ throw new Error(
1703
+ `r-state-tree: snapshots do not support bigint${atPath}. Snapshots are JSON-only (primitives, arrays, plain objects, Dates as ISO strings).`
1704
+ );
1280
1705
  }
1281
- return cloned;
1706
+ if (typeof val === "symbol") {
1707
+ throw new Error(
1708
+ `r-state-tree: snapshots do not support symbol${atPath}. Snapshots are JSON-only (primitives, arrays, plain objects, Dates as ISO strings).`
1709
+ );
1710
+ }
1711
+ if (typeof val === "function") {
1712
+ throw new Error(
1713
+ `r-state-tree: snapshots do not support function${atPath}. Snapshots are JSON-only (primitives, arrays, plain objects, Dates as ISO strings).`
1714
+ );
1715
+ }
1716
+ throw new Error(
1717
+ `r-state-tree: snapshots do not support ${typeof val}${atPath}. Snapshots are JSON-only (primitives, arrays, plain objects, Dates as ISO strings).`
1718
+ );
1282
1719
  }
1283
- return val;
1720
+ if (val instanceof Signal) {
1721
+ return clone(
1722
+ val.value,
1723
+ path
1724
+ );
1725
+ }
1726
+ if (val instanceof Date) {
1727
+ return val.toISOString();
1728
+ }
1729
+ if (Array.isArray(val)) {
1730
+ return val.map(
1731
+ (v, i) => clone(v, path ? `${path}[${i}]` : `[${i}]`)
1732
+ );
1733
+ }
1734
+ if (!isPlainObject(val)) {
1735
+ const typeName = getTypeName(val);
1736
+ const atPath = path ? ` at path "${path}"` : "";
1737
+ throw new Error(
1738
+ `r-state-tree: snapshots do not support ${typeName}${atPath}. Snapshots are JSON-only (primitives, arrays, plain objects, Dates as ISO strings).`
1739
+ );
1740
+ }
1741
+ const keys = Object.keys(val);
1742
+ const cloned = {};
1743
+ for (let i = 0; i < keys.length; i++) {
1744
+ const key = keys[i];
1745
+ const keyPath = path ? `${path}.${key}` : key;
1746
+ cloned[key] = clone(val[key], keyPath);
1747
+ }
1748
+ return cloned;
1749
+ }
1750
+ function getTypeName(val) {
1751
+ if (val instanceof Map) return "Map";
1752
+ if (val instanceof Set) return "Set";
1753
+ if (val instanceof WeakMap) return "WeakMap";
1754
+ if (val instanceof WeakSet) return "WeakSet";
1755
+ if (val instanceof RegExp) return "RegExp";
1756
+ if (val instanceof Error) return "Error";
1757
+ if (val instanceof Promise) return "Promise";
1758
+ const proto = Object.getPrototypeOf(val);
1759
+ if (proto?.constructor?.name && proto.constructor.name !== "Object") {
1760
+ return `class instance (${proto.constructor.name})`;
1761
+ }
1762
+ return "non-plain object";
1284
1763
  }
1285
1764
  function getDiff(o1, o2, getConfig) {
1286
1765
  const config = getConfig(o2);
@@ -1316,6 +1795,33 @@ function getDiff(o1, o2, getConfig) {
1316
1795
  }
1317
1796
  return Object.keys(diff).length > 0 ? diff : null;
1318
1797
  }
1798
+ const MAX_MOUNT_DEPTH = 100;
1799
+ const mountingStack = [];
1800
+ function formatMountFrame(frame) {
1801
+ const childSegment = frame.childName === void 0 ? "" : `.${String(frame.childName)}`;
1802
+ return `${frame.storeName}${childSegment}`;
1803
+ }
1804
+ function formatMountChain(frame) {
1805
+ const chain = [...mountingStack, frame];
1806
+ const maxParts = 6;
1807
+ if (chain.length > maxParts) {
1808
+ const start = chain.slice(0, 3);
1809
+ const end = chain.slice(-2);
1810
+ return [
1811
+ ...start,
1812
+ { storeName: "...", modelsKeys: [], childName: void 0 },
1813
+ ...end
1814
+ ].map(formatMountFrame).join(" -> ");
1815
+ }
1816
+ return chain.map(formatMountFrame).join(" -> ");
1817
+ }
1818
+ function createCircularMountError(frame) {
1819
+ const chain = formatMountChain(frame);
1820
+ const models = frame.modelsKeys.length === 0 ? "no models provided" : `models: ${frame.modelsKeys.join(", ")}`;
1821
+ return new Error(
1822
+ `r-state-tree: detected circular store/model creation while mounting ${chain} (using ${models}). Passing models into child stores during mount can create recursive wiring. Move child store/model creation into storeDidMount or break the cycle.`
1823
+ );
1824
+ }
1319
1825
  function updateProps(props, newProps) {
1320
1826
  untracked(() => {
1321
1827
  batch(() => {
@@ -1326,7 +1832,9 @@ function updateProps(props, newProps) {
1326
1832
  }
1327
1833
  });
1328
1834
  if (newProps.models) {
1329
- if (!props.models) props.models = {};
1835
+ if (!props.models || !isObservable(props.models)) {
1836
+ props.models = getObservable(props.models || {});
1837
+ }
1330
1838
  Object.assign(props.models, newProps.models);
1331
1839
  }
1332
1840
  });
@@ -1335,6 +1843,35 @@ function updateProps(props, newProps) {
1335
1843
  function getStoreAdm(store) {
1336
1844
  return getAdministration(store);
1337
1845
  }
1846
+ function validateStoreChildValue(value, propertyName) {
1847
+ if (value === null || value === void 0) {
1848
+ return;
1849
+ }
1850
+ if (Array.isArray(value)) {
1851
+ const invalidItem = value.find(
1852
+ (item) => item !== null && (typeof item !== "object" || !("Type" in item) || !("props" in item) || typeof item.Type !== "function" || typeof item.props !== "object")
1853
+ );
1854
+ if (invalidItem !== void 0) {
1855
+ throw new Error(
1856
+ `r-state-tree: child property '${String(
1857
+ propertyName
1858
+ )}' must be a StoreElement ({ Type, props, key }), an array of StoreElements, or null/undefined. Found invalid array item: ${typeof invalidItem}`
1859
+ );
1860
+ }
1861
+ return;
1862
+ }
1863
+ if (typeof value === "object" && value !== null && "Type" in value && "props" in value) {
1864
+ const element = value;
1865
+ if (typeof element.Type === "function" && typeof element.props === "object") {
1866
+ return;
1867
+ }
1868
+ }
1869
+ throw new Error(
1870
+ `r-state-tree: child property '${String(
1871
+ propertyName
1872
+ )}' must be a StoreElement ({ Type, props, key }), an array of StoreElements, or null/undefined. Found: ${typeof value}`
1873
+ );
1874
+ }
1338
1875
  class StoreAdministration extends PreactObjectAdministration {
1339
1876
  static proxyTraps = Object.assign(
1340
1877
  {},
@@ -1402,7 +1939,7 @@ class StoreAdministration extends PreactObjectAdministration {
1402
1939
  }
1403
1940
  });
1404
1941
  childStoreData.value.set(stores);
1405
- stores.forEach((s) => getStoreAdm(s).mount(this));
1942
+ stores.forEach((s) => getStoreAdm(s).mount(this, name));
1406
1943
  return stores;
1407
1944
  }
1408
1945
  const newStores = /* @__PURE__ */ new Set();
@@ -1453,7 +1990,7 @@ class StoreAdministration extends PreactObjectAdministration {
1453
1990
  batch(() => childStoreData.value.set(stores));
1454
1991
  }
1455
1992
  removedStores.forEach((s) => getStoreAdm(s).unmount());
1456
- newStores.forEach((s) => getStoreAdm(s).mount(this));
1993
+ newStores.forEach((s) => getStoreAdm(s).mount(this, name));
1457
1994
  return stores;
1458
1995
  }
1459
1996
  setSingleStore(name, element) {
@@ -1472,7 +2009,7 @@ class StoreAdministration extends PreactObjectAdministration {
1472
2009
  }
1473
2010
  const childStore = this.createChildStore(element);
1474
2011
  batch(() => childStoreData.value.set(childStore));
1475
- getStoreAdm(childStore).mount(this);
2012
+ getStoreAdm(childStore).mount(this, name);
1476
2013
  return childStore;
1477
2014
  } else {
1478
2015
  batch(() => updateProps(oldStore.props, props));
@@ -1484,6 +2021,7 @@ class StoreAdministration extends PreactObjectAdministration {
1484
2021
  const storeElement = childStoreData.listener.track(
1485
2022
  () => childStoreData.computed.get()
1486
2023
  );
2024
+ validateStoreChildValue(storeElement, name);
1487
2025
  Array.isArray(storeElement) ? this.setStoreList(name, storeElement) : this.setSingleStore(name, storeElement);
1488
2026
  }
1489
2027
  getComputedGetter(name) {
@@ -1504,6 +2042,7 @@ class StoreAdministration extends PreactObjectAdministration {
1504
2042
  const storeElement = childStoreData.listener.track(
1505
2043
  () => childStoreData.computed.get()
1506
2044
  );
2045
+ validateStoreChildValue(storeElement, name);
1507
2046
  Array.isArray(storeElement) ? this.setStoreList(name, storeElement) : this.setSingleStore(name, storeElement);
1508
2047
  return childStoreData.value.get();
1509
2048
  }
@@ -1513,12 +2052,15 @@ class StoreAdministration extends PreactObjectAdministration {
1513
2052
  return this.initializeStore(name);
1514
2053
  } else {
1515
2054
  const storeElement = untracked(() => childStoreData.computed.get());
2055
+ validateStoreChildValue(storeElement, name);
1516
2056
  Array.isArray(storeElement) ? this.setStoreList(name, storeElement) : this.setSingleStore(name, storeElement);
1517
2057
  return childStoreData.value.get();
1518
2058
  }
1519
2059
  }
1520
2060
  getModelRef(name) {
1521
- return this.proxy.props.models?.[name] ?? null;
2061
+ const models = this.proxy.props.models;
2062
+ const ref = models?.[name] ?? null;
2063
+ return ref;
1522
2064
  }
1523
2065
  isRoot() {
1524
2066
  return !this.parent;
@@ -1561,18 +2103,36 @@ class StoreAdministration extends PreactObjectAdministration {
1561
2103
  this.reactionsUnsub.push(unsub);
1562
2104
  return unsub;
1563
2105
  }
1564
- mount(parent = null) {
1565
- this.parent = parent || null;
1566
- this.childStoreDataMap.forEach(({ value }) => {
1567
- const stores = value.get();
1568
- if (Array.isArray(stores)) {
1569
- stores?.forEach((s) => getStoreAdm(s)?.mount(this));
1570
- } else if (stores) {
1571
- getStoreAdm(stores)?.mount(this);
2106
+ mount(parent = null, childName) {
2107
+ const frame = {
2108
+ storeName: this.proxy.constructor.name || "Store",
2109
+ childName,
2110
+ modelsKeys: Object.keys(this.proxy.props?.models ?? {})
2111
+ };
2112
+ if (mountingStack.length + 1 > MAX_MOUNT_DEPTH) {
2113
+ throw createCircularMountError(frame);
2114
+ }
2115
+ mountingStack.push(frame);
2116
+ try {
2117
+ this.parent = parent || null;
2118
+ this.childStoreDataMap.forEach(({ value }, name) => {
2119
+ const stores = value.get();
2120
+ if (Array.isArray(stores)) {
2121
+ stores?.forEach((s) => getStoreAdm(s)?.mount(this, name));
2122
+ } else if (stores) {
2123
+ getStoreAdm(stores)?.mount(this, name);
2124
+ }
2125
+ });
2126
+ this.mounted = true;
2127
+ batch(() => this.proxy.storeDidMount?.());
2128
+ } catch (error) {
2129
+ if (error instanceof RangeError && /call stack/i.test(error.message)) {
2130
+ throw createCircularMountError(frame);
1572
2131
  }
1573
- });
1574
- this.mounted = true;
1575
- batch(() => this.proxy.storeDidMount?.());
2132
+ throw error;
2133
+ } finally {
2134
+ mountingStack.pop();
2135
+ }
1576
2136
  }
1577
2137
  unmount() {
1578
2138
  this.proxy.storeWillUnmount?.();
@@ -1838,11 +2398,12 @@ class ObservableListener {
1838
2398
  class ChildModelsAdministration extends ArrayAdministration {
1839
2399
  set(index, newValue) {
1840
2400
  return batch(() => {
1841
- super.set(index, newValue);
2401
+ const result = super.set(index, newValue);
1842
2402
  const sourceValue = getSource(newValue);
1843
2403
  if (this.source[index] !== sourceValue) {
1844
2404
  notifyArrayUpdate(this.proxy, index, this.source[index], sourceValue);
1845
2405
  }
2406
+ return result;
1846
2407
  });
1847
2408
  }
1848
2409
  spliceWithArray(index, deleteCount, newItems) {
@@ -1875,7 +2436,19 @@ function getIdKey(Ctor) {
1875
2436
  function getModelRefSnapshot(modelRef2) {
1876
2437
  const Ctor = Object.getPrototypeOf(modelRef2).constructor;
1877
2438
  const idKey = getIdKey(Ctor);
1878
- return idKey ? { [idKey]: getIdentifier(modelRef2) } : null;
2439
+ if (!idKey) return null;
2440
+ let id2 = getIdentifier(modelRef2);
2441
+ if (id2 === void 0) {
2442
+ const source2 = getSource(modelRef2);
2443
+ id2 = getIdentifier(source2);
2444
+ if (id2 === void 0) {
2445
+ const adm = getAdministration(modelRef2);
2446
+ if (adm && adm.proxy !== modelRef2) {
2447
+ id2 = getIdentifier(adm.proxy);
2448
+ }
2449
+ }
2450
+ }
2451
+ return { [idKey]: id2 };
1879
2452
  }
1880
2453
  function getSnapshotId(snapshot, Ctor) {
1881
2454
  const idKey = getIdKey(Ctor);
@@ -1890,6 +2463,30 @@ function getSnapshotRefId(snapshot) {
1890
2463
  }
1891
2464
  return snapshot[keys[0]];
1892
2465
  }
2466
+ function validateModelChildValue(value, propertyName) {
2467
+ if (value === null || value === void 0) {
2468
+ return;
2469
+ }
2470
+ if (value instanceof Model) {
2471
+ return;
2472
+ }
2473
+ if (Array.isArray(value)) {
2474
+ const invalidItem = value.find((item) => !(item instanceof Model));
2475
+ if (invalidItem !== void 0) {
2476
+ throw new Error(
2477
+ `r-state-tree: child property '${String(
2478
+ propertyName
2479
+ )}' must be a Model instance, an array of Model instances, or null/undefined. Found invalid array item: ${typeof invalidItem}`
2480
+ );
2481
+ }
2482
+ return;
2483
+ }
2484
+ throw new Error(
2485
+ `r-state-tree: child property '${String(
2486
+ propertyName
2487
+ )}' must be a Model instance, an array of Model instances, or null/undefined. Found: ${typeof value}`
2488
+ );
2489
+ }
1893
2490
  class ModelAdministration extends PreactObjectAdministration {
1894
2491
  static proxyTraps = Object.assign(
1895
2492
  {},
@@ -1923,6 +2520,7 @@ class ModelAdministration extends PreactObjectAdministration {
1923
2520
  return true;
1924
2521
  }
1925
2522
  case CommonCfgTypes.child: {
2523
+ validateModelChildValue(value, name);
1926
2524
  if (Array.isArray(value)) {
1927
2525
  adm.setModels(name, value);
1928
2526
  return true;
@@ -1974,9 +2572,60 @@ class ModelAdministration extends PreactObjectAdministration {
1974
2572
  modelsTraceUnsub = /* @__PURE__ */ new Map();
1975
2573
  writeInProgress = /* @__PURE__ */ new Set();
1976
2574
  computedSnapshot;
2575
+ snapshotAtom = createAtom();
1977
2576
  snapshotMap = /* @__PURE__ */ new Map();
1978
2577
  contextCache = /* @__PURE__ */ new Map();
1979
2578
  parentName = null;
2579
+ /**
2580
+ * `@state` fields are shallow-reactive (property-level assignment triggers reactivity)
2581
+ * and participate in snapshots. Values stored in `@state` are not deep-wrapped.
2582
+ *
2583
+ * This helper walks a value and:
2584
+ * - observes any observable containers found (proxy or source) so in-place mutations
2585
+ * invalidate `getSnapshot()` / `toSnapshot()`
2586
+ * - avoids proxy traversal by preferring `getSource(...)`
2587
+ * - guards against cycles via `WeakSet`
2588
+ */
2589
+ observeSnapshotValue(value, seen) {
2590
+ if (value == null) return;
2591
+ if (typeof value !== "object") return;
2592
+ if (!seen) seen = /* @__PURE__ */ new WeakSet();
2593
+ const obj = value;
2594
+ if (seen.has(obj)) return;
2595
+ seen.add(obj);
2596
+ const adm = getAdministration(obj);
2597
+ if (adm) {
2598
+ adm.reportObserved();
2599
+ }
2600
+ const src = getSource(value);
2601
+ if (src && typeof src === "object" && src !== value) {
2602
+ this.observeSnapshotValue(src, seen);
2603
+ return;
2604
+ }
2605
+ if (Array.isArray(value)) {
2606
+ for (let i = 0; i < value.length; i++) {
2607
+ this.observeSnapshotValue(value[i], seen);
2608
+ }
2609
+ return;
2610
+ }
2611
+ if (value instanceof Map) {
2612
+ value.forEach((v, k) => {
2613
+ this.observeSnapshotValue(k, seen);
2614
+ this.observeSnapshotValue(v, seen);
2615
+ });
2616
+ return;
2617
+ }
2618
+ if (value instanceof Set) {
2619
+ value.forEach((v) => this.observeSnapshotValue(v, seen));
2620
+ return;
2621
+ }
2622
+ if (value instanceof Date) {
2623
+ return;
2624
+ }
2625
+ for (const key of Object.keys(value)) {
2626
+ this.observeSnapshotValue(value[key], seen);
2627
+ }
2628
+ }
1980
2629
  get parent() {
1981
2630
  this.parentAtom.reportObserved();
1982
2631
  return this._parent;
@@ -2005,12 +2654,15 @@ class ModelAdministration extends PreactObjectAdministration {
2005
2654
  setState(name, value) {
2006
2655
  const oldValue = this.source[name];
2007
2656
  if (value !== oldValue) {
2008
- PreactObjectAdministration.proxyTraps.set(
2009
- this.source,
2010
- name,
2011
- value,
2012
- this.proxy
2013
- );
2657
+ batch(() => {
2658
+ PreactObjectAdministration.proxyTraps.set(
2659
+ this.source,
2660
+ name,
2661
+ value,
2662
+ this.proxy
2663
+ );
2664
+ this.snapshotAtom.reportChanged();
2665
+ });
2014
2666
  }
2015
2667
  }
2016
2668
  setId(name, v) {
@@ -2029,6 +2681,7 @@ class ModelAdministration extends PreactObjectAdministration {
2029
2681
  }
2030
2682
  }
2031
2683
  setModel(name, newModel) {
2684
+ validateModelChildValue(newModel, name);
2032
2685
  const currentValue = this.proxy[name];
2033
2686
  if (currentValue === newModel) {
2034
2687
  return;
@@ -2048,6 +2701,7 @@ class ModelAdministration extends PreactObjectAdministration {
2048
2701
  }
2049
2702
  }
2050
2703
  setModels(name, newModelsSource) {
2704
+ validateModelChildValue(newModelsSource, name);
2051
2705
  const newModels = createObservableWithCustomAdministration(
2052
2706
  [],
2053
2707
  ChildModelsAdministration
@@ -2062,9 +2716,9 @@ class ModelAdministration extends PreactObjectAdministration {
2062
2716
  getModelAdm(currentValue).detach();
2063
2717
  } else if (Array.isArray(currentValue)) {
2064
2718
  const oldModels = currentValue;
2065
- const newModelSet = new Set(newModels);
2719
+ const newModelSet = new Set(newModels.map((m) => getSource(m)));
2066
2720
  oldModels.forEach(
2067
- (child2) => newModelSet.has(child2) || getModelAdm(child2).detach()
2721
+ (child2) => newModelSet.has(getSource(child2)) || getModelAdm(child2).detach()
2068
2722
  );
2069
2723
  this.modelsTraceUnsub.get(name)?.();
2070
2724
  }
@@ -2087,8 +2741,8 @@ class ModelAdministration extends PreactObjectAdministration {
2087
2741
  })
2088
2742
  );
2089
2743
  newModels.forEach((child2) => {
2090
- const oldModelSet = Array.isArray(currentValue) ? new Set(currentValue) : /* @__PURE__ */ new Set();
2091
- if (!oldModelSet.has(child2)) {
2744
+ const oldModelSet = Array.isArray(currentValue) ? new Set(currentValue.map((m) => getSource(m))) : /* @__PURE__ */ new Set();
2745
+ if (!oldModelSet.has(getSource(child2))) {
2092
2746
  const internalModel = getModelAdm(child2);
2093
2747
  internalModel.attach(this, name);
2094
2748
  }
@@ -2202,9 +2856,14 @@ class ModelAdministration extends PreactObjectAdministration {
2202
2856
  toJSON() {
2203
2857
  return Object.keys(this.configuration).reduce((json, key) => {
2204
2858
  switch (this.configuration[key].type) {
2205
- case ModelCfgTypes.state:
2859
+ case ModelCfgTypes.state: {
2860
+ const value = this.proxy[key];
2861
+ this.observeSnapshotValue(value);
2862
+ json[key] = clone(getSource(value), key);
2863
+ break;
2864
+ }
2206
2865
  case ModelCfgTypes.id:
2207
- json[key] = clone(getSource(this.proxy[key]));
2866
+ json[key] = clone(getSource(this.proxy[key]), key);
2208
2867
  break;
2209
2868
  case ModelCfgTypes.modelRef:
2210
2869
  const model2 = this.proxy[key];
@@ -2343,6 +3002,7 @@ class ModelAdministration extends PreactObjectAdministration {
2343
3002
  getSnapshot() {
2344
3003
  if (!this.computedSnapshot) {
2345
3004
  this.computedSnapshot = createComputed(() => {
3005
+ this.snapshotAtom.reportObserved();
2346
3006
  const json = this.toJSON();
2347
3007
  configMap.set(json, this.configuration);
2348
3008
  return json;
@@ -2461,6 +3121,73 @@ function createContext(defaultValue) {
2461
3121
  }
2462
3122
  };
2463
3123
  }
3124
+ function toObservableTree(value) {
3125
+ return toObservableTreeInternal(value, /* @__PURE__ */ new Set(), "");
3126
+ }
3127
+ function buildPath(currentPath, key) {
3128
+ if (typeof key === "number") {
3129
+ return `${currentPath}[${key}]`;
3130
+ }
3131
+ return currentPath ? `${currentPath}.${key}` : key;
3132
+ }
3133
+ function toObservableTreeInternal(value, ancestorPath, path) {
3134
+ if (value === null || typeof value !== "object") {
3135
+ return value;
3136
+ }
3137
+ if (Array.isArray(value)) {
3138
+ if (ancestorPath.has(value)) {
3139
+ throw new Error(
3140
+ `r-state-tree: toObservableTree does not support circular references (cycle detected at path "${path}")`
3141
+ );
3142
+ }
3143
+ ancestorPath.add(value);
3144
+ const toWrap = [];
3145
+ for (let i = 0; i < value.length; i++) {
3146
+ const element = value[i];
3147
+ if (Array.isArray(element) || isPlainObject(element)) {
3148
+ toWrap.push({ index: i, element });
3149
+ }
3150
+ }
3151
+ const proxy = observable(value);
3152
+ for (const { index, element } of toWrap) {
3153
+ proxy[index] = toObservableTreeInternal(
3154
+ element,
3155
+ ancestorPath,
3156
+ buildPath(path, index)
3157
+ );
3158
+ }
3159
+ ancestorPath.delete(value);
3160
+ return proxy;
3161
+ }
3162
+ if (isPlainObject(value)) {
3163
+ if (ancestorPath.has(value)) {
3164
+ throw new Error(
3165
+ `r-state-tree: toObservableTree does not support circular references (cycle detected at path "${path}")`
3166
+ );
3167
+ }
3168
+ ancestorPath.add(value);
3169
+ const toWrap = [];
3170
+ const keys = Object.keys(value);
3171
+ for (let i = 0; i < keys.length; i++) {
3172
+ const key = keys[i];
3173
+ const propValue = value[key];
3174
+ if (Array.isArray(propValue) || isPlainObject(propValue)) {
3175
+ toWrap.push({ key, propValue });
3176
+ }
3177
+ }
3178
+ const proxy = observable(value);
3179
+ for (const { key, propValue } of toWrap) {
3180
+ proxy[key] = toObservableTreeInternal(
3181
+ propValue,
3182
+ ancestorPath,
3183
+ buildPath(path, key)
3184
+ );
3185
+ }
3186
+ ancestorPath.delete(value);
3187
+ return proxy;
3188
+ }
3189
+ return value;
3190
+ }
2464
3191
  function makeDecorator(type) {
2465
3192
  return function(value, context) {
2466
3193
  context.metadata[context.name] = type;
@@ -2508,9 +3235,10 @@ export {
2508
3235
  reaction,
2509
3236
  reportChanged,
2510
3237
  reportObserved,
2511
- signal2 as signal,
3238
+ signal,
2512
3239
  source,
2513
3240
  state,
3241
+ toObservableTree,
2514
3242
  toSnapshot,
2515
3243
  unmount,
2516
3244
  untracked2 as untracked,