@astrale-os/kernel-dsl 0.2.0-beta.15 → 0.2.0-beta.18

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/CHANGELOG.md ADDED
@@ -0,0 +1,221 @@
1
+ # Changelog
2
+
3
+ ## [0.2.0-beta.18](https://github.com/astrale-os/kernel/compare/kernel-dsl-v0.2.0-beta.17...kernel-dsl-v0.2.0-beta.18) (2026-08-29)
4
+
5
+
6
+ ### Features
7
+
8
+ * **dsl:** make StateProperty topology portable ([#534](https://github.com/astrale-os/kernel/issues/534)) ([f71cf87](https://github.com/astrale-os/kernel/commit/f71cf879e68475ffd002cafe6688be0649eb9c49))
9
+
10
+ ## [0.2.0-beta.17](https://github.com/astrale-os/kernel/compare/kernel-dsl-v0.2.0-beta.16...kernel-dsl-v0.2.0-beta.17) (2026-08-29)
11
+
12
+
13
+ ### ⚠ BREAKING CHANGES
14
+
15
+ * View declarations now contain only target and optional description. Legacy View.auth fields are rejected; callable authorization, View.resolve admission, Policies, and Shell handshakes remain independent.
16
+ * **dsl:** make edge direction explicit
17
+
18
+ ### Features
19
+
20
+ * add aliased domain dependency projection ([afb799b](https://github.com/astrale-os/kernel/commit/afb799b0d61fd6f7436fe659f558a6a62ef1e7a1))
21
+ * add aliased Domain dependency projection ([9c4c4fb](https://github.com/astrale-os/kernel/commit/9c4c4fb4f942c0c5e3961faf4428ed299d42f847))
22
+ * add compiled remote domain serving ([ac9e365](https://github.com/astrale-os/kernel/commit/ac9e36538982a91359712e4cbbc68353ea2cc1a2))
23
+ * add compiled remote Domain serving ([6149628](https://github.com/astrale-os/kernel/commit/6149628820d1294981156ff5b50ceaa522ea0403))
24
+ * **callable:** preserve native binary streams and status ([d14c6f1](https://github.com/astrale-os/kernel/commit/d14c6f13492c14a3363b2c4af59c738034752fa2))
25
+ * **dsl:** authorize Edge value reads with policies ([#502](https://github.com/astrale-os/kernel/issues/502)) ([a27e129](https://github.com/astrale-os/kernel/commit/a27e129378ff64e69031a011cbfa21299998a35e))
26
+ * **dsl:** make edge direction explicit ([3f05bf5](https://github.com/astrale-os/kernel/commit/3f05bf52ce5b20e9f549ec0fd98cb0e4e03de1ea))
27
+ * remove Property visibility and cut DSL V2 ([#518](https://github.com/astrale-os/kernel/issues/518)) ([4d99e8f](https://github.com/astrale-os/kernel/commit/4d99e8f0837136cf6be257ab3a6df666b62e06b5))
28
+ * remove View authentication declarations ([4a5bfe0](https://github.com/astrale-os/kernel/commit/4a5bfe016717267d31257748f95e7f646782f876))
29
+ * **runtime:** implement auto property projection lifecycle ([#451](https://github.com/astrale-os/kernel/issues/451)) ([e0c484a](https://github.com/astrale-os/kernel/commit/e0c484a79f2d5314b6a54597c340bd09d3e4e566))
30
+ * **schema:** split inspection and add convergence ([6afbd39](https://github.com/astrale-os/kernel/commit/6afbd39506b8a9e37225aded1c02f94ffa64e54b))
31
+
32
+
33
+ ### Bug Fixes
34
+
35
+ * admit optional callable node paths ([#464](https://github.com/astrale-os/kernel/issues/464)) ([8f261d5](https://github.com/astrale-os/kernel/commit/8f261d54dfb489541d2976892c5cacadf688f1a1))
36
+ * **api:** retain visibility-free DSL as V1 ([#526](https://github.com/astrale-os/kernel/issues/526)) ([e24c1ea](https://github.com/astrale-os/kernel/commit/e24c1ea257e8567d9bd33c6ada0de63bb346a496))
37
+ * **boot:** point local host CLI at graph.query ([8341e10](https://github.com/astrale-os/kernel/commit/8341e1020cd32848ffb95de80e66936f17db3087))
38
+ * **boot:** point local host CLI at graph.query ([70c656b](https://github.com/astrale-os/kernel/commit/70c656bc7162b477a97ace4b999f8e7f6bf3a988))
39
+ * **ci:** enforce the official Kernel cohort ([#469](https://github.com/astrale-os/kernel/issues/469)) ([f6ea87a](https://github.com/astrale-os/kernel/commit/f6ea87a47f7b1f9c415e404dc1a09b480a2a3f5f))
40
+ * **core:** preserve callable identity and runtime boundaries ([#394](https://github.com/astrale-os/kernel/issues/394)) ([ad67dad](https://github.com/astrale-os/kernel/commit/ad67dad84aef3c8b79f769009595ea1f1229026b))
41
+ * **deps:** refresh the Kernel dependency cohort ([#393](https://github.com/astrale-os/kernel/issues/393)) ([883e7bb](https://github.com/astrale-os/kernel/commit/883e7bb7ce17eecb7dad1c94ad2089c576ba3746))
42
+ * **dsl:** close runtime facade contracts ([ff99450](https://github.com/astrale-os/kernel/commit/ff99450ce3889013f57c39293e7022b32e186ca6))
43
+ * **dsl:** close semantic qualification gaps ([4a48cd7](https://github.com/astrale-os/kernel/commit/4a48cd729bcaf839ceda880b26ade064d6505fe2))
44
+ * **dsl:** expose runtime-clean load paths ([7dba075](https://github.com/astrale-os/kernel/commit/7dba075887e4796e5464d5a41ddb03212eed887f))
45
+ * **dsl:** keep schema projections declaration-nameable ([#432](https://github.com/astrale-os/kernel/issues/432)) ([448d23d](https://github.com/astrale-os/kernel/commit/448d23d58fc2b564ef93be4a54dc8ebd385b5066))
46
+ * **dsl:** make schema declarations portable ([55e13c0](https://github.com/astrale-os/kernel/commit/55e13c06896eb5d6cf195607aec10f176b585504))
47
+ * **dsl:** make schema declarations portable ([90c04ac](https://github.com/astrale-os/kernel/commit/90c04acfa5af714c70a92dc90999675d53f159bc))
48
+ * **dsl:** preserve generic resolved domain type ([46f306b](https://github.com/astrale-os/kernel/commit/46f306bc3d1c73c822608c777a82f4502591d3e2))
49
+ * **dsl:** reject unknown authoring fields on edge endpoints ([0483aa9](https://github.com/astrale-os/kernel/commit/0483aa9d985459c873922262b6f60363ffb3902b))
50
+ * **dsl:** reject unknown authoring fields on edge endpoints ([cb90dae](https://github.com/astrale-os/kernel/commit/cb90dae6e165166ddcfe5e31ee2780d36b07ea53))
51
+ * **dsl:** reject unknown edge endpoint fields ([06a47ed](https://github.com/astrale-os/kernel/commit/06a47edf1bb1ba58d0ac7258e810ef2d20b30c69))
52
+ * **dsl:** reject unknown edge endpoint fields ([2d83dbf](https://github.com/astrale-os/kernel/commit/2d83dbf25a3e3818f9db2519b15741d109750727))
53
+ * **dsl:** trust exact generated build material ([#466](https://github.com/astrale-os/kernel/issues/466)) ([77f2686](https://github.com/astrale-os/kernel/commit/77f26862d8041928029c04da9f2b2521a101c17e))
54
+ * **packages:** keep workspace guard private ([e0ba76c](https://github.com/astrale-os/kernel/commit/e0ba76c5ae163245e31115e2a72e0663db0f5320))
55
+ * **packages:** keep workspace guard private ([d260a52](https://github.com/astrale-os/kernel/commit/d260a52329cde5ce4b0260c43a3bbf28cb78f408))
56
+ * **packages:** keep workspace guard private ([a3e82ec](https://github.com/astrale-os/kernel/commit/a3e82ec671f07252a5966b4de988e275e4078b8c))
57
+ * publish a TypeScript-compatible cohort ([#406](https://github.com/astrale-os/kernel/issues/406)) ([f1a0cd0](https://github.com/astrale-os/kernel/commit/f1a0cd09f2f0b4498f9fa8924b2e319cac6552b7))
58
+ * **release:** add package repository metadata ([8238077](https://github.com/astrale-os/kernel/commit/8238077d47a96c0f7b50a1bae8769fe4faab45b7))
59
+ * **release:** harden public package closure ([#397](https://github.com/astrale-os/kernel/issues/397)) ([5a5886f](https://github.com/astrale-os/kernel/commit/5a5886fe66c7b3ea0a014766a5df8c04fd93efeb))
60
+ * **schema:** harden introspection evidence and caches ([9516eb5](https://github.com/astrale-os/kernel/commit/9516eb510242427296861ef9e730b01861e45463))
61
+ * stabilize governed Kernel integration ([#347](https://github.com/astrale-os/kernel/issues/347)) ([6869e3f](https://github.com/astrale-os/kernel/commit/6869e3fc4de1e73ff701bb38383e89c934ddfdf2))
62
+ * **system:** clear Codegraph diagnostic debt ([f7a8e1f](https://github.com/astrale-os/kernel/commit/f7a8e1f5c5694d9c3c45d95fde184f0d5f2c7343))
63
+ * **system:** clear Codegraph diagnostic debt ([45f86a9](https://github.com/astrale-os/kernel/commit/45f86a9ce14a224efed0e07966a5df8d7a892078))
64
+ * **system:** preserve erased domain and runtime facade contracts ([b525d47](https://github.com/astrale-os/kernel/commit/b525d4781d2d58776ec6b4bbe1e045a3c1accebb))
65
+ * **system:** preserve public revision vocabulary ([5e990d0](https://github.com/astrale-os/kernel/commit/5e990d0b28578a040b80c508943552c46b8632ae))
66
+ * **test:** preserve authored semantic contracts ([bedb8cd](https://github.com/astrale-os/kernel/commit/bedb8cd2d36f4a95cb8d219067df0d0e39100f08))
67
+
68
+
69
+ ### Documentation
70
+
71
+ * **release:** align kernel beta changelogs ([ad59dbc](https://github.com/astrale-os/kernel/commit/ad59dbc8df458d8bd025692d594b0b4666cd2e1f))
72
+
73
+ ## [0.2.0-beta.16](https://github.com/astrale-os/kernel/compare/kernel-dsl-v0.2.0-beta.15...kernel-dsl-v0.2.0-beta.16) (2026-08-29)
74
+
75
+
76
+ ### Features
77
+
78
+ * remove Property visibility and cut DSL V2 ([#518](https://github.com/astrale-os/kernel/issues/518)) ([4d99e8f](https://github.com/astrale-os/kernel/commit/4d99e8f0837136cf6be257ab3a6df666b62e06b5))
79
+
80
+
81
+ ### Bug Fixes
82
+
83
+ * **api:** retain visibility-free DSL as V1 ([#526](https://github.com/astrale-os/kernel/issues/526)) ([e24c1ea](https://github.com/astrale-os/kernel/commit/e24c1ea257e8567d9bd33c6ada0de63bb346a496))
84
+
85
+ ## [0.2.0-beta.15](https://github.com/astrale-os/kernel/compare/kernel-dsl-v0.2.0-beta.14...kernel-dsl-v0.2.0-beta.15) (2026-08-27)
86
+
87
+
88
+ ### Features
89
+
90
+ * **dsl:** authorize Edge value reads with policies ([#502](https://github.com/astrale-os/kernel/issues/502)) ([a27e129](https://github.com/astrale-os/kernel/commit/a27e129378ff64e69031a011cbfa21299998a35e))
91
+
92
+ ## [0.2.0-beta.14](https://github.com/astrale-os/kernel/compare/kernel-dsl-v0.2.0-beta.13...kernel-dsl-v0.2.0-beta.14) (2026-08-26)
93
+
94
+
95
+ ### Bug Fixes
96
+
97
+ * **ci:** enforce the official Kernel cohort ([#469](https://github.com/astrale-os/kernel/issues/469)) ([f6ea87a](https://github.com/astrale-os/kernel/commit/f6ea87a47f7b1f9c415e404dc1a09b480a2a3f5f))
98
+
99
+ ## [0.2.0-beta.13](https://github.com/astrale-os/kernel/compare/kernel-dsl-v0.2.0-beta.12...kernel-dsl-v0.2.0-beta.13) (2026-08-26)
100
+
101
+
102
+ ### Features
103
+
104
+ * **runtime:** implement auto property projection lifecycle ([#451](https://github.com/astrale-os/kernel/issues/451)) ([e0c484a](https://github.com/astrale-os/kernel/commit/e0c484a79f2d5314b6a54597c340bd09d3e4e566))
105
+
106
+
107
+ ### Bug Fixes
108
+
109
+ * **dsl:** trust exact generated build material ([#466](https://github.com/astrale-os/kernel/issues/466)) ([77f2686](https://github.com/astrale-os/kernel/commit/77f26862d8041928029c04da9f2b2521a101c17e))
110
+
111
+ ## [0.2.0-beta.12](https://github.com/astrale-os/kernel/compare/kernel-dsl-v0.2.0-beta.11...kernel-dsl-v0.2.0-beta.12) (2026-08-26)
112
+
113
+
114
+ ### Bug Fixes
115
+
116
+ * admit optional callable node paths ([#464](https://github.com/astrale-os/kernel/issues/464)) ([8f261d5](https://github.com/astrale-os/kernel/commit/8f261d54dfb489541d2976892c5cacadf688f1a1))
117
+ * **system:** clear Codegraph diagnostic debt ([f7a8e1f](https://github.com/astrale-os/kernel/commit/f7a8e1f5c5694d9c3c45d95fde184f0d5f2c7343))
118
+
119
+ ## [0.2.0-beta.11](https://github.com/astrale-os/kernel/compare/kernel-dsl-v0.2.0-beta.10...kernel-dsl-v0.2.0-beta.11) (2026-08-25)
120
+
121
+
122
+ ### Features
123
+
124
+ * **callable:** preserve native binary streams and status ([d14c6f1](https://github.com/astrale-os/kernel/commit/d14c6f13492c14a3363b2c4af59c738034752fa2))
125
+ * **schema:** split inspection and add convergence ([6afbd39](https://github.com/astrale-os/kernel/commit/6afbd39506b8a9e37225aded1c02f94ffa64e54b))
126
+
127
+
128
+ ### Bug Fixes
129
+
130
+ * **schema:** harden introspection evidence and caches ([9516eb5](https://github.com/astrale-os/kernel/commit/9516eb510242427296861ef9e730b01861e45463))
131
+
132
+ ## [0.2.0-beta.10](https://github.com/astrale-os/kernel/compare/kernel-dsl-v0.2.0-beta.9...kernel-dsl-v0.2.0-beta.10) (2026-08-25)
133
+
134
+
135
+ ### Bug Fixes
136
+
137
+ * **dsl:** keep schema projections declaration-nameable ([#432](https://github.com/astrale-os/kernel/issues/432)) ([448d23d](https://github.com/astrale-os/kernel/commit/448d23d58fc2b564ef93be4a54dc8ebd385b5066))
138
+
139
+ ## [0.2.0-beta.9](https://github.com/astrale-os/kernel/compare/kernel-dsl-v0.2.0-beta.8...kernel-dsl-v0.2.0-beta.9) (2026-08-24)
140
+
141
+
142
+ ### Bug Fixes
143
+
144
+ * **packages:** keep workspace guard private ([e0ba76c](https://github.com/astrale-os/kernel/commit/e0ba76c5ae163245e31115e2a72e0663db0f5320))
145
+ * **packages:** keep workspace guard private ([d260a52](https://github.com/astrale-os/kernel/commit/d260a52329cde5ce4b0260c43a3bbf28cb78f408))
146
+ * **packages:** keep workspace guard private ([a3e82ec](https://github.com/astrale-os/kernel/commit/a3e82ec671f07252a5966b4de988e275e4078b8c))
147
+
148
+ ## [0.2.0-beta.8](https://github.com/astrale-os/kernel/compare/kernel-dsl-v0.2.0-beta.7...kernel-dsl-v0.2.0-beta.8) (2026-08-24)
149
+
150
+
151
+ ### Features
152
+
153
+ * add aliased domain dependency projection ([afb799b](https://github.com/astrale-os/kernel/commit/afb799b0d61fd6f7436fe659f558a6a62ef1e7a1))
154
+ * add aliased Domain dependency projection ([9c4c4fb](https://github.com/astrale-os/kernel/commit/9c4c4fb4f942c0c5e3961faf4428ed299d42f847))
155
+
156
+ ## [0.2.0-beta.7](https://github.com/astrale-os/kernel/compare/kernel-dsl-v0.2.0-beta.6...kernel-dsl-v0.2.0-beta.7) (2026-08-24)
157
+
158
+
159
+ ### Bug Fixes
160
+
161
+ * **dsl:** make schema declarations portable ([55e13c0](https://github.com/astrale-os/kernel/commit/55e13c06896eb5d6cf195607aec10f176b585504))
162
+ * publish a TypeScript-compatible cohort ([#406](https://github.com/astrale-os/kernel/issues/406)) ([f1a0cd0](https://github.com/astrale-os/kernel/commit/f1a0cd09f2f0b4498f9fa8924b2e319cac6552b7))
163
+
164
+ ## [0.2.0-beta.6](https://github.com/astrale-os/kernel/compare/kernel-dsl-v0.2.0-beta.5...kernel-dsl-v0.2.0-beta.6) (2026-08-23)
165
+
166
+
167
+ ### Bug Fixes
168
+
169
+ * **core:** preserve callable identity and runtime boundaries ([#394](https://github.com/astrale-os/kernel/issues/394)) ([ad67dad](https://github.com/astrale-os/kernel/commit/ad67dad84aef3c8b79f769009595ea1f1229026b))
170
+ * **deps:** refresh the Kernel dependency cohort ([#393](https://github.com/astrale-os/kernel/issues/393)) ([883e7bb](https://github.com/astrale-os/kernel/commit/883e7bb7ce17eecb7dad1c94ad2089c576ba3746))
171
+ * **dsl:** close runtime facade contracts ([ff99450](https://github.com/astrale-os/kernel/commit/ff99450ce3889013f57c39293e7022b32e186ca6))
172
+ * **dsl:** close semantic qualification gaps ([4a48cd7](https://github.com/astrale-os/kernel/commit/4a48cd729bcaf839ceda880b26ade064d6505fe2))
173
+ * **dsl:** expose runtime-clean load paths ([7dba075](https://github.com/astrale-os/kernel/commit/7dba075887e4796e5464d5a41ddb03212eed887f))
174
+ * **dsl:** preserve generic resolved domain type ([46f306b](https://github.com/astrale-os/kernel/commit/46f306bc3d1c73c822608c777a82f4502591d3e2))
175
+ * **release:** harden public package closure ([#397](https://github.com/astrale-os/kernel/issues/397)) ([5a5886f](https://github.com/astrale-os/kernel/commit/5a5886fe66c7b3ea0a014766a5df8c04fd93efeb))
176
+ * **system:** preserve erased domain and runtime facade contracts ([b525d47](https://github.com/astrale-os/kernel/commit/b525d4781d2d58776ec6b4bbe1e045a3c1accebb))
177
+ * **system:** preserve public revision vocabulary ([5e990d0](https://github.com/astrale-os/kernel/commit/5e990d0b28578a040b80c508943552c46b8632ae))
178
+ * **test:** preserve authored semantic contracts ([bedb8cd](https://github.com/astrale-os/kernel/commit/bedb8cd2d36f4a95cb8d219067df0d0e39100f08))
179
+
180
+ ## [0.2.0-beta.5](https://github.com/astrale-os/kernel/compare/kernel-dsl-v0.2.0-beta.4...kernel-dsl-v0.2.0-beta.5) (2026-08-21)
181
+
182
+
183
+ ### ⚠ BREAKING CHANGES
184
+
185
+ * View declarations now contain only target and optional description. Legacy View.auth fields are rejected; callable authorization, View.resolve admission, Policies, and Shell handshakes remain independent.
186
+
187
+ ### Features
188
+
189
+ * remove View authentication declarations ([4a5bfe0](https://github.com/astrale-os/kernel/commit/4a5bfe016717267d31257748f95e7f646782f876))
190
+
191
+ ## [0.2.0-beta.4](https://github.com/astrale-os/kernel/compare/kernel-dsl-v0.2.0-beta.3...kernel-dsl-v0.2.0-beta.4) (2026-08-21)
192
+
193
+
194
+ ### Bug Fixes
195
+
196
+ * **release:** add package repository metadata ([8238077](https://github.com/astrale-os/kernel/commit/8238077d47a96c0f7b50a1bae8769fe4faab45b7))
197
+
198
+ ## [0.1.5](https://github.com/astrale-os/kernel/compare/kernel-dsl-v0.1.4...kernel-dsl-v0.1.5) (2026-08-07)
199
+
200
+
201
+ ### Features
202
+
203
+ * **dsl:** add non-breaking policy IR preview ([1202d29](https://github.com/astrale-os/kernel/commit/1202d294cc7f32bc8e3e29d7537d3604403d09a5))
204
+ * **dsl:** align policy authoring with v1 ([514961f](https://github.com/astrale-os/kernel/commit/514961f9902d97e96535126b0a983764bb0f30ac))
205
+ * **dsl:** align policy authoring with v1 ([d082d5e](https://github.com/astrale-os/kernel/commit/d082d5e923458c0eec4ee28358f1b41309067843))
206
+
207
+ ## [0.1.4](https://github.com/astrale-os/kernel/compare/kernel-dsl-v0.1.3...kernel-dsl-v0.1.4) (2026-07-10)
208
+
209
+
210
+ ### Bug Fixes
211
+
212
+ * export ./package.json from all published packages ([9560a34](https://github.com/astrale-os/kernel/commit/9560a34379c68d475f09a863e9d1962b560d83a0))
213
+ * export ./package.json from all published packages ([8633acb](https://github.com/astrale-os/kernel/commit/8633acba8953644805fc43840732bd16c3e19ab1))
214
+ * export ./package.json in publishConfig.exports too — the map that ships ([85ba0a1](https://github.com/astrale-os/kernel/commit/85ba0a121466ed5ef33fced51d28c0d09a7c0ec4))
215
+
216
+ ## [0.1.3](https://github.com/astrale-os/kernel/compare/kernel-dsl-v0.1.2...kernel-dsl-v0.1.3) (2026-07-08)
217
+
218
+
219
+ ### Features
220
+
221
+ * support top-level functions of the kernel domain ([db45b06](https://github.com/astrale-os/kernel/commit/db45b061d0a7562950277344778991592f0a19eb))
@@ -6,12 +6,13 @@ import type { ResolvedMethod } from '../../language/callable/resolved.js';
6
6
  import type { MediaType } from '../../language/class/model/data.js';
7
7
  import type { EdgeCount } from '../../language/class/model/edge.js';
8
8
  import type { ResolvedClass, ResolvedProperty } from '../../language/class/resolved.js';
9
+ import type { StateTopology, StateTopologyOf } from '../../language/state/topology.js';
9
10
  import type { Method, ProjectionOfCallable } from '../callable/authoring.js';
10
11
  import type { Policy } from '../policy/authoring.js';
11
12
  import type { Lazy } from '../schema/lazy.js';
12
13
  import type { ClassProjectionOfResolved } from '../schema/projection.js';
13
14
  import type { TypedValueSchema } from '../value/schema.js';
14
- import type { AutoProperty, Property, PropertyOptions, ValueSchemaInput } from './property.js';
15
+ import type { AutoProperty, Property, PropertyOptions, PropertyStateMachineOf, ValueSchemaInput } from './property.js';
15
16
  import type { PropertyRecordInput } from './property.js';
16
17
  import { type AUTHORING } from '../schema/handle.js';
17
18
  declare const CLASS_TYPE: unique symbol;
@@ -88,26 +89,27 @@ export type ClassInput = ({
88
89
  readonly abstract: boolean;
89
90
  } & Omit<UndirectedEdgeInput, 'orientation'>);
90
91
  export type Class = NodeClass | EdgeClass;
91
- export interface AuthoredPropertyProjection<out Input = unknown, out Output = unknown, out Required extends boolean = boolean, out Name extends string = string, out Owner = 'self'> {
92
+ export interface AuthoredPropertyProjection<out Input = unknown, out Output = unknown, out Required extends boolean = boolean, out Name extends string = string, out Owner = 'self', out State extends StateTopology | undefined = StateTopology | undefined> {
92
93
  readonly input: Input;
93
94
  readonly output: Output;
94
95
  readonly required: Required;
95
96
  readonly name: Name;
96
97
  readonly owner: Owner;
98
+ readonly state?: State;
97
99
  }
98
100
  export interface AuthoredMethodProjection<out Value extends Method = Method, out Name extends string = string, out Owner = 'self'> {
99
101
  readonly value: Value;
100
102
  readonly name: Name;
101
103
  readonly owner: Owner;
102
104
  }
103
- type PropertySchemaOf<Field> = Field extends AutoProperty<infer Value> ? PropertySchemaOf<Value> : Field extends Property<infer Schema, PropertyOptions> ? Schema : Field;
104
- type PropertyOptionsOf<Field> = Field extends AutoProperty<infer Value> ? PropertyOptionsOf<Value> : Field extends Property<ValueSchemaInput, infer Options> ? Options : Record<never, never>;
105
+ type PropertySchemaOf<Field> = Field extends AutoProperty<infer Value> ? PropertySchemaOf<Value> : Field extends Property<infer Schema, PropertyOptions, unknown> ? Schema : Field;
106
+ type PropertyOptionsOf<Field> = Field extends AutoProperty<infer Value> ? PropertyOptionsOf<Value> : Field extends Property<ValueSchemaInput, infer Options, unknown> ? Options : Record<never, never>;
105
107
  type ValueInputOf<Schema> = Schema extends TypedValueSchema<infer Value> ? Value : Schema extends z.ZodType ? z.input<Schema> : PortableValue;
106
108
  type ValueOutputOf<Schema> = Schema extends TypedValueSchema<infer Value> ? Value : Schema extends z.ZodType ? z.output<Schema> : PortableValue;
107
109
  type PropertyRequiredOf<Field> = PropertyOptionsOf<Field> extends {
108
110
  readonly required: infer Required extends boolean;
109
111
  } ? Required : undefined extends ValueInputOf<PropertySchemaOf<Field>> ? false : true;
110
- type PropertyProjectionOf<Name extends string, Field> = AuthoredPropertyProjection<Field extends AutoProperty ? never : ValueInputOf<PropertySchemaOf<Field>>, ValueOutputOf<PropertySchemaOf<Field>>, PropertyRequiredOf<Field>, Name>;
112
+ type PropertyProjectionOf<Name extends string, Field> = AuthoredPropertyProjection<Field extends AutoProperty ? never : ValueInputOf<PropertySchemaOf<Field>>, ValueOutputOf<PropertySchemaOf<Field>>, PropertyRequiredOf<Field>, Name, 'self', Field extends Property ? StateTopologyOf<PropertyStateMachineOf<Field>> : undefined>;
111
113
  type PropertyProjectionsOf<Input> = Input extends Readonly<Record<string, unknown>> ? {
112
114
  readonly [Name in keyof Input]: PropertyProjectionOf<Extract<Name, string>, Input[Name]>;
113
115
  } : Readonly<Record<never, never>>;
@@ -124,7 +126,7 @@ type ParentPropertyProjectionsOf<Input> = Input extends {
124
126
  type EffectivePropertyProjectionsOf<Input> = PropertyProjectionEntriesOf<'properties' extends keyof Input ? Input extends {
125
127
  readonly properties?: infer Value;
126
128
  } ? NonNullable<Value> : never : never> | ParentPropertyProjectionsOf<Input>;
127
- type BindPropertyOwners<Entries, Owner> = Entries extends AuthoredPropertyProjection<infer Input, infer Output, infer Required, infer Name, infer ExistingOwner> ? AuthoredPropertyProjection<Input, Output, Required, Name, ExistingOwner extends 'self' ? Owner : ExistingOwner> : Entries;
129
+ type BindPropertyOwners<Entries, Owner> = Entries extends AuthoredPropertyProjection<infer Input, infer Output, infer Required, infer Name, infer ExistingOwner, infer State> ? AuthoredPropertyProjection<Input, Output, Required, Name, ExistingOwner extends 'self' ? Owner : ExistingOwner, State> : Entries;
128
130
  type MethodFieldsOf<Input> = 'methods' extends keyof Input ? Input extends {
129
131
  readonly methods?: infer Methods extends Readonly<Record<string, Method>>;
130
132
  } ? NonNullable<Methods> : Readonly<Record<never, never>> : Readonly<Record<never, never>>;
@@ -208,7 +210,7 @@ type UndirectedEdgeClassIdentity<Config> = Config extends {
208
210
  readonly endpoints: Endpoints;
209
211
  readonly constraints: Constraints;
210
212
  } : never;
211
- type OwnerErasedPropertyProjection<Entry> = Entry extends AuthoredPropertyProjection<infer Input, infer Output, infer Required, infer Name, unknown> ? AuthoredPropertyProjection<Input, Output, Required, Name, unknown> : Entry extends ResolvedProperty<infer Value, infer Required> & {
213
+ type OwnerErasedPropertyProjection<Entry> = Entry extends AuthoredPropertyProjection<infer Input, infer Output, infer Required, infer Name, unknown, infer State> ? AuthoredPropertyProjection<Input, Output, Required, Name, unknown, State> : Entry extends ResolvedProperty<infer Value, infer Required, infer State> & {
212
214
  readonly name: infer Name;
213
215
  readonly key: infer Key;
214
216
  } ? {
@@ -216,6 +218,7 @@ type OwnerErasedPropertyProjection<Entry> = Entry extends AuthoredPropertyProjec
216
218
  readonly required: Required;
217
219
  readonly name: Name;
218
220
  readonly key: Key;
221
+ readonly state?: State;
219
222
  } : never;
220
223
  type OwnerErasedMethodProjection<Entry> = Entry extends AuthoredMethodProjection<infer Value, infer Name, unknown> ? AuthoredMethodProjection<Value, Name, unknown> : Entry extends ResolvedMethod<infer Input, infer Output, infer Static, infer Inheritance, infer Auth, infer _Policy, infer Key> & {
221
224
  readonly name: infer Name;
@@ -355,11 +358,18 @@ export declare const edgeClass: Readonly<{
355
358
  directed<const Input extends Omit<DirectedEdgeInput, 'orientation'>>(input: Input & {
356
359
  readonly source: ExactEndpointInput<Input['source'], DirectedSourceInput>;
357
360
  readonly target: ExactEndpointInput<Input['target'], DirectedTargetInput>;
358
- }): DirectedEdgeClass<CompactDirectedInput<Input>>;
361
+ } & WithoutStateProperties<Input>): DirectedEdgeClass<CompactDirectedInput<Input>>;
359
362
  undirected<const Input extends Omit<UndirectedEdgeInput, 'orientation'>>(input: Input & {
360
363
  readonly endpoints: readonly [ExactEndpointInput<Input['endpoints'][0], IncidentEndpointInput>, ExactEndpointInput<Input['endpoints'][1], IncidentEndpointInput>];
361
- }): UndirectedEdgeClass<CompactUndirectedInput<Input>>;
364
+ } & WithoutStateProperties<Input>): UndirectedEdgeClass<CompactUndirectedInput<Input>>;
362
365
  }>;
366
+ type WithoutStateProperties<Input> = Input extends {
367
+ readonly properties?: infer Properties extends Readonly<Record<string, unknown>>;
368
+ } ? {
369
+ readonly properties?: {
370
+ readonly [Name in keyof Properties]: Properties[Name] extends Property ? [PropertyStateMachineOf<Properties[Name]>] extends [never] ? Properties[Name] : never : Properties[Name];
371
+ };
372
+ } : unknown;
363
373
  export type ProjectionOfClass<Value extends Class> = Value extends NodeClass<infer Config> ? Config : Value extends DirectedEdgeClass<infer Input> ? Input : Value extends UndirectedEdgeClass<infer Input> ? Input : never;
364
374
  export declare function classConfiguration(value: NodeClass): NodeClassInput;
365
375
  export declare function classConfiguration(value: DirectedEdgeClass): Omit<DirectedEdgeInput, 'orientation'>;
@@ -1,12 +1,12 @@
1
1
  import type { z } from 'zod';
2
2
  import type { AutoEvent, AutoSet } from '../../language/class/model/property.js';
3
+ import type { StateMachine } from '../../language/state/index.js';
3
4
  import type { JsonSchema } from '../../language/value/model/schema.js';
4
5
  import type { AUTHORING } from '../schema/handle.js';
5
6
  declare const PROPERTY_INPUT: unique symbol;
6
7
  declare const AUTO_INPUT: unique symbol;
7
8
  export type ValueSchemaInput = z.ZodType | JsonSchema;
8
9
  export interface PropertyOptions {
9
- readonly visibility?: 'public' | 'private';
10
10
  readonly required?: boolean;
11
11
  readonly description?: string;
12
12
  }
@@ -14,15 +14,17 @@ export interface AutoOptions {
14
14
  readonly on: AutoEvent | readonly AutoEvent[];
15
15
  readonly set: AutoSet;
16
16
  }
17
- export interface Property<out Schema extends ValueSchemaInput = ValueSchemaInput, out Options extends PropertyOptions = PropertyOptions> {
17
+ export interface Property<out Schema extends ValueSchemaInput = ValueSchemaInput, out Options extends PropertyOptions = PropertyOptions, out Machine = unknown> {
18
18
  readonly [AUTHORING]: 'property';
19
19
  readonly [PROPERTY_INPUT]: {
20
20
  readonly schema: Schema;
21
21
  readonly options: Options;
22
+ readonly machine?: Machine;
22
23
  };
23
24
  }
24
- export type PropertySchemaOf<Value extends Property> = Value extends Property<infer Schema, PropertyOptions> ? Schema : never;
25
- export type PropertyOptionsOf<Value extends Property> = Value extends Property<ValueSchemaInput, infer Options> ? Options : never;
25
+ export type PropertySchemaOf<Value extends Property> = Value extends Property<infer Schema, PropertyOptions, unknown> ? Schema : never;
26
+ export type PropertyOptionsOf<Value extends Property> = Value extends Property<ValueSchemaInput, infer Options, unknown> ? Options : never;
27
+ export type PropertyStateMachineOf<Value extends Property> = Value extends Property<ValueSchemaInput, PropertyOptions, infer Machine> ? Machine : never;
26
28
  export interface AutoProperty<out PropertyValue extends Property = Property> {
27
29
  readonly [AUTHORING]: 'auto';
28
30
  readonly [AUTO_INPUT]: {
@@ -33,9 +35,10 @@ export interface AutoProperty<out PropertyValue extends Property = Property> {
33
35
  };
34
36
  };
35
37
  }
36
- export type PropertyAuthoringInput<Value extends Property> = Value extends Property<infer Schema, infer Options> ? {
38
+ export type PropertyAuthoringInput<Value extends Property> = Value extends Property<infer Schema, infer Options, infer Machine> ? {
37
39
  readonly schema: Schema;
38
40
  readonly options: Options;
41
+ readonly machine?: Machine;
39
42
  } : never;
40
43
  export declare function propertyAuthoringInput<const Value extends Property>(value: Value): PropertyAuthoringInput<Value>;
41
44
  export declare function autoPropertyAuthoringInput<const Value extends AutoProperty>(value: Value): Value extends AutoProperty<infer Property> ? {
@@ -47,6 +50,9 @@ export declare function autoPropertyAuthoringInput<const Value extends AutoPrope
47
50
  } : never;
48
51
  export type PropertyFieldInput = ValueSchemaInput | Property | AutoProperty;
49
52
  export type PropertyRecordInput = Readonly<Record<string, PropertyFieldInput>>;
50
- export declare function property<const Schema extends ValueSchemaInput, const Options extends PropertyOptions = Record<never, never>>(schema: Schema, options?: Options): Property<Schema, Options>;
51
- export declare function auto<const PropertyValue extends Property>(property: PropertyValue, options: AutoOptions): AutoProperty<PropertyValue>;
53
+ export declare function property<const Schema extends ValueSchemaInput, const Options extends PropertyOptions = Record<never, never>>(schema: Schema, options?: Options): Property<Schema, Options, never>;
54
+ export declare function stateProperty<const Machine extends StateMachine, const Options extends Omit<PropertyOptions, 'required'> = Record<never, never>>(machine: Machine, options?: Options & Record<Exclude<keyof Options, 'description'>, never>): Property<Machine['stateSchema'], Readonly<Options & {
55
+ readonly required: true;
56
+ }>, Machine>;
57
+ export declare function auto<const PropertyValue extends Property>(property: [PropertyStateMachineOf<PropertyValue>] extends [never] ? PropertyValue : never, options: AutoOptions): AutoProperty<PropertyValue>;
52
58
  export {};
@@ -10,14 +10,22 @@ export function autoPropertyAuthoringInput(value) {
10
10
  }
11
11
  export function property(schema, options) {
12
12
  const admitted = options ?? {};
13
- assertKnownKeys(admitted, ['visibility', 'required', 'description']);
13
+ assertKnownKeys(admitted, ['required', 'description']);
14
14
  return authoringValue('property', {
15
15
  [PROPERTY_INPUT]: {
16
16
  schema,
17
- options: {
18
- ...admitted,
19
- visibility: admitted.visibility ?? 'public',
20
- },
17
+ options: admitted,
18
+ },
19
+ });
20
+ }
21
+ export function stateProperty(machine, options) {
22
+ const admitted = options ?? {};
23
+ assertKnownKeys(admitted, ['description']);
24
+ return authoringValue('property', {
25
+ [PROPERTY_INPUT]: {
26
+ schema: machine.stateSchema,
27
+ options: { ...admitted, required: true },
28
+ machine,
21
29
  },
22
30
  });
23
31
  }
@@ -4,7 +4,7 @@ export { defineClass, edgeClass, nodeClass } from './class/authoring.js';
4
4
  export { fullMatch } from './value/full-match.js';
5
5
  export { path } from './value/path.js';
6
6
  export { policy } from './policy/authoring.js';
7
- export { auto, property } from './class/property.js';
7
+ export { auto, property, stateProperty } from './class/property.js';
8
8
  export { defineSchema } from './schema/define.js';
9
9
  export type { DefinedSchema } from './schema/define.js';
10
10
  export type { ResolvedDomainOfInput } from './schema/projection.js';
@@ -4,7 +4,7 @@ export { defineClass, edgeClass, nodeClass } from './class/authoring.js';
4
4
  export { fullMatch } from './value/full-match.js';
5
5
  export { path } from './value/path.js';
6
6
  export { policy } from './policy/authoring.js';
7
- export { auto, property } from './class/property.js';
7
+ export { auto, property, stateProperty } from './class/property.js';
8
8
  export { defineSchema } from './schema/define.js';
9
9
  export { valueSchema } from './value/schema.js';
10
10
  export { view } from './view/authoring.js';
@@ -36,11 +36,18 @@ export class BuilderValueSchemas {
36
36
  compiled[name] = {
37
37
  schema: canonicalizeValueSchema(schema, 'property-facet', this.registry),
38
38
  required: authoredInput?.options.required ?? isRequired(schemaInput),
39
- visibility: authoredInput?.options.visibility ?? 'public',
40
39
  ...(autoInput === undefined ? {} : { auto: autoInput.options }),
41
40
  ...(authoredInput?.options.description === undefined
42
41
  ? {}
43
42
  : { description: authoredInput.options.description }),
43
+ ...(authoredInput?.machine === undefined
44
+ ? {}
45
+ : {
46
+ state: {
47
+ initial: authoredInput.machine.initial,
48
+ transitions: authoredInput.machine.transitions,
49
+ },
50
+ }),
44
51
  };
45
52
  }
46
53
  return compiled;
@@ -1,15 +1,17 @@
1
1
  import type { Revision } from '../../addressing/index.js';
2
2
  import type * as domain from '../../domain/model/domain.js';
3
3
  import type * as language from '../../language/index.js';
4
+ import type { StateTopology } from '../../language/state/index.js';
4
5
  import type { DomainOfSchema, DomainSchema } from '../../schema/model/schema.js';
5
6
  import type { CallableProjection, Function, Method } from '../callable/authoring.js';
6
7
  import type { AuthoredPropertyProjection, AuthoredMethodProjection, Class, ClassIdentityProjection, ClassIdentityProjectionOf, ClassOwnerProjection, ClassOwnerProjectionOf, ClassReferenceProjection, ClassReferenceProjectionOf, DirectedEdgeClass, NodeClass, ProjectionOfClass, UndirectedEdgeClass } from '../class/authoring.js';
7
8
  import type { DomainSchemaInput } from './input.js';
8
- export interface PropertyProjection<Value = unknown, Required extends boolean = boolean, Name extends string = string, Key extends language.PropertyKey = language.PropertyKey> {
9
+ export interface PropertyProjection<Value = unknown, Required extends boolean = boolean, Name extends string = string, Key extends language.PropertyKey = language.PropertyKey, State extends StateTopology | undefined = StateTopology | undefined> {
9
10
  readonly value: Value;
10
11
  readonly required: Required;
11
12
  readonly name: Name;
12
13
  readonly key: Key;
14
+ readonly state?: State;
13
15
  }
14
16
  export interface MethodProjection<Input = unknown, Output = unknown, Static extends boolean = boolean, Inheritance extends language.MethodInheritance = language.MethodInheritance, Auth extends language.FunctionAuth = language.FunctionAuth, Name extends string = string, Key extends language.MethodKey = language.MethodKey> {
15
17
  readonly input: Input;
@@ -256,10 +258,10 @@ type CallableAuthOf<Value extends Method | Function> = CallableConfig<Value>['au
256
258
  type MethodProjectionOfEntry<Origin extends string, OwnerName extends string, Entry> = Entry extends language.ResolvedMethod ? MethodProjectionOfResolved<Entry> : Entry extends AuthoredMethodEntry<unknown, infer Name, infer Value> ? MethodProjection<CallableInputValue<Value>, CallableOutputValue<Value>, CallableStaticOf<Value>, CallableInheritanceOf<Value>, CallableAuthOf<Value>, Name, language.MethodKey<Origin, OwnerName, Name>> : never;
257
259
  type MethodProjectionOfEntries<Origin extends string, OwnerName extends string, Entries> = Entries extends unknown ? MethodProjectionOfEntry<Origin, OwnerName, Entries> : never;
258
260
  type MethodCollectionOperation = 'byKey' | 'get';
259
- type PropertyProjectionOfResolved<Value> = Value extends language.ResolvedProperty<infer PropertyValue, infer Required> & {
261
+ type PropertyProjectionOfResolved<Value> = Value extends language.ResolvedProperty<infer PropertyValue, infer Required, infer State> & {
260
262
  readonly name: infer Name extends string;
261
263
  readonly key: infer Key extends language.PropertyKey;
262
- } ? PropertyProjection<PropertyValue, Required, Name, Key> : never;
264
+ } ? PropertyProjection<PropertyValue, Required, Name, Key, State> : never;
263
265
  type MethodProjectionOfResolved<Value> = Value extends language.ResolvedMethod<infer Input, infer Output, infer Static, infer Inheritance, infer Auth, infer _Policy, infer Key> & {
264
266
  readonly name: infer Name extends string;
265
267
  } ? MethodProjection<Input, Output, Static, Inheritance, Auth, Name, Key> : never;
@@ -288,12 +290,12 @@ type ShallowClassProjectionTupleOfResolved<Parents extends readonly unknown[]> =
288
290
  type ExactClass<Value> = Value extends {
289
291
  readonly key: infer Key extends language.DefinitionKey<string, 'class'>;
290
292
  } ? Key extends `${infer Origin}:class.${infer Name}` ? string extends Origin ? never : string extends Name ? never : Value : never : never;
291
- type OwnPropertyProjectionsOf<Origin extends string, Name extends string, Value> = OwnPropertyEntries<Value> extends infer Entry ? Entry extends AuthoredPropertyEntry<unknown, infer PropertyName, infer Field> ? Field extends AuthoredPropertyProjection<unknown, infer Output, infer Required> ? PropertyProjection<Output, Required, PropertyName, language.PropertyKey<Origin, Name, PropertyName>> : never : never : never;
293
+ type OwnPropertyProjectionsOf<Origin extends string, Name extends string, Value> = OwnPropertyEntries<Value> extends infer Entry ? Entry extends AuthoredPropertyEntry<unknown, infer PropertyName, infer Field> ? Field extends AuthoredPropertyProjection<unknown, infer Output, infer Required, string, unknown, infer State> ? PropertyProjection<Output, Required, PropertyName, language.PropertyKey<Origin, Name, PropertyName>, State> : never : never : never;
292
294
  type EffectivePropertyEntriesOfClass<Value> = ClassInputOf<Value> extends {
293
295
  readonly effectiveProperties: infer Properties;
294
296
  } ? Properties : never;
295
297
  type OwnerNameOf<Root extends DomainSchemaInput, CurrentName extends string, Owner> = Owner extends 'self' ? CurrentName : Owner extends ClassOwnerProjection ? Extract<LocalNameOfOwner<Root, Owner>, string> : Owner extends ClassIdentityProjection ? Extract<LocalNameOfIdentity<Root, Owner>, string> : never;
296
- type EffectivePropertyProjectionOfEntry<Origin extends string, CurrentName extends string, Root extends DomainSchemaInput, Entry> = Entry extends language.ResolvedProperty ? PropertyProjectionOfResolved<Entry> : Entry extends AuthoredPropertyProjection<unknown, infer Output, infer Required, infer PropertyName, infer Owner> ? OwnerNameOf<Root, CurrentName, Owner> extends infer OwnerName extends string ? PropertyProjection<Output, Required, PropertyName, language.PropertyKey<Origin, OwnerName, PropertyName>> : never : never;
298
+ type EffectivePropertyProjectionOfEntry<Origin extends string, CurrentName extends string, Root extends DomainSchemaInput, Entry> = Entry extends language.ResolvedProperty ? PropertyProjectionOfResolved<Entry> : Entry extends AuthoredPropertyProjection<unknown, infer Output, infer Required, infer PropertyName, infer Owner, infer State> ? OwnerNameOf<Root, CurrentName, Owner> extends infer OwnerName extends string ? PropertyProjection<Output, Required, PropertyName, language.PropertyKey<Origin, OwnerName, PropertyName>, State> : never : never;
297
299
  type EffectivePropertyProjectionsOf<Origin extends string, Name extends string, Value, Root extends DomainSchemaInput> = EffectivePropertyEntriesOfClass<Value> extends infer Entry ? Entry extends unknown ? EffectivePropertyProjectionOfEntry<Origin, Name, Root, Entry> : never : never;
298
300
  type OwnInstanceMethodProjectionsOf<Origin extends string, Name extends string, Value> = MethodProjectionOfEntries<Origin, Name, OwnMethodEntries<Value, false>>;
299
301
  type OwnStaticMethodProjectionsOf<Origin extends string, Name extends string, Value> = MethodProjectionOfEntries<Origin, Name, OwnMethodEntries<Value, true>>;
@@ -316,7 +318,7 @@ type ClassProjectionOfAuthoring<Origin extends string, Name extends string, Valu
316
318
  type FunctionProjectionOfAuthoring<Origin extends string, Name extends string, Value> = Value extends Function ? FunctionProjection<CallableInputValue<Value>, CallableOutputValue<Value>, CallableAuthOf<Value>, language.FunctionRef<Name> & {
317
319
  readonly origin: Origin;
318
320
  }, language.DefinitionKey<Origin, 'function', Name>> : never;
319
- type ResolvedPropertyOfProjection<Value> = Value extends PropertyProjection<infer PropertyValue, infer Required, infer Name, infer Key> ? language.ResolvedProperty<PropertyValue, Required> & {
321
+ type ResolvedPropertyOfProjection<Value> = Value extends PropertyProjection<infer PropertyValue, infer Required, infer Name, infer Key, infer State> ? language.ResolvedProperty<PropertyValue, Required, State> & {
320
322
  readonly name: Name;
321
323
  readonly key: Key;
322
324
  } : never;
@@ -4,6 +4,7 @@ import { isDefinitionRef, Key } from '../../addressing/index.js';
4
4
  import { DEPENDENCY_ALIAS_PATTERN, DOMAIN_ORIGIN_PATTERN, DOMAIN_REVISION_PATTERN, MEMBER_NAME_PATTERN, } from '../../addressing/patterns.js';
5
5
  import { MEDIA_TYPE_PATTERN } from '../../language/class/model/data.js';
6
6
  import { PropertyValues } from '../../language/class/property-values.js';
7
+ import { admitStateTopology } from '../../language/state/topology.js';
7
8
  import { classifyValueProgramOrdering } from '../../language/value/ordering.js';
8
9
  import { invalidCompiled } from '../diagnostic.js';
9
10
  import { revisionOfCompiledEntry } from './revision.js';
@@ -158,10 +159,8 @@ function compiledClass(input, values, path) {
158
159
  const parents = array(value.extends, 'Class extends', extendsPath).map((parent, index) => definitionRef(parent, 'class', 'Class parent', `${extendsPath}/${index}`));
159
160
  unique(parents.map(Key.of), 'Class parents', extendsPath);
160
161
  const propertiesPath = `${path}/properties`;
161
- const properties = array(value.properties, 'Class properties', propertiesPath);
162
- for (const [index, property] of properties.entries())
163
- compiledProperty(property, values, `${propertiesPath}/${index}`);
164
- unique(properties.map((property, index) => string(object(property, 'Compiled Property', `${propertiesPath}/${index}`).name, 'Property name', `${propertiesPath}/${index}/name`)), 'Class Properties', propertiesPath);
162
+ const properties = array(value.properties, 'Class properties', propertiesPath).map((property, index) => compiledProperty(property, values, value.kind === 'node', `${propertiesPath}/${index}`));
163
+ unique(properties.map((property) => property.name), 'Class Properties', propertiesPath);
165
164
  if (value.kind === 'node') {
166
165
  if (value.data !== undefined)
167
166
  dataDefinition(value.data, `${path}/data`);
@@ -177,7 +176,7 @@ function compiledClass(input, values, path) {
177
176
  classPolicies(value.policies, `${path}/policies`);
178
177
  edgeContract(value, path);
179
178
  }
180
- return value;
179
+ return { ...value, properties };
181
180
  }
182
181
  function compiledFunction(input, values, path) {
183
182
  const value = object(input, 'Compiled Function', path);
@@ -185,25 +184,55 @@ function compiledFunction(input, values, path) {
185
184
  definitionRef(value.ref, 'function', 'Function ref', `${path}/ref`);
186
185
  return value;
187
186
  }
188
- function compiledProperty(input, values, path) {
187
+ function compiledProperty(input, values, node, path) {
189
188
  const value = object(input, 'Compiled Property', path);
190
- exact(value, ['name', 'required', 'visibility', 'value'], 'Compiled Property', path, [
189
+ exact(value, ['name', 'required', 'value'], 'Compiled Property', path, [
191
190
  'auto',
192
191
  'description',
193
192
  'ordering',
193
+ 'state',
194
194
  ]);
195
195
  memberName(value.name, 'Property name', `${path}/name`);
196
196
  boolean(value.required, 'Property required', `${path}/required`);
197
- if (value.visibility !== 'public' && value.visibility !== 'private') {
198
- invalid('Property visibility', undefined, `${path}/visibility`);
199
- }
200
197
  description(value.description, 'Property description', `${path}/description`);
201
198
  if (value.auto !== undefined)
202
199
  propertyAuto(value.auto, `${path}/auto`);
203
200
  const valueIndex = index(value.value, values.length, 'Property value', `${path}/value`);
201
+ let state;
202
+ if (value.state !== undefined) {
203
+ if (!node)
204
+ invalid('Property state placement', 'COMPILED_SOURCE_INVALID', `${path}/state`);
205
+ let topology;
206
+ try {
207
+ topology = admitStateTopology(value.state);
208
+ }
209
+ catch {
210
+ invalid('Property state topology', 'COMPILED_SOURCE_INVALID', `${path}/state`);
211
+ }
212
+ const program = values[valueIndex];
213
+ const schema = program.nodes[program.root].schema;
214
+ const states = Object.keys(topology.transitions);
215
+ const schemaObject = schema;
216
+ const schemaMatches = schema !== null &&
217
+ typeof schema === 'object' &&
218
+ !Array.isArray(schema) &&
219
+ Object.keys(schemaObject).length === 2 &&
220
+ schemaObject.type === 'string' &&
221
+ Array.isArray(schemaObject.enum) &&
222
+ schemaObject.enum.length === states.length &&
223
+ schemaObject.enum.every((state, index) => state === states[index]);
224
+ if (!value.required || value.auto !== undefined || !schemaMatches) {
225
+ invalid('Property state contract', 'COMPILED_SOURCE_INVALID', `${path}/state`);
226
+ }
227
+ state = topology;
228
+ }
204
229
  if (value.ordering !== classifyValueProgramOrdering(values[valueIndex])) {
205
230
  invalid('Property ordering', 'COMPILED_CANONICAL_MISMATCH', `${path}/ordering`);
206
231
  }
232
+ return {
233
+ ...value,
234
+ ...(state === undefined ? {} : { state }),
235
+ };
207
236
  }
208
237
  function compiledCallable(input, values, method, path) {
209
238
  const value = object(input, 'Compiled Callable', path);
@@ -37,9 +37,9 @@ function compileEntry(schema, lookup) {
37
37
  return {
38
38
  name,
39
39
  required: property.required,
40
- visibility: property.visibility,
41
40
  ...(property.auto === undefined ? {} : { auto: property.auto }),
42
41
  ...(property.description === undefined ? {} : { description: property.description }),
42
+ ...(property.state === undefined ? {} : { state: property.state }),
43
43
  ...(ordering === undefined ? {} : { ordering }),
44
44
  value: add(property.schema, `${pointer}/properties/${name}/schema`),
45
45
  };
@@ -1,5 +1,7 @@
1
1
  /** Stable aggregate facade for the V1 language. */
2
- export { auto, core, defineClass, defineSchema, edgeClass, func, fullMatch, method, nodeClass, output, path, policy, property, valueSchema, view, } from './builder/index.js';
2
+ export { auto, core, defineClass, defineSchema, edgeClass, func, fullMatch, method, nodeClass, output, path, policy, property, stateProperty, valueSchema, view, } from './builder/index.js';
3
+ export { stateMachine } from './language/state/index.js';
4
+ export type { EventOf, StateMachine, StateOf } from './language/state/index.js';
3
5
  export { PropertyValues } from './language/index.js';
4
6
  export * as metadata from './language/definition/metadata.js';
5
7
  export type { AnyResolvedClass, BoundMethodOf, BoundMethodShortcutsOf, CallableResultOf, CallableInputOf, CallableOutputOf, ClassSatisfactionKeysOf, ClassDefinition, CoreDefinition, CoreEdge, FunctionAuth, FunctionDefinition, MethodDefinition, MethodInheritance, MethodOwnerKeyOf, PolicyCheckExpression, PolicyDefinition, PropertyInputOf, PropertyAccessOf, PropertyOutputOf, PropertyShortcutsOf, PropertyValuesOf, ResolvedClass, ResolvedCoreDefinition, ResolvedData, ResolvedFunction, ResolvedMethod, ResolvedMethodCollection, ResolvedPolicy, ResolvedProperty, ResolvedView, MethodAccessOf, SelfMethodsOf, SelfPropertiesOf, SelfStaticMethodsOf, StaticMethodsOf, ViewDefinition, } from './language/index.js';
package/dist/v1/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  /** Stable aggregate facade for the V1 language. */
2
- export { auto, core, defineClass, defineSchema, edgeClass, func, fullMatch, method, nodeClass, output, path, policy, property, valueSchema, view, } from './builder/index.js';
2
+ export { auto, core, defineClass, defineSchema, edgeClass, func, fullMatch, method, nodeClass, output, path, policy, property, stateProperty, valueSchema, view, } from './builder/index.js';
3
+ export { stateMachine } from './language/state/index.js';
3
4
  export { PropertyValues } from './language/index.js';
4
5
  export * as metadata from './language/definition/metadata.js';
5
6
  export { acceptDefinitionRef, callableAddress, ClassKey, equalDefinitionRefs, isDefinitionRef, Key, MethodKey, PropertyKey, } from './addressing/index.js';
@@ -1,4 +1,3 @@
1
- export type PropertyVisibility = 'public' | 'private';
2
1
  export type AutoEvent = 'create' | 'update';
3
2
  export type AutoSet = 'instant';
4
3
  export interface PropertyAuto {
@@ -8,9 +7,9 @@ export interface PropertyAuto {
8
7
  export interface PropertyDefinition {
9
8
  readonly schema: import('../../value/model/schema.js').JsonSchema;
10
9
  readonly required: boolean;
11
- readonly visibility: PropertyVisibility;
12
10
  readonly auto?: PropertyAuto;
13
11
  readonly description?: string;
12
+ readonly state?: import('../../state/index.js').StateTopology;
14
13
  }
15
14
  export type PropertyRecord = Readonly<Record<string, PropertyDefinition>>;
16
15
  export interface PropertyFacet {
@@ -1,18 +1,20 @@
1
1
  import type { Value as PortableValue } from '@astrale-os/kernel-dsl/value';
2
2
  import type { ClassRef, DefinitionKey, Key, PolicyRef, PropertyKey } from '../../addressing/index.js';
3
3
  import type { ResolvedMethodCollection } from '../callable/resolved.js';
4
+ import type { StateTopology } from '../state/index.js';
4
5
  import type { Diagnostic } from '../validation/diagnostic.js';
5
6
  import type { OrderingKind } from '../value/ordering.js';
6
7
  import type { ClassDefinition, ClassKind } from './model/class.js';
7
8
  import type { DataDefinition } from './model/data.js';
8
9
  import type { PropertyDefinition } from './model/property.js';
9
10
  import type { PropertyValues } from './property-values.js';
10
- export interface ResolvedProperty<out Value = PortableValue, out Required extends boolean = boolean> {
11
+ export interface ResolvedProperty<out Value = PortableValue, out Required extends boolean = boolean, out State extends StateTopology | undefined = StateTopology | undefined> {
11
12
  readonly owner: AnyResolvedClass;
12
13
  readonly name: string;
13
14
  readonly key: PropertyKey;
14
- readonly definition: PropertyDefinition & {
15
+ readonly definition: Omit<PropertyDefinition, 'required' | 'state'> & {
15
16
  readonly required: Required;
17
+ readonly state?: State;
16
18
  };
17
19
  /** The one portable scalar ordering domain, when the Property is orderable. */
18
20
  readonly ordering?: OrderingKind;
@@ -2,6 +2,8 @@ export type { ClassRef, CoreRef, DefinitionBase, DefinitionKey, DefinitionRef, F
2
2
  export type { Value as PropertyValue } from '@astrale-os/kernel-dsl/value';
3
3
  export type { JsonSchema as ValueSchema, JsonSchemaObject as ValueSchemaObject, } from './value/model/schema.js';
4
4
  export type { OrderingKind } from './value/ordering.js';
5
+ export { stateMachine } from './state/index.js';
6
+ export type { EventOf, StateMachine, StateOf, StateTopology } from './state/index.js';
5
7
  export type * from './callable/model/callable.js';
6
8
  export type * from './callable/resolved.js';
7
9
  export type * from './class/model/class.js';
@@ -1 +1,2 @@
1
+ export { stateMachine } from './state/index.js';
1
2
  export { PropertyValues } from './class/property-values.js';
@@ -0,0 +1,3 @@
1
+ export { stateMachine } from './machine.js';
2
+ export type { EventOf, StateMachine, StateOf } from './machine.js';
3
+ export type { StateTopology } from './topology.js';
@@ -0,0 +1 @@
1
+ export { stateMachine } from './machine.js';
@@ -0,0 +1,28 @@
1
+ import { z } from 'zod';
2
+ import type { EventName, StateName, StateTopology, TransitionRelation, ValidTransitionRelation } from './topology.js';
3
+ export interface StateMachine<Transitions extends TransitionRelation = any, Initial extends StateName<Transitions> = StateName<Transitions>> extends StateTopology<Transitions, Initial> {
4
+ readonly stateSchema: z.ZodType<StateName<Transitions>>;
5
+ readonly eventSchema: z.ZodType<EventName<Transitions>>;
6
+ eventsFrom<State extends StateName<Transitions>>(state: State): readonly EventName<Transitions, State>[];
7
+ decide<State extends StateName<Transitions>, Event extends EventName<Transitions>>(state: State, event: Event): TransitionDecision<Transitions, State, Event>;
8
+ }
9
+ export type StateOf<Machine extends StateMachine> = StateName<Machine['transitions']>;
10
+ export type EventOf<Machine extends StateMachine, State extends StateOf<Machine> = StateOf<Machine>> = EventName<Machine['transitions'], State>;
11
+ type TransitionDecision<Transitions extends TransitionRelation, State extends StateName<Transitions>, Event extends EventName<Transitions>> = State extends StateName<Transitions> ? Event extends EventName<Transitions> ? Event extends keyof Transitions[State] ? Readonly<{
12
+ kind: 'allowed';
13
+ transition: Readonly<{
14
+ from: State;
15
+ event: Event;
16
+ to: Transitions[State][Event];
17
+ }>;
18
+ }> : Readonly<{
19
+ kind: 'rejected';
20
+ code: 'STATE_TRANSITION_ILLEGAL';
21
+ from: State;
22
+ event: Event;
23
+ }> : never : never;
24
+ export declare function stateMachine<const Transitions extends TransitionRelation, const Initial extends StateName<Transitions>>(input: Readonly<{
25
+ initial: Initial;
26
+ transitions: Transitions & ValidTransitionRelation<Transitions>;
27
+ }>): StateMachine<Transitions, Initial>;
28
+ export {};
@@ -0,0 +1,40 @@
1
+ import { z } from 'zod';
2
+ import { compareUnicode } from '../../addressing/ordering.js';
3
+ import { admitStateTopology } from './topology.js';
4
+ export function stateMachine(input) {
5
+ const topology = admitStateTopology(input);
6
+ const states = Object.keys(topology.transitions);
7
+ const events = [
8
+ ...new Set(states.flatMap((state) => Object.keys(topology.transitions[state]))),
9
+ ].sort(compareUnicode);
10
+ const stateSet = new Set(states);
11
+ const eventSet = new Set(events);
12
+ return Object.freeze({
13
+ ...topology,
14
+ stateSchema: z.enum(states),
15
+ eventSchema: z.enum(events),
16
+ eventsFrom(state) {
17
+ admitState(state, stateSet);
18
+ return Object.freeze(Object.keys(topology.transitions[state]));
19
+ },
20
+ decide(state, event) {
21
+ admitState(state, stateSet);
22
+ admitEvent(event, eventSet);
23
+ const target = topology.transitions[state][event];
24
+ return target === undefined
25
+ ? Object.freeze({ kind: 'rejected', code: 'STATE_TRANSITION_ILLEGAL', from: state, event })
26
+ : Object.freeze({
27
+ kind: 'allowed',
28
+ transition: Object.freeze({ from: state, event, to: target }),
29
+ });
30
+ },
31
+ });
32
+ }
33
+ function admitState(state, states) {
34
+ if (!states.has(state))
35
+ throw new TypeError(`State machine does not declare state "${state}".`);
36
+ }
37
+ function admitEvent(event, events) {
38
+ if (!events.has(event))
39
+ throw new TypeError(`State machine does not declare event "${event}".`);
40
+ }
@@ -0,0 +1,14 @@
1
+ export type TransitionRelation = Readonly<Record<string, Readonly<Record<string, string>>>>;
2
+ export type StateName<Transitions extends TransitionRelation> = Extract<keyof Transitions, string>;
3
+ export type EventName<Transitions extends TransitionRelation, State extends StateName<Transitions> = StateName<Transitions>> = State extends StateName<Transitions> ? Extract<keyof Transitions[State], string> : never;
4
+ export type ValidTransitionRelation<Transitions extends TransitionRelation> = Readonly<{
5
+ [State in StateName<Transitions>]: Readonly<{
6
+ [Event in keyof Transitions[State]]: string extends StateName<Transitions> ? string : Exclude<StateName<Transitions>, State>;
7
+ }>;
8
+ }>;
9
+ export interface StateTopology<Transitions extends TransitionRelation = TransitionRelation, Initial extends StateName<Transitions> = StateName<Transitions>> {
10
+ readonly initial: Initial;
11
+ readonly transitions: Transitions;
12
+ }
13
+ export type StateTopologyOf<Value> = Value extends StateTopology<infer Transitions, infer Initial> ? StateTopology<Transitions, Initial> : undefined;
14
+ export declare function admitStateTopology(input: unknown): StateTopology;
@@ -0,0 +1,69 @@
1
+ import { compareUnicode } from '../../addressing/ordering.js';
2
+ export function admitStateTopology(input) {
3
+ if (!isRecord(input) || !exactKeys(input, ['initial', 'transitions']))
4
+ invalidInput();
5
+ const initial = input.initial;
6
+ const authored = input.transitions;
7
+ if (typeof initial !== 'string' || initial.length === 0 || !isRecord(authored))
8
+ invalidInput();
9
+ const states = Object.keys(authored);
10
+ if (states.length === 0)
11
+ throw new TypeError('State topology requires at least one state.');
12
+ if (states.includes(''))
13
+ throw new TypeError('State topology has an empty state name.');
14
+ if (!states.includes(initial)) {
15
+ throw new TypeError(`State topology initial state "${initial}" is not declared.`);
16
+ }
17
+ const declared = new Set(states);
18
+ const transitions = Object.create(null);
19
+ let transitionCount = 0;
20
+ for (const state of states.sort(compareUnicode)) {
21
+ const outgoing = authored[state];
22
+ if (!isRecord(outgoing))
23
+ throw new TypeError(`State "${state}" transitions must be an object.`);
24
+ const accepted = Object.create(null);
25
+ for (const event of Object.keys(outgoing).sort(compareUnicode)) {
26
+ const target = outgoing[event];
27
+ if (event.length === 0)
28
+ throw new TypeError(`State "${state}" has an empty event name.`);
29
+ if (typeof target !== 'string' || !declared.has(target)) {
30
+ throw new TypeError(`State "${state}" event "${event}" targets undeclared state "${String(target)}".`);
31
+ }
32
+ if (target === state) {
33
+ throw new TypeError(`State "${state}" event "${event}" is a self-transition.`);
34
+ }
35
+ accepted[event] = target;
36
+ transitionCount += 1;
37
+ }
38
+ transitions[state] = Object.freeze(accepted);
39
+ }
40
+ if (transitionCount === 0)
41
+ throw new TypeError('State topology requires at least one transition.');
42
+ const reachable = new Set([initial]);
43
+ const pending = [initial];
44
+ while (pending.length > 0) {
45
+ const state = pending.shift();
46
+ for (const target of Object.values(transitions[state])) {
47
+ if (reachable.has(target))
48
+ continue;
49
+ reachable.add(target);
50
+ pending.push(target);
51
+ }
52
+ }
53
+ for (const state of states) {
54
+ if (!reachable.has(state)) {
55
+ throw new TypeError(`State "${state}" is unreachable from initial "${initial}".`);
56
+ }
57
+ }
58
+ return Object.freeze({ initial, transitions: Object.freeze(transitions) });
59
+ }
60
+ function invalidInput() {
61
+ throw new TypeError('State topology must contain exactly initial and transitions.');
62
+ }
63
+ function isRecord(input) {
64
+ return input !== null && typeof input === 'object' && !Array.isArray(input);
65
+ }
66
+ function exactKeys(input, expected) {
67
+ const keys = Reflect.ownKeys(input);
68
+ return keys.length === expected.length && keys.every((key) => expected.includes(String(key)));
69
+ }
@@ -3,6 +3,7 @@ import type { MethodDefinition } from '../../language/callable/model/callable.js
3
3
  import type { ClassDefinition } from '../../language/class/model/class.js';
4
4
  import type { DataDefinition } from '../../language/class/model/data.js';
5
5
  import type { PropertyAuto } from '../../language/class/model/property.js';
6
+ import type { StateTopology } from '../../language/state/index.js';
6
7
  import type { JsonSchema } from '../../language/value/model/schema.js';
7
8
  import type { SchemaDiagnostic } from '../diagnostic.js';
8
9
  import type { DomainResolutionContext } from '../resolution/context.js';
@@ -13,8 +14,8 @@ export interface EffectiveField {
13
14
  readonly name: string;
14
15
  readonly schema: JsonSchema;
15
16
  readonly required: boolean;
16
- readonly visibility: 'public' | 'private';
17
17
  readonly auto?: PropertyAuto;
18
+ readonly state?: StateTopology;
18
19
  }
19
20
  export interface EffectiveMethod {
20
21
  readonly identity: string;
@@ -62,8 +62,8 @@ function ownFields(owner, declaration) {
62
62
  name,
63
63
  schema: property.schema,
64
64
  required: property.required,
65
- visibility: property.visibility,
66
65
  ...(property.auto === undefined ? {} : { auto: property.auto }),
66
+ ...(property.state === undefined ? {} : { state: property.state }),
67
67
  });
68
68
  }
69
69
  return result;
@@ -371,7 +371,7 @@ function propertyMeaning(field) {
371
371
  name: field.name,
372
372
  schema: semanticValueSchema(field.schema),
373
373
  required: field.required,
374
- visibility: field.visibility,
374
+ ...(field.state === undefined ? {} : { state: field.state }),
375
375
  };
376
376
  }
377
377
  function methodMeaning(method) {
@@ -1,4 +1,4 @@
1
- export type SchemaDiagnosticCode = 'DM_MEMBER_ROOT_INVALID' | 'DM_DEPENDENCY_CONTEXT_INVALID' | 'DM_DEPENDENCY_NOT_RETAINED' | 'DM_MEANING_INCONSISTENT' | 'DM_MEMBER_ORIGIN_MISMATCH' | 'DV_ACCEPTANCE_CONTEXT' | 'DV_CALLABLE_AUTH' | 'DV_CALLABLE_IO' | 'DV_CALLABLE_POLICY_AUTH' | 'DV_CLASS_ABSTRACT' | 'DV_CLASS_ACYCLIC' | 'DV_CLASS_KIND' | 'DV_CORE_EDGE_CLASS' | 'DV_CORE_EDGE_CONSTRAINTS' | 'DV_CORE_EDGE_KEY' | 'DV_CORE_EDGE_PROPERTIES' | 'DV_CORE_NODE_CLASS' | 'DV_CORE_NODE_PROPERTIES' | 'DV_CORE_REF' | 'DV_DATA_COMPOSITION' | 'DV_DEPENDENCY_ACYCLIC' | 'DV_DEPENDENCY_DIRECT' | 'DV_DEPENDENCY_EXACT' | 'DV_DEPENDENCY_LIMITS' | 'DV_DEPENDENCY_REVISION_COHERENCE' | 'DV_DEPENDENCY_UNIQUE' | 'DV_EDGE_ACCEPTS' | 'DV_EDGE_CLASS_COMPOSITION' | 'DV_EDGE_CONSTRAINT' | 'DV_EDGE_ROLE' | 'DV_EDGE_UNDIRECTED' | 'DV_JSON_VALUE' | 'DV_METHOD_ABSTRACT' | 'DV_METHOD_COMPOSITION' | 'DV_PROPERTY_AUTO' | 'DV_PROPERTY_COMPOSITION' | 'DV_REF_RESOLVES' | 'DV_VALUE_SCHEMA' | 'DV_VIEW_TARGET' | 'PL_BUDGET' | 'PL_COMPOSITION' | 'PL_CONNECTIVITY' | 'PL_REF' | 'PL_REPEAT' | 'PL_TARGET' | 'PL_TYPING' | 'PL_USE' | 'PL_VARIABLE_SCOPE' | 'STRUCTURE_ABSTRACT_POLICY' | 'STRUCTURE_CALLABLE_POLICY_AUTH' | 'STRUCTURE_DUPLICATE_ITEM' | 'STRUCTURE_EDGE_ORIENTATION' | 'STRUCTURE_FORMAT' | 'STRUCTURE_INVALID' | 'STRUCTURE_KEY' | 'STRUCTURE_MAXIMUM' | 'STRUCTURE_MINIMUM' | 'STRUCTURE_MULTIPLE' | 'STRUCTURE_REQUIRED' | 'STRUCTURE_TYPE' | 'STRUCTURE_UNION' | 'STRUCTURE_UNKNOWN_FIELD' | 'STRUCTURE_VALUE' | 'UNSUPPORTED_DOCUMENT_FORMAT' | 'UNSUPPORTED_DSL_VERSION';
1
+ export type SchemaDiagnosticCode = 'DM_MEMBER_ROOT_INVALID' | 'DM_DEPENDENCY_CONTEXT_INVALID' | 'DM_DEPENDENCY_NOT_RETAINED' | 'DM_MEANING_INCONSISTENT' | 'DM_MEMBER_ORIGIN_MISMATCH' | 'DV_ACCEPTANCE_CONTEXT' | 'DV_CALLABLE_AUTH' | 'DV_CALLABLE_IO' | 'DV_CALLABLE_POLICY_AUTH' | 'DV_CLASS_ABSTRACT' | 'DV_CLASS_ACYCLIC' | 'DV_CLASS_KIND' | 'DV_CORE_EDGE_CLASS' | 'DV_CORE_EDGE_CONSTRAINTS' | 'DV_CORE_EDGE_KEY' | 'DV_CORE_EDGE_PROPERTIES' | 'DV_CORE_NODE_CLASS' | 'DV_CORE_NODE_PROPERTIES' | 'DV_CORE_REF' | 'DV_DATA_COMPOSITION' | 'DV_DEPENDENCY_ACYCLIC' | 'DV_DEPENDENCY_DIRECT' | 'DV_DEPENDENCY_EXACT' | 'DV_DEPENDENCY_LIMITS' | 'DV_DEPENDENCY_REVISION_COHERENCE' | 'DV_DEPENDENCY_UNIQUE' | 'DV_EDGE_ACCEPTS' | 'DV_EDGE_CLASS_COMPOSITION' | 'DV_EDGE_CONSTRAINT' | 'DV_EDGE_ROLE' | 'DV_EDGE_UNDIRECTED' | 'DV_JSON_VALUE' | 'DV_METHOD_ABSTRACT' | 'DV_METHOD_COMPOSITION' | 'DV_PROPERTY_AUTO' | 'DV_PROPERTY_COMPOSITION' | 'DV_PROPERTY_STATE' | 'DV_REF_RESOLVES' | 'DV_VALUE_SCHEMA' | 'DV_VIEW_TARGET' | 'PL_BUDGET' | 'PL_COMPOSITION' | 'PL_CONNECTIVITY' | 'PL_REF' | 'PL_REPEAT' | 'PL_TARGET' | 'PL_TYPING' | 'PL_USE' | 'PL_VARIABLE_SCOPE' | 'STRUCTURE_ABSTRACT_POLICY' | 'STRUCTURE_CALLABLE_POLICY_AUTH' | 'STRUCTURE_DUPLICATE_ITEM' | 'STRUCTURE_EDGE_ORIENTATION' | 'STRUCTURE_FORMAT' | 'STRUCTURE_INVALID' | 'STRUCTURE_KEY' | 'STRUCTURE_MAXIMUM' | 'STRUCTURE_MINIMUM' | 'STRUCTURE_MULTIPLE' | 'STRUCTURE_REQUIRED' | 'STRUCTURE_TYPE' | 'STRUCTURE_UNION' | 'STRUCTURE_UNKNOWN_FIELD' | 'STRUCTURE_VALUE' | 'UNSUPPORTED_DOCUMENT_FORMAT' | 'UNSUPPORTED_DSL_VERSION';
2
2
  export interface SchemaDiagnostic<out Code extends SchemaDiagnosticCode = SchemaDiagnosticCode> {
3
3
  readonly code: Code;
4
4
  readonly pointer: string;
@@ -1,6 +1,7 @@
1
1
  import { json } from '@astrale-os/kernel-dsl/value';
2
2
  import { compareDefinitionRefs, compareUnicode } from '../../addressing/ordering.js';
3
3
  import { normalizePolicyChecks, normalizePolicyExpression, } from '../../language/policy/normalization/normalize.js';
4
+ import { admitStateTopology } from '../../language/state/topology.js';
4
5
  import { canonicalizeValueSchema } from '../../language/value/profile/canonicalize.js';
5
6
  export function normalizeDomainSchema(schema) {
6
7
  const classes = mapRecord(schema.classes, canonicalizeClass);
@@ -123,7 +124,6 @@ function canonicalizeProperty(value) {
123
124
  return {
124
125
  schema: canonicalizeValueSchema(value.schema, 'property-facet'),
125
126
  required: value.required,
126
- visibility: value.visibility,
127
127
  ...(value.auto === undefined
128
128
  ? {}
129
129
  : {
@@ -133,6 +133,9 @@ function canonicalizeProperty(value) {
133
133
  },
134
134
  }),
135
135
  ...(value.description === undefined ? {} : { description: value.description }),
136
+ ...(value.state === undefined
137
+ ? {}
138
+ : { state: admitStateTopology(value.state) }),
136
139
  };
137
140
  }
138
141
  function canonicalizeDirectedEndpoints(value) {
@@ -1,5 +1,6 @@
1
1
  import { Key } from '../../addressing/key.js';
2
2
  import { definitionRefIndex } from '../../addressing/ordering.js';
3
+ import { admitStateTopology } from '../../language/state/topology.js';
3
4
  import { classifyOrdering } from '../../language/value/ordering.js';
4
5
  import { diagnostic } from '../diagnostic.js';
5
6
  import { createValueSchemaRegistry } from '../resolution/value.registry.js';
@@ -26,15 +27,40 @@ export function validateDefinitions(environment, analysis) {
26
27
  function validateFacet(environment, declaration, pointer, diagnostics) {
27
28
  const valueRegistry = createValueSchemaRegistry(environment);
28
29
  for (const [name, property] of Object.entries(declaration.properties)) {
30
+ const propertyPointer = `${pointer}/properties/${escapePointer(name)}`;
31
+ if (property.state !== undefined) {
32
+ if (declaration.kind !== 'node') {
33
+ diagnostics.push(diagnostic('DV_PROPERTY_STATE', `${propertyPointer}/state`, 'A State Property may be declared only on a Node Class.'));
34
+ }
35
+ try {
36
+ const topology = admitStateTopology(property.state);
37
+ const expected = Object.keys(topology.transitions).sort();
38
+ const schema = property.schema;
39
+ const schemaMatches = schema !== null &&
40
+ typeof schema === 'object' &&
41
+ !Array.isArray(schema) &&
42
+ Object.keys(schema).length === 2 &&
43
+ schema.type === 'string' &&
44
+ Array.isArray(schema.enum) &&
45
+ schema.enum.length === expected.length &&
46
+ [...schema.enum].sort().every((state, index) => state === expected[index]);
47
+ if (!property.required || property.auto !== undefined || !schemaMatches) {
48
+ diagnostics.push(diagnostic('DV_PROPERTY_STATE', `${propertyPointer}/state`, 'A State Property is required, non-automatic, and has exactly its declared states.'));
49
+ }
50
+ }
51
+ catch (error) {
52
+ diagnostics.push(diagnostic('DV_PROPERTY_STATE', `${propertyPointer}/state`, error instanceof Error ? error.message : 'Invalid State topology.'));
53
+ }
54
+ }
29
55
  if (property.auto === undefined)
30
56
  continue;
31
- const propertyPointer = `${pointer}/properties/${escapePointer(name)}/auto`;
57
+ const autoPointer = `${propertyPointer}/auto`;
32
58
  if (property.required && !property.auto.on.includes('create')) {
33
- diagnostics.push(diagnostic('DV_PROPERTY_AUTO', `${propertyPointer}/on`, 'A required auto Property must run on create.'));
59
+ diagnostics.push(diagnostic('DV_PROPERTY_AUTO', `${autoPointer}/on`, 'A required auto Property must run on create.'));
34
60
  }
35
61
  if (property.auto.set === 'instant' &&
36
62
  classifyOrdering(property.schema, valueRegistry) !== 'instant') {
37
- diagnostics.push(diagnostic('DV_PROPERTY_AUTO', `${propertyPointer}/set`, 'The instant setter requires an Instant value schema.'));
63
+ diagnostics.push(diagnostic('DV_PROPERTY_AUTO', `${autoPointer}/set`, 'The instant setter requires an Instant value schema.'));
38
64
  }
39
65
  }
40
66
  if (declaration.kind !== 'node')
@@ -34,10 +34,15 @@ const jsonSchemaSchema = z.union([z.boolean(), jsonObjectSchema]);
34
34
  const dataDeclarationSchema = z.strictObject({
35
35
  mediaType: z.string().regex(MEDIA_TYPE_PATTERN),
36
36
  });
37
+ const stateNameSchema = z.string().min(1);
38
+ const stateTransitionsSchema = z.custom(isStateTransitions);
39
+ const stateTopologySchema = z.strictObject({
40
+ initial: stateNameSchema,
41
+ transitions: stateTransitionsSchema,
42
+ });
37
43
  const propertyDefinitionSchema = z.strictObject({
38
44
  schema: jsonSchemaSchema,
39
45
  required: z.boolean(),
40
- visibility: z.enum(['public', 'private']),
41
46
  auto: z
42
47
  .strictObject({
43
48
  on: uniqueArray(z.enum(['create', 'update'])).min(1),
@@ -45,6 +50,7 @@ const propertyDefinitionSchema = z.strictObject({
45
50
  })
46
51
  .optional(),
47
52
  description: descriptionSchema.optional(),
53
+ state: stateTopologySchema.optional(),
48
54
  });
49
55
  const propertyRecordSchema = z.record(memberNameSchema, propertyDefinitionSchema);
50
56
  const domainDependencySchema = z.strictObject({
@@ -326,6 +332,30 @@ function absoluteRefSchema(kind) {
326
332
  name: memberNameSchema,
327
333
  });
328
334
  }
335
+ function isStateTransitions(input) {
336
+ if (!isRecord(input))
337
+ return false;
338
+ for (const state of Reflect.ownKeys(input)) {
339
+ if (typeof state !== 'string' || state.length === 0)
340
+ return false;
341
+ const outgoing = Reflect.get(input, state);
342
+ if (!isRecord(outgoing))
343
+ return false;
344
+ for (const event of Reflect.ownKeys(outgoing)) {
345
+ const target = Reflect.get(outgoing, event);
346
+ if (typeof event !== 'string' ||
347
+ event.length === 0 ||
348
+ typeof target !== 'string' ||
349
+ target.length === 0) {
350
+ return false;
351
+ }
352
+ }
353
+ }
354
+ return true;
355
+ }
356
+ function isRecord(input) {
357
+ return input !== null && typeof input === 'object' && !Array.isArray(input);
358
+ }
329
359
  function uniqueArray(element) {
330
360
  return z.array(element).superRefine((values, context) => {
331
361
  const firstIndexByValue = new Map();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrale-os/kernel-dsl",
3
- "version": "0.2.0-beta.15",
3
+ "version": "0.2.0-beta.18",
4
4
  "description": "Astrale Kernel DSL - Schema authoring, inference, and IR serialization",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -59,6 +59,10 @@
59
59
  "types": "./dist/v1/language/index.d.ts",
60
60
  "import": "./dist/v1/language/index.js"
61
61
  },
62
+ "./v1/language/state": {
63
+ "types": "./dist/v1/language/state/index.d.ts",
64
+ "import": "./dist/v1/language/state/index.js"
65
+ },
62
66
  "./v1/schema": {
63
67
  "types": "./dist/v1/schema/index.d.ts",
64
68
  "import": "./dist/v1/schema/index.js"