r-state-tree 0.5.0 → 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() {
@@ -16,8 +16,6 @@ var CommonCfgTypes = /* @__PURE__ */ ((CommonCfgTypes2) => {
16
16
  })(CommonCfgTypes || {});
17
17
  var ModelCfgTypes = /* @__PURE__ */ ((ModelCfgTypes2) => {
18
18
  ModelCfgTypes2["state"] = "state";
19
- ModelCfgTypes2["stateShallow"] = "stateShallow";
20
- ModelCfgTypes2["stateSignal"] = "stateSignal";
21
19
  ModelCfgTypes2["id"] = "id";
22
20
  ModelCfgTypes2["modelRef"] = "modelRef";
23
21
  return ModelCfgTypes2;
@@ -27,9 +25,6 @@ var StoreCfgTypes = /* @__PURE__ */ ((StoreCfgTypes2) => {
27
25
  return StoreCfgTypes2;
28
26
  })(StoreCfgTypes || {});
29
27
  var ObservableCfgTypes = /* @__PURE__ */ ((ObservableCfgTypes2) => {
30
- ObservableCfgTypes2["observable"] = "observable";
31
- ObservableCfgTypes2["observableShallow"] = "observableShallow";
32
- ObservableCfgTypes2["observableSignal"] = "observableSignal";
33
28
  ObservableCfgTypes2["computed"] = "computed";
34
29
  return ObservableCfgTypes2;
35
30
  })(ObservableCfgTypes || {});
@@ -46,14 +41,6 @@ const stateType = {
46
41
  type: "state"
47
42
  /* state */
48
43
  };
49
- const stateShallowType = {
50
- type: "stateShallow"
51
- /* stateShallow */
52
- };
53
- const stateSignalType = {
54
- type: "stateSignal"
55
- /* stateSignal */
56
- };
57
44
  const modelRefType = Object.assign(
58
45
  function(childType2) {
59
46
  return { type: "modelRef", childType: childType2 };
@@ -78,32 +65,29 @@ function isPropertyKey(val) {
78
65
  return typeof val === "string" || typeof val === "number" || typeof val === "symbol";
79
66
  }
80
67
  function getPropertyType(key, obj) {
81
- const hasMetadata = obj.constructor[Symbol.metadata] !== void 0;
68
+ const ctor = obj.constructor;
69
+ const hasMetadata = ctor != null && ctor[Symbol.metadata] !== void 0;
82
70
  const descriptor = getPropertyDescriptor$1(obj, key);
83
71
  if (descriptor?.value && typeof descriptor.value === "function") {
84
72
  return "action";
85
73
  }
86
- const isGetter = descriptor && (typeof descriptor.get === "function" || typeof descriptor.set === "function");
74
+ const isAccessor = descriptor && (typeof descriptor.get === "function" || typeof descriptor.set === "function");
87
75
  if (!hasMetadata) {
88
- if (isGetter) {
76
+ if (descriptor?.get) {
89
77
  return "computed";
90
78
  }
79
+ if (isAccessor) {
80
+ return null;
81
+ }
91
82
  return "observable";
92
83
  }
93
84
  const metadata = obj.constructor[Symbol.metadata];
94
- if (metadata && metadata[key]) {
95
- const config = metadata[key];
85
+ const config = metadata?.[key];
86
+ if (config) {
96
87
  switch (config.type) {
97
88
  case ObservableCfgTypes.computed:
98
89
  return "computed";
99
- case ObservableCfgTypes.observableShallow:
100
- case ModelCfgTypes.stateShallow:
101
- return "observableShallow";
102
- case ObservableCfgTypes.observableSignal:
103
- case ModelCfgTypes.stateSignal:
104
- return "observableSignal";
105
90
  case ModelCfgTypes.state:
106
- case ObservableCfgTypes.observable:
107
91
  case ModelCfgTypes.id:
108
92
  case ModelCfgTypes.modelRef:
109
93
  case CommonCfgTypes.child:
@@ -111,7 +95,7 @@ function getPropertyType(key, obj) {
111
95
  return "observable";
112
96
  }
113
97
  }
114
- return null;
98
+ return isAccessor ? null : "observable";
115
99
  }
116
100
  function getPropertyDescriptor$1(obj, key) {
117
101
  let node = obj;
@@ -140,7 +124,7 @@ class Administration {
140
124
  atom;
141
125
  valuesMap;
142
126
  isObserved = false;
143
- forceObservedAtoms;
127
+ forceObservedAtom;
144
128
  constructor(source2) {
145
129
  this.atom = createObservedAtom();
146
130
  this.source = source2;
@@ -150,13 +134,9 @@ class Administration {
150
134
  );
151
135
  }
152
136
  flushChange() {
153
- if (this.forceObservedAtoms?.length) {
154
- batch(() => {
155
- for (let i = 0; i < this.forceObservedAtoms.length; i++) {
156
- this.forceObservedAtoms[i].reportChanged();
157
- }
158
- });
159
- this.forceObservedAtoms = void 0;
137
+ if (this.forceObservedAtom) {
138
+ this.forceObservedAtom.reportChanged();
139
+ this.forceObservedAtom = void 0;
160
140
  }
161
141
  }
162
142
  getNode() {
@@ -165,9 +145,7 @@ class Administration {
165
145
  reportChanged() {
166
146
  this.atom.reportChanged();
167
147
  }
168
- reportObserveDeep() {
169
- }
170
- reportObserved(deep = false) {
148
+ reportObserved() {
171
149
  const entry = circularRefSet == null;
172
150
  if (entry) {
173
151
  circularRefSet = /* @__PURE__ */ new WeakSet();
@@ -175,15 +153,10 @@ class Administration {
175
153
  return;
176
154
  }
177
155
  circularRefSet.add(this);
178
- const atom = createAtom();
179
- if (!this.forceObservedAtoms) {
180
- this.forceObservedAtoms = [];
181
- }
182
- this.forceObservedAtoms.push(atom);
183
- atom.reportObserved();
184
- if (deep) {
185
- this.reportObserveDeep();
156
+ if (!this.forceObservedAtom) {
157
+ this.forceObservedAtom = createAtom();
186
158
  }
159
+ this.forceObservedAtom.reportObserved();
187
160
  if (entry) {
188
161
  circularRefSet = null;
189
162
  }
@@ -246,6 +219,9 @@ class NodeMap {
246
219
  reportChanged(key, value) {
247
220
  return this.get(key)?.reportChanged(value);
248
221
  }
222
+ keys() {
223
+ return this.map?.keys() ?? [];
224
+ }
249
225
  }
250
226
  class AtomMap extends NodeMap {
251
227
  createNode() {
@@ -263,31 +239,34 @@ class ObjectAdministration extends Administration {
263
239
  valuesMap;
264
240
  computedMap;
265
241
  types;
242
+ isWriting = false;
266
243
  static proxyTraps = {
267
244
  has(target, name) {
268
245
  const adm = getAdministration(target);
269
- if (!(name in Object.prototype) && isPropertyKey(name))
246
+ if (isPropertyKey(name) && (!(name in Object.prototype) || Object.prototype.hasOwnProperty.call(adm.source, name)))
270
247
  return adm.has(name);
271
248
  return Reflect.has(adm.source, name);
272
249
  },
273
250
  get(target, name) {
274
251
  const adm = getAdministration(target);
275
- if (!(name in Object.prototype) && isPropertyKey(name) && (typeof adm.source !== "function" || name !== "prototype")) {
276
- 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]);
277
254
  }
278
- return Reflect.get(adm.source, name, adm.proxy);
255
+ return Reflect.get(adm.source, name, arguments[2]);
279
256
  },
280
257
  set(target, name, value) {
281
258
  if (!isPropertyKey(name)) return false;
282
259
  const adm = getAdministration(target);
283
- adm.write(name, value);
284
- 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);
285
265
  },
286
266
  deleteProperty(target, name) {
287
267
  if (!isPropertyKey(name)) return false;
288
268
  const adm = getAdministration(target);
289
- adm.remove(name);
290
- return true;
269
+ return adm.remove(name);
291
270
  },
292
271
  ownKeys(target) {
293
272
  const adm = getAdministration(target);
@@ -296,21 +275,47 @@ class ObjectAdministration extends Administration {
296
275
  adm.atom.reportObserved();
297
276
  });
298
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;
299
304
  }
300
305
  };
301
306
  constructor(source2 = {}) {
302
307
  super(source2);
303
308
  this.keysAtom = createAtom();
304
309
  this.hasMap = new AtomMap(this.atom);
305
- this.valuesMap = new SignalMap();
310
+ this.valuesMap = new SignalMap(this.atom);
306
311
  this.types = /* @__PURE__ */ new Map();
307
312
  }
308
313
  get(key) {
309
314
  return Reflect.get(this.source, key, this.proxy);
310
315
  }
311
316
  set(key, value) {
312
- batch(() => {
313
- Reflect.set(this.source, key, value, this.proxy);
317
+ return batch(() => {
318
+ return Reflect.set(this.source, key, value, this.proxy);
314
319
  });
315
320
  }
316
321
  getComputed(key) {
@@ -338,17 +343,6 @@ class ObjectAdministration extends Administration {
338
343
  }
339
344
  return type;
340
345
  }
341
- reportObserveDeep() {
342
- Object.getOwnPropertyNames(this.source).forEach((name) => {
343
- const type = this.getType(name);
344
- if (type === "observable") {
345
- const value = this.source[name];
346
- if (value && typeof value === "object") {
347
- getAdministration(getObservable(value))?.reportObserved();
348
- }
349
- }
350
- });
351
- }
352
346
  reportChanged() {
353
347
  this.types.clear();
354
348
  super.reportChanged();
@@ -363,14 +357,13 @@ class ObjectAdministration extends Administration {
363
357
  }
364
358
  return resolveNode(this.valuesMap.getOrCreate(key, this.source[key]));
365
359
  }
366
- read(key) {
360
+ read(key, receiver = this.proxy) {
367
361
  const type = this.getType(key);
368
362
  if (type === null) {
369
- return this.get(key);
363
+ return Reflect.get(this.source, key, receiver);
370
364
  }
371
365
  switch (type) {
372
366
  case "observable":
373
- case "observableShallow":
374
367
  case "action": {
375
368
  if (key in this.source) {
376
369
  this.valuesMap.reportObserved(key, this.source[key]);
@@ -380,48 +373,66 @@ class ObjectAdministration extends Administration {
380
373
  this.hasMap.reportObserved(key);
381
374
  }
382
375
  if (type === "observable") {
383
- return getObservable(this.get(key));
384
- }
385
- if (type === "observableShallow") {
386
- return getShallowObservable(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;
387
389
  }
388
- return getAction(this.get(key));
390
+ return getAction(
391
+ Reflect.get(this.source, key, receiver)
392
+ );
389
393
  }
390
- case "observableSignal": {
391
- if (key in this.source) {
392
- this.valuesMap.reportObserved(key, this.source[key]);
394
+ case "computed": {
395
+ if (receiver === this.proxy) {
396
+ return this.callComputed(key);
393
397
  }
394
398
  this.atom.reportObserved();
395
- if (this.atom.observing) {
396
- this.hasMap.reportObserved(key);
397
- }
398
- return this.get(key);
399
- }
400
- case "computed": {
401
- return this.callComputed(key);
399
+ return Reflect.get(this.source, key, receiver);
402
400
  }
403
401
  default:
404
402
  throw new Error(`unknown type passed to configure`);
405
403
  }
406
404
  }
405
+ explicitObservables = /* @__PURE__ */ new Set();
407
406
  write(key, newValue) {
408
407
  const type = this.getType(key);
409
408
  if (type === null) {
410
- this.set(key, newValue);
411
- return;
409
+ return this.set(key, newValue);
412
410
  }
413
411
  if (type === "computed") {
414
- batch(() => this.set(key, newValue));
415
- return;
412
+ return batch(() => this.set(key, newValue));
416
413
  }
417
414
  const had = key in this.source;
418
415
  const oldValue = this.get(key);
419
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
+ }
420
424
  if (type === "action" && typeof newValue !== "function" || type === "observable" && typeof newValue === "function") {
421
425
  this.types.delete(key);
422
426
  }
423
- if (!had || (isObservable(oldValue) ? oldValue !== newValue : oldValue !== targetValue)) {
424
- 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
+ }
425
436
  batch(() => {
426
437
  this.flushChange();
427
438
  if (!had) {
@@ -430,7 +441,9 @@ class ObjectAdministration extends Administration {
430
441
  }
431
442
  this.valuesMap.reportChanged(key, newValue);
432
443
  });
444
+ return true;
433
445
  }
446
+ return true;
434
447
  }
435
448
  has(key) {
436
449
  this.atom.reportObserved();
@@ -440,39 +453,27 @@ class ObjectAdministration extends Administration {
440
453
  return key in this.source;
441
454
  }
442
455
  remove(key) {
443
- if (!(key in this.source)) return;
444
- delete this.source[key];
445
- batch(() => {
446
- this.flushChange();
447
- this.valuesMap.reportChanged(key, void 0);
448
- this.keysAtom.reportChanged();
449
- this.hasMap.reportChanged(key);
450
- this.valuesMap.delete(key);
451
- });
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;
452
468
  }
453
469
  }
454
470
  class PreactObjectAdministration extends ObjectAdministration {
455
- static proxyTraps = Object.assign(
456
- {},
457
- ObjectAdministration.proxyTraps,
458
- {
459
- get(target, prop, proxy) {
460
- if (!(prop in target) && (typeof prop === "string" || typeof prop === "number") && String(prop)[0] === "$") {
461
- return getSignal(proxy, prop.substring(1));
462
- }
463
- return ObjectAdministration.proxyTraps.get?.apply(
464
- null,
465
- arguments
466
- );
467
- }
468
- }
469
- );
470
471
  }
471
472
  function createObservedAtom() {
472
473
  let value = 0;
473
474
  const callbacks = /* @__PURE__ */ new Set();
474
475
  let observing = false;
475
- const signal22 = new Signal(value, {
476
+ const signal2 = new Signal(value, {
476
477
  watched() {
477
478
  callbacks.forEach((callback) => callback(true));
478
479
  observing = true;
@@ -483,12 +484,12 @@ function createObservedAtom() {
483
484
  }
484
485
  });
485
486
  return {
486
- node: signal22,
487
+ node: signal2,
487
488
  reportObserved() {
488
- return signal22.value;
489
+ return signal2.value;
489
490
  },
490
491
  reportChanged() {
491
- return signal22.value = ++value;
492
+ return signal2.value = ++value;
492
493
  },
493
494
  get observing() {
494
495
  return observing;
@@ -502,7 +503,7 @@ function createObservedAtom() {
502
503
  };
503
504
  }
504
505
  function createSignal(initialValue) {
505
- const s = signal(initialValue);
506
+ const s = signal$1(initialValue);
506
507
  return {
507
508
  node: s,
508
509
  reportChanged(value) {
@@ -521,7 +522,7 @@ function createSignal(initialValue) {
521
522
  }
522
523
  function createAtom() {
523
524
  let value = 0;
524
- const s = signal(value);
525
+ const s = signal$1(value);
525
526
  return {
526
527
  node: s,
527
528
  reportChanged() {
@@ -604,31 +605,12 @@ function createComputed(fn, context = null) {
604
605
  }
605
606
  };
606
607
  }
607
- function observableImpl(value, context) {
608
- if (context && typeof context === "object" && "kind" in context) {
609
- context.metadata[context.name] = { type: "observable" };
610
- return value;
611
- }
612
- return getObservable(value);
608
+ function observable(obj) {
609
+ return getObservable(obj);
613
610
  }
614
- function shallowDecorator(value, context) {
615
- if (context && typeof context === "object" && "kind" in context) {
616
- context.metadata[context.name] = { type: "observableShallow" };
617
- return value;
618
- }
619
- throw new Error("observable.shallow can only be used as a decorator");
611
+ function signal(value) {
612
+ return signal$1(value);
620
613
  }
621
- function signalDecorator(value, context) {
622
- if (context && typeof context === "object" && "kind" in context) {
623
- context.metadata[context.name] = { type: "observableSignal" };
624
- return value;
625
- }
626
- throw new Error("observable.signal can only be used as a decorator");
627
- }
628
- const observable = Object.assign(observableImpl, {
629
- shallow: shallowDecorator,
630
- signal: signalDecorator
631
- });
632
614
  function computed(value, context) {
633
615
  if (context && typeof context === "object" && "kind" in context) {
634
616
  context.metadata[context.name] = { type: "computed" };
@@ -639,29 +621,24 @@ function computed(value, context) {
639
621
  function source(obj) {
640
622
  return getSource(obj);
641
623
  }
642
- class Observable {
643
- constructor() {
644
- return getObservableClassInstance(this);
645
- }
646
- }
647
624
  function reportChanged(obj) {
648
625
  const adm = getAdministration(obj);
649
626
  adm.reportChanged();
650
627
  return obj;
651
628
  }
652
- function reportObserved(obj, opts) {
629
+ function reportObserved(obj) {
653
630
  const adm = getAdministration(obj);
654
- adm.reportObserved(opts?.deep);
631
+ adm.reportObserved();
655
632
  return obj;
656
633
  }
657
634
  const signalMap = /* @__PURE__ */ new WeakMap();
658
635
  function getSignal(obj, key) {
659
636
  const node = getInternalNode(obj, key);
660
637
  if (node instanceof Signal) {
661
- let signal22 = signalMap.get(node);
662
- if (!signal22) {
663
- signal22 = new Signal();
664
- Object.defineProperties(signal22, {
638
+ let signal2 = signalMap.get(node);
639
+ if (!signal2) {
640
+ signal2 = new Signal();
641
+ Object.defineProperties(signal2, {
665
642
  value: {
666
643
  get() {
667
644
  return obj[key];
@@ -676,9 +653,9 @@ function getSignal(obj, key) {
676
653
  }
677
654
  }
678
655
  });
679
- signalMap.set(node, signal22);
656
+ signalMap.set(node, signal2);
680
657
  }
681
- return signal22;
658
+ return signal2;
682
659
  }
683
660
  return node;
684
661
  }
@@ -687,17 +664,36 @@ class CollectionAdministration extends Administration {
687
664
  hasMap;
688
665
  valuesMap;
689
666
  keysAtom;
667
+ isWeak;
668
+ strongTracking = null;
669
+ weakTracking = null;
690
670
  static proxyTraps = {
691
671
  get(target, name) {
692
672
  const adm = getAdministration(target);
693
- if (name === "size" && "size" in adm.source) {
673
+ if (name === "size" && !adm.isWeak && "size" in adm.source) {
694
674
  return adm.size;
695
675
  }
696
676
  const val = adm.source[name];
697
677
  const collectionMethods = adm.constructor.methods;
698
- if (collectionMethods.hasOwnProperty(name) && typeof val === "function") {
678
+ if (collectionMethods.hasOwnProperty(name)) {
679
+ if (adm.isWeak && !isValidWeakMethod(name)) {
680
+ return val;
681
+ }
699
682
  return collectionMethods[name];
700
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
+ }
701
697
  return val;
702
698
  }
703
699
  };
@@ -712,17 +708,71 @@ class CollectionAdministration extends Administration {
712
708
  entries: createMethod$1("entries"),
713
709
  keys: createMethod$1("keys"),
714
710
  values: createMethod$1("values"),
715
- [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")
716
720
  };
717
721
  constructor(source2) {
718
722
  super(source2);
719
723
  this.hasMap = new AtomMap(this.atom);
720
- this.valuesMap = new SignalMap();
724
+ this.valuesMap = new SignalMap(this.atom);
721
725
  this.keysAtom = createAtom();
722
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;
723
773
  }
724
774
  hasEntry(key) {
725
- return this.source.has(getSource(key)) || this.source.has(key);
775
+ return this.getExistingKey(key) !== void 0;
726
776
  }
727
777
  onCollectionChange(key) {
728
778
  batch(() => {
@@ -731,13 +781,6 @@ class CollectionAdministration extends Administration {
731
781
  this.flushChange();
732
782
  });
733
783
  }
734
- reportObserveDeep() {
735
- this.source.forEach?.((value) => {
736
- if (value && typeof value === "object") {
737
- getAdministration(getObservable(value))?.reportObserved();
738
- }
739
- });
740
- }
741
784
  getNode(key) {
742
785
  if (key == null) {
743
786
  return resolveNode(this.atom);
@@ -758,13 +801,12 @@ class CollectionAdministration extends Administration {
758
801
  this.keysAtom.reportObserved();
759
802
  this.atom.reportObserved();
760
803
  this.source.forEach((value, key) => {
761
- const observed = getObservable(this.isMap ? key : value);
762
- callbackFn.call(
763
- thisArg,
764
- this.isMap ? this.get(key) : observed,
765
- observed,
766
- this.proxy
767
- );
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);
768
810
  });
769
811
  }
770
812
  get size() {
@@ -773,43 +815,68 @@ class CollectionAdministration extends Administration {
773
815
  return this.source.size;
774
816
  }
775
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
+ }
776
825
  if (!this.hasEntry(value)) {
777
- const target = getSource(value);
778
826
  this.source.add(target);
779
827
  this.onCollectionChange(target);
780
828
  }
781
829
  return this;
782
830
  }
783
831
  delete(value) {
784
- if (this.hasEntry(value)) {
785
- const target = getSource(value);
786
- this.source.delete(target);
787
- this.source.delete(value);
788
- this.onCollectionChange(target);
789
- 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
+ }
790
852
  }
791
- return false;
853
+ return value;
792
854
  }
793
855
  has(value) {
794
856
  this.atom.reportObserved();
795
- if (this.atom.observing || true) {
796
- const target = getSource(value);
797
- this.hasMap.reportObserved(target);
798
- }
857
+ const target = getSource(value);
858
+ this.hasMap.reportObserved(target);
799
859
  return this.hasEntry(value);
800
860
  }
801
861
  entries() {
862
+ this.keysAtom.reportObserved();
863
+ this.atom.reportObserved();
802
864
  const self = this;
803
- const keys = this.keys();
865
+ const iterator = this.source.entries();
804
866
  return {
805
867
  [Symbol.iterator]: function() {
806
868
  return this;
807
869
  },
808
870
  next() {
809
- 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;
810
874
  return {
811
- done,
812
- 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
+ ]
813
880
  };
814
881
  }
815
882
  };
@@ -817,19 +884,19 @@ class CollectionAdministration extends Administration {
817
884
  keys() {
818
885
  this.keysAtom.reportObserved();
819
886
  this.atom.reportObserved();
820
- let nextIndex = 0;
821
- const observableKeys = Array.from(this.source.keys()).map(
822
- (o) => getObservable(o)
823
- );
887
+ const self = this;
888
+ const iterator = this.source.keys();
824
889
  return {
825
890
  [Symbol.iterator]: function() {
826
891
  return this;
827
892
  },
828
893
  next() {
829
- return nextIndex < observableKeys.length ? {
830
- value: observableKeys[nextIndex++],
831
- done: false
832
- } : { 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
+ };
833
900
  }
834
901
  };
835
902
  }
@@ -837,31 +904,54 @@ class CollectionAdministration extends Administration {
837
904
  const targetKey = getSource(key);
838
905
  const sourceMap = this.source;
839
906
  const has = this.has(key);
840
- const value = sourceMap.get(targetKey) ?? sourceMap.get(key);
841
- 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) {
842
912
  this.valuesMap.reportObserved(key, value);
843
- if (isShallowObservable(this.proxy)) {
844
- return value;
913
+ }
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;
845
922
  }
846
- return getObservable(value);
847
923
  }
848
- return void 0;
924
+ return value;
849
925
  }
850
926
  set(key, value) {
851
927
  const targetKey = getSource(key);
852
928
  const targetValue = getSource(value);
853
929
  const sourceMap = this.source;
854
- const hasKey = this.hasEntry(key);
855
- const oldValue = sourceMap.get(targetKey) ?? sourceMap.get(key);
856
- 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)) {
857
940
  batch(() => {
858
941
  this.flushChange();
859
- if (sourceMap.has(key)) {
860
- sourceMap.set(key, targetValue);
942
+ if (existingKey !== void 0) {
943
+ sourceMap.set(existingKey, targetValue);
861
944
  } else {
862
945
  sourceMap.set(targetKey, targetValue);
863
946
  }
864
- 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
+ }
865
955
  if (!hasKey) {
866
956
  this.hasMap.reportChanged(targetKey);
867
957
  this.keysAtom.reportChanged();
@@ -871,20 +961,22 @@ class CollectionAdministration extends Administration {
871
961
  return this;
872
962
  }
873
963
  values() {
874
- const self = this;
875
- const keys = this.keys();
964
+ this.keysAtom.reportObserved();
965
+ this.atom.reportObserved();
876
966
  if (!this.isMap) {
877
- return keys;
967
+ return this.keys();
878
968
  }
969
+ const entries = this.entries();
879
970
  return {
880
971
  [Symbol.iterator]: function() {
881
972
  return this;
882
973
  },
883
974
  next() {
884
- const { done, value } = keys.next();
975
+ const { done, value } = entries.next();
976
+ if (done) return { done: true, value: void 0 };
885
977
  return {
886
- done,
887
- value: done ? void 0 : self.get(value)
978
+ done: false,
979
+ value: value[1]
888
980
  };
889
981
  }
890
982
  };
@@ -894,53 +986,177 @@ class CollectionAdministration extends Administration {
894
986
  }
895
987
  [Symbol.toStringTag] = "Set";
896
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
+ }
897
1039
  function createMethod$1(method) {
898
1040
  return function() {
899
1041
  const adm = getAdministration(this);
900
- 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;
901
1047
  };
902
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
+ }
903
1056
  class ArrayAdministration extends Administration {
904
1057
  valuesMap;
905
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
+ }
906
1068
  static proxyTraps = {
907
- get(target, name) {
1069
+ get(target, name, receiver) {
908
1070
  const adm = getAdministration(target);
909
1071
  if (name === "length") {
910
1072
  return adm.getArrayLength();
911
1073
  }
912
- if (typeof name === "number") {
913
- return adm.get(name);
914
- }
915
- if (typeof name === "string" && String(parseInt(name)) === name) {
916
- return adm.get(parseInt(name));
1074
+ if (isArrayIndexKey(name)) {
1075
+ return adm.get(Number(name));
917
1076
  }
918
1077
  const arrayMethods = adm.constructor.methods;
919
1078
  if (arrayMethods.hasOwnProperty(name)) {
920
1079
  return arrayMethods[name];
921
1080
  }
922
- return adm.source[name];
1081
+ return Reflect.get(adm.source, name, receiver);
923
1082
  },
924
1083
  set(target, name, value) {
925
1084
  const adm = getAdministration(target);
926
1085
  if (name === "length") {
927
- adm.setArrayLength(value);
928
- } else if (typeof name === "number") {
929
- adm.set(name, value);
930
- } else if (typeof name === "string" && String(parseInt(name)) === name) {
931
- adm.set(parseInt(name), value);
1086
+ return adm.setArrayLength(value);
1087
+ } else if (isArrayIndexKey(name)) {
1088
+ return adm.set(Number(name), value);
932
1089
  } else {
933
- adm.source[name] = value;
1090
+ return Reflect.set(adm.source, name, value, arguments[3]);
934
1091
  }
935
- 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);
936
1142
  }
937
1143
  };
938
1144
  static methods = {
939
1145
  fill(value, start, end) {
940
1146
  const adm = getAdministration(this);
941
- const oldLength = adm.source.length;
942
- adm.source.fill(value, start, end);
943
- 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
+ }
944
1160
  return this;
945
1161
  },
946
1162
  splice(index, deleteCount, ...newItems) {
@@ -976,16 +1192,43 @@ class ArrayAdministration extends Administration {
976
1192
  },
977
1193
  reverse() {
978
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
+ }
979
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
+ }
980
1206
  adm.onArrayChanged(false, 0, adm.source.length);
981
1207
  return this;
982
1208
  },
983
1209
  sort(compareFn) {
984
1210
  const adm = getAdministration(this);
985
- adm.onArrayChanged();
986
- adm.source.sort(
987
- compareFn && ((a, b) => compareFn(getObservable(a), getObservable(b)))
988
- );
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);
989
1232
  return this;
990
1233
  },
991
1234
  join: createStringMethod("join"),
@@ -997,7 +1240,22 @@ class ArrayAdministration extends Administration {
997
1240
  slice: createCopyMethod("slice"),
998
1241
  concat: createCopyMethod("concat"),
999
1242
  flat: createCopyMethod("flat"),
1000
- 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
+ },
1001
1259
  every: createMapMethod("every"),
1002
1260
  forEach: createMapMethod("forEach"),
1003
1261
  map: createMapMethod("map"),
@@ -1011,17 +1269,9 @@ class ArrayAdministration extends Administration {
1011
1269
  };
1012
1270
  constructor(source2 = []) {
1013
1271
  super(source2);
1014
- this.valuesMap = new SignalMap();
1272
+ this.valuesMap = new SignalMap(this.atom);
1015
1273
  this.keysAtom = createAtom();
1016
1274
  }
1017
- reportObserveDeep() {
1018
- for (let i = 0; i < this.source.length; i++) {
1019
- const value = this.source[i];
1020
- if (value && typeof value === "object") {
1021
- getAdministration(getObservable(value))?.reportObserved();
1022
- }
1023
- }
1024
- }
1025
1275
  getNode(key) {
1026
1276
  if (key == null) {
1027
1277
  return this.atom;
@@ -1031,52 +1281,98 @@ class ArrayAdministration extends Administration {
1031
1281
  get(index) {
1032
1282
  this.atom.reportObserved();
1033
1283
  this.valuesMap.reportObserved(index, this.source[index]);
1034
- if (isShallowObservable(this.proxy)) {
1035
- return 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
+ }
1036
1307
  }
1037
- return getObservable(this.source[index]);
1308
+ return value;
1038
1309
  }
1039
1310
  set(index, newValue) {
1040
1311
  const values = this.source;
1041
1312
  const targetValue = getSource(newValue);
1042
- if (index < values.length) {
1313
+ const oldLength = values.length;
1314
+ let changed = true;
1315
+ if (index < oldLength) {
1043
1316
  const oldValue = values[index];
1044
- const changed = isObservable(oldValue) ? newValue !== oldValue : targetValue !== oldValue;
1045
- if (changed) {
1046
- values[index] = targetValue;
1047
- this.onArrayChanged(false, index, 1);
1048
- }
1049
- } else if (index === values.length) {
1050
- 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);
1051
1328
  } else {
1052
- throw new Error(
1053
- `Index out of bounds, ${index} is larger than ${values.length}`
1054
- );
1329
+ this.explicitObservables.delete(index);
1055
1330
  }
1331
+ this.onArrayChanged(lengthChanged, index, 1);
1332
+ return true;
1056
1333
  }
1057
1334
  getArrayLength() {
1058
1335
  this.atom.reportObserved();
1059
1336
  this.keysAtom.reportObserved();
1060
1337
  return this.source.length;
1061
1338
  }
1062
- setArrayLength(newLength) {
1063
- if (typeof newLength !== "number" || newLength < 0)
1064
- 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;
1065
1346
  const currentLength = this.source.length;
1066
- if (newLength === currentLength) return;
1067
- else if (newLength > currentLength) {
1068
- const newItems = new Array(newLength - currentLength);
1069
- for (let i = 0; i < newLength - currentLength; i++)
1070
- newItems[i] = void 0;
1071
- this.spliceWithArray(currentLength, 0, newItems);
1072
- } 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;
1073
1365
  }
1074
1366
  spliceWithArray(index, deleteCount, newItems) {
1075
1367
  const length = this.source.length;
1076
1368
  const newTargetItems = [];
1369
+ const newObservableIndices = [];
1077
1370
  if (newItems) {
1078
1371
  for (let i = 0; i < newItems.length; i++) {
1079
1372
  newTargetItems[i] = getSource(newItems[i]);
1373
+ if (isObservable(newItems[i])) {
1374
+ newObservableIndices.push(i);
1375
+ }
1080
1376
  }
1081
1377
  }
1082
1378
  if (index === void 0) index = 0;
@@ -1085,15 +1381,39 @@ class ArrayAdministration extends Administration {
1085
1381
  if (arguments.length === 1) deleteCount = length - index;
1086
1382
  else if (deleteCount === void 0 || deleteCount === null) deleteCount = 0;
1087
1383
  else deleteCount = Math.max(0, Math.min(deleteCount, length - index));
1088
- 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);
1089
1410
  if (deleteCount !== 0 || newTargetItems.length !== 0) {
1090
- this.onArrayChanged(
1091
- length !== this.source.length,
1092
- index,
1093
- Math.max(deleteCount ?? 0, newItems?.length ?? 0)
1094
- );
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);
1095
1415
  }
1096
- return res;
1416
+ return removedItems;
1097
1417
  }
1098
1418
  spliceItemsIntoValues(index, deleteCount, newItems) {
1099
1419
  return this.source.splice.apply(
@@ -1108,9 +1428,16 @@ class ArrayAdministration extends Administration {
1108
1428
  }
1109
1429
  if (index == null) {
1110
1430
  this.atom.reportChanged();
1111
- } else {
1112
- for (let i = index; i < index + count; i++) {
1113
- 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
+ }
1114
1441
  }
1115
1442
  }
1116
1443
  this.flushChange();
@@ -1126,7 +1453,7 @@ function createMethod(method, func) {
1126
1453
  function createStringMethod(method) {
1127
1454
  return createMethod(method, function() {
1128
1455
  const adm = getAdministration(this);
1129
- adm.reportObserved(false);
1456
+ adm.reportObserved();
1130
1457
  const sourceArr = getSource(this);
1131
1458
  return sourceArr[method].apply(sourceArr, arguments);
1132
1459
  });
@@ -1134,7 +1461,7 @@ function createStringMethod(method) {
1134
1461
  function createSearchMethod(method) {
1135
1462
  return createMethod(method, function() {
1136
1463
  const adm = getAdministration(this);
1137
- adm.reportObserved(false);
1464
+ adm.reportObserved();
1138
1465
  const target = arguments[0];
1139
1466
  const source2 = getSource(target);
1140
1467
  const sourceArr = getSource(this);
@@ -1150,10 +1477,38 @@ function createSearchMethod(method) {
1150
1477
  function createCopyMethod(method) {
1151
1478
  return createMethod(method, function() {
1152
1479
  const adm = getAdministration(this);
1153
- adm.reportObserved(false);
1154
- return getObservable(
1155
- adm.source[method].apply(adm.source, arguments)
1156
- );
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);
1157
1512
  });
1158
1513
  }
1159
1514
  function createMapMethod(method) {
@@ -1161,14 +1516,9 @@ function createMapMethod(method) {
1161
1516
  method,
1162
1517
  function(callback, thisArg) {
1163
1518
  const adm = getAdministration(this);
1164
- adm.reportObserved(false);
1165
- return adm.source[method]((element, index) => {
1166
- return callback.call(
1167
- thisArg,
1168
- element && typeof element === "object" ? getObservable(element) : element,
1169
- index,
1170
- this
1171
- );
1519
+ adm.reportObserved();
1520
+ return adm.source[method]((_element, index) => {
1521
+ return callback.call(thisArg, this[index], index, this);
1172
1522
  });
1173
1523
  }
1174
1524
  );
@@ -1178,28 +1528,17 @@ function createFilterMethod(method) {
1178
1528
  method,
1179
1529
  function(callback, thisArg) {
1180
1530
  const adm = getAdministration(this);
1181
- adm.reportObserved(false);
1182
- return getObservable(
1183
- adm.source[method]((element, index) => {
1184
- return callback.call(
1185
- thisArg,
1186
- element && typeof element === "object" ? getObservable(element) : element,
1187
- index,
1188
- this
1189
- );
1190
- })
1191
- );
1531
+ adm.reportObserved();
1532
+ return adm.source[method]((_element, index) => {
1533
+ return callback.call(thisArg, this[index], index, this);
1534
+ });
1192
1535
  }
1193
1536
  );
1194
1537
  }
1195
1538
  function createReduceMethod(method) {
1196
1539
  return createMethod(method, function() {
1197
1540
  const adm = getAdministration(this);
1198
- adm.reportObserved(false);
1199
- const callback = arguments[0];
1200
- arguments[0] = (accumulator, currentValue, index) => {
1201
- return callback(accumulator, getObservable(currentValue), index, this);
1202
- };
1541
+ adm.reportObserved();
1203
1542
  return adm.source[method].apply(adm.source, arguments);
1204
1543
  });
1205
1544
  }
@@ -1226,6 +1565,7 @@ function addDateSetMethod(method) {
1226
1565
  const adm = getAdministration(this);
1227
1566
  const res = adm.source[method].apply(adm.source, arguments);
1228
1567
  adm.atom.reportChanged();
1568
+ adm.flushChange();
1229
1569
  return res;
1230
1570
  };
1231
1571
  }
@@ -1261,9 +1601,15 @@ function getAction(fn) {
1261
1601
  }
1262
1602
  function getObservableClassInstance(value) {
1263
1603
  const adm = new PreactObjectAdministration(value);
1604
+ administrationMap.set(adm.proxy, adm);
1264
1605
  administrationMap.set(adm.source, adm);
1265
1606
  return adm.proxy;
1266
1607
  }
1608
+ class Observable {
1609
+ constructor() {
1610
+ return getObservableClassInstance(this);
1611
+ }
1612
+ }
1267
1613
  function createObservableWithCustomAdministration(value, Adm) {
1268
1614
  const adm = new Adm(value);
1269
1615
  administrationMap.set(adm.proxy, adm);
@@ -1271,40 +1617,6 @@ function createObservableWithCustomAdministration(value, Adm) {
1271
1617
  return adm.proxy;
1272
1618
  }
1273
1619
  function getObservable(value) {
1274
- if (!value) {
1275
- return value;
1276
- }
1277
- const adm = getAdministration(value);
1278
- if (adm) {
1279
- return adm.proxy;
1280
- }
1281
- if ((typeof value === "object" || typeof value === "function") && !Object.isFrozen(value)) {
1282
- const obj = value;
1283
- let Adm = PreactObjectAdministration;
1284
- if (Array.isArray(obj)) {
1285
- Adm = ArrayAdministration;
1286
- } else if (obj instanceof Map || obj instanceof WeakMap) {
1287
- Adm = CollectionAdministration;
1288
- } else if (obj instanceof Set || obj instanceof WeakSet) {
1289
- Adm = CollectionAdministration;
1290
- } else if (obj instanceof Date) {
1291
- Adm = DateAdministration;
1292
- } else if (!isPlainObject(value)) {
1293
- return value;
1294
- }
1295
- const adm2 = new Adm(obj);
1296
- administrationMap.set(adm2.proxy, adm2);
1297
- administrationMap.set(adm2.source, adm2);
1298
- return adm2.proxy;
1299
- }
1300
- return value;
1301
- }
1302
- const shallowObservables = /* @__PURE__ */ new WeakSet();
1303
- function isShallowObservable(obj) {
1304
- if (!obj || typeof obj !== "object") return false;
1305
- return shallowObservables.has(obj);
1306
- }
1307
- function getShallowObservable(value) {
1308
1620
  if (!value) {
1309
1621
  return value;
1310
1622
  }
@@ -1312,23 +1624,43 @@ function getShallowObservable(value) {
1312
1624
  if (existingAdm) {
1313
1625
  return existingAdm.proxy;
1314
1626
  }
1315
- 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") {
1316
1636
  const obj = value;
1317
1637
  let Adm = null;
1318
- if (Array.isArray(obj)) {
1319
- Adm = ArrayAdministration;
1320
- } else if (obj instanceof Map || obj instanceof WeakMap) {
1638
+ if (obj instanceof Map || obj instanceof WeakMap) {
1321
1639
  Adm = CollectionAdministration;
1322
1640
  } else if (obj instanceof Set || obj instanceof WeakSet) {
1323
1641
  Adm = CollectionAdministration;
1642
+ } else if (obj instanceof Date) {
1643
+ Adm = DateAdministration;
1644
+ } else if (!Object.isFrozen(obj)) {
1645
+ if (Array.isArray(obj)) {
1646
+ Adm = ArrayAdministration;
1647
+ } else if (isPlainObject(obj)) {
1648
+ Adm = PreactObjectAdministration;
1649
+ }
1324
1650
  }
1325
1651
  if (Adm) {
1326
1652
  const adm = new Adm(obj);
1327
1653
  administrationMap.set(adm.proxy, adm);
1328
1654
  administrationMap.set(adm.source, adm);
1329
- shallowObservables.add(adm.proxy);
1330
1655
  return adm.proxy;
1331
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
+ );
1663
+ }
1332
1664
  }
1333
1665
  return value;
1334
1666
  }
@@ -1357,19 +1689,77 @@ function getPropertyDescriptor(obj, key) {
1357
1689
  }
1358
1690
  return void 0;
1359
1691
  }
1360
- function clone(val) {
1361
- if (Array.isArray(val)) {
1362
- return val.map((v) => clone(v));
1363
- } else if (val && typeof val === "object") {
1364
- const keys = Object.keys(val);
1365
- const cloned = {};
1366
- for (let i = 0; i < keys.length; i++) {
1367
- const key = keys[i];
1368
- 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
+ );
1705
+ }
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
+ );
1369
1715
  }
1370
- return cloned;
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
+ );
1719
+ }
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
+ );
1371
1740
  }
1372
- return val;
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";
1373
1763
  }
1374
1764
  function getDiff(o1, o2, getConfig) {
1375
1765
  const config = getConfig(o2);
@@ -1442,7 +1832,9 @@ function updateProps(props, newProps) {
1442
1832
  }
1443
1833
  });
1444
1834
  if (newProps.models) {
1445
- if (!props.models) props.models = {};
1835
+ if (!props.models || !isObservable(props.models)) {
1836
+ props.models = getObservable(props.models || {});
1837
+ }
1446
1838
  Object.assign(props.models, newProps.models);
1447
1839
  }
1448
1840
  });
@@ -1666,7 +2058,9 @@ class StoreAdministration extends PreactObjectAdministration {
1666
2058
  }
1667
2059
  }
1668
2060
  getModelRef(name) {
1669
- return this.proxy.props.models?.[name] ?? null;
2061
+ const models = this.proxy.props.models;
2062
+ const ref = models?.[name] ?? null;
2063
+ return ref;
1670
2064
  }
1671
2065
  isRoot() {
1672
2066
  return !this.parent;
@@ -2004,11 +2398,12 @@ class ObservableListener {
2004
2398
  class ChildModelsAdministration extends ArrayAdministration {
2005
2399
  set(index, newValue) {
2006
2400
  return batch(() => {
2007
- super.set(index, newValue);
2401
+ const result = super.set(index, newValue);
2008
2402
  const sourceValue = getSource(newValue);
2009
2403
  if (this.source[index] !== sourceValue) {
2010
2404
  notifyArrayUpdate(this.proxy, index, this.source[index], sourceValue);
2011
2405
  }
2406
+ return result;
2012
2407
  });
2013
2408
  }
2014
2409
  spliceWithArray(index, deleteCount, newItems) {
@@ -2041,7 +2436,19 @@ function getIdKey(Ctor) {
2041
2436
  function getModelRefSnapshot(modelRef2) {
2042
2437
  const Ctor = Object.getPrototypeOf(modelRef2).constructor;
2043
2438
  const idKey = getIdKey(Ctor);
2044
- 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 };
2045
2452
  }
2046
2453
  function getSnapshotId(snapshot, Ctor) {
2047
2454
  const idKey = getIdKey(Ctor);
@@ -2126,9 +2533,7 @@ class ModelAdministration extends PreactObjectAdministration {
2126
2533
  adm.setId(name, value);
2127
2534
  break;
2128
2535
  }
2129
- case ModelCfgTypes.state:
2130
- case ModelCfgTypes.stateShallow:
2131
- case ModelCfgTypes.stateSignal: {
2536
+ case ModelCfgTypes.state: {
2132
2537
  adm.setState(name, value);
2133
2538
  break;
2134
2539
  }
@@ -2167,9 +2572,60 @@ class ModelAdministration extends PreactObjectAdministration {
2167
2572
  modelsTraceUnsub = /* @__PURE__ */ new Map();
2168
2573
  writeInProgress = /* @__PURE__ */ new Set();
2169
2574
  computedSnapshot;
2575
+ snapshotAtom = createAtom();
2170
2576
  snapshotMap = /* @__PURE__ */ new Map();
2171
2577
  contextCache = /* @__PURE__ */ new Map();
2172
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
+ }
2173
2629
  get parent() {
2174
2630
  this.parentAtom.reportObserved();
2175
2631
  return this._parent;
@@ -2198,12 +2654,15 @@ class ModelAdministration extends PreactObjectAdministration {
2198
2654
  setState(name, value) {
2199
2655
  const oldValue = this.source[name];
2200
2656
  if (value !== oldValue) {
2201
- PreactObjectAdministration.proxyTraps.set(
2202
- this.source,
2203
- name,
2204
- value,
2205
- this.proxy
2206
- );
2657
+ batch(() => {
2658
+ PreactObjectAdministration.proxyTraps.set(
2659
+ this.source,
2660
+ name,
2661
+ value,
2662
+ this.proxy
2663
+ );
2664
+ this.snapshotAtom.reportChanged();
2665
+ });
2207
2666
  }
2208
2667
  }
2209
2668
  setId(name, v) {
@@ -2257,9 +2716,9 @@ class ModelAdministration extends PreactObjectAdministration {
2257
2716
  getModelAdm(currentValue).detach();
2258
2717
  } else if (Array.isArray(currentValue)) {
2259
2718
  const oldModels = currentValue;
2260
- const newModelSet = new Set(newModels);
2719
+ const newModelSet = new Set(newModels.map((m) => getSource(m)));
2261
2720
  oldModels.forEach(
2262
- (child2) => newModelSet.has(child2) || getModelAdm(child2).detach()
2721
+ (child2) => newModelSet.has(getSource(child2)) || getModelAdm(child2).detach()
2263
2722
  );
2264
2723
  this.modelsTraceUnsub.get(name)?.();
2265
2724
  }
@@ -2282,8 +2741,8 @@ class ModelAdministration extends PreactObjectAdministration {
2282
2741
  })
2283
2742
  );
2284
2743
  newModels.forEach((child2) => {
2285
- const oldModelSet = Array.isArray(currentValue) ? new Set(currentValue) : /* @__PURE__ */ new Set();
2286
- 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))) {
2287
2746
  const internalModel = getModelAdm(child2);
2288
2747
  internalModel.attach(this, name);
2289
2748
  }
@@ -2397,11 +2856,14 @@ class ModelAdministration extends PreactObjectAdministration {
2397
2856
  toJSON() {
2398
2857
  return Object.keys(this.configuration).reduce((json, key) => {
2399
2858
  switch (this.configuration[key].type) {
2400
- case ModelCfgTypes.state:
2401
- case ModelCfgTypes.stateShallow:
2402
- case ModelCfgTypes.stateSignal:
2859
+ case ModelCfgTypes.state: {
2860
+ const value = this.proxy[key];
2861
+ this.observeSnapshotValue(value);
2862
+ json[key] = clone(getSource(value), key);
2863
+ break;
2864
+ }
2403
2865
  case ModelCfgTypes.id:
2404
- json[key] = clone(getSource(this.proxy[key]));
2866
+ json[key] = clone(getSource(this.proxy[key]), key);
2405
2867
  break;
2406
2868
  case ModelCfgTypes.modelRef:
2407
2869
  const model2 = this.proxy[key];
@@ -2465,8 +2927,6 @@ class ModelAdministration extends PreactObjectAdministration {
2465
2927
  const value = snapshot[key];
2466
2928
  switch (type) {
2467
2929
  case ModelCfgTypes.state:
2468
- case ModelCfgTypes.stateShallow:
2469
- case ModelCfgTypes.stateSignal:
2470
2930
  this.proxy[key] = value;
2471
2931
  break;
2472
2932
  case ModelCfgTypes.modelRef:
@@ -2542,6 +3002,7 @@ class ModelAdministration extends PreactObjectAdministration {
2542
3002
  getSnapshot() {
2543
3003
  if (!this.computedSnapshot) {
2544
3004
  this.computedSnapshot = createComputed(() => {
3005
+ this.snapshotAtom.reportObserved();
2545
3006
  const json = this.toJSON();
2546
3007
  configMap.set(json, this.configuration);
2547
3008
  return json;
@@ -2660,6 +3121,73 @@ function createContext(defaultValue) {
2660
3121
  }
2661
3122
  };
2662
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
+ }
2663
3191
  function makeDecorator(type) {
2664
3192
  return function(value, context) {
2665
3193
  context.metadata[context.name] = type;
@@ -2682,10 +3210,7 @@ const child = makeChildDecorator(childType);
2682
3210
  const modelRef = makeChildDecorator(modelRefType);
2683
3211
  const model = makeDecorator(modelType);
2684
3212
  const id = makeDecorator(idType);
2685
- const state = Object.assign(makeDecorator(stateType), {
2686
- shallow: makeDecorator(stateShallowType),
2687
- signal: makeDecorator(stateSignalType)
2688
- });
3213
+ const state = makeDecorator(stateType);
2689
3214
  export {
2690
3215
  Model,
2691
3216
  Observable,
@@ -2710,9 +3235,10 @@ export {
2710
3235
  reaction,
2711
3236
  reportChanged,
2712
3237
  reportObserved,
2713
- signal2 as signal,
3238
+ signal,
2714
3239
  source,
2715
3240
  state,
3241
+ toObservableTree,
2716
3242
  toSnapshot,
2717
3243
  unmount,
2718
3244
  untracked2 as untracked,