@rabbit-company/web
Version:
High-performance web framework
1,290 lines (1,288 loc) • 38.3 kB
TypeScript
/**
* Middleware function type that processes requests and can return responses.
* Middleware functions receive a context object and a next function to call the next middleware in the chain.
*
* @template T - The type of the context state object
* @param ctx - Context object containing request data and helper methods
* @param next - Function to call the next middleware in the chain
* @returns Response object, Promise resolving to Response, or void to continue to next middleware
*
* @example
* ```typescript
* const authMiddleware: Middleware<{ user: User }> = async (ctx, next) => {
* const token = ctx.req.headers.get('authorization');
* if (!token) {
* return ctx.json({ error: 'Unauthorized' }, 401);
* }
*
* const user = await verifyToken(token);
* ctx.set('user', user);
* await next(); // Continue to next middleware/handler
* };
* ```
*/
export type Middleware<T extends Record<string, unknown> = Record<string, unknown>, B extends Record<string, unknown> = Record<string, unknown>> = (ctx: Context<T, B>, next: Next) => Response | Promise<Response | void>;
/**
* Function type for calling the next middleware in the chain.
* Returns a Promise that resolves to a Response or void.
*
* @returns Promise that resolves when the next middleware completes
*
* @example
* ```typescript
* const loggingMiddleware: Middleware = async (ctx, next) => {
* console.log(`${ctx.req.method} ${ctx.req.url} - Started`);
* const startTime = Date.now();
*
* await next(); // Call next middleware
*
* const duration = Date.now() - startTime;
* console.log(`${ctx.req.method} ${ctx.req.url} - Completed in ${duration}ms`);
* };
* ```
*/
export type Next = () => Promise<Response | void>;
/**
* Interface representing a node in the trie data structure used for efficient route matching.
* Each node can have static children, parameter children, or wildcard children.
*
* @template T - The type of the context state object
*
* @example
* ```typescript
* // Internal structure for route '/users/:id/posts'
* // Root -> 'users' (static) -> ':id' (param) -> 'posts' (static)
* ```
*/
export interface TrieNode<T extends Record<string, unknown> = Record<string, unknown>, B extends Record<string, unknown> = Record<string, unknown>> {
/** Map of static path segments to their corresponding child nodes */
children: Map<string, TrieNode<T, B>>;
/** Parameter child node for capturing dynamic segments (e.g., ':id') */
paramChild?: TrieNode<T, B>;
/** Name of the parameter without the ':' prefix */
paramName?: string;
/** Wildcard child node for matching remaining path segments ('*') */
wildcardChild?: TrieNode<T, B>;
/** Array of middleware handlers to execute when this node represents a complete route */
handlers?: Middleware<T, B>[];
}
/**
* HTTP methods supported by the framework.
*
* @example
* ```typescript
* const method: Method = 'GET';
* app.addRoute(method, '/users', handler);
* ```
*/
export type Method = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | "HEAD";
/**
* Result of attempting to match a URL path against a route pattern.
*
* @example
* ```typescript
* const result: MatchResult = {
* matched: true,
* params: { id: '123', category: 'electronics' }
* };
* ```
*/
export type MatchResult = {
matched: boolean;
params: Record<string, string>;
};
/**
* Internal representation of middleware with matching logic.
* Used to determine which middleware should run for a given request.
*
* @template T - The type of the context state object
*/
export type MiddlewareRoute<T extends Record<string, unknown> = Record<string, unknown>, B extends Record<string, unknown> = Record<string, unknown>> = {
/** Optional HTTP method this middleware applies to */
method?: Method;
/** Optional path pattern this middleware applies to */
path?: string;
/** Static prefix of the path for optimization */
pathPrefix?: string;
/** Function to determine if this middleware matches a given URL */
match: (url: string) => MatchResult;
/** The middleware handler function */
handler: Middleware<T, B>;
};
/**
* Context object passed to middleware and route handlers containing request data and helper methods.
* The context provides a convenient API for handling common web operations like parsing request bodies,
* setting response headers, and managing application state.
*
* @template T - The type of the context state object for sharing data between middleware
*
* @example
* ```typescript
* interface AppState {
* user: User;
* requestId: string;
* }
*
* const handler: Middleware<AppState> = async (ctx) => {
* // Access request data
* const userId = ctx.params.id;
* const query = ctx.query();
*
* // Parse request body
* const body = await ctx.body<CreateUserRequest>();
*
* // Set state
* ctx.set('requestId', generateId());
*
* // Return response
* return ctx.json({ success: true });
* };
* ```
*/
export interface Context<T extends Record<string, unknown> = Record<string, unknown>, B extends Record<string, unknown> = Record<string, unknown>> {
/** The original Request object */
req: Request;
/** Optional Response object (for advanced use cases) */
res?: Response;
/** Object containing URL parameters extracted from the route path */
params: Record<string, string>;
/** Application state object for sharing data between middleware */
state: T;
/** Only present in Cloudflare Workers */
env: B;
/** Client IP address, populated by web server or `ip-extract` middleware */
clientIp?: string;
/**
* Returns a plain text response.
*
* @param body - Text content for the response body
* @param status - HTTP status code (default: 200)
* @param headers - Additional headers to include
* @returns Response object with text content
*
* @example
* ```typescript
* return ctx.text('Hello World');
* return ctx.text('Not Found', 404);
* return ctx.text('Created', 201, { 'X-Custom': 'value' });
* ```
*/
text: (body: string | null | undefined, status?: number, headers?: Record<string, string>) => Response;
/**
* Context method to send a JSON response with proper headers.
*
* @param data - Data to be serialized as JSON
* @param status - HTTP status code (default: 200)
* @param headers - Additional headers to include
* @returns {Response} Configured Response object
*
* @example
* ```typescript
* // Basic response
* return ctx.json({ message: 'Success' });
*
* // With status code
* return ctx.json({ error: 'Not found' }, 404);
*
* // With custom headers
* return ctx.json(
* { data },
* 200,
* { 'Cache-Control': 'max-age=3600' }
* );
*
* // With TypeScript type safety
* return ctx.json<ApiResponse<User>>({
* status: 'success',
* data: user
* });
* ```
*/
json: (data: unknown, status?: number, headers?: Record<string, string>) => Response;
/**
* Returns an HTML response.
*
* @param html - HTML content for the response body
* @param status - HTTP status code (default: 200)
* @param headers - Additional headers to include
* @returns Response object with HTML content
*
* @example
* ```typescript
* return ctx.html('<h1>Welcome</h1>');
* return ctx.html('<h1>Error</h1>', 500);
* return ctx.html(template, 200, { 'X-Frame-Options': 'DENY' });
* ```
*/
html: (html: string | null | undefined, status?: number, headers?: Record<string, string>) => Response;
/**
* Returns the URL search parameters as a URLSearchParams object.
*
* @returns URLSearchParams object for accessing query parameters
*
* @example
* ```typescript
* // For URL: /users?page=2&limit=10
* const query = ctx.query();
* const page = query.get('page'); // '2'
* const limit = query.get('limit'); // '10'
* ```
*/
query: () => URLSearchParams;
/**
* Context method to parse and return the request body as JSON.
* Automatically handles content-type detection and parsing.
*
* @template U - Type of the expected response body
* @returns {Promise<U>} Parsed request body
*
* @example
* ```typescript
* // Basic usage
* const user = await ctx.body<User>();
*
* // With error handling
* try {
* const data = await ctx.body<CreateUserRequest>();
* } catch (err) {
* return ctx.json({ error: 'Invalid JSON' }, 400);
* }
*
* // With validation
* const raw = await ctx.body<unknown>();
* const valid = userSchema.parse(raw);
* ```
*/
body: <T>() => Promise<T>;
/**
* Sets a response header.
*
* @param name - Header name
* @param value - Header value
*
* @example
* ```typescript
* ctx.header('X-Custom-Header', 'value');
* ```
*/
header: (name: string, value: string) => void;
/**
* Sets a value in the context state.
*
* @template K - Key type from the state object
* @param key - The state key to set
* @param value - The value to set
*
* @example
* ```typescript
* ctx.set('user', currentUser);
* ctx.set('requestId', uuid());
* ```
*/
set: <K extends keyof T>(key: K, value: T[K]) => void;
/**
* Gets a value from the context state.
*
* @template K - Key type from the state object
* @param key - The state key to retrieve
* @returns The value associated with the key
*
* @example
* ```typescript
* const user = ctx.get('user');
* const requestId = ctx.get('requestId');
* ```
*/
get: <K extends keyof T>(key: K) => T[K];
/**
* Returns a redirect response.
*
* @param url - URL to redirect to
* @param status - HTTP status code for redirect (default: 302)
* @returns Response object with redirect headers
*
* @example
* ```typescript
* return ctx.redirect('/login');
* return ctx.redirect('https://example.com', 301);
* ```
*/
redirect: (url: string, status?: number) => Response;
}
/**
* Internal representation of a route with its matching logic and handlers.
*
* @template T - The type of the context state object
*/
export interface Route<T extends Record<string, unknown> = Record<string, unknown>, B extends Record<string, unknown> = Record<string, unknown>> {
/** HTTP method for this route */
method: Method;
/** Path pattern for this route */
path: string;
/** Function to match URLs against this route pattern */
match: (url: string) => {
matched: boolean;
params: Record<string, string>;
};
/** Array of middleware handlers for this route */
handlers: Middleware<T, B>[];
}
/**
* Server instance returned by the listen method.
* Provides a unified interface for controlling servers across different runtimes.
*/
export interface Server {
/** The port number the server is listening on */
port: number;
/** The hostname/IP address the server is bound to */
hostname: string;
/** The runtime name ('bun', 'deno', 'node' or 'cloudflare-workers') */
runtime: "bun" | "deno" | "node" | "cloudflare-workers";
/**
* Stops the server gracefully.
* @returns {Promise<void>} Promise that resolves when the server is fully stopped
*/
stop(): Promise<void>;
/** The underlying runtime-specific server instance */
instance: unknown;
}
/**
* Node.js specific server options for HTTP/HTTPS configuration.
*/
export interface NodeServerOptions {
/**
* Enable HTTPS server instead of HTTP.
* @default false
*/
https?: boolean;
/**
* TLS private key for HTTPS server.
* Required when https is true.
*/
key?: string | Buffer;
/**
* TLS certificate for HTTPS server.
* Required when https is true.
*/
cert?: string | Buffer;
}
/**
* Deno specific server options.
*/
export interface DenoServerOptions {
/** TLS private key file path or content */
key?: string;
/** TLS certificate file path or content */
cert?: string;
/**
* Application-Layer Protocol Negotiation protocols.
* @example ['h2', 'http/1.1']
*/
alpnProtocols?: string[];
}
/**
* Bun specific TLS configuration.
*/
export interface BunTlsOptions {
/** TLS private key */
key?: string | Buffer | Array<string | Buffer>;
/** TLS certificate */
cert?: string | Buffer | Array<string | Buffer>;
/** TLS certificate authority */
ca?: string | Buffer | Array<string | Buffer>;
/** Passphrase for the private key */
passphrase?: string;
/** Diffie-Hellman parameters */
dhParamsFile?: string;
/** Minimum TLS version */
secureOptions?: number;
}
/**
* Bun specific server options.
*/
export interface BunServerOptions {
/** TLS configuration for HTTPS */
tls?: BunTlsOptions;
/**
* Maximum allowed request body size in bytes.
* @default 128 * 1024 * 1024 (128MB)
*/
maxRequestBodySize?: number;
/** WebSocket handler configuration */
websocket?: unknown;
/** Server name for the Server header */
serverName?: string;
/** Enable HTTP/2 support */
reusePort?: boolean;
}
/**
* Callback function invoked when the server starts listening.
*/
export type ListenCallback = (info: {
/** The port the server is listening on */
port: number;
/** The hostname the server is bound to */
hostname: string;
/** The runtime name */
runtime: "bun" | "deno" | "node" | "cloudflare-workers";
}) => void;
/**
* Configuration options for starting a server with the listen method.
*/
export interface ListenOptions {
/**
* Port number to listen on.
* @default 3000
*/
port?: number;
/**
* Hostname or IP address to bind to.
* Use '0.0.0.0' to listen on all interfaces.
* @default 'localhost'
*/
hostname?: string;
/**
* Callback function invoked when the server starts successfully.
* Receives server information including port, hostname, and runtime.
*/
onListen?: ListenCallback;
/**
* Node.js specific server options.
* Only used when running in Node.js runtime.
*/
node?: NodeServerOptions;
/**
* Deno specific server options.
* Only used when running in Deno runtime.
*/
deno?: DenoServerOptions;
/**
* Bun specific server options.
* Only used when running in Bun runtime.
*/
bun?: BunServerOptions;
}
/**
* Type definition for Node.js HTTP/HTTPS server instance.
* @internal
*/
export interface NodeServerInstance {
listen(port: number, hostname: string, callback?: () => void): void;
close(callback?: (err?: Error) => void): void;
on(event: string, listener: (...args: any[]) => void): void;
off(event: string, listener: (...args: any[]) => void): void;
}
/**
* Type definition for Deno server instance.
* @internal
*/
export interface DenoServerInstance {
finished: Promise<void>;
shutdown(): Promise<void>;
}
/**
* Type definition for Bun server instance.
* @internal
*/
export interface BunServerInstance {
port: number;
hostname?: string;
stop(): void;
}
/**
* High-performance web framework with trie-based routing, middleware support, and extensive caching.
*
* Features:
* - Fast trie-based route matching
* - Middleware support with method and path filtering
* - Route scoping and sub-applications
* - Built-in caching for improved performance
* - Support for all standard HTTP methods
* - Parameter extraction and wildcard routes
* - Dynamic route and middleware removal
* - Custom error and 404 handlers
*
* @template T - The type of the context state object that will be shared across middleware
*
* @example
* ```typescript
* const app = new Web<{ user: User }>();
*
* app.get('/users/:id', async (ctx, next) => {
* const user = await getUser(ctx.params.id);
* ctx.set('user', user);
* return ctx.json(user);
* });
*
* app.use('/admin', async (ctx, next) => {
* // Authentication middleware
* if (!ctx.get('user')?.isAdmin) {
* return ctx.json({ error: 'Unauthorized' }, 401);
* }
* await next();
* });
* ```
*/
export declare class Web<T extends Record<string, unknown> = Record<string, unknown>, B extends Record<string, unknown> = Record<string, unknown>> {
/** Array of all registered routes */
private routes;
/** Array of all registered middleware */
private middlewares;
/** Cache for method-specific middleware to avoid filtering on each request */
private methodMiddlewareCache;
/** Cache for parsed URLs to avoid repeated parsing */
private urlCache;
/** Cache for path segments to avoid repeated splitting */
private segmentCache;
/** Cache for compiled route matchers */
private matcherCache;
/** Cache for frequently matched routes */
private routeMatchCache;
/** Counter for generating unique IDs */
private idCounter;
/** Trie roots for each HTTP method for fast route matching */
private roots;
/**
* Creates a new Web framework instance
*/
constructor();
/**
* Generates a unique ID for routes and middleware
* @private
*/
private generateId;
/**
* Clears all internal caches. Called automatically when routes or middleware are modified.
* @private
*/
private clearCaches;
/**
* Rebuilds the trie structure from scratch. Used after route removal.
* @private
*/
private rebuildTrie;
/**
* Adds a route to the trie structure (internal method)
* @private
*/
private addRouteToTrie;
/** Error handler function for handling uncaught errors */
private errorHandler?;
/** 404 Not Found handler function */
private notFoundHandler?;
/**
* Sets a global error handler for the application.
* This handler will be called whenever an unhandled error occurs during request processing.
*
* @param handler - Function that takes an error and context, returns a Response
* @returns The Web instance for method chaining
*
* @example
* ```typescript
* app.onError((err, ctx) => {
* console.error('Application error:', err);
* return ctx.json({ error: 'Internal Server Error' }, 500);
* });
* ```
*/
onError(handler: (err: Error, ctx: Context<T, B>) => Response | Promise<Response>): this;
/**
* Sets a custom 404 Not Found handler for the application.
* This handler will be called whenever a request doesn't match any registered routes.
*
* @param handler - Function that takes a context and returns a Response
* @returns The Web instance for method chaining
*
* @example
* ```typescript
* // Simple text response
* app.onNotFound((ctx) => {
* return ctx.text('Page not found', 404);
* });
*
* // JSON response with request details
* app.onNotFound((ctx) => {
* return ctx.json({
* error: 'Not Found',
* path: ctx.req.url,
* method: ctx.req.method
* }, 404);
* });
*
* // HTML response with custom 404 page
* app.onNotFound((ctx) => {
* return ctx.html(`
* <!DOCTYPE html>
* <html>
* <head>
* <title>404 - Page Not Found</title>
* <style>
* body { font-family: Arial, sans-serif; text-align: center; padding: 50px; }
* h1 { color: #ff6b6b; }
* </style>
* </head>
* <body>
* <h1>404 - Page Not Found</h1>
* <p>The page you're looking for doesn't exist.</p>
* <a href="/">Go back home</a>
* </body>
* </html>
* `, 404);
* });
* ```
*/
onNotFound(handler: (ctx: Context<T, B>) => Response | Promise<Response>): this;
/**
* Splits a path into segments and caches the result for performance.
*
* @param path - The URL path to split
* @returns Array of path segments (empty segments filtered out)
* @private
*/
private getPathSegments;
/**
* Parses a URL into pathname and search parameters with caching for performance.
* Handles both absolute and relative URLs.
*
* @param url - The URL to parse
* @returns Object containing pathname and optional URLSearchParams
* @private
*/
private parseUrl;
/**
* Registers middleware that will run for matching requests.
* Middleware can be global, path-specific, or method and path specific.
*
* @param args - Variable arguments for different middleware registration patterns:
* - `[handler]` - Global middleware that runs for all requests
* - `[path, handler]` - Path-specific middleware
* - `[method, path, handler]` - Method and path-specific middleware
* @returns The Web instance for method chaining
*
* @example
* ```typescript
* // Global middleware
* app.use(async (ctx, next) => {
* console.log(`${ctx.req.method} ${ctx.req.url}`);
* await next();
* });
*
* // Path-specific middleware
* app.use('/api', async (ctx, next) => {
* ctx.set('apiVersion', '1.0');
* await next();
* });
*
* // Method and path-specific middleware
* app.use('POST', '/users', async (ctx, next) => {
* // Validate request body
* await next();
* });
* ```
*/
use(...args: [
Middleware<T, B>
] | [
string,
Middleware<T, B>
] | [
Method,
string,
Middleware<T, B>
]): this;
/**
* Removes middleware by its ID.
*
* @param id - The middleware ID returned from the use() method
* @returns true if middleware was found and removed, false otherwise
*
* @example
* ```typescript
* const middlewareId = app.use('/api', authMiddleware);
*
* // Later remove it
* const removed = app.removeMiddleware(middlewareId);
* console.log(removed ? 'Middleware removed' : 'Middleware not found');
* ```
*/
removeMiddleware(id: string): boolean;
/**
* Removes all middleware matching the given criteria.
*
* @param criteria - Object with optional method and/or path to match
* @returns Number of middleware items removed
*
* @example
* ```typescript
* // Remove all middleware for a specific path
* const removed = app.removeMiddlewareBy({ path: '/api' });
*
* // Remove all POST middleware
* app.removeMiddlewareBy({ method: 'POST' });
*
* // Remove specific method and path combination
* app.removeMiddlewareBy({ method: 'GET', path: '/users' });
* ```
*/
removeMiddlewareBy(criteria: {
method?: Method;
path?: string;
}): number;
/**
* Adds middleware using the specified pattern and returns an ID for later removal.
* This is an alternative to use() that returns an ID instead of the Web instance.
*
* @param args - Variable arguments for different middleware registration patterns
* @returns The middleware ID for later removal
*
* @example
* ```typescript
* // Global middleware
* const globalId = app.addMiddleware(async (ctx, next) => {
* console.log(`${ctx.req.method} ${ctx.req.url}`);
* await next();
* });
*
* // Path-specific middleware
* const pathId = app.addMiddleware('/api', async (ctx, next) => {
* ctx.set('apiVersion', '1.0');
* await next();
* });
*
* // Remove middleware later
* app.removeMiddleware(globalId);
* ```
*/
addMiddleware(...args: [
Middleware<T, B>
] | [
string,
Middleware<T, B>
] | [
Method,
string,
Middleware<T, B>
]): string;
/**
* Gets all registered middleware with their IDs and metadata.
*
* @returns Array of middleware information objects
*
* @example
* ```typescript
* const middlewares = app.getMiddlewares();
* middlewares.forEach(mw => {
* console.log(`ID: ${mw.id}, Method: ${mw.method || 'ALL'}, Path: ${mw.path || 'ALL'}`);
* });
* ```
*/
getMiddlewares(): Array<{
id: string;
method?: Method;
path?: string;
}>;
/**
* Gets or creates a cached matcher function for the given path pattern
* @private
*/
private getCachedMatcher;
/**
* Adds a route with the specified method, path, and handlers to the trie structure.
*
* @param method - HTTP method (GET, POST, etc.)
* @param path - URL path pattern (supports :param and * wildcards)
* @param handlers - One or more middleware handlers for this route
* @returns The route ID for later removal
*
* @example
* ```typescript
* const routeId = app.addRoute('GET', '/users/:id', async (ctx) => {
* return ctx.json({ id: ctx.params.id });
* });
*
* // Remove it later
* app.removeRoute(routeId);
* ```
*/
addRoute(method: Method, path: string, ...handlers: Middleware<T, B>[]): string;
/**
* Removes a route by its ID.
*
* @param id - The route ID returned from route registration methods
* @returns true if route was found and removed, false otherwise
*
* @example
* ```typescript
* const routeId = app.get('/users/:id', getUserHandler);
*
* // Later remove it
* const removed = app.removeRoute(routeId);
* console.log(removed ? 'Route removed' : 'Route not found');
* ```
*/
removeRoute(id: string): boolean;
/**
* Removes all routes matching the given criteria.
*
* @param criteria - Object with optional method and/or path to match
* @returns Number of routes removed
*
* @example
* ```typescript
* // Remove all routes for a specific path
* const removed = app.removeRoutesBy({ path: '/users/:id' });
*
* // Remove all GET routes
* app.removeRoutesBy({ method: 'GET' });
*
* // Remove specific method and path combination
* app.removeRoutesBy({ method: 'POST', path: '/users' });
* ```
*/
removeRoutesBy(criteria: {
method?: Method;
path?: string;
}): number;
/**
* Gets all registered routes with their IDs and metadata.
*
* @returns Array of route information objects
*
* @example
* ```typescript
* const routes = app.getRoutes();
* routes.forEach(route => {
* console.log(`ID: ${route.id}, ${route.method} ${route.path}`);
* });
* ```
*/
getRoutes(): Array<{
id: string;
method: Method;
path: string;
}>;
/**
* Removes all routes and middleware, effectively resetting the application.
*
* @example
* ```typescript
* // Clear everything and start fresh
* app.clear();
*
* // Now add new routes
* app.get('/', handler);
* ```
*/
clear(): void;
/**
* Matches a method and path against the trie structure to find handlers and extract parameters.
*
* @param method - HTTP method to match
* @param path - URL path to match
* @returns Object with handlers and params if matched, null otherwise
*
* @example
* ```typescript
* const match = app.match('GET', '/users/123');
* if (match) {
* console.log(match.params.id); // "123"
* }
* ```
*/
match(method: Method, path: string): {
handlers?: Middleware<T, B>[];
params: Record<string, string>;
} | null;
/**
* Gets cached middleware that applies to a specific HTTP method.
*
* @param method - HTTP method to filter middleware for
* @returns Array of middleware routes that apply to the method
* @private
*/
private getMethodMiddlewares;
/**
* Creates a scoped sub-application that inherits middleware and routes with a path prefix.
* Useful for organizing routes and creating modular applications.
*
* @param path - Base path for the scope
* @param callback - Function that receives the scoped app instance to configure
* @returns The Web instance for method chaining
*
* @example
* ```typescript
* app.scope('/api/v1', (api) => {
* api.get('/users', async (ctx) => {
* return ctx.json(await getUsers());
* });
*
* api.post('/users', async (ctx) => {
* const user = await ctx.body<User>();
* return ctx.json(await createUser(user));
* });
* });
* // Routes will be available at /api/v1/users
* ```
*/
scope(path: string, callback: (scopeApp: this) => void): this;
/**
* Mounts a sub-application at the specified path prefix.
* All routes from the sub-application will be prefixed with the given path.
*
* @param prefix - Path prefix to mount the sub-application at
* @param subApp - Web instance to mount
* @returns The Web instance for method chaining
*
* @example
* ```typescript
* const adminApp = new Web();
* adminApp.get('/dashboard', handler);
*
* app.route('/admin', adminApp);
* // Dashboard will be available at /admin/dashboard
* ```
*/
route(prefix: string, subApp: this): this;
/**
* Registers a GET route handler.
*
* @param path - URL path pattern (supports :param and * wildcards)
* @param handlers - One or more middleware handlers
* @returns The Web instance for method chaining
*
* @example
* ```typescript
* app.get('/users/:id', async (ctx) => {
* const user = await getUserById(ctx.params.id);
* return ctx.json(user);
* });
* ```
*/
get(path: string, ...handlers: Middleware<T, B>[]): this;
/**
* Registers a POST route handler.
*
* @param path - URL path pattern
* @param handlers - One or more middleware handlers
* @returns The Web instance for method chaining
*
* @example
* ```typescript
* app.post('/users', async (ctx) => {
* const userData = await ctx.body<CreateUserRequest>();
* const user = await createUser(userData);
* return ctx.json(user, 201);
* });
* ```
*/
post(path: string, ...handlers: Middleware<T, B>[]): this;
/**
* Registers a PUT route handler for complete resource updates.
* PUT is typically used when you want to replace an entire resource.
*
* @param path - URL path pattern
* @param handlers - One or more middleware handlers
* @returns The Web instance for method chaining
*
* @example
* ```typescript
* // Basic PUT route
* app.put('/users/:id', async (ctx) => {
* const userData = await ctx.body<User>();
* const updatedUser = await replaceUser(ctx.params.id, userData);
* return ctx.json(updatedUser);
* });
*
* // PUT with optimistic concurrency control
* app.put('/documents/:id',
* async (ctx) => {
* const doc = await ctx.body<Document>();
* if (ctx.req.headers.get('If-Match') !== doc.version) {
* return ctx.json({ error: 'Version mismatch' }, 412);
* }
* const savedDoc = await saveDocument(doc);
* return ctx.json(savedDoc);
* }
* );
* ```
*/
put(path: string, ...handlers: Middleware<T, B>[]): this;
/**
* Registers a DELETE route handler.
*
* @param path - URL path pattern
* @param handlers - One or more middleware handlers
* @returns The Web instance for method chaining
*
* @example
* ```typescript
* app.delete('/users/:id', async (ctx) => {
* await deleteUser(ctx.params.id);
* return new Response(null, { status: 204 });
* });
* ```
*/
delete(path: string, ...handlers: Middleware<T, B>[]): this;
/**
* Registers a PATCH route handler for partial updates to resources.
* PATCH is typically used when you want to update only specific fields of a resource.
*
* @param path - URL path pattern (supports :param and * wildcards)
* @param handlers - One or more middleware handlers
* @returns The Web instance for method chaining
*
* @example
* ```typescript
* // Basic PATCH route
* app.patch('/users/:id', async (ctx) => {
* const updates = await ctx.body<Partial<User>>();
* const updatedUser = await updateUser(ctx.params.id, updates);
* return ctx.json(updatedUser);
* });
*
* // PATCH with validation middleware
* app.patch('/articles/:id',
* validateArticleUpdate, // middleware that validates the patch body
* async (ctx) => {
* const updates = ctx.get('validatedUpdates');
* const article = await updateArticle(ctx.params.id, updates);
* return ctx.json(article);
* }
* );
* ```
*/
patch(path: string, ...handlers: Middleware<T, B>[]): this;
/**
* Registers an OPTIONS route handler for CORS preflight requests.
* OPTIONS requests are typically used to determine what HTTP methods
* are supported for a given endpoint.
*
* @param path - URL path pattern
* @param handlers - One or more middleware handlers
* @returns The Web instance for method chaining
*
* @example
* ```typescript
* // Basic OPTIONS handler
* app.options('/users', (ctx) => {
* return new Response(null, {
* headers: {
* 'Allow': 'GET, POST, OPTIONS',
* 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
* 'Access-Control-Allow-Headers': 'Content-Type'
* }
* });
* });
*
* // Automatic CORS handling
* app.options('*', (ctx) => {
* return new Response(null, {
* headers: {
* 'Access-Control-Allow-Origin': '*',
* 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
* 'Access-Control-Allow-Headers': 'Content-Type, Authorization'
* }
* });
* });
* ```
*/
options(path: string, ...handlers: Middleware<T, B>[]): this;
/**
* Registers a HEAD route handler.
* HEAD responses automatically strip the response body while preserving headers and status.
*
* @param path - URL path pattern
* @param handlers - One or more middleware handlers
* @returns The Web instance for method chaining
*
* @example
* ```typescript
* app.head('/users/:id', async (ctx) => {
* const exists = await userExists(ctx.params.id);
* return exists ? new Response() : new Response(null, { status: 404 });
* });
* ```
*/
head(path: string, ...handlers: Middleware<T, B>[]): this;
/**
* Creates a context object for the current request with helper methods.
*
* @param req - The incoming Request object
* @param params - URL parameters extracted from the path
* @param parsedUrl - Pre-parsed URL components
* @param clientIp - Optional client IP address
* @param env - Optional environment-specific bindings or variables (e.g., Cloudflare environment)
* @returns Context object with request data and helper methods
* @private
*/
private createContext;
/**
* Creates a 404 Not Found response using the custom handler if set.
* @private
*/
private createNotFoundResponse;
/**
* Main request handler that processes incoming requests through the middleware chain and route handlers.
* This method implements several optimization paths for different scenarios:
* - Ultra-fast path: no middleware, no parameters, single handler
* - Fast path: no middleware, might have parameters
* - Full path: includes middleware processing
*
* @param req - The incoming Request object
* @returns Promise that resolves to a Response object
*
* @example
* ```typescript
* // Use with a server
* const server = Bun.serve({
* port: 3000,
* fetch: app.handle,
* });
*
* // Or with other runtimes
* addEventListener('fetch', (event) => {
* event.respondWith(app.handle(event.request));
* });
* ```
*/
handle(req: Request): Promise<Response>;
/**
* Internal handler that processes requests with a known client IP.
* This is the common implementation used by both runtime-specific handlers.
*
* @param req - The incoming Request object
* @param clientIp - The client IP address (optional)
* @returns Promise that resolves to a Response object
*
* @internal
*/
private handleWithIp;
/**
* Request handler optimized for Bun runtime with automatic IP extraction.
* Uses Bun's server request info for reliable client IP detection.
*
* @param req - The incoming Request object
* @param server - Bun server instance
* @returns Promise that resolves to a Response object
*
* @example
* ```typescript
* Bun.serve({
* port: 3000,
* hostname: 'localhost',
* fetch: app.handleBun
* });
* ```
*/
handleBun(req: Request, server: unknown): Promise<Response>;
/**
* Request handler optimized for Deno runtime with automatic IP extraction.
* Uses Deno's ServeHandlerInfo for reliable client IP detection.
*
* @param req - The incoming Request object
* @param info - Deno.ServeHandlerInfo instance for accessing runtime-specific features
* @returns Promise that resolves to a Response object
*
* @example
* ```typescript
* Deno.serve({
* port: 3000
* },
* (req, info) => app.handleDeno(req, info)
* );
* ```
*/
handleDeno(req: Request, info: unknown): Promise<Response>;
/**
* Request handler optimized for Cloudflare Workers or Pages Functions.
* Automatically extracts the client IP from the "CF-Connecting-IP" header.
*
* @param req - The incoming Request object from Cloudflare
* @param env - Cloudflare environment bindings (type parameter B)
* @param ctx - Optional execution context (used for async operations like waitUntil)
* @returns Promise that resolves to a Response object
*
* @example
* ```ts
* export default {
* fetch: app.handleCloudflare
* };
* ```
*/
handleCloudflare(req: Request, env?: unknown, ctx?: unknown): Promise<Response>;
/**
* Request handler for Node.js that handles both request and response.
* Automatically converts between Node.js and Web APIs and extracts client IP.
*
* @param nodeReq - Node.js IncomingMessage object
* @param nodeRes - Node.js ServerResponse object
* @returns Promise that resolves when response is sent
*
* @example
* ```typescript
* import { createServer } from "http";
*
* createServer((req, res) => app.handleNode(req, res)).listen(3000);
* ```
*/
handleNode(nodeReq: unknown, nodeRes: unknown): Promise<void>;
/**
* Starts a server with automatic runtime detection.
* Automatically selects the appropriate server implementation based on the runtime environment.
*
* @param {ListenOptions} options - Server configuration options
* @returns {Promise<Server>} Promise that resolves to a Server instance
* @throws {Error} If the runtime is not supported
*
* @example
* ```typescript
* // Basic usage with default options
* const server = await app.listen({ port: 3000 });
* console.log(`Server running on ${server.runtime} at http://localhost:${server.port}`);
*
* // With startup callback
* await app.listen({
* port: 8080,
* hostname: '0.0.0.0',
* onListen: ({ port, hostname, runtime }) => {
* console.log(`✅ ${runtime} server running at http://${hostname}:${port}`);
* }
* });
*
* // With HTTPS in Node.js
* await app.listen({
* port: 443,
* node: {
* https: true,
* key: fs.readFileSync('./key.pem'),
* cert: fs.readFileSync('./cert.pem')
* }
* });
*
* // With TLS in Deno
* await app.listen({
* port: 443,
* deno: {
* key: './key.pem',
* cert: './cert.pem'
* }
* });
*
* // With TLS in Bun
* await app.listen({
* port: 443,
* bun: {
* tls: {
* key: Bun.file('./key.pem'),
* cert: Bun.file('./cert.pem')
* }
* }
* });
*
* // Gracefully stop the server
* await server.stop();
* ```
*/
listen(options?: ListenOptions): Promise<Server>;
}
export {};