Skip to content

Commit 001201b

Browse files
Merge pull request #10 from typeonce-dev/codex/add-safe-state-from
feat: add safe state construction
2 parents 4d8598f + e556e63 commit 001201b

8 files changed

Lines changed: 790 additions & 84 deletions

File tree

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"@typeonce/effect-machine": minor
3+
---
4+
5+
Add safe `.from` state construction to initial and transition target builders.
6+
Constructor inputs are resolved through the selected state schema during
7+
planning, preserving defaults and class identity while reporting validation
8+
failures as `MachineSchemaDecodeError` values.

README.md

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ const Counter = Machine.make({
5555
id: "Counter",
5656
states: States.states,
5757
events: [Event.cases.Start],
58-
initial: () => States.initial.Idle(State.cases.Idle.make({}))
58+
initial: () => States.initial.Idle.from({})
5959
}).handle({
6060
Idle: {
6161
on: {
62-
Start: ({ target }) => target.full.Running(State.cases.Running.make({}))
62+
Start: ({ target }) => target.full.Running.from({})
6363
}
6464
},
6565
Running: {}
@@ -69,6 +69,23 @@ const Counter = Machine.make({
6969
`initial` is always a function. For a machine with an input schema, the
7070
initializer receives the decoded input.
7171

72+
Builder methods accept an already constructed state value directly, or expose
73+
`.from` for constructing one safely from the state schema's make input:
74+
75+
```ts
76+
target.local.Running(decodedRunning)
77+
target.local.Running.from({ startedAt: event.at })
78+
```
79+
80+
Use the direct call when a decoded value already exists. Use `.from` when
81+
entering a state from fields. Construction runs through the schema's
82+
`makeEffect` while the machine plans the configuration, so constructor
83+
defaults and tagged-class identity are preserved and failed refinements become
84+
`MachineSchemaDecodeError` failures instead of synchronous throws. The same
85+
form is available on initial, local, branch, full, compound, parallel, and
86+
final builders. A `.from` builder result is therefore a machine construction
87+
instruction; it becomes a validated public snapshot when planning succeeds.
88+
7289
Tagged classes are equally valid when cases need class methods or nominal
7390
identity:
7491

@@ -157,8 +174,7 @@ Handlers implement behavior and output computation without repeating it:
157174
const machine = Machine.make({
158175
states: States.states,
159176
events: [],
160-
initial: () =>
161-
States.initial.Form(State.cases.Form.make({ draft: "" }), (form) => form.Editing(State.cases.Editing.make({})))
177+
initial: () => States.initial.Form.from({ draft: "" }, (form) => form.Editing.from({}))
162178
}).handle({
163179
Form: {
164180
states: {

docs/agent-guide.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,22 @@ Refresh: {
230230
Do not use `target.full` merely because it is easiest to discover. Prefer the
231231
narrowest builder that expresses the intended configuration change.
232232

233+
Every state builder method has two construction forms:
234+
235+
```ts
236+
target.local.Ready(decodedReady)
237+
target.local.Ready.from({ value: event.value })
238+
```
239+
240+
The direct call accepts the schema's decoded `Type`. `.from` accepts its
241+
`~type.make.in`, so callers do not need to invoke a TaggedUnion case's `make`
242+
or instantiate a TaggedClass. The machine resolves `.from` with
243+
`schema.makeEffect` during planning. Constructor defaults and class identity
244+
are retained; refinement failures use `MachineSchemaDecodeError` at the state
245+
boundary rather than throwing synchronously. This applies recursively to
246+
initial, full, local, branch, compound, parallel, final, and `local.with`
247+
builders.
248+
233249
## Reading state and parents
234250

235251
`Machine.defineStates` returns typed helpers:

0 commit comments

Comments
 (0)