{"_id":"@depthlabs/nestjs-state-machine","_rev":"2-09c3cad5ef5661906df1817653f69e3b","name":"@depthlabs/nestjs-state-machine","dist-tags":{"latest":"0.0.2"},"versions":{"0.0.1":{"name":"@depthlabs/nestjs-state-machine","version":"0.0.1","description":"Finite State Machine for Nestjs framework","author":{"name":"Tomasz Felczyk"},"license":"MIT","url":"https://github.com/depthlabs-io/nestjs-state-machine","main":"./dist/index.js","types":"./dist/index.d.ts","scripts":{"build":"rimraf -rf dist && tsc -p tsconfig.json","dev":"tsc -p tsconfig.json -w","lint":"eslint 'lib/**/*.ts' --fix","prepublish:npm":"npm run build","publish:npm":"npm publish --access public","prepublish:next":"npm run build","publish:next":"npm publish --access public --tag next","test:e2e":"jest --config ./tests/jest-e2e.json --runInBand","prerelease":"npm run build","release":"release-it"},"dependencies":{"@nestjs/event-emitter":"0.0.2"},"devDependencies":{"@nestjs/common":"7.6.5","@nestjs/core":"7.6.5","@nestjs/platform-express":"7.6.5","@nestjs/testing":"7.6.5","@types/jest":"26.0.20","@types/node":"7.10.8","@typescript-eslint/eslint-plugin":"4.12.0","@typescript-eslint/parser":"4.12.0","eslint":"7.17.0","eslint-config-prettier":"7.1.0","eslint-plugin-import":"2.22.1","husky":"4.3.7","jest":"26.6.3","lint-staged":"10.5.3","prettier":"2.2.1","reflect-metadata":"0.1.13","release-it":"14.2.2","rimraf":"3.0.2","rxjs":"6.6.3","ts-jest":"26.4.4","typescript":"4.1.3"},"peerDependencies":{"@nestjs/common":"^7.0.0","reflect-metadata":"^0.1.12","rxjs":"^6.0.0"},"lint-staged":{"*.ts":["prettier --write"]},"husky":{"hooks":{"pre-commit":"lint-staged"}},"repository":{"type":"git","url":"git+https://github.com/depthlabs-io/nestjs-state-machine.git"},"gitHead":"ae04e0b7142f1443dd42443406aad83360063845","bugs":{"url":"https://github.com/depthlabs-io/nestjs-state-machine/issues"},"homepage":"https://github.com/depthlabs-io/nestjs-state-machine#readme","_id":"@depthlabs/nestjs-state-machine@0.0.1","_nodeVersion":"14.15.4","_npmVersion":"6.14.11","dist":{"integrity":"sha512-eYKpIhYOwtbcKHYF1uoSKDmfm6zsTo6Wa1v2UFHntIGKajtnZT4/nA1SNjjGk6xR/XQzBs+5d4py6ZIUk3+X7g==","shasum":"104caaaba8edbbc3703d6e51c31d0036f298d1a0","tarball":"https://registry.npmjs.org/@depthlabs/nestjs-state-machine/-/nestjs-state-machine-0.0.1.tgz","fileCount":123,"unpackedSize":65190,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf/eFdCRA9TVsSAnZWagAAOn8QAJdiMudsaHoABViip36+\nvBL2yzgsaqvqniEAmPnRTZMDLtsqLhUAKjSmhIbVT5pNohSklxsof2FI/ufc\njCqniKj2j1IWsRFfqNtmgM7/163zbu/XNjM5cgf8LjfQO+5RWQkAFl+Gfeg1\ndPUG+Q7CAc7g0qN5u7fY3wmL9vhsO+8bFLTjqj3sPtd3HjC5GBUtPvnbQS45\npbSNH4z2W5ySef6Wu4vrj9J4qrplC5h0Yn05MqewH1qCKapUW8ycRvOGzZbG\nx+/2H0H07uCC85kAb3zm79A0WtmdouStcwckNlKQS5pRcgpgraGT3CPMpft7\nAFKuEkJS8prfF9z6XgVo45HTOEGMpI7VeDaG4NT3o2UoSLbCqJKIeqZvIsaa\nRHyR9VHw94Bwodrj2Hd31PIK2Bna+cfICAy3w1j66B12RUj0m584SfMPMjaL\n9O1VbwkAwsoo234k4YgRXKBb4LGyO+ErOgPJVQQWGR9p0sNjvC1kokclkZXC\nZWl0csJ58geMK8lWCaYsDFZ2bJZF/2br/kxMBkT+fOGsChUMFEGrdk4RoRjk\neQEkTsOmPshZq6yeQIpPMhBevQ94RWFXC1x6TQDng89IEd6bw1+7mErLAgT3\nIZyNm5N8HbJvUouRqQCtso4v7kfeT0LB86r2CaI8N2rXxBCLM3F5cfKwPnhd\nmmtq\r\n=HVbx\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCUckBQTZVTiPgbryrw74vDBGny4r+wjzbRl8AC6T8vCQIhAPNBHkSLTkCRsr1r27e3OkRV3+iJzInqfzCGnWf+csMF"}]},"_npmUser":{"name":"tomaszfelczyk","email":"tomasz.felczyk@liteweb.io"},"directories":{},"maintainers":[{"name":"tomaszfelczyk","email":"tomasz.felczyk@liteweb.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/nestjs-state-machine_0.0.1_1610473821004_0.7127412782115976"},"_hasShrinkwrap":false},"0.0.2":{"name":"@depthlabs/nestjs-state-machine","version":"0.0.2","description":"Finite State Machine for Nestjs framework","author":{"name":"Tomasz Felczyk"},"license":"MIT","url":"https://github.com/depthlabs-io/nestjs-state-machine","main":"./dist/index.js","types":"./dist/index.d.ts","scripts":{"build":"rimraf -rf dist && tsc -p tsconfig.json","dev":"tsc -p tsconfig.json -w","lint":"eslint 'lib/**/*.ts' --fix","prepublish:npm":"npm run build","publish:npm":"npm publish --access public","prepublish:next":"npm run build","publish:next":"npm publish --access public --tag next","test:e2e":"jest --config ./tests/jest-e2e.json --runInBand","prerelease":"npm run build","release":"release-it"},"dependencies":{"@nestjs/event-emitter":"0.0.2"},"devDependencies":{"@nestjs/common":"7.6.5","@nestjs/core":"7.6.5","@nestjs/platform-express":"7.6.5","@nestjs/testing":"7.6.5","@types/jest":"26.0.20","@types/node":"7.10.8","@typescript-eslint/eslint-plugin":"4.12.0","@typescript-eslint/parser":"4.12.0","eslint":"7.17.0","eslint-config-prettier":"7.1.0","eslint-plugin-import":"2.22.1","husky":"4.3.7","jest":"26.6.3","lint-staged":"10.5.3","prettier":"2.2.1","reflect-metadata":"0.1.13","release-it":"14.2.2","rimraf":"3.0.2","rxjs":"6.6.3","ts-jest":"26.4.4","typescript":"4.1.3"},"peerDependencies":{"@nestjs/common":"^7.0.0","reflect-metadata":"^0.1.12","rxjs":"^6.0.0"},"lint-staged":{"*.ts":["prettier --write"]},"husky":{"hooks":{"pre-commit":"lint-staged"}},"repository":{"type":"git","url":"git+https://github.com/depthlabs-io/nestjs-state-machine.git"},"gitHead":"10b01343d6bd6d103956f7a65daa0a163e6c9efc","bugs":{"url":"https://github.com/depthlabs-io/nestjs-state-machine/issues"},"homepage":"https://github.com/depthlabs-io/nestjs-state-machine#readme","_id":"@depthlabs/nestjs-state-machine@0.0.2","_nodeVersion":"14.15.4","_npmVersion":"6.14.11","dist":{"integrity":"sha512-KWXSU9o/VVwmWbWCE1xiN72Oi9Zaf8r62AQtFTcbCbKcCP5evVCZ4TvgF99SSy9qqh5o5W79bY6K5DlUfLBKXQ==","shasum":"024f1991848cfbb5c0ea8f59639c0981fc57d63a","tarball":"https://registry.npmjs.org/@depthlabs/nestjs-state-machine/-/nestjs-state-machine-0.0.2.tgz","fileCount":124,"unpackedSize":110216,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgAG2zCRA9TVsSAnZWagAAEnYP/36VnjkY0Zx+46HM7+Kc\nMNZ2nAE8OLideuhtJvM77ITt8PqUjcJkoAUu6AYaEjksmD3pPg9sWSjQaQXn\nflGK7EwvLzEhAgSohMMG6isR+aEz21i1Oaj4vuGUXx0mnaSoNfu+Lt++rEtn\nwy7Jy3v9GkXeQwvEb9+v22BhgssJyfswZ8hf0ATtVxrrXTUMkRU73YEzgyhg\nAmju7PoR8y9ET3vu54ARG0Yj0t1PuHpBftTbA8GJtvVuWzfMTjeMPTT62zXw\nyhz1nGo0QPmDFmRqmMO2Y5PA6HTXmCl25gqJ/P8aPhoqXCFYoEhOGgGom0Qa\nSUj5tX2SkdmP6FasRMluh9Ow06jfGTlYOR2azsk8aKdIwH9loYnA6XtsJieX\ntOJIx57h2HZ6gXZpwoAFfDQaUw5JpTcdnDEiI5yQQHpN7e73YlftpiLjTZdw\n3uPOyUcMT1ZZgfdOcJvyLwNmGRzVSqLQdg8GTZuH/hO1KfAV/Dz4g3e4AnaV\n05YOaLmSAtlPJp+Mi8vPVXtXEZpXqv7n7jb14PPoo1gray8hCX7O3j9mZI3N\ny+dcvRnEec3tQyaEWqnrav49UiZAHy6boNpo2PgJiLJ/AQwAGXTrX1rXHwVK\nMhO0T7h3RaOBvRwLwdGrSt9cs/amdP/pNfWAuFx6VXWvREw3KZilSt4j4Hqt\n8V2p\r\n=7Ymc\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDQzj4xmDj3lefiTn6w/CzMZLHGCaf+0bgKCwxirwH8WgIgWKJOWV22Y9rlnXwUnIsHxI5JSFMmlNEStIyPmEMQLQc="}]},"_npmUser":{"name":"tomaszfelczyk","email":"tomasz.felczyk@liteweb.io"},"directories":{},"maintainers":[{"name":"tomaszfelczyk","email":"tomasz.felczyk@liteweb.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/nestjs-state-machine_0.0.2_1610640818190_0.8081850867516087"},"_hasShrinkwrap":false}},"time":{"created":"2021-01-12T17:50:20.778Z","0.0.1":"2021-01-12T17:50:21.159Z","modified":"2022-04-05T03:48:07.981Z","0.0.2":"2021-01-14T16:13:38.564Z"},"maintainers":[{"name":"tomaszfelczyk","email":"tomasz.felczyk@liteweb.io"}],"description":"Finite State Machine for Nestjs framework","homepage":"https://github.com/depthlabs-io/nestjs-state-machine#readme","repository":{"type":"git","url":"git+https://github.com/depthlabs-io/nestjs-state-machine.git"},"author":{"name":"Tomasz Felczyk"},"bugs":{"url":"https://github.com/depthlabs-io/nestjs-state-machine/issues"},"license":"MIT","readme":"## Description\n\nFinite State Machine module for [Nest](https://github.com/nestjs/nest).\n\n## Getting started\n\nInstall package:\n```bash\n$ npm i --save @depthlabs/nestjs-state-machine\n```\n\nFor example, we will map the following state machine:\n\n![example state machine](https://github.com/depthlabs-io/nestjs-state-machine/blob/main/example.jpg?raw=true)\n\n\nAfter installation, import StateMachineModule into your root module with state machine graph configurations:\n```typescript\n// app.module.ts\nimport { StateMachineModule } from '@depthlabs/nestjs-state-machine';\n\n@Module({\n  imports: [\n    // .forRoot takes array of graph configurations\n    StateMachineModule.forRoot([\n        {\n            // Name of graph\n            name: 'project-graph',\n            // Initial state of graph\n            initialState: 'new',\n            // Available states in graph\n            states: [\n                'new',\n                'in-progress',\n                'done'\n            ],\n            // Available transitions in graph\n            transitions: [\n                {\n                    // Name of transistion\n                    name: 'start',\n                    // Source states\n                    from: ['new'],\n                    // Target state of transition\n                    to: 'in-progress',\n                },\n                {\n                    name: 'finish',\n                    from: ['in-progress'],\n                    to: 'done',\n                }\n            ],\n        },\n    ]),\n  ]\n})\nexport class AppModule {}\n```\n\nIt's good idea to define graph, state and transition names in one place e.g.:\n```typescript\n// constants.ts\nexport const PROJECT_GRAPH = 'project-graph'\n\nexport enum ProjectState {\n    NEW = 'new',\n    IN_PROGRESS = 'in-progress',\n    DONE = 'done'\n}\n\nexport enum ProjectTransition {\n    START = 'start',\n    FINISH = 'finish'\n}\n\n```\n\nand then:\n\n```typescript\nimport { StateMachineModule } from '@depthlabs/nestjs-state-machine';\nimport { PROJECT_GRAPH, ProjectState, ProjectTransition } from './constants';\n\n// ...\n\nStateMachineModule.forRoot([\n    {\n        name: PROJECT_GRAPH,\n        initialState: ProjectState.NEW,\n        states: [\n            ProjectState.NEW,\n            ProjectState.IN_PROGRESS,\n            ProjectState.DONE\n        ],\n        transitions: [\n            {\n                name: ProjectTransition.START,\n                from: [ProjectState.NEW],\n                to: ProjectState.IN_PROGRESS,\n            },\n            {\n                name: ProjectTransition.FINISH,\n                from: [ProjectState.IN_PROGRESS],\n                to: ProjectState.DONE,\n            }\n        ],\n    }\n]);\n```\n\nNext, create model or use your exisiting model and decorate property which will be responsible for storing state of model:\n```typescript\n// project.model.ts\nimport { StateStore } from '@depthlabs/nestjs-state-machine';\nimport { PROJECT_GRAPH, ProjectState } from './constants';\n\nexport class Project {\n    name: string;\n\n    @StateStore(PROJECT_GRAPH)\n    state: string = ProjectState.NEW;\n\n}\n```\n`@StateStore` takes one argument with graph name (string). Thanks to this one model can handle more then many graphs: \n```typescript\n@StateStore(PROJECT_GRAPH)\nstate: string = ProjectState.NEW;\n\n@StateStore(PROJECT_STATUS_GRAPH)\nstatus: string = ProjectStatusState.ACTIVE;\n```\n\nAt this point we can create our state machine. First inject `StateMachineFactory` using standard constructor injection:\n\n\n```typescript\nimport { StateMachineFactory } from '@depthlabs/nestjs-state-machine';\n\n// ...\n\nconstructor(\n    private readonly stateMachineFactory: StateMachineFactory,\n) {}\n```\n\nCreate state machine with instance of `Project` model as subject in first argument of factory and with graph name in second.\n```typescript\nconst projectStateMachine = this.stateMachineFactory.create<Project>(project, PROJECT_GRAPH)\n```\n    \n## State Machine methods\n\nApply transition:\n```typescript\n// takes transition name in argument\nawait projectStateMachine.apply(ProjectTransition.START)\n// return void but project.state is now equal ProjectState.IN_PROGRESS\n```\n\nCheck if transition is possible:\n```typescript\n// takes transition name in argument\nawait projectStateMachine.can(ProjectTransition.START)\n// return true or false, can() don't throw Errors\n```\n\nGet all possible transitions:\n```typescript\nawait projectStateMachine.getAvailableTransitions()\n// return TransitionInterface[];\n```\n    \n## Guards\n\nYou can create guards to block transitions.  \nTo declare an `Guard`, decorate a method with the `@OnGuard()` decorator:\n\n```typescript\nimport { GuardEvent, OnGuard } from '@depthlabs/nestjs-state-machine';\nimport { ProjectTransition, PROJECT_GRAPH } from '../constance';\nimport { Project } from '../project.model';\n\nexport class ProjectCantBeNamedBlockmeGuard {\n\n    // Graph name in first argument, transition name in second\n    @OnGuard(PROJECT_GRAPH, ProjectTransition.START)\n    handle(event: GuardEvent<Project>) {\n        // event.subject is our Project instance\n        if (event.subject.name == 'blockme') { // if name isn't allowed for some reasons\n            event.setBlocked('transition-blocked'); // block transition using setBlocked() method\n        }\n    }\n\n}\n```\nThan you need to register `ProjectCantBeNamedBlockmeGuard` in module as provider:\n```typescript\n@Module({\n    imports: [\n        StateMachineModule.forRoot([\n            // ...\n        ])\n    ],\n    providers: [\n        ProjectCantBeNamedBlockmeGuard\n    ],\n})\nexport class AppModule {}\n```\n\nNow, if you create `StateMachine` instance and try to apply `START` transition you will get:\n```typescript\nconst project = new Project()\nproject.name = 'blockme'\n\nconst projectStateMachine = this.stateMachineFactory.create<Project>(project, PROJECT_GRAPH);\n\nawait projectStateMachine.can(ProjectTransition.START)\n// false\n\nawait projectStateMachine.apply(ProjectTransition.START)\n// Throw TransitionBlockedByGuardException with .blockingReasons property that contain ['transition-blocked']\n\nprojectStateMachine.getAvailableTransitions()\n// [] - empty\n```\n\n## Transition Events\n\nYou can create transition event listeners to do additional actions when a state machine operation happened (e.g. sending emails, recalculate)\n\nWhen a state transition is initiated, the events are dispatched in the following order:  \n\n| Order | Event | Decorator | Decorator second argument |\n|-|-|-|-|\n| 1 | LeaveState<br><small><small>(The subject is about to leave a place). | OnLeaveState | State name |\n| 2 | BeginTransition<br><small>(The subject is going through this transition.)</small> | OnBeginTransition | Transition name |\n| 3 | EnterState<br><small>(The subject is about to enter a new place. This event is triggered right before the subject places are updated.)</small> | OnEnterState | State name |\n| 4 | -> Change of state \n| 5 | EnteredState<br><small>(The subject has entered in the places and the marking is updated.)</small> | OnEnteredState | State name |\n| 6 | CompletedTransition<br><small>(The object has completed this transition.)</small> | OnCompletedTransition | Transition name |\n| 7 | AnnounceTransitions<br><small>(Triggered for each transition that now is accessible for the subject.)</small> | OnAnnounceTransitions | State name |\n\n\nExample:\n```typescript\nimport { OnCompletedTransition, CompletedTransitionEvent } from '@depthlabs/nestjs-state-machine';\nimport { ProjectTransition, PROJECT_GRAPH } from '../constance';\nimport { Project } from '../project.model';\n\nexport class NotifyTeamAboutFinishedTask {\n\n    // Graph name in first argument, transition name in second. Third if truem method is async.\n    @OnCompletedTransition(PROJECT_GRAPH, ProjectTransition.FINISH, true)\n    async handle(event: CompletedTransitionEvent<Project>) {\n        // Send emails to all users in team\n    }\n\n}\n```\nand of course:\n```typescript\n@Module({\n    // ...\n    providers: [\n        NotifyTeamAboutFinishedTask\n    ],\n    // ...\n})\nexport class AppModule {}\n```\n\n\n## License\n\nNestjs State Machine is [MIT licensed](LICENSE).","readmeFilename":"README.md"}