@alwatr/fsm 6.2.0 → 9.1.1

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/src/type.ts ADDED
@@ -0,0 +1,137 @@
1
+ import type {SignalConfig} from '@alwatr/signal';
2
+
3
+ /**
4
+ * Represents the state of a state machine, including its current finite state value
5
+ * and its extended state (context).
6
+ *
7
+ * @template TState The union type of the finite state values.
8
+ * @template TContext The type of the context object (extended state).
9
+ */
10
+ export type MachineState<TState extends string, TContext extends JsonObject> = {
11
+ /** The current finite state value. */
12
+ readonly name: TState;
13
+ /** The context (extended state) of the machine, holding quantitative data. */
14
+ readonly context: TContext;
15
+ };
16
+
17
+ /**
18
+ * Represents an event that can be sent to the state machine.
19
+ * It must have a `type` property, which acts as a discriminator.
20
+ *
21
+ * @template TEventType The union type of event names.
22
+ */
23
+ export interface MachineEvent<TEventType extends string = string> {
24
+ /** The unique type of the event. */
25
+ readonly type: TEventType;
26
+ /** An event can carry an optional payload. */
27
+ [key: string]: unknown;
28
+ }
29
+
30
+ /**
31
+ * Defines an assigner (synchronous action) that updates the context during transitions.
32
+ * It must return a partial context object to merge.
33
+ *
34
+ * @template TContext The type of the machine's context.
35
+ * @template TEvent The type of the event that triggered this assigner.
36
+ * @returns A partial context object to be merged into the machine's context.
37
+ */
38
+ export type Assigner<TEvent extends MachineEvent, TContext extends JsonObject> = (
39
+ event: Readonly<TEvent>,
40
+ context: Readonly<TContext>,
41
+ // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
42
+ ) => Partial<TContext> | void;
43
+
44
+ /**
45
+ * Defines an effect (asynchronous side-effect action) executed on state entry/exit.
46
+ * It can interact with the outside world and can dispatch new events.
47
+ *
48
+ * @template TContext The type of the machine's context.
49
+ * @template TEvent The type of the event that triggered this effect.
50
+ * @returns void or a Promise<void>.
51
+ */
52
+ export type Effect<TEvent extends MachineEvent, TContext extends JsonObject> = (
53
+ event: Readonly<TEvent>,
54
+ context: Readonly<TContext>,
55
+ // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
56
+ ) => Awaitable<TEvent | void>;
57
+
58
+ /**
59
+ * Defines a conditional guard function for a transition.
60
+ * The transition is only taken if this function returns true.
61
+ *
62
+ * @template TContext The type of the machine's context.
63
+ * @template TEvent The type of the event.
64
+ * @returns `true` if the transition should be taken, `false` otherwise.
65
+ */
66
+ export type Condition<TEvent extends MachineEvent, TContext extends JsonObject> = (
67
+ event: Readonly<TEvent>,
68
+ context: Readonly<TContext>,
69
+ ) => boolean;
70
+
71
+ /**
72
+ * Defines a transition for a given state and event. It specifies the target state,
73
+ * actions, and an optional condition.
74
+ *
75
+ * @template TState The type of the state.
76
+ * @template TEvent The type of the event.
77
+ * @template TContext The type of the machine's context.
78
+ */
79
+ export interface Transition<TState extends string, TEvent extends MachineEvent, TContext extends JsonObject> {
80
+ /** The target state to transition to. If undefined, it's an internal transition. */
81
+ readonly target?: TState;
82
+ /** A condition function that must return true for the transition to occur. */
83
+ readonly condition?: Condition<TEvent, TContext>;
84
+ /** An array of assigners to execute. These update context synchronously. */
85
+ readonly assigners?: SingleOrArray<Assigner<TEvent, TContext>>;
86
+ }
87
+
88
+ /**
89
+ * Configuration options for persisting the FSM state in localStorage.
90
+ */
91
+ export interface FsmPersistenceConfig {
92
+ /**
93
+ * The version of the state's data structure (schema).
94
+ * Increment this number whenever you make a breaking change to the state's context shape.
95
+ */
96
+ schemaVersion: number;
97
+
98
+ /**
99
+ * The key under which to store the FSM state in localStorage.
100
+ * @default `signal-name`
101
+ */
102
+ storageKey?: string;
103
+ }
104
+
105
+ /**
106
+ * The declarative configuration object for creating a state machine.
107
+ * This object defines the entire behavior of the machine.
108
+ *
109
+ * @template TState The union type of all possible states.
110
+ * @template TEvent The union type of all possible events.
111
+ * @template TContext The type of the context object.
112
+ */
113
+ export interface StateMachineConfig<TState extends string, TEvent extends MachineEvent, TContext extends JsonObject>
114
+ extends Pick<SignalConfig, 'name'> {
115
+ /** The initial finite state value. */
116
+ readonly initial: TState;
117
+
118
+ /** The initial context (extended state) of the machine. */
119
+ readonly context: TContext;
120
+
121
+ /** If provided, the FSM's state will be persisted in localStorage. */
122
+ persistent?: FsmPersistenceConfig;
123
+
124
+ /** An object defining all possible states and their transitions. */
125
+ readonly states: {
126
+ readonly [S in TState]?: {
127
+ /** An object mapping event types to transitions for the current state. */
128
+ readonly on?: {
129
+ readonly [E in TEvent['type']]?: SingleOrArray<Transition<TState, Extract<TEvent, {type: E}>, TContext>>;
130
+ };
131
+ /** An array of side-effect effects to execute upon entering this state. */
132
+ readonly entry?: SingleOrArray<Effect<TEvent, TContext>>;
133
+ /** An array of side-effect effects to execute upon exiting this state. */
134
+ readonly exit?: SingleOrArray<Effect<TEvent, TContext>>;
135
+ };
136
+ };
137
+ }