@typeonce/effect-machine 0.14.1 → 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 +12 -7
- 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 +27 -20
- 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
package/README.md
CHANGED
|
@@ -53,14 +53,14 @@ const State = Schema.TaggedUnion({
|
|
|
53
53
|
Running: { count: Schema.Number }
|
|
54
54
|
})
|
|
55
55
|
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
56
|
+
const States = Machine.states(State.cases)
|
|
57
|
+
const CounterEvent = Machine.events(
|
|
58
|
+
Schema.TaggedUnion({
|
|
59
|
+
Start: {},
|
|
60
|
+
Increment: {},
|
|
61
|
+
Stop: {}
|
|
62
|
+
})
|
|
63
|
+
)
|
|
64
64
|
|
|
65
65
|
const CounterDefinition = Machine.make({
|
|
66
66
|
id: "Counter",
|
|
@@ -102,6 +102,16 @@ const program = Effect.gen(function*() {
|
|
|
102
102
|
})
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
+
`handle` creates a complete implementation boundary. Its result does not
|
|
106
|
+
expose `handle`, so all behavior for one machine belongs in the same handler
|
|
107
|
+
tree. Reuse the definition when multiple independent implementations are
|
|
108
|
+
useful, such as production and testing variants:
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
const ProductionCounter = CounterDefinition.handle(productionHandlers)
|
|
112
|
+
const TestingCounter = CounterDefinition.handle(testingHandlers)
|
|
113
|
+
```
|
|
114
|
+
|
|
105
115
|
`Machine.start` returns a `MachineRef` with `send`, `state`, `snapshot`,
|
|
106
116
|
`changes`, `emissions`, `join`, and `stop`. Sending enqueues an event; observe
|
|
107
117
|
`changes` or use the testing probe when work must be causally acknowledged.
|
|
@@ -110,13 +120,21 @@ const program = Effect.gen(function*() {
|
|
|
110
120
|
|
|
111
121
|
Use this order to preserve inference and keep boundaries explicit:
|
|
112
122
|
|
|
113
|
-
1. Define domain
|
|
114
|
-
2. Declare topology with `Machine.
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
123
|
+
1. Define domain schemas used by state and by shared event fields.
|
|
124
|
+
2. Declare topology with `Machine.states`, naming a tagged state union
|
|
125
|
+
when its `.cases` are reused.
|
|
126
|
+
3. Create event descriptors with `Machine.events`, `Machine.internalEvents`,
|
|
127
|
+
and `Machine.emittedEvents`, passing tagged unions or tagged classes directly.
|
|
128
|
+
4. Create the machine and implement every active state with
|
|
129
|
+
`Machine.make({...}).handle({...})`.
|
|
130
|
+
5. Add child descriptors, then runtime, Atom, testing, or cluster adapters at
|
|
131
|
+
the application boundary.
|
|
132
|
+
|
|
133
|
+
Keep one-off topology inline in `Machine.states`. Use `Machine.state` only when
|
|
134
|
+
the same active state definition is mounted more than once; tagged schemas are
|
|
135
|
+
already reusable without it. For repeated finite regions, derive names with
|
|
136
|
+
`States.path(...)` so every literal in the path family is checked against the
|
|
137
|
+
complete tree. Type full-snapshot helpers as `Machine.Snapshot<typeof States>`.
|
|
120
138
|
|
|
121
139
|
### Construct state through builders
|
|
122
140
|
|
|
@@ -147,7 +165,7 @@ Submit: Machine.transition({
|
|
|
147
165
|
Omit `schema` when a state represents control flow but owns no data:
|
|
148
166
|
|
|
149
167
|
```ts
|
|
150
|
-
const States = Machine.
|
|
168
|
+
const States = Machine.states({
|
|
151
169
|
Form: {
|
|
152
170
|
initial: "Editing",
|
|
153
171
|
states: {
|
|
@@ -178,19 +196,21 @@ belong in `internalEvents`. Ephemeral outward notifications have their own
|
|
|
178
196
|
`emittedEvents` protocol:
|
|
179
197
|
|
|
180
198
|
```ts
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
SaveFailed: { message: Schema.String }
|
|
185
|
-
})
|
|
186
|
-
const Emitted = Schema.TaggedUnion({
|
|
187
|
-
SaveObserved: { id: Schema.String }
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
export const CommandEvent = Machine.events(Command)
|
|
199
|
+
export const CommandEvent = Machine.events(
|
|
200
|
+
Schema.TaggedUnion({ Save: {} })
|
|
201
|
+
)
|
|
191
202
|
export type PublicCommandEvent = Machine.EventOf<typeof CommandEvent>
|
|
192
|
-
const InternalEvent = Machine.internalEvents(
|
|
193
|
-
|
|
203
|
+
const InternalEvent = Machine.internalEvents(
|
|
204
|
+
Schema.TaggedUnion({
|
|
205
|
+
Saved: { id: Schema.String },
|
|
206
|
+
SaveFailed: { message: Schema.String }
|
|
207
|
+
})
|
|
208
|
+
)
|
|
209
|
+
const Emissions = Machine.emittedEvents(
|
|
210
|
+
Schema.TaggedUnion({
|
|
211
|
+
SaveObserved: { id: Schema.String }
|
|
212
|
+
})
|
|
213
|
+
)
|
|
194
214
|
|
|
195
215
|
const definition = Machine.make({
|
|
196
216
|
states: States.states,
|
|
@@ -374,7 +394,7 @@ change; use `{ reenter: true, transition }` when the source must restart. With
|
|
|
374
394
|
|
|
375
395
|
## Statechart capabilities
|
|
376
396
|
|
|
377
|
-
`Machine.
|
|
397
|
+
`Machine.states` supports:
|
|
378
398
|
|
|
379
399
|
- atomic states;
|
|
380
400
|
- compound states with one active child;
|
|
@@ -384,7 +404,7 @@ change; use `{ reenter: true, transition }` when the source must restart. With
|
|
|
384
404
|
- shallow and deep history states.
|
|
385
405
|
|
|
386
406
|
Declare topology—including finality, output schemas, choices, and history—only
|
|
387
|
-
in `
|
|
407
|
+
in `states`. Handlers implement behavior and output computation without
|
|
388
408
|
repeating structural metadata. Final children complete their parent, so
|
|
389
409
|
`onDone` belongs on that compound or parallel parent.
|
|
390
410
|
|
|
@@ -446,31 +466,31 @@ invoke: Machine.invoke({
|
|
|
446
466
|
})
|
|
447
467
|
```
|
|
448
468
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
`parentEvents` protocols:
|
|
469
|
+
Inside `.handle(...)`, `Machine.invoke(...)` receives the owning machine's
|
|
470
|
+
public input and `parentEvents` protocols contextually. Its source and lifecycle
|
|
471
|
+
callbacks can send through `self` and `parent` while retaining the invoked
|
|
472
|
+
Effect's output and error inference:
|
|
454
473
|
|
|
455
474
|
```ts
|
|
456
|
-
const
|
|
475
|
+
const machine = Machine.make({
|
|
457
476
|
events: Commands,
|
|
458
477
|
internalEvents: InternalEvents,
|
|
459
478
|
parentEvents: ParentEvents
|
|
460
479
|
// ...
|
|
461
|
-
})
|
|
462
|
-
|
|
463
|
-
const machine = definition.handle({
|
|
480
|
+
}).handle({
|
|
464
481
|
Saving: {
|
|
465
|
-
invoke:
|
|
482
|
+
invoke: Machine.invoke({
|
|
466
483
|
id: "notify-parent",
|
|
467
|
-
effect: (
|
|
468
|
-
parent === undefined
|
|
469
|
-
? Effect.void
|
|
470
|
-
: parent.send(ParentEvents.SaveStarted()),
|
|
484
|
+
effect: () => saveDocument,
|
|
471
485
|
onDone: Machine.transition({
|
|
472
486
|
target: (to) => to.none(),
|
|
473
|
-
resolve: () =>
|
|
487
|
+
resolve: ({ parent, self }, enqueue) => {
|
|
488
|
+
enqueue.sendTo(self, Commands.Save())
|
|
489
|
+
if (parent !== undefined) {
|
|
490
|
+
enqueue.sendTo(parent, ParentEvents.ChildFinished({ id: "job-1" }))
|
|
491
|
+
}
|
|
492
|
+
return undefined
|
|
493
|
+
}
|
|
474
494
|
}),
|
|
475
495
|
onFailure: Machine.transition({
|
|
476
496
|
target: (to) => to.none(),
|
|
@@ -481,6 +501,9 @@ const machine = definition.handle({
|
|
|
481
501
|
})
|
|
482
502
|
```
|
|
483
503
|
|
|
504
|
+
The machine-bound `definition.invoke(...)` form remains equivalent when a
|
|
505
|
+
definition is already named; it is not required for `self` or `parent` typing.
|
|
506
|
+
|
|
484
507
|
A direct `invoke: { ... }` object is also supported when its lifecycle handlers
|
|
485
508
|
do not need source-derived context. Reuse one exported
|
|
486
509
|
`Machine.child(id, machine)` descriptor for invocation, `sendTo`, and child
|