Koa Unless

raw JSON →
1.0.7 verified Thu Apr 23 auth: no javascript abandoned

Koa Unless is a utility for Koa.js applications that allows developers to conditionally skip middleware execution based on various criteria such as HTTP method, request path (string or regex), file extension, or a custom function. The current stable version, 1.0.7, was last published about 9 years ago (March 2017). Given its age, it relies on older Koa.js conventions (e.g., generator functions for middleware) and CommonJS modules. This package's primary differentiator is its simple, declarative API for conditional middleware, though modern Koa applications often achieve similar functionality with explicit `if` statements or newer conditional middleware libraries. The project appears to be abandoned, with the last commit also around 9 years ago, indicating no active development or compatibility updates for newer Koa versions or Node.js features like ESM.

error TypeError: app.use(...) is not a function
cause Attempting to use `unless` on a middleware that hasn't had `unless` assigned to it, or assigning `unless` incorrectly.
fix
Ensure yourMiddleware.unless = require('koa-unless'); is called before applying the conditional logic to app.use.
error SyntaxError: await is only valid in async function
cause Using `koa-unless` with Koa middleware written as generator functions (Koa v1.x style) while also trying to use `async/await` patterns within your application or in other middleware. This package was designed for Koa v1.x, which utilized generator-based middleware, leading to conflicts with modern `async/await` patterns in Koa v2+.
fix
If staying with koa-unless, ensure all integrated middleware (including koa-unless itself, if adapting it) are compatible with either generator functions or async/await consistently. For modern Koa, it's strongly recommended to avoid koa-unless and use native async/await middleware with explicit conditional logic.
error this.url is not a function (or similar property access errors within custom condition)
cause Within a `custom` function passed to `unless`, using an arrow function (`() => { ... }`) for the condition. Arrow functions do not bind their own `this` context, causing `this` to refer to the surrounding lexical scope instead of Koa's `ctx` object.
fix
Change the custom condition to a regular function declaration (e.g., function () { return this.url === '/some-path'; }) to correctly bind this to the Koa context (ctx).
breaking Koa-unless was designed for Koa v1.x, which used generator functions for middleware (e.g., `function *(next)`). Modern Koa (v2.x and above) exclusively uses `async/await` functions. While it might still function for simple cases, full compatibility with the cascading `async/await` middleware pattern is not guaranteed, and unexpected behavior may occur.
fix For new applications, consider reimplementing conditional logic directly within your `async` middleware functions or using more modern conditional middleware solutions compatible with `async/await`. If migrating an existing Koa 1.x application, thoroughly test `koa-unless` integration or refactor conditional logic.
deprecated This package is abandoned; its last publish was approximately 9 years ago. There will be no further updates for bug fixes, security patches, or compatibility with newer Node.js or Koa versions.
fix Evaluate modern alternatives or implement conditional middleware logic natively within your application using standard `if` statements and `async/await`.
gotcha Koa-unless does not ship with TypeScript type definitions. Using it in a TypeScript project will require creating custom declaration files (`.d.ts`) or disabling type checks for its usage, which can reduce type safety and developer experience.
fix Create `koa-unless.d.ts` declaration files or consider alternatives that provide native TypeScript support.
gotcha The `custom` option for conditional logic provides a `this` context that refers to Koa's `ctx` object. However, if the custom function is an arrow function, `this` will not be bound to `ctx`, leading to unexpected behavior.
fix Always use a regular `function` declaration for the `custom` option to ensure `this` correctly refers to the Koa context (e.g., `function () { return this.path === '/api'; }`).
gotcha Due to its CommonJS nature, `koa-unless` cannot be directly `import`ed in an ES module environment without specific Node.js loader configurations or transpilation. Many modern Koa projects are now ESM-first.
fix If your project is ESM-first, you will need to either configure your build system to handle CommonJS `require` statements or use dynamic `import()` for `koa-unless`. The recommended approach is to migrate to a modern, actively maintained conditional middleware solution.
npm install koa-unless
yarn add koa-unless
pnpm add koa-unless

This quickstart demonstrates how to apply `koa-unless` to both custom and third-party Koa middleware, using path and method conditions to skip authentication and static file serving respectively. It also includes basic setup for a Koa application and a static directory.

const Koa = require('koa');
const unless = require('koa-unless');
const serve = require('koa-static');

const app = new Koa();

// A simple authentication middleware
const requiresAuth = async (ctx, next) => {
  if (!ctx.headers.authorization || ctx.headers.authorization !== 'Bearer my-secret-token') {
    ctx.status = 401;
    ctx.body = 'Unauthorized';
    return;
  }
  await next();
};

// Make the authentication middleware conditional
// It will run for all paths EXCEPT '/public' and '/login'
requiresAuth.unless = unless;
app.use(requiresAuth.unless({ path: ['/public', '/login'] }));

// Serve static files from a 'public' directory, unless the method is OPTIONS
const staticMiddleware = serve(__dirname + '/public');
staticMiddleware.unless = unless;
app.use(staticMiddleware.unless({ method: 'OPTIONS' }));

// Example public route, accessible without auth
app.use(async (ctx, next) => {
  if (ctx.path === '/public') {
    ctx.body = 'This is a public page!';
  } else {
    await next();
  }
});

// Example login route, accessible without auth
app.use(async (ctx) => {
  if (ctx.path === '/login') {
    ctx.body = 'Login page, no auth required here.';
  } else if (!ctx.body) {
    // If no middleware has set a body yet (meaning auth passed, or path was /public or /login)
    ctx.body = 'Protected content! You are authorized.';
  }
});

// Create a simple 'public' directory for the static middleware
const fs = require('fs');
const path = require('path');
const publicDirPath = path.join(__dirname, 'public');
if (!fs.existsSync(publicDirPath)) {
  fs.mkdirSync(publicDirPath);
}
fs.writeFileSync(path.join(publicDirPath, 'index.html'), '<h1>Hello from static!</h1>');

app.listen(3000, () => {
  console.log('Koa app listening on port 3000');
  console.log('Try:');
  console.log('  curl http://localhost:3000/public');
  console.log('  curl http://localhost:3000/login');
  console.log('  curl http://localhost:3000/ (will be unauthorized)');
  console.log('  curl -H "Authorization: Bearer my-secret-token" http://localhost:3000/');
});