Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(deps): update dependency xstate to v5 #240

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

renovate[bot]
Copy link
Contributor

@renovate renovate bot commented Dec 4, 2023

Mend Renovate

This PR contains the following updates:

Package Change Age Adoption Passing Confidence
xstate (source) ^4.35.0 -> ^5.0.0 age adoption passing confidence

Release Notes

statelyai/xstate (xstate)

v5.9.1

Compare Source

Patch Changes

v5.9.0

Compare Source

Minor Changes
  • #​4746 b570ba20d Thanks @​davidkpiano! - The new emit(…) action creator emits events that can be received by listeners. Actors are now event emitters.

    import { emit } from 'xstate';
    
    const machine = createMachine({
      // ...
      on: {
        something: {
          actions: emit({
            type: 'emitted',
            some: 'data'
          })
        }
      }
      // ...
    });
    
    const actor = createActor(machine).start();
    
    actor.on('emitted', (event) => {
      console.log(event);
    });
    
    actor.send({ type: 'something' });
    // logs:
    // {
    //   type: 'emitted',
    //   some: 'data'
    // }
  • #​4777 4abeed9df Thanks @​Andarist! - Added support for params to enqueueActions

v5.8.2

Compare Source

Patch Changes
  • #​4772 9a0120901 Thanks @​Andarist! - Fixed a type issue that prevent sendParent to be accepted by setup when delays stayed not configured.

v5.8.1

Compare Source

Patch Changes

v5.8.0

Compare Source

Minor Changes

v5.7.1

Compare Source

Patch Changes
  • #​4739 15b7dd1f0 Thanks @​devanfarrell! - Removed this from machine snapshot methods to fix issues with accessing those methods from union of actors and their snapshots.

v5.7.0

Compare Source

Minor Changes
  • #​4290 7a8796f80 Thanks @​davidkpiano! - An error will now be thrown if an incompatible state value is passed to machine.resolveState({ value }).

  • #​4693 11b6a1ae1 Thanks @​davidkpiano! - You can now inspect microsteps (@xstate.microstep) and actions (@xstate.action):

    const machine = createMachine({
      initial: 'a',
      states: {
        a: {
          on: {
            event: 'b'
          }
        },
        b: {
          entry: 'someAction',
          always: 'c'
        },
        c: {}
      }
    });
    
    const actor = createActor(machine, {
      inspect: (inspEvent) => {
        if (inspEvent.type === '@​xstate.microstep') {
          console.log(inspEvent.snapshot);
          // logs:
          // { value: 'a', … }
          // { value: 'b', … }
          // { value: 'c', … }
    
          console.log(inspEvent.event);
          // logs:
          // { type: 'event', … }
        } else if (inspEvent.type === '@​xstate.action') {
          console.log(inspEvent.action);
          // logs:
          // { type: 'someAction', … }
        }
      }
    });
    
    actor.start();
    
    actor.send({ type: 'event' });

v5.6.2

Compare Source

Patch Changes
  • #​4731 960cdcbcb Thanks @​davidkpiano! - You can now import getInitialSnapshot(…) from xstate directly, which is useful for getting a mock of the initial snapshot when interacting with machines (or other actor logic) without createActor(…):

    import { getInitialSnapshot } from 'xstate';
    import { someMachine } from './someMachine';
    
    // Returns the initial snapshot (state) of the machine
    const initialSnapshot = getInitialSnapshot(
      someMachine,
      { name: 'Mateusz' } // optional input
    );

v5.6.1

Compare Source

Patch Changes

v5.6.0

Compare Source

Minor Changes
  • #​4704 78699aef6 Thanks @​Andarist! - createActor will now error if the required input is not given to it.

  • #​4688 14902e17a Thanks @​Andarist! - The schemas property in setup(...) is now passed through to the resulting machine. This property is meant to be used with future developer tooling, and is typed as unknown for now.

Patch Changes

v5.5.2

Compare Source

Patch Changes
  • #​4685 e43eab144 Thanks @​davidkpiano! - State IDs that have periods in them are now supported if those periods are escaped.

    The motivation is that external tools, such as Stately Studio, may allow users to enter any text into the state ID field. This change allows those tools to escape periods in state IDs, so that they don't conflict with the internal path-based state IDs.

    E.g. if a state ID of "Loading..." is entered into the state ID field, instead of crashing either the external tool and/or the XState state machine, it should be converted by the tool to "Loading\\.\\.\\.", and those periods will be ignored by XState.

v5.5.1

Compare Source

Patch Changes

v5.5.0

Compare Source

Minor Changes
  • #​4596 6113a590a Thanks @​davidkpiano! - Introduce getNextSnapshot(...), which determines the next snapshot for the given actorLogic based on the given snapshot and event.

    If the snapshot is undefined, the initial snapshot of the actorLogic is used.

    import { getNextSnapshot } from 'xstate';
    import { trafficLightMachine } from './trafficLightMachine.ts';
    
    const nextSnapshot = getNextSnapshot(
      trafficLightMachine, // actor logic
      undefined, // snapshot (or initial state if undefined)
      { type: 'TIMER' }
    ); // event object
    
    console.log(nextSnapshot.value);
    // => 'yellow'
    
    const nextSnapshot2 = getNextSnapshot(
      trafficLightMachine, // actor logic
      nextSnapshot, // snapshot
      { type: 'TIMER' }
    ); // event object
    
    console.log(nextSnapshot2.value);
    // =>'red'
Patch Changes

v5.4.1

Compare Source

Patch Changes

v5.4.0

Compare Source

Minor Changes
  • #​4616 e8c0b15b2 Thanks @​Andarist! - context factories receive self now so you can immediately pass that as part of the input to spawned actors.

    setup({
      /* ... */
    }).createMachine({
      context: ({ spawn, self }) => {
        return {
          childRef: spawn('child', { input: { parent: self } })
        };
      }
    });

v5.3.1

Compare Source

Patch Changes
  • #​4597 ae0b05f11 Thanks @​davidkpiano! - Update the argument object of enqueueActions(...) to include the self and system properties:

    // ...
    entry: enqueueActions(({ self, system }) => {
      // ...
    });

v5.3.0

Compare Source

Minor Changes
  • #​4547 8e8d2ba38 Thanks @​davidkpiano! - Add assertEvent(...) to help provide strong typings for events that can't be easily inferred, such as events in entry and exit actions, or in invoke.input.

    The assertEvent(event, 'someType') function will throw if the event is not the expected type. This ensures that the event is guaranteed to have that type, and assumes that the event object has the expected payload (naturally enforced by TypeScript).

    // ...
    entry: ({ event }) => {
      assertEvent(event, 'greet');
      // event is { type: 'greet'; message: string }
    
      assertEvent(event, ['greet', 'notify']);
      // event is { type: 'greet'; message: string }
      // or { type: 'notify'; message: string; level: 'info' | 'error' }
    },
    exit: ({ event }) => {
      assertEvent(event, 'doNothing');
      // event is { type: 'doNothing' }
    }
Patch Changes
  • #​4586 97f1cbd5f Thanks @​Andarist! - Fixed an issue with ancestors of the default history target that lie outside of the transition domain being incorrectly entered.

v5.2.1

Compare Source

Patch Changes

v5.2.0

Compare Source

Minor Changes
  • #​4198 ca58904ad Thanks @​davidkpiano! - Introduce toPromise(actor), which creates a promise from an actor that resolves with the actor snapshot's output when done, or rejects with the actor snapshot's error when it fails.

    import { createMachine, createActor, toPromise } from 'xstate';
    
    const machine = createMachine({
      // ...
      states: {
        // ...
        done: { type: 'final', output: 42 }
      }
    });
    
    const actor = createActor(machine);
    
    actor.start();
    
    const output = await toPromise(actor);
    
    console.log(output);
    // => 42
Patch Changes
  • #​4568 a5c55fae2 Thanks @​Andarist! - Fixed an issue with spawn within assign not returning a narrowed down ActorRef type on TypeScrip 5.0

  • #​4570 c11127336 Thanks @​Andarist! - Fixed an issue that caused a complete listener to be called instead of the error one when the actor was subscribed after being stopped.

v5.1.0

Compare Source

Minor Changes
Patch Changes

v5.0.2

Compare Source

Patch Changes

v5.0.1

Compare Source

Patch Changes

v5.0.0

Compare Source

Major Changes
  • d3d6149: If context types are specified in the machine config, the context property will now be required:

    // ❌ TS error
    createMachine({
      types: {} as {
        context: { count: number };
      }
      // Missing context property
    });
    
    // ✅ OK
    createMachine({
      types: {} as {
        context: { count: number };
      },
      context: {
        count: 0
      }
    });
  • d3d6149: - The third argument of machine.transition(state, event) has been removed. The context should always be given as part of the state.

    • There is a new method: machine.microstep(snapshot, event) which returns the resulting intermediate MachineSnapshot object that represents a single microstep being taken when transitioning from snapshot via the event. This is the MachineSnapshot that does not take into account transient transitions nor raised events, and is useful for debugging.
    • The state.events property has been removed from the State object
    • The state.historyValue property now more closely represents the original SCXML algorithm, and is a mapping of state node IDs to their historic descendent state nodes. This is used for resolving history states, and should be considered internal.
    • The stateNode.isTransient property is removed from StateNode.
    • The .initial property of a state node config object can now contain executable content (i.e., actions):
    // ...
    initial: {
      target: 'someTarget',
      actions: [/* initial actions */]
    }
    • Assign actions (via assign()) will now be executed "in order", rather than automatically prioritized. They will be evaluated after previously defined actions are evaluated, and actions that read from context will have those intermediate values applied, rather than the final resolved value of all assign() actions taken, which was the previous behavior.

    This shouldn't change the behavior for most state machines. To maintain the previous behavior, ensure that assign() actions are defined before any other actions.

  • d3d6149: An error will be thrown if an initial state key is not specified for compound state nodes. For example:

    const lightMachine = createMachine({
      id: 'light',
      initial: 'green',
      states: {
        green: {},
        yellow: {},
        red: {
          // Forgotten initial state:
          // initial: 'walk',
          states: {
            walk: {},
            wait: {}
          }
        }
      }
    });

    You will get the error:

    No initial state specified for state node "#light.red". Try adding { initial: "walk" } to the state config.
    
  • d3d6149: IDs for delayed events are no longer derived from event types so this won't work automatically:

    entry: raise({ type: 'TIMER' }, { delay: 200 });
    exit: cancel('TIMER');

    Please use explicit IDs:

    entry: raise({ type: 'TIMER' }, { delay: 200, id: 'myTimer' });
    exit: cancel('myTimer');
  • d3d6149: Removed State#toStrings method.

  • d3d6149: The machine's context is now restricted to an Record<string, any>. This was the most common usage, but now the typings prevent context from being anything but an object:

    const machine = createMachine({
      // This will produce the TS error:
      // "Type 'string' is not assignable to type 'object | undefined'"
      context: 'some string'
    });

    If context is undefined, it will now default to an empty object {}.

  • d3d6149: Actors are now always part of a "system", which is a collection of actors that can communicate with each other. Systems are implicitly created, and can be used to get and set references to any actor in the system via the systemId prop:

    const machine = createMachine({
      // ...
      invoke: {
        src: emailMachine,
        // Registers `emailMachine` as `emailer` on the system
        systemId: 'emailer'
      }
    });
    const machine = createMachine({
      // ...
      entry: assign({
        emailer: (ctx, ev, { spawn }) =>
          spawn(emailMachine, { systemId: 'emailer' })
      })
    });

    Any invoked/spawned actor that is part of a system will be able to reference that actor:

    const anotherMachine = createMachine({
      // ...
      entry: sendTo(
        (ctx, ev, { system }) => {
          return system.get('emailer');
        },
        { type: 'SEND_EMAIL', subject: 'Hello', body: 'World' }
      )
    });

    Each top-level createActor(...) call creates a separate implicit system. In this example example, actor1 and actor2 are part of different systems and are unrelated:

    // Implicit system
    const actor1 = createActor(machine).start();
    
    // Another implicit system
    const actor2 = createActor(machine).start();
  • d3d6149: external property on transitions has been renamed to reenter

  • d3d6149: The interpreter.onStop(...) method has been removed. Use an observer instead via actorRef.subscribe({ complete() { ... } }) instead.

  • d3d6149: Removed MachineSnapshot['nextEvents'].

  • d3d6149: Renamed machine.withConfig(...) to machine.provide(...).

  • d3d6149: Removed third parameter (context) from Machine's transition method. If you want to transition with a particular context value you should create appropriate MachineSnapshot using machine.resolveState. So instead of this - machine.transition('green', { type: 'TIMER' }, { elapsed: 100 }), you should do this - machine.transition(machine.resolveState({ value: 'green', context: { elapsed: 100 } }), { type: 'TIMER' }).

  • d3d6149: Sending a string event to actorRef.send('some string') will now throw a proper error message.

  • d3d6149: The self actor reference is now available in all action metas. This makes it easier to reference the "self" ActorRef so that actions such as sendTo can include it in the event payload:

    // Sender
    actions: sendTo('somewhere', (ctx, ev, { self }) => ({
      type: 'EVENT',
      ref: self
    })),
    
    // ...
    
    // Responder
    actions: sendTo((ctx, ev) => ev.ref, ...)
  • d3d6149: isState/isStateConfig were replaced by isMachineSnapshot. Similarly, AnyState type was deprecated and it's replaced by AnyMachineSnapshot type.

  • d3d6149: All actor snapshots now have a consistent, predictable shape containing these common properties:

    • status: 'active' | 'done' | 'error' | 'stopped'
    • output: The output data of the actor when it has reached status: 'done'
    • error: The error thrown by the actor when it has reached status: 'error'
    • context: The context of the actor

    This makes it easier to work with actors in a consistent way, and to inspect their snapshots.

    const promiseActor = fromPromise(async () => {
      return 42;
    });
    
    // Previously number | undefined
    // Now a snapshot object with { status, output, error, context }
    const promiseActorSnapshot = promiseActor.getSnapshot();
    
    if (promiseActorSnapshot.status === 'done') {
      console.log(promiseActorSnapshot.output); // 42
    }
  • d3d6149: Restoring persisted state is now done by passing the state into the snapshot: ... property of the createActor options argument:

    -interpret(machine).start(state);
    +createActor(machine, { snapshot }).start();

    The persisted snapshot is obtained from an actor by calling actor.getPersistedSnapshot():

    const actor = createActor(machine).start();
    
    const persistedSnapshot = actor.getPersistedSnapshot();
    
    // ...
    
    const restoredActor = createActor(machine, {
      snapshot: persistedSnapshot
    }).start();
  • d3d6149: - The execute option for an interpreted service has been removed. If you don't want to execute actions, it's recommended that you don't hardcode implementation details into the base machine that will be interpreted, and extend the machine's options.actions instead. By default, the interpreter will execute all actions according to SCXML semantics (immediately upon transition).

    • Dev tools integration has been simplified, and Redux dev tools support is no longer the default. It can be included from xstate/devTools/redux:
    import { createActor } from 'xstate';
    import { createReduxDevTools } from 'xstate/devTools/redux';
    
    const service = createActor(someMachine, {
      devTools: createReduxDevTools({
        // Redux Dev Tools options
      })
    });

    By default, dev tools are attached to the global window.__xstate__ object:

    const service = createActor(someMachine, {
      devTools: true // attaches via window.__xstate__.register(service)
    });

    And creating your own custom dev tools adapter is a function that takes in the actorRef:

    const myCustomDevTools = (actorRef) => {
      console.log('Got a actorRef!');
    
      actorRef.subscribe((state) => {
        // ...
      });
    };
    
    const actorRef = createActor(someMachine, {
      devTools: myCustomDevTools
    });
    • These handlers have been removed, as they are redundant and can all be accomplished with .onTransition(...) and/or .subscribe(...):

      • actorRef.onEvent()
      • actorRef.onSend()
      • actorRef.onChange()
    • The actorRef.send(...) method no longer returns the next state. It is a void function (fire-and-forget).

    • The actorRef.sender(...) method has been removed as redundant. Use actorRef.send(...) instead.

  • d3d6149: The output data on final states is now specified as .output instead of .data:

    const machine = createMachine({
      // ...
      states: {
        // ...
        success: {
    -     data: { message: 'Success!' }
    +     output: { message: 'Success!' }
        }
      }
    })
  • d3d6149: Support for getters as a transition target (instead of referencing state nodes by ID or relative key) has been removed.

    The Machine() and createMachine() factory functions no longer support passing in context as a third argument.

    The context property in the machine configuration no longer accepts a function for determining context (which was introduced in 4.7). This might change as the API becomes finalized.

    The activities property was removed from State objects, as activities are now part of invoke declarations.

    The state nodes will not show the machine's version on them - the version property is only available on the root machine node.

  • d3d6149: The in: ... property for transitions is removed and replaced with guards. It is recommended to use stateIn() and not(stateIn()) guard creators instead:

    + import { stateIn } from 'xstate/guards';
    
    // ...
    on: {
      SOME_EVENT: {
        target: 'somewhere',
    -   in: '#someState'
    +   guard: stateIn('#someState')
      }
    }
    // ...
  • d3d6149: Removed Actor['status'] from publicly available properties.

  • d3d6149: All builtin action creators (assign, sendTo, etc) are now returning functions. They exact shape of those is considered an implementation detail of XState and users are meant to only pass around the returned values.

  • d3d6149: Autoforwarding events is no longer supported and the autoForward property has been removed.

    Instead of autoforwarding, events should be explicitly sent to actors:

    invoke: {
      id: 'child',
      src: 'someSrc',
    - autoForward: true
    },
    // ...
    on: {
      // ...
    + EVENT_TO_FORWARD: {
    +   actions: sendTo('child', (_, event) => event)
    + }
    }
  • d3d6149: The machine .schema property is now .types:

    const machine = createMachine({
      // schema: { ... }
      types: {} as {
        context: { ... };
        events: { ... };
        // ...
      }
    });

    And the .tsTypes property is now .types.typegen:

    const machine = createMachine({
      // tsTypes: { ... }
      types: {} as {
        typegen: {};
        context: { ... };
        events: { ... };
        // ...
      }
    });
  • d3d6149: Returning promises when creating a callback actor doesn't work anymore. Only cleanup functions can be returned now (or undefined).

  • d3d6149: There is now support for higher-level guards, which are guards that can compose other guards:

    • and([guard1, guard2, /* ... */]) returns true if all guards evaluate to truthy, otherwise false
    • or([guard1, guard2, /* ... */]) returns true if any guard evaluates to truthy, otherwise false
    • not(guard1) returns true if a single guard evaluates to false, otherwise true
    import { and, or, not } from 'xstate/guards';
    
    const someMachine = createMachine({
      // ...
      on: {
        EVENT: {
          target: 'somewhere',
          guard: and([
            'stringGuard',
            or([{ type: 'anotherGuard' }, not(() => false)])
          ])
        }
      }
    });
  • d3d6149: The .send(...) method on actorRef.send(...) now requires the first argument (the event to send) to be an object; that is, either:

    • an event object (e.g. { type: 'someEvent' })
    • an SCXML event object.

    The second argument (payload) is no longer supported, and should instead be included within the object:

    -actorRef.send('SOME_EVENT')
    +actorRef.send({ type: 'SOME_EVENT' })
    
    -actorRef.send('EVENT', { some: 'payload' })
    +actorRef.send({ type: 'EVENT', some: 'payload' })
  • d3d6149: Actions and guards that follow eventless transitions will now receive the event that triggered the transition instead of a "null" event ({ type: '' }), which no longer exists:

    // ...
    states: {
      a: {
        on: {
          SOME_EVENT: 'b'
        }
      },
      b: {
        always: 'c'
      },
      c: {
        entry: [({ event }) => {
          // event.type is now "SOME_EVENT", not ""
        }]
      }
    }
    // ...
  • d3d6149: You can now add a systemId to spawned actors to reference them anywhere in the system.

    const machine = createMachine({
      // ...
      context: ({ spawn }) => ({
        actorRef: spawn(
          createMachine({
            // ...
          }),
          { systemId: 'actorRef' }
        )
      })
    });
  • d3d6149: Reading the initial state from an actor via actorRef.initialState is removed. Use actorRef.getSnapshot() instead.

  • d3d6149: machine.initialState has been removed, you can use machine.getInitialState(...) instead

  • d3d6149: Target resolution improvements: targeting sibling nodes from the root is no longer valid, since the root node has no siblings:

    createMachine({
      id: 'direction',
      initial: 'left',
      states: {
        left: {},
        right: {}
      },
      on: {
    -   LEFT_CLICK: 'left',
    +   LEFT_CLICK: '.left'
      }
    });
  • d3d6149: The createActor(...) function now accepts input in the second argument, which passes input data in the "xstate.init" event:

    const greetMachine = createMachine({
      context: ({ input }) => ({
        greeting: `Hello ${input.name}!`
      }),
      entry: (_, event) => {
        event.type; // 'xstate.init'
        event.input; // { name: 'David' }
      }
      // ...
    });
    
    const actor = createActor(greetMachine, {
      // Pass input data to the machine
      input: { name: 'David' }
    }).start();
  • d3d6149: Invoked actors can now be deeply persisted and restored. When the persisted state of an actor is obtained via actorRef.getPersistedSnapshot(), the states of all invoked actors are also persisted, if possible. This state can be restored by passing the persisted state into the snapshot: ... property of the createActor options argument:

    -createActor(machine).start(state);
    +createActor(machine, { snapshot }).start();
  • d3d6149: Atomic and parallel states should no longer be reentered when the transition target doesn't escape them. You can get the reentering behavior by configuring reenter: true for the transition.

  • d3d6149: Restored state will no longer contain actions, since they are assumed to have already been executed. Actions will not be replayed.

    If you want to replay actions when restoring state, it is recommended to use an event sourcing approach.

  • d3d6149: The in: '...' transition property can now be replaced with stateIn(...) and stateNotIn(...) guards, imported from xstate/guards:

    import {
      createMachine,
    + stateIn
    } from 'xstate/guards';
    
    const machine = createMachine({
      // ...
      on: {
        SOME_EVENT: {
          target: 'anotherState',
    -     in: '#someState',
    +     cond: stateIn('#someState')
        }
      }
    })

    The stateIn(...) and stateNotIn(...) guards also can be used the same way as snapshot.matches(...):

    // ...
    SOME_EVENT: {
      target: 'anotherState',
      cond: stateNotIn({ red: 'stop' })
    }

    An error will now be thrown if the assign(...) action is executed when the context is undefined. Previously, there was only a warning.

    Error events raised by the machine will be thrown if there are no error listeners registered on an actor via actorRef.subscribe({ error: () => {} }).

  • d3d6149: Action/actor/delay/guard arguments are now consolidated into a single object argument. This is a breaking change for all of those things that are called with arguments.

    assign({
    - count: (context, event) => {
    + count: ({ context, event }) => {
        return context.count + event.value;
      }
    })
  • d3d6149: Eventless transitions must now be specified in the always: { ... } object and not in the on: { ... } object:

    someState: {
      on: {
        // Will no longer work
    -   '': { target: 'anotherState' }
      },
    + always: { target: 'anotherState' }
    }
  • d3d6149: Removed the ability to pass a string value directly to invoke. To migrate you should use the object version of invoke:

    -invoke: 'myActor'
    +invoke: { src: 'myActor' }
  • d3d6149: machine.transition(...) and machine.getInitialState(...) require now an actorScope argument

  • d3d6149: All events automatically generated by XState will now be prefixed by xstate.. Naming scheme changed slightly as well, for example done.invoke.* events became xstate.done.actor.* events.

  • d3d6149: The escalate() action is removed. Just throw an error normally.

  • d3d6149: The actor.onTransition(...) method has been removed in favor of .subscribe(...)

     const actor = interpret(machine)
    -  .onTransition(...)
    -  .start();
    +actor.subscribe(...);
    +actor.start();
  • d3d6149: Observing an actor via actorRef.subscribe(...) no longer immediately receives the current snapshot. Instead, the current snapshot can be read from actorRef.getSnapshot(), and observers will receive snapshots only when a transition in the actor occurs.

    const actorRef = createActor(machine);
    actorRef.start();
    
    // Late subscription; will not receive the current snapshot
    actorRef.subscribe((state) => {
      // Only called when the actor transitions
      console.log(state);
    });
    
    // Instead, current snapshot can be read at any time
    console.log(actorRef.getSnapshot());
  • d3d6149: Actors can no longer be stopped directly by calling actor.stop(). They can only be stopped from its parent internally (which might happen when you use stop action or automatically when a machine leaves the invoking state). The root actor can still be stopped since it has no parent.

  • d3d6149: The matchState(...) helper function is removed.

  • d3d6149: Parameterized actions now require a params property:

    // ...
    entry: [
      {
        type: 'greet',
    -   message: 'Hello'
    +   params: { message: 'Hello' }
      }
    ]
    // ...
  • d3d6149: The history resolution algorithm has been refactored to closely match the SCXML algorithm, which changes the shape of state.historyValue to map history state node IDs to their most recently resolved target state nodes.

  • d3d6149: Custom action objects and guard objects are now expected to put extra parameters on the params property:

    actions: {
      type: 'sendMessage',
    - message: 'hello'
    + params: {
    +   message: 'hello'
    + }
    }
    guard: {
      type: 'exists',
    - prop: 'user'
    + params: {
    +   prop: 'user'
    + }
    }
  • d3d6149: The strict: true option for machine config has been removed.

  • d3d6149: Removed the ability to define delayed transitions using an array. Only object variant is supported now:

    createMachine({
      initial: 'a',
      states: {
        a: {
          after: {
            10000: 'b',
            noon: 'c'
          }
        }
        // ...
      }
    });
  • d3d6149: Removed State['transitions'].

  • d3d6149: Removed the deprecated send action creator. Please use sendTo when sending events to other actors or raise when sending to itself.

  • d3d6149: The createEmptyActor() function has been added to make it easier to create actors that do nothing ("empty" actors). This is useful for testing, or for some integrations such as useActor(actor) in @xstate/react that require an actor:

    import { createEmptyActor } from 'xstate';
    
    const SomeComponent = (props) => {
      // props.actor may be undefined
      const [state, send] = useActor(props.actor ?? createEmptyActor());
    
      // ...
    };
  • d3d6149: machine.transition no longer accepts state values. You have to resolve the state value to a State before passing it to machine.transition

  • d3d6149: Removed deferEvents from the actor options.

  • d3d6149: The state.history property has been removed. This does not affect the machine "history" mechanism.

    Storing previous state should now be done explicitly:

    let previousSnapshot;
    
    const actorRef = createActor(someMachine);
    actorRef.subscribe((snapshot) => {
      // previousSnapshot represents the last snapshot here
    
      // ...
    
      // update the previous snapshot at the end
      previousSnapshot = snapshot;
    });
    actorRef.start();
  • d3d6149: All errors caught while executing the actor should now consistently include the error in its snapshot.error and should be reported to the closest error listener.

  • d3d6149: You can now import the following from xstate:

    import {
      // actions
      // sendTo (removed)
      pure,
    
      // interpret helpers
      waitFor,
    
      // actor functions
      fromPromise,
      fromObservable,
      fromCallback,
      fromEventObservable,
      fromTransition,
    
      // guard functions
      stateIn,
      not,
      and,
      or
    }

    The send action was removed from exports; use sendTo(...) or raise(...) instead.

  • d3d6149: BREAKING: The cond property in transition config objects has been renamed to guard. This unifies terminology for guarded transitions and guard predicates (previously called "cond", or "conditional", predicates):

    someState: {
      on: {
        EVENT: {
          target: 'anotherState',
    -     cond: 'isValid'
    +     guard: 'isValid'
        }
      }
    }
  • d3d6149: The Machine() function has been removed. Use the createMachine() function instead.

    -import { Machine } from 'xstate';
    +import { createMachine } from 'xstate';
    
    -const machine = Machine({
    +const machine = createMachine({
      // ...
    });
  • d3d6149: The interpreter.onError(...) method has been removed. Use interpreter.subscribe({ error(err) => { ... } }) instead.

  • d3d6149: Actions are no longer called with state

  • d3d6149: spawn is no longer importable from xstate. Instead you get it in assign like this:

    assign((ctx, ev, { spawn }) => {
      return {
        ...ctx,
        actorRef: spawn(promiseActor)
      };
    });

    In addition to that, you can now spawn actors defined in your implementations object, in the same way that you were already able to do that with invoke. To do that just reference the defined actor like this:

    spawn('promiseActor');
  • d3d6149: State class has been removed and replaced by MachineSnapshot object. They largely have the same properties and methods. On of the main noticeable results of this change is that you can no longer check state instanceof State.

  • d3d6149: Guard arguments are now consolidated into a single object argument. This is a breaking change for all guards that are called with arguments.

    - guard: (context, event) => {
    + guard: ({ context, event }) => {
      return context.count + event.value > 10;
    }
  • d3d6149: The service.batch(events) method is no longer available.

  • d3d6149: The StateSchema type has been removed from all generic type signatures.

  • d3d6149: Removed State['_internalQueue'].

  • d3d6149: EmittedFrom type helper has been renamed to SnapshotFrom.

  • d3d6149: The fromReducer(...) function is now called fromTransition(...).

  • d3d6149: The pure() and choose() action creators have been removed, in favor of the more flexible enqueueActions() action creator:

    entry: [
      // pure(() => {
      //   return [
      //     'action1',
      //     'action2'
      //   ]
      // }),
      enqueueActions(({ enqueue }) => {
        enqueue('action1');
        enqueue('action2');
      })
    ];
    entry: [
      // choose([
      //   {
      //     guard: 'someGuard',
      //     actions: ['action1', 'action2']
      //   }
      // ]),
      enqueueActions(({ enqueue, check }) => {
        if (check('someGuard')) {
          enqueue('action1');
          enqueue('action2');
        }
      })
    ];
  • d3d6149: Changed behavior of always transitions. Previously they were always selected after selecting any transition (including the always transitions). Because of that it was relatively easy to create an infinite loop using them.

    Now they are no longer selected if the preceeding transition doesn't change the state of a machine.

  • d3d6149: Breaking: The state.children property is now a mapping of invoked actor IDs to their ActorRef instances.

    Breaking: The way that you interface with invoked/spawned actors is now through ActorRef instances. An ActorRef is an opaque reference to an Actor, which should be never referenced directly.

    Breaking: The origin of an SCXML.Event is no longer a string, but an ActorRef instance.

  • d3d6149: The services option passed as the second argument to createMachine(config, options) is renamed to actors. Each value in actors should be a function that takes in context and event and returns a [behavior](TODO: link) for an actor. The provided behavior creators are:

    • fromMachine
    • fromPromise
    • fromCallback
    • fromObservable
    • fromEventObservable
    import { createMachine } from 'xstate';
    +import { fromPromise } from 'xstate/actors';
    
    const machine = createMachine(
      {
        // ...
        invoke: {
          src: 'fetchFromAPI'
        }
      },
      {
    -   services: {
    +   actors: {
    -     fetchFromAPI: (context, event) => {
    +     fetchFromAPI: (context, event) => fromPromise(() => {
            // ... (return a promise)
          })
        }
      }
    );
  • d3d6149: The error event (type: 'xstate.error.*') now has the error data on the event.error instead of event.data:

    // ...
    invoke: {
      src: 'someSrc',
      onError: {
        actions: ({ event }) => {
    -     event.data;
    +     event.error;
        }
      }
    }
  • d3d6149: _event has been removed from all APIs and types. It was a wrapper structure containing the event that users were using directly.

  • d3d6149: Actor types can now be specified in the .types property of createMachine:

    const fetcher = fromPromise(() => fetchUser());
    
    const machine = createMachine({
      types: {} as {
        actors: {
          src: 'fetchData'; // src name (inline behaviors ideally inferred)
          id: 'fetch1' | 'fetch2'; // possible ids (optional)
          logic: typeof fetcher;
        };
      },
      invoke: {
        src: 'fetchData', // strongly typed
        id: 'fetch2', // strongly typed
        onDone: {
          actions: ({ event }) => {
            event.output; // strongly typed as { result: string }
          }
        },
        input: { foo: 'hello' } // strongly typed
      }
    });
  • d3d6149: Interpreter['off'] method has been removed.

  • d3d6149: .nextState method has been removed from the Interpreter. State#can can be used to check if sending a particular event would lead to a state change.

  • d3d6149: Support for compound string state values has been dropped from Machine's transition method. It's no longer allowed to call transition like this - machine.transition('a.b', { type: 'NEXT' }), instead it's required to use "state value" representation like this - machine.transition({ a: 'b' }, { type: 'NEXT' }).

  • d3d6149: - Breaking: activities removed (can be invoked)

    Since activities can be considered invoked services, they can be implemented as such. Activities are services that do not send any events back to the parent machine, nor do they receive any events, other than a "stop" signal when the parent changes to a state where the activity is no longer active. This is modeled the same way as a callback service is modeled.

  • d3d6149: Removed previously deprecated config properties: onEntry, onExit, parallel and forward.

  • d3d6149: The state._sessionid property has been removed. It should be obtained directly from the actor: actor.sessionId.

  • d3d6149: The system can now be accessed in all available actor logic creator functions:

    fromPromise(({ system }) => { ... });
    
    fromTransition((state, event, { system }) => { ... });
    
    fromObservable(({ system }) => { ... });
    
    fromEventObservable(({ system }) => { ... });
    
    fromCallback((sendBack, receive, { system }) => { ... });
  • d3d6149: Typings for Typestate have been removed. The reason for this is that types for typestates needed to be manually specified, which is unsound because it is possible to specify impossible typestates; i.e., typings for a state's value and context that are impossible to achieve.

  • d3d6149: The actor.onDone(...) method is removed. Use actor.subscribe({ complete() {... } }) instead.

    - actor.onDone(() => { ... })
    + actor.subscribe({
    +  complete() {
    +    // ...
    +  }
    +})
  • d3d6149: The createModel() function has been removed in favor of relying on strong types in the machine configuration.

  • d3d6149: sync option has been removed from invoke and spawn.

  • d3d6149: Removed State['event'].

  • d3d6149: The final output of a state machine is now specified directly in the output property of the machine config:

    const machine = createMachine({
      initial: 'started',
      states: {
        started: {
          // ...
        },
        finished: {
          type: 'final'
          // moved to the top level
          //
          // output: {
          //   status: 200
          // }
        }
      },
      // This will be the final output of the machine
      // present on `snapshot.output` and in the done events received by the parent
      // when the machine reaches the top-level final state

Configuration

📅 Schedule: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR has been generated by Mend Renovate. View repository job log here.

Copy link

changeset-bot bot commented Dec 4, 2023

⚠️ No Changeset found

Latest commit: 3afaf2c

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@renovate renovate bot force-pushed the renovate/major-xstate-monorepo branch from 31d7f0a to a62d4ea Compare December 4, 2023 17:23
Copy link

codecov bot commented Dec 4, 2023

Codecov Report

All modified and coverable lines are covered by tests ✅

Comparison is base (e034039) 85.09% compared to head (a62d4ea) 85.09%.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #240   +/-   ##
=======================================
  Coverage   85.09%   85.09%           
=======================================
  Files           8        8           
  Lines        1791     1791           
  Branches      285      285           
=======================================
  Hits         1524     1524           
  Misses        266      266           
  Partials        1        1           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@renovate renovate bot force-pushed the renovate/major-xstate-monorepo branch from a62d4ea to 3afaf2c Compare December 20, 2023 19:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

0 participants