UNPKG

@sapphire/plugin-api

Version:

Plugin for @sapphire/framework to expose a REST API

1,251 lines (1,231 loc) • 43.7 kB
import { AsyncEventEmitter } from '@vladfrangu/async_event_emitter'; import { IncomingMessage, ServerResponse, Server as Server$1, ServerOptions as ServerOptions$1 } from 'node:http'; import { ListenOptions } from 'node:net'; import { Piece, Store } from '@sapphire/pieces'; import { Awaitable } from '@sapphire/utilities'; import { Blob } from 'node:buffer'; import { Request, FormData } from 'undici'; import { Snowflake, OAuth2Scopes, RESTGetAPICurrentUserResult, RESTGetAPICurrentUserGuildsResult, RESTGetAPICurrentUserConnectionsResult } from 'discord.js'; import { Readable } from 'node:stream'; import { MimeType } from '@sapphire/iana-mime-types'; export * from '@sapphire/iana-mime-types'; declare class Auth { #private; /** * The client's application id, this can be retrieved in Discord Developer Portal at https://discord.com/developers/applications. * @since 1.0.0 */ id: Snowflake; /** * The name for the cookie, this will be used to identify a Secure HttpOnly cookie. * @since 1.0.0 */ cookie: string; /** * The scopes defined at https://discord.com/developers/docs/topics/oauth2#shared-resources-oauth2-scopes. * @since 1.0.0 */ scopes: readonly OAuth2Scopes[]; /** * The redirect uri. * @since 1.0.0 */ redirect: string | undefined; /** * The transformers used for {@link Auth.fetchData}. * @since 1.4.0 */ transformers: LoginDataTransformer[]; domainOverwrite: string | null; private constructor(); /** * The client secret, this can be retrieved in Discord Developer Portal at https://discord.com/developers/applications. * @since 1.0.0 */ get secret(): string; /** * Encrypts an object with aes-256-cbc to use as a token. * @since 1.0.0 * @param data An object to encrypt */ encrypt(data: AuthData): string; /** * Decrypts an object with aes-256-cbc to use as a token. * @since 1.0.0 * @param token An data to decrypt */ decrypt(token: string): AuthData | null; /** * Retrieves the data for a specific user. * @since 1.4.0 * @param token The access token from the user. */ fetchData(token: string): Promise<LoginData>; private fetchInformation; static create(options?: ServerOptionsAuth): Auth | null; } /** * Defines the authentication data, this is to be encrypted and decrypted by the server. * @since 1.0.0 */ interface AuthData { /** * The user ID. * @since 1.0.0 */ id: string; /** * The timestamp at which the token expires. * @since 1.0.0 */ expires: number; /** * The refresh token. * @since 1.0.0 */ refresh: string; /** * The access token. * @since 1.0.0 */ token: string; } /** * Defines the authentication options. * @since 1.0.0 */ interface ServerOptionsAuth { /** * The client's application id, this can be retrieved in Discord Developer Portal at https://discord.com/developers/applications. * @since 1.0.0 */ id: Snowflake; /** * The name for the cookie, this will be used to identify a Secure HttpOnly cookie. * @since 1.0.0 * @default 'SAPPHIRE_AUTH' */ cookie?: string; /** * The client secret, this can be retrieved in Discord Developer Portal at https://discord.com/developers/applications. * @since 1.0.0 */ secret: string; /** * The scopes defined at https://discord.com/developers/docs/topics/oauth2#shared-resources-oauth2-scopes. * @since 1.0.0 * @default [OAuth2Scopes.Identify] */ scopes?: OAuth2Scopes[]; /** * The redirect uri. This will default to {@link OAuth2BodyData.redirectUri} if missing. * @since 1.0.0 */ redirect?: string; /** * The login data transformers used for {@link Auth.fetchData}. * @since 1.4.0 * @default [] */ transformers?: LoginDataTransformer[]; /** * The domain that should be used for the cookie. This overwrites the automatic detection of the domain. * @remark if you want to support subdomains (`one.example.two` and `two.example.com`) then you need to use prefix your domain with a `.`, for example `.example.com` * @since 2.1.0 * @default undefined */ domainOverwrite?: string; } /** * The login data sent when fetching data from a user. * @since 1.4.0 */ interface LoginData { /** * The user data, defined when the `'identify'` scope is defined. * @since 1.4.0 */ user?: RESTGetAPICurrentUserResult | null; /** * The guilds data, defined when the `'guilds'` scope is defined. * @since 1.4.0 */ guilds?: RESTGetAPICurrentUserGuildsResult | null; /** * The connections data, defined when the `'connections'` scope is defined. * @since 1.4.0 */ connections?: RESTGetAPICurrentUserConnectionsResult | null; } /** * A login data transformer. * @since 1.4.0 */ interface LoginDataTransformer<T extends LoginData = LoginData> { /** * Transforms the object by mutating its properties or adding new ones. * @since 1.4.0 */ (data: LoginData): Awaitable<T>; } type MethodName = (typeof MethodNames)[number]; declare const MethodNames: readonly ["ACL", "BIND", "CHECKOUT", "CONNECT", "COPY", "DELETE", "GET", "HEAD", "LINK", "LOCK", "M-SEARCH", "MERGE", "MKACTIVITY", "MKCALENDAR", "MKCOL", "MOVE", "NOTIFY", "OPTIONS", "PATCH", "POST", "PROPFIND", "PROPPATCH", "PURGE", "PUT", "QUERY", "REBIND", "REPORT", "SEARCH", "SOURCE", "SUBSCRIBE", "TRACE", "UNBIND", "UNLINK", "UNLOCK", "UNSUBSCRIBE"]; declare class CookieStore extends Map<string, string> { protected request: ApiRequest; protected response: ApiResponse; private domain; private secure; constructor(request: ApiRequest, response: ApiResponse, secure: boolean, domainOverwrite?: string | null); add(name: string, value: string, options?: SecureCookieStoreSetOptions): void; remove(name: string): void; protected insert(name: string, entry: string): void; protected prepare(name: string, value: string, { expires, maxAge, domain, path, httpOnly }?: SecureCookieStoreSetOptions): string; /** * Parses a host using the {@linkplain https://github.com/remusao/tldts tldts} library to extract the domain. * This is used for the domain of the cookie * @param host The hot to parse * @returns Either the host in all lower case or the parsed domain, ready for use on cookies */ private getHostDomain; private static readonly octetRegExp; private static encodeCookieOctet; } interface SecureCookieStoreSetOptions { expires?: Date; maxAge?: number; domain?: string; path?: string; httpOnly?: boolean; } /** * @since 1.0.0 */ declare class ApiResponse<Request extends IncomingMessage = IncomingMessage> extends ServerResponse<Request> { /** * @since 1.0.0 */ cookies: CookieStore; /** * @since 1.0.0 */ ok(data?: unknown): void; /** * @since 1.0.0 */ created(data?: unknown): void; /** * @since 1.0.0 */ noContent(data?: unknown): void; /** * @since 1.0.0 */ badRequest(data?: unknown): void; /** * @since 1.0.0 */ unauthorized(data?: unknown): void; /** * @since 1.0.0 */ forbidden(data?: unknown): void; /** * @since 1.0.0 */ notFound(data?: unknown): void; /** * @since 7.0.0 */ methodNotAllowed(data?: unknown): void; /** * @since 1.0.0 */ conflict(data?: unknown): void; /** * @since 1.0.0 */ error(error: number | string, data?: unknown): void; /** * @since 1.0.0 */ respond(data: unknown): void; /** * @since 1.0.0 */ status(code: number): this; /** * @since 1.0.0 */ json(data: any): void; /** * @since 1.0.0 */ text(data: string): void; /** * @since 6.1.0 * * Sets the image content type and sends the image data in the response. * * @param type - The MIME type of the image (e.g., 'image/png'). * @param data - The image data as a `string`, {@link Buffer}, {@link Uint8Array}, or {@link ReadableStream}. */ image(type: Extract<MimeType, `image/${string}`>, data: string | Buffer | Uint8Array | Readable): void; /** * @since 5.1.0 */ html(code: number, data: string): void; /** * @since 1.0.0 */ setContentType(contentType: MimeType): this; } interface RouteOptions extends Piece.Options { /** * The route the piece should represent. * @since 1.0.0 * * @defaultValue The filesystem-based path, or the name if the location is virtual. * * @example * ```typescript * '/users' * // request.params -> {} * ``` * @example * ```typescript * '/guilds/[guild]/members/[member]' * // request.params -> { guild: '...', member: '...' } * ``` */ route?: string; /** * (RFC 7230 3.3.2) The maximum decimal number of octets. * @since 1.0.0 * * @defaultValue this.context.server.options.maximumBodyLength ?? 1024 * 1024 * 50 */ maximumBodyLength?: number; /** * The methods this route accepts. * @since 7.0.0 * * @defaultValue The method defined in the piece name, or none if not set. */ methods?: readonly MethodName[]; } /** * @since 1.0.0 * * @example A simple GET route that returns a JSON response: * ```typescript * // hello.get.ts * import { Route } from '@sapphire/plugin-api'; * * export class MyRoute extends Route { * public run(request: Route.Request, response: Route.Response) { * return response.json({ message: 'Hello, World!' }); * } * } * ``` * * ```bash * $ curl http://localhost:4000/hello * {"message":"Hello, World!"} * ``` * * @example A simple POST route that reads the body and returns it: * ```typescript * // echo.post.ts * import { Route } from '@sapphire/plugin-api'; * * export class MyRoute extends Route { * public run(request: Route.Request, response: Route.Response) { * return response.json(request.params); * } * } * ``` * * ```bash * $ curl -X POST -H "Content-Type: application/json" -d '{"hello":"world"}' http://localhost:4000/echo * {"hello":"world"} * ``` */ declare abstract class Route<Options extends Route.Options = Route.Options> extends Piece<Options, 'routes'> { /** * (RFC 7230 3.3.2) The maximum decimal number of octets. */ readonly maximumBodyLength: number; /** * The path this route represents. */ readonly path: readonly string[]; /** * The methods this route accepts. */ readonly methods: ReadonlySet<MethodName>; constructor(context: Route.LoaderContext, options?: Options); abstract run(request: Route.Request, response: Route.Response): Awaitable<unknown>; } declare namespace Route { /** @deprecated Use {@linkcode LoaderContext} instead. */ type Context = LoaderContext; type LoaderContext = Piece.LoaderContext<'routes'>; type Options = RouteOptions; type JSON = Piece.JSON; type LocationJSON = Piece.LocationJSON; type Request = ApiRequest; type Response = ApiResponse; } declare class RouterBranch { /** * The name of the branch. */ readonly name: string; /** * Whether or not the branch is dynamic. */ readonly dynamic: boolean; /** * The parent branch, if any. */ readonly parent: RouterBranch | null; /** * The node this branch is associated with. */ readonly node: RouterNode; /** * The methods supported by the branch's node or any of its children. */ supportedMethods: readonly string[]; private _staticChildren; private _dynamicChild; constructor(name: string, dynamic: boolean, parent: RouterBranch | null); /** * The path representing this branch * @version 7.0.0 */ get path(): string; /** * The branches the branch is associated with * @version 7.0.0 */ get children(): RouterBranch[]; /** * Whether or not the branch is empty * @version 7.0.0 */ get empty(): boolean; /** * Tries to find a branch given a path * @version 7.0.0 * * @param parts The parts of a path to find a node from * @returns The branch found, or null if not found */ find(parts: readonly string[]): RouterBranch | null; /** * Checks if the given name matches the branch * @version 7.0.0 * * @param name The name to match * @returns Whether or not the branch matches the name */ matches(name: string): boolean; /** * Returns the string representation of the branch * @version 7.0.0 * * @returns The string representation of the branch */ toString(): string; nodes(): IterableIterator<RouterNode>; protected _add(parts: readonly string[], index: number, route: Route): RouterNode; protected _remove(parts: readonly string[], index: number, route: Route): boolean; protected _performAdd(parts: readonly string[], index: number, route: Route): RouterNode; protected _performRemove(parts: readonly string[], index: number, route: Route): boolean; protected _find(parts: readonly string[], index: number): RouterBranch | null; protected _updateSupportedChildrenMethods(): void; } declare class RouterNode { #private; /** * The branch containing this node. */ readonly parent: RouterBranch; constructor(parent: RouterBranch); get path(): string; extractParameters(parts: readonly string[]): Record<string, string>; get(method: MethodName): Route | null; set(method: MethodName, route: Route): this; delete(method: MethodName, route: Route): boolean; methods(): IterableIterator<MethodName>; } declare class ApiRequest extends IncomingMessage { #private; /** * The query parameters. */ query: Record<string, string | string[]>; /** * The URI parameters. */ params: Record<string, string>; /** * The authorization information. This field indicates three possible values: * * - `undefined`: The authorization middleware has not been executed yet. * - `null`: The user is not authorized. * - `AuthData`: The user is authorized. */ auth?: AuthData | null; /** * The router node that matched the request. The field indicates three * possible values: * * - `undefined`: The router handler has not been executed yet. * - `null`: The router handler has been executed, but no node matched the * request. * - `RouterNode`: The router handler has been executed and a node matched * the request. * * @since 7.0.0 */ routerNode?: RouterNode | null; /** * The route that matched the request. The field indicates three possible * values: * * - `undefined`: The router handler has not been executed yet. * - `null`: The router handler has been executed, but no route matched the * request. * - `Route`: The router handler has been executed and a route matched the * request. * * @since 7.0.0 */ route?: Route | null; /** * The response object, used to validate the request's headers and body. */ asWeb(): Request; /** * Reads the request body and tries to parse using JSON or form-urlencoded. * * @example * ```typescript * const body = await request.readBody(); * ``` * * @returns The result of the body parsing */ readBody(): Promise<unknown>; /** * Reads the request body as an {@link ArrayBuffer}. * * @returns The result of the body parsing */ readBodyArrayBuffer(): Promise<ArrayBuffer>; /** * Reads the request body as a {@link Blob}. * * @returns The result of the body parsing */ readBodyBlob(): Promise<Blob>; /** * Reads the request body as a {@link FormData}. * * @remarks * * This will throw an error if the content type is not one of the following: * * - `application/x-www-form-urlencoded` * - `multipart/form-data` * * @returns The result of the body parsing */ readBodyFormData(): Promise<FormData>; /** * Reads the request body as text, using {@link TextDecoder}. Afterward, it * parses the body as JSON with {@link JSON.parse}. * * @returns The result of the body parsing */ readBodyJson(): Promise<unknown>; /** * Reads the request body as text, using {@link TextDecoder}. * * @returns The result of the body parsing */ readBodyText(): Promise<string>; /** * Identical to {@link ApiRequest.readBody}, but it validates the result. * * @param validator The validator function to use on the body parsing result * @returns The validated body */ readValidatedBody<Type>(validator: ValidatorFunction<unknown, Type>): Promise<Type>; /** * Identical to {@link ApiRequest.readBodyFormData}, but it validates the * result. * * @param validator The validator function to use on the body parsing result * @returns The validated body */ readValidatedBodyFormData<Type>(validator: ValidatorFunction<FormData, Type>): Promise<Type>; /** * Identical to {@link ApiRequest.readBodyJson}, but it validates the result. * * @param validator The validator function to use on the body parsing result * @returns The validated body */ readValidatedBodyJson<Type>(validator: ValidatorFunction<unknown, Type>): Promise<Type>; /** * Identical to {@link ApiRequest.readBodyText}, but it validates the result. * * @param validator The validator function to use on the body parsing result * @returns The validated body */ readValidatedBodyText<Type>(validator: ValidatorFunction<string, Type>): Promise<Type>; } type ValidatorFunction<Data, Type> = (data: Data) => Type; /** * The options for all middlewares. */ interface MiddlewareOptions extends Piece.Options { /** * The position to insert the middleware at. * @see Middleware#position * @default 1000 */ position?: number; } /** * @since 1.0.0 */ declare abstract class Middleware<Options extends Middleware.Options = Middleware.Options> extends Piece<Options, 'middlewares'> { /** * The position the middleware has. The {@link MiddlewareStore} will run all middlewares with lower position than * this one. * * The built-in middlewares follow the following positions: * - headers: 10 * - body: 20 * - cookies: 30 * - auth: 40 */ readonly position: number; constructor(context: Middleware.LoaderContext, options?: Options); /** * The method to be overridden by other middlewares. * @param request The client's request. * @param response The server's response. * @param route The route that matched this request, will be `null` if none matched. */ abstract run(request: Middleware.Request, response: Middleware.Response): Awaitable<unknown>; } declare namespace Middleware { /** @deprecated Use {@linkcode LoaderContext} instead. */ type Context = LoaderContext; type LoaderContext = Piece.LoaderContext<'middlewares'>; type Options = MiddlewareOptions; type JSON = Piece.JSON; type LocationJSON = Piece.LocationJSON; type Request = ApiRequest; type Response = ApiResponse; } /** * @since 1.0.0 */ declare class MiddlewareStore extends Store<Middleware, 'middlewares'> { /** * The sorted middlewares, in ascending order of see {@link Middleware.position}. */ readonly sortedMiddlewares: Middleware[]; constructor(); run(request: Middleware.Request, response: Middleware.Response): Promise<void>; set(key: string, value: Middleware): this; delete(key: string): boolean; clear(): void; } declare class RouterRoot extends RouterBranch { constructor(); /** * Adds a route to the branch * * @param route The route to add * @returns The node the route was added to */ add(route: Route): RouterNode; /** * Removes a route from the branch * * @param route The route to remove * @returns Whether or not the route was removed */ remove(route: Route): boolean; get path(): string; toString(): string; static makeRoutePathForPiece(directories: readonly string[], name: string): string; static normalize(path: string | null | undefined): string[]; static extractMethod(path: string | readonly string[]): MethodName | null; } /** * @since 1.0.0 */ declare class RouteStore extends Store<Route, 'routes'> { readonly router: RouterRoot; constructor(); } declare enum ServerEvent { Error = "error", Request = "request", RouterBranchNotFound = "routerBranchNotFound", RouterBranchMethodNotAllowed = "routerBranchMethodNotAllowed", RouterFound = "routerFound", RouteError = "routeError", MiddlewareFailure = "middlewareFailure", MiddlewareError = "middlewareError", MiddlewareSuccess = "middlewareSuccess" } interface ServerEvents { [ServerEvent.Error]: [error: Error, request: ApiRequest, response: ApiResponse]; [ServerEvent.Request]: [request: ApiRequest, response: ApiResponse]; [ServerEvent.RouterBranchNotFound]: [request: ApiRequest, response: ApiResponse]; [ServerEvent.RouterBranchMethodNotAllowed]: [request: ApiRequest, response: ApiResponse, node: RouterBranch]; [ServerEvent.RouterFound]: [request: ApiRequest, response: ApiResponse]; [ServerEvent.RouteError]: [error: Error, request: ApiRequest, response: ApiResponse]; [ServerEvent.MiddlewareFailure]: [request: ApiRequest, response: ApiResponse]; [ServerEvent.MiddlewareSuccess]: [request: Route.Request, response: Route.Response, route: Route]; [ServerEvent.MiddlewareError]: [error: Error, request: ApiRequest, response: ApiResponse]; } /** * @since 1.0.0 */ declare class Server extends AsyncEventEmitter<ServerEvents> { /** * The routes this server holds. * @since 1.0.0 */ readonly routes: RouteStore; /** * The middlewares this server holds. * @since 1.0.0 */ readonly middlewares: MiddlewareStore; /** * The authentication system. * @since 1.0.0 */ readonly auth: Auth | null; /** * The http.Server instance that manages the recieved HTTP requests. * @since 1.0.0 */ readonly server: Server$1; /** * The options for this server. * @since 1.0.0 */ readonly options: AuthLessServerOptions; /** * @since 1.0.0 * @param options The options for this server */ constructor({ auth, ...options }?: ServerOptions); connect(): Promise<void>; disconnect(): Promise<void>; } /** * RFC 1341 4: Defines a Content-Type's type, which follows the following structure: * * - `type` = `text` | `multipart` | `message` | `image` | `audio` | `video` | `application` | x-token * - `x-token` = The two characters "X-" followed, with no intervening white space, by any token * @since 1.3.0 */ type ContentTypeType = 'text' | 'multipart' | 'message' | 'image' | 'audio' | 'video' | 'application' | `X-${string}`; /** * RFC 1341 4: Defines a Content-Type's parameter, which follows the following structure: * * - `parameter` = `attribute` "=" `value` * - `attribute` = `token` * - `value` = `token` / `quoted-string` * - `token` = `1*<any CHAR except "SPACE", "CTLs", or "tspecials">` * - `tspecials` = `(` | `)` | `<` | `>` | `@` | `,` | `;` | `:` | `\` | `"` | `/` | `[` | `]` | `?` | `.` | `=` * * @note `tspecials` must be in quoted-string, to use within parameter values. * @note The definition of `tspecials` is the same as the RFC 822 definition of `specials` with the addition of the * three characters `/`, `?`, and `=`. * @since 1.3.0 */ type ContentTypeParameter = `; ${string}=${string}`; /** * RFC 1341 4: Defines the syntax for a Content-Type field without parameters, which follows the following structure: * `type "/" subtype`. * @since 7.0.0 */ type GenericMimeType = `${ContentTypeType}/${string}`; /** * RFC 1341 4: Defines the syntax for a Content-Type field, which follows the following structure: * `type "/" subtype *[";" parameter]`. * @since 7.0.0 */ type GenericParametrizedMimeType = `${GenericMimeType}${'' | ContentTypeParameter}`; /** * The API options. * @since 1.0.0 */ interface ServerOptions { /** * The prefix for all routes, e.g. `v1/`. * @since 1.0.0 * @default '' */ prefix?: string; /** * The origin header to be set on every request at 'Access-Control-Allow-Origin'. * @since 1.0.0 * @default '*' */ origin?: string; /** * (RFC 7230 3.3.2) The maximum decimal number of octets. * @since 1.0.0 * @default 1024 * 1024 * 50 */ maximumBodyLength?: number; /** * The HTTP server options. * @since 1.0.0 * @default {} */ server?: ServerOptions$1; /** * The HTTP listen options. * @since 1.0.0 * @default { port: 4000 } */ listenOptions?: ListenOptions; /** * The auth options. If neither `auth` nor `auth.secret` are defined, auth-related routes and middlewares will be * automatically disabled. * @since 1.0.0 * @default {} */ auth?: ServerOptionsAuth; /** * Whether the server should connect upon being when the plugin is loaded. * @since 3.2.0 * @default true */ automaticallyConnect?: boolean; } /** * The {@link ServerOptions} without {@link ServerOptions.auth}. * @since 1.0.0 */ type AuthLessServerOptions = Omit<ServerOptions, 'auth'>; declare enum HttpCodes { /** * Standard response for successful HTTP requests. The actual response will * depend on the request method used. In a GET request, the response will * contain an entity corresponding to the requested resource. In a POST * request, the response will contain an entity describing or containing the * result of the action. */ OK = 200, /** * The request has been fulfilled, resulting in the creation of a new * resource. */ Created = 201, /** * The request has been accepted for processing, but the processing has not * been completed. The request might or might not be eventually acted upon, * and may be disallowed when processing occurs. */ Accepted = 202, /** * The server is a transforming proxy (e.g. a Web accelerator) that received * a 200 OK from its origin, but is returning a modified version of the * origin's response. */ NonAuthoritativeInformation = 203, /** * The server successfully processed the request, and is not returning any * content. */ NoContent = 204, /** * The server successfully processed the request, asks that the requester * reset its document view, and is not returning any content. */ ResetContent = 205, /** * (RFC 7233) The server is delivering only part of the resource (byte * serving) due to a range header sent by the client. The range header is * used by HTTP clients to enable resuming of interrupted downloads, or * split a download into multiple simultaneous streams. */ PartialContent = 206, /** * (WebDAV; RFC 4918) The message body that follows is by default an XML * message and can contain a number of separate response codes, depending on * how many sub-requests were made. */ MultiStatus = 207, /** * (WebDAV; RFC 5842) The members of a DAV binding have already been * enumerated in a preceding part of the (multistatus) response, and are not * being included again. */ AlreadyReported = 208, /** * (RFC 3229) The server has fulfilled a request for the resource, and the * response is a representation of the result of one or more * instance-manipulations applied to the current instance. */ IMUsed = 226, /** * Indicates multiple options for the resource from which the client may * choose (via agent-driven content negotiation). For example, this code * could be used to present multiple video format options, to list files * with different filename extensions, or to suggest word-sense * disambiguation. */ MultipleChoices = 300, /** * This and all future requests should be directed to the given URI. */ MovedPermanently = 301, /** * (Previously "Moved temporarily") Tells the client to look at (browse to) * another URL. 302 has been superseded by 303 and 307. This is an example * of industry practice contradicting the standard. The HTTP/1.0 * specification (RFC 1945) required the client to perform a temporary * redirect (the original describing phrase was "Moved Temporarily"), but * popular browsers implemented 302 with the functionality of a 303 See * Other. Therefore, HTTP/1.1 added status codes 303 and 307 to distinguish * between the two behaviours. However, some Web applications and frameworks * use the 302 status code as if it were the 303. */ Found = 302, /** * The response to the request can be found under another URI using the GET * method. When received in response to a POST (or PUT/DELETE), the client * should presume that the server has received the data and should issue a * new GET request to the given URI. */ SeeOther = 303, /** * (RFC 7232) Indicates that the resource has not been modified since the * version specified by the request headers If-Modified-Since or * If-None-Match. In such case, there is no need to retransmit the resource * since the client still has a previously-downloaded copy. */ NotModified = 304, /** * The requested resource is available only through a proxy, the address for * which is provided in the response. For security reasons, many HTTP * clients (such as Mozilla Firefox and Internet Explorer) do not obey this * status code. */ UseProxy = 305, /** * No longer used. Originally meant "Subsequent requests should use the * specified proxy.". */ SwitchProxy = 306, /** * In this case, the request should be repeated with another URI; however, * future requests should still use the original URI. In contrast to how 302 * was historically implemented, the request method is not allowed to be * changed when reissuing the original request. For example, a POST request * should be repeated using another POST request. */ TemporaryRedirect = 307, /** * (RFC 7538) The request and all future requests should be repeated using * another URI. 307 and 308 parallel the behaviors of 302 and 301, but do * not allow the HTTP method to change. So, for example, submitting a form * to a permanently redirected resource may continue smoothly. */ PermanentRedirect = 308, /** * The server cannot or will not process the request due to an apparent * client error (e.g., malformed request syntax, size too large, invalid * request message framing, or deceptive request routing). */ BadRequest = 400, /** * (RFC 7235) Similar to 403 Forbidden, but specifically for use when * authentication is required and has failed or has not yet been provided. * The response must include a WWW-Authenticate header field containing a * challenge applicable to the requested resource. See Basic access * authentication and Digest access authentication. 401 semantically means * "unauthorised", the user does not have valid authentication credentials * for the target resource. */ Unauthorized = 401, /** * Reserved for future use. The original intention was that this code might * be used as part of some form of digital cash or micropayment scheme, as * proposed, for example, by GNU Taler, but that has not yet happened, and * this code is not widely used. Google Developers API uses this status if a * particular developer has exceeded the daily limit on requests. Sipgate * uses this code if an account does not have sufficient funds to start a * call. Shopify uses this code when the store has not paid their fees and * is temporarily disabled. Stripe uses this code for failed payments where * parameters were correct, for example blocked fraudulent payments. */ PaymentRequired = 402, /** * The request contained valid data and was understood by the server, but * the server is refusing action. This may be due to the user not having the * necessary permissions for a resource or needing an account of some sort, * or attempting a prohibited action (e.g. creating a duplicate record * where only one is allowed). This code is also typically used if the * request provided authentication by answering the WWW-Authenticate header * field challenge, but the server did not accept that authentication. The * request should not be repeated. */ Forbidden = 403, /** * The requested resource could not be found but may be available in the * future. Subsequent requests by the client are permissible. */ NotFound = 404, /** * A request method is not supported for the requested resource; for example, * a GET request on a form that requires data to be presented via POST, or a * PUT request on a read-only resource. */ MethodNotAllowed = 405, /** * The requested resource is capable of generating only content not * acceptable according to the Accept headers sent in the request. See Content negotiation. */ NotAcceptable = 406, /** * (RFC 7235) The client must first authenticate itself with the proxy. */ ProxyAuthenticationRequired = 407, /** * The server timed out waiting for the request. According to HTTP * specifications: "The client did not produce a request within the time * that the server was prepared to wait. The client MAY repeat the request * without modifications at any later time." */ RequestTimeout = 408, /** * Indicates that the request could not be processed because of conflict in * the current state of the resource, such as an edit conflict between * multiple simultaneous updates. */ Conflict = 409, /** * Indicates that the resource requested is no longer available and will not * be available again. This should be used when a resource has been * intentionally removed and the resource should be purged. Upon receiving a * 410 status code, the client should not request the resource in the future. * Clients such as search engines should remove the resource from their * indices. Most use cases do not require clients and search engines to * purge the resource, and a "404 Not Found" may be used instead. */ Gone = 410, /** * The request did not specify the length of its content, which is required * by the requested resource. */ LengthRequired = 411, /** * (RFC 7232) The server does not meet one of the preconditions that the * requester put on the request header fields. */ PreconditionFailed = 412, /** * (RFC 7231) The request is larger than the server is willing or able to * process. Previously called "Request Entity Too Large". */ PayloadTooLarge = 413, /** * (RFC 7231) The URI provided was too long for the server to process. Often * the result of too much data being encoded as a query-string of a GET * request, in which case it should be converted to a POST request. Called * "Request-URI Too Long" previously. */ URITooLong = 414, /** * (RFC 7231) The request entity has a media type which the server or * resource does not support. For example, the client uploads an image as * image/svg+xml, but the server requires that images use a different format. */ UnsupportedMediaType = 415, /** * (RFC 7233) The client has asked for a portion of the file (byte serving), * but the server cannot supply that portion. For example, if the client * asked for a part of the file that lies beyond the end of the file. Called * "Requested Range Not Satisfiable" previously. */ RangeNotSatisfiable = 416, /** * The server cannot meet the requirements of the Expect request-header * field. */ ExpectationFailed = 417, /** * (RFC 2324, RFC 7168) This code was defined in 1998 as one of the * traditional IETF April Fools' jokes, in RFC 2324, Hyper Text Coffee Pot * Control Protocol, and is not expected to be implemented by actual HTTP * servers. The RFC specifies this code should be returned by teapots * requested to brew coffee. This HTTP status is used as an Easter egg in * some websites, such as Google.com's I'm a teapot easter egg. */ IAmATeapot = 418, /** * Returned by the Twitter Search and Trends API when the client is being rate limited. * The text is a quote from 'Demolition Man' and the '420' code is likely a reference * to this number's association with marijuana. Other services may wish to implement * the 429 Too Many Requests response code instead. */ EnhanceYourCalm = 420, /** * (RFC 7540) The request was directed at a server that is not able to * produce a response (for example because of connection reuse). */ MisdirectedRequest = 421, /** * (WebDAV; RFC 4918) The request was well-formed but was unable to be * followed due to semantic errors. */ UnprocessableEntity = 422, /** * (WebDAV; RFC 4918) The resource that is being accessed is locked. */ Locked = 423, /** * (WebDAV; RFC 4918) The request failed because it depended on another * request and that request failed (e.g., a PROPPATCH). */ FailedDependency = 424, /** * (RFC 8470) Indicates that the server is unwilling to risk processing a * request that might be replayed. */ TooEarly = 425, /** * The client should switch to a different protocol such as TLS/1.0, given * in the Upgrade header field. */ UpgradeRequired = 426, /** * (RFC 6585) The origin server requires the request to be conditional. * Intended to prevent the 'lost update' problem, where a client GETs a * resource's state, modifies it, and PUTs it back to the server, when * meanwhile a third party has modified the state on the server, leading to * a conflict. */ PreconditionRequired = 428, /** * (RFC 6585) The user has sent too many requests in a given amount of time. * Intended for use with rate-limiting schemes. */ TooManyRequests = 429, /** * (RFC 6585) The server is unwilling to process the request because either * an individual header field, or all the header fields collectively, are * too large. */ RequestHeaderFieldsTooLarge = 431, /** * (RFC 7725) A server operator has received a legal demand to deny access * to a resource or to a set of resources that includes the requested * resource. The code 451 was chosen as a reference to the novel Fahrenheit * 451 (see the Acknowledgements in the RFC). */ UnavailableForLegalReasons = 451, /** * A generic error message, given when an unexpected condition was * encountered and no more specific message is suitable. */ InternalServerError = 500, /** * The server either does not recognize the request method, or it lacks the * ability to fulfil the request. Usually this implies future availability * (e.g., a new feature of a web-service API). */ NotImplemented = 501, /** * The server was acting as a gateway or proxy and received an invalid * response from the upstream server. */ BadGateway = 502, /** * The server cannot handle the request (because it is overloaded or down * for maintenance). Generally, this is a temporary state. */ ServiceUnavailable = 503, /** * The server was acting as a gateway or proxy and did not receive a timely * response from the upstream server. */ GatewayTimeout = 504, /** * The server does not support the HTTP protocol version used in the request. */ HTTPVersionNotSupported = 505, /** * (RFC 2295) Transparent content negotiation for the request results in a * circular reference. */ VariantAlsoNegotiates = 506, /** * (WebDAV; RFC 4918) The server is unable to store the representation * needed to complete the request. */ InsufficientStorage = 507, /** * (WebDAV; RFC 5842) The server detected an infinite loop while processing * the request (sent instead of 208 Already Reported). */ LoopDetected = 508, /** * (RFC 2774) Further extensions to the request are required for the server * to fulfil it. */ NotExtended = 510, /** * (RFC 6585) The client needs to authenticate to gain network access. * Intended for use by intercepting proxies used to control access to the * network (e.g., "captive portals" used to require agreement to Terms of * Service before granting full Internet access via a Wi-Fi hotspot). */ NetworkAuthenticationRequired = 511 } declare function loadListeners(): void; declare function loadMiddlewares(): void; declare function loadRoutes(): void; declare module 'discord.js' { interface Client { server: Server; } interface ClientOptions { api?: ServerOptions; } } declare module '@sapphire/pieces' { interface StoreRegistryEntries { routes: RouteStore; middlewares: MiddlewareStore; } interface Container { server: Server; } } /** * The [@sapphire/plugin-api](https://github.com/sapphiredev/plugins/blob/main/packages/api) version that you are currently using. * An example use of this is showing it of in a bot information command. * * Note to Sapphire developers: This needs to explicitly be `string` so it is not typed as the string that gets replaced by esbuild */ declare const version: string; export { ApiRequest, ApiResponse, Auth, type AuthData, type AuthLessServerOptions, type ContentTypeParameter, type ContentTypeType, CookieStore, type GenericMimeType, type GenericParametrizedMimeType, HttpCodes, type LoginData, type LoginDataTransformer, type MethodName, MethodNames, Middleware, type MiddlewareOptions, MiddlewareStore, Route, type RouteOptions, RouteStore, RouterBranch, RouterNode, RouterRoot, type SecureCookieStoreSetOptions, Server, ServerEvent, type ServerEvents, type ServerOptions, type ServerOptionsAuth, type ValidatorFunction, loadListeners, loadMiddlewares, loadRoutes, version };