UNPKG

@tradecrush/next-route-guard

Version:

Convention-based route authentication middleware for Next.js applications

212 lines (205 loc) 8.12 kB
import * as next_server from 'next/server'; import { NextRequest, NextResponse, NextFetchEvent } from 'next/server'; /** * Type definitions for Next Route Guard * * This module defines the TypeScript interfaces and types used throughout the package. */ /** * Type alias for a Next.js middleware function * This is the standard signature for Next.js middleware */ type NextMiddleware = (request: NextRequest) => Promise<NextResponse | undefined> | NextResponse | undefined; /** * Route map for protected and public routes * * This interface represents the structure of the JSON file generated during build time * that contains the lists of protected and public routes based on directory conventions. */ interface RouteMap { /** * Array of paths that are protected and require authentication * These paths will trigger authentication checks when accessed */ protected: string[]; /** * Array of paths that are public and don't require authentication * These paths are freely accessible without authentication */ public: string[]; } /** * Configuration options for creating a route guard middleware * * These options control how the middleware behaves, including how to check * authentication, how to handle unauthenticated requests, and which routes * to protect or exclude. */ interface RouteGuardOptions { /** * Function to determine if a user is authenticated * * This function is called for protected routes to check if the user is authenticated. * You should implement this function based on your authentication system (JWT, cookies, etc.) * * @example * isAuthenticated: (request) => { * const token = request.cookies.get('auth-token')?.value; * return !!token; * } */ isAuthenticated: (request: NextRequest) => Promise<boolean> | boolean; /** * Function to handle unauthenticated requests * * This function is called when a user tries to access a protected route * without being authenticated. The default behavior redirects to /login. * * @default Redirects to /login with the original URL as a 'from' parameter * * @example * onUnauthenticated: (request) => { * if (request.nextUrl.pathname.startsWith('/api/')) { * return new NextResponse( * JSON.stringify({ error: 'Authentication required' }), * { status: 401, headers: { 'Content-Type': 'application/json' } } * ); * } * * // Default login redirect for non-API routes * const url = request.nextUrl.clone(); * url.pathname = '/login'; * url.searchParams.set('from', request.nextUrl.pathname); * return NextResponse.redirect(url); * } */ onUnauthenticated?: (request: NextRequest) => Promise<NextResponse> | NextResponse; /** * Map of protected and public routes * * This is the route map generated during build time by the CLI tools. * It contains the lists of protected and public routes based on directory conventions. * * This must be generated at build time to work with Edge runtime since it can't * scan the filesystem during execution. * * @example * // Import the generated route map * import routeMap from './app/route-map.json'; */ routeMap: RouteMap; /** * Default behavior for routes not explicitly marked in the route map * * When set to true (default), routes are protected unless explicitly marked as public. * When set to false, routes are public unless explicitly marked as protected. * * @default true - Routes are protected by default */ defaultProtected?: boolean; /** * URLs to exclude from authentication checks * * These URLs will bypass the authentication check entirely, regardless of * whether they are in the protected routes list. * * Can be strings with glob-style wildcards or RegExp objects. * * @default ['/api/(.*)'] - Excludes all API routes * * @example * excludeUrls: [ * '/api/(.*)', // All API routes * '/static/(.*)', // Static assets * '/public/(.*)' // Anything under /public/ * ] */ excludeUrls?: (string | RegExp)[]; } /** * Core implementation of Next Route Guard middleware. * This module contains the runtime logic for checking if a route should be protected * and enforcing authentication based on the route map generated at build time. */ /** * Creates a Next.js middleware function that enforces route authentication * based on the directory structure conventions in the app router. * * This is the main entry point for the runtime middleware that checks if a user * is authenticated and handles redirection for protected routes. * * @param options - Configuration options for the middleware * @returns A Next.js middleware function */ declare function createRouteGuardMiddleware(options: RouteGuardOptions): (request: NextRequest) => Promise<NextResponse<unknown>>; /** * A middleware function that takes a request and returns a response. * This is compatible with Next.js middleware system. */ type Middleware = (request: next_server.NextRequest, event?: NextFetchEvent) => Promise<next_server.NextResponse | undefined> | next_server.NextResponse | undefined; /** * A middleware factory that wraps a middleware. * This is used to create reusable middleware components that can be chained together. */ type MiddlewareFactory = (middleware: Middleware) => Middleware; /** * Chain multiple middleware factories together. * * This allows you to compose multiple middleware functions into a single middleware pipeline. * Each middleware in the chain can choose to call the next middleware or short-circuit the chain. * * @param functions - Array of middleware factories to chain together * @param index - Current index in the chain (used internally for recursion) * @returns A middleware function representing the entire chain * * @example * ```ts * // Create middleware factories * const withLogging: MiddlewareFactory = (next) => { * return (request) => { * console.log(`Request: ${request.method} ${request.url}`); * return next(request); * }; * }; * * const withAuth: MiddlewareFactory = (next) => { * return (request) => { * if (!isAuthenticated(request)) { * return NextResponse.redirect('/login'); * } * return next(request); * }; * }; * * // Use the chain * export default function middleware(req: NextRequest, ev: NextFetchEvent) { * return chain([withLogging, withAuth])(req, ev); * } * ``` */ declare function chain(functions: MiddlewareFactory[], index?: number): Middleware; /** * Generate a route map based on the Next.js app directory structure. * * This function analyzes the directory structure to identify routes and their protection status. * It's used by the CLI tools to generate the route map at build time or during development. * * Routes are classified as protected or public based on their directory context: * - Routes inside a "(public)" directory group are marked as public * - Routes inside a "(protected)" directory group are marked as protected * - Routes inherit protection status from their parent directories * - Routes are protected by default if not explicitly marked * * @param appDir - Path to the Next.js app directory * @param publicPatterns - Array of directory name patterns that indicate public routes * @param protectedPatterns - Array of directory name patterns that indicate protected routes * @returns Object containing either the generated route map or an error message */ declare function generateRouteMap(appDir: string, publicPatterns?: string[], protectedPatterns?: string[]): { error?: string; routeMap?: { public: string[]; protected: string[]; }; }; export { type Middleware, type MiddlewareFactory, type NextMiddleware, type RouteGuardOptions, type RouteMap, chain, createRouteGuardMiddleware, generateRouteMap };