@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 +109 -0
- package/README.md +274 -63
- package/dist/facade.d.ts +64 -0
- package/dist/facade.d.ts.map +1 -0
- package/dist/fsm-service.d.ts +61 -0
- package/dist/fsm-service.d.ts.map +1 -0
- package/dist/main.cjs +2 -143
- package/dist/main.cjs.map +4 -4
- package/dist/main.d.ts +3 -3
- package/dist/main.d.ts.map +1 -1
- package/dist/main.mjs +2 -116
- package/dist/main.mjs.map +4 -4
- package/dist/type.d.ts +98 -9
- package/dist/type.d.ts.map +1 -1
- package/package.json +10 -10
- package/dist/base.d.ts +0 -47
- package/dist/base.d.ts.map +0 -1
- package/dist/fsm.d.ts +0 -19
- package/dist/fsm.d.ts.map +0 -1
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
|
-
#
|
|
1
|
+
# Alwatr FSM
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
|
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
|
-
|
|
94
|
+
### ۲. پیکربندی ماشین
|
|
20
95
|
|
|
21
|
-
|
|
22
|
-
|
|
96
|
+
Define the entire machine logic in a configuration object.
|
|
97
|
+
کل منطق ماشین را در یک آبجکت پیکربندی تعریف میکنیم.
|
|
23
98
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
29
|
-
constructor() {
|
|
30
|
-
super({
|
|
31
|
-
name: 'my-state-machine',
|
|
32
|
-
initialState: 'idle',
|
|
33
|
-
});
|
|
159
|
+
## Example 2: Async Data Fetching
|
|
34
160
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
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
|
-
|
|
267
|
+
## API Reference / مرجع API
|
|
77
268
|
|
|
78
|
-
|
|
269
|
+
### `createFsmService(config)`
|
|
79
270
|
|
|
80
|
-
|
|
271
|
+
The main factory function to create a new FSM service.
|
|
272
|
+
تابع اصلی برای ساخت یک سرویس FSM جدید.
|
|
81
273
|
|
|
82
|
-
|
|
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
|
-
|
|
285
|
+
### Key Types / انواع کلیدی
|
|
85
286
|
|
|
86
|
-
|
|
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
|
-
|
package/dist/facade.d.ts
ADDED
|
@@ -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"}
|