{"version":3,"sources":["../src/route-guard.ts","../src/index.ts"],"sourcesContent":["/**\n * Core implementation of Next Route Guard middleware.\n * This module contains the runtime logic for checking if a route should be protected\n * and enforcing authentication based on the route map generated at build time.\n */\nimport { type NextRequest, NextResponse } from \"next/server\";\nimport type { RouteGuardOptions, RouteMap } from \"./types\";\n\n/**\n * Default route to redirect to when authentication fails\n */\nconst DEFAULT_LOGIN_ROUTE = '/login';\n\n/**\n * Node in the route trie representing a route segment\n * Used for efficient route matching and protection status lookup\n */\ninterface RouteNode {\n  // Whether this route is protected\n  isProtected?: boolean;\n\n  // Regular children by segment name\n  children: Map<string, RouteNode>;\n\n  // Dynamic child node (for [param] segments)\n  dynamicChild?: RouteNode;\n\n  // Catch-all child (for [...slug] or [[...slug]])\n  catchAllChild?: {\n    node: RouteNode;\n    isOptional: boolean;\n  };\n}\n\n/**\n * Creates a Next.js middleware function that enforces route authentication\n * based on the directory structure conventions in the app router.\n *\n * This is the main entry point for the runtime middleware that checks if a user\n * is authenticated and handles redirection for protected routes.\n *\n * @param options - Configuration options for the middleware\n * @returns A Next.js middleware function\n */\nexport function createRouteGuardMiddleware(options: RouteGuardOptions) {\n  // Set up default options\n  const {\n    isAuthenticated,\n    onUnauthenticated = (request) => {\n      // Default behavior: redirect to login with return URL\n      const url = request.nextUrl.clone();\n      url.pathname = DEFAULT_LOGIN_ROUTE;\n      url.searchParams.set('from', request.nextUrl.pathname);\n      return NextResponse.redirect(url);\n    },\n    routeMap,\n    defaultProtected = true,\n    excludeUrls = ['/api/(.*)']\n  } = options;\n\n  // Build the route trie at initialization time for efficient matching\n  const routeTrie = buildRouteTrie(routeMap);\n\n  // Return the middleware function that will be executed for each request\n  return async function routeGuardMiddleware(request: NextRequest) {\n    const pathname = request.nextUrl.pathname;\n\n    // Skip authentication check for excluded URL patterns (e.g., API routes)\n    for (const pattern of excludeUrls) {\n      const isRegex = pattern instanceof RegExp;\n      // Convert string patterns to regex if needed\n      const regex = isRegex ? pattern : new RegExp(`^${pattern.replace(/\\*/g, '.*')}$`);\n\n      if (regex.test(pathname)) {\n        // Excluded path - allow access without auth check\n        return NextResponse.next();\n      }\n    }\n\n    // Determine if the current route should be protected using the trie\n    const isProtected = matchPath(pathname, routeTrie, defaultProtected);\n\n    // If route is public, allow access without auth check\n    if (!isProtected) {\n      return NextResponse.next();\n    }\n\n    // For protected routes, check if the user is authenticated\n    const isAuthed = await isAuthenticated(request);\n\n    // If authenticated, allow access to the protected route\n    if (isAuthed) {\n      return NextResponse.next();\n    }\n\n    // User is not authenticated for a protected route, handle according to options\n    return onUnauthenticated(request);\n  };\n}\n\n/**\n * Builds a route trie from a route map for efficient path matching\n * This converts the flat route lists into a tree structure for O(k) lookups\n * where k is the depth of the path (number of segments).\n *\n * @param routeMap - Map of protected and public routes\n * @returns Root node of the route trie\n */\nfunction buildRouteTrie(routeMap: RouteMap): RouteNode {\n  // Create the root node\n  const root: RouteNode = {\n    children: new Map()\n  };\n\n  // Add protected routes first\n  for (const route of routeMap.protected) {\n    addRouteToTrie(root, route, true);\n  }\n\n  // Add public routes (these will override protection status for the same paths)\n  for (const route of routeMap.public) {\n    addRouteToTrie(root, route, false);\n  }\n\n  return root;\n}\n\n/**\n * Adds a single route to the trie\n *\n * @param root - Root node of the trie\n * @param route - Route path to add\n * @param isProtected - Whether this route is protected\n */\nfunction addRouteToTrie(root: RouteNode, route: string, isProtected: boolean): void {\n  // Split the path into segments and remove empty segments\n  const segments = route.split('/').filter((segment) => segment !== '');\n\n  let current = root;\n\n  // Process each segment of the path\n  for (let i = 0; i < segments.length; i++) {\n    const segment = segments[i]!;\n\n    // Handle catch-all routes: [...slug] or [[...slug]]\n    if (segment.startsWith('[...') || segment.startsWith('[[...')) {\n      const isOptional = segment.startsWith('[[...');\n\n      // Create a catch-all node if it doesn't exist\n      if (!current.catchAllChild) {\n        current.catchAllChild = {\n          node: { children: new Map() },\n          isOptional\n        };\n      }\n\n      // If this is the last segment, mark protection status\n      if (i === segments.length - 1) {\n        current.catchAllChild.node.isProtected = isProtected;\n      }\n\n      // Continue adding remaining segments even after a catch-all\n      current = current.catchAllChild.node;\n    }\n    // Handle dynamic segments: [param]\n    else if (segment.startsWith('[') && segment.endsWith(']')) {\n      // Create a dynamic node if it doesn't exist\n      if (!current.dynamicChild) {\n        current.dynamicChild = { children: new Map() };\n      }\n\n      // If this is the last segment, mark protection status\n      if (i === segments.length - 1) {\n        current.dynamicChild.isProtected = isProtected;\n      }\n\n      // Move to the dynamic child for next iteration\n      current = current.dynamicChild;\n    }\n    // Handle regular segments\n    else {\n      // Create a regular child if it doesn't exist\n      if (!current.children.has(segment)) {\n        current.children.set(segment, { children: new Map() });\n      }\n\n      // If this is the last segment, mark protection status\n      if (i === segments.length - 1) {\n        const child = current.children.get(segment)!;\n        child.isProtected = isProtected;\n      }\n\n      // Move to the child for next iteration\n      current = current.children.get(segment)!;\n    }\n  }\n\n  // For root routes like '/' that don't have segments\n  if (segments.length === 0) {\n    root.isProtected = isProtected;\n  }\n}\n\n/**\n * Improved visualization function for route tries with correct indentation\n *\n * @param trie - The route trie to visualize\n * @param options - Visualization options\n * @returns A string representation of the trie\n */\nfunction visualizeTrie(\n  trie: RouteNode,\n  options: {\n    indent?: string;\n    path?: string;\n  } = {}\n): string {\n  const { indent = '', path = '' } = options;\n\n  let output = '';\n  const protectionStatus =\n    trie.isProtected !== undefined ? (trie.isProtected ? '🔒 Protected' : '🔓 Public') : '❓ Default';\n\n  // Root node special case\n  if (indent === '') {\n    output += `Root (${protectionStatus})\\n`;\n  }\n\n  // Convert Map entries to array for easier handling\n  const children = Array.from(trie.children.entries());\n\n  // Process regular children\n  children.forEach(([segment, childNode], index) => {\n    const isLastChild = !trie.dynamicChild && !trie.catchAllChild && index === children.length - 1;\n    const childPath = path + '/' + segment;\n    const childStatus =\n      childNode.isProtected !== undefined ? (childNode.isProtected ? '🔒 Protected' : '🔓 Public') : '❓ Default';\n\n    // Use different connectors based on position\n    const connector = isLastChild ? '└── ' : '├── ';\n    output += `${indent}${connector}${segment} (${childStatus})\\n`;\n\n    // Child indentation changes based on whether this is the last child\n    const childIndent = indent + (isLastChild ? '    ' : '│   ');\n\n    // Recurse into child\n    output += visualizeTrie(childNode, {\n      indent: childIndent,\n      path: childPath\n    });\n  });\n\n  // Process dynamic parameter child\n  if (trie.dynamicChild) {\n    const isLastChild = !trie.catchAllChild;\n    const childStatus =\n      trie.dynamicChild.isProtected !== undefined\n        ? trie.dynamicChild.isProtected\n          ? '🔒 Protected'\n          : '🔓 Public'\n        : '❓ Default';\n\n    // Use different connectors based on position\n    const connector = isLastChild ? '└── ' : '├── ';\n    output += `${indent}${connector}[param] (${childStatus})\\n`;\n\n    // Child indentation changes based on whether this is the last child\n    const childIndent = indent + (isLastChild ? '    ' : '│   ');\n\n    // Recurse into dynamic child\n    output += visualizeTrie(trie.dynamicChild, {\n      indent: childIndent,\n      path: path + '/[param]'\n    });\n  }\n\n  // Process catch-all child (always the last child if it exists)\n  if (trie.catchAllChild) {\n    const catchAllType = trie.catchAllChild.isOptional ? '[[...slug]]' : '[...slug]';\n    const optionalText = trie.catchAllChild.isOptional ? ' (optional)' : '';\n    const childStatus =\n      trie.catchAllChild.node.isProtected !== undefined\n        ? trie.catchAllChild.node.isProtected\n          ? '🔒 Protected'\n          : '🔓 Public'\n        : '❓ Default';\n\n    output += `${indent}└── ${catchAllType}${optionalText} (${childStatus})\\n`;\n\n    // Catch-all is always the last child, so no need for vertical lines in indentation\n    const childIndent = indent + '    ';\n\n    // Recurse into catch-all child\n    output += visualizeTrie(trie.catchAllChild.node, {\n      indent: childIndent,\n      path: path + '/' + catchAllType\n    });\n  }\n\n  return output;\n}\n\n/**\n * Match a path against the route trie to determine if it's protected\n *\n * @param path - URL path to check\n * @param routeTrie - Route trie for efficient matching\n * @param defaultProtected - Default protection status\n * @returns true if the path should be protected, false if it's public\n */\nfunction matchPath(path: string, routeTrie: RouteNode, defaultProtected: boolean): boolean {\n  // Clean and normalize the path\n  let cleanPath = (path.split('?')[0] || '').split('#')[0] || '';\n  if (cleanPath.endsWith('/') && cleanPath.length > 1) {\n    cleanPath = cleanPath.slice(0, -1);\n  }\n\n  // Special case for root path\n  if (cleanPath === '/') {\n    return routeTrie.isProtected ?? defaultProtected;\n  }\n\n  // Split path into segments\n  const segments = cleanPath.split('/').filter(Boolean);\n\n  // Use recursive matching with backtracking\n  return findMatch(routeTrie, segments, 0, defaultProtected);\n}\n\n/**\n * Recursively find the best match for segments in the route trie\n *\n * @param node - Current node in the trie\n * @param segments - Path segments\n * @param index - Current segment index\n * @param defaultProtected - Default protection status\n * @returns The protection status for the best matched path\n */\nfunction findMatch(node: RouteNode, segments: string[], index: number, defaultProtected: boolean): boolean {\n  // If we reached the end of the path, return the protection status of this node\n  if (index >= segments.length) {\n    // If this node has an explicit protection status, use it\n    if (node.isProtected !== undefined) {\n      return node.isProtected;\n    }\n    // If this node has an optional catch-all child, use its protection status\n    else if (node.catchAllChild && node.catchAllChild.isOptional) {\n      return node.catchAllChild.node.isProtected ?? defaultProtected;\n    }\n    // Otherwise, use the default\n    else {\n      return defaultProtected;\n    }\n  }\n\n  // Get the current segment\n  const segment = segments[index]!;\n\n  // Check for exact match in children\n  if (node.children.has(segment)) {\n    // Continue matching with the next segment\n    const childNode = node.children.get(segment)!;\n    return findMatch(childNode, segments, index + 1, defaultProtected);\n  }\n  // Check for dynamic parameter match\n  else if (node.dynamicChild) {\n    return findMatch(node.dynamicChild, segments, index + 1, defaultProtected);\n  }\n  // Check for catch-all match\n  else if (node.catchAllChild) {\n    // Handle rest segments after catch-all (if any)\n    if (node.catchAllChild.node && node.catchAllChild.node.children.size > 0) {\n      // Try to find a matching rest segment for the remaining path\n      // We need to check all possible places where the catch-all might end\n\n      // First, let's try the most specific match: check if any segments after the catch-all\n      // match the remainder of our path\n      const tryRestSegmentMatch = (startIndex: number): boolean | null => {\n        // Make sure we have segments remaining\n        if (startIndex >= segments.length) {\n          return null;\n        }\n\n        const remainingSegment = segments[startIndex]!;\n\n        // If we have a match in the rest segments, follow that path\n        if (node.catchAllChild?.node.children?.has(remainingSegment)) {\n          const restNode = node.catchAllChild.node.children.get(remainingSegment)!;\n          return findMatch(restNode, segments, startIndex + 1, defaultProtected);\n        }\n\n        return null;\n      };\n\n      // Try each possible ending position for the catch-all\n      for (let i = index; i < segments.length; i++) {\n        const result = tryRestSegmentMatch(i);\n        if (result !== null) {\n          return result;\n        }\n      }\n    }\n\n    // If no rest segments matched or if there are no rest segments,\n    // use the catch-all node's protection status\n    return node.catchAllChild.node.isProtected ?? defaultProtected;\n  }\n\n  // No match found, use default protection status\n  return defaultProtected;\n}\n","/**\n * Next Route Guard - Convention-based route authentication middleware for Next.js\n *\n * This package provides a simple way to protect routes in Next.js applications\n * based on directory naming conventions. It uses Next.js Edge middleware to\n * perform authentication checks at runtime based on a route map generated\n * during build time.\n *\n * @packageDocumentation\n */\n\nexport { createRouteGuardMiddleware } from './route-guard';\nexport type { RouteGuardOptions, NextMiddleware, RouteMap } from './types';\n\nimport type { NextFetchEvent } from 'next/server';\n\n/**\n * A middleware function that takes a request and returns a response.\n * This is compatible with Next.js middleware system.\n */\nexport type Middleware = (\n  request: import('next/server').NextRequest,\n  event?: NextFetchEvent\n) => Promise<import('next/server').NextResponse | undefined> | import('next/server').NextResponse | undefined;\n\n/**\n * A middleware factory that wraps a middleware.\n * This is used to create reusable middleware components that can be chained together.\n */\nexport type MiddlewareFactory = (middleware: Middleware) => Middleware;\n\n/**\n * Chain multiple middleware factories together.\n *\n * This allows you to compose multiple middleware functions into a single middleware pipeline.\n * Each middleware in the chain can choose to call the next middleware or short-circuit the chain.\n *\n * @param functions - Array of middleware factories to chain together\n * @param index - Current index in the chain (used internally for recursion)\n * @returns A middleware function representing the entire chain\n *\n * @example\n * ```ts\n * // Create middleware factories\n * const withLogging: MiddlewareFactory = (next) => {\n *   return (request) => {\n *     console.log(`Request: ${request.method} ${request.url}`);\n *     return next(request);\n *   };\n * };\n *\n * const withAuth: MiddlewareFactory = (next) => {\n *   return (request) => {\n *     if (!isAuthenticated(request)) {\n *       return NextResponse.redirect('/login');\n *     }\n *     return next(request);\n *   };\n * };\n *\n * // Use the chain\n * export default function middleware(req: NextRequest, ev: NextFetchEvent) {\n *   return chain([withLogging, withAuth])(req, ev);\n * }\n * ```\n */\nexport function chain(functions: MiddlewareFactory[], index = 0): Middleware {\n  const current = functions[index];\n\n  if (current) {\n    // Get the next middleware in the chain\n    const next = chain(functions, index + 1);\n\n    // Apply the current middleware factory to the next middleware\n    return current(next);\n  }\n\n  // Base case: we've reached the end of the chain\n  // Return a middleware that just returns undefined (letting Next.js continue to the actual route)\n  return () => undefined;\n}\n\n/**\n * Generate a route map based on the Next.js app directory structure.\n *\n * This function analyzes the directory structure to identify routes and their protection status.\n * It's used by the CLI tools to generate the route map at build time or during development.\n *\n * Routes are classified as protected or public based on their directory context:\n * - Routes inside a \"(public)\" directory group are marked as public\n * - Routes inside a \"(protected)\" directory group are marked as protected\n * - Routes inherit protection status from their parent directories\n * - Routes are protected by default if not explicitly marked\n *\n * @param appDir - Path to the Next.js app directory\n * @param publicPatterns - Array of directory name patterns that indicate public routes\n * @param protectedPatterns - Array of directory name patterns that indicate protected routes\n * @returns Object containing either the generated route map or an error message\n */\nexport function generateRouteMap(\n  appDir: string,\n  publicPatterns: string[] = ['(public)'],\n  protectedPatterns: string[] = ['(protected)']\n): { error?: string; routeMap?: { public: string[]; protected: string[] } } {\n  // Make sure we're running in a Node.js environment\n  if (typeof process === 'undefined' || !process.env) {\n    return { error: 'This function can only be used in a Node.js environment' };\n  }\n\n  try {\n    // We need to dynamically import these modules since they're not available in Edge runtime\n    // This function is only intended to be used during build time or development\n    // eslint-disable-next-line @typescript-eslint/no-require-imports\n    const fs = require('fs');\n    // eslint-disable-next-line @typescript-eslint/no-require-imports\n    const path = require('path');\n\n    // Initialize the route map\n    const routeMap: { public: string[]; protected: string[] } = {\n      public: [],\n      protected: []\n    };\n\n    /**\n     * Recursively scans the directory structure to identify routes\n     *\n     * @param dirPath - Current directory path being scanned\n     * @param segments - URL segments collected so far (for constructing the route path)\n     * @param groups - Route groups encountered in the current path\n     */\n    function scanDirectory(dirPath: string, segments: string[] = [], groups: string[] = []) {\n      // Skip if directory doesn't exist\n      if (!fs.existsSync(dirPath)) return;\n\n      // Read directory contents\n      const items = fs.readdirSync(dirPath);\n\n      // Process each item in the directory\n      for (const item of items) {\n        const itemPath = path.join(dirPath, item);\n        const stat = fs.statSync(itemPath);\n\n        if (stat.isDirectory()) {\n          // Skip special directories like node_modules\n          if (item === 'node_modules' || item.startsWith('.')) continue;\n\n          // Check if this is a route group (enclosed in parentheses)\n          const isRouteGroup = item.startsWith('(') && item.endsWith(')');\n          const newGroups = [...groups];\n          const newSegments = [...segments];\n\n          if (isRouteGroup) {\n            // Route groups are organizational only and don't affect the URL path\n            newGroups.push(item);\n          } else {\n            // Regular directories become part of the URL path\n            newSegments.push(item);\n          }\n\n          // Continue scanning subdirectories\n          scanDirectory(itemPath, newSegments, newGroups);\n        } else if (\n          stat.isFile() &&\n          (item === 'page.js' || item === 'page.tsx' || item === 'page.jsx' || item === 'page.ts')\n        ) {\n          // Found a page file, which represents a route endpoint\n          const route = '/' + segments.join('/');\n          const routePath = route === '//' ? '/' : route;\n\n          // Determine if the route is protected based on its group context\n          // Default to protected unless explicitly marked as public\n          let isProtected = true;\n\n          // Check route groups to determine protection status\n          // Process groups in reverse order to prioritize the innermost (most specific) group\n          // This behavior was enhanced in v0.2.2 to allow nested groups to override parent groups\n          // For example, (public)/docs/(protected)/admin would make /docs/admin protected\n          // despite being in a public parent group\n          for (let i = groups.length - 1; i >= 0; i--) {\n            const group = groups[i];\n            if (group && publicPatterns.includes(group)) {\n              isProtected = false;\n              break;\n            } else if (group && protectedPatterns.includes(group)) {\n              isProtected = true;\n              break;\n            }\n          }\n\n          // Add to the appropriate category in the route map\n          if (isProtected) {\n            routeMap.protected.push(routePath);\n          } else {\n            routeMap.public.push(routePath);\n          }\n        }\n      }\n    }\n\n    // Start the directory scan from the app root\n    scanDirectory(appDir);\n\n    // Sort the routes for better readability and consistency\n    routeMap.protected.sort();\n    routeMap.public.sort();\n\n    return { routeMap };\n  } catch (error) {\n    return { error: error instanceof Error ? error.message : String(error) };\n  }\n}\n"],"mappings":"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","names":["_a","_b","scanDirectory"]}