@typeonce/effect-machine 0.14.0 → 0.15.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 +68 -45
- package/dist/Machine.d.ts +178 -68
- package/dist/Machine.d.ts.map +1 -1
- package/dist/Machine.js +81 -24
- package/dist/Machine.js.map +1 -1
- package/dist/internal/machine/machine.d.ts +9 -4
- package/dist/internal/machine/machine.d.ts.map +1 -1
- package/dist/internal/machine/machine.js +27 -10
- package/dist/internal/machine/machine.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 +35 -0
- package/dist/internal/machine/stateDefinition.js.map +1 -1
- package/dist/internal/testing/machine/finiteModel.js +1 -1
- package/dist/internal/testing/machine/finiteModel.js.map +1 -1
- package/dist/testing/MachineTest.d.ts +7 -7
- package/dist/testing/MachineTest.js +7 -7
- package/dist/unstable/cluster/ClusterMachine.d.ts +1 -1
- package/dist/unstable/cluster/ClusterMachine.js +1 -1
- package/dist/unstable/reactivity/AtomMachine.d.ts +3 -3
- package/dist/unstable/reactivity/AtomMachine.js +3 -3
- package/docs/agent-guide.md +144 -51
- package/package.json +1 -1
- package/src/Machine.ts +279 -97
- package/src/internal/machine/machine.ts +42 -22
- package/src/internal/machine/stateDefinition.ts +41 -1
- package/src/internal/testing/machine/finiteModel.ts +1 -1
- package/src/testing/MachineTest.ts +7 -7
- package/src/unstable/cluster/ClusterMachine.ts +1 -1
- package/src/unstable/reactivity/AtomMachine.ts +3 -3
|
@@ -30,7 +30,7 @@ export const interpretModel = internal.interpretModel;
|
|
|
30
30
|
*
|
|
31
31
|
* class Idle extends Schema.TaggedClass<Idle>("Idle")("Idle", {}) {}
|
|
32
32
|
* class Reset extends Schema.TaggedClass<Reset>("Reset")("Reset", {}) {}
|
|
33
|
-
* const States = Machine.
|
|
33
|
+
* const States = Machine.states({ Idle })
|
|
34
34
|
* const machine = Machine.make({
|
|
35
35
|
* states: States.states,
|
|
36
36
|
* events: Machine.events(Reset),
|
|
@@ -79,7 +79,7 @@ export { ProbeUnavailableError } from "../internal/testing/machine/verification.
|
|
|
79
79
|
* import { MachineTest } from "@typeonce/effect-machine/testing"
|
|
80
80
|
*
|
|
81
81
|
* class Idle extends Schema.TaggedClass<Idle>("Idle")("Idle", {}) {}
|
|
82
|
-
* const States = Machine.
|
|
82
|
+
* const States = Machine.states({ Idle })
|
|
83
83
|
* const machine = Machine.make({
|
|
84
84
|
* states: States.states,
|
|
85
85
|
* events: Machine.events(),
|
|
@@ -164,7 +164,7 @@ export const Invariant = internal.Invariant;
|
|
|
164
164
|
* class Count extends Schema.TaggedClass<Count>("Count")("Count", {
|
|
165
165
|
* value: Schema.Number
|
|
166
166
|
* }) {}
|
|
167
|
-
* const States = Machine.
|
|
167
|
+
* const States = Machine.states({ Count })
|
|
168
168
|
* const machine = Machine.make({
|
|
169
169
|
* states: States.states,
|
|
170
170
|
* events: Machine.events(),
|
|
@@ -235,7 +235,7 @@ export const assertInvariants = internal.assertInvariants;
|
|
|
235
235
|
* value: Schema.Number
|
|
236
236
|
* }) {}
|
|
237
237
|
* class Increment extends Schema.TaggedClass<Increment>("Increment")("Increment", {}) {}
|
|
238
|
-
* const States = Machine.
|
|
238
|
+
* const States = Machine.states({ Count })
|
|
239
239
|
* const machine = Machine.make({
|
|
240
240
|
* states: States.states,
|
|
241
241
|
* events: Machine.events(Increment),
|
|
@@ -327,7 +327,7 @@ export const verifyModel = internal.verifyModel;
|
|
|
327
327
|
* import { MachineTest } from "@typeonce/effect-machine/testing"
|
|
328
328
|
*
|
|
329
329
|
* class Idle extends Schema.TaggedClass<Idle>("Idle")("Idle", {}) {}
|
|
330
|
-
* const States = Machine.
|
|
330
|
+
* const States = Machine.states({ Idle })
|
|
331
331
|
* const machine = Machine.make({
|
|
332
332
|
* states: States.states,
|
|
333
333
|
* events: Machine.events(),
|
|
@@ -358,7 +358,7 @@ export const run = internal.run;
|
|
|
358
358
|
* import { MachineTest } from "@typeonce/effect-machine/testing"
|
|
359
359
|
*
|
|
360
360
|
* class Idle extends Schema.TaggedClass<Idle>("Idle")("Idle", {}) {}
|
|
361
|
-
* const States = Machine.
|
|
361
|
+
* const States = Machine.states({ Idle })
|
|
362
362
|
* const machine = Machine.make({
|
|
363
363
|
* states: States.states,
|
|
364
364
|
* events: Machine.events(),
|
|
@@ -414,7 +414,7 @@ export { VerificationError } from "../internal/testing/machine/verification.js";
|
|
|
414
414
|
* import { MachineTest } from "@typeonce/effect-machine/testing"
|
|
415
415
|
*
|
|
416
416
|
* class Idle extends Schema.TaggedClass<Idle>("Idle")("Idle", {}) {}
|
|
417
|
-
* const States = Machine.
|
|
417
|
+
* const States = Machine.states({ Idle })
|
|
418
418
|
* const machine = Machine.make({
|
|
419
419
|
* states: States.states,
|
|
420
420
|
* events: Machine.events(),
|
|
@@ -252,7 +252,7 @@ export declare const layerMemory: Layer.Layer<Storage>;
|
|
|
252
252
|
* import { ClusterMachine } from "@typeonce/effect-machine/cluster"
|
|
253
253
|
*
|
|
254
254
|
* class Idle extends Schema.TaggedClass<Idle>("Idle")("Idle", {}) {}
|
|
255
|
-
* const States = Machine.
|
|
255
|
+
* const States = Machine.states({ Idle })
|
|
256
256
|
* const machine = Machine.make({
|
|
257
257
|
* states: States.states,
|
|
258
258
|
* events: Machine.events(),
|
|
@@ -127,7 +127,7 @@ export const layerMemory = internal.layerMemory;
|
|
|
127
127
|
* import { ClusterMachine } from "@typeonce/effect-machine/cluster"
|
|
128
128
|
*
|
|
129
129
|
* class Idle extends Schema.TaggedClass<Idle>("Idle")("Idle", {}) {}
|
|
130
|
-
* const States = Machine.
|
|
130
|
+
* const States = Machine.states({ Idle })
|
|
131
131
|
* const machine = Machine.make({
|
|
132
132
|
* states: States.states,
|
|
133
133
|
* events: Machine.events(),
|
|
@@ -250,7 +250,7 @@ type ChildState<Child extends Machine.ChildMachine.Any> = RefState<Machine.Child
|
|
|
250
250
|
* class Count extends Schema.TaggedClass<Count>("Count")("Count", {
|
|
251
251
|
* value: Schema.Number
|
|
252
252
|
* }) {}
|
|
253
|
-
* const States = Machine.
|
|
253
|
+
* const States = Machine.states({ Count })
|
|
254
254
|
* const machine = Machine.make({
|
|
255
255
|
* states: States.states,
|
|
256
256
|
* events: Machine.events(),
|
|
@@ -324,7 +324,7 @@ export declare const selectSnapshotChild: <Child extends Machine.ChildMachine.An
|
|
|
324
324
|
* import { AtomMachine } from "@typeonce/effect-machine/reactivity"
|
|
325
325
|
*
|
|
326
326
|
* class Idle extends Schema.TaggedClass<Idle>("Idle")("Idle", {}) {}
|
|
327
|
-
* const States = Machine.
|
|
327
|
+
* const States = Machine.states({ Idle })
|
|
328
328
|
* const machine = Machine.make({
|
|
329
329
|
* states: States.states,
|
|
330
330
|
* events: Machine.events(),
|
|
@@ -409,7 +409,7 @@ export interface Bound<Services, RuntimeError = never> {
|
|
|
409
409
|
* import { AtomMachine } from "@typeonce/effect-machine/reactivity"
|
|
410
410
|
*
|
|
411
411
|
* class Idle extends Schema.TaggedClass<Idle>("Idle")("Idle", {}) {}
|
|
412
|
-
* const States = Machine.
|
|
412
|
+
* const States = Machine.states({ Idle })
|
|
413
413
|
* const machine = Machine.make({
|
|
414
414
|
* states: States.states,
|
|
415
415
|
* events: Machine.events(),
|
|
@@ -62,7 +62,7 @@ export const childEmissions = internal.childEmissions;
|
|
|
62
62
|
* class Count extends Schema.TaggedClass<Count>("Count")("Count", {
|
|
63
63
|
* value: Schema.Number
|
|
64
64
|
* }) {}
|
|
65
|
-
* const States = Machine.
|
|
65
|
+
* const States = Machine.states({ Count })
|
|
66
66
|
* const machine = Machine.make({
|
|
67
67
|
* states: States.states,
|
|
68
68
|
* events: Machine.events(),
|
|
@@ -136,7 +136,7 @@ export const selectSnapshotChild = internal.selectSnapshotChild;
|
|
|
136
136
|
* import { AtomMachine } from "@typeonce/effect-machine/reactivity"
|
|
137
137
|
*
|
|
138
138
|
* class Idle extends Schema.TaggedClass<Idle>("Idle")("Idle", {}) {}
|
|
139
|
-
* const States = Machine.
|
|
139
|
+
* const States = Machine.states({ Idle })
|
|
140
140
|
* const machine = Machine.make({
|
|
141
141
|
* states: States.states,
|
|
142
142
|
* events: Machine.events(),
|
|
@@ -180,7 +180,7 @@ const BoundRequirementsTypeId = "~effect/reactivity/AtomMachine/BoundRequirement
|
|
|
180
180
|
* import { AtomMachine } from "@typeonce/effect-machine/reactivity"
|
|
181
181
|
*
|
|
182
182
|
* class Idle extends Schema.TaggedClass<Idle>("Idle")("Idle", {}) {}
|
|
183
|
-
* const States = Machine.
|
|
183
|
+
* const States = Machine.states({ Idle })
|
|
184
184
|
* const machine = Machine.make({
|
|
185
185
|
* states: States.states,
|
|
186
186
|
* events: Machine.events(),
|
package/docs/agent-guide.md
CHANGED
|
@@ -35,15 +35,19 @@ currently coupled to the exact Effect peer version listed in its `package.json`.
|
|
|
35
35
|
Use this order so inference has all schemas available when handlers are
|
|
36
36
|
declared:
|
|
37
37
|
|
|
38
|
-
1. Domain schemas used by state and event fields.
|
|
39
|
-
2.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
38
|
+
1. Domain schemas used by state, and by event fields when they are shared.
|
|
39
|
+
2. `Machine.states`, using a tagged state union and `.cases` when state
|
|
40
|
+
schemas need to be reused.
|
|
41
|
+
3. `Machine.events`, `Machine.internalEvents`, `Machine.emittedEvents`, and
|
|
42
|
+
`parentEvents`; pass `Schema.TaggedUnion({...})` or tagged classes directly.
|
|
43
|
+
4. `Machine.make({...}).handle({...})`.
|
|
44
|
+
5. Child descriptors, then runtime, Atom, or Cluster adapters.
|
|
45
|
+
|
|
46
|
+
`Machine.make` returns a reusable definition. Each `handle` call creates one
|
|
47
|
+
independent machine implementation and the result does not expose `handle`
|
|
48
|
+
again. Put one implementation's complete behavior in a single handler tree;
|
|
49
|
+
call `handle` again on the original definition for a separate production,
|
|
50
|
+
testing, or simulation variant.
|
|
47
51
|
|
|
48
52
|
`Schema.TaggedUnion` avoids one class declaration per case:
|
|
49
53
|
|
|
@@ -54,22 +58,23 @@ const State = Schema.TaggedUnion({
|
|
|
54
58
|
Failed: { message: Schema.String }
|
|
55
59
|
})
|
|
56
60
|
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
61
|
+
const States = Machine.states(State.cases)
|
|
62
|
+
export const Event = Machine.events(
|
|
63
|
+
Schema.TaggedUnion({
|
|
64
|
+
Save: {}
|
|
65
|
+
})
|
|
66
|
+
)
|
|
67
|
+
export const Internal = Machine.internalEvents(
|
|
68
|
+
Schema.TaggedUnion({
|
|
69
|
+
Saved: { id: Schema.String },
|
|
70
|
+
SaveFailed: { message: Schema.String }
|
|
71
|
+
})
|
|
72
|
+
)
|
|
69
73
|
```
|
|
70
74
|
|
|
71
|
-
Pass these descriptors to `Machine.make
|
|
72
|
-
|
|
75
|
+
Pass these descriptors to `Machine.make`; the event descriptor is the public
|
|
76
|
+
handle, so do not introduce a tagged-union binding used only by an event helper.
|
|
77
|
+
Construct new state values through the target or initial
|
|
73
78
|
builder's `.from(...)` method. Both event constructors and state `.from(...)`
|
|
74
79
|
defer schema construction until planning, so validation failures remain typed
|
|
75
80
|
machine errors. Use
|
|
@@ -121,9 +126,9 @@ its extra control is required:
|
|
|
121
126
|
- Use one invocation object: `effect` for one-shot work, `after` for a timer,
|
|
122
127
|
`logic` for reusable process logic, and `child` for a complete child
|
|
123
128
|
statechart. `Machine.invoke({...})` preserves owner state and source channels
|
|
124
|
-
across sibling lifecycle handlers.
|
|
125
|
-
|
|
126
|
-
definition
|
|
129
|
+
across sibling lifecycle handlers. Inside `.handle(...)`, `self` and `parent`
|
|
130
|
+
use the owning definition's exact public input and `parentEvents` protocols.
|
|
131
|
+
The bound `definition.invoke({...})` form is equivalent, not required.
|
|
127
132
|
- Use `Machine.child(id, machine)` for a complete statechart descriptor and
|
|
128
133
|
`Machine.childAddress<Event>(id)` for a low-level process address. A logic
|
|
129
134
|
invocation is addressable only when `Machine.invoke` receives that
|
|
@@ -133,11 +138,88 @@ its extra control is required:
|
|
|
133
138
|
|
|
134
139
|
## Atomic, compound, parallel, and history states
|
|
135
140
|
|
|
141
|
+
### Inline topology by default; extract only repeated states
|
|
142
|
+
|
|
143
|
+
Prefer writing the complete topology inline in `Machine.states`. A one-off
|
|
144
|
+
compound or parallel area is easier to understand in place, and extracting it
|
|
145
|
+
does not improve its types. Use `Machine.state` only when the same active state
|
|
146
|
+
definition is mounted more than once. Tagged schemas are already reusable and
|
|
147
|
+
do not need `Machine.state`.
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
type TeamSlot = 1 | 2 | 3 | 4 | 5 | 6
|
|
151
|
+
|
|
152
|
+
const TradingSlot = Machine.state({
|
|
153
|
+
initial: "Idle",
|
|
154
|
+
states: {
|
|
155
|
+
Idle: {},
|
|
156
|
+
InSession: State.cases.InSession,
|
|
157
|
+
Applying: State.cases.Applying
|
|
158
|
+
}
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
const States = Machine.states({
|
|
162
|
+
root: {
|
|
163
|
+
type: "parallel",
|
|
164
|
+
states: {
|
|
165
|
+
trading: {
|
|
166
|
+
type: "parallel",
|
|
167
|
+
states: {
|
|
168
|
+
slot1: TradingSlot,
|
|
169
|
+
slot2: TradingSlot,
|
|
170
|
+
slot3: TradingSlot,
|
|
171
|
+
slot4: TradingSlot,
|
|
172
|
+
slot5: TradingSlot,
|
|
173
|
+
slot6: TradingSlot
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
// Other explicit regions stay visible here.
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
})
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
`Machine.state` accepts one active atomic, compound, or parallel node. It
|
|
183
|
+
checks child keys and the compound `initial` at the reusable definition. It is
|
|
184
|
+
not a second model builder, does not define handlers, and does not accept
|
|
185
|
+
history or choice nodes as roots. `Machine.states` remains the complete model
|
|
186
|
+
boundary and captures every mount independently.
|
|
187
|
+
|
|
188
|
+
For a finite family of paths, bind the template to that definition instead of
|
|
189
|
+
maintaining a parallel string table:
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
const inSessionPath = <const Slot extends TeamSlot>(slot: Slot) =>
|
|
193
|
+
States.path(`root.trading.slot${slot}.InSession`)
|
|
194
|
+
|
|
195
|
+
States.matches(snapshot, inSessionPath(slot))
|
|
196
|
+
AtomMachine.matches(machineAtom, inSessionPath(slot))
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
`States.path` is a compile-time identity helper. It accepts a literal or a
|
|
200
|
+
finite template-literal union only when every member is an active path in this
|
|
201
|
+
tree. Renaming a slot or child therefore breaks the path helper at its
|
|
202
|
+
definition rather than leaving a stale catalog.
|
|
203
|
+
|
|
204
|
+
Use the definition-bound snapshot type when a query genuinely needs the full
|
|
205
|
+
machine snapshot:
|
|
206
|
+
|
|
207
|
+
```ts
|
|
208
|
+
const offeredIfSlot = (
|
|
209
|
+
snapshot: Machine.Snapshot<typeof States>,
|
|
210
|
+
slot: TeamSlot
|
|
211
|
+
) =>
|
|
212
|
+
!States.matches(snapshot, inSessionPath(slot))
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Do not derive this type with `Parameters<typeof States.get>[0]`; that depends
|
|
216
|
+
on overload order and does not express ownership by the state definition.
|
|
217
|
+
|
|
136
218
|
An active state does not need a schema unless it owns data. Omit `schema` for
|
|
137
219
|
control-only atomic, compound, parallel, and final states:
|
|
138
220
|
|
|
139
221
|
```ts
|
|
140
|
-
const States = Machine.
|
|
222
|
+
const States = Machine.states({
|
|
141
223
|
Idle: {},
|
|
142
224
|
Form: {
|
|
143
225
|
initial: "Editing",
|
|
@@ -190,7 +272,7 @@ Use a compound state when exactly one child phase is active. It must declare an
|
|
|
190
272
|
```ts
|
|
191
273
|
const FormState = Schema.TaggedUnion({ Saving: { draft: Schema.String } })
|
|
192
274
|
|
|
193
|
-
const FormStates = Machine.
|
|
275
|
+
const FormStates = Machine.states({
|
|
194
276
|
Form: {
|
|
195
277
|
initial: "Editing",
|
|
196
278
|
states: {
|
|
@@ -204,7 +286,7 @@ const FormStates = Machine.defineStates({
|
|
|
204
286
|
Use a parallel state when every direct region is active:
|
|
205
287
|
|
|
206
288
|
```ts
|
|
207
|
-
const ParallelStates = Machine.
|
|
289
|
+
const ParallelStates = Machine.states({
|
|
208
290
|
Screen: {
|
|
209
291
|
type: "parallel",
|
|
210
292
|
states: {
|
|
@@ -231,13 +313,13 @@ Every parallel region needs an active state in initial and full snapshot
|
|
|
231
313
|
builders. The same rule applies when a local or branch target enters an
|
|
232
314
|
inactive nested parallel state.
|
|
233
315
|
|
|
234
|
-
Use `type: "final"` for a terminal leaf in `Machine.
|
|
316
|
+
Use `type: "final"` for a terminal leaf in `Machine.states`. A final
|
|
235
317
|
child completes its compound parent. Put `onDone` on that completed parent,
|
|
236
318
|
never on the final leaf. The definition owns the output schema and the handler
|
|
237
319
|
computes its value:
|
|
238
320
|
|
|
239
321
|
```ts
|
|
240
|
-
const States = Machine.
|
|
322
|
+
const States = Machine.states({
|
|
241
323
|
Done: {
|
|
242
324
|
schema: State.cases.Done,
|
|
243
325
|
type: "final",
|
|
@@ -311,7 +393,7 @@ should remember. It has no schema, is excluded from active state identifiers,
|
|
|
311
393
|
and is addressed only through `target.history`:
|
|
312
394
|
|
|
313
395
|
```ts
|
|
314
|
-
const States = Machine.
|
|
396
|
+
const States = Machine.states({
|
|
315
397
|
checkout: {
|
|
316
398
|
schema: Checkout,
|
|
317
399
|
initial: "shipping",
|
|
@@ -455,7 +537,7 @@ through `schema.makeEffect`, including refinements.
|
|
|
455
537
|
|
|
456
538
|
## Reading state and structural ancestors
|
|
457
539
|
|
|
458
|
-
`Machine.
|
|
540
|
+
`Machine.states` returns typed helpers:
|
|
459
541
|
|
|
460
542
|
```ts
|
|
461
543
|
States.get(snapshot, "Route.Ready")
|
|
@@ -764,8 +846,17 @@ an event for the parent. Both operations validate their schemas.
|
|
|
764
846
|
union handled inside the statechart:
|
|
765
847
|
|
|
766
848
|
```ts
|
|
767
|
-
const Events = Machine.events(
|
|
768
|
-
|
|
849
|
+
const Events = Machine.events(
|
|
850
|
+
Schema.TaggedUnion({
|
|
851
|
+
Save: {}
|
|
852
|
+
})
|
|
853
|
+
)
|
|
854
|
+
const InternalEvents = Machine.internalEvents(
|
|
855
|
+
Schema.TaggedUnion({
|
|
856
|
+
Saved: { id: Schema.String },
|
|
857
|
+
SaveFailed: { message: Schema.String }
|
|
858
|
+
})
|
|
859
|
+
)
|
|
769
860
|
|
|
770
861
|
const definition = Machine.make({
|
|
771
862
|
states: States.states,
|
|
@@ -871,29 +962,30 @@ invoke: Machine.invoke({
|
|
|
871
962
|
})
|
|
872
963
|
```
|
|
873
964
|
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
through
|
|
965
|
+
Inside `.handle(...)`, the constructor receives the owning machine's public
|
|
966
|
+
input and `parentEvents` protocols contextually. Sources and lifecycle handlers
|
|
967
|
+
can send through `self` and `parent` without naming the definition:
|
|
877
968
|
|
|
878
969
|
```ts
|
|
879
|
-
const
|
|
970
|
+
const machine = Machine.make({
|
|
880
971
|
events: Commands,
|
|
881
972
|
internalEvents: InternalEvents,
|
|
882
973
|
parentEvents: ParentEvents,
|
|
883
974
|
// ...
|
|
884
|
-
})
|
|
885
|
-
|
|
886
|
-
const machine = definition.handle({
|
|
975
|
+
}).handle({
|
|
887
976
|
Saving: {
|
|
888
|
-
invoke:
|
|
977
|
+
invoke: Machine.invoke({
|
|
889
978
|
id: "notify-parent",
|
|
890
|
-
effect: (
|
|
891
|
-
parent === undefined
|
|
892
|
-
? Effect.void
|
|
893
|
-
: parent.send(ParentEvents.SaveStarted()),
|
|
979
|
+
effect: () => saveDocument,
|
|
894
980
|
onDone: Machine.transition({
|
|
895
981
|
target: (to) => to.none(),
|
|
896
|
-
resolve: () =>
|
|
982
|
+
resolve: ({ parent, self }, enqueue) => {
|
|
983
|
+
enqueue.sendTo(self, Commands.Save())
|
|
984
|
+
if (parent !== undefined) {
|
|
985
|
+
enqueue.sendTo(parent, ParentEvents.ChildFinished({ id: "job-1" }))
|
|
986
|
+
}
|
|
987
|
+
return undefined
|
|
988
|
+
}
|
|
897
989
|
}),
|
|
898
990
|
onFailure: Machine.transition({
|
|
899
991
|
target: (to) => to.none(),
|
|
@@ -904,8 +996,9 @@ const machine = definition.handle({
|
|
|
904
996
|
})
|
|
905
997
|
```
|
|
906
998
|
|
|
907
|
-
|
|
908
|
-
|
|
999
|
+
The machine-bound `definition.invoke(...)` form remains equivalent when the
|
|
1000
|
+
definition is already named. A direct `invoke: { ... }` object remains available
|
|
1001
|
+
when lifecycle handlers do not need source-derived context.
|
|
909
1002
|
|
|
910
1003
|
A cancellable timer uses the same object:
|
|
911
1004
|
|
|
@@ -1314,7 +1407,7 @@ repeat the final marker in this handler.
|
|
|
1314
1407
|
|
|
1315
1408
|
### `type: "final"` is rejected by `handle`
|
|
1316
1409
|
|
|
1317
|
-
Move it to `Machine.
|
|
1410
|
+
Move it to `Machine.states`. Definitions own statechart topology;
|
|
1318
1411
|
handlers own behavior.
|
|
1319
1412
|
|
|
1320
1413
|
### Parent property does not exist
|