@nextrush/router 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/router.ts","../src/radix-tree.ts"],"sourcesContent":["/**\n * @nextrush/router - Router Implementation\n *\n * High-performance router using a segment trie for route matching.\n * Routes are keyed by full path segments (e.g. \"users\", \":id\"), not by\n * individual characters — this is a segment-based trie, not a compressed\n * radix tree. Supports parameters, wildcards, and method-based routing.\n *\n * @packageDocumentation\n */\n\nimport {\n HTTP_METHODS,\n type Context,\n type HttpMethod,\n type Middleware,\n type RouteHandler,\n type RouteMatch,\n type RouterOptions,\n} from '@nextrush/types';\nimport {\n compileExecutor,\n createNode,\n NodeType,\n NOOP_NEXT,\n parseSegments,\n type HandlerEntry,\n type RadixNode,\n} from './radix-tree';\n\n/** Frozen empty params for static routes — avoids allocation per request */\nconst EMPTY_PARAMS: Record<string, string> = Object.freeze(\n Object.create(null) as Record<string, string>\n);\n\n/**\n * Router class — high-performance segment trie router\n *\n * Routes are indexed by path segment, giving O(d) lookup where d is the\n * number of segments. Static routes are additionally stored in a hash map\n * for O(1) fast-path lookup.\n *\n * @example\n * ```typescript\n * const router = createRouter();\n *\n * router.get('/users', listUsers);\n * router.get('/users/:id', getUser);\n * router.post('/users', createUser);\n *\n * app.use(router.routes());\n * ```\n */\nexport class Router {\n private readonly root: RadixNode;\n private readonly opts: Required<RouterOptions>;\n private readonly routerMiddleware: Middleware[] = [];\n\n /**\n * Static route hash map for O(1) lookup.\n * Key: \"METHOD path\" (e.g. \"GET /users\"), Value: HandlerEntry\n */\n private readonly staticRoutes = new Map<string, HandlerEntry>();\n\n /** Whether any routes have params or wildcards (disables static-only fast path) */\n private hasParamRoutes = false;\n\n constructor(options: RouterOptions = {}) {\n this.root = createNode('');\n this.opts = {\n prefix: options.prefix ?? '',\n caseSensitive: options.caseSensitive ?? false,\n strict: options.strict ?? false,\n };\n }\n\n /**\n * Normalize path based on router options\n */\n private normalizePath(path: string): string {\n // Handle prefix with trailing slash and path with leading slash\n let prefix = this.opts.prefix;\n if (prefix.endsWith('/') && path.startsWith('/')) {\n prefix = prefix.slice(0, -1);\n }\n\n let normalized = prefix + path;\n\n // Fast-path: skip regex when no double slashes (99%+ of requests)\n if (normalized.includes('//')) {\n normalized = normalized.replace(/\\/+/g, '/');\n }\n\n // For non-strict mode during registration, remove trailing slash\n if (!this.opts.strict && normalized.length > 1 && normalized.endsWith('/')) {\n normalized = normalized.slice(0, -1);\n }\n\n return normalized.startsWith('/') ? normalized : '/' + normalized;\n }\n\n /**\n * Add a route to the radix tree\n */\n private addRoute(\n method: HttpMethod,\n path: string,\n handlers: RouteHandler[],\n middleware: Middleware[] = []\n ): void {\n const normalized = this.normalizePath(path);\n const segments = parseSegments(normalized, this.opts.caseSensitive);\n\n let node = this.root;\n\n for (const seg of segments) {\n if (seg.type === NodeType.PARAM) {\n if (!node.paramChild) {\n node.paramChild = createNode(seg.segment, NodeType.PARAM);\n node.paramChild.paramName = seg.paramName;\n } else if (node.paramChild.paramName !== seg.paramName) {\n // Warn about param name collision — same position, different names\n // This helps catch accidental mismatches like :id vs :userId\n if (typeof process !== 'undefined' && process.env.NODE_ENV !== 'production') {\n const existing = node.paramChild.paramName;\n console.warn(\n `[nextrush:router] Route param name conflict at \"${normalized}\": ` +\n `\":${String(seg.paramName)}\" conflicts with existing \":${String(existing)}\". ` +\n `The existing name \":${String(existing)}\" will be used.`\n );\n }\n }\n node = node.paramChild;\n } else if (seg.type === NodeType.WILDCARD) {\n node.wildcardChild ??= createNode('*', NodeType.WILDCARD);\n node = node.wildcardChild;\n break; // Wildcard must be last\n } else {\n const key = seg.segment;\n let child = node.children.get(key);\n if (!child) {\n child = createNode(seg.segment, NodeType.STATIC);\n node.children.set(key, child);\n }\n node = child;\n }\n }\n\n // Combine multiple handlers into single handler with inline middleware\n const combinedMiddleware = [...middleware];\n const finalHandler = handlers[handlers.length - 1];\n\n if (!finalHandler) {\n throw new Error('At least one handler is required');\n }\n\n const inlineMiddleware = handlers.slice(0, -1);\n\n // Add inline middleware (handlers before the last one)\n for (const mw of inlineMiddleware) {\n combinedMiddleware.push(mw);\n }\n\n // Pre-compile executor at registration time (not per-request!)\n const executor = compileExecutor(finalHandler, combinedMiddleware);\n\n const entry: HandlerEntry = {\n handler: finalHandler,\n middleware: combinedMiddleware,\n executor,\n };\n\n // Detect duplicate route registration\n if (node.handlers.has(method)) {\n throw new Error(\n `Route conflict: ${method} ${normalized} is already registered. ` +\n 'Remove the duplicate or use a different path.'\n );\n }\n\n node.handlers.set(method, entry);\n\n // Populate static route hash map for O(1) lookup\n const hasParams = segments.some(\n (s) => s.type === NodeType.PARAM || s.type === NodeType.WILDCARD\n );\n if (hasParams) {\n this.hasParamRoutes = true;\n } else {\n const normalizedKey = this.opts.caseSensitive ? normalized : normalized.toLowerCase();\n this.staticRoutes.set(`${method} ${normalizedKey}`, entry);\n }\n }\n\n // ===========================================================================\n // HTTP Method Shortcuts\n // ===========================================================================\n\n get(path: string, ...handlers: RouteHandler[]): this {\n this.addRoute('GET', path, handlers);\n return this;\n }\n\n post(path: string, ...handlers: RouteHandler[]): this {\n this.addRoute('POST', path, handlers);\n return this;\n }\n\n put(path: string, ...handlers: RouteHandler[]): this {\n this.addRoute('PUT', path, handlers);\n return this;\n }\n\n delete(path: string, ...handlers: RouteHandler[]): this {\n this.addRoute('DELETE', path, handlers);\n return this;\n }\n\n patch(path: string, ...handlers: RouteHandler[]): this {\n this.addRoute('PATCH', path, handlers);\n return this;\n }\n\n head(path: string, ...handlers: RouteHandler[]): this {\n this.addRoute('HEAD', path, handlers);\n return this;\n }\n\n options(path: string, ...handlers: RouteHandler[]): this {\n this.addRoute('OPTIONS', path, handlers);\n return this;\n }\n\n all(path: string, ...handlers: RouteHandler[]): this {\n for (const method of HTTP_METHODS) {\n this.addRoute(method, path, handlers);\n }\n return this;\n }\n\n route(method: HttpMethod, path: string, ...handlers: RouteHandler[]): this {\n this.addRoute(method, path, handlers);\n return this;\n }\n\n /**\n * Register a redirect route from one path to another\n *\n * @param from - Source path to redirect from\n * @param to - Target path or URL to redirect to\n * @param status - HTTP status code (default: 301 permanent redirect)\n * @returns this for chaining\n *\n * @example\n * ```typescript\n * // Permanent redirect (301)\n * router.redirect('/old-page', '/new-page');\n *\n * // Temporary redirect (302)\n * router.redirect('/temp', '/destination', 302);\n *\n * // Redirect to external URL\n * router.redirect('/docs', 'https://docs.example.com');\n *\n * // With parameters - redirects /users/:id to /profiles/:id\n * router.redirect('/users/:id', '/profiles/:id');\n * ```\n */\n redirect(from: string, to: string, status: 301 | 302 | 303 | 307 | 308 = 301): this {\n // Precompile the target template at registration time.\n // If `to` contains route-style `:param` placeholders, build a parts\n // array of alternating literal / param-name entries so the per-request\n // handler can substitute without sorting or scanning the string.\n //\n // Only `:` preceded by `/` or at position 0 is a param slot. This\n // avoids misinterpreting `https://` or other non-route colons.\n let compiledParts: string[] | undefined;\n\n {\n const parts: string[] = [];\n let pos = 0;\n let found = false;\n\n while (pos < to.length) {\n // Find next `:` that looks like a route param\n let idx = -1;\n for (let i = pos; i < to.length; i++) {\n if (\n to[i] === ':' &&\n (i === 0 || to[i - 1] === '/') &&\n i + 1 < to.length &&\n to[i + 1] !== '/'\n ) {\n idx = i;\n break;\n }\n }\n if (idx === -1) break;\n\n found = true;\n parts.push(to.slice(pos, idx)); // literal before ':'\n const end = to.indexOf('/', idx + 1);\n if (end === -1) {\n parts.push(to.slice(idx + 1)); // param name (rest of string)\n pos = to.length;\n } else {\n parts.push(to.slice(idx + 1, end)); // param name\n pos = end;\n }\n }\n\n if (found) {\n parts.push(to.slice(pos)); // trailing literal\n compiledParts = parts;\n }\n }\n\n const redirectHandler: RouteHandler = (ctx: Context) => {\n let targetPath: string;\n\n if (compiledParts) {\n // Fast path: build from precompiled template\n const params = ctx.params;\n const parts = compiledParts;\n const head = parts[0];\n if (head === undefined) {\n targetPath = to;\n } else {\n let result = head;\n for (let i = 1; i < parts.length - 1; i += 2) {\n const paramKey = parts[i];\n const tail = parts[i + 1];\n if (paramKey === undefined || tail === undefined) break;\n result += (params[paramKey] ?? '') + tail;\n }\n targetPath = result;\n }\n } else {\n targetPath = to;\n }\n\n ctx.status = status;\n ctx.set('Location', targetPath);\n ctx.body = '';\n };\n\n // Register for common methods. 307/308 preserve the original method,\n // so register all standard methods for those status codes.\n this.addRoute('GET', from, [redirectHandler]);\n this.addRoute('HEAD', from, [redirectHandler]);\n if (status === 307 || status === 308) {\n this.addRoute('POST', from, [redirectHandler]);\n this.addRoute('PUT', from, [redirectHandler]);\n this.addRoute('PATCH', from, [redirectHandler]);\n this.addRoute('DELETE', from, [redirectHandler]);\n }\n\n return this;\n }\n\n // ===========================================================================\n // Router Composition\n // ===========================================================================\n\n use(pathOrMiddleware: string | Middleware | Router, routerOrUndefined?: Router): this {\n if (typeof pathOrMiddleware === 'function') {\n // Middleware function\n this.routerMiddleware.push(pathOrMiddleware);\n } else if (typeof pathOrMiddleware === 'string' && routerOrUndefined instanceof Router) {\n // Mount sub-router at path\n this.mountRouter(pathOrMiddleware, routerOrUndefined);\n } else if (typeof pathOrMiddleware === 'string') {\n // String prefix without a Router — unsupported, throw clear error\n throw new Error(\n `router.use('${pathOrMiddleware}', ...) requires a Router instance as the second argument. ` +\n 'Use router.group(prefix, callback) for prefix-scoped middleware, ' +\n 'or router.use(middlewareFn) to register middleware without a prefix.'\n );\n } else if (pathOrMiddleware instanceof Router) {\n // Mount router at root\n this.mountRouter('', pathOrMiddleware);\n }\n return this;\n }\n\n /**\n * Mount a sub-router at a path prefix (Hono-style)\n *\n * This is the explicit API for mounting sub-routers.\n * Equivalent to `router.use(path, subRouter)` but more semantic.\n *\n * @param path - Path prefix for the sub-router\n * @param router - Router instance to mount\n * @returns this for chaining\n *\n * @example\n * ```typescript\n * // Create modular routers\n * const users = createRouter();\n * users.get('/', listUsers);\n * users.get('/:id', getUser);\n *\n * const posts = createRouter();\n * posts.get('/', listPosts);\n *\n * // Mount sub-routers\n * const api = createRouter();\n * api.mount('/users', users);\n * api.mount('/posts', posts);\n *\n * // Or use on main router\n * const router = createRouter();\n * router.mount('/api', api);\n *\n * app.use(router.routes());\n * ```\n */\n mount(path: string, router: Router): this {\n this.mountRouter(path, router);\n return this;\n }\n\n /**\n * Mount a sub-router (internal)\n *\n * Carries the sub-router's own `routerMiddleware` forward so that\n * `subrouter.use(mw)` middleware applies to every copied route.\n */\n private mountRouter(prefix: string, router: Router): void {\n this.copyRoutes(router.root, prefix, [], router.routerMiddleware);\n }\n\n /**\n * Recursively copy routes from another router\n */\n private copyRoutes(\n node: RadixNode,\n prefix: string,\n segments: string[],\n subRouterMiddleware: Middleware[]\n ): void {\n // Copy handlers at this node\n for (const [method, entry] of node.handlers) {\n const path = prefix + '/' + segments.join('/');\n // Prepend sub-router middleware so it runs before the route's own middleware\n const combined =\n subRouterMiddleware.length > 0\n ? [...subRouterMiddleware, ...entry.middleware]\n : entry.middleware;\n this.addRoute(method, path || '/', [entry.handler], combined);\n }\n\n // Copy static children\n for (const [, child] of node.children) {\n this.copyRoutes(child, prefix, [...segments, child.segment], subRouterMiddleware);\n }\n\n // Copy param child\n if (node.paramChild) {\n this.copyRoutes(\n node.paramChild,\n prefix,\n [...segments, node.paramChild.segment],\n subRouterMiddleware\n );\n }\n\n // Copy wildcard child\n if (node.wildcardChild) {\n this.copyRoutes(node.wildcardChild, prefix, [...segments, '*'], subRouterMiddleware);\n }\n }\n\n // ===========================================================================\n // Route Matching\n // ===========================================================================\n\n /**\n * Match a route and return handler + params\n */\n match(method: HttpMethod, path: string): RouteMatch | null {\n const isCaseInsensitive = !this.opts.caseSensitive;\n let normalized = isCaseInsensitive ? path.toLowerCase() : path;\n\n // Fast-path: skip regex when no double slashes (99%+ of requests)\n if (normalized.includes('//')) {\n normalized = normalized.replace(/\\/+/g, '/');\n }\n\n // For strict mode, keep trailing slash; otherwise remove it\n if (!this.opts.strict && normalized.length > 1 && normalized.endsWith('/')) {\n normalized = normalized.slice(0, -1);\n }\n\n // FAST PATH: O(1) static route lookup (no tree traversal)\n // For static routes, trailing slash is irrelevant — always strip for lookup\n const staticKey =\n normalized.length > 1 && normalized.endsWith('/')\n ? `${method} ${normalized.slice(0, -1)}`\n : `${method} ${normalized}`;\n const staticEntry = this.staticRoutes.get(staticKey);\n if (staticEntry) {\n return {\n handler: staticEntry.handler,\n params: EMPTY_PARAMS,\n middleware: this.routerMiddleware,\n executor: staticEntry.executor,\n };\n }\n\n // Only walk tree if we have param/wildcard routes\n if (!this.hasParamRoutes) return null;\n\n // Use index-based path scanning instead of split('/').filter(Boolean)\n const params: Record<string, string> = {};\n\n // For case-insensitive mode, preserve original-case path for param values\n let originalPath: string | undefined;\n if (isCaseInsensitive) {\n originalPath = path;\n if (originalPath.includes('//')) {\n originalPath = originalPath.replace(/\\/+/g, '/');\n }\n if (!this.opts.strict && originalPath.length > 1 && originalPath.endsWith('/')) {\n originalPath = originalPath.slice(0, -1);\n }\n }\n\n const result = this.matchNodeIndexed(\n this.root,\n normalized,\n 1, // Start after leading '/'\n params,\n method,\n originalPath\n );\n if (!result) return null;\n\n // Check if any params were actually set\n let hasParams = false;\n for (const key of Object.keys(params)) {\n if (params[key] === undefined) {\n Reflect.deleteProperty(params, key);\n } else {\n hasParams = true;\n }\n }\n\n return {\n handler: result.handler,\n params: hasParams ? params : EMPTY_PARAMS,\n middleware: this.routerMiddleware,\n executor: result.executor,\n };\n }\n\n /**\n * Extract the next segment from path at given position without allocating arrays.\n * Returns [segment, nextIndex] where nextIndex is position after the trailing '/'.\n */\n private extractSegment(path: string, start: number): [segment: string, nextIndex: number] {\n const slashPos = path.indexOf('/', start);\n if (slashPos === -1) {\n return [path.slice(start), path.length];\n }\n return [path.slice(start, slashPos), slashPos + 1];\n }\n\n /**\n * Index-based recursive node matching (avoids array allocation)\n */\n private matchNodeIndexed(\n node: RadixNode,\n path: string,\n pos: number,\n params: Record<string, string>,\n method: HttpMethod,\n originalPath?: string\n ): HandlerEntry | null {\n // Reached end of path\n if (pos >= path.length) {\n return node.handlers.get(method) ?? null;\n }\n\n const [segment, nextPos] = this.extractSegment(path, pos);\n if (segment === '') return node.handlers.get(method) ?? null;\n\n // Try static match first (most specific)\n const staticChild = node.children.get(segment);\n if (staticChild) {\n const result = this.matchNodeIndexed(\n staticChild,\n path,\n nextPos,\n params,\n method,\n originalPath\n );\n if (result) return result;\n }\n\n // Try parameter match — use original-case segment for param value\n if (node.paramChild) {\n const paramName = node.paramChild.paramName;\n if (paramName === undefined) return null;\n if (originalPath) {\n const [origSeg] = this.extractSegment(originalPath, pos);\n params[paramName] = origSeg;\n } else {\n params[paramName] = segment;\n }\n const result = this.matchNodeIndexed(\n node.paramChild,\n path,\n nextPos,\n params,\n method,\n originalPath\n );\n if (result) return result;\n Reflect.deleteProperty(params, paramName);\n }\n\n // Try wildcard match (catches remaining path) — use original-case path\n if (node.wildcardChild) {\n const src = originalPath ?? path;\n params['*'] = src.slice(pos);\n return node.wildcardChild.handlers.get(method) ?? null;\n }\n\n return null;\n }\n\n // ===========================================================================\n // Middleware Generation\n // ===========================================================================\n\n /**\n * Get routes middleware function\n * Mount this on the application\n *\n * @example\n * ```typescript\n * app.use(router.routes());\n * ```\n */\n routes(): Middleware {\n // Seal router-level middleware into route executors at routes() call time\n // This avoids per-request closure creation\n const hasRouterMiddleware = this.routerMiddleware.length > 0;\n if (hasRouterMiddleware) {\n this.sealRouterMiddleware();\n }\n\n return async (ctx: Context, next?: () => Promise<void>): Promise<void> => {\n const match = this.match(ctx.method, ctx.path);\n\n if (!match) {\n // No route matched — set 404 so allowedMethods() and notFoundHandler() can act\n ctx.status = 404;\n if (next) await next();\n return;\n }\n\n // Set params on context\n ctx.params = match.params;\n\n // Use pre-compiled executor (includes router middleware if any)\n if (match.executor) {\n await match.executor(ctx);\n return;\n }\n\n // Fallback: No executor (shouldn't happen but be safe)\n await match.handler(ctx, NOOP_NEXT);\n };\n }\n\n /**\n * Re-compile all route executors to include router-level middleware.\n * Called once when routes() is invoked, not per-request.\n */\n private sealRouterMiddleware(): void {\n const routerMw = [...this.routerMiddleware];\n\n // Walk the tree and re-compile every handler entry\n const walk = (node: RadixNode): void => {\n for (const [method, entry] of node.handlers) {\n const combinedMw = [...routerMw, ...entry.middleware];\n entry.executor = compileExecutor(entry.handler, combinedMw);\n node.handlers.set(method, entry);\n }\n for (const [, child] of node.children) {\n walk(child);\n }\n if (node.paramChild) walk(node.paramChild);\n if (node.wildcardChild) walk(node.wildcardChild);\n };\n\n walk(this.root);\n\n // Also update static route entries\n for (const [key, entry] of this.staticRoutes) {\n const combinedMw = [...routerMw, ...entry.middleware];\n entry.executor = compileExecutor(entry.handler, combinedMw);\n this.staticRoutes.set(key, entry);\n }\n }\n\n /**\n * Generate allowed methods middleware\n * Responds to OPTIONS and sets Allow header\n */\n allowedMethods(): Middleware {\n return async (ctx: Context, next?: () => Promise<void>): Promise<void> => {\n if (next) {\n await next();\n }\n\n if (ctx.status !== 404) return;\n\n // Single tree walk to find all allowed methods instead of N×match()\n const allowed = this.findAllowedMethods(ctx.path);\n\n if (allowed.length === 0) return;\n\n const allowHeader = allowed.join(', ');\n\n // If OPTIONS request, respond with allowed methods\n if (ctx.method === 'OPTIONS') {\n ctx.status = 200;\n ctx.set('Allow', allowHeader);\n ctx.body = '';\n return;\n }\n\n // Otherwise, return 405 Method Not Allowed\n ctx.status = 405;\n ctx.set('Allow', allowHeader);\n };\n }\n\n /**\n * Find all HTTP methods registered for a given path via single tree walk\n * @internal\n */\n private findAllowedMethods(path: string): HttpMethod[] {\n let normalized = this.opts.caseSensitive ? path : path.toLowerCase();\n\n if (normalized.includes('//')) {\n normalized = normalized.replace(/\\/+/g, '/');\n }\n\n if (!this.opts.strict && normalized.length > 1 && normalized.endsWith('/')) {\n normalized = normalized.slice(0, -1);\n }\n\n const segments = normalized.split('/').filter(Boolean);\n const node = this.findNode(this.root, segments, 0);\n if (!node || node.handlers.size === 0) return [];\n\n return Array.from(node.handlers.keys());\n }\n\n /**\n * Walk the tree to find the node matching a path (ignoring HTTP method)\n * @internal\n */\n private findNode(node: RadixNode, segments: string[], index: number): RadixNode | null {\n if (index === segments.length) {\n return node;\n }\n\n const segment = segments[index];\n if (segment === undefined) return null;\n\n // Static match\n const staticChild = node.children.get(segment);\n if (staticChild) {\n const result = this.findNode(staticChild, segments, index + 1);\n if (result) return result;\n }\n\n // Param match\n if (node.paramChild) {\n const result = this.findNode(node.paramChild, segments, index + 1);\n if (result) return result;\n }\n\n // Wildcard match\n if (node.wildcardChild) {\n return node.wildcardChild;\n }\n\n return null;\n }\n\n // ===========================================================================\n // Route Groups\n // ===========================================================================\n\n /**\n * Create a route group with shared prefix and middleware\n *\n * @param prefix - Path prefix for all routes in the group\n * @param middlewareOrCallback - Middleware array or callback function\n * @param callback - Callback function if middleware is provided\n * @returns this for chaining\n *\n * @example\n * ```typescript\n * // Simple group with prefix\n * router.group('/api', (r) => {\n * r.get('/users', listUsers);\n * r.get('/posts', listPosts);\n * });\n *\n * // Group with middleware\n * router.group('/admin', [authMiddleware], (r) => {\n * r.get('/dashboard', dashboard);\n * r.post('/settings', updateSettings);\n * });\n *\n * // Nested groups\n * router.group('/api/v1', (r) => {\n * r.group('/users', [rateLimit], (ur) => {\n * ur.get('/', listUsers);\n * ur.get('/:id', getUser);\n * });\n * });\n * ```\n */\n group(\n prefix: string,\n middlewareOrCallback: Middleware[] | ((router: Router) => void),\n callback?: (router: Router) => void\n ): this {\n let middleware: Middleware[] = [];\n let cb: (router: Router) => void;\n\n if (Array.isArray(middlewareOrCallback)) {\n middleware = middlewareOrCallback;\n if (!callback) {\n throw new Error('Callback function is required when providing middleware array');\n }\n cb = callback;\n } else {\n cb = middlewareOrCallback;\n }\n\n // Create a temporary router to collect routes\n const groupRouter = new GroupRouter(this, prefix, middleware);\n\n // Execute callback with the group router\n cb(groupRouter as unknown as Router);\n\n return this;\n }\n\n /**\n * Remove all registered routes and middleware, resetting the router to its initial state.\n * Useful for plugin `destroy()` to cleanly un-register routes.\n */\n reset(): void {\n this.root.children.clear();\n this.root.handlers.clear();\n this.root.paramChild = undefined;\n this.root.wildcardChild = undefined;\n this.staticRoutes.clear();\n this.routerMiddleware.length = 0;\n this.hasParamRoutes = false;\n }\n\n /**\n * Internal method to add route with group context\n * @internal\n */\n _addGroupRoute(\n method: HttpMethod,\n path: string,\n handlers: RouteHandler[],\n groupMiddleware: Middleware[]\n ): void {\n this.addRoute(method, path, handlers, groupMiddleware);\n }\n}\n\n/**\n * Internal router class for handling route groups\n * Wraps the parent router and adds prefix/middleware to all routes\n * @internal\n */\nclass GroupRouter {\n private readonly parent: Router;\n private readonly prefix: string;\n private readonly middleware: Middleware[];\n\n constructor(parent: Router, prefix: string, middleware: Middleware[]) {\n this.parent = parent;\n this.prefix = prefix;\n this.middleware = middleware;\n }\n\n private fullPath(path: string): string {\n // Handle root path in group\n if (path === '/' || path === '') {\n return this.prefix;\n }\n // Combine prefix and path\n const cleanPrefix = this.prefix.endsWith('/') ? this.prefix.slice(0, -1) : this.prefix;\n const cleanPath = path.startsWith('/') ? path : '/' + path;\n return cleanPrefix + cleanPath;\n }\n\n get(path: string, ...handlers: RouteHandler[]): this {\n this.parent._addGroupRoute('GET', this.fullPath(path), handlers, this.middleware);\n return this;\n }\n\n post(path: string, ...handlers: RouteHandler[]): this {\n this.parent._addGroupRoute('POST', this.fullPath(path), handlers, this.middleware);\n return this;\n }\n\n put(path: string, ...handlers: RouteHandler[]): this {\n this.parent._addGroupRoute('PUT', this.fullPath(path), handlers, this.middleware);\n return this;\n }\n\n delete(path: string, ...handlers: RouteHandler[]): this {\n this.parent._addGroupRoute('DELETE', this.fullPath(path), handlers, this.middleware);\n return this;\n }\n\n patch(path: string, ...handlers: RouteHandler[]): this {\n this.parent._addGroupRoute('PATCH', this.fullPath(path), handlers, this.middleware);\n return this;\n }\n\n head(path: string, ...handlers: RouteHandler[]): this {\n this.parent._addGroupRoute('HEAD', this.fullPath(path), handlers, this.middleware);\n return this;\n }\n\n options(path: string, ...handlers: RouteHandler[]): this {\n this.parent._addGroupRoute('OPTIONS', this.fullPath(path), handlers, this.middleware);\n return this;\n }\n\n all(path: string, ...handlers: RouteHandler[]): this {\n for (const method of HTTP_METHODS) {\n this.parent._addGroupRoute(method, this.fullPath(path), handlers, this.middleware);\n }\n return this;\n }\n\n /**\n * Register a redirect within the group\n */\n redirect(from: string, to: string, status: 301 | 302 | 303 | 307 | 308 = 301): this {\n const redirectHandler: RouteHandler = (ctx: Context) => {\n let targetPath = to;\n\n if (targetPath.includes(':')) {\n const entries = Object.entries(ctx.params).sort((a, b) => b[0].length - a[0].length);\n for (const [key, value] of entries) {\n targetPath = targetPath.replaceAll(`:${key}`, value);\n }\n }\n\n ctx.status = status;\n ctx.set('Location', targetPath);\n ctx.body = '';\n };\n\n this.parent._addGroupRoute('GET', this.fullPath(from), [redirectHandler], this.middleware);\n this.parent._addGroupRoute('HEAD', this.fullPath(from), [redirectHandler], this.middleware);\n\n return this;\n }\n\n /**\n * Nested group support\n */\n group(\n prefix: string,\n middlewareOrCallback: Middleware[] | ((router: GroupRouter) => void),\n callback?: (router: GroupRouter) => void\n ): this {\n let nestedMiddleware: Middleware[] = [];\n let cb: (router: GroupRouter) => void;\n\n if (Array.isArray(middlewareOrCallback)) {\n nestedMiddleware = middlewareOrCallback;\n if (!callback) {\n throw new Error('Callback function is required when providing middleware array');\n }\n cb = callback;\n } else {\n cb = middlewareOrCallback;\n }\n\n // Create nested group with combined prefix and middleware\n const nestedRouter = new GroupRouter(this.parent, this.fullPath(prefix), [\n ...this.middleware,\n ...nestedMiddleware,\n ]);\n\n cb(nestedRouter);\n\n return this;\n }\n}\n\n/**\n * Create a new Router instance\n *\n * @param options - Router options\n * @returns New Router instance\n *\n * @example\n * ```typescript\n * const router = createRouter();\n * const apiRouter = createRouter({ prefix: '/api/v1' });\n * ```\n */\nexport function createRouter(options?: RouterOptions): Router {\n return new Router(options);\n}\n","/**\n * @nextrush/router - Segment Trie Node\n *\n * Internal segment trie implementation for high-performance route matching.\n * Uses a compressed trie structure for O(k) lookups where k is path length.\n *\n * @packageDocumentation\n * @internal\n */\n\nimport type { Context, HttpMethod, Middleware, RouteHandler } from '@nextrush/types';\n\n/**\n * Node type enumeration\n */\nexport const enum NodeType {\n /** Static path segment: /users */\n STATIC = 0,\n /** Named parameter: /:id */\n PARAM = 1,\n /** Wildcard: /* */\n WILDCARD = 2,\n}\n\n/**\n * Radix tree node\n */\nexport interface RadixNode {\n /** Path segment for this node */\n segment: string;\n /** Node type */\n type: NodeType;\n /** Children nodes keyed by first character */\n children: Map<string, RadixNode>;\n /** Parameter name if this is a param node */\n paramName?: string;\n /** Handlers keyed by HTTP method */\n handlers: Map<HttpMethod, HandlerEntry>;\n /** Wildcard child if any */\n wildcardChild?: RadixNode;\n /** Parameter child if any */\n paramChild?: RadixNode;\n}\n\n/**\n * Handler entry with middleware and pre-compiled executor\n */\nexport interface HandlerEntry {\n handler: RouteHandler;\n middleware: Middleware[];\n /** Pre-compiled executor for fast dispatch (no closure per request) */\n executor?: (ctx: Context) => Promise<void>;\n}\n\n/**\n * No-op next function - reusable, zero allocation\n * Caches the resolved Promise to avoid per-call allocation\n * @internal\n */\nconst RESOLVED_PROMISE = Promise.resolve();\nexport const NOOP_NEXT = (): Promise<void> => RESOLVED_PROMISE;\n\n/**\n * Compile an executor for a route handler with middleware\n * This creates the executor ONCE at registration time, not per-request\n * @internal\n */\nexport function compileExecutor(\n handler: RouteHandler,\n middleware: Middleware[]\n): (ctx: Context) => Promise<void> {\n const len = middleware.length;\n\n // FAST PATH: No middleware - direct handler call\n if (len === 0) {\n return async (ctx: Context) => {\n await handler(ctx, NOOP_NEXT);\n };\n }\n\n // FAST PATH: Single middleware\n if (len === 1) {\n const mw = middleware[0];\n if (mw === undefined) throw new Error('middleware length mismatch');\n return async (ctx: Context) => {\n await mw(ctx, async () => {\n await handler(ctx, NOOP_NEXT);\n });\n };\n }\n\n // FAST PATH: Two middleware (very common)\n if (len === 2) {\n const mw0 = middleware[0];\n const mw1 = middleware[1];\n if (mw0 === undefined || mw1 === undefined) throw new Error('middleware length mismatch');\n return async (ctx: Context) => {\n await mw0(ctx, async () => {\n await mw1(ctx, async () => {\n await handler(ctx, NOOP_NEXT);\n });\n });\n };\n }\n\n // General case: Build recursive dispatch\n // Note: This closure is created ONCE at registration, not per request\n return async (ctx: Context): Promise<void> => {\n let index = 0;\n\n const dispatch = async (): Promise<void> => {\n if (index < len) {\n const mw = middleware[index++];\n if (mw === undefined) throw new Error('middleware length mismatch');\n await mw(ctx, dispatch);\n } else {\n await handler(ctx, NOOP_NEXT);\n }\n };\n\n await dispatch();\n };\n}\n\n/**\n * Create a new radix node\n */\nexport function createNode(segment: string, type: NodeType = NodeType.STATIC): RadixNode {\n return {\n segment,\n type,\n children: new Map(),\n handlers: new Map(),\n };\n}\n\n/**\n * Parse path segments\n * Splits path into segments and identifies param/wildcard types\n *\n * @param path - Route path to parse\n * @param caseSensitive - If false, lowercase static segments for case-insensitive matching\n */\nexport function parseSegments(path: string, caseSensitive = true): ParsedSegment[] {\n const normalized = path.startsWith('/') ? path.slice(1) : path;\n if (normalized === '') return [];\n\n const parts = normalized.split('/');\n const segments: ParsedSegment[] = [];\n\n for (const part of parts) {\n if (part.startsWith(':')) {\n // Preserve the original parameter name case\n const paramName = part.slice(1);\n segments.push({\n segment: part, // Preserve original case — param nodes match any segment\n type: NodeType.PARAM,\n paramName, // Keep original case\n });\n } else if (part === '*') {\n segments.push({\n segment: '*',\n type: NodeType.WILDCARD,\n });\n break; // Wildcard must be last\n } else {\n segments.push({\n segment: caseSensitive ? part : part.toLowerCase(),\n type: NodeType.STATIC,\n });\n }\n }\n\n return segments;\n}\n\n/**\n * Parsed segment structure\n */\nexport interface ParsedSegment {\n segment: string;\n type: NodeType;\n paramName?: string;\n}\n"],"mappings":"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","names":["HTTP_METHODS","NodeType","RESOLVED_PROMISE","Promise","resolve","NOOP_NEXT","compileExecutor","handler","middleware","len","length","ctx","mw","undefined","Error","mw0","mw1","index","dispatch","createNode","segment","type","children","Map","handlers","parseSegments","path","caseSensitive","normalized","startsWith","slice","parts","split","segments","part","paramName","push","toLowerCase","EMPTY_PARAMS","Object","freeze","create","Router","root","opts","routerMiddleware","staticRoutes","Map","hasParamRoutes","options","createNode","prefix","caseSensitive","strict","normalizePath","path","endsWith","startsWith","slice","normalized","includes","replace","length","addRoute","method","handlers","middleware","segments","parseSegments","node","seg","type","NodeType","PARAM","paramChild","segment","paramName","process","env","NODE_ENV","existing","console","warn","String","WILDCARD","wildcardChild","key","child","children","get","STATIC","set","combinedMiddleware","finalHandler","Error","inlineMiddleware","mw","push","executor","compileExecutor","entry","handler","has","hasParams","some","s","normalizedKey","toLowerCase","post","put","delete","patch","head","all","HTTP_METHODS","route","redirect","from","to","status","compiledParts","parts","pos","found","idx","i","end","indexOf","redirectHandler","ctx","targetPath","params","undefined","result","paramKey","tail","body","use","pathOrMiddleware","routerOrUndefined","mountRouter","mount","router","copyRoutes","subRouterMiddleware","join","combined","match","isCaseInsensitive","staticKey","staticEntry","originalPath","matchNodeIndexed","keys","Reflect","deleteProperty","extractSegment","start","slashPos","nextPos","staticChild","origSeg","src","routes","hasRouterMiddleware","sealRouterMiddleware","next","NOOP_NEXT","routerMw","walk","combinedMw","allowedMethods","allowed","findAllowedMethods","allowHeader","split","filter","Boolean","findNode","size","Array","index","group","middlewareOrCallback","callback","cb","isArray","groupRouter","GroupRouter","reset","clear","_addGroupRoute","groupMiddleware","parent","fullPath","cleanPrefix","cleanPath","entries","sort","a","b","value","replaceAll","nestedMiddleware","nestedRouter","createRouter"]}
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@nextrush/router",
3
+ "version": "3.0.0",
4
+ "description": "High-performance radix tree router for NextRush",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "src"
18
+ ],
19
+ "dependencies": {
20
+ "@nextrush/types": "3.0.0"
21
+ },
22
+ "devDependencies": {
23
+ "tsup": "^8.5.1",
24
+ "typescript": "^6.0.2",
25
+ "@nextrush/core": "3.0.0"
26
+ },
27
+ "peerDependencies": {
28
+ "@nextrush/core": "3.0.0"
29
+ },
30
+ "peerDependenciesMeta": {
31
+ "@nextrush/core": {
32
+ "optional": true
33
+ }
34
+ },
35
+ "keywords": [
36
+ "nextrush",
37
+ "router",
38
+ "radix-tree",
39
+ "http",
40
+ "framework"
41
+ ],
42
+ "license": "MIT",
43
+ "engines": {
44
+ "node": ">=22.0.0"
45
+ },
46
+ "publishConfig": {
47
+ "access": "public"
48
+ },
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "git+https://github.com/0xTanzim/nextrush.git",
52
+ "directory": "packages/router"
53
+ },
54
+ "author": {
55
+ "name": "Tanzim Hossain",
56
+ "email": "tanzimhossain2@gmail.com",
57
+ "url": "https://github.com/0xTanzim"
58
+ },
59
+ "sideEffects": false,
60
+ "scripts": {
61
+ "build": "tsup",
62
+ "dev": "tsup --watch",
63
+ "test": "vitest run",
64
+ "test:watch": "vitest",
65
+ "typecheck": "tsc --noEmit",
66
+ "lint": "eslint src --ignore-pattern '**/__tests__/**'",
67
+ "clean": "rm -rf dist"
68
+ }
69
+ }