Jubi Middleware
raw JSON → 1.0.88 verified Sat May 09 auth: no javascript
A lightweight middleware library for Node.js (v1.0.88, actively maintained). It provides a simple and flexible way to compose asynchronous middleware chains, similar to Koa or Express but with a minimal API surface. Key differentiators: zero dependencies, TypeScript-first design with built-in types, and a focus on performance. It is intended for use in HTTP server frameworks or custom middleware pipelines. Current version 1.0.88 is stable; new releases appear monthly.
Common errors
error Error: next is not a function ↓
cause Middleware function signature missing 'next' parameter or not calling next correctly.
fix
Ensure each middleware has (ctx, next) => ... and calls await next() if needed.
error TypeError: ctx.req is undefined ↓
cause Context object does not have 'req' property; you may be using the wrong context shape.
fix
Provide a context with 'req' and 'res' properties as expected by the middleware.
error Cannot find module 'jubi-middleware' ↓
cause Package not installed or incorrect import path.
fix
Run 'npm install jubi-middleware' and use correct import: import { compose } from 'jubi-middleware'.
error UnhandledPromiseRejectionWarning: Error: next() called multiple times ↓
cause Calling next() more than once in a single middleware execution.
fix
Ensure next() is called exactly once (or not at all if terminating the chain).
Warnings
gotcha Middleware functions must call `await next()` to pass control to the next middleware; otherwise the chain stops. ↓
fix Always await next() in middleware unless you intend to terminate the chain.
gotcha The context object (ctx) is mutable and shared across middleware. Mutations persist. ↓
fix Be careful about modifying ctx; use it to pass data (e.g., ctx.user) but avoid unintended side effects.
breaking In v1.0.0, the compose function returned a promise that resolves when the chain completes. In earlier alpha versions, it did not return a promise. ↓
fix Update to v1.0.0+ and await the result of compose() if you relied on synchronous behavior.
Install
npm install jubi-middleware yarn add jubi-middleware pnpm add jubi-middleware Imports
- Middleware wrong
const Middleware = require('jubi-middleware').Middlewarecorrectimport { Middleware } from 'jubi-middleware' - compose wrong
import compose from 'jubi-middleware'correctimport { compose } from 'jubi-middleware' - Context wrong
import { Context } from 'jubi-middleware'correctimport type { Context } from 'jubi-middleware'
Quickstart
import { compose, Middleware } from 'jubi-middleware';
// Define middleware functions
const logger: Middleware = async (ctx, next) => {
console.log('Request:', ctx.req.method, ctx.req.url);
await next();
console.log('Response status:', ctx.res.statusCode);
};
const auth: Middleware = async (ctx, next) => {
const token = ctx.req.headers['authorization'];
if (!token) {
ctx.res.statusCode = 401;
ctx.res.end('Unauthorized');
return;
}
ctx.user = { id: '123' };
await next();
};
const handler: Middleware = async (ctx) => {
ctx.res.end('Hello, ' + (ctx.user?.id ?? 'World'));
};
// Compose and execute
const app = compose([logger, auth, handler]);
const ctx = {
req: { method: 'GET', url: '/', headers: { authorization: 'Bearer secret' } } as any,
res: new (require('stream').Writable)({
write(chunk: any) { console.log('Write:', chunk.toString()); },
end(chunk: any) { console.log('End:', chunk?.toString()); }
}) as any,
};
app(ctx).then(() => console.log('Done')).catch(console.error);