@typeonce/effect-machine 0.7.0 → 0.9.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 +85 -24
- package/dist/Machine.d.ts +545 -444
- package/dist/Machine.d.ts.map +1 -1
- package/dist/Machine.js +69 -172
- package/dist/Machine.js.map +1 -1
- package/dist/internal/machine/activities.d.ts +5 -12
- package/dist/internal/machine/activities.d.ts.map +1 -1
- package/dist/internal/machine/activities.js +47 -17
- package/dist/internal/machine/activities.js.map +1 -1
- package/dist/internal/machine/atom.d.ts +10 -4
- package/dist/internal/machine/atom.d.ts.map +1 -1
- package/dist/internal/machine/atom.js.map +1 -1
- package/dist/internal/machine/configuration.d.ts.map +1 -1
- package/dist/internal/machine/configuration.js +103 -20
- package/dist/internal/machine/configuration.js.map +1 -1
- package/dist/internal/machine/executionPlan.d.ts.map +1 -1
- package/dist/internal/machine/executionPlan.js +31 -0
- package/dist/internal/machine/executionPlan.js.map +1 -1
- package/dist/internal/machine/invocation.d.ts +10 -2
- package/dist/internal/machine/invocation.d.ts.map +1 -1
- package/dist/internal/machine/invocation.js +93 -34
- package/dist/internal/machine/invocation.js.map +1 -1
- package/dist/internal/machine/invocationEvent.d.ts +39 -0
- package/dist/internal/machine/invocationEvent.d.ts.map +1 -0
- package/dist/internal/machine/invocationEvent.js +43 -0
- package/dist/internal/machine/invocationEvent.js.map +1 -0
- package/dist/internal/machine/machine.d.ts +6 -50
- package/dist/internal/machine/machine.d.ts.map +1 -1
- package/dist/internal/machine/machine.js +30 -81
- package/dist/internal/machine/machine.js.map +1 -1
- package/dist/internal/machine/planner.d.ts +12 -1
- package/dist/internal/machine/planner.d.ts.map +1 -1
- package/dist/internal/machine/planner.js +90 -37
- package/dist/internal/machine/planner.js.map +1 -1
- package/dist/internal/machine/protocol.d.ts +9 -0
- package/dist/internal/machine/protocol.d.ts.map +1 -1
- package/dist/internal/machine/protocol.js +114 -0
- package/dist/internal/machine/protocol.js.map +1 -1
- package/dist/internal/machine/serialization.d.ts.map +1 -1
- package/dist/internal/machine/serialization.js +53 -21
- package/dist/internal/machine/serialization.js.map +1 -1
- package/dist/internal/machine/stateDefinition.d.ts +4 -4
- package/dist/internal/machine/stateDefinition.d.ts.map +1 -1
- package/dist/internal/machine/stateDefinition.js +18 -11
- package/dist/internal/machine/stateDefinition.js.map +1 -1
- package/dist/internal/machine/symbols.d.ts +2 -0
- package/dist/internal/machine/symbols.d.ts.map +1 -1
- package/dist/internal/machine/symbols.js +2 -0
- package/dist/internal/machine/symbols.js.map +1 -1
- package/dist/internal/machine/topology.d.ts +5 -5
- package/dist/internal/machine/topology.d.ts.map +1 -1
- package/dist/internal/machine/topology.js +39 -13
- package/dist/internal/machine/topology.js.map +1 -1
- package/dist/internal/testing/machine/verification.d.ts.map +1 -1
- package/dist/internal/testing/machine/verification.js +10 -3
- package/dist/internal/testing/machine/verification.js.map +1 -1
- package/dist/unstable/reactivity/AtomMachine.d.ts +11 -5
- package/dist/unstable/reactivity/AtomMachine.d.ts.map +1 -1
- package/dist/unstable/reactivity/AtomMachine.js.map +1 -1
- package/docs/agent-guide.md +174 -121
- package/package.json +3 -3
- package/src/Machine.ts +1336 -872
- package/src/internal/machine/activities.ts +48 -33
- package/src/internal/machine/atom.ts +13 -6
- package/src/internal/machine/configuration.ts +102 -23
- package/src/internal/machine/executionPlan.ts +35 -0
- package/src/internal/machine/invocation.ts +180 -49
- package/src/internal/machine/invocationEvent.ts +72 -0
- package/src/internal/machine/machine.ts +105 -403
- package/src/internal/machine/planner.ts +110 -48
- package/src/internal/machine/protocol.ts +149 -0
- package/src/internal/machine/serialization.ts +56 -31
- package/src/internal/machine/stateDefinition.ts +22 -11
- package/src/internal/machine/symbols.ts +3 -0
- package/src/internal/machine/topology.ts +44 -18
- package/src/internal/testing/machine/verification.ts +13 -3
- package/src/unstable/reactivity/AtomMachine.ts +12 -5
package/README.md
CHANGED
|
@@ -40,12 +40,14 @@ const Event = Schema.TaggedUnion({
|
|
|
40
40
|
|
|
41
41
|
const States = Machine.defineStates(State.cases)
|
|
42
42
|
|
|
43
|
-
const
|
|
43
|
+
const CounterDefinition = Machine.make({
|
|
44
44
|
id: "Counter",
|
|
45
45
|
states: States.states,
|
|
46
46
|
events: [Event],
|
|
47
47
|
initial: () => States.initial.Idle.from()
|
|
48
|
-
})
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
const Counter = CounterDefinition.handle({
|
|
49
51
|
Idle: {
|
|
50
52
|
on: {
|
|
51
53
|
Start: ({ target }) => target.full.Running.from({ count: 0 })
|
|
@@ -59,10 +61,12 @@ const Counter = Machine.make({
|
|
|
59
61
|
}
|
|
60
62
|
})
|
|
61
63
|
|
|
64
|
+
const CounterEvent = Machine.events(Counter)
|
|
65
|
+
|
|
62
66
|
const program = Effect.gen(function*() {
|
|
63
67
|
const ref = yield* Machine.start(Counter)
|
|
64
|
-
yield* ref.send(
|
|
65
|
-
yield* ref.send(
|
|
68
|
+
yield* ref.send(CounterEvent.Start())
|
|
69
|
+
yield* ref.send(CounterEvent.Increment())
|
|
66
70
|
})
|
|
67
71
|
```
|
|
68
72
|
|
|
@@ -94,6 +98,27 @@ defaults, refinements, and tagged-class identity are therefore preserved, and
|
|
|
94
98
|
decode failures remain typed machine failures. Pass a value directly only when
|
|
95
99
|
it is already decoded, such as a value returned by `Machine.retag`.
|
|
96
100
|
|
|
101
|
+
Omit `schema` when a state represents control flow but owns no data:
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
const States = Machine.defineStates({
|
|
105
|
+
Form: {
|
|
106
|
+
initial: "Editing",
|
|
107
|
+
states: {
|
|
108
|
+
Editing: {},
|
|
109
|
+
Saving
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
States.initial.Form.from((form) => form.Editing.from())
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Schema-less states remain active, targetable, matchable, and visible through
|
|
118
|
+
`getSnapshot`, but have no value to read. Their builders expose only `.from`,
|
|
119
|
+
their handler `state` is `undefined`, and `get` / `getWithParents` accept only
|
|
120
|
+
schema-backed paths. Add a schema later if the state starts owning data.
|
|
121
|
+
|
|
97
122
|
Put data on the narrowest state where it is valid. If sibling phases share
|
|
98
123
|
data, put it on their compound parent.
|
|
99
124
|
|
|
@@ -109,20 +134,32 @@ const Internal = Schema.TaggedUnion({
|
|
|
109
134
|
SaveFailed: { message: Schema.String }
|
|
110
135
|
})
|
|
111
136
|
|
|
112
|
-
const
|
|
137
|
+
const definition = Machine.make({
|
|
113
138
|
states: States.states,
|
|
114
139
|
events: [Command],
|
|
115
140
|
internalEvents: [Internal],
|
|
116
141
|
initial: () => States.initial.Idle.from()
|
|
117
142
|
})
|
|
143
|
+
|
|
144
|
+
const CommandEvent = Machine.events(definition)
|
|
145
|
+
const InternalEvent = Machine.internalEvents(definition)
|
|
118
146
|
```
|
|
119
147
|
|
|
120
148
|
Handlers see both protocols. Typed `send` and `Machine.plan` accept only public
|
|
121
149
|
events. Event tags must be unique and public/internal tags must be disjoint.
|
|
122
150
|
|
|
123
|
-
Use `Machine.
|
|
124
|
-
|
|
125
|
-
|
|
151
|
+
Use `Machine.events(machine)` and `Machine.internalEvents(machine)` as the
|
|
152
|
+
standard constructors for their respective protocols:
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
ref.send(CommandEvent.Save())
|
|
156
|
+
enqueue.raise(InternalEvent.Saved({ id: "entry-1" }))
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
The returned constructors preserve each schema's make input, including required
|
|
160
|
+
fields and constructor defaults. They defer schema construction until delivery,
|
|
161
|
+
so invalid values fail planning or the running machine with
|
|
162
|
+
`MachineSchemaDecodeError` instead of throwing at the call site.
|
|
126
163
|
|
|
127
164
|
### Choose the target by scope
|
|
128
165
|
|
|
@@ -164,29 +201,48 @@ State-scoped work starts on entry and is interrupted on exit:
|
|
|
164
201
|
|
|
165
202
|
```ts
|
|
166
203
|
Loading: {
|
|
167
|
-
invoke: Machine.
|
|
204
|
+
invoke: Machine.invoke({
|
|
168
205
|
id: "save-document",
|
|
169
206
|
effect: saveDocument,
|
|
170
|
-
|
|
171
|
-
onFailure: (error) =>
|
|
207
|
+
onDone: ({ output, target }) => target.full.Saved({ id: output.id }),
|
|
208
|
+
onFailure: ({ error, target }) => target.full.Failed({ message: String(error) })
|
|
172
209
|
})
|
|
173
210
|
}
|
|
174
211
|
|
|
175
212
|
Waiting: {
|
|
176
|
-
invoke: Machine.
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
213
|
+
invoke: Machine.invoke({
|
|
214
|
+
id: "save-timeout",
|
|
215
|
+
after: "3 seconds",
|
|
216
|
+
onDone: ({ target }) => target.full.Failed({ message: "Timed out" })
|
|
217
|
+
})
|
|
180
218
|
}
|
|
181
219
|
```
|
|
182
220
|
|
|
183
|
-
Use `
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
221
|
+
Use `effect` for one Effect, `after` for a cancellable delay, `logic` for a
|
|
222
|
+
reusable process, and `child` for a complete child statechart—all through
|
|
223
|
+
`Machine.invoke({...})`. The helper is an identity at runtime and preserves
|
|
224
|
+
owner-context and source-channel inference across lifecycle handlers, including
|
|
225
|
+
for state-dependent Effects:
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
invoke: Machine.invoke({
|
|
229
|
+
id: "load-document",
|
|
230
|
+
effect: ({ state }) => loadDocument(state.documentId),
|
|
231
|
+
onDone: ({ output, target }) => target.full.Ready({ document: output }),
|
|
232
|
+
onFailure: ({ error, target }) => target.full.Failed({ message: error.message })
|
|
233
|
+
})
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
A direct `invoke: { ... }` object is also supported when its lifecycle handlers
|
|
237
|
+
do not need source-derived context. Reuse one exported
|
|
238
|
+
`Machine.child(id, machine)` descriptor for invocation, `sendTo`, and child
|
|
239
|
+
lookup.
|
|
187
240
|
|
|
188
|
-
|
|
189
|
-
|
|
241
|
+
`onDone` is required for a non-`never` output, and `onFailure` is required for a
|
|
242
|
+
non-`never` typed error; each handler is omitted when its channel is `never`.
|
|
243
|
+
Defects, interruption, and source-construction failures terminate the owning
|
|
244
|
+
runtime. `effect: Effect.sleep(...)` is valid, but `after` keeps timers explicit
|
|
245
|
+
and makes static durations visible through activity inspection.
|
|
190
246
|
|
|
191
247
|
## Reactivity
|
|
192
248
|
|
|
@@ -239,14 +295,19 @@ The testing entrypoint provides complementary layers:
|
|
|
239
295
|
import { MachineTest } from "@typeonce/effect-machine/testing"
|
|
240
296
|
|
|
241
297
|
const trace = yield* MachineTest.run(Counter, {
|
|
242
|
-
events: [
|
|
298
|
+
events: [
|
|
299
|
+
Machine.event(Counter, Event.cases.Start),
|
|
300
|
+
Machine.event(Counter, Event.cases.Increment)
|
|
301
|
+
]
|
|
243
302
|
})
|
|
244
303
|
|
|
245
304
|
yield* MachineTest.verify(Counter, trace)
|
|
246
305
|
```
|
|
247
306
|
|
|
248
|
-
|
|
249
|
-
|
|
307
|
+
`MachineTest` scenarios retain decoded event values for model inspection, so
|
|
308
|
+
this is the main case for the eager `Machine.event` API. Pure planner tests do
|
|
309
|
+
not execute invokes or time. Use a started machine and a probe when those
|
|
310
|
+
semantics matter.
|
|
250
311
|
|
|
251
312
|
## Entrypoints
|
|
252
313
|
|