@nestjs/platform-fastify
Version:
Run NestJS on Fastify: the HTTP adapter with Fastify's plugins, JSON schemas and serialization.
249 lines (248 loc) • 16.5 kB
TypeScript
import { FastifyCorsOptions } from '@fastify/cors';
import { Logger, type NestApplicationOptions, type RequestMethod, type VersioningOptions } from '@nestjs/common';
import { FastifyBaseLogger, FastifyBodyParser, FastifyInstance, FastifyPluginAsync, FastifyPluginCallback, FastifyRegister, FastifyReply, FastifyRequest, FastifyServerOptions, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerBase, RawServerDefault, RequestGenericInterface, RouteGenericInterface } from 'fastify';
import * as http from 'http';
import * as http2 from 'http2';
import * as https from 'https';
import { InjectOptions, Chain as LightMyRequestChain, Response as LightMyRequestResponse } from 'light-my-request';
import { type SecurityRequestHook, type VersionValue } from '@nestjs/common/internal';
import { AbstractHttpAdapter } from '@nestjs/core';
import { FastifyMultipartOptions, FastifyStaticOptions, FastifyViewOptions } from '../interfaces/external/index.js';
import { NestFastifyBodyParserOptions } from '../interfaces/index.js';
type FastifyAdapterBaseOptions<Server extends RawServerBase = RawServerDefault, Logger extends FastifyBaseLogger = FastifyBaseLogger> = FastifyServerOptions<Server, Logger> & {
skipMiddie?: boolean;
/**
* Controls the "@fastify/multipart" plugin (an optional peer dependency),
* which the upload interceptors from "@nestjs/platform-fastify/multipart"
* require.
*
* - unset (default): the adapter registers the plugin when an upload
* interceptor is used, unless it is already registered.
* - an object: plugin options (e.g. `limits`); the plugin is registered
* when the application initializes.
* - `true`: the same, with the plugin defaults.
* - `false`: the adapter never registers the plugin.
*/
multipart?: boolean | FastifyMultipartOptions;
};
type FastifyHttp2SecureOptions<Server extends http2.Http2SecureServer, Logger extends FastifyBaseLogger = FastifyBaseLogger> = FastifyAdapterBaseOptions<Server, Logger> & {
http2: true;
https: http2.SecureServerOptions;
};
type FastifyHttp2Options<Server extends http2.Http2Server, Logger extends FastifyBaseLogger = FastifyBaseLogger> = FastifyAdapterBaseOptions<Server, Logger> & {
http2: true;
http2SessionTimeout?: number;
};
type FastifyHttpsOptions<Server extends https.Server, Logger extends FastifyBaseLogger = FastifyBaseLogger> = FastifyAdapterBaseOptions<Server, Logger> & {
https: https.ServerOptions;
};
type FastifyHttpOptions<Server extends http.Server, Logger extends FastifyBaseLogger = FastifyBaseLogger> = FastifyAdapterBaseOptions<Server, Logger> & {
http: http.ServerOptions;
};
type VersionedRoute<TRequest, TResponse> = ((req: TRequest, res: TResponse, next: Function) => Function) & {
version: VersionValue;
versioningOptions: VersioningOptions;
};
/**
* The following type assertion is valid as we enforce "middie" plugin registration
* which enhances the FastifyRequest.RawRequest with the "originalUrl" property.
* ref https://github.com/fastify/middie/pull/16
* ref https://github.com/fastify/fastify/pull/559
*/
type FastifyRawRequest<TServer extends RawServerBase> = RawRequestDefaultExpression<TServer> & {
originalUrl?: string;
};
/**
* @publicApi
*/
export declare class FastifyAdapter<TServer extends RawServerBase = RawServerDefault, TRawRequest extends FastifyRawRequest<TServer> = FastifyRawRequest<TServer>, TRawResponse extends RawReplyDefaultExpression<TServer> = RawReplyDefaultExpression<TServer>, TRequest extends FastifyRequest<RequestGenericInterface, TServer, TRawRequest> = FastifyRequest<RequestGenericInterface, TServer, TRawRequest>, TReply extends FastifyReply<RouteGenericInterface, TServer, TRawRequest, TRawResponse> = FastifyReply<RouteGenericInterface, TServer, TRawRequest, TRawResponse>, TInstance extends FastifyInstance<TServer, TRawRequest, TRawResponse> = FastifyInstance<TServer, TRawRequest, TRawResponse>> extends AbstractHttpAdapter<TServer, TRequest, TReply> {
protected readonly logger: Logger;
protected readonly instance: TInstance;
protected _pathPrefix?: string;
private readonly openConnections;
private isClosing;
private isShuttingDown;
private return503OnClosing;
private _isParserRegistered;
private readonly registeredContentTypes;
private onRequestHook?;
private onResponseHook?;
private securityHook?;
private corsHook?;
private isMiddieRegistered;
private multipartMode;
private multipartOptions;
private isMultipartRequested;
private pendingMiddlewares;
private readonly middieContexts;
private versioningOptions?;
private readonly versionExtractorErrors;
private readonly versionConstraint;
get isParserRegistered(): boolean;
constructor(instanceOrOptions?: TInstance | FastifyHttp2Options<any> | FastifyHttp2SecureOptions<any> | FastifyHttpsOptions<any> | FastifyHttpOptions<any> | FastifyAdapterBaseOptions<TServer>);
private runLifecycleHook;
setOnRequestHook(hook: (request: TRequest, reply: TReply, done: (err?: Error) => void) => void | Promise<void>): void;
setOnResponseHook(hook: (request: TRequest, reply: TReply, done: (err?: Error) => void) => void | Promise<void>): void;
init(): Promise<void>;
listen(port: string | number, callback?: () => void): void;
listen(port: string | number, hostname: string, callback?: () => void): void;
private isValidPort;
get(...args: any[]): FastifyInstance<TServer, TRawRequest, TRawResponse, FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>;
post(...args: any[]): FastifyInstance<TServer, TRawRequest, TRawResponse, FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>;
head(...args: any[]): FastifyInstance<TServer, TRawRequest, TRawResponse, FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>;
delete(...args: any[]): FastifyInstance<TServer, TRawRequest, TRawResponse, FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>;
put(...args: any[]): FastifyInstance<TServer, TRawRequest, TRawResponse, FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>;
patch(...args: any[]): FastifyInstance<TServer, TRawRequest, TRawResponse, FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>;
options(...args: any[]): FastifyInstance<TServer, TRawRequest, TRawResponse, FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>;
search(...args: any[]): FastifyInstance<TServer, TRawRequest, TRawResponse, FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>;
query(...args: any[]): FastifyInstance<TServer, TRawRequest, TRawResponse, FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>;
propfind(...args: any[]): FastifyInstance<TServer, TRawRequest, TRawResponse, FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>;
proppatch(...args: any[]): FastifyInstance<TServer, TRawRequest, TRawResponse, FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>;
mkcol(...args: any[]): FastifyInstance<TServer, TRawRequest, TRawResponse, FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>;
copy(...args: any[]): FastifyInstance<TServer, TRawRequest, TRawResponse, FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>;
move(...args: any[]): FastifyInstance<TServer, TRawRequest, TRawResponse, FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>;
lock(...args: any[]): FastifyInstance<TServer, TRawRequest, TRawResponse, FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>;
unlock(...args: any[]): FastifyInstance<TServer, TRawRequest, TRawResponse, FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>;
all(...args: any[]): any;
applyVersionFilter(handler: Function, version: VersionValue, versioningOptions: VersioningOptions): VersionedRoute<TRequest, TReply>;
reply(response: TRawResponse | TReply, body: any, statusCode?: number): FastifyReply<RouteGenericInterface, TServer, TRawRequest, TRawResponse, unknown, import("fastify").FastifySchema, import("fastify").FastifyTypeProviderDefault, unknown>;
status(response: TRawResponse | TReply, statusCode: number): any;
end(response: TRawResponse | TReply, message?: string): void;
render(response: TReply & {
view: Function;
}, view: string, options: any): FastifyReply<RouteGenericInterface, RawServerDefault, http.IncomingMessage, http.ServerResponse<http.IncomingMessage>, unknown, import("fastify").FastifySchema, import("fastify").FastifyTypeProviderDefault, unknown>;
redirect(response: TReply, statusCode: number, url: string): FastifyReply<RouteGenericInterface, TServer, TRawRequest, TRawResponse, unknown, import("fastify").FastifySchema, import("fastify").FastifyTypeProviderDefault, unknown>;
setErrorHandler(handler: Parameters<TInstance['setErrorHandler']>[0]): FastifyInstance<TServer, TRawRequest, TRawResponse, FastifyBaseLogger, import("fastify").FastifyTypeProvider>;
setNotFoundHandler(handler: Function): FastifyInstance<TServer, TRawRequest, TRawResponse, FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>;
getHttpServer<T = TServer>(): T;
getInstance<T = TInstance>(): T;
register<TRegister extends Parameters<FastifyRegister<FastifyInstance<TServer, TRawRequest, TRawResponse>>>>(plugin: TRegister['0'], opts?: TRegister['1']): any;
/**
* Registers the "@fastify/multipart" plugin, unless the adapter's
* `multipart` option is `false`, or the plugin has been registered
* already by the time it loads. Idempotent. Called by the upload
* interceptors from "@nestjs/platform-fastify/multipart".
*
* The plugin is loaded lazily, and a missing package fails the
* application's startup (`ready()`) with an error naming the package,
* rather than exiting the process.
*/
useMultipart(): void;
inject(): LightMyRequestChain;
inject(opts: InjectOptions | string): Promise<LightMyRequestResponse>;
beforeClose(): void;
close(): Promise<void>;
initHttpServer(options?: NestApplicationOptions): void;
useStaticAssets(options: FastifyStaticOptions): any;
setViewEngine(options: FastifyViewOptions | string): any;
isHeadersSent(response: TRawResponse | TReply): boolean;
getHeader(response: TRawResponse | TReply, name: string): string | number | string[] | undefined;
setHeader(response: TRawResponse | TReply, name: string, value: string): void | http.ServerResponse<http.IncomingMessage> | FastifyReply<RouteGenericInterface, TServer, TRawRequest, TRawResponse, unknown, import("fastify").FastifySchema, import("fastify").FastifyTypeProviderDefault, unknown>;
appendHeader(response: TRawResponse | TReply, name: string, value: string): void | http.ServerResponse<http.IncomingMessage> | FastifyReply<RouteGenericInterface, TServer, TRawRequest, TRawResponse, unknown, import("fastify").FastifySchema, import("fastify").FastifyTypeProviderDefault, unknown>;
getRequestHostname(request: TRequest): string;
getRequestMethod(request: TRequest): string;
getRequestUrl(request: TRequest): string;
getRequestUrl(request: TRawRequest): string;
enableCors(options?: FastifyCorsOptions): void;
/**
* Copies the headers `@fastify/cors` set on the reply to the Node.js
* response, so that a response a middleware ends itself, or the error
* response of a middleware that throws (sent through a new reply), carries
* them too. Fastify merges them into the response it sends, in which the
* reply's own values win.
*/
private copyCorsHeadersToRaw;
/**
* Runs the request hook of the built-in HTTP security features in an
* `onRequest` hook added by the constructor: before middie (Nest middleware
* and `app.use()` middleware, whenever they are registered), content-type
* parsing, guards and handlers, and also for unmatched routes. Headers set
* by the hook go to the Node.js response (`reply.raw`): Fastify merges them
* into every response it sends, errors and `404`s included, while
* `reply.header()` / `@Header()` values take precedence, and responses
* written to `reply.raw` directly (e.g. `@Sse()`, or middleware) carry them
* too. A rejection goes to `done(error)`, i.e. to the Nest exception layer
* installed with `setErrorHandler()`.
*/
registerSecurityHook(hook: SecurityRequestHook<TRequest>): void;
registerParserMiddleware(prefix?: string, rawBody?: boolean): void;
useBodyParser(type: string | string[] | RegExp, rawBody: boolean, options?: NestFastifyBodyParserOptions, parser?: FastifyBodyParser<Buffer, TServer>): void;
createMiddlewareFactory(requestMethod: RequestMethod): Promise<(path: string, callback: Function) => any>;
private runMiddleware;
getType(): string;
isRouteOrderSensitive(): boolean;
getRouteMatchingOptions(): {
caseSensitive: boolean;
ignoreTrailingSlash: boolean;
};
use(...args: any[]): any;
mapException(error: unknown): unknown;
private isHttpFastifyError;
protected registerWithPrefix(factory: FastifyPluginCallback<any> | FastifyPluginAsync<any> | Promise<{
default: FastifyPluginCallback<any>;
}> | Promise<{
default: FastifyPluginAsync<any>;
}>, prefix?: string): FastifyInstance<TServer, TRawRequest, TRawResponse, FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault> & PromiseLike<undefined> & {
__linterBrands: "SafePromiseLike";
};
private isNativeResponse;
private registerJsonContentParser;
private registerUrlencodedContentParser;
private hasCustomBodyParser;
private normalizeContentType;
private getDefaultBodyParser;
private registerMiddie;
private getRequestOriginalUrl;
private injectRouteOptions;
/**
* "find-my-way" matches an empty path segment for a route parameter
* ("/users//profile" -> { id: "" }), while "path-to-regexp", which
* middleware paths (and the ExpressAdapter's routes) are matched with,
* needs at least one character per parameter. Requests with an empty route
* parameter are passed to the not-found handler instead, as with the
* ExpressAdapter, so that middleware and routes always match the same
* requests. Only the wildcard ("*") may be empty.
*/
private requireNonEmptyParams;
/**
* Fastify still accepts the router options ("ignoreTrailingSlash",
* "caseSensitive", ...) at the top level, but "initialConfig.routerOptions"
* only reflects them when they are passed through "routerOptions". As the
* adapter always passes "routerOptions" (for the version constraint), the
* top-level values are folded in so that plugins relying on
* "initialConfig.routerOptions" (like @fastify/middie) normalize request
* paths exactly like the router does.
*/
private getTopLevelRouterOptions;
private sanitizeUrl;
private removeDuplicateSlashes;
private trimLastSlash;
/**
* Mirrors the absolute-form request target handling of "find-my-way".
* Returns the path of an absolute-form target ("http://host/path" -> "/path",
* "http://host?a=b" -> "/?a=b") and leaves any other request target
* untouched.
*/
private getPathFromRequestTarget;
/**
* Whether the request target is in origin-form ("/users") or in the
* absolute-form of an "http(s)" URL ("http://host/users"), the only forms
* middleware paths can match.
*
* Node.js accepts other targets too (e.g. "GET *users HTTP/1.1").
* "find-my-way" routes those as if their first character were the leading
* "/" ("*users" is served by the "/users" route), while no middleware path
* matches them, so the route would run without its middleware. They are
* answered by the not-found handler instead, as with the ExpressAdapter,
* whose router never matches a path that does not start with "/".
*
* That includes the asterisk-form "OPTIONS *" (RFC 9112, section 3.2.4),
* which asks about the server as a whole rather than about a resource:
* Nest has no handler for it, and "find-my-way" would serve it with the
* "OPTIONS /" route.
*/
private isRoutableRequestTarget;
private trackOpenConnections;
private closeOpenConnections;
}
export {};