/** * Adapted directly from @koa/router at * https://github.com/koajs/router/ which is licensed as: * * The MIT License (MIT) * * Copyright (c) 2015 Alexander C. Mingoia * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * Contains the router of oak. Typical usage is the creation of an application * instance, the creation of a router instance, registration of route * middleware, registration of router with the application, and then starting to * listen for requests. * * # Example * * ```ts * import { Application } from "jsr:@oak/oak@14/application"; * import { Router } from "jsr:@oak/oak@14/router"; * * const app = new Application(); * const router = new Router(); * router.get("/", (ctx) => { * ctx.response.body = "hello world!"; * }); * app.use(router.routes()); * app.use(router.allowedMethods()); * * app.listen(); * ``` * * @module */ import type { State } from "./application.js"; import type { Context } from "./context.js"; import { type HTTPMethods, ParseOptions, type RedirectStatus, TokensToRegexpOptions } from "./deps.js"; import { Middleware } from "./middleware.js"; /** Options which can be specified when calling the `.allowedMethods()` method * on a {@linkcode Router} instance. */ export interface RouterAllowedMethodsOptions { /** Use the value returned from this function instead of an HTTP error * `MethodNotAllowed`. */ methodNotAllowed?(): any; /** Use the value returned from this function instead of an HTTP error * `NotImplemented`. */ notImplemented?(): any; /** When dealing with a non-implemented method or a method not allowed, throw * an error instead of setting the status and header for the response. */ throw?: boolean; } /** The internal abstraction of a route used by the oak {@linkcode Router}. */ export interface Route = RouteParams, S extends State = Record> { /** The HTTP methods that this route handles. */ methods: HTTPMethods[]; /** The middleware that will be applied to this route. */ middleware: RouterMiddleware[]; /** An optional name for the route. */ name?: string; /** Options that were used to create the route. */ options: LayerOptions; /** The parameters that are identified in the route that will be parsed out * on matched requests. */ paramNames: (keyof P)[]; /** The path that this route manages. */ path: string; /** The regular expression used for matching and parsing parameters for the * route. */ regexp: RegExp; } /** The context passed router middleware. */ export interface RouterContext = RouteParams, S extends State = Record> extends Context { /** When matching the route, an array of the capturing groups from the regular * expression. */ captures: string[]; /** The routes that were matched for this request. */ matched?: Layer[]; /** Any parameters parsed from the route when matched. */ params: P; /** A reference to the router instance. */ router: Router; /** If the matched route has a `name`, the matched route name is provided * here. */ routeName?: string; /** Overrides the matched path for future route middleware, when a * `routerPath` option is not defined on the `Router` options. */ routerPath?: string; } /** The interface that {@linkcode Router} middleware should adhere to. */ export interface RouterMiddleware = RouteParams, S extends State = Record> { (context: RouterContext, next: () => Promise): Promise | unknown; /** For route parameter middleware, the `param` key for this parameter will * be set. */ param?: keyof P; router?: Router; } /** Options which can be specified when creating a new instance of a * {@linkcode Router}. */ export interface RouterOptions { /** Override the default set of methods supported by the router. */ methods?: HTTPMethods[]; /** Only handle routes where the requested path starts with the prefix. */ prefix?: string; /** Override the `request.url.pathname` when matching middleware to run. */ routerPath?: string; /** Determines if routes are matched in a case sensitive way. Defaults to * `false`. */ sensitive?: boolean; /** Determines if routes are matched strictly, where the trailing `/` is not * optional. Defaults to `false`. */ strict?: boolean; } /** Middleware that will be called by the router when handling a specific * parameter, which the middleware will be called when a request matches the * route parameter. */ export interface RouterParamMiddleware = RouteParams, S extends State = Record> { (param: string, context: RouterContext, next: () => Promise): Promise | unknown; router?: Router; } interface ParamsDictionary { [key: string]: string; } type RemoveTail = S extends `${infer P}${Tail}` ? P : S; type GetRouteParams = RemoveTail, `-${string}`>, `.${string}`>; /** A dynamic type which attempts to determine the route params based on * matching the route string. */ export type RouteParams = string extends Route ? ParamsDictionary : Route extends `${string}(${string}` ? ParamsDictionary : Route extends `${string}:${infer Rest}` ? (GetRouteParams extends never ? ParamsDictionary : GetRouteParams extends `${infer ParamName}?` ? { [P in ParamName]?: string; } : { [P in GetRouteParams]: string; }) & (Rest extends `${GetRouteParams}${infer Next}` ? RouteParams : unknown) : Record; type LayerOptions = TokensToRegexpOptions & ParseOptions & { ignoreCaptures?: boolean; name?: string; }; type UrlOptions = TokensToRegexpOptions & ParseOptions & { /** When generating a URL from a route, add the query to the URL. If an * object */ query?: URLSearchParams | Record | string; }; /** An internal class used to group together middleware when using multiple * middlewares with a router. */ export declare class Layer = RouteParams, S extends State = Record> { #private; methods: HTTPMethods[]; name?: string; path: string; stack: RouterMiddleware[]; constructor(path: string, methods: HTTPMethods[], middleware: RouterMiddleware | RouterMiddleware[], { name, ...opts }?: LayerOptions); clone(): Layer; match(path: string): boolean; params(captures: string[], existingParams?: RouteParams): RouteParams; captures(path: string): string[]; url(params?: RouteParams, options?: UrlOptions): string; param(param: string, fn: RouterParamMiddleware): this; setPrefix(prefix: string): this; toJSON(): Route; } /** An interface for registering middleware that will run when certain HTTP * methods and paths are requested, as well as provides a way to parameterize * parts of the requested path. * * ### Basic example * * ```ts * import { Application, Router } from "https://deno.land/x/oak/mod.ts"; * * const router = new Router(); * router.get("/", (ctx, next) => { * // handle the GET endpoint here * }); * router.all("/item/:item", (ctx, next) => { * // called for all HTTP verbs/requests * ctx.params.item; // contains the value of `:item` from the parsed URL * }); * * const app = new Application(); * app.use(router.routes()); * app.use(router.allowedMethods()); * * app.listen({ port: 8080 }); * ``` */ export declare class Router> { #private; constructor(opts?: RouterOptions); /** Register named middleware for the specified routes when specified methods * are requested. */ add = RouteParams, S extends State = RS>(methods: HTTPMethods[] | HTTPMethods, name: string, path: R, middleware: RouterMiddleware, ...middlewares: RouterMiddleware[]): Router; /** Register middleware for the specified routes when the specified methods is * requested. */ add = RouteParams, S extends State = RS>(methods: HTTPMethods[] | HTTPMethods, path: R, middleware: RouterMiddleware, ...middlewares: RouterMiddleware[]): Router; /** Register middleware for the specified routes when the specified methods * are requested with explicit path parameters. */ add

, S extends State = RS>(methods: HTTPMethods[] | HTTPMethods, nameOrPath: string, pathOrMiddleware: string | RouterMiddleware, ...middleware: RouterMiddleware[]): Router; /** Register named middleware for the specified routes when the `DELETE`, * `GET`, `POST`, or `PUT` method is requested. */ all = RouteParams, S extends State = RS>(name: string, path: R, middleware: RouterMiddleware, ...middlewares: RouterMiddleware[]): Router; /** Register middleware for the specified routes when the `DELETE`, * `GET`, `POST`, or `PUT` method is requested. */ all = RouteParams, S extends State = RS>(path: R, middleware: RouterMiddleware, ...middlewares: RouterMiddleware[]): Router; /** Register middleware for the specified routes when the `DELETE`, * `GET`, `POST`, or `PUT` method is requested with explicit path parameters. */ all

, S extends State = RS>(nameOrPath: string, pathOrMiddleware: string | RouterMiddleware, ...middleware: RouterMiddleware[]): Router; /** Middleware that handles requests for HTTP methods registered with the * router. If none of the routes handle a method, then "not allowed" logic * will be used. If a method is supported by some routes, but not the * particular matched router, then "not implemented" will be returned. * * The middleware will also automatically handle the `OPTIONS` method, * responding with a `200 OK` when the `Allowed` header sent to the allowed * methods for a given route. * * By default, a "not allowed" request will respond with a `405 Not Allowed` * and a "not implemented" will respond with a `501 Not Implemented`. Setting * the option `.throw` to `true` will cause the middleware to throw an * `HTTPError` instead of setting the response status. The error can be * overridden by providing a `.notImplemented` or `.notAllowed` method in the * options, of which the value will be returned will be thrown instead of the * HTTP error. */ allowedMethods(options?: RouterAllowedMethodsOptions): Middleware; /** Register named middleware for the specified routes when the `DELETE`, * method is requested. */ delete = RouteParams, S extends State = RS>(name: string, path: R, middleware: RouterMiddleware, ...middlewares: RouterMiddleware[]): Router; /** Register middleware for the specified routes when the `DELETE`, * method is requested. */ delete = RouteParams, S extends State = RS>(path: R, middleware: RouterMiddleware, ...middlewares: RouterMiddleware[]): Router; /** Register middleware for the specified routes when the `DELETE`, * method is requested with explicit path parameters. */ delete

, S extends State = RS>(nameOrPath: string, pathOrMiddleware: string | RouterMiddleware, ...middleware: RouterMiddleware[]): Router; /** Iterate over the routes currently added to the router. To be compatible * with the iterable interfaces, both the key and value are set to the value * of the route. */ entries(): IterableIterator<[Route, Route]>; /** Iterate over the routes currently added to the router, calling the * `callback` function for each value. */ forEach(callback: (value1: Route, value2: Route, router: this) => void, thisArg?: any): void; /** Register named middleware for the specified routes when the `GET`, * method is requested. */ get = RouteParams, S extends State = RS>(name: string, path: R, middleware: RouterMiddleware, ...middlewares: RouterMiddleware[]): Router; /** Register middleware for the specified routes when the `GET`, * method is requested. */ get = RouteParams, S extends State = RS>(path: R, middleware: RouterMiddleware, ...middlewares: RouterMiddleware[]): Router; /** Register middleware for the specified routes when the `GET`, * method is requested with explicit path parameters. */ get

, S extends State = RS>(nameOrPath: string, pathOrMiddleware: string | RouterMiddleware, ...middleware: RouterMiddleware[]): Router; /** Register named middleware for the specified routes when the `HEAD`, * method is requested. */ head = RouteParams, S extends State = RS>(name: string, path: R, middleware: RouterMiddleware, ...middlewares: RouterMiddleware[]): Router; /** Register middleware for the specified routes when the `HEAD`, * method is requested. */ head = RouteParams, S extends State = RS>(path: R, middleware: RouterMiddleware, ...middlewares: RouterMiddleware[]): Router; /** Register middleware for the specified routes when the `HEAD`, * method is requested with explicit path parameters. */ head

, S extends State = RS>(nameOrPath: string, pathOrMiddleware: string | RouterMiddleware, ...middleware: RouterMiddleware[]): Router; /** Iterate over the routes currently added to the router. To be compatible * with the iterable interfaces, the key is set to the value of the route. */ keys(): IterableIterator>; /** Register named middleware for the specified routes when the `OPTIONS`, * method is requested. */ options = RouteParams, S extends State = RS>(name: string, path: R, middleware: RouterMiddleware, ...middlewares: RouterMiddleware[]): Router; /** Register middleware for the specified routes when the `OPTIONS`, * method is requested. */ options = RouteParams, S extends State = RS>(path: R, middleware: RouterMiddleware, ...middlewares: RouterMiddleware[]): Router; /** Register middleware for the specified routes when the `OPTIONS`, * method is requested with explicit path parameters. */ options

, S extends State = RS>(nameOrPath: string, pathOrMiddleware: string | RouterMiddleware, ...middleware: RouterMiddleware[]): Router; /** Register param middleware, which will be called when the particular param * is parsed from the route. */ param(param: keyof RouteParams, middleware: RouterParamMiddleware, S>): Router; /** Register named middleware for the specified routes when the `PATCH`, * method is requested. */ patch = RouteParams, S extends State = RS>(name: string, path: R, middleware: RouterMiddleware, ...middlewares: RouterMiddleware[]): Router; /** Register middleware for the specified routes when the `PATCH`, * method is requested. */ patch = RouteParams, S extends State = RS>(path: R, middleware: RouterMiddleware, ...middlewares: RouterMiddleware[]): Router; /** Register middleware for the specified routes when the `PATCH`, * method is requested with explicit path parameters. */ patch

, S extends State = RS>(nameOrPath: string, pathOrMiddleware: string | RouterMiddleware, ...middleware: RouterMiddleware[]): Router; /** Register named middleware for the specified routes when the `POST`, * method is requested. */ post = RouteParams, S extends State = RS>(name: string, path: R, middleware: RouterMiddleware, ...middlewares: RouterMiddleware[]): Router; /** Register middleware for the specified routes when the `POST`, * method is requested. */ post = RouteParams, S extends State = RS>(path: R, middleware: RouterMiddleware, ...middlewares: RouterMiddleware[]): Router; /** Register middleware for the specified routes when the `POST`, * method is requested with explicit path parameters. */ post

, S extends State = RS>(nameOrPath: string, pathOrMiddleware: string | RouterMiddleware, ...middleware: RouterMiddleware[]): Router; /** Set the router prefix for this router. */ prefix(prefix: string): this; /** Register named middleware for the specified routes when the `PUT` * method is requested. */ put = RouteParams, S extends State = RS>(name: string, path: R, middleware: RouterMiddleware, ...middlewares: RouterMiddleware[]): Router; /** Register middleware for the specified routes when the `PUT` * method is requested. */ put = RouteParams, S extends State = RS>(path: R, middleware: RouterMiddleware, ...middlewares: RouterMiddleware[]): Router; /** Register middleware for the specified routes when the `PUT` * method is requested with explicit path parameters. */ put

, S extends State = RS>(nameOrPath: string, pathOrMiddleware: string | RouterMiddleware, ...middleware: RouterMiddleware[]): Router; /** Register a direction middleware, where when the `source` path is matched * the router will redirect the request to the `destination` path. A `status` * of `302 Found` will be set by default. * * The `source` and `destination` can be named routes. */ redirect(source: string, destination: string | URL, status?: RedirectStatus): this; /** Return middleware that will do all the route processing that the router * has been configured to handle. Typical usage would be something like this: * * ```ts * import { Application, Router } from "https://deno.land/x/oak/mod.ts"; * * const app = new Application(); * const router = new Router(); * * // register routes * * app.use(router.routes()); * app.use(router.allowedMethods()); * await app.listen({ port: 80 }); * ``` */ routes(): Middleware; /** Generate a URL pathname for a named route, interpolating the optional * params provided. Also accepts an optional set of options. */ url

= RouteParams>(name: string, params?: P, options?: UrlOptions): string | undefined; /** Register middleware to be used on every matched route. */ use

= RouteParams, S extends State = RS>(middleware: RouterMiddleware, ...middlewares: RouterMiddleware[]): Router; /** Register middleware to be used on every route that matches the supplied * `path`. */ use = RouteParams, S extends State = RS>(path: R, middleware: RouterMiddleware, ...middlewares: RouterMiddleware[]): Router; /** Register middleware to be used on every route that matches the supplied * `path` with explicit path parameters. */ use

, S extends State = RS>(path: string, middleware: RouterMiddleware, ...middlewares: RouterMiddleware[]): Router; use

= RouteParams, S extends State = RS>(path: string[], middleware: RouterMiddleware, ...middlewares: RouterMiddleware[]): Router; /** Iterate over the routes currently added to the router. */ values(): IterableIterator, RS>>; /** Provide an iterator interface that iterates over the routes registered * with the router. */ [Symbol.iterator](): IterableIterator, RS>>; /** Generate a URL pathname based on the provided path, interpolating the * optional params provided. Also accepts an optional set of options. */ static url(path: R, params?: RouteParams, options?: UrlOptions): string; } export {};