r-state-tree 0.6.3 → 0.8.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.
package/README.md CHANGED
@@ -14,7 +14,10 @@ pnpm add r-state-tree
14
14
 
15
15
  ### Requirements
16
16
 
17
- This library uses [TC39 Stage 3 Decorators](https://github.com/tc39/proposal-decorators) and requires TypeScript 5.0+ with `target: "es2022"` or higher.
17
+ This library strongly recommends using decorators.
18
+
19
+ - Recommended: decorators (`@child`, `@model`, `@state`, `@id`, `@modelRef`, `@computed`). Requires TypeScript 5.0+ with `target: "es2022"` or higher.
20
+ - Fallback: `static types` configuration (no decorators) if you can't or don't want to enable decorators in your toolchain.
18
21
 
19
22
  The library includes a decorator metadata polyfill for runtimes that don't yet natively support `Symbol.metadata`.
20
23
 
@@ -22,6 +25,8 @@ The library includes a decorator metadata polyfill for runtimes that don't yet n
22
25
 
23
26
  TypeScript 5+ supports TC39 Stage 3 decorators.
24
27
 
28
+ Only needed if you use decorators.
29
+
25
30
  ```json
26
31
  {
27
32
  "compilerOptions": {
@@ -57,10 +62,10 @@ export default defineConfig({
57
62
 
58
63
  ## Core concepts
59
64
 
60
- - Stores: application/view state containers. Create with `createStore()`, attach with `mount()`. Compose with `@child` (single or arrays, stable via `{ key }`). React to changes with `effect`/`reaction` and store lifecycles (`storeDidMount`/`storeWillUnmount`). Update reactive `props` via `updateStore()`.
65
+ - Stores: application/view state containers. Create with `createStore()`, attach with `mount()`, and dispose with `Symbol.dispose`. Compose with `@child` and register owned `effect`/`reaction` behavior in constructors. Update reactive `props` via `updateStore()`.
61
66
  - Models: domain state containers. Create with `Model.create()`. Persistent via snapshots (`toSnapshot`, `applySnapshot`, `onSnapshot`, diffs via `onSnapshotDiff`). Structure with `@state`, `@child`, identifiers via `@id`, and references via `@modelRef`.
62
67
  - Context: pass data through Store/Model trees without prop drilling using `createContext<T>()`, `[Context.provide]`, and `Context.consume(this)`. Context is reactive and can be overridden by descendants.
63
- - Reactivity: powered by signals. Use `observable()`, `@computed`, `effect`, `reaction`, `batch`, and `untracked` for precise updates.
68
+ - Reactivity: powered by signals. Use `observable()`, `computed` / `@computed`, `effect`, `reaction`, `batch`, and `untracked` for precise updates.
64
69
 
65
70
  ## Separation of concerns
66
71
 
@@ -105,11 +110,36 @@ const app = mount(createStore(AppStore));
105
110
  app.todo.title; // "Write docs"
106
111
  ```
107
112
 
113
+ Fallback (no decorators) using `static types`:
114
+
115
+ ```ts
116
+ import { Store, createStore, mount, child } from "r-state-tree";
117
+
118
+ class TodoStore extends Store<{ title: string }> {
119
+ get title() {
120
+ return this.props.title;
121
+ }
122
+ }
123
+
124
+ class AppStore extends Store {
125
+ get todo() {
126
+ return createStore(TodoStore, { title: "Write docs" });
127
+ }
128
+
129
+ static types = {
130
+ todo: child,
131
+ };
132
+ }
133
+
134
+ const app = mount(createStore(AppStore));
135
+ app.todo.title;
136
+ ```
137
+
108
138
  ### Store creation, props, and typing
109
139
 
110
140
  - Always create with `createStore()` and attach with `mount()`. Stores cannot be constructed with `new` directly.
111
141
  - Prefer no custom constructor. Type stores as `Store<Props>` and access props via `this.props`.
112
- - If a constructor is necessary, call `super(props)` exactly once and keep it minimal; put effects in `storeDidMount`.
142
+ - Constructors may register framework-owned reactions and effects after `super(props)`. Gate external resource acquisition on `isMounted` and return cleanup from effects.
113
143
  - Do not shadow or re-declare `props` as a class field; `props` is read-only. Use the generic `Store<{ ... }>` for typing.
114
144
 
115
145
  ```ts
@@ -173,20 +203,28 @@ class ItemsStore extends Store {
173
203
  }
174
204
  ```
175
205
 
176
- ### Lifecycle hooks
206
+ ### Store lifetime and owned effects
177
207
 
178
- Stores support lifecycle methods:
208
+ Mounted stores expose reactive `isMounted` state and implement `Disposable`:
179
209
 
180
210
  ```ts
181
211
  class TodoStore extends Store {
182
- storeDidMount() {
183
- console.log("Store mounted");
184
- }
185
-
186
- storeWillUnmount() {
187
- console.log("Store will unmount");
212
+ constructor(props) {
213
+ super(props);
214
+ this.effect(() => {
215
+ if (!this.isMounted) return;
216
+ const connection = connect();
217
+ return () => connection.close();
218
+ });
188
219
  }
189
220
  }
221
+
222
+ const store = mount(createStore(TodoStore));
223
+ store[Symbol.dispose]();
224
+
225
+ {
226
+ using store = mount(createStore(TodoStore));
227
+ } // Symbol.dispose is called automatically
190
228
  ```
191
229
 
192
230
  ### Reactions
@@ -195,10 +233,11 @@ Create side effects that run when reactive values change:
195
233
 
196
234
  ```ts
197
235
  class TodoStore extends Store {
198
- storeDidMount() {
236
+ constructor(props) {
237
+ super(props);
199
238
  this.reaction(
200
239
  () => this.props.title,
201
- (title) => console.log("Title changed:", title)
240
+ (title, previousTitle) => console.log(previousTitle, "->", title)
202
241
  );
203
242
  }
204
243
  }
@@ -270,6 +309,35 @@ const profile = mount(createStore(ProfileStore, { models: { user } }));
270
309
  profile.user.name; // "Ada"
271
310
  ```
272
311
 
312
+ Fallback (no decorators) using `static types`:
313
+
314
+ ```ts
315
+ import {
316
+ Model,
317
+ Store,
318
+ createStore,
319
+ mount,
320
+ model,
321
+ id,
322
+ state,
323
+ } from "r-state-tree";
324
+
325
+ class User extends Model {
326
+ id = 0;
327
+ name = "";
328
+ static types = { id, name: state };
329
+ }
330
+
331
+ class ProfileStore extends Store {
332
+ user!: User;
333
+ static types = { user: model };
334
+ }
335
+
336
+ const user = User.create({ id: 1, name: "Ada" });
337
+ const profile = mount(createStore(ProfileStore, { models: { user } }));
338
+ profile.user.name;
339
+ ```
340
+
273
341
  Type stores as `Store<Props>` and explicitly type `@model` fields for clarity. The `models` prop may also provide arrays of models.
274
342
 
275
343
  ## Modeling guide
@@ -775,41 +843,61 @@ const off = onSnapshot(list, (snap) => {
775
843
 
776
844
  Mutate Models through domain methods and let snapshots record changes automatically.
777
845
 
778
- ### Model lifecycle hooks
846
+ ### Model creation and named factories
779
847
 
780
- Models support lifecycle methods:
848
+ `Model.create()` accepts a canonical snapshot. For defaults, identifier generation, normalization, migrations, or external API formats, use a named static factory that prepares the input before calling `create()`:
781
849
 
782
850
  ```ts
783
851
  class TodoModel extends Model {
784
- @child tags: TagModel[] = [];
852
+ @id id = "";
853
+ @state title = "";
785
854
 
786
- modelDidInit(snapshot?, ...args: unknown[]) {
787
- // Called when model is created via Model.create()
788
- // Receives the snapshot and any additional arguments passed to create()
789
- console.log("Model initialized", snapshot);
855
+ static new(title = "Untitled") {
856
+ return this.create({
857
+ id: crypto.randomUUID(),
858
+ title: title.trim(),
859
+ });
790
860
  }
791
861
 
792
- modelDidAttach() {
793
- // Called when this model is attached as a child to another model
794
- console.log("Model attached to parent");
862
+ static fromApi(input: ApiTodo) {
863
+ return this.create({
864
+ id: input.todo_id,
865
+ title: input.name.trim(),
866
+ });
795
867
  }
868
+ }
869
+
870
+ const todo = TodoModel.new(" Write documentation ");
871
+ todo.title; // "Write documentation"
872
+ ```
873
+
874
+ This keeps snapshot hydration predictable: `create(snapshot)` and `applySnapshot(model, snapshot)` both consume the same canonical shape. Named factories make non-canonical inputs and generated values explicit and independently typed. Nested snapshots must already be canonical.
875
+
876
+ ### Model attachment and disposal
877
+
878
+ The public `parent` relationship is reactive. Register a model-owned reaction in the constructor to observe attachment and detachment:
879
+
880
+ ```ts
881
+ class TodoModel extends Model {
882
+ @child tags: TagModel[] = [];
796
883
 
797
- modelWillDetach() {
798
- // Called when this model is detached from its parent
799
- console.log("Model will be detached");
884
+ constructor() {
885
+ super();
886
+ this.reaction(() => this.parent, (parent, previousParent) => {
887
+ if (previousParent) console.log("detached", previousParent);
888
+ if (parent) console.log("attached", parent);
889
+ });
800
890
  }
801
891
  }
802
892
  ```
803
893
 
804
- When to use each:
894
+ Detachment is reversible; model-owned effects survive reattachment. `model[Symbol.dispose]()` is terminal and recursively disposes owned child models, but never model refs.
805
895
 
806
- - `modelDidInit`: initialize/normalize data based on the initial snapshot.
807
- - `modelDidAttach`: link to other models or read context after the model is part of a tree.
808
- - `modelWillDetach`: cleanup before the model is removed or replaced.
896
+ ### Model configuration
809
897
 
810
- ### Model decorators
898
+ Recommended: configure model properties with decorators.
811
899
 
812
- Use decorators to configure model properties:
900
+ Fallback: if you can't or don't want to use decorators, use `static types`.
813
901
 
814
902
  ```ts
815
903
  import { Model, state, id, child, modelRef } from "r-state-tree";
@@ -822,13 +910,41 @@ class User extends Model {
822
910
  class TodoModel extends Model {
823
911
  @id id = 0;
824
912
  @state title = "";
825
- @modelRef assignee?: User; // Reference to another model by ID
913
+ @modelRef(User) assignee?: User; // Reference to another model by ID
826
914
  @child metadata = MetadataModel.create(); // Nested child model
827
915
  @child tags: TagModel[] = []; // Array of child models
828
916
  }
829
917
  ```
830
918
 
831
- The `@child` and `@modelRef` decorators support both single values and arrays. You can also specify the child type using `@child(ChildType)`:
919
+ Fallback (no decorators) using `static types`:
920
+
921
+ ```ts
922
+ import { Model, id, state, child, modelRef } from "r-state-tree";
923
+
924
+ class User extends Model {
925
+ id = 0;
926
+ name = "";
927
+ static types = { id, name: state };
928
+ }
929
+
930
+ class TodoModel extends Model {
931
+ id = 0;
932
+ title = "";
933
+ assignee?: User;
934
+ metadata = MetadataModel.create();
935
+ tags: TagModel[] = [];
936
+
937
+ static types = {
938
+ id,
939
+ title: state,
940
+ assignee: modelRef(User),
941
+ metadata: child(MetadataModel),
942
+ tags: child(TagModel),
943
+ };
944
+ }
945
+ ```
946
+
947
+ The `child` and `modelRef` helpers support both single values and arrays. You can also specify the child type using `@child(ChildType)` (decorators) or `child(ChildType)` (`static types`):
832
948
 
833
949
  ```ts
834
950
  class TodoModel extends Model {
@@ -839,14 +955,14 @@ class TodoModel extends Model {
839
955
 
840
956
  ### Model references
841
957
 
842
- Reference models by ID using `@modelRef`:
958
+ Reference models by ID using `@modelRef(ModelType)` (or `modelRef(ModelType)` in `static types`). The model constructor is required because identifiers are namespaced by model type:
843
959
 
844
960
  ```ts
845
961
  class ProjectModel extends Model {
846
962
  @id id = 0;
847
963
  @child users: User[] = [];
848
- @modelRef owner?: User; // Single reference
849
- @modelRef assignees: User[] = []; // Array of references
964
+ @modelRef(User) owner?: User; // Single reference
965
+ @modelRef(User) assignees: User[] = []; // Array of references
850
966
 
851
967
  assignOwner(userId: number) {
852
968
  // Find user by ID and set as owner
@@ -894,9 +1010,12 @@ class ContainerModel extends Model {
894
1010
  ## API surface
895
1011
 
896
1012
  - Stores
897
- - `Store`, `createStore`, `mount`, `unmount`, `updateStore`
1013
+ - `Store`, `createStore`, `mount`, `updateStore`
898
1014
  - Models
899
- - `Model`, decorators: `@state`, `@id`, `@child`, `@modelRef`
1015
+ - `Model`, `Model.create()`
1016
+ - configuration: decorators (`@state`, `@id`, `@child`, `@modelRef`) or `static types` with `state`, `id`, `child`, `modelRef`
1017
+ - Store configuration
1018
+ - decorators (`@child`, `@model`) or `static types` with `child`, `model`
900
1019
  - Snapshots
901
1020
  - `onSnapshot`, `toSnapshot`, `applySnapshot`, `onSnapshotDiff`
902
1021
  - Types: `Snapshot`, `SnapshotDiff`, `IdType`, `Configuration`
@@ -958,12 +1077,21 @@ Use the observers/renderers provided by the signals bindings for your UI library
958
1077
 
959
1078
  ### Identifier and reference rules
960
1079
 
961
- - `@id` values are unique within a tree. They cannot be cleared to `undefined` after assignment.
962
- - Identifiers can be reassigned to a new value (including in snapshots) as long as uniqueness is preserved.
963
- - `@modelRef` requires the referenced model to have an id and be attached to the tree; the ref becomes `undefined` when the model detaches.
1080
+ - `@id` values are unique per exact runtime Model class within a tree. Different Model classes may use the same id; subclasses have their own identifier namespace. IDs cannot be cleared to `undefined` after assignment.
1081
+ - Identifiers are mutable and can be reassigned (including in snapshots) as long as the new id is unused by that exact Model class. A failed reassignment preserves the old id and its references.
1082
+ - Use `@modelRef(ModelType)` or `modelRef(ModelType)` when ids can overlap across Model classes; references resolve only within the declared Model class.
1083
+ - `@modelRef(ModelType)` requires an explicit model constructor. The referenced model must have an id and be attached to the tree; the ref becomes `undefined` when the model detaches.
964
1084
  - When a model is re-attached to the same tree, compatible refs restore automatically; attaching to a different root does not restore prior refs.
965
1085
  - `@modelRef` and `@child` can switch between single and array at runtime; reactions observe the property itself rather than internal array mutations.
966
1086
 
1087
+ Use `findModelById` for an optional, typed lookup within a model tree:
1088
+
1089
+ ```ts
1090
+ const user = findModelById(root, User, 1); // User | undefined
1091
+ ```
1092
+
1093
+ The lookup is reactive inside an effect or computed value. It returns `undefined` when the matching model changes its id, detaches, or is disposed.
1094
+
967
1095
  ### Snapshot diffs
968
1096
 
969
1097
  Use `onSnapshotDiff` to receive undo/redo payloads:
@@ -1076,17 +1204,22 @@ class ListModel extends Model {
1076
1204
  }
1077
1205
  ```
1078
1206
 
1079
- Lifecycle hooks:
1207
+ Lifecycle registration:
1080
1208
 
1081
1209
  ```ts
1082
1210
  class M extends Model {
1083
- modelDidInit() {}
1084
- modelDidAttach() {}
1085
- modelWillDetach() {}
1211
+ constructor() {
1212
+ super();
1213
+ this.reaction(() => this.parent, (parent, previousParent) => {});
1214
+ }
1086
1215
  }
1087
1216
  class S extends Store {
1088
- storeDidMount() {}
1089
- storeWillUnmount() {}
1217
+ constructor(props) {
1218
+ super(props);
1219
+ this.effect(() => {
1220
+ if (!this.isMounted) return;
1221
+ });
1222
+ }
1090
1223
  }
1091
1224
  ```
1092
1225
 
@@ -1108,11 +1241,11 @@ const off = onSnapshot(m, (snap) =>
1108
1241
  - Mutating raw `@state` arrays/objects in place (`push`, `obj.x = 1`) and expecting snapshots to update. Snapshots are memoized; use reassignment or store `observable()` containers / `signal()` values in `@state`.
1109
1242
  - Passing observables to third‑party APIs that expect cloneable/serializable values (e.g. `structuredClone`). Use `source(value)` to get the backing value. It will be observable-free for values written via r-state-tree’s observable APIs (unwrap-on-write), but `source(...)` is **not** guaranteed observable-free if you manually seed observables into backing sources.
1110
1243
  - Creating child stores in constructors: `@child` must be on getters so identity and lifecycle can be managed by the framework.
1111
- - Passing `models` into child stores during mount can create a recursive mount loop. If a child needs parent models, create the child store/model inside `storeDidMount` instead of wiring it through `models` during the mount cycle.
1244
+ - Passing `models` into child stores during mount can create a recursive mount loop. Break the ownership cycle rather than wiring models back through a child during mount.
1112
1245
 
1113
1246
  ### Circular store/model creation
1114
1247
 
1115
- When child stores are created during mount with `models` that point back into the parent, it is easy to trigger an endless mount loop. The runtime now guards this by throwing a descriptive error (for example, `detected circular store/model creation while mounting ParentStore -> ChildStore.loop -> ...`). If you see this, move child creation into `storeDidMount` or break the cycle so that models are produced after the parent finishes mounting.
1248
+ When child stores are created during mount with `models` that point back into the parent, it is easy to trigger an endless mount loop. The runtime guards this with a descriptive circular-creation error. Break the cycle so models are produced independently of the child mount.
1116
1249
 
1117
1250
  ## LLM implementation checklist
1118
1251
 
@@ -1131,8 +1264,8 @@ When child stores are created during mount with `models` that point back into th
1131
1264
  - For `createStore` props, extend `Record<string, unknown>` only if needed; otherwise rely on proper prop types and context.
1132
1265
  - Avoid barrel files if they cause import confusion; prefer direct imports.
1133
1266
  - Keep file boundaries clean: one model per file; avoid piling multiple models together.
1134
- - Do not shadow `props` or use constructors for work better suited to `storeDidMount`.
1135
- - Use `@model` for injected models; `@child` for child stores; stable keys for arrays.
1267
+ - Do not shadow `props`; constructors are the registration phase for owned reactions and effects.
1268
+ - Use `@model`/`model` for injected models; `@child`/`child` for child stores; stable keys for arrays.
1136
1269
 
1137
1270
  ## Typing recipes
1138
1271
 
@@ -1142,12 +1275,13 @@ When child stores are created during mount with `models` that point back into th
1142
1275
 
1143
1276
  ## Cheat sheet
1144
1277
 
1278
+ - Configuration (no decorators): `static types = { ... }` with `state`, `id`, `child`, `modelRef`, `model`, `computed`
1145
1279
  - Decorators (Models): `@state`, `@id`, `@child`, `@modelRef`
1146
1280
  - Decorators (Stores): `@child`, `@model`
1147
- - Core: `createStore`, `mount`, `unmount`, `updateStore`
1281
+ - Core: `createStore`, `mount`, `Symbol.dispose`, `updateStore`
1148
1282
  - Snapshots: `onSnapshot`, `toSnapshot`, `applySnapshot`, `onSnapshotDiff`
1149
- - Lifecycle: `storeDidMount`, `storeWillUnmount`, `modelDidInit`, `modelDidAttach`, `modelWillDetach`
1150
- - Best practices: domain in Models; delegate from Stores; stable keys for `@child`; in-place mutations in Models; no effectful constructors; don’t shadow `props`.
1283
+ - Lifecycle: reactive `Store.isMounted`, reactive `Model.parent`, and owned `reaction`/`effect`
1284
+ - Best practices: domain in Models; delegate from Stores; stable keys for `@child`; gate resources on lifecycle state; don’t shadow `props`.
1151
1285
 
1152
1286
  ## Testing
1153
1287
 
package/dist/api.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import type { Snapshot, SnapshotDiff } from "./types";
1
+ import type { Snapshot, SnapshotDiff, IdType } from "./types";
2
2
  import type Store from "./store/Store";
3
3
  import type Model from "./model/Model";
4
+ export declare function findModelById<T extends Model>(root: Model, ModelType: new (...args: any[]) => T, id: IdType): T | undefined;
4
5
  export declare function mount<T extends Store>(container: T): T;
5
- export declare function unmount<S extends Store>(container: S): void;
6
6
  export declare function toSnapshot<T extends Model>(model: T): Snapshot<T>;
7
7
  export declare function onSnapshot<T extends Model>(model: T, callback: (snapshot: Snapshot<T>, model: T) => void): () => void;
8
8
  export declare function onSnapshotDiff<T extends Model>(model: T, callback: (snapshotDiff: SnapshotDiff<T>, model: T) => void): () => void;
@@ -0,0 +1,10 @@
1
+ import type { ConfigurationType, ConfigurationTypes } from "./types";
2
+ type Ctor = Function;
3
+ type Config = Record<PropertyKey, ConfigurationType>;
4
+ export declare function getConfigType(entry: ConfigurationType | undefined): ConfigurationTypes | undefined;
5
+ export declare function getConfigChildType(entry: ConfigurationType | undefined): Function | undefined;
6
+ export declare function getConfigurationForCtor(ctor: Ctor | undefined): Config;
7
+ export declare function getConfigurationValue(ctor: Ctor | undefined, key: PropertyKey): ConfigurationType | undefined;
8
+ export declare function getConfigurationType(ctor: Ctor | undefined, key: PropertyKey): ConfigurationTypes | undefined;
9
+ export declare function getConfigurationChildType(ctor: Ctor | undefined, key: PropertyKey): Function | undefined;
10
+ export {};
@@ -1,6 +1,6 @@
1
1
  import "@tsmetadata/polyfill";
2
2
  export declare const child: any;
3
- export declare const modelRef: any;
3
+ export declare function modelRef<T extends Function>(childCtor: T): any;
4
4
  export declare const model: any;
5
5
  export declare const id: any;
6
6
  export declare const state: any;
package/dist/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import "@tsmetadata/polyfill";
2
2
  import Store, { createStore, updateStore } from "./store/Store";
3
3
  import Model from "./model/Model";
4
- import { mount, unmount, onSnapshot, toSnapshot, applySnapshot, onSnapshotDiff } from "./api";
4
+ import { mount, onSnapshot, toSnapshot, applySnapshot, onSnapshotDiff, findModelById } from "./api";
5
5
  import { createContext } from "./context";
6
6
  import { toObservableTree } from "./toObservableTree";
7
- export { createStore, Store, Model, mount, unmount, updateStore, onSnapshot, onSnapshotDiff, toSnapshot, applySnapshot, createContext, toObservableTree, };
7
+ export { createStore, Store, Model, mount, updateStore, onSnapshot, onSnapshotDiff, toSnapshot, applySnapshot, findModelById, createContext, toObservableTree, };
8
8
  export { observable, computed, source, reportChanged, reportObserved, getSignal, isObservable, reaction, Signal, type ReadonlySignal, batch, untracked, effect, signal, Observable, } from "./observables";
9
9
  export * from "./decorators";
10
10
  export type { Configuration, Snapshot, SnapshotValue, IdType, SnapshotDiff, } from "./types";
@@ -1,17 +1,13 @@
1
1
  import type { ModelConfiguration, Snapshot } from "../types";
2
- type ExtractModelDidInitArgs<T extends Model> = T extends {
3
- modelDidInit(...args: infer Args): unknown;
4
- } ? Args extends [infer Snapshot, ...infer Rest] ? Rest : [] : [];
5
- export default class Model {
6
- static get types(): ModelConfiguration<unknown>;
2
+ export default class Model implements Disposable {
3
+ static types?: ModelConfiguration<unknown>;
7
4
  static childTypes: object;
8
5
  static create<T extends Model = Model>(this: {
9
6
  new (...args: unknown[]): T;
10
- }, snapshot?: Snapshot<T>, ...args: ExtractModelDidInitArgs<T>): T;
7
+ }, snapshot?: Snapshot<T>): T;
11
8
  constructor();
12
9
  get parent(): Model | null;
13
- modelDidInit(snapshot?: Snapshot<this>, ...args: unknown[]): void;
14
- modelDidAttach(): void;
15
- modelWillDetach(): void;
10
+ reaction<T>(track: () => T, callback: (value: T, previousValue: T) => void): () => void;
11
+ effect(callback: () => void | (() => void)): () => void;
12
+ [Symbol.dispose](): void;
16
13
  }
17
- export {};
@@ -5,6 +5,8 @@ import type { ModelConfiguration, Snapshot, SnapshotChange } from "../types";
5
5
  export declare function getConfigurationFromSnapshot(snapshot: object): ModelConfiguration<unknown> | undefined;
6
6
  export declare function getModelAdm<T extends Model>(model: T): ModelAdministration;
7
7
  export declare class ModelAdministration extends PreactObjectAdministration<any> {
8
+ private getCfgType;
9
+ private getCfgChildType;
8
10
  static proxyTraps: ProxyHandler<object>;
9
11
  private configurationGetter?;
10
12
  private _parent;
@@ -18,13 +20,20 @@ export declare class ModelAdministration extends PreactObjectAdministration<any>
18
20
  private computedSnapshot;
19
21
  private snapshotMap;
20
22
  private contextCache;
23
+ private ownedDisposers;
24
+ private disposed;
21
25
  parentName: PropertyKey | null;
22
26
  get parent(): ModelAdministration | null;
23
27
  set parent(value: ModelAdministration | null);
24
28
  setConfiguration(configurationGetter: () => ModelConfiguration<any>): void;
29
+ assertUsable(): void;
30
+ private own;
31
+ reaction<T>(track: () => T, callback: (value: T, previousValue: T) => void): () => void;
32
+ effect(callback: () => void | (() => void)): () => void;
25
33
  private get configuration();
26
34
  private getReferencedAtom;
27
35
  private setState;
36
+ private hydrateStateValue;
28
37
  private setId;
29
38
  private setModel;
30
39
  private setModels;
@@ -32,12 +41,17 @@ export declare class ModelAdministration extends PreactObjectAdministration<any>
32
41
  private getModelRefs;
33
42
  private setModelRef;
34
43
  private setModelRefs;
44
+ private getRequiredModelRefType;
45
+ private assertModelRefType;
35
46
  private attach;
47
+ private getReactiveRoot;
36
48
  private detach;
49
+ dispose(internal?: boolean): void;
37
50
  getContextValue<T>(contextId: symbol, provideSymbol: symbol, defaultValue: T | undefined, hasDefault: boolean): T;
38
51
  private lookupContextValue;
39
52
  private toJSON;
40
53
  onSnapshotChange(onChange: SnapshotChange<any>): () => void;
41
54
  loadSnapshot(snapshot: Snapshot<any>): void;
42
55
  getSnapshot(): Snapshot<any>;
56
+ getSnapshotForRollback(): Snapshot<any>;
43
57
  }
@@ -1,8 +1,8 @@
1
1
  import type { IdType } from "../types";
2
- import type Model from "./Model";
3
- export declare function onSnapshotLoad<T>(fn: () => T): T;
4
- export declare function setIdentifier(model: Model, id: string | number): void;
2
+ import Model from "./Model";
3
+ export type ModelConstructor<T extends Model = Model> = new (...args: any[]) => T;
4
+ export declare function setIdentifier(model: Model, id: IdType): void;
5
5
  export declare function getIdentifier(model: Model): IdType | undefined;
6
- export declare function getModelById(root: Model, id: IdType): Model | undefined;
6
+ export declare function getModelById<T extends Model>(root: Model, Type: ModelConstructor<T>, id: IdType): T | undefined;
7
7
  export declare function onModelAttached(model: Model): void;
8
8
  export declare function onModelDetached(model: Model): void;
@@ -41,7 +41,7 @@ export declare function createSignal<T>(initialValue: T): SignalNode<T>;
41
41
  export declare function createAtom(): AtomNode;
42
42
  export { effect, batch, untracked, Signal };
43
43
  export type { ReadonlySignal };
44
- export declare function reaction<T>(fn: () => T, callback: (value: T) => void): () => void;
44
+ export declare function reaction<T>(fn: () => T, callback: (value: T, previousValue: T) => void): () => void;
45
45
  export type Listener = {
46
46
  dispose: () => void;
47
47
  track: <T>(trackFn: () => T) => T;