https://github.com/cafjs/caf_fsm
Caf.js plugin to implement finite state machines with xstate
https://github.com/cafjs/caf_fsm
Last synced: 5 months ago
JSON representation
Caf.js plugin to implement finite state machines with xstate
- Host: GitHub
- URL: https://github.com/cafjs/caf_fsm
- Owner: cafjs
- Created: 2021-11-30T22:25:18.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2023-04-18T22:34:07.000Z (about 3 years ago)
- Last Synced: 2025-09-26T14:54:38.273Z (9 months ago)
- Language: JavaScript
- Size: 21.5 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGES.md
- Contributing: CONTRIBUTING.md
- License: LICENSE-2.0.txt
Awesome Lists containing this project
README
# Caf.js
Co-design cloud assistants with your web app and IoT devices.
See https://www.cafjs.com
## Create Finite State Machines (FSM) with xstate and Caf.js
[](https://github.com/cafjs/caf_fsm/actions/workflows/push.yml)
Caf.js plugin to integrate the great FSM library `@xstate/fsm` (see https://github.com/statelyai/xstate/tree/main/packages/xstate-fsm)
When we combine state machines with our autonomous cloud assistants we make it easier to remotely control IoT devices, make them feel alive, or synchronize actions on hundreds of thousands of them across the world.
And that's not all. The internal state of a cloud assistant is always externally consistent. If the server crashes and restarts, the recovered state is always what everybody expects.
This means that our state machines are also reliable, and we can count on them to, for example, safely orchestrate service API calls, or track the progress of a request in a sea of microservices.
You can learn more about external consistency in Caf.js [here](https://www.cafjslabs.com/orchestration)
## API
See {@link module:caf_fsm/proxy_fsm} and the docs in https://xstate.js.org/docs/packages/xstate-fsm
An example that configures a traffic light state machine from https://github.com/cafjs/caf_hellofsm.git :
```
async __ca_init__() {
...
this.$.fsm.setCreateMachineMethod('__ca_createMachine__');
...
},
async __ca_createMachine__() {
const updateImpl = (newLight) => {
this.state.light = newLight;
...
this.$.pubsub.publish(this.state.myChannel, newLight);
};
const config = {
id: 'semaphore',
initial: LIGHTS.RED,
states: {
RED: {
on: {
TICK: {
target: LIGHTS.GREEN,
actions: () => updateImpl(LIGHTS.GREEN)
}
}
},
GREEN: {
on: {
TICK: {
target: LIGHTS.YELLOW,
actions: () => updateImpl(LIGHTS.YELLOW)
}
}
},
YELLOW: {
on: {
TICK: {
target: LIGHTS.RED,
actions: () => updateImpl(LIGHTS.RED)
}
}
}
}
};
return [null, {config}];
},
async __ca_pulse__() {
...
await this.tick();
...
},
async tick() {
await this.$.fsm.send(this, TICK);
return [null, this.state];
},
```
By using `await` in `this.$.fsm.send` we force state transition actions to be part of the transaction processing the pulse request.
But this also means that the transition action `updateImpl()` cannot be an `async` function, to ensure it completes within the transaction (`xstate` does not internally `await` actions).
This is not a big concern because actions can always call transactional plugins, like `this.$.pubsub`, or modify CA state.
## Configuration
### ca.json
See {@link module:caf_fsm/plug_ca_fsm}