{"id":24869398,"url":"https://github.com/khraksmamtsov/ts-fsm","last_synced_at":"2025-10-15T13:31:46.242Z","repository":{"id":57380739,"uuid":"135808887","full_name":"KhraksMamtsov/ts-fsm","owner":"KhraksMamtsov","description":"Finit state machine writen in typescript","archived":false,"fork":false,"pushed_at":"2018-06-18T06:42:39.000Z","size":873,"stargazers_count":22,"open_issues_count":1,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-10T11:52:04.197Z","etag":null,"topics":["lifecycle","lifecycle-management","state-machine","state-management","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KhraksMamtsov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"code-of-conduct.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-06-02T10:34:03.000Z","updated_at":"2023-04-01T02:10:17.000Z","dependencies_parsed_at":"2022-08-27T13:23:35.478Z","dependency_job_id":null,"html_url":"https://github.com/KhraksMamtsov/ts-fsm","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KhraksMamtsov%2Fts-fsm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KhraksMamtsov%2Fts-fsm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KhraksMamtsov%2Fts-fsm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KhraksMamtsov%2Fts-fsm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KhraksMamtsov","download_url":"https://codeload.github.com/KhraksMamtsov/ts-fsm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":236612823,"owners_count":19177159,"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":["lifecycle","lifecycle-management","state-machine","state-management","typescript"],"created_at":"2025-02-01T03:22:58.756Z","updated_at":"2025-10-15T13:31:40.913Z","avatar_url":"https://github.com/KhraksMamtsov.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![GitHub top language](https://img.shields.io/github/languages/top/KhraksMamtsov/ts-fsm.svg?style=flat-square)\n![npm type definitions](https://img.shields.io/npm/types/ts-fsm.svg?style=flat-square)\n[![Build Status](https://img.shields.io/travis/KhraksMamtsov/ts-fsm/master.svg?style=flat-square)](https://travis-ci.org/KhraksMamtsov/ts-fsm)\n[![Coverage Status](https://img.shields.io/coveralls/github/KhraksMamtsov/ts-fsm/master.svg?style=flat-square)](https://coveralls.io/github/KhraksMamtsov/ts-fsm?branch=master)\n[![npm bundle size (minified + gzip)](https://img.shields.io/bundlephobia/minzip/ts-fsm.svg?style=flat-square)](https://bundlephobia.com/result?p=ts-fsm)\n[![npm bundle size (minified)](https://img.shields.io/bundlephobia/min/ts-fsm.svg?style=flat-square)](https://bundlephobia.com/result?p=ts-fsm)\n![license](https://img.shields.io/github/license/KhraksMamtsov/ts-fsm.svg?style=flat-square)\n\n\n\n\n# 🤖 Finite state machine written in typescript\n❄️ ↔️ 🌊 ↔️ ♨️\nAdvanced control of entities' lifecycle.\n\n```cmd\nnpm install ts-fsm\nyarn add ts-fsm\n```\n\n## Simple usage\n\n```typescript\nimport StateMachine from \"ts-fsm\";\n\nenum STATE {\n    SOLID = \"SOLID\",\n    LIQUID = \"LIQUID\",\n    GAS = \"GAS\",\n} \n\nenum TRANSITION {\n    MELT = \"MELT\",\n    VAPORIZE = \"VAPORIZE\",\n    CONDENSE = \"CONDENSE\",\n    FREEZE = \"FREEZE\",\n}\n\ninterface IDATA {\n    temperature: number;\n}\n\nconst states = [{\n    name: STATE.SOLID,\n    data: { temperature: -100 },\n}, {\n    name: STATE.LIQUID,\n    data: { temperature: 50 },\n}, {\n    name: STATE.GAS,\n    data: { temperature: 200 },\n}];\n\nconst transitions = [{\n    name: TRANSITION.MELT,\n    from: STATE.SOLID,\n    to: STATE.LIQUID,\n}, {\n    name: TRANSITION.FREEZE,\n    from: STATE.LIQUID,\n    to: STATE.SOLID,\n}, {\n    name: TRANSITION.VAPORIZE,\n    from: STATE.LIQUID,\n    to: STATE.GAS,\n}, {\n    name: TRANSITION.CONDENSE,\n    from: STATE.GAS,\n    to: STATE.LIQUID,\n}];\n\nconst sm = new StateMachine\u003cSTATE, TRANSITION, IDATA\u003e(STATE.SOLID, states, transitions);\n\nsm.state // \"SOLID\"\nsm.data // { temperature: -100 }\n\nsm.transitTo(STATE.LIQUID) // Promise { sm }\n   .then(sm =\u003e {\n       sm.state; // \"LIQUID\"\n       sm.data; // { temperature: 50 }\n   });\n\nsm.doTransition(TRANSITION.VAPORIZE) // Promise { sm }\n   .then(sm =\u003e {\n       sm.state; // \"GAS\"\n       sm.data; // { temperature: 200 }\n   });\n```\n\n## 🏁🏁 Initialization\n\n`ts-fsm` provide overloaded constructor and methods signature.\n\n```typescript\nnew StateMachine\u003cSTATE, TRANSITION, IDATA\u003e(\n    STATE.SOLID, \n    states,\n    transitions\n);\n\nnew StateMachine\u003cSTATE, TRANSITION, IDATA\u003e(\n    STATE.SOLID, // initial state \n    {\n        before: () =\u003e {}, // beforeEachState\n        states,\n        after: [() =\u003e {}, () =\u003e {}], // afterEachState\n    }, {\n        before: () =\u003e {}, // beforeEachTransition\n        transitions,\n        after: [() =\u003e {}, () =\u003e {}], // afterEachTransition\n    }, {\n        onError: () =\u003e {};\n        timeout: 1000;\n    }\n);\n```\n\n## 🍃🎣 Lifecycle Hooks\n\nState machine provide several hooks for track or perform an action when a transition occurs.\n\nAs a handler, both a single function and an array of functions can be passed.\n\nAs a value, the handler takes `transport`, `from-state`, `to-state`. `this` - an instance of state machine.\n\n`transport` argument - mutable object, shared and passed through each hook handler.\n\nTransition can be canceled from any handler with explicitly return `false` or `Promise { false }`, in this case, then the subsequent handlers are not called, and state machine return to previous state.\n\nEach handler can be limited by time with passing `timeout` setting into constructor.\n\n| Hook | Define | Fired |\n|------|--------|-------|\n| ```afterEachState``` | constructor: state: after | after any state\n| ```afterState``` | state: after | after specific state\n| ```beforeEachTransition``` | constructor: transition: before | before any transition\n| ```beforeTransition``` | transition: before | before specific transition\n|-|-|-|\n| ```afterTransition``` | transition: after | after specific transition\n| ```afterEachTransition``` | constructor: transition: after | after any transition\n| ```beforeState``` | state: before | before specific state\n| ```beforeEachState``` | constructor: state: before | before any state\n\n```typescript\nconst increaseEntropy = ({ transport }: { transport: IObject }) =\u003e {\n    transport[\"entropy\"] = transport[\"entropy\"] === undefined ? 0 : transport[\"entropy\"] + 1;\n};\n\nnew StateMachine\u003cSTATE, TRANSITION, IDATA\u003e(\n    STATE.SOLID, \n    {\n        before: increaseEntropy, // accept single function or array of functions\n        states,\n        after: [ // accept single function or array of functions\n            (transport, from, to) =\u003e {\n                console.log(transport[\"entropy\"]); // 0\n            },\n            increaseEntropy,\n            (transport, from, to) =\u003e {\n                console.log(transport[\"entropy\"]); // 1\n            },\n        ]\n    },\n    transitions \n); \n```\n\nAlso additional aruments can be passed to `transitTo` and `doTransition` methods.\n\n```typescript\nconst handler = (transport, from, to, ...args) =\u003e { console.log(args); }\n\nsm.transitTo(STATE.GAS, 1, null, \"3\"); // [1, null, \"3\"]\n```\n\n## ⏲️⏲️ Pending state\n\n`doTransition` and `transitTo` methods set state machine into pending state.\n\n```typescript\nsm.isPending; // false\n\nsm.transitTo(STATE.GAS)\n  .then(sm =\u003e {\n      sm.isPending; // false\n  });\n\nsm.isPending; // true\n\nsm.transitTo(STATE.LIQUID) // throws: StateMachineError#PENDING_STATE\n```\n\n## 🏜️🌧️ Hydration \\ dehydration\n\nHydration\\dehydration mechanism allows save\\recover current state of state machine.\n\nGetter `dehydrated` returns simple plain object-representation of state machine's state.\n\nMethod `hydrate` accept object returned by `dehydrated` and recover state.\n\n```typescript\nconst currentState = sm.hydrated;\nconsole.log(currentState);\n/* {\n    state: \"GAS\",\n    data: { temperature: 200 },\n    transport: { entropy: 2 }\n} */\n\nsaveToAnywhere(currentState);\n\n\n// ***********\n// later\nconst savedState = getFromAnywhere();\nsm.hydrate(savedState);\n```\n\n## 🚫⚠️ Custom error handling\n\nBy default `ts-fsm` throw errors, but this behaviour mey be changed with `onError` handler function implementation.\n\nEach time, then `ts-fsm` throw an error firstly will fire `onError` handler with error passed with first argument.\n\n`onError` may throw it's custom error, otherwise `ts-fsm`'s error will thrown.\n\nAnyway state machine throw error.\n\n```typescript\nnew StateMachine\u003cSTATE, TRANSITION, IDATA\u003e(\n    STATE.SOLID, \n    states,\n    transitions,\n    {\n        onError(error) {\n            someAwesomeLogger(error);\n            makeSomeAction();\n            throw CustomError(\"Custom Error!\");\n        }\n    }\n); \n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkhraksmamtsov%2Fts-fsm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkhraksmamtsov%2Fts-fsm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkhraksmamtsov%2Fts-fsm/lists"}