FluentState supports a flexible plugin architecture that allows for extending its functionality through plugins. Plugins can be functions or objects that enhance the state machine's capabilities.
- Function Plugins: Functions that either extend the
FluentStateinstance or act as middleware for state transitions. - Object Plugins: Objects with an
installmethod that is called with theFluentStateinstance.
Middleware functions are a special type of plugin that intercept state transitions. They have three parameters: the previous state, the next state, and a transition function. Middleware can block transitions by not calling the transition function.
Plugins are installed using the use method of the FluentState class. The use method checks the type of the plugin and either adds it to the middleware list or calls its install method. The method returns the FluentState instance, allowing for method chaining.
-
Function Plugin:
fluentState.use((fluentState) => { // Extend the fluentState instance }); // Supports async fluentState.use(async (fluentState) => { await initializePlugin(); // Extend the fluentState instance after async call });
-
Middleware Plugin:
fluentState.use((prev, next, transition) => { // Intercept transition if (someCondition) { transition(); // Allow transition } }); // Supports async fluentState.use(async (prev, next, transition) => { // Perform async validation const isValid = await validateTransition(prev, next); if (isValid) { transition(); // Allow transition } });
-
Object Plugin:
const plugin = { install(fluentState) { // Extend the fluentState instance } }; fluentState.use(plugin); // Supports async const plugin = { async install(fluentState) { await initializePlugin(); // Extend the fluentState instance after async call } }; fluentState.use(plugin);
Fluent State ships with the following plugins that provide common functionality. While these plugins are included in the package, you'll need to explicitly implement them using the use() method to add their functionality to your state machine.
- Purpose: Allows intercepting and controlling state transitions by providing a middleware function.
- Usage:
- The plugin is created using the
createTransitionGuardfunction, which takes a handler function as an argument. - The handler function receives the current state, the next state name, and a
proceedfunction. Theproceedfunction must be called to allow the transition to continue.
- The plugin is created using the
- Example:
fluentState.use(createTransitionGuard((prev, next, proceed) => { console.log(`Checking transition: ${prev?.name} → ${next}`); if (next === 'mainApp' && !userHasAccess()) { console.log("Access Denied!"); return; } })); // Async is supported fluentState.use(createTransitionGuard(async (prev, next, proceed) => { console.log(`Checking transition: ${prev?.name} → ${next}`); const hasAccess = await checkUserPermissions(); const isValid = await validateTransition(prev, next); if (hasAccess && isValid) { proceed(); } }));