xstate
4.23.3
Patch Changes
- #2587
5aaa8445c
Thanks @Andarist! - Allow for guards to be always resolved from the implementations object. This allows a guard implementation to be updated in the running service by@xstate/react
.
4.23.2
Patch Changes
6c3f15c9
#2551 Thanks @mattpocock! - Widened the *From utility types to allow extracting from factory functions.This allows for:
const makeMachine = () => createMachine({}); type Interpreter = InterpreterFrom<typeof makeMachine>; type Actor = ActorRefFrom<typeof makeMachine>; type Context = ContextFrom<typeof makeMachine>; type Event = EventsFrom<typeof makeMachine>;
This also works for models, behaviours, and other actor types.
The previous method for doing this was a good bit more verbose:
const makeMachine = () => createMachine({}); type Interpreter = InterpreterFrom<ReturnType<typeof machine>>;
413a4578
#2491 Thanks @davidkpiano! - The custom.toString()
method on action objects is now removed which improves performance in larger applications (see #2488 for more context).
5e1223cd
#2422 Thanks @davidkpiano! - Thecontext
property has been removed fromStateNodeConfig
, as it has never been allowed, nor has it ever done anything. The previous typing was unsafe and allowedcontext
to be specified on nested state nodes:createMachine({ context: { /* ... */ }, // ✅ This is allowed initial: 'inner', states: { inner: { context: { /* ... */ } // ❌ This will no longer compile } } });
5b70c2ff
#2508 Thanks @davidkpiano! - A race condition occurred when a child service is immediately stopped and the parent service tried to remove it from its undefined state (during its own initialization). This has been fixed, and the race condition no longer occurs. See this issue for details.
5a9500d1
#2522 Thanks @farskid, @Andarist! - Adjusted TS type definitions of thewithContext
andwithConfig
methods so that they accept “lazy context” now.Example:
const copy = machine.withContext(() => ({ ref: spawn(() => {}) }));
84f9fcae
#2540 Thanks @Andarist! - Fixed an issue withstate.hasTag('someTag')
crashing when thestate
was rehydrated.
c17dd376
#2496 Thanks @VanTanev! - Add utility typeEmittedFrom<T>
that extractsEmitted
type from any type which can emit data
4.23.1
Patch Changes
141c91cf
#2436 Thanks @Andarist! - Fixed an issue where, when usingmodel.createMachine
, state’s context was incorrectly inferred asany
after refinement with.matches(...)
, e.g.// `state.context` became `any` erroneously if (state.matches('inactive')) { console.log(state.context.count); }
4.23.0
Minor Changes
7dc7ceb8
#2379 Thanks @davidkpiano! - There is a new.preserveActionOrder
(default:false
) setting in the machine configuration that preserves the order of actions when set totrue
. Normally, actions are executed in order except forassign(...)
actions, which are prioritized and executed first. When.preserveActionOrder
is set totrue
,assign(...)
actions will not be prioritized, and will instead run in order. As a result, actions will capture the intermediatecontext
values instead of the resultingcontext
value from allassign(...)
actions.// With `.preserveActionOrder: true` const machine = createMachine({ context: { count: 0 }, entry: [ ctx => console.log(ctx.count), // 0 assign({ count: ctx => ctx.count + 1 }), ctx => console.log(ctx.count), // 1 assign({ count: ctx => ctx.count + 1 }), ctx => console.log(ctx.count) // 2 ], preserveActionOrder: true }); // With `.preserveActionOrder: false` (default) const machine = createMachine({ context: { count: 0 }, entry: [ ctx => console.log(ctx.count), // 2 assign({ count: ctx => ctx.count + 1 }), ctx => console.log(ctx.count), // 2 assign({ count: ctx => ctx.count + 1 }), ctx => console.log(ctx.count) // 2 ] // preserveActionOrder: false });
Patch Changes
4e305372
#2361 Thanks @woutermont! - Add type forSymbol.observable
to theInterpreter
to improve the compatibility with RxJS.
1def6cf6
#2374 Thanks @davidkpiano! - Existing actors can now be identified inspawn(...)
calls by providing anid
. This allows them to be referenced by string:const machine = createMachine({ context: () => ({ someRef: spawn(someExistingRef, 'something') }), on: { SOME_EVENT: { actions: send('AN_EVENT', { to: 'something' }) } } });
da6861e3
#2391 Thanks @davidkpiano! - There are two new helper types for extractingcontext
andevent
types:ContextFrom<T>
which extracts thecontext
from any type that uses contextEventFrom<T>
which extracts theevent
type (which extendsEventObject
) from any type which uses events
4.22.0
Minor Changes
1b32aa0d
#2356 Thanks @davidkpiano! - The model created fromcreateModel(...)
now provides a.createMachine(...)
method that does not require passing any generic type parameters:const model = createModel(/* ... */); -const machine = createMachine<typeof model>(/* ... */); +const machine = model.createMachine(/* ... */);
432b60f7
#2280 Thanks @davidkpiano! - Actors can now be invoked/spawned from reducers using thefromReducer(...)
behavior creator:import { fromReducer } from 'xstate/lib/behaviors'; type CountEvent = { type: 'INC' } | { type: 'DEC' }; const countReducer = (count: number, event: CountEvent): number => { if (event.type === 'INC') { return count + 1; } else if (event.type === 'DEC') { return count - 1; } return count; }; const countMachine = createMachine({ invoke: { id: 'count', src: () => fromReducer(countReducer, 0) }, on: { INC: { actions: forwardTo('count') }, DEC: { actions: forwardTo('count') } } });
f9bcea2c
#2366 Thanks @davidkpiano! - Actors can now be spawned directly in the initialmachine.context
using lazy initialization, avoiding the need for intermediate states and unsafe typings for immediately spawned actors:const machine = createMachine<{ ref: ActorRef<SomeEvent> }>({ context: () => ({ ref: spawn(anotherMachine, 'some-id') // spawn immediately! }) // ... });
4.20.2
Patch Changes
1ef29e83
#2343 Thanks @davidkpiano! - Eventless (“always”) transitions will no longer be ignored if an event is sent to a machine in a state that does not have any enabled transitions for that event.
4.20.1
Patch Changes
99bc5fb9
#2275 Thanks @davidkpiano! - TheSpawnedActorRef
TypeScript interface has been deprecated in favor of a unifiedActorRef
interface, which contains the following:interface ActorRef<TEvent extends EventObject, TEmitted = any> extends Subscribable<TEmitted> { send: (event: TEvent) => void; id: string; subscribe(observer: Observer<T>): Subscription; subscribe( next: (value: T) => void, error?: (error: any) => void, complete?: () => void ): Subscription; getSnapshot: () => TEmitted | undefined; }
For simpler actor-ref-like objects, the
BaseActorRef<TEvent>
interface has been introduced.interface BaseActorRef<TEvent extends EventObject> { send: (event: TEvent) => void; }
38e6a5e9
#2334 Thanks @davidkpiano! - When using a model type increateMachine<typeof someModel>(...)
, TypeScript will no longer compile machines that are missing thecontext
property in the machine configuration:const machine = createMachine<typeof someModel>({ // missing context - will give a TS error! // context: someModel.initialContext, initial: 'somewhere', states: { somewhere: {} } });
5f790ba5
#2320 Thanks @davidkpiano! - The typing forInvokeCallback
have been improved for better event constraints when using thesendBack
parameter of invoked callbacks:invoke: () => (sendBack, receive) => { // Will now be constrained to events that the parent machine can receive sendBack({ type: 'SOME_EVENT' }); };
2de3ec3e
#2272 Thanks @davidkpiano! - Thestate.meta
value is now calculated directly fromstate.configuration
. This is most useful when starting a service from a persisted state:const machine = createMachine({ id: 'test', initial: 'first', states: { first: { meta: { name: 'first state' } }, second: { meta: { name: 'second state' } } } }); const service = interpret(machine); service.start('second'); // `meta` will be computed // the state will have // meta: { // 'test.second': { // name: 'second state' // } // } });
4.20.0
Minor Changes
28059b9f
#2197 Thanks @davidkpiano! - All spawned and invoked actors now have a.getSnapshot()
method, which allows you to retrieve the latest value emitted from that actor. That value may beundefined
if no value has been emitted yet.const machine = createMachine({ context: { promiseRef: null }, initial: 'pending', states: { pending: { entry: assign({ promiseRef: () => spawn(fetch(/* ... */), 'some-promise') }) } } }); const service = interpret(machine) .onTransition(state => { // Read promise value synchronously const resolvedValue = state.context.promiseRef?.getSnapshot(); // => undefined (if promise not resolved yet) // => { ... } (resolved data) }) .start(); // ...
Patch Changes
4ef03465
#2240 Thanks @VanTanev! - Preserve StateMachine type when .withConfig() and .withContext() modifiers are used on a machine.
4.19.2
Patch Changes
18789aa9
#2107 Thanks @woutermont! - This update restricts invokedSubscribable
s toEventObject
s, so that type inference can be done on whichSubscribable
s are allowed to be invoked. ExistingMachineConfig
s that invokeSubscribable<any>
s that are notSubscribable<EventObject>
s should be updated accordingly.
38dcec1d
#2149 Thanks @davidkpiano! - Invocations and entry actions for combinatorial machines (machines with only a single root state) now behave predictably and will not re-execute upon targetless transitions.
4.19.1
Patch Changes
64ab1150
#2173 Thanks @Andarist! - Fixed an issue with tags not being set correctly after sending an event to a machine that didn’t result in selecting any transitions.
4.19.0
Minor Changes
4f2f626d
#2143 Thanks @davidkpiano! - Tags can now be added to state node configs under the.tags
property:const machine = createMachine({ initial: 'green', states: { green: { tags: 'go' // single tag }, yellow: { tags: 'go' }, red: { tags: ['stop', 'other'] // multiple tags } } });
You can query whether a state has a tag via
state.hasTag(tag)
:const canGo = state.hasTag('go'); // => `true` if in 'green' or 'red' state
Patch Changes
a61d01ce
#2125 Thanks @VanTanev! - In callback invokes, the types ofcallback
andonReceive
are properly scoped to the machine TEvent.
4.18.0
Minor Changes
d0939ec6
#2046 Thanks @SimeonC! - Allow machines to communicate with the inspector even in production builds.
e37fffef
#2079 Thanks @davidkpiano! - There is now support for “combinatorial machines” (state machines that only have one state):const testMachine = createMachine({ context: { value: 42 }, on: { INC: { actions: assign({ value: ctx => ctx.value + 1 }) } } });
These machines omit the
initial
andstate
properties, as the entire machine is treated as a single state.
Patch Changes
6a9247d4
#2102 Thanks @VanTanev! - Provide a convenience type for getting theInterpreter
type based on theStateMachine
type by transferring all generic parameters onto it. It can be used like this:InterpreterFrom<typeof machine>
4.17.1
Patch Changes
33302814
#2041 Thanks @Andarist! - Fixed an issue with creatorless models not being correctly matched bycreateMachine
’s overload responsible for using model-induced types.
4.17.0
Minor Changes
7763db8d
#1977 Thanks @davidkpiano! - Theschema
property has been introduced to the machine config passed intocreateMachine(machineConfig)
, which allows you to provide metadata for the following:- Context
- Events
- Actions
- Guards
- Services
This metadata can be accessed as-is from
machine.schema
:const machine = createMachine({ schema: { // Example in JSON Schema (anything can be used) context: { type: 'object', properties: { foo: { type: 'string' }, bar: { type: 'number' }, baz: { type: 'object', properties: { one: { type: 'string' } } } } }, events: { FOO: { type: 'object' }, BAR: { type: 'object' } } } // ... });
Additionally, the new
createSchema()
identity function allows any schema “metadata” to be represented by a specific type, which makes type inference easier without having to specify generic types:import { createSchema, createMachine } from 'xstate'; // Both `context` and `events` are inferred in the rest of the machine! const machine = createMachine({ schema: { context: createSchema<{ count: number }>(), // No arguments necessary events: createSchema<{ type: 'FOO' } | { type: 'BAR' }>() } // ... });
5febfe83
#1955 Thanks @davidkpiano! - Event creators can now be modeled inside of the 2nd argument ofcreateModel()
, and types for bothcontext
andevents
will be inferred properly increateMachine()
when given thetypeof model
as the first generic parameter.import { createModel } from 'xstate/lib/model'; const userModel = createModel( // initial context { name: 'David', age: 30 }, // creators (just events for now) { events: { updateName: (value: string) => ({ value }), updateAge: (value: number) => ({ value }), anotherEvent: () => ({}) // no payload } } ); const machine = createMachine<typeof userModel>({ context: userModel.initialContext, initial: 'active', states: { active: { on: { updateName: { /* ... */ }, updateAge: { /* ... */ } } } } }); const nextState = machine.transition( undefined, userModel.events.updateName('David') );
4.16.2
Patch Changes
4194ffe8
#1710 Thanks @davidkpiano! - Stopping an already stopped interpreter will no longer crash. See #1697 for details.
4.16.1
Patch Changes
af6b7c70
#1865 Thanks @Andarist! - Improved.matches(value)
inference for typestates containing union types as values.
4.16.0
Minor Changes
d2e328f8
#1439 Thanks @davidkpiano! - An opt-increateModel()
helper has been introduced to make it easier to work with typedcontext
and events.createModel(initialContext)
creates amodel
objectmodel.initialContext
returns theinitialContext
model.assign(assigner, event?)
creates anassign
action that is properly scoped to theevent
in TypeScript
See https://github.com/davidkpiano/xstate/pull/1439 for more details.
import { createMachine } from 'xstate'; import { createModel } from 'xstate/lib/model'; // opt-in, not part of main build interface UserContext { name: string; age: number; } type UserEvents = | { type: 'updateName'; value: string } | { type: 'updateAge'; value: number } const userModel = createModel<UserContext, UserEvents>({ name: 'David', age: 30 }); const assignName = userModel.assign({ name: (_, e) => e.value // correctly typed to `string` }, 'updateName'); // restrict to 'updateName' event const machine = createMachine<UserContext, UserEvents>({ context: userModel.context, initial: 'active', states: { active: { on: { updateName: { actions: assignName } } } } });
4.15.4
Patch Changes
0cb8df9b
#1816 Thanks @Andarist! -machine.resolveState(state)
calls should resolve to the correct value of.done
property now.
4.15.3
Patch Changes
63ba888e
#1770 Thanks @davidkpiano! - Instead of referencingwindow
directly, XState now internally calls agetGlobal()
function that will resolve to the properglobalThis
value in all environments. This affects the dev tools code only.
4.15.2
Patch Changes
497c543d
#1766 Thanks @Andarist! - Fixed an issue with events received from callback actors not having the appropriate_event.origin
set.
4.15.1
Patch Changes
8a8cfa32
#1704 Thanks @blimmer! - The defaultclock
methods (setTimeout
andclearTimeout
) are now invoked properly with the global context preserved for those invocations which matter for some JS environments. More details can be found in the corresponding issue: #1703.
4.15.0
Minor Changes
6596d0ba
#1622 Thanks @davidkpiano! - Spawned/invoked actors and interpreters are now typed as extendingActorRef
(e.g.,SpawnedActorRef
) rather thanActor
orInterpreter
. This unification of types should make it more straightforward to provide actor types:import { - Actor + ActorRef } from 'xstate'; // ... interface SomeContext { - server?: Actor; + server?: ActorRef<ServerEvent>; }
It’s also easier to specify the type of a spawned/invoked machine with
ActorRefFrom
:import { createMachine, - Actor + ActorRefFrom } from 'xstate'; const serverMachine = createMachine<ServerContext, ServerEvent>({ // ... }); interface SomeContext { - server?: Actor; // difficult to type + server?: ActorRefFrom<typeof serverMachine>; }
Patch Changes
75a91b07
#1692 Thanks @Andarist! - Fixed an issue with history state entering a wrong state if the most recent visit in its parent has been caused by a transient transition.
4.14.1
Patch Changes
02c76350
#1656 Thanks @Andarist! - Exit actions will now be properly called when a service gets canceled by calling itsstop
method.
4.14.0
Minor Changes
119db8fb
#1577 Thanks @davidkpiano! - Expressions can now be used in thestop()
action creator:// ... actions: stop(context => context.someActor);
Patch Changes
8c78e120
#1570 Thanks @davidkpiano! - The return type ofspawn(machine)
will now beActor<State<TContext, TEvent>, TEvent>
, which is a supertype ofInterpreter<...>
.
602687c2
#1566 Thanks @davidkpiano! - Exit actions will now be properly called when an invoked machine reaches its final state. See #1109 for more details.
6e44d02a
#1553 Thanks @davidkpiano! - Thestate.children
property now properly shows all spawned and invoked actors. See #795 for more details.
72b0880e
#1504 Thanks @Andarist! - Addedstatus
property on theInterpreter
- this can be used to differentiate not started, running and stopped interpreters. This property is best compared to values on the newInterpreterStatus
export.
4.13.0
Minor Changes
f51614df
#1409 Thanks @jirutka! - Fix typeExtractStateValue
so that it generates a type actually describing aState.value
Patch Changes
b1684ead
#1402 Thanks @Andarist! - Improved TypeScript type-checking performance a little bit by using distributive conditional type withinTransitionsConfigArray
declarations instead of a mapped type. Kudos to @amcasey, some discussion around this can be found here
ad3026d4
#1407 Thanks @tomenden! - Fixed an issue with not being able to run XState in Web Workers due to assuming thatwindow
orglobal
object is available in the executing environment, but none of those are actually available in the Web Workers context.
4e949ec8
#1401 Thanks @Andarist! - Fixed an issue with spawned actors being spawned multiple times when they got spawned in an initial state of a child machine that is invoked in the initial state of a parent machine.Illustrating example for curious readers.
const child = createMachine({ initial: 'bar', context: {}, states: { bar: { entry: assign({ promise: () => { return spawn(() => Promise.resolve('answer')); } }) } } }); const parent = createMachine({ initial: 'foo', states: { foo: { invoke: { src: child, onDone: 'end' } }, end: { type: 'final' } } }); interpret(parent).start();
4.12.0
Minor Changes
b72e29dd
#1354 Thanks @davidkpiano! - TheAction
type was simplified, and as a result, you should see better TypeScript performance.
4dbabfe7
#1320 Thanks @davidkpiano! - Theinvoke.src
property now accepts an object that describes the invoke source with itstype
and other related metadata. This can be read from theservices
option in themeta.src
argument:const machine = createMachine( { initial: 'searching', states: { searching: { invoke: { src: { type: 'search', endpoint: 'example.com' } // ... } // ... } } }, { services: { search: (context, event, { src }) => { console.log(src); // => { endpoint: 'example.com' } } } } );
Specifying a string for
invoke.src
will continue to work the same; e.g., ifsrc: 'search'
was specified, this would be the same assrc: { type: 'search' }
.
8662e543
#1317 Thanks @Andarist! - AllTTypestate
type parameters default to{ value: any; context: TContext }
now and the parametrized type is passed correctly between various types which results in more accurate types involving typestates.
Patch Changes
3ab3f25e
#1285 Thanks @Andarist! - Fixed an issue with initial state of invoked machines being read without custom data passed to them which could lead to a crash when evaluating transient transitions for the initial state.
a7da1451
#1290 Thanks @davidkpiano! - The “Attempted to spawn an Actor […] outside of a service. This will have no effect.” warnings are now silenced for “lazily spawned” actors, which are actors that aren’t immediately active until the function that creates them are called:// ⚠️ "active" actor - will warn spawn(somePromise); // 🕐 "lazy" actor - won't warn spawn(() => somePromise); // 🕐 machines are also "lazy" - won't warn spawn(someMachine);
It is recommended that all
spawn(...)
-ed actors are lazy, to avoid accidentally initializing them e.g., when readingmachine.initialState
or calculating otherwise pure transitions. In V5, this will be enforced.
c1f3d260
#1317 Thanks @Andarist! - Fixed a type returned by araise
action - it’s nowRaiseAction<TEvent> | SendAction<TContext, AnyEventObject, TEvent>
instead ofRaiseAction<TEvent> | SendAction<TContext, TEvent, TEvent>
. This makes it comaptible in a broader range of scenarios.
8270d5a7
#1372 Thanks @christianchown! - Narrowed theServiceConfig
type definition to use a specific event type to prevent compilation errors on strictly-typedMachineOptions
.
01e3e2dc
#1320 Thanks @davidkpiano! - The JSON definition forstateNode.invoke
objects will no longer include theonDone
andonError
transitions, since those transitions are already merged into thetransitions
array. This solves the issue of reviving a serialized machine from JSON, where before, theonDone
andonError
transitions for invocations were wrongly duplicated.
4.11.0
Minor Changes
36ed8d0a
#1262 Thanks @Andarist! - Improved type inference forInvokeConfig['data']
. This has required renamingdata
property onStateNode
instances todoneData
. This property was never meant to be a part of the public API, so we don’t consider this to be a breaking change.
2c75ab82
#1219 Thanks @davidkpiano! - The resolved value of theinvoke.data
property is now available in the “invoke meta” object, which is passed as the 3rd argument to the service creator inoptions.services
. This will work for all types of invoked services now, including promises, observables, and callbacks.const machine = createMachine({ initial: 'pending', context: { id: 42 }, states: { pending: { invoke: { src: 'fetchUser', data: { userId: (context) => context.id }, onDone: 'success' } }, success: { type: 'final' } } }, { services: { fetchUser: (ctx, _, { data }) => { return fetch(`some/api/user/${data.userId}`) .then(response => response.json()); } } }
a6c78ae9
#1249 Thanks @davidkpiano! - New property introduced for eventless (transient) transitions:always
, which indicates a transition that is always taken when in that state. Empty string transition configs for transient transitions are deprecated in favor ofalways
:// ... states: { playing: { + always: [ + { target: 'win', cond: 'didPlayerWin' }, + { target: 'lose', cond: 'didPlayerLose' }, + ], on: { // ⚠️ Deprecation warning - '': [ - { target: 'win', cond: 'didPlayerWin' }, - { target: 'lose', cond: 'didPlayerLose' }, - ] } } } // ...
The old empty string syntax (
'': ...
) will continue to work until V5.
Patch Changes
36ed8d0a
#1262 Thanks @Andarist! -StateMachine<any, any, any>
is no longer a part of theInvokeConfig
type, but rather it creates a union withInvokeConfig
in places where it is needed. This change shouldn’t affect consumers’ code.
4.10.0
Minor Changes
0133954
#1178 Thanks @davidkpiano! - The types for thesend()
andsendParent()
action creators have been changed to fix the issue of only being able to send events that the machine can receive. In reality, a machine can and should send events to other actors that it might not be able to receive itself. See #711 for more information.
a1f1239
#1189 Thanks @davidkpiano! - Previously,state.matches(...)
was problematic because it was castingstate
tonever
if it didn’t match the state value. This is now fixed by making theTypestate
resolution more granular.
dbc6a16
#1183 Thanks @davidkpiano! - Actions from a restored state provided as a custom initial state tointerpret(machine).start(initialState)
are now executed properly. See #1174 for more information.
Patch Changes
a10d604
#1176 Thanks @itfarrier! - Fix passing state schema into State generic
326db72
#1185 Thanks @Andarist! - Fixed an issue with invoked service not being correctly started if other service got stopped in a subsequent microstep (in response to raised or null event).
c3a496e
#1160 Thanks @davidkpiano! - Delayed transitions defined usingafter
were previously causing a circular dependency when the machine was converted using.toJSON()
. This has now been fixed.
e16e48e
#1153 Thanks @Andarist! - Fixed an issue withchoose
andpure
not being able to use actions defined in options.
d496ecb
#1165 Thanks @davidkpiano! - XState will now warn if you define an.onDone
transition on the root node. Root nodes which are “done” represent the machine being in its final state, and can no longer accept any events. This has been reported as confusing in #1111.
4.9.1
Patch Changes
8a97785
#1137 Thanks @davidkpiano! - Added docs for thechoose()
andpure()
action creators, as well as exporting thepure()
action creator in theactions
object.
e65dee9
#1131 Thanks @wKovacs64! - Include the newchoose
action in theactions
export from thexstate
core package. This was missed in v4.9.0.
4.9.0
Minor Changes
f3ff150
#1103 Thanks @davidkpiano! - Simplify theTransitionConfigArray
andTransitionConfigMap
types in order to fix excessively deep type instantiation TypeScript reports. This addresses #1015.
6c47b66
#1076 Thanks @Andarist! - Added support for conditional actions. It’s possible now to have actions executed based on conditions using following:entry: [ choose([ { cond: ctx => ctx > 100, actions: raise('TOGGLE') }, { cond: 'hasMagicBottle', actions: [assign(ctx => ({ counter: ctx.counter + 1 }))] }, { actions: ['fallbackAction'] } ]) ];
It works very similar to the if-else syntax where only the first matched condition is causing associated actions to be executed and the last ones can be unconditional (serving as a general fallback, just like else branch).
Patch Changes
1a129f0
#1073 Thanks @Andarist! - Cleanup internal structures upon receiving termination events from spawned actors.
e88aa18
#1085 Thanks @Andarist! - Fixed an issue with data expressions of root’s final nodes being called twice.
88b17b2
#1090 Thanks @rjdestigter! - This change carries forward the typestate type information encoded in the arguments of the following functions and assures that the return type also has the same typestate type information:- Cloned state machine returned by
.withConfig
. .state
getter defined for services.start
method of services.
- Cloned state machine returned by
d5f622f
#1069 Thanks @davidkpiano! - Loosened event type forSendAction<TContext, AnyEventObject>
4.8.0
Minor Changes
55aa589
#960 Thanks @davidkpiano! - The machine can now be safely JSON-serialized, usingJSON.stringify(machine)
. The shape of this serialization is defined inmachine.schema.json
and reflected inmachine.definition
.Note that
onEntry
andonExit
have been deprecated in the definition in favor ofentry
andexit
.
Patch Changes
4.7.8
Patch Changes
520580b
#967 Thanks @andrewgordstewart! - Add context & event types to InvokeConfig
4.7.7
Patch Changes
c8db035
#936 Thanks @davidkpiano! - Theescalate()
action can now take in an expression, which will be evaluated against thecontext
,event
, andmeta
to return the error data.
2a3fea1
#952 Thanks @davidkpiano! - The typings for the raise() action have been fixed to allow any event to be raised. This typed behavior will be refined in version 5, to limit raised events to those that the machine accepts.
f86d419
#957 Thanks @Andarist! - Fixed memory leak - each created service has been registered in internal map but it was never removed from it. Registration has been moved to a point where Interpreter is being started and it’s deregistered when it is being stopped.
4.7.6
Patch Changes
- dae8818: Typestates are now propagated to interpreted services.
4.7.5
Patch Changes
- 6b3d767: Fixed issue with delayed transitions scheduling a delayed event for each transition defined for a single delay.
4.7.4
Patch Changes
- 9b043cd: The initial state is now cached inside of the service instance instead of the machine, which was the previous (faulty) strategy. This will prevent entry actions on initial states from being called more than once, which is important for ensuring that actors are not spawned more than once.
4.7.3
Patch Changes
- 2b134eee: Fixed issue with events being forwarded to children after being processed by the current machine. Events are now always forwarded first.
- 2b134eee: Fixed issue with not being able to spawn an actor when processing an event batch.