{"id":27827945,"url":"https://github.com/NikitaTopchii/fsm-state-manager","last_synced_at":"2025-05-01T22:02:02.181Z","repository":{"id":287715904,"uuid":"964174232","full_name":"NikitaTopchii/fsm-state-manager","owner":"NikitaTopchii","description":null,"archived":false,"fork":false,"pushed_at":"2025-04-23T17:54:24.000Z","size":3680,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-23T18:43:35.147Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NikitaTopchii.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-04-10T19:58:44.000Z","updated_at":"2025-04-23T17:54:27.000Z","dependencies_parsed_at":"2025-04-13T14:44:13.626Z","dependency_job_id":null,"html_url":"https://github.com/NikitaTopchii/fsm-state-manager","commit_stats":null,"previous_names":["nikitatopchii/fsm-state-manager"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NikitaTopchii%2Ffsm-state-manager","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NikitaTopchii%2Ffsm-state-manager/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NikitaTopchii%2Ffsm-state-manager/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NikitaTopchii%2Ffsm-state-manager/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NikitaTopchii","download_url":"https://codeload.github.com/NikitaTopchii/fsm-state-manager/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251951278,"owners_count":21670236,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-05-01T22:02:00.940Z","updated_at":"2025-05-01T22:02:02.172Z","avatar_url":"https://github.com/NikitaTopchii.png","language":"TypeScript","funding_links":[],"categories":["State Management"],"sub_categories":["Other State Libraries"],"readme":"\n# State Transition Manager\n\n\u003e A simple, flexible and strongly-typed finite state machine manager for managing state transitions in Angular or any TypeScript-based application.\n\n---\n\n# Latest Updates\n\n\u003e v1.1.2 — State Subscriptions Added, Error Handling Improved, and Subscription Mode Toggle Introduced\n\n---\n\n## 🌐 Table of Contents\n\n- [What is a State](#what-is-a-state)\n- [What is an Event](#what-is-an-event)\n- [What is a Transition](#what-is-a-transition)\n- [What are Transition Rules](#what-are-transition-rules)\n- [What is FSM Config](#what-is-fsm-config)\n- [What is Transition Guard](#what-is-transition-guard)\n- [What are Options](#what-are-options)\n- [Example of Transition Rules for HTTP Requests](#example-of-transition-rules-for-http-requests)\n\n---\n\n## 🧠 What is a State\n\nIn this implementation, a **state** represents the current phase of an action the user is performing. This could be processing an HTTP request or the status of a filter the user has opened.\n\n### Example:\n\n```ts\ntype HttpRequestStateType = 'init' | 'loading' | 'loaded' | 'error';\n\nconst initialState = {\n  state: 'init',\n  appliedData: [],\n};\n```\n\nEach state describes a phase of your application logic — e.g., \"loading\" during a data fetch or \"error\" when something goes wrong.\n\n---\n\n## ⚡ What is an Event\n\nAn **event** is an action that triggers a state change.\nThanks to events, we can precisely control **transitions** between states via defined transition rules.\n\nFor example, consider an HTTP request. The initial state before the user clicks a button might be init. When the user clicks the button, an event like fetch is triggered, transitioning to the loading state — because from init, we can only go to loading. Then from loading, we can go to either loaded or error, depending on the outcome (success or failure events).\n\n### Example:\n\n```ts\ntype HttpRequestEventType = 'fetch' | 'success' | 'failure' | 'retry';\n```\n\nEvents are mapped to states, and when fired, they initiate a transition based on defined rules.\n\n---\n\n## 🔁 What is a Transition\n\n**Transitions** define how we move from one state to another, triggered by events.\nTransitions are controlled by a transition function. For better type safety and consistency, it’s recommended to define a reusable type for them.\n\nThe function takes two arguments: the **current state** (including any data), and an **optional payload** used to shape the next state.\n\n### Transition Function Signature\n\n```ts\ntype TransitionBaseStateFn\u003cConfig extends FSMConfigI\u003e = (\n    data: StateDataI\u003cConfig\u003e,\n    payload?: { appliedData?: Config['data'] } \n  ) =\u003e StateDataI\u003cConfig\u003e;\n```\n\n---\n\n## 🧾 What are Transition Rules\n\n**Transition rules** define how the state machine should **transition** between states when specific events occur.\nIf an event happens in a certain state and there's a matching transition rule for it, the rule is executed.\n\n### Type Definition\n\n```ts\ntype TransitionRulesType\u003cConfig extends FSMConfigI\u003e = {\n  [State in Config['state']]: Partial\u003cRecord\u003cConfig['event'], TransitionRule\u003cConfig\u003e\u003e\u003e;\n};\n```\n\n---\n\n## 🧾 What is FSM Config\n\n**FSMConfig** is the interface that defines the configuration for a particular implementation of the state manager. For instance, a state manager for HTTP requests will have a different config than one managing filter state.\n\n### Type Definition\n\n```ts\ninterface HttpRequestFSMConfigI extends FSMConfigI{\n    state: HttpRequestStateType,\n    event: HttpRequestEventType,\n    rule: TransitionHttpRequestStateFn\u003cHttpRequestFSMConfigI\u003e, \n    data: any // data type coming from the backend\n}\n\nexport default HttpRequestFSMConfigI;\n```\n\n---\n\n## 🧾 What is Transition Guard\n\nA **TransitionGuard** is a function that prevents a state change based on some condition.\nIt’s useful for scenarios like preventing unauthenticated users from transitioning or validating a state or event before a transition occurs.\n\n### Type Definition\n\n```ts\ntype TransitionGuardFn\u003cConfig extends FSMConfigI\u003e = (\n    currentState?: Config['state'],\n    event?: Config['event'],\n) =\u003e boolean;\n```\n\n### Use Case\n\n```ts\nsuccess: {\n  transitionAction: (data: any, payload: any) =\u003e\n    payload?.appliedData\n      ? { state: 'loaded', appliedData: payload.appliedData }\n      : data,\n  transitionGuard: () =\u003e doSomething(), // some function returning a boolean\n}\n```\n\n---\n\n## 🧾 What are Options\n\n**Options** are additional settings that can be optionally passed when creating a state manager instance.\nThey allow enabling devMode or logging transitions. By default, both are set to false.\n\n### Definition\n\n```ts\nnew StateManagerFSM(HttpRequestTransitionRules, { devMode: true, logTransitions: true });\n```\n\n---\n\n## What is transition\n\nThe **transition** method is the core feature that performs state changes based on transition rules.\nIt does several safety checks and ensures the transition is valid. When devMode or logTransitions are enabled, it also logs state transitions to the console.\n\n### Definition\n\n```ts\nstateManager.transition('fetch');\n\nstateManager.transition('success', ['data1', 'data2']);\n```\n\n---\n\n## What is canTransition\n\n**canTransition** is a public method that checks if a transition from the current state is possible using a specific event.\n\n### Definition\n\n```ts\nstateManager.canTransition('failure');\n```\n\n---\n\n## What are setStateData and getStateData\n\n**setStateData** is a setter method for initializing or overriding the current state.\n**getStateData** is a getter method to retrieve the current state data.\n\n### Definition\n\n```ts\nstateManager.setStateData({ state: 'init', appliedData: [] });\n\nstateManager.getStateData(); // { state: 'init', appliedData: [] }\n```\n\n---\n\n## Subscription on changing state\n\nYou can subscribe to a specific state change and pass a function that will be triggered when the transition to the desired state occurs.\nThis can be useful for displaying loading notifications, error messages, or any other scenarios — the only limit is your imagination.\nTo subscribe, simply call the **subscribe** method on the state manager, passing two arguments: the first is the state you want to listen to, and the second is the callback function that should execute when the state changes.\nTo unsubscribe, refer to the variable where you stored the subscription and call the **unsubscribe** method on it.\n\nThis is optional with **subscriptionMode**.\n\n```ts\nconst stateManager = new StateManagerFSM\u003cConfig\u003e(transitionRules, { subscriptionMode: true })\n\nconst subscribtion = stateManager.subscribe('loaded', () =\u003e {})\n\nbenchmarkTransition('fetch');\nbenchmarkTransition('success', ['data1', 'data2']);\n\nsubscribtion.unsubscribe();\n\nbenchmarkTransition('fetch');\nbenchmarkTransition('success', ['data1', 'data2']);\n```\n---\n\n## 📦 Example of Transition Rules for HTTP Requests\n\nHere’s a complete example that demonstrates how you could define transition rules for managing the lifecycle of an HTTP request:\n\n```ts\nconst HttpRequestTransitionRules: TransitionRulesType\u003cHttpRequestFSMConfigI\u003e = {\n  init: {\n    fetch: {\n      transitionAction: () =\u003e ({\n        state: 'loading',\n        appliedData: [],\n      }),\n    },\n  },\n  loading: {\n    success: {\n      transitionAction: (data: any, payload: any) =\u003e\n        payload?.appliedData\n          ? { state: 'loaded', appliedData: payload.appliedData }\n          : data,\n      transitionGuard: () =\u003e doSomething(),\n    },\n    failure: {\n      transitionAction: (data: any, payload: any) =\u003e\n        payload?.appliedData\n          ? { state: 'error', appliedData: payload.appliedData }\n          : data,\n    },\n  },\n  loaded: {\n    fetch: {\n      transitionAction: () =\u003e ({\n        state: 'loading',\n        appliedData: [],\n      }),\n    },\n  },\n  error: {\n    retry: {\n      transitionAction: () =\u003e ({\n        state: 'loading',\n        appliedData: [],\n      }),\n    },\n  },\n};\n```\n\nEach transition function returns either a new state or the current one (if unchanged).\nThis makes the state machine predictable, easy to test, and highly reusable.\n\n---\n\n## Use case \n\n```ts\ntype HttpRequestStateType = 'init' | 'loading' | 'loaded' | 'error';\n\ntype HttpRequestEventType = 'fetch' | 'success' | 'failure' | 'retry';\n\ntype TransitionHttpRequestStateFn\u003cConfig extends HttpRequestFSMConfigI\u003e = (\n  data: Config['data'],\n  payload?: { appliedData?: Config['data'] }\n) =\u003e Config['data'];\n\ninterface HttpRequestFSMConfigI extends FSMConfigI {\n  state: HttpRequestStateType,\n  event: HttpRequestEventType,\n  rule: TransitionHttpRequestStateFn\u003cHttpRequestFSMConfigI\u003e,\n  data: any\n}\n\nconst stateManager = new StateManagerFSM(HttpRequestTransitionRules, { devMode: true, logTransitions: true });\n\nstateManager.setStateData({ state: 'init', appliedData: [] });\n\nstateManager.transition('fetch'); \n// [FSM] Transition: 'init' state → 'loading' state triggered by 'fetch' event\n\nstateManager.transition('success', ['data1', 'data2']); \n// [FSM] Transition: 'loading' state → 'loaded' state triggered by 'success' event\n\nconsole.log(stateManager.canTransition('failure')); \n// [FSM Warn] We can't transition to another state with event 'failure' from state 'loaded' → false\n\nconsole.log(stateManager.getStateData().appliedData); \n// ['data1', 'dota2']\n```\n\n---\n\n## Трішки про швидкість\n\nПереходи між стейтами відбуваються майже миттево, завдяки цьому ви можете швидше маніпулювати даними та UI вашого застосунку що буде утримувати користувачів залишатися разом з вами\n\n```ts\n2518.5655ms\n[FSM] Transition: 'init' state → 'loading' state triggered by 'fetch' event\n[FSM Benchmark] Transition for event 'fetch' took 0.1023ms\n[FSM] Transition: 'loading' state → 'loaded' state triggered by 'success' event\n[FSM Benchmark] Transition for event 'success' took 0.0898ms\n[FSM] Transition: 'loaded' state → 'loading' state triggered by 'fetch' event\n[FSM Benchmark] Transition for event 'fetch' took 0.3693ms\n[FSM] Transition: 'loading' state → 'loaded' state triggered by 'success' event\n[FSM Benchmark] Transition for event 'success' took 0.0184ms\n```\n\n## 🧠 Що таке стейт \n\nСтейт у цій реалізації відображає поточний **стан** якоїсь дії яку виконує користувач. Це може бути або обробка http запиту, або стан в якому знаходиться фільтр відкритий користувачем.\n\n### Example:\n\n```ts\ntype HttpRequestStateType = 'init' | 'loading' | 'loaded' | 'error';\n\nconst initialState = {\n  state: 'init',\n  appliedData: [], // гіпотетичні дані які прийдуть з серверу ( або будь які дані які будуть вкладені в стейт )\n};\n```\n\n---\n\n## ⚡ Що таке івент\n\nІвент це **дія**, яка спричиняє зміну стану. \nСаме завдяки ньому ми можемо чітко переходити між станами завдяки правилам переходу.\n\nНаприклад є у нас запит на бекенд, початковий стан до того як користувач натисне на кнопку буде \"init\".\nПісля того як користувач натисне на кнопку то ініт запустить **event**, наприклад fetch, який повертає стейт loading, бо з init\nми можемо перейти тільки у loading. З loading ми можемо перейти у loaded або error ( завдяки як раз таки івентам success або failure відповідно ).\n\n### Example \n\n```ts\ntype HttpRequestEventType = 'fetch' | 'success' | 'failure' | 'retry';\n```\n\n---\n\n## 🔁 Що таке переходи\n\n**Transitions** це як зрозуміло з назви процес переходу з одного стейту в інший враховуючи дію яка відбулась. \nДля переходів треба використовувати **функцію переходу**, під яку бажано використовувати окремий тип для більшої консистентності даних.\nВона використовує два аргумента одним з яких ж інформація про поточний стан ( його стан та можливі дані які він містить ), та не обовʼязковий аргумент payload який є передаваємими даними в новий стейт.\n\n### Transition Function Signature\n\n```ts\ntype TransitionBaseStateFn\u003cConfig extends FSMConfigI\u003e = (\n    data: StateDataI\u003cConfig\u003e,\n    payload?: { appliedData?: Config['data'] } \n  ) =\u003e StateDataI\u003cConfig\u003e;\n\nexport default TransitionBaseStateFn;\n```\n\n---\n\n## 🧾 Що таке правила переходів\n\n**Правила переходів** показують машині шляхи, за якими вона повина переключати стейти через івенти ( про які було сказано вище ).\nЦе дозволяє доволі гнучко налаштовувати ці самі переходи. Якщо під час певного стану відбувається подія і для цієї події існує правило переходу, то воно виконується. \n\n### Type Definition\n\n```ts\ntype TransitionRulesType\u003cConfig extends FSMConfigI\u003e = {\n  [State in Config['state']]: Partial\u003cRecord\u003cConfig['event'], TransitionRule\u003cConfig\u003e\u003e\u003e;\n};\n```\n\n---\n\n## 🧾 Що таке FSMConfig\n\n**FSMConfig** це інтерфейс який визначає конфігурацію для конкретної імплементації стейт менеджера. Якщо це стейт менеджер для обробки запитів, то це одна конфігурація зі своїми типами стейтів, івентів та функцій для переходу, якщо це стейт менеджер для обробки фільтрів, то це ще одна конфігурація.\n\n### Type Definition\n\n```ts\ninterface HttpRequestFSMConfigI {\n    state: HttpRequestStateType,\n    event: HttpRequestEventType,\n    rule: TransitionHttpRequestStateFn\u003cHttpRequestFSMConfigI\u003e, \n    data: any // тип даних які ловимо з бекенду \n}\n\nexport default HttpRequestFSMConfigI;\n```\n\n---\n\n## Що таке TransitionsGuard \n\n**TransitionsGuardd** це тип функції, який дозволяє нам не дати перейти на інший стейт за якоїсь умови, наприклад за відсутності авторизації у користувача, або при умові невалідного івенту або стану. Це дає нам більш гнучко налаштовувати наші переходи між станами, та навіть при валідному правилі переходу не дати це зробити (перехід).\n\n### Type Definition\n\n```ts\ntype TransitionGuardFn\u003cConfig extends FSMConfigI\u003e = (\n    currentState?: Config['state'],\n    event?: Config['event'],\n) =\u003e boolean\n\nexport default HttpRequestFSMConfigI;\n```\n\n### Use case\n\n```ts\n      success: {\n        transitionAction: (data: any, payload: any) =\u003e\n            payload?.appliedData\n              ? { state: 'loaded', appliedData: payload.appliedData }\n              : data,\n        transitionGuard: () =\u003e doSomething(), // якась функція що повертає boolean \n      },\n```\n\n---\n\n## Що таке options\n\n**options** це додаткові налаштування, які ми можемо опціонально вмикати/вимикати в нашому стейт менеджері, прокидуючи в конструктор обʼєкт з двома полями. Поле devMode та поле logTransition. За замовчуванням їх треба ставити false, якщо вам не треба логування, або попереджувальні логи.\n\n### Definition\n\n```ts\n  new StateManagerFSM(HttpRequestTransitionRules, { devMode: true, logTransitions: true });\n```\n---\n\n## Що таке transition\n\n**transition** це головний метод, який нам дозволяє робити всю магію, та використовуючи правила переходів перемикати стейти. Він робить декілька перевірок для того щоб зробити це коректно та не дасть перейти в стейт якщо івент який ми хочемо виконати не є валідним. Також ми можемо уввімкнути devMode та logMode і при використанні цього методу спостерігати за тим які стейти і як перемикаються.\n\n### Definition\n\n```ts\n  stateManager.transition('fetch');\n\n  stateManager.transition('success', ['data1', 'data2']);\n```\n---\n\n## Що таке canTransition\n\n**canTransition** це public функція самого стейт менеджеру яка перевіряє чи є можливість зробити перехід з поточного стану на той, який ми вкажемо в аргументі цієї функції.\n\n### Definition\n\n```ts\n  stateManager.canTransition('failure')\n```\n---\n\n## Що таке setStateData та GetStateData\n\n**setStateData** та **getStateData** це два методи які є сетером та геттером і дають можливість ініціалізувати поточний стан та отримати значення з поточного стану\n\n### Definition\n\n```ts\n  stateManager.setStateData({ state: 'init', appliedData: [] });\n\n  stateManager.getStateData(); // { state: 'init', appliedData: [] }\n```\n---\n\n## 📦 Правила переходів для HTTP Requests\n\nПідсумуючи все вище зазначене, можна розглянути приклад правил переходу між станами для http запиту:\n\n```ts\nconst HttpRequestTransitionRules: TransitionRulesType\u003cHttpRequestFSMConfigI\u003e = {\n    init: {\n      fetch: {\n        transitionAction: () =\u003e ({\n            state: 'loading',\n            appliedData: [],\n        })\n      },\n    },\n    loading: {\n      success: {\n        transitionAction: (data: any, payload: any) =\u003e\n            payload?.appliedData\n              ? { state: 'loaded', appliedData: payload.appliedData }\n              : data,\n        transitionGuard: () =\u003e doSomething(),\n      },\n      failure: {\n        transitionAction: (data: any, payload: any) =\u003e\n            payload?.appliedData\n              ? { state: 'error', appliedData: payload.appliedData }\n              : data,\n      }\n    },\n    loaded: {\n      fetch: {\n        transitionAction: () =\u003e ({\n            state: 'loading',\n            appliedData: [],\n          }),\n      }\n    },\n    error: {\n      retry: {\n        transitionAction: () =\u003e ({\n            state: 'loading',\n            appliedData: [],\n          }),\n      }\n    },\n};\n```\n\nКожна функція повертає новий стан або поточний, якщо змін не відбулося. Це робить автомат передбачуваним, \nякий легко тестувати та багаторазово перевикористовувати код. \n\n---\n\n## Підписки на зміну станів\n\nВи можете підписатися на зміну конкретного стану й передати туди функцію, яка спрацює в момент переходу до потрібного вам стану.\nЦе може бути корисно для відображення сповіщень під час завантаження, повідомлень про помилки або будь-яких інших сценаріїв — обмеження тільки у вашій уяві.\nЩоб підписатися, достатньо звернутися до стейт-менеджера та викликати метод **subscribe**, передавши в нього два аргументи: перший — це стан, на який потрібно реагувати, другий — функція-колбек, яка виконається під час зміни на цей стан.\nЩоб відписатися, зверніться до змінної у яку ви зберегли підписку та використайте метод **unsubscribe**.\n\nЦе необовʼязковий фукнціонал, він вимкнений за замовчуванням, для його роботи треба в конструкторі дописати **subscriptionMode: true**\n\n```ts\nconst stateManager = new StateManagerFSM\u003cConfig\u003e(transitionRules, { subscriptionMode: true })\n\nconst subscribtion = stateManager.subscribe('loaded', () =\u003e {})\n\nbenchmarkTransition('fetch');\nbenchmarkTransition('success', ['data1', 'data2']);\n\nsubscribtion.unsubscribe();\n\nbenchmarkTransition('fetch');\nbenchmarkTransition('success', ['data1', 'data2']);\n```\n\n---\n\n## Приклад використання\n\n```ts\ntype HttpRequestStateType = 'init' | 'loading' | 'loaded' | 'error';\n\ntype HttpRequestEventType = 'fetch' | 'success' | 'failure' | 'retry';\n\ntype TransitionHttpRequestStateFn\u003cConfig extends HttpRequestFSMConfigI\u003e = (\n    data: Config['data'],\n    payload?: { appliedData?: Config['data'] } \n  ) =\u003e Config['data'];\n\ninterface HttpRequestFSMConfigI extends FSMConfigI{\n    state: HttpRequestStateType,\n    event: HttpRequestEventType,\n    rule: TransitionHttpRequestStateFn\u003cHttpRequestFSMConfigI\u003e, \n    data: any\n}\n\nconst HttpRequestTransitionRules: TransitionRulesType\u003cHttpRequestFSMConfigI\u003e = {\n    init: {\n      fetch: {\n        transitionAction: () =\u003e ({\n            state: 'loading',\n            appliedData: [],\n        })\n      },\n    },\n    loading: {\n      success: {\n        transitionAction: (data: any, payload: any) =\u003e\n            payload?.appliedData\n              ? { state: 'loaded', appliedData: payload.appliedData }\n              : data,\n        transitionGuard: () =\u003e doSomething(),\n      },\n      failure: {\n        transitionAction: (data: any, payload: any) =\u003e\n            payload?.appliedData\n              ? { state: 'error', appliedData: payload.appliedData }\n              : data,\n      }\n    },\n    loaded: {\n      fetch: {\n        transitionAction: () =\u003e ({\n            state: 'loading',\n            appliedData: [],\n          }),\n      }\n    },\n    error: {\n      retry: {\n        transitionAction: () =\u003e ({\n            state: 'loading',\n            appliedData: [],\n          }),\n      }\n    },\n  };\n\nconst doSomething = () =\u003e { return true }\n\nconst stateManager = new StateManagerFSM(HttpRequestTransitionRules, { devMode: true, logTransitions: true });\n\nstateManager.setStateData({ state: 'init', appliedData: [] });\n\nstateManager.transition('fetch'); //[FSM] Transition: 'init' state → 'loading' state triggered by 'fetch' event\n\nstateManager.transition('success', ['data1', 'data2']); //[FSM] Transition: 'loading' state → 'loaded' state triggered by 'success' event\n\nconsole.log(stateManager.canTransition('failure')); //[FSM Warn] We can't transition to another state with event 'failure' from state 'loaded' (false in console.log)\n\nconsole.log(stateManager.getStateData().appliedData); // ['data1, 'data2']\n```\n\n## 📝 License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNikitaTopchii%2Ffsm-state-manager","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FNikitaTopchii%2Ffsm-state-manager","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNikitaTopchii%2Ffsm-state-manager/lists"}