@typeonce/effect-machine 0.8.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 +64 -24
- package/dist/Machine.d.ts +386 -304
- package/dist/Machine.d.ts.map +1 -1
- package/dist/Machine.js +66 -171
- 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 +2 -2
- package/dist/internal/machine/atom.d.ts.map +1 -1
- package/dist/internal/machine/executionPlan.d.ts.map +1 -1
- package/dist/internal/machine/executionPlan.js +25 -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 +8 -65
- package/dist/internal/machine/machine.js.map +1 -1
- package/dist/internal/machine/planner.d.ts +2 -1
- package/dist/internal/machine/planner.d.ts.map +1 -1
- package/dist/internal/machine/planner.js +45 -2
- 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/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.map +1 -1
- package/dist/internal/machine/topology.js +23 -0
- package/dist/internal/machine/topology.js.map +1 -1
- package/dist/unstable/reactivity/AtomMachine.d.ts +3 -3
- package/dist/unstable/reactivity/AtomMachine.d.ts.map +1 -1
- package/docs/agent-guide.md +118 -93
- package/package.json +2 -2
- package/src/Machine.ts +1040 -651
- package/src/internal/machine/activities.ts +48 -33
- package/src/internal/machine/atom.ts +3 -3
- package/src/internal/machine/executionPlan.ts +29 -0
- package/src/internal/machine/invocation.ts +179 -48
- package/src/internal/machine/invocationEvent.ts +72 -0
- package/src/internal/machine/machine.ts +20 -346
- package/src/internal/machine/planner.ts +61 -10
- package/src/internal/machine/protocol.ts +149 -0
- package/src/internal/machine/symbols.ts +3 -0
- package/src/internal/machine/topology.ts +23 -0
- package/src/unstable/reactivity/AtomMachine.ts +3 -3
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
|
|
|
@@ -130,20 +134,32 @@ const Internal = Schema.TaggedUnion({
|
|
|
130
134
|
SaveFailed: { message: Schema.String }
|
|
131
135
|
})
|
|
132
136
|
|
|
133
|
-
const
|
|
137
|
+
const definition = Machine.make({
|
|
134
138
|
states: States.states,
|
|
135
139
|
events: [Command],
|
|
136
140
|
internalEvents: [Internal],
|
|
137
141
|
initial: () => States.initial.Idle.from()
|
|
138
142
|
})
|
|
143
|
+
|
|
144
|
+
const CommandEvent = Machine.events(definition)
|
|
145
|
+
const InternalEvent = Machine.internalEvents(definition)
|
|
139
146
|
```
|
|
140
147
|
|
|
141
148
|
Handlers see both protocols. Typed `send` and `Machine.plan` accept only public
|
|
142
149
|
events. Event tags must be unique and public/internal tags must be disjoint.
|
|
143
150
|
|
|
144
|
-
Use `Machine.
|
|
145
|
-
|
|
146
|
-
|
|
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.
|
|
147
163
|
|
|
148
164
|
### Choose the target by scope
|
|
149
165
|
|
|
@@ -185,29 +201,48 @@ State-scoped work starts on entry and is interrupted on exit:
|
|
|
185
201
|
|
|
186
202
|
```ts
|
|
187
203
|
Loading: {
|
|
188
|
-
invoke: Machine.
|
|
204
|
+
invoke: Machine.invoke({
|
|
189
205
|
id: "save-document",
|
|
190
206
|
effect: saveDocument,
|
|
191
|
-
|
|
192
|
-
onFailure: (error) =>
|
|
207
|
+
onDone: ({ output, target }) => target.full.Saved({ id: output.id }),
|
|
208
|
+
onFailure: ({ error, target }) => target.full.Failed({ message: String(error) })
|
|
193
209
|
})
|
|
194
210
|
}
|
|
195
211
|
|
|
196
212
|
Waiting: {
|
|
197
|
-
invoke: Machine.
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
213
|
+
invoke: Machine.invoke({
|
|
214
|
+
id: "save-timeout",
|
|
215
|
+
after: "3 seconds",
|
|
216
|
+
onDone: ({ target }) => target.full.Failed({ message: "Timed out" })
|
|
217
|
+
})
|
|
201
218
|
}
|
|
202
219
|
```
|
|
203
220
|
|
|
204
|
-
Use `
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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.
|
|
208
240
|
|
|
209
|
-
|
|
210
|
-
|
|
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.
|
|
211
246
|
|
|
212
247
|
## Reactivity
|
|
213
248
|
|
|
@@ -260,14 +295,19 @@ The testing entrypoint provides complementary layers:
|
|
|
260
295
|
import { MachineTest } from "@typeonce/effect-machine/testing"
|
|
261
296
|
|
|
262
297
|
const trace = yield* MachineTest.run(Counter, {
|
|
263
|
-
events: [
|
|
298
|
+
events: [
|
|
299
|
+
Machine.event(Counter, Event.cases.Start),
|
|
300
|
+
Machine.event(Counter, Event.cases.Increment)
|
|
301
|
+
]
|
|
264
302
|
})
|
|
265
303
|
|
|
266
304
|
yield* MachineTest.verify(Counter, trace)
|
|
267
305
|
```
|
|
268
306
|
|
|
269
|
-
|
|
270
|
-
|
|
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.
|
|
271
311
|
|
|
272
312
|
## Entrypoints
|
|
273
313
|
|