@pyreon/state-tree 0.0.1

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/src/types.ts ADDED
@@ -0,0 +1,98 @@
1
+ import type { Computed, Signal } from '@pyreon/reactivity'
2
+
3
+ // ─── Model brand ──────────────────────────────────────────────────────────────
4
+
5
+ /** Property key stamped on every ModelDefinition to distinguish it from plain objects. */
6
+ export const MODEL_BRAND = '__pyreonMod' as const
7
+
8
+ // ─── State type helpers ───────────────────────────────────────────────────────
9
+
10
+ export type StateShape = Record<string, unknown>
11
+
12
+ /**
13
+ * Resolve a state field type:
14
+ * - ModelDefinition → the instance type it produces
15
+ * - Anything else → as-is
16
+ */
17
+ export type ResolveField<T> = T extends {
18
+ readonly __pyreonMod: true
19
+ create(initial?: any): infer I
20
+ }
21
+ ? I
22
+ : T
23
+
24
+ /** Map state shape to per-field signals. */
25
+ export type StateSignals<TState extends StateShape> = {
26
+ readonly [K in keyof TState]: Signal<ResolveField<TState[K]>>
27
+ }
28
+
29
+ /**
30
+ * `self` type inside actions / views:
31
+ * strongly typed for state signals, `any` for actions and views so that
32
+ * actions can call each other without circular type issues.
33
+ */
34
+ export type ModelSelf<TState extends StateShape> = StateSignals<TState> &
35
+ Record<string, any>
36
+
37
+ /** The public instance type returned by `.create()` and hooks. */
38
+ export type ModelInstance<
39
+ TState extends StateShape,
40
+ TActions extends Record<string, (...args: any[]) => any>,
41
+ TViews extends Record<string, Signal<any> | Computed<any>>,
42
+ > = StateSignals<TState> & TActions & TViews
43
+
44
+ /**
45
+ * Extract the state type from a ModelDefinition.
46
+ * Used by Snapshot to recursively resolve nested model types.
47
+ */
48
+ type ExtractModelState<T> = T extends {
49
+ readonly __pyreonMod: true
50
+ readonly _config: { state: infer S extends StateShape }
51
+ }
52
+ ? S
53
+ : never
54
+
55
+ /**
56
+ * Snapshot type: plain JS values (no signals, no model instances).
57
+ * Nested model fields recursively produce their own typed snapshot.
58
+ */
59
+ export type Snapshot<TState extends StateShape> = {
60
+ [K in keyof TState]: TState[K] extends { readonly __pyreonMod: true }
61
+ ? Snapshot<ExtractModelState<TState[K]>>
62
+ : TState[K]
63
+ }
64
+
65
+ // ─── Patch ────────────────────────────────────────────────────────────────────
66
+
67
+ export interface Patch {
68
+ op: 'replace'
69
+ path: string
70
+ value: unknown
71
+ }
72
+
73
+ export type PatchListener = (patch: Patch) => void
74
+
75
+ // ─── Middleware ───────────────────────────────────────────────────────────────
76
+
77
+ export interface ActionCall {
78
+ /** Action name. */
79
+ name: string
80
+ /** Arguments passed to the action. */
81
+ args: unknown[]
82
+ /** JSON-pointer-style path, e.g. `"/inc"`. */
83
+ path: string
84
+ }
85
+
86
+ export type MiddlewareFn = (
87
+ call: ActionCall,
88
+ next: (nextCall: ActionCall) => unknown,
89
+ ) => unknown
90
+
91
+ // ─── Instance metadata ────────────────────────────────────────────────────────
92
+
93
+ export interface InstanceMeta {
94
+ stateKeys: string[]
95
+ patchListeners: Set<PatchListener>
96
+ middlewares: MiddlewareFn[]
97
+ emitPatch(patch: Patch): void
98
+ }