Flowstate Per-Request State Management
Flowstate is a Node.js middleware designed for managing and propagating per-request state across a sequence of HTTP requests within an Express or Connect application. It allows developers to implement 'flows' where state is maintained across multiple redirects and user interactions, culminating in a desired outcome. By default, it integrates with existing session middleware, isolating state for specific request sequences rather than global session state. State propagation relies on `return_to` and `state` query/body parameters, which the middleware automatically handles on redirects and exposes via `res.locals` for manual inclusion in views. The current and only stable version is 0.6.0, published in 2017. The package appears to be abandoned, with no releases or significant activity since that time, making it potentially incompatible with modern Node.js and Express versions.
Common errors
-
TypeError: app.use() requires middleware functions but got a [object Undefined]
cause The `flowstate` function was called without being initialized, or an incompatible version of Express is being used.fixEnsure `flowstate()` is called as a function `app.use(flowstate())`. Also verify that your Express version is compatible; given the package's age, very recent Express versions might have breaking changes. -
Error: Failed to find session
cause `flowstate` middleware was invoked without a session middleware being active or correctly configured upstream. Flowstate depends on `req.session` being available.fixAdd a compatible session middleware, such as `express-session`, before `flowstate` in your middleware stack. Example: `app.use(require('express-session')({ secret: '...', resave: false, saveUninitialized: false })); app.use(flowstate());` -
State does not persist across redirects or form submissions.
cause The `return_to` and `state` parameters are not being correctly propagated in your view templates (links, hidden form fields) or the session middleware is misconfigured.fixInspect your rendered HTML to ensure that `return_to` and `state` query parameters (for links) or hidden form fields (for forms) are present and populated with the values from `res.locals.returnTo` and `res.locals.state` (or `res.locals.stateParam`). Also, double-check your `express-session` configuration for proper setup.
Warnings
- breaking The `flowstate` package is abandoned and has not been updated since 2017 (version 0.6.0). It is highly likely to have compatibility issues with modern Node.js versions (e.g., Node.js 16+) and recent major versions of Express. Using it in new projects is strongly discouraged, and existing projects should consider migration.
- gotcha Flowstate relies on a standard session middleware (e.g., `express-session`) to persist state across requests. If a session middleware is not configured and mounted *before* flowstate, the state will not be persisted correctly, leading to unexpected behavior.
- gotcha When rendering views, `flowstate` requires manual propagation of `return_to` and `state` parameters in generated links or form hidden inputs. The middleware exposes these values on `res.locals.returnTo` and `res.locals.state` (or `res.locals.stateParam` in some examples if `res.locals.state` is used by other middleware) which must be explicitly used by your templating engine.
- gotcha This package is CommonJS-only and cannot be directly imported using ES module syntax (`import ... from 'pkg'`). Attempting to use ES module imports will result in errors in environments that enforce ESM.
Install
-
npm install flowstate -
yarn add flowstate -
pnpm add flowstate
Imports
- flowstate
import flowstate from 'flowstate';
const flowstate = require('flowstate'); - FlowstateMiddleware
const flowstate = require('flowstate'); // flowstate() returns the middleware function
Quickstart
const express = require('express');
const session = require('express-session');
const flowstate = require('flowstate');
const app = express();
// Basic session middleware is required for flowstate to persist data.
// In a real application, configure a robust session store.
app.use(session({
secret: process.env.SESSION_SECRET || 'a-very-secret-key',
resave: false,
saveUninitialized: false,
cookie: { secure: false } // Set to true in production with HTTPS
}));
// Set up a simple view engine (e.g., EJS for demonstration)
app.set('view engine', 'ejs');
app.set('views', __dirname + '/views');
app.get('/login', flowstate(), function(req, res, next) {
// Access current state via req.state
const messages = req.state.messages || [];
res.locals.messages = messages;
res.locals.hasMessages = !! messages.length;
// Propagate return_to and state via res.locals for view rendering
// if not already managed by flowstate itself (e.g., if a new state is created)
res.locals.returnTo = res.locals.returnTo || req.query.return_to;
res.locals.stateParam = res.locals.state || req.query.state;
console.log('Current state handle:', res.locals.stateParam);
console.log('Return to:', res.locals.returnTo);
res.render('login', {
title: 'Login',
// Example: Pass state information to the view
flowstateHandle: res.locals.stateParam,
returnTo: res.locals.returnTo
});
});
// Dummy /views/login.ejs content for illustration:
// <form action="/login" method="POST">
// <input type="hidden" name="return_to" value="<%= returnTo %>">
// <input type="hidden" name="state" value="<%= flowstateHandle %>">
// <button type="submit">Login</button>
// </form>
app.listen(3000, () => {
console.log('Server running on http://localhost:3000');
console.log('Try visiting: http://localhost:3000/login?return_to=/dashboard');
});