@typeonce/effect-machine 0.31.2 → 0.32.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 +145 -140
- package/dist/Machine.d.ts +428 -254
- package/dist/Machine.d.ts.map +1 -1
- package/dist/Machine.js +91 -111
- package/dist/Machine.js.map +1 -1
- package/dist/internal/machine/atom.d.ts +3 -4
- package/dist/internal/machine/atom.d.ts.map +1 -1
- package/dist/internal/machine/atom.js +0 -2
- package/dist/internal/machine/atom.js.map +1 -1
- package/dist/internal/machine/childRegistry.d.ts +52 -0
- package/dist/internal/machine/childRegistry.d.ts.map +1 -0
- package/dist/internal/machine/childRegistry.js +74 -0
- package/dist/internal/machine/childRegistry.js.map +1 -0
- package/dist/internal/machine/cluster.d.ts +2 -3
- package/dist/internal/machine/cluster.d.ts.map +1 -1
- package/dist/internal/machine/cluster.js.map +1 -1
- package/dist/internal/machine/configuration.d.ts.map +1 -1
- package/dist/internal/machine/configuration.js +14 -4
- package/dist/internal/machine/configuration.js.map +1 -1
- package/dist/internal/machine/executionPlan.d.ts +1 -0
- package/dist/internal/machine/executionPlan.d.ts.map +1 -1
- package/dist/internal/machine/executionPlan.js +97 -53
- package/dist/internal/machine/executionPlan.js.map +1 -1
- package/dist/internal/machine/invocation.d.ts.map +1 -1
- package/dist/internal/machine/invocation.js +4 -2
- package/dist/internal/machine/invocation.js.map +1 -1
- package/dist/internal/machine/invocationDefinition.d.ts +35 -0
- package/dist/internal/machine/invocationDefinition.d.ts.map +1 -0
- package/dist/internal/machine/invocationDefinition.js +21 -0
- package/dist/internal/machine/invocationDefinition.js.map +1 -0
- package/dist/internal/machine/invocationEvent.d.ts +0 -2
- package/dist/internal/machine/invocationEvent.d.ts.map +1 -1
- package/dist/internal/machine/invocationEvent.js +0 -8
- package/dist/internal/machine/invocationEvent.js.map +1 -1
- package/dist/internal/machine/machine.d.ts +21 -43
- package/dist/internal/machine/machine.d.ts.map +1 -1
- package/dist/internal/machine/machine.js +98 -374
- package/dist/internal/machine/machine.js.map +1 -1
- package/dist/internal/machine/planner.d.ts +13 -19
- package/dist/internal/machine/planner.d.ts.map +1 -1
- package/dist/internal/machine/planner.js +63 -35
- package/dist/internal/machine/planner.js.map +1 -1
- package/dist/internal/machine/process.d.ts +6 -8
- package/dist/internal/machine/process.d.ts.map +1 -1
- package/dist/internal/machine/process.js +1 -0
- package/dist/internal/machine/process.js.map +1 -1
- package/dist/internal/machine/protocol.d.ts +2 -2
- package/dist/internal/machine/protocol.d.ts.map +1 -1
- package/dist/internal/machine/protocol.js +4 -18
- package/dist/internal/machine/protocol.js.map +1 -1
- package/dist/internal/machine/readiness.d.ts +1 -1
- package/dist/internal/machine/readiness.d.ts.map +1 -1
- package/dist/internal/machine/requirements.d.ts +4 -0
- package/dist/internal/machine/requirements.d.ts.map +1 -0
- package/dist/internal/machine/requirements.js +2 -0
- package/dist/internal/machine/requirements.js.map +1 -0
- package/dist/internal/machine/runtime.d.ts +4 -58
- package/dist/internal/machine/runtime.d.ts.map +1 -1
- package/dist/internal/machine/runtime.js +1 -69
- package/dist/internal/machine/runtime.js.map +1 -1
- package/dist/internal/machine/serialization.d.ts.map +1 -1
- package/dist/internal/machine/serialization.js +16 -0
- package/dist/internal/machine/serialization.js.map +1 -1
- package/dist/internal/machine/stateDefinition.d.ts +3 -1
- package/dist/internal/machine/stateDefinition.d.ts.map +1 -1
- package/dist/internal/machine/stateDefinition.js +36 -2
- package/dist/internal/machine/stateDefinition.js.map +1 -1
- package/dist/internal/machine/targetBuilder.d.ts +16 -0
- package/dist/internal/machine/targetBuilder.d.ts.map +1 -0
- package/dist/internal/machine/targetBuilder.js +333 -0
- package/dist/internal/machine/targetBuilder.js.map +1 -0
- package/dist/internal/machine/topology.js +3 -3
- package/dist/internal/machine/topology.js.map +1 -1
- package/dist/internal/machine/transition.d.ts +16 -0
- package/dist/internal/machine/transition.d.ts.map +1 -0
- package/dist/internal/machine/transition.js +2 -0
- package/dist/internal/machine/transition.js.map +1 -0
- package/dist/internal/testing/machine/finiteModel.d.ts.map +1 -1
- package/dist/internal/testing/machine/finiteModel.js +10 -12
- package/dist/internal/testing/machine/finiteModel.js.map +1 -1
- package/dist/internal/testing/machine/format.d.ts +7 -0
- package/dist/internal/testing/machine/format.d.ts.map +1 -0
- package/dist/internal/testing/machine/format.js +104 -0
- package/dist/internal/testing/machine/format.js.map +1 -0
- package/dist/internal/testing/machine/probe.d.ts +1 -1
- package/dist/internal/testing/machine/probe.d.ts.map +1 -1
- package/dist/internal/testing/machine/probe.js +1 -1
- package/dist/internal/testing/machine/probe.js.map +1 -1
- package/dist/internal/testing/machine/referenceModel.d.ts.map +1 -1
- package/dist/internal/testing/machine/referenceModel.js +15 -19
- package/dist/internal/testing/machine/referenceModel.js.map +1 -1
- package/dist/internal/testing/machine/trace.d.ts +1 -1
- package/dist/internal/testing/machine/trace.d.ts.map +1 -1
- package/dist/internal/testing/machine/trace.js +3 -3
- package/dist/internal/testing/machine/trace.js.map +1 -1
- package/dist/internal/testing/machine/value.d.ts +8 -0
- package/dist/internal/testing/machine/value.d.ts.map +1 -0
- package/dist/internal/testing/machine/value.js +82 -0
- package/dist/internal/testing/machine/value.js.map +1 -0
- package/dist/internal/testing/machine/verification.d.ts +2 -13
- package/dist/internal/testing/machine/verification.d.ts.map +1 -1
- package/dist/internal/testing/machine/verification.js +21 -113
- package/dist/internal/testing/machine/verification.js.map +1 -1
- package/dist/testing/MachineTest.d.ts +89 -104
- package/dist/testing/MachineTest.d.ts.map +1 -1
- package/dist/testing/MachineTest.js +70 -84
- package/dist/testing/MachineTest.js.map +1 -1
- package/dist/unstable/cluster/ClusterMachine.d.ts +10 -13
- package/dist/unstable/cluster/ClusterMachine.d.ts.map +1 -1
- package/dist/unstable/cluster/ClusterMachine.js +5 -8
- package/dist/unstable/cluster/ClusterMachine.js.map +1 -1
- package/dist/unstable/reactivity/AtomMachine.d.ts +26 -61
- package/dist/unstable/reactivity/AtomMachine.d.ts.map +1 -1
- package/dist/unstable/reactivity/AtomMachine.js +17 -26
- package/dist/unstable/reactivity/AtomMachine.js.map +1 -1
- package/docs/agent-guide.md +45 -45
- package/docs/effect-atom-react.md +35 -63
- package/docs/machine-review.md +7 -7
- package/docs/root-api.md +214 -0
- package/package.json +1 -1
- package/src/Machine.ts +778 -437
- package/src/internal/machine/atom.ts +3 -13
- package/src/internal/machine/childRegistry.ts +141 -0
- package/src/internal/machine/cluster.ts +5 -14
- package/src/internal/machine/configuration.ts +20 -4
- package/src/internal/machine/executionPlan.ts +109 -52
- package/src/internal/machine/invocation.ts +10 -6
- package/src/internal/machine/invocationDefinition.ts +52 -0
- package/src/internal/machine/invocationEvent.ts +0 -8
- package/src/internal/machine/machine.ts +154 -679
- package/src/internal/machine/planner.ts +74 -62
- package/src/internal/machine/process.ts +14 -21
- package/src/internal/machine/protocol.ts +9 -32
- package/src/internal/machine/readiness.ts +1 -0
- package/src/internal/machine/requirements.ts +11 -0
- package/src/internal/machine/runtime.ts +17 -186
- package/src/internal/machine/serialization.ts +22 -0
- package/src/internal/machine/stateDefinition.ts +36 -3
- package/src/internal/machine/targetBuilder.ts +525 -0
- package/src/internal/machine/topology.ts +3 -3
- package/src/internal/machine/transition.ts +26 -0
- package/src/internal/testing/machine/finiteModel.ts +22 -23
- package/src/internal/testing/machine/format.ts +120 -0
- package/src/internal/testing/machine/probe.ts +4 -4
- package/src/internal/testing/machine/referenceModel.ts +25 -17
- package/src/internal/testing/machine/trace.ts +4 -4
- package/src/internal/testing/machine/value.ts +77 -0
- package/src/internal/testing/machine/verification.ts +904 -1109
- package/src/testing/MachineTest.ts +103 -114
- package/src/unstable/cluster/ClusterMachine.ts +10 -20
- package/src/unstable/reactivity/AtomMachine.ts +42 -79
package/README.md
CHANGED
|
@@ -42,57 +42,42 @@ in lockstep with this package.
|
|
|
42
42
|
|
|
43
43
|
## Quick start
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
Start with events and root-owned data. A data-only machine needs no child states:
|
|
46
46
|
|
|
47
47
|
```ts
|
|
48
48
|
import { Machine } from "@typeonce/effect-machine"
|
|
49
|
-
import { Effect, Schema
|
|
50
|
-
|
|
51
|
-
const State = Schema.TaggedUnion({
|
|
52
|
-
Running: { count: Schema.Number }
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
const States = Machine.states({
|
|
56
|
-
Idle: {},
|
|
57
|
-
Running: State.cases.Running
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
const CounterEvent = Machine.events(
|
|
61
|
-
Schema.TaggedUnion({
|
|
62
|
-
Start: {},
|
|
63
|
-
Increment: {},
|
|
64
|
-
Stop: {}
|
|
65
|
-
})
|
|
66
|
-
)
|
|
49
|
+
import { Effect, Schema } from "effect"
|
|
67
50
|
|
|
51
|
+
const Root = Machine.state({ fields: { count: Schema.Number } })
|
|
52
|
+
const Events = Machine.events({ Increment: { by: Schema.Number } })
|
|
68
53
|
const CounterDefinition = Machine.make({
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
initial: (to) => to.Idle()
|
|
54
|
+
root: Root,
|
|
55
|
+
events: Events,
|
|
56
|
+
initial: (root) => root.from(() => ({ count: 0 }))
|
|
73
57
|
})
|
|
74
|
-
|
|
75
58
|
const Counter = CounterDefinition.handle({
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
Running: {
|
|
82
|
-
on: {
|
|
83
|
-
Increment: (to) => to.full.Running().resolve(({ state, target }) => target.from({ count: state.count + 1 })),
|
|
84
|
-
Stop: (to) => to.full.Idle()
|
|
85
|
-
}
|
|
59
|
+
on: {
|
|
60
|
+
Increment: (to) =>
|
|
61
|
+
to.self.update.from(({ current, event }) => ({
|
|
62
|
+
count: current.count + event.by
|
|
63
|
+
}))
|
|
86
64
|
}
|
|
87
65
|
})
|
|
88
66
|
|
|
89
|
-
const program = Effect.gen(function*() {
|
|
67
|
+
const program = Effect.scoped(Effect.gen(function*() {
|
|
90
68
|
const ref = yield* Machine.start(Counter)
|
|
91
|
-
yield* ref.send(
|
|
92
|
-
|
|
93
|
-
})
|
|
69
|
+
yield* ref.send(Events.Increment({ by: 1 }))
|
|
70
|
+
}))
|
|
94
71
|
```
|
|
95
72
|
|
|
73
|
+
`self.update` replaces the owner's complete value without exiting and reentering
|
|
74
|
+
it. Its children and scoped work remain active. Add `initial` and `states` to
|
|
75
|
+
the same root descriptor when the workflow needs distinct modes; the root data
|
|
76
|
+
survives transitions between those children.
|
|
77
|
+
|
|
78
|
+
See [the root API guide](./docs/root-api.md) for topology-only machines,
|
|
79
|
+
initialization, reusable schemas, guards, migration, and observation contracts.
|
|
80
|
+
|
|
96
81
|
`handle` creates a complete implementation boundary. Its result does not
|
|
97
82
|
expose `handle`, so all behavior for one machine belongs in the same handler
|
|
98
83
|
tree. Reuse the definition when multiple independent implementations are
|
|
@@ -109,26 +94,25 @@ const TestingCounter = CounterDefinition.handle(testingHandlers)
|
|
|
109
94
|
|
|
110
95
|
## Modeling workflow
|
|
111
96
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
`
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
`Machine.
|
|
131
|
-
`Machine.SnapshotAt<typeof States, Path>`.
|
|
97
|
+
1. Define reusable domain schemas where they express a domain boundary.
|
|
98
|
+
2. Declare one root with `Machine.state`. Use inline children or mount reusable
|
|
99
|
+
descriptors under `states`. `fields` builds a tagged schema; `schema` keeps
|
|
100
|
+
an existing schema and its construction behavior.
|
|
101
|
+
3. Declare field records with `Machine.events`, `Machine.internalEvents`, and
|
|
102
|
+
`Machine.emittedEvents`. Import existing tagged unions or tagged classes with
|
|
103
|
+
the corresponding `eventsFromSchemas`, `internalEventsFromSchemas`, or
|
|
104
|
+
`emittedEventsFromSchemas` constructor.
|
|
105
|
+
4. Pass the root descriptor to `Machine.make({ root, events })`. Supply root
|
|
106
|
+
values with `initial`; declared child defaults determine startup topology.
|
|
107
|
+
5. Implement root behavior directly in `handle`, with child behavior in its
|
|
108
|
+
`states` property. Add runtime, Atom, testing, or Cluster adapters at the
|
|
109
|
+
application boundary.
|
|
110
|
+
|
|
111
|
+
The root has path `""`; children retain paths such as `Editing` and
|
|
112
|
+
`Editing.Form`. Use `Root.path(...)` to validate path literals. Type full
|
|
113
|
+
snapshots as `Machine.Snapshot<typeof Root>` or `Machine.Snapshot<typeof machine>`,
|
|
114
|
+
state values as `Machine.Value<typeof Root, Path>`, and selected snapshots as
|
|
115
|
+
`Machine.SnapshotAt<typeof Root, Path>`.
|
|
132
116
|
|
|
133
117
|
### Make invalid states unrepresentable
|
|
134
118
|
|
|
@@ -187,20 +171,24 @@ Omit `schema` when a state represents control flow but owns no data. Use `{}`
|
|
|
187
171
|
instead of defining an empty tagged schema:
|
|
188
172
|
|
|
189
173
|
```ts
|
|
190
|
-
const States = Machine.
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
174
|
+
const States = Machine.state({
|
|
175
|
+
initial: "Form",
|
|
176
|
+
states: {
|
|
177
|
+
Form: {
|
|
178
|
+
initial: "Editing",
|
|
179
|
+
states: {
|
|
180
|
+
Editing: {},
|
|
181
|
+
Saving
|
|
182
|
+
}
|
|
196
183
|
}
|
|
197
184
|
}
|
|
198
185
|
})
|
|
199
186
|
|
|
200
187
|
const definition = Machine.make({
|
|
201
|
-
|
|
202
|
-
events: Machine.
|
|
203
|
-
|
|
188
|
+
root: States,
|
|
189
|
+
events: Machine.eventsFromSchemas(),
|
|
190
|
+
initialConfiguration: (root) =>
|
|
191
|
+
root.resolve(({ target }) => target.from((to) => to.Form.from((form) => form.Editing.from())))
|
|
204
192
|
})
|
|
205
193
|
```
|
|
206
194
|
|
|
@@ -212,7 +200,7 @@ schema-backed paths. Add a schema later if the state starts owning data.
|
|
|
212
200
|
Keep data-bearing state schemas together in a named `Schema.TaggedUnion` and
|
|
213
201
|
reference its cases from the topology. For a standalone state schema whose
|
|
214
202
|
class identity is useful, declare a named `Schema.TaggedClass`. Do not bury
|
|
215
|
-
|
|
203
|
+
inline `fields` in a `Machine.state` descriptor.
|
|
216
204
|
|
|
217
205
|
Put data on the narrowest state where it is valid. If sibling phases share
|
|
218
206
|
data, put it on their compound parent.
|
|
@@ -224,24 +212,24 @@ belong in `internalEvents`. Ephemeral outward notifications have their own
|
|
|
224
212
|
`emittedEvents` protocol:
|
|
225
213
|
|
|
226
214
|
```ts
|
|
227
|
-
export const CommandEvent = Machine.
|
|
215
|
+
export const CommandEvent = Machine.eventsFromSchemas(
|
|
228
216
|
Schema.TaggedUnion({ Save: {} })
|
|
229
217
|
)
|
|
230
218
|
export type PublicCommandEvent = Machine.EventOf<typeof CommandEvent>
|
|
231
|
-
const InternalEvent = Machine.
|
|
219
|
+
const InternalEvent = Machine.internalEventsFromSchemas(
|
|
232
220
|
Schema.TaggedUnion({
|
|
233
221
|
Saved: { id: Schema.String },
|
|
234
222
|
SaveFailed: { message: Schema.String }
|
|
235
223
|
})
|
|
236
224
|
)
|
|
237
|
-
const Emissions = Machine.
|
|
225
|
+
const Emissions = Machine.emittedEventsFromSchemas(
|
|
238
226
|
Schema.TaggedUnion({
|
|
239
227
|
SaveObserved: { id: Schema.String }
|
|
240
228
|
})
|
|
241
229
|
)
|
|
242
230
|
|
|
243
231
|
const definition = Machine.make({
|
|
244
|
-
|
|
232
|
+
root: States,
|
|
245
233
|
events: CommandEvent,
|
|
246
234
|
internalEvents: InternalEvent,
|
|
247
235
|
emittedEvents: Emissions,
|
|
@@ -352,28 +340,30 @@ machine mailbox and is processed later. A machine that requires an owner
|
|
|
352
340
|
declares the subset of parent inputs it may send with `Machine.parent`:
|
|
353
341
|
|
|
354
342
|
```ts
|
|
355
|
-
const ParentEvents = Machine.
|
|
343
|
+
const ParentEvents = Machine.eventsFromSchemas(ChildFinished)
|
|
356
344
|
|
|
357
345
|
const child = Machine.make({
|
|
358
|
-
|
|
346
|
+
root: ChildStates,
|
|
359
347
|
events: ChildEvents,
|
|
360
348
|
parent: Machine.parent(ParentEvents),
|
|
361
349
|
initial: (to) => to.Working()
|
|
362
350
|
}).handle({
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
to
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
351
|
+
states: {
|
|
352
|
+
Working: {
|
|
353
|
+
on: {
|
|
354
|
+
Finish: (to) =>
|
|
355
|
+
to.branch.Done().resolve(({ parent, target }, enqueue) => {
|
|
356
|
+
enqueue.sendTo(parent, ParentEvents.ChildFinished({ id: "job-1" }))
|
|
357
|
+
return target.from()
|
|
358
|
+
})
|
|
359
|
+
}
|
|
360
|
+
},
|
|
361
|
+
Done: {}
|
|
362
|
+
}
|
|
373
363
|
})
|
|
374
364
|
|
|
375
365
|
const Child = Machine.child("worker", child)
|
|
376
|
-
const ParentInputs = Machine.
|
|
366
|
+
const ParentInputs = Machine.eventsFromSchemas(Start, ParentEvents)
|
|
377
367
|
```
|
|
378
368
|
|
|
379
369
|
`parent` is statically present in every child callback, and root APIs such as
|
|
@@ -409,7 +399,7 @@ paths. `parent` always means the owning machine target.
|
|
|
409
399
|
| `target.history` | Restoring a declared history node | The remembered configuration or its typed default |
|
|
410
400
|
|
|
411
401
|
Every required transition handler selects a target from its inline `to`
|
|
412
|
-
builder. Return a bare selection such as `to.
|
|
402
|
+
builder. Return a bare selection such as `to.local.Idle()` when the selected
|
|
413
403
|
builder supports zero-argument construction; the machine applies the same
|
|
414
404
|
default construction as `target.from()`. This includes empty schemas and
|
|
415
405
|
schemas whose constructor fields are all optional or defaulted. TypeScript
|
|
@@ -427,7 +417,7 @@ restarts the source while retaining its configuration.
|
|
|
427
417
|
|
|
428
418
|
Topology-only definition instructions are values: `to.none`, declared
|
|
429
419
|
`.initial` and history selections, and `to.local.with`. Concrete state and
|
|
430
|
-
choice destinations remain calls such as `to.
|
|
420
|
+
choice destinations remain calls such as `to.local.Running()`. Runtime named
|
|
431
421
|
branch builders remain callable, including `select.unchanged()`, because their
|
|
432
422
|
result carries the selected branch evidence.
|
|
433
423
|
|
|
@@ -574,7 +564,7 @@ lifecycle do not run.
|
|
|
574
564
|
|
|
575
565
|
## Statechart capabilities
|
|
576
566
|
|
|
577
|
-
`Machine.
|
|
567
|
+
`Machine.state` supports:
|
|
578
568
|
|
|
579
569
|
- atomic states;
|
|
580
570
|
- compound states with one active child;
|
|
@@ -599,16 +589,18 @@ State-scoped work starts on entry and is interrupted on exit:
|
|
|
599
589
|
|
|
600
590
|
```ts
|
|
601
591
|
machine.handle({
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
.
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
from
|
|
611
|
-
.
|
|
592
|
+
states: {
|
|
593
|
+
Loading: {
|
|
594
|
+
invoke: (from) =>
|
|
595
|
+
from.effect("save-document", () => saveDocument)
|
|
596
|
+
.onDone((to) => to.branch.Saved().resolve(({ output, target }) => target.from({ id: output.id })))
|
|
597
|
+
.onFailure((to) => to.branch.Failed().resolve(({ error, target }) => target.from({ message: String(error) })))
|
|
598
|
+
},
|
|
599
|
+
Waiting: {
|
|
600
|
+
invoke: (from) =>
|
|
601
|
+
from.timer("save-timeout", "3 seconds")
|
|
602
|
+
.onDone((to) => to.branch.Failed().resolve(({ target }) => target.from({ message: "Timed out" })))
|
|
603
|
+
}
|
|
612
604
|
}
|
|
613
605
|
})
|
|
614
606
|
```
|
|
@@ -621,11 +613,13 @@ the completed chain is the value returned by the callback:
|
|
|
621
613
|
|
|
622
614
|
```ts
|
|
623
615
|
machine.handle({
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
.
|
|
628
|
-
|
|
616
|
+
states: {
|
|
617
|
+
Loading: {
|
|
618
|
+
invoke: (from) =>
|
|
619
|
+
from.effect("load-document", ({ state }) => loadDocument(state.documentId))
|
|
620
|
+
.onDone((to) => to.branch.Ready().resolve(({ output, target }) => target.from({ document: output })))
|
|
621
|
+
.onFailure((to) => to.branch.Failed().resolve(({ error, target }) => target.from({ message: error.message })))
|
|
622
|
+
}
|
|
629
623
|
}
|
|
630
624
|
})
|
|
631
625
|
```
|
|
@@ -636,16 +630,18 @@ macrostep commits:
|
|
|
636
630
|
|
|
637
631
|
```ts
|
|
638
632
|
machine.handle({
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
.
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
633
|
+
states: {
|
|
634
|
+
Listening: {
|
|
635
|
+
invoke: (from) =>
|
|
636
|
+
from.stream("channel", () => channelMessages)
|
|
637
|
+
.onElement((to) =>
|
|
638
|
+
to.none.resolve(({ element }, enqueue) => {
|
|
639
|
+
enqueue.raise(Events.MessageReceived({ message: element }))
|
|
640
|
+
})
|
|
641
|
+
)
|
|
642
|
+
.onDone((to) => to.none)
|
|
643
|
+
.onFailure((to) => to.branch.Failed().resolve(({ error, target }) => target.from({ error })))
|
|
644
|
+
}
|
|
649
645
|
}
|
|
650
646
|
})
|
|
651
647
|
```
|
|
@@ -667,16 +663,18 @@ const machine = Machine.make({
|
|
|
667
663
|
parent: Machine.parent(ParentEvents)
|
|
668
664
|
// ...
|
|
669
665
|
}).handle({
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
.
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
666
|
+
states: {
|
|
667
|
+
Saving: {
|
|
668
|
+
invoke: (from) =>
|
|
669
|
+
from.effect("notify-parent", () => saveDocument)
|
|
670
|
+
.onDone((to) =>
|
|
671
|
+
to.none.resolve(({ parent, self }, enqueue) => {
|
|
672
|
+
enqueue.sendTo(self, Commands.Save())
|
|
673
|
+
enqueue.sendTo(parent, ParentEvents.ChildFinished({ id: "job-1" }))
|
|
674
|
+
})
|
|
675
|
+
)
|
|
676
|
+
.onFailure((to) => to.none)
|
|
677
|
+
}
|
|
680
678
|
}
|
|
681
679
|
})
|
|
682
680
|
```
|
|
@@ -690,11 +688,13 @@ transitions retain the exact owning state and machine protocols.
|
|
|
690
688
|
const refreshCache = Cache.refresh
|
|
691
689
|
|
|
692
690
|
machine.handle({
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
691
|
+
states: {
|
|
692
|
+
Active: {
|
|
693
|
+
invoke: (from) => [
|
|
694
|
+
from.effect("refresh-cache", () => refreshCache).onDone((to) => to.none).onFailure((to) => to.none),
|
|
695
|
+
from.timer("expire-session", "5 minutes").onDone((to) => to.branch.Expired())
|
|
696
|
+
]
|
|
697
|
+
}
|
|
698
698
|
}
|
|
699
699
|
})
|
|
700
700
|
```
|
|
@@ -720,19 +720,21 @@ open set of children that must survive state changes:
|
|
|
720
720
|
const Plant = Machine.childFamily(plantMachine)
|
|
721
721
|
|
|
722
722
|
const central = Machine.make({
|
|
723
|
-
events: Machine.
|
|
723
|
+
events: Machine.eventsFromSchemas(ResourcesOffered, PlantBroken)
|
|
724
724
|
// ...
|
|
725
725
|
}).handle({
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
726
|
+
states: {
|
|
727
|
+
Commissioning: {
|
|
728
|
+
invoke: (from) =>
|
|
729
|
+
from.effect("commission-wave", ({ children, state }) =>
|
|
730
|
+
Effect.forEach(
|
|
731
|
+
state.plants,
|
|
732
|
+
(input) => children.spawn(Plant(input.id), { input }),
|
|
733
|
+
{ discard: true }
|
|
734
|
+
))
|
|
735
|
+
.onDone((to) => to.branch.Operating())
|
|
736
|
+
.onFailure((to) => to.branch.CommissioningFailed())
|
|
737
|
+
}
|
|
736
738
|
}
|
|
737
739
|
})
|
|
738
740
|
```
|
|
@@ -857,7 +859,10 @@ or child instance.
|
|
|
857
859
|
|
|
858
860
|
## Persistence
|
|
859
861
|
|
|
860
|
-
Logical snapshots
|
|
862
|
+
Logical snapshots use codec version 2, including the root at path `""`. Earlier
|
|
863
|
+
encoded snapshots are rejected; migrate persisted data explicitly before decoding.
|
|
864
|
+
|
|
865
|
+
Snapshots can be validated for storage or transport:
|
|
861
866
|
|
|
862
867
|
```ts
|
|
863
868
|
const encoded = yield * Machine.encodeSnapshot(machine, snapshot)
|