UNPKG

rjweb-server

Version:

Easy and Robust Way to create a Web Server with Many Easy-to-use Features in NodeJS

175 lines (174 loc) 6.65 kB
import Route from "../Route"; import { Method } from "../../types/global"; import Http from "./Http"; import { UsableMiddleware } from "../Middleware"; import { UsableValidator } from "../Validator"; import { RateLimitConfig } from "../../types/internal"; import RateLimit from "./RateLimit"; import GlobalContext from "../../types/internal/classes/GlobalContext"; import { ArrayOrNot } from "@rjweb/utils"; import Ws from "./Ws"; import { OperationObject } from "openapi3-ts/oas31"; export default class Path<Middlewares extends UsableMiddleware[], Validators extends UsableValidator[] = [], Context extends Record<string, any> = {}, Excluded extends (keyof Path<Middlewares>)[] = []> { private validators; protected routesHttp: Route<'http'>[]; protected routesStatic: Route<'static'>[]; protected routesWS: Route<'ws'>[]; protected _httpRatelimit: RateLimitConfig; protected _wsRatelimit: RateLimitConfig; protected promises: Promise<any>[]; protected openApi: OperationObject; private _global; private prefix; private computePath; /** * Create a new Path * @since 6.0.0 */ constructor(prefix: string, global: GlobalContext, validators?: Validators, ratelimits?: [RateLimitConfig, RateLimitConfig], promises?: Promise<any>[], openApi?: OperationObject); /** * Add OpenAPI Documentation to all HTTP Endpoints in this Path (and all children) * @since 9.0.0 */ document(item: OperationObject): Omit<Path<Middlewares, Validators, Context, [...Excluded, 'document']>, Excluded[number] | 'document'>; /** * Add a Ratelimit to all HTTP Endpoints in this Path (and all children) * * When a User requests an Endpoint, that will count against their hit count, if * the hits exceeds the `<maxHits>` in `<timeWindow>ms`, they wont be able to access * the route for `<penalty>ms`. * @example * ``` * import { time } from "@rjweb/utils" * * server.path('/', (path) => path * .httpRateLimit((limit) => limit * .hits(5) * .window(time(20).s()) * .penalty(0) * ) // This will allow 5 requests every 20 seconds * .http('GET', '/hello', (ws) => ws * .onRequest(async(ctr) => { * ctr.print('Hello bro!') * }) * ) * ) * * server.rateLimit('httpRequest', (ctr) => { * ctr.print(`Please wait ${ctr.getRateLimit()?.resetIn}ms!!!!!`) * }) * ``` * @since 8.6.0 */ httpRatelimit(callback: (limit: RateLimit) => any): Omit<Path<Middlewares, Validators, Context, Excluded>, Excluded[number] | 'httpRatelimit'>; /** * Add a Ratelimit to all WebSocket Endpoints in this Path (and all children) * * When a User sends a message to a Socket, that will count against their hit count, if * the hits exceeds the `<maxHits>` in `<timeWindow>ms`, they wont be able to access * the route for `<penalty>ms`. * @example * ``` * import { time } from "@rjweb/utils" * * server.path('/', (path) => path * .httpRateLimit((limit) => limit * .hits(5) * .window(time(20).s()) * .penalty(0) * ) // This will allow 5 messages every 20 seconds * .ws('/echo', (ws) => ws * .onMessage(async(ctr) => { * ctr.print(await ctr.rawMessageBytes()) * }) * ) * ) * * server.rateLimit('wsMessage', (ctr) => { * ctr.print(`Please wait ${ctr.getRateLimit()?.resetIn}ms!!!!!`) * }) * ``` * @since 8.6.0 */ wsRatelimit(callback: (limit: RateLimit) => any): Omit<Path<Middlewares, Validators, Context, Excluded>, Excluded[number] | 'wsRatelimit'>; /** * Create a redirection route * @example * ``` * const server = new Server(...) * * server.path('/', (path) => path * .redirect('/google', 'https://google.com') * ) * ``` * @since 3.10.0 */ redirect(path: ArrayOrNot<string | RegExp>, redirect: string, type?: 'temporary' | 'permanent'): this; /** * Create a subpath of this Path * @since 6.0.0 */ path(prefix: string, callback: (path: Path<Middlewares, Validators, Context>) => any): this; /** * Use a Validator on all Endpoints in this Path * * This will attach a Validator to all Endpoints in this Path * @since 9.0.0 */ validate<_Validator extends UsableValidator<any>>(validator: _Validator): Path<Middlewares, [...Validators, _Validator], Context, Excluded>; /** * Serve Static Files * @example * ``` * // All Files in "./public" will be served dynamically so they wont be loaded as routes by default * // Due to the stripHtmlEnding Option being on files will be served differently, /index.html -> /; /about.html -> /about; /contributors/index.html -> /contributors * const server = new Server(...) * * server.path('/', (path) => path * .static('./public', { * stripHtmlEnding: true // If enabled will remove .html ending from files * }) * ) * ``` * @since 3.1.0 */ static(folder: string, options?: { /** * Whether to automatically remove .html ending from files * @default false * @since 9.0.0 */ stripHtmlEnding?: boolean; /** * Whether to pre-process the files before serving them, * this will force you to restart the server every time * you add or remove a file. * @warning THIS WILL RECURSIVELY WALK THROUGH ALL FILES IN THE FOLDER, USE WITH CAUTION * @default false * @since 9.0.0 */ preProcessFiles?: boolean; }): this; /** * Add a new HTTP Route * @example * ``` * const server = new Server(...) * * server.path('/', (path) => path * .http('GET', '/hello', (ws) => ws * .onRequest((ctr) => { * ctr.print('Hello!') * }) * ) * ) * ``` * @since 6.0.0 */ http<_Method extends Method>(method: _Method, path: ArrayOrNot<string | RegExp>, callback: (http: Http<_Method, Middlewares, Validators, Context>) => any): this; /** * Add a new WebSocket Route * @example * ``` * const server = new Server(...) * * server.path('/', (path) => path * .ws('/echo', (ws) => ws * .onMessage((ctr) => { * ctr.print(ctr.rawMessageBytes()) * }) * ) * ) * ``` * @since 6.0.0 */ ws(path: ArrayOrNot<string | RegExp>, callback: (ws: Ws<Middlewares, Validators, Context>) => any): this; }