@alwatr/fsm 4.1.1 → 6.0.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/CHANGELOG.md CHANGED
@@ -3,6 +3,115 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [6.0.0](https://github.com/Alwatr/flux/compare/v5.2.2...v6.0.0) (2025-09-19)
7
+
8
+ ### ⚠ BREAKING CHANGES
9
+
10
+ * Complete rewrite of @alwatr/fsm package
11
+
12
+ Summary:
13
+ - The package has been fully rewritten: public API, types, internal behavior and lifecycle semantics have changed.
14
+ - Consumers must update imports and usage. Existing code written for the old API will not work without changes.
15
+
16
+ Example:
17
+ ```ts
18
+ import {createFsmService} from '@alwatr/fsm';
19
+ const service = createFsmService({
20
+ name: 'light-switch',
21
+ initial: 'off',
22
+ context: {brightness: 0},
23
+ states: {
24
+ off: {
25
+ on: { TOGGLE: { target: 'on', actions: [() => ({brightness: 100})] } },
26
+ },
27
+ on: {
28
+ on: {
29
+ TOGGLE: { target: 'off', actions: [() => ({brightness: 0})] },
30
+ SET_BRIGHTNESS: { actions: [(e) => ({brightness: e.level})] },
31
+ },
32
+ },
33
+ },
34
+ });
35
+
36
+ const sub = service.stateSignal.subscribe((state) => {
37
+ console.log(\`Light is \${state.name} brightness=\${state.context.brightness}\`);
38
+ });
39
+
40
+ service.eventSignal.dispatch({type: 'TOGGLE'});
41
+ // When done:
42
+ sub.unsubscribe?.();
43
+ service.destroy();
44
+ ```
45
+
46
+ ### ✨ Features
47
+
48
+ * add factory function for creating StateMachine instances ([d5afa79](https://github.com/Alwatr/flux/commit/d5afa79f323f4a20b9d9917861774dba3c18ba91))
49
+ * add type definitions for state machine events, states, and transitions ([cd5d770](https://github.com/Alwatr/flux/commit/cd5d770d2c5ca0ab462e27d2ac6a119e6816d82e))
50
+ * implement FsmService for managing finite state machines with event and state signals ([4fbc72a](https://github.com/Alwatr/flux/commit/4fbc72addbc4dc29b3deb1bb5c07e3fa5ad6e2e1))
51
+ * implement StateMachine class with state management and transition logic ([eca4208](https://github.com/Alwatr/flux/commit/eca4208c82932b736f284c7f28df79820c24986a))
52
+ * rewrite new state machine interfaces and types ([31885e5](https://github.com/Alwatr/flux/commit/31885e59dd5542ecffad971704cc20ae26ccca90))
53
+
54
+ ### 🐛 Bug Fixes
55
+
56
+ * add documentation for eventSignal in FsmService class ([a11cb4a](https://github.com/Alwatr/flux/commit/a11cb4a8c005356832fab3a9924d4f75cc9cc8af))
57
+ * add logging to destroy method for better tracking of service cleanup ([6187d17](https://github.com/Alwatr/flux/commit/6187d17bb4765bae89b271f3dc6920cb69818fa6))
58
+ * allow void return type for Assigner function ([5e1ae6b](https://github.com/Alwatr/flux/commit/5e1ae6b4cd7e472f2928a7ad25c81d2b9d40e8b7))
59
+ * correct entry action execution to use target state context for improved accuracy ([cf16271](https://github.com/Alwatr/flux/commit/cf16271969f020fa502f1178459d44a9c8e74677))
60
+ * correct logger method names in processTransition and applyAssigners for consistency ([f33d553](https://github.com/Alwatr/flux/commit/f33d5533f9b296483f807779e3cb522d4313a876))
61
+ * correct stateSignal naming and improve documentation in FsmService class ([7d5b7fe](https://github.com/Alwatr/flux/commit/7d5b7feef54fbbd76fead7a2fa1a964d77ec0401))
62
+ * enhance applyAssigners logic for atomic updates and improved error handling ([988e00c](https://github.com/Alwatr/flux/commit/988e00cfe4be5974966d52235d2bf3a8f08e1d59))
63
+ * enhance applyAssigners logic to improve context updates and error handling ([73384c0](https://github.com/Alwatr/flux/commit/73384c04479c7398cea0504c0ea8a14b57b7a366))
64
+ * enhance executeEffects logic to improve error handling and logging ([8fe6bed](https://github.com/Alwatr/flux/commit/8fe6beda209ee75ab81bf2249fe1d0b25185a1cd))
65
+ * enhance FSM transition handling and logging for improved clarity and performance ([8695d99](https://github.com/Alwatr/flux/commit/8695d99910b5a1e0abc8603a5ea947d6f77d463b))
66
+ * enhance transition condition logging for better debugging and clarity ([e7cd799](https://github.com/Alwatr/flux/commit/e7cd79964ecfab3c8e9a9ff1d0b74eb4d2f09cbf))
67
+ * ensure proper cleanup of stateSignal in destroy method ([d90a0cf](https://github.com/Alwatr/flux/commit/d90a0cf3ae871f0db1832bdc92a61cb7b0567a65))
68
+ * ensure proper destruction of state signals in destroy method ([512221b](https://github.com/Alwatr/flux/commit/512221bc7a62b77392eb368b97e323bfd95a02fb))
69
+ * execute exit/entry effects only when state changes in FSM ([99a1d66](https://github.com/Alwatr/flux/commit/99a1d6653be5350867d7050cf59d18dd43966cb0))
70
+ * executeEffects__ context ([f1fde9b](https://github.com/Alwatr/flux/commit/f1fde9baccebd27ca76ae785643d60cd463aff97))
71
+ * fsm-service.ts run cond ([5c91967](https://github.com/Alwatr/flux/commit/5c91967b605e5529a8d3e9deb630808966d4f3aa))
72
+ * fsm-service.ts type ([239ea9b](https://github.com/Alwatr/flux/commit/239ea9b77b2cc3c41d14df426315381ce65f156d))
73
+ * improve context handling in applyAssigners__ method ([d3ac560](https://github.com/Alwatr/flux/commit/d3ac56007e18d744fea289d21f5f3518d8726794))
74
+ * improve processTransition logic and enhance logging in FsmService class ([434e6e1](https://github.com/Alwatr/flux/commit/434e6e10b9ee764830898d9c762afba2c893b9d9))
75
+ * move powerLostWarning action to flashingRed state entry ([441223d](https://github.com/Alwatr/flux/commit/441223d30d571b5fd244d7f50a1428c74fef39f0))
76
+ * refactor findTransition logic to improve condition evaluation and logging ([0a32c8d](https://github.com/Alwatr/flux/commit/0a32c8de6974f587404de6d39b8dd10ca20f0d0f))
77
+ * remove space in logger initialization for FsmService class ([d91065a](https://github.com/Alwatr/flux/commit/d91065aa08339f9a3075304e9b061672118f9525))
78
+ * rename transition.actions to transition.assigners for clarity ([1198b59](https://github.com/Alwatr/flux/commit/1198b597c5b326a4a8deb84c1503648a62d28a1c))
79
+ * reorder assigners property documentation for improved clarity ([019a9f0](https://github.com/Alwatr/flux/commit/019a9f0c56876f82e2dcb9c02aaa01ab8a6b2234))
80
+ * replace computed state signal with read-only state signal for improved performance ([76fac47](https://github.com/Alwatr/flux/commit/76fac47612a1e5566dcfd246b16823f93078c908))
81
+ * simplify assigner function in light machine config ([a479b5d](https://github.com/Alwatr/flux/commit/a479b5d6fb511409a1b66734b262fc5371d83d79))
82
+ * standardize light state logging messages for clarity ([a1a464a](https://github.com/Alwatr/flux/commit/a1a464a1588459de1a4e26c6bd933a00fb031b75))
83
+ * update Assigner and Effect types to support SingleOrArray for improved flexibility ([8e6e7ad](https://github.com/Alwatr/flux/commit/8e6e7ad10bfde1170904f3b2820810230af80241))
84
+ * update Assigner type definition to allow void return and change Transition type to array ([f43c993](https://github.com/Alwatr/flux/commit/f43c99369c993c5e252bdb6e47b177d46e86e18f))
85
+ * update entry actions to assigners for consistency in light machine configuration ([66f76c7](https://github.com/Alwatr/flux/commit/66f76c7627af9b096db4a2c4ab16fcbb79b81321))
86
+ * update package description for clarity and accuracy ([86c29fb](https://github.com/Alwatr/flux/commit/86c29fb38eeed2fe71f9b04f28a00231a1074d1f))
87
+ * update type definitions for MachineState, Assigner, Effect, and Transition interfaces ([79760f4](https://github.com/Alwatr/flux/commit/79760f4bf4df48685cb60af5fd20c9496130161c))
88
+
89
+ ### 🔨 Code Refactoring
90
+
91
+ * enhance action and guard types for state transitions ([1fdfa1b](https://github.com/Alwatr/flux/commit/1fdfa1bb3e847b9e4d1051320a23701d29d243ca))
92
+ * migrate light switch implementation to JavaScript and enhance logging ([2f81bc0](https://github.com/Alwatr/flux/commit/2f81bc03b7ceda739e2204021ce40e0389f52e2a))
93
+ * migrate to createFsmService and enhance state management logging ([5209c4b](https://github.com/Alwatr/flux/commit/5209c4b0dfb6e5737c386a344f7bdbbca3c4c2dd))
94
+ * remove obsolete files and clean up state machine implementation ([921cb24](https://github.com/Alwatr/flux/commit/921cb24f363a635ad8e91523e49500780ffcbb9a))
95
+ * remove unused import and clean up exports in fsm module ([a6c6374](https://github.com/Alwatr/flux/commit/a6c63742ee5d3f7fc8042b51f0889978e0e709e6))
96
+ * replace signalId with name in StateMachine signal creation ([0ce2654](https://github.com/Alwatr/flux/commit/0ce2654b10b7c6dd6f519a62428cdfcac8fa3189))
97
+ * restructure state machine types for improved clarity and functionality ([7b21778](https://github.com/Alwatr/flux/commit/7b21778db22a3fcf5a855790708ee7576d257682))
98
+ * standardize signal naming and visibility in FsmService ([ddfae0f](https://github.com/Alwatr/flux/commit/ddfae0f62fa5355054cf43ca88a0e00f65dc0bb4))
99
+ * update createStateMachine to createFsmService with improved documentation and example ([cc73194](https://github.com/Alwatr/flux/commit/cc73194ec01ab570054e2dba877d8b6c2cd336c2))
100
+ * update exports in main.ts to include facade, state-machine, and types ([0796b4f](https://github.com/Alwatr/flux/commit/0796b4fd3281e42614eec8a79389e242592df5a4))
101
+ * update exports in main.ts to include fsm-service and type-old ([ddcf0be](https://github.com/Alwatr/flux/commit/ddcf0bef31958a93f0433f587184b88e75f2819f))
102
+ * update log message for new event from enter effect in processTransition method ([314e516](https://github.com/Alwatr/flux/commit/314e516745ffaaae0495fe96aea6bcd06d7e49d9))
103
+ * update type definitions and improve state machine configuration ([5d749ca](https://github.com/Alwatr/flux/commit/5d749ca5a4cec6065e91e87f203e0ea05392f6fb))
104
+
105
+ ### 🧹 Miscellaneous Chores
106
+
107
+ * rollback old fsm ([b2e7f32](https://github.com/Alwatr/flux/commit/b2e7f323841443e30772874eeab52481025a4b1e))
108
+
109
+ ### 🔗 Dependencies update
110
+
111
+ * update @alwatr/logger to version 6.0.2 and @types/node to version 22.18.6; upgrade esbuild and other dependencies ([95dfaba](https://github.com/Alwatr/flux/commit/95dfabab2a4d4ea2b0e42a70bee1f3e68a67bffc))
112
+ * update dependencies for logger, nano-build, type-helper, and node types ([23fe723](https://github.com/Alwatr/flux/commit/23fe7236ffa0bfd2551a6dfc52c23689ce4b036e))
113
+ * update package dependencies for improved compatibility and performance ([1e91063](https://github.com/Alwatr/flux/commit/1e9106343d01330089c33d9591969a66625a1e7b))
114
+
6
115
  ## [4.1.1](https://github.com/Alwatr/flux/compare/v4.1.0...v4.1.1) (2025-09-08)
7
116
 
8
117
  ### 🔗 Dependencies update
package/README.md CHANGED
@@ -1,96 +1,307 @@
1
- # Flux: Finite State Machine
1
+ # Alwatr FSM
2
2
 
3
- A robust TypeScript library for implementing Flux (Finite) State Machines, enabling clear and organized management of application state and transitions.
3
+ [](https://www.google.com/search?q=https://www.npmjs.com/package/%40alwatr/fsm)
4
+ [](https://www.google.com/search?q=https://bundlephobia.com/package/%40alwatr/fsm)
4
5
 
5
- ## Features
6
+ A tiny, type-safe, declarative, and reactive finite state machine (FSM) library for modern TypeScript applications, built on top of [Alwatr Signals](https://www.google.com/search?q=https://github.com/Alwatr/alwatr/tree/main/packages/signal).
6
7
 
7
- * **Clear State Management:** Model your application's behavior with well-defined states and transitions.
8
- * **TypeScript Support:** Written in TypeScript with full type definitions for improved code quality and developer experience.
9
- * **Flexible Actions:** Attach custom actions to state transitions and events.
10
- * **Observable Integration:** Built-in integration with `@alwatr/observable` for reactive state updates.
11
- * **Built-in Logging:** Integrated logging for debugging and monitoring state machine behavior.
8
+ یک کتابخانه کوچک، تایپ-سیف، اعلانی و واکنش‌گرا (reactive) برای مدیریت وضعیت به روش ماشین حالت متناهی (FSM) در اپلیکیشن‌های مدرن TypeScript که بر پایه [Alwatr Signals](https://www.google.com/search?q=https://github.com/Alwatr/alwatr/tree/main/packages/signal) ساخته شده است.
9
+
10
+ [](https://www.google.com/search?q=https://www.npmjs.com/package/%40alwatr/fsm)
11
+ [](https://www.google.com/search?q=https://www.npmjs.com/package/%40alwatr/flux)
12
+ [](https://www.google.com/search?q=alwatr+fsm)
13
+ [](https://www.google.com/search?q=alwatr+flux)
14
+ [](https://www.google.com/search?q=alwatr)
15
+
16
+ ## Philosophy
17
+
18
+ Managing state in complex applications can be challenging. As features grow, state transitions can become unpredictable, leading to bugs and difficult-to-maintain code. Finite State Machines provide a powerful model to solve this problem by formalizing application logic.
19
+
20
+ An FSM describes a system that can be in **exactly one** of a finite number of **states** at any given time. It transitions from one state to another in response to **events**, following predefined rules. This approach makes state changes predictable, visualizable, and robust.
21
+
22
+ This library is designed to be:
23
+
24
+ - **Declarative**: Define your entire machine logic in a single, easy-to-read configuration object.
25
+ - **Type-Safe**: Leverage TypeScript to catch errors at compile time, not runtime.
26
+ - **Reactive**: Built around signals for seamless integration with modern UI frameworks and reactive codebases.
27
+ - **Resilient**: Guarantees Run-to-Completion (RTC) and handles errors in user-defined functions gracefully without crashing.
28
+
29
+ ---
30
+
31
+ ## مفاهیم و فلسفه
32
+
33
+ مدیریت وضعیت در اپلیکیشن‌های پیچیده یک چالش است. با رشد برنامه، جریان تغییر وضعیت‌ها می‌تواند غیرقابل‌پیش‌بینی شده و منجر به باگ‌ها و کدهای غیرقابل نگهداری شود. ماشین‌های حالت متناهی (FSM) یک مدل قدرتمند برای حل این مشکل از طریق ساختارمند کردن منطق برنامه ارائه می‌دهند.
34
+
35
+ یک FSM سیستمی را توصیف می‌کند که در هر لحظه **دقیقا در یکی** از تعداد محدودی **وضعیت (state)** قرار دارد. این سیستم در پاسخ به **رویدادها (events)** و بر اساس قوانین از پیش تعریف‌شده، از یک وضعیت به وضعیت دیگر **گذار (transition)** می‌کند. این رویکرد، تغییرات وضعیت را قابل‌پیش‌بینی، قابل ترسیم و مستحکم می‌سازد.
36
+
37
+ این کتابخانه با اهداف زیر طراحی شده است:
38
+
39
+ - **اعلانی (Declarative)**: تمام منطق ماشین خود را در یک آبجکت پیکربندی واحد و خوانا تعریف کنید.
40
+ - **تایپ-سیف (Type-Safe)**: با بهره‌گیری از قدرت TypeScript، خطاها را در زمان کامپایل پیدا کنید، نه در زمان اجرا.
41
+ - **واکنش‌گرا (Reactive)**: مبتنی بر سیگنال‌ها برای یکپارچه‌سازی آسان با فریم‌ورک‌های مدرن و کدهای واکنش‌گرا.
42
+ - **مستحکم و تاب‌آور (Resilient)**: مدل اجرای کامل تا انتها (RTC) را تضمین کرده و خطاهای توابع تعریف‌شده توسط کاربر را بدون متوقف کردن سیستم مدیریت می‌کند.
12
43
 
13
44
  ## Installation
14
45
 
15
46
  ```bash
16
- npm install @alwatr/fsm
47
+ npm i @alwatr/fsm
48
+ ```
49
+
50
+ ## Core Concepts / مفاهیم کلیدی
51
+
52
+ | Term | Description |
53
+ | :------------- | :------------------------------------------------------------------------------------------------------------------ |
54
+ | **State** | The current finite state of the machine (e.g., `'idle'`, `'loading'`). |
55
+ | **Context** | An object holding the "extended state"—any quantitative or non-finite data (e.g., `{retries: 2, data: null}`). |
56
+ | **Event** | An object that triggers a potential state transition (e.g., `{type: 'FETCH', id: '123'}`). |
57
+ | **Transition** | A rule defining the path from a source state to a target state for a given event. It can be guarded by a condition. |
58
+ | **Assigner** | A **pure function** that synchronously updates the `context` during a transition. |
59
+ | **Effect** | A function for **side effects** (e.g., API calls, logging) that runs upon entering or exiting a state. |
60
+ | **Condition** | A **predicate function** that must return `true` for its associated transition to be taken. |
61
+
62
+ | اصطلاح | توضیحات |
63
+ | :------------------------- | :----------------------------------------------------------------------------------------------------------------------------- |
64
+ | **وضعیت (State)** | وضعیت متناهی فعلی ماشین (مثلاً `'idle'`, `'loading'`). |
65
+ | **زمینه (Context)** | یک آبجکت برای نگهداری "وضعیت گسترده"—هرگونه داده کمی یا نامتناهی (مثلاً `{retries: 2, data: null}`). |
66
+ | **رویداد (Event)** | آبجکتی که یک گذار وضعیت بالقوه را آغاز می‌کند (مثلاً `{type: 'FETCH', id: '123'}`). |
67
+ | **گذار (Transition)** | قانونی که مسیر از یک وضعیت مبدأ به یک وضعیت مقصد را برای یک رویداد خاص تعریف می‌کند. این گذار می‌تواند توسط یک شرط محافظت شود. |
68
+ | **تخصیص‌دهنده (Assigner)** | یک **تابع خالص** که به صورت همزمان (synchronously) `context` را در طول یک گذار به‌روزرسانی می‌کند. |
69
+ | **اثر جانبی (Effect)** | تابعی برای **عملیات‌های جانبی** (مانند فراخوانی API یا لاگ کردن) که هنگام ورود یا خروج از یک وضعیت اجرا می‌شود. |
70
+ | **شرط (Condition)** | یک **تابع گزاره‌ای** که باید `true` برگرداند تا گذار مرتبط با آن انجام شود. |
71
+
72
+ ## Example 1: A Simple Light Switch
73
+
74
+ Let's model a simple light switch that can be turned on and off.
75
+
76
+ ### ۱. تعریف انواع
77
+
78
+ First, define the types for the states, events, and context.
79
+ ابتدا انواع مربوط به وضعیت‌ها، رویدادها و زمینه را تعریف می‌کنیم.
80
+
81
+ ```ts
82
+ import type {StateMachineConfig} from '@alwatr/fsm';
83
+
84
+ // The context stores the brightness level.
85
+ type LightContext = {brightness: number};
86
+
87
+ // The machine can only be in one of these two states.
88
+ type LightState = 'on' | 'off';
89
+
90
+ // Define the events that can be sent to the machine.
91
+ type LightEvent = {type: 'TOGGLE'} | {type: 'SET_BRIGHTNESS'; level: number};
17
92
  ```
18
93
 
19
- ## Usage
94
+ ### ۲. پیکربندی ماشین
20
95
 
21
- ```typescript
22
- import {FluxStateMachineBase} from '@alwatr/fsm';
96
+ Define the entire machine logic in a configuration object.
97
+ کل منطق ماشین را در یک آبجکت پیکربندی تعریف می‌کنیم.
23
98
 
24
- // Define your states and events
25
- type MyState = 'idle' | 'loading' | 'success' | 'error';
26
- type MyEvent = 'fetch' | 'success' | 'error';
99
+ ```ts
100
+ const lightMachineConfig: StateMachineConfig<LightState, LightEvent, LightContext> = {
101
+ name: 'light-switch',
102
+ initial: 'off',
103
+ context: {brightness: 0},
104
+ states: {
105
+ off: {
106
+ on: {
107
+ // When in the 'off' state and a 'TOGGLE' event occurs...
108
+ TOGGLE: {
109
+ target: 'on', // ...transition to the 'on' state.
110
+ assigners: [() => ({brightness: 100})], // ...and set brightness to 100.
111
+ },
112
+ },
113
+ },
114
+ on: {
115
+ on: {
116
+ // When in the 'on' state and a 'TOGGLE' event occurs...
117
+ TOGGLE: {
118
+ target: 'off', // ...transition to 'off'.
119
+ assigners: [() => ({brightness: 0})], // ...and reset brightness.
120
+ },
121
+ // An internal transition that only updates context without changing the state.
122
+ SET_BRIGHTNESS: {
123
+ // No 'target' means it's an internal transition.
124
+ assigners: [(event) => ({brightness: event.level})],
125
+ },
126
+ },
127
+ },
128
+ },
129
+ };
130
+ ```
131
+
132
+ ### ۳. ساخت و استفاده از سرویس
133
+
134
+ Create the service and interact with it using signals.
135
+ سرویس را ایجاد کرده و با استفاده از سیگنال‌ها با آن تعامل می‌کنیم.
136
+
137
+ ```ts
138
+ import {createFsmService} from '@alwatr/fsm';
139
+
140
+ // Create the FSM service instance.
141
+ const lightService = createFsmService(lightMachineConfig);
142
+
143
+ // Subscribe to state changes.
144
+ lightService.stateSignal.subscribe((state) => {
145
+ console.log(`Light is ${state.name} with brightness ${state.context.brightness}`);
146
+ });
147
+
148
+ // Dispatch events to trigger transitions.
149
+ lightService.eventSignal.dispatch({type: 'TOGGLE'});
150
+ // Logs: Light is on with brightness 100
151
+
152
+ lightService.eventSignal.dispatch({type: 'SET_BRIGHTNESS', level: 50});
153
+ // Logs: Light is on with brightness 50
154
+
155
+ lightService.eventSignal.dispatch({type: 'TOGGLE'});
156
+ // Logs: Light is off with brightness 0
157
+ ```
27
158
 
28
- class MyStateMachine extends FluxStateMachineBase<MyState, MyEvent> {
29
- constructor() {
30
- super({
31
- name: 'my-state-machine',
32
- initialState: 'idle',
33
- });
159
+ ## Example 2: Async Data Fetching
34
160
 
35
- // Define state transitions
36
- this.stateRecord_ = {
37
- idle: {
38
- fetch: 'loading',
161
+ A more advanced example showing side effects (`effects`) and conditional transitions (`condition`).
162
+
163
+ ```ts
164
+ import {createFsmService} from '@alwatr/fsm';
165
+ import type {StateMachineConfig} from '@alwatr/fsm';
166
+
167
+ // Types
168
+ type User = {id: string; name: string};
169
+ type FetchContext = {user: User | null; error: string | null};
170
+ type FetchState = 'idle' | 'pending' | 'success' | 'error';
171
+ type FetchEvent = {type: 'FETCH'; id: string} | {type: 'RESOLVE'; user: User} | {type: 'REJECT'; error: string} | {type: 'RETRY'};
172
+
173
+ // FSM Configuration
174
+ const fetchMachineConfig: StateMachineConfig<FetchState, FetchEvent, FetchContext> = {
175
+ name: 'fetch-user',
176
+ initial: 'idle',
177
+ context: {
178
+ user: null,
179
+ error: null,
180
+ },
181
+ states: {
182
+ idle: {
183
+ on: {
184
+ FETCH: {target: 'pending'},
39
185
  },
40
- loading: {
41
- success: 'success',
42
- error: 'error',
186
+ },
187
+ pending: {
188
+ // On entering 'pending' state, execute the fetchUser effect.
189
+ entry: [
190
+ async (event, context) => {
191
+ if (event.type !== 'FETCH') return; // Type guard
192
+ try {
193
+ console.log(`Fetching user with id: ${event.id}...`);
194
+ const response = await fetch(`https://api.example.com/users/${event.id}`);
195
+ if (!response.ok) throw new Error('User not found');
196
+ const user = (await response.json()) as User;
197
+ // An effect can return a new event to be dispatched back to the machine.
198
+ return {type: 'RESOLVE', user};
199
+ } catch (err) {
200
+ // If an error occurs, dispatch a 'REJECT' event.
201
+ return {type: 'REJECT', error: (err as Error).message};
202
+ }
203
+ },
204
+ ],
205
+ on: {
206
+ RESOLVE: {
207
+ target: 'success',
208
+ assigners: [(event) => ({user: event.user})],
209
+ },
210
+ REJECT: {
211
+ target: 'error',
212
+ assigners: [(event) => ({error: event.error})],
213
+ },
43
214
  },
44
- success: {}, // Terminal state
45
- error: {}, // Terminal state
46
- };
47
-
48
- // Define actions (optional)
49
- this.actionRecord_ = {
50
- 'on_fetch': this.handleFetch,
51
- 'on_success': this.handleSuccess,
52
- 'on_error': this.handleError,
53
- };
54
- }
55
-
56
- // ... (Implement your action methods: handleFetch, handleSuccess, handleError)
57
-
58
- // Trigger a state transition
59
- fetchData() {
60
- this.transition_('fetch');
61
- }
62
- }
215
+ },
216
+ success: {
217
+ on: {
218
+ FETCH: {target: 'pending'}, // Allow re-fetching
219
+ },
220
+ },
221
+ error: {
222
+ on: {
223
+ RETRY: {
224
+ target: 'pending',
225
+ // A condition that must be met for the transition to occur.
226
+ condition: (event, context) => {
227
+ // This is just an example; you might have retry logic in the context.
228
+ console.log('Checking retry condition...');
229
+ return true;
230
+ },
231
+ },
232
+ },
233
+ },
234
+ },
235
+ };
236
+
237
+ // --- Usage ---
238
+ const fetchService = createFsmService(fetchMachineConfig);
239
+
240
+ fetchService.stateSignal.subscribe((state) => {
241
+ console.log('Current State:', state.name);
242
+ if (state.name === 'success') console.log('User:', state.context.user);
243
+ if (state.name === 'error') console.log('Error:', state.context.error);
244
+ });
245
+
246
+ fetchService.eventSignal.dispatch({type: 'FETCH', id: '1'});
63
247
  ```
64
248
 
65
- ## API
249
+ ## Architectural Advantages / مزیت‌های معماری
250
+
251
+ - **Predictable & Visualizable**: By constraining how and when state can change, your application logic becomes deterministic and easy to reason about. The declarative nature of the config allows for easy visualization of all possible states and transitions.
252
+ <br>
253
+ **قابل پیش‌بینی و ترسیم**: با محدود کردن زمان و چگونگی تغییر وضعیت، منطق برنامه شما قطعی و قابل درک می‌شود. ماهیت اعلانی پیکربندی، امکان ترسیم و مشاهده تمام وضعیت‌ها و گذارهای ممکن را فراهم می‌کند.
66
254
 
67
- ### `FluxStateMachineBase<S extends string, E extends string>`
255
+ - **Type-Safe by Design**: The library is built from the ground up with TypeScript. It ensures that event payloads are correctly typed for each transition and that assigners update the context with valid data, preventing a wide class of bugs at compile time.
256
+ <br>
257
+ **ذاتاً تایپ-سیف**: این کتابخانه از پایه با TypeScript ساخته شده است. این امر تضمین می‌کند که پارامترهای رویدادها در هر گذار به درستی تایپ‌دهی شده و `assigner`ها زمینه (`context`) را با داده‌های معتبر به‌روزرسانی می‌کنند، که از بروز دسته وسیعی از باگ‌ها در زمان کامپایل جلوگیری می‌کند.
68
258
 
69
- * **`constructor(config: {name: string; loggerPrefix?: string; initialState: S})`:**
70
- * `config.name`: The name of the state machine (used for logging).
71
- * `config.loggerPrefix`: Optional prefix for log messages.
72
- * `config.initialState`: The initial state of the machine.
259
+ - **Decouples Logic from UI**: The `FsmService` encapsulates your application's logic, keeping it completely independent of your UI framework. Your UI simply subscribes to the `stateSignal` and dispatches events to the `eventSignal`. This improves testability and makes it easy to refactor or even replace the UI layer.
260
+ <br>
261
+ **جداسازی منطق از UI**: سرویس FSM منطق برنامه شما را کپسوله کرده و آن را کاملاً مستقل از فریم‌ورک UI نگه می‌دارد. لایه UI شما تنها به `stateSignal` گوش می‌دهد و رویدادها را به `eventSignal` ارسال می‌کند. این رویکرد آزمون‌پذیری را بهبود بخشیده و بازنویسی یا حتی تعویض لایه UI را آسان می‌کند.
73
262
 
74
- * **`stateRecord_: StateRecord<S, E>`:** Defines the states and their possible transitions based on events.
263
+ - **Robust & Resilient**: The machine operates on a Run-to-Completion (RTC) model, ensuring that each event is fully processed before the next one begins, preventing race conditions. Furthermore, any errors thrown inside user-defined functions (`condition`, `assigner`, `effect`) are caught and logged, preventing the entire machine from crashing.
264
+ <br>
265
+ **مستحکم و انعطاف‌پذیر**: ماشین بر اساس مدل اجرای کامل تا انتها (RTC) عمل می‌کند، که تضمین می‌کند هر رویداد به طور کامل پردازش شده و سپس رویداد بعدی آغاز می‌شود. این از بروز race condition جلوگیری می‌کند. علاوه بر این، هرگونه خطای ایجاد شده در توابع تعریف‌شده توسط کاربر (`condition`, `assigner`, `effect`) مدیریت و لاگ می‌شود و از کرش کردن کل ماشین جلوگیری می‌کند.
75
266
 
76
- * **`actionRecord_: ActionRecord<S, E>`:** Binds action names to class methods for execution during transitions.
267
+ ## API Reference / مرجع API
77
268
 
78
- * **`transition_(event: E)`:** Triggers a state transition based on the provided event.
269
+ ### `createFsmService(config)`
79
270
 
80
- * **`shouldTransition_(_eventDetail: StateEventDetail<S, E>): MaybePromise<boolean>`:** (Optional) Allows you to define custom conditions for transitions.
271
+ The main factory function to create a new FSM service.
272
+ تابع اصلی برای ساخت یک سرویس FSM جدید.
81
273
 
82
- * **`postTransition__(eventDetail: StateEventDetail<S, E>)`:** Executes actions associated with state transitions and events.
274
+ - **`config`**: `StateMachineConfig<TState, TEvent, TContext>`
275
+ - The declarative configuration object for the state machine.
276
+ - آبجکت پیکربندی اعلانی برای ماشین حالت.
277
+ - **Returns**: `FsmService<TState, TEvent, TContext>`
278
+ - An instance of the FSM service with two main properties:
279
+ - `stateSignal`: A readable signal that emits the current `MachineState`.
280
+ - `eventSignal`: A signal to `dispatch` new events to the machine.
281
+ - یک نمونه از سرویس FSM با دو پراپرتی اصلی:
282
+ - `stateSignal`: یک سیگنال خواندنی که `MachineState` فعلی را منتشر می‌کند.
283
+ - `eventSignal`: سیگنالی برای ارسال (`dispatch`) رویدادهای جدید به ماشین.
83
284
 
84
- * **`execAction__(name: ActionName<S, E>, eventDetail: StateEventDetail<S, E>)`:** Executes a specific action if defined in the `actionRecord_`.
285
+ ### Key Types / انواع کلیدی
85
286
 
86
- * **`resetToInitialState_()`:** Resets the machine to its initial state without notifying subscribers.
287
+ | Type | Description |
288
+ | :----------------------- | :---------------------------------------------------------------------------- |
289
+ | **`MachineState<S, C>`** | Represents the complete state, containing `name: S` and `context: C`. |
290
+ | **`MachineEvent<T>`** | The base interface for events. Must have a `type: T` property. |
291
+ | **`StateMachineConfig`** | The main configuration object defining `initial`, `context`, and `states`. |
292
+ | **`Transition`** | Defines a transition with an optional `target`, `condition`, and `assigners`. |
293
+
294
+ | نوع | توضیحات |
295
+ | :----------------------- | :------------------------------------------------------------------------------------------------------------- |
296
+ | **`MachineState<S, C>`** | وضعیت کامل ماشین را نمایش می‌دهد که شامل `name: S` (نام وضعیت) و `context: C` (زمینه) است. |
297
+ | **`MachineEvent<T>`** | اینترفیس پایه برای رویدادها. باید یک پراپرتی `type: T` داشته باشد. |
298
+ | **`StateMachineConfig`** | آبجکت اصلی پیکربندی که `initial` (وضعیت اولیه)، `context` (زمینه اولیه) و `states` (وضعیت‌ها) را تعریف می‌کند. |
299
+ | **`Transition`** | یک گذار را با `target` (مقصد)، `condition` (شرط) و `assigners` (تخصیص‌دهنده‌ها)ی اختیاری تعریف می‌کند. |
87
300
 
88
301
  ## Sponsors
89
302
 
90
303
  The following companies, organizations, and individuals support flux ongoing maintenance and development. Become a Sponsor to get your logo on our README and website.
91
304
 
92
-
93
- ### Contributing
305
+ ## Contributing
94
306
 
95
307
  Contributions are welcome! Please read our [contribution guidelines](https://github.com/Alwatr/.github/blob/next/CONTRIBUTING.md) before submitting a pull request.
96
-
@@ -0,0 +1,64 @@
1
+ import { FsmService } from './fsm-service.js';
2
+ import type { MachineEvent, StateMachineConfig } from './type.js';
3
+ /**
4
+ * A simple and clean factory function for creating an `FsmService` instance.
5
+ * This is the recommended way to instantiate a new state machine.
6
+ *
7
+ * @template TState - The union type of all possible states.
8
+ * @template TEvent - The union type of all possible events.
9
+ * @template TContext - The type of the machine's context.
10
+ *
11
+ * @param config - The machine's configuration object.
12
+ * @returns A new, ready-to-use instance of `FsmService`.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * import {createFsmService} from '@alwatr/fsm';
17
+ * import type {StateMachineConfig} from '@alwatr/fsm';
18
+ *
19
+ * // 1. Define types
20
+ * type LightContext = {brightness: number};
21
+ * type LightState = 'on' | 'off';
22
+ * type LightEvent = {type: 'TOGGLE'} | {type: 'SET_BRIGHTNESS'; level: number};
23
+ *
24
+ * // 2. Config the state machine
25
+ * const lightMachineConfig: StateMachineConfig<LightState, LightEvent, LightContext> = {
26
+ * name: 'light-switch',
27
+ * initial: 'off',
28
+ * context: {brightness: 0},
29
+ * states: {
30
+ * off: {
31
+ * on: {
32
+ * TOGGLE: {
33
+ * target: 'on',
34
+ * assigners: [() => ({brightness: 100})],
35
+ * },
36
+ * },
37
+ * },
38
+ * on: {
39
+ * on: {
40
+ * TOGGLE: {target: 'off', assigners: [() => ({brightness: 0})]},
41
+ * SET_BRIGHTNESS: {assigners: [(event) => ({brightness: event.level})]},
42
+ * },
43
+ * },
44
+ * },
45
+ * };
46
+ *
47
+ * // 3. Create the service
48
+ * const lightService = createFsmService(lightMachineConfig);
49
+ *
50
+ * // 4. Use it in your application
51
+ * lightService.stateSignal.subscribe((state) => {
52
+ * console.log(`Light is ${state.name} with brightness ${state.context.brightness}`);
53
+ * });
54
+ *
55
+ * lightService.eventSignal.dispatch({type: 'TOGGLE'}); // Light is on with brightness 100
56
+ *
57
+ * lightService.eventSignal.dispatch({type: 'SET_BRIGHTNESS', level: 50}); // Light is on with brightness 50
58
+ *
59
+ * // 5. Cleanup
60
+ * // lightService.destroy();
61
+ * ```
62
+ */
63
+ export declare function createFsmService<TState extends string, TEvent extends MachineEvent, TContext extends Record<string, unknown>>(config: StateMachineConfig<TState, TEvent, TContext>): FsmService<TState, TEvent, TContext>;
64
+ //# sourceMappingURL=facade.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"facade.d.ts","sourceRoot":"","sources":["../src/facade.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAE5C,OAAO,KAAK,EAAC,YAAY,EAAE,kBAAkB,EAAC,MAAM,WAAW,CAAC;AAEhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,SAAS,YAAY,EAAE,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC3H,MAAM,EAAE,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,GACnD,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAEtC"}
@@ -0,0 +1,61 @@
1
+ import type { StateMachineConfig, MachineState, MachineEvent } from './type.js';
2
+ /**
3
+ * A generic, encapsulated service that creates, runs, and manages a finite state machine.
4
+ * It handles signal creation, logic connection, and lifecycle management, providing a clean,
5
+ * reactive API for interacting with the FSM.
6
+ *
7
+ * @template TState The union type of all possible state names.
8
+ * @template TEvent The union type of all possible events.
9
+ * @template TContext The type of the machine's context (extended state).
10
+ */
11
+ export declare class FsmService<TState extends string, TEvent extends MachineEvent, TContext extends Record<string, unknown>> {
12
+ protected readonly config_: StateMachineConfig<TState, TEvent, TContext>;
13
+ protected readonly logger_: import("@alwatr/logger").AlwatrLogger;
14
+ /** The event signal for sending events to the FSM. */
15
+ readonly eventSignal: import("@alwatr/signal").EventSignal<TEvent>;
16
+ private readonly stateSignal__;
17
+ /** The public, read-only state signal. Subscribe to react to state changes. */
18
+ readonly stateSignal: import("@alwatr/signal").IReadonlySignal<MachineState<TState, TContext>>;
19
+ constructor(config_: StateMachineConfig<TState, TEvent, TContext>);
20
+ /**
21
+ * The core FSM logic that processes a single event and transitions the machine to a new state.
22
+ * This process is atomic and follows the Run-to-Completion (RTC) model.
23
+ *
24
+ * @param event The event to process.
25
+ */
26
+ private processTransition__;
27
+ /**
28
+ * Finds the first valid transition for the given event and context by evaluating conditions.
29
+ *
30
+ * @param event The triggering event.
31
+ * @param context The current machine context.
32
+ * @returns The first matching transition or `undefined` if none are found.
33
+ */
34
+ private findTransition__;
35
+ /**
36
+ * Sequentially executes a list of effects (side-effects).
37
+ * Errors are caught and logged without stopping the FSM.
38
+ *
39
+ * @param event The event that triggered these effects.
40
+ * @param context The context at the time of execution.
41
+ * @param effects A single effect or an array of effects.
42
+ */
43
+ private executeEffects__;
44
+ /**
45
+ * Applies all assigner functions to the context to produce a new, updated context.
46
+ * This process is atomic (all-or-nothing). If any assigner fails, the original
47
+ * context is returned, and all updates are discarded.
48
+ *
49
+ * @param event The event that triggered the transition.
50
+ * @param context The current context.
51
+ * @param assigners A single assigner or an array of assigners.
52
+ * @returns The new, updated context, or the original context if any assigner fails.
53
+ */
54
+ private applyAssigners__;
55
+ /**
56
+ * Destroys the service, cleaning up all internal signals and subscriptions
57
+ * to prevent memory leaks.
58
+ */
59
+ destroy(): void;
60
+ }
61
+ //# sourceMappingURL=fsm-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fsm-service.d.ts","sourceRoot":"","sources":["../src/fsm-service.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,kBAAkB,EAAE,YAAY,EAAE,YAAY,EAA+B,MAAM,WAAW,CAAC;AAE5G;;;;;;;;GAQG;AACH,qBAAa,UAAU,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,SAAS,YAAY,EAAE,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAmB/F,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC;IAlB3F,SAAS,CAAC,QAAQ,CAAC,OAAO,wCAA4C;IAEtE,sDAAsD;IACtD,SAAgB,WAAW,+CAExB;IAEH,OAAO,CAAC,QAAQ,CAAC,aAAa,CAM3B;IAEH,+EAA+E;IAC/E,SAAgB,WAAW,2EAAmC;gBAExB,OAAO,EAAE,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC;IAK3F;;;;;OAKG;YACW,mBAAmB;IAuCjC;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB;IAwCxB;;;;;;;OAOG;YACW,gBAAgB;IAqC9B;;;;;;;;;OASG;IACH,OAAO,CAAC,gBAAgB;IAkCxB;;;OAGG;IACI,OAAO,IAAI,IAAI;CAKvB"}