@@ -39,11 +39,12 @@ const Event = Schema.TaggedUnion({
3939})
4040
4141const States = Machine .defineStates (State .cases )
42+ const CounterEvent = Machine .events (Event )
4243
4344const CounterDefinition = Machine .make ({
4445 id: " Counter" ,
4546 states: States .states ,
46- events: [ Event ] ,
47+ events: CounterEvent ,
4748 initial : () => States .initial .Idle .from ()
4849})
4950
@@ -61,8 +62,6 @@ const Counter = CounterDefinition.handle({
6162 }
6263})
6364
64- const CounterEvent = Machine .events (Counter )
65-
6665const program = Effect .gen (function * () {
6766 const ref = yield * Machine .start (Counter )
6867 yield * ref .send (CounterEvent .Start ())
@@ -80,9 +79,11 @@ Use this order to preserve inference and keep boundaries explicit:
8079
81801 . Define domain, state, public-event, internal-event, and emitted-event schemas.
82812 . Declare topology with ` Machine.defineStates ` .
83- 3 . Create the protocol and initializer with ` Machine.make ` .
84- 4 . Implement every active state with ` .handle(...) ` .
85- 5 . Add runtime, Atom, testing, or cluster adapters at the application boundary.
82+ 3 . Create public and internal event descriptors with ` Machine.events ` and
83+ ` Machine.internalEvents ` .
84+ 4 . Create the machine protocol and initializer with ` Machine.make ` .
85+ 5 . Implement every active state with ` .handle(...) ` .
86+ 6 . Add runtime, Atom, testing, or cluster adapters at the application boundary.
8687
8788### Construct state through builders
8889
@@ -134,22 +135,24 @@ const Internal = Schema.TaggedUnion({
134135 SaveFailed: { message: Schema .String }
135136})
136137
138+ export const CommandEvent = Machine .events (Command )
139+ export type PublicCommandEvent = Machine .EventOf <typeof CommandEvent >
140+ const InternalEvent = Machine .internalEvents (Internal )
141+
137142const definition = Machine .make ({
138143 states: States .states ,
139- events: [ Command ] ,
140- internalEvents: [ Internal ] ,
144+ events: CommandEvent ,
145+ internalEvents: InternalEvent ,
141146 initial : () => States .initial .Idle .from ()
142147})
143-
144- const CommandEvent = Machine .events (definition )
145- const InternalEvent = Machine .internalEvents (definition )
146148```
147149
148150Handlers see both protocols. Typed ` send ` and ` Machine.plan ` accept only public
149151events. Event tags must be unique and public/internal tags must be disjoint.
150152
151- Use ` Machine.events(machine) ` and ` Machine.internalEvents(machine) ` as the
152- standard constructors for their respective protocols:
153+ Export the descriptor returned by ` Machine.events ` instead of exporting its
154+ schemas. This keeps the deferred constructors as the standard way to create
155+ events without exposing schema ` .make ` methods:
153156
154157``` ts
155158ref .send (CommandEvent .Save ())
@@ -160,6 +163,9 @@ The returned constructors preserve each schema's make input, including required
160163fields and constructor defaults. They defer schema construction until delivery,
161164so invalid values fail planning or the running machine with
162165` MachineSchemaDecodeError ` instead of throwing at the call site.
166+ Schemas with an open discriminator such as ` _tag: Schema.String ` remain valid
167+ protocols but cannot expose a finite constructor set; pass a complete event
168+ object to ` send ` or ` Machine.plan ` for those events.
163169
164170### Choose the target by scope
165171
@@ -296,18 +302,18 @@ import { MachineTest } from "@typeonce/effect-machine/testing"
296302
297303const trace = yield * MachineTest .run (Counter , {
298304 events: [
299- Machine . event ( Counter , Event . cases . Start ) ,
300- Machine . event ( Counter , Event . cases . Increment )
305+ { _tag: " Start" } ,
306+ { _tag: " Increment" }
301307 ]
302308})
303309
304310yield * MachineTest .verify (Counter , trace )
305311```
306312
307313` 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.
314+ pass complete decoded objects when defining scenarios manually. Pure planner
315+ tests do not execute invokes or time. Use a started machine and a probe when
316+ those semantics matter.
311317
312318## Entrypoints
313319
0 commit comments