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