diff --git a/src/Request.ts b/src/Request.ts index 4869ea0..ad312bd 100644 --- a/src/Request.ts +++ b/src/Request.ts @@ -1,6 +1,6 @@ +import {Multipart} from "multipart-ts"; import http, {OutgoingHttpHeader} from "node:http"; import stream from "node:stream"; -import {Multipart} from "multipart-ts"; /** * An incoming HTTP request from a connected client. @@ -33,7 +33,12 @@ export class Request { * @param headers See {@link Request#headers}. * @param bodyStream See {@link Request#bodyStream}. */ - protected constructor(method: Request["method"], url: Request["url"], headers: Request["headers"], bodyStream: Request["bodyStream"]) { + protected constructor( + method: Request["method"], + url: Request["url"], + headers: Request["headers"], + bodyStream: Request["bodyStream"], + ) { this.method = method; this.url = url; this.headers = headers; @@ -45,8 +50,14 @@ export class Request { * @throws {@link Request.BadUrlError} If the request URL is invalid. */ public static incomingMessage(incomingMessage: http.IncomingMessage) { - const auth = incomingMessage.headers.authorization?.toLowerCase().startsWith("basic ") - ? Buffer.from(incomingMessage.headers.authorization.substring("basic ".length), "base64").toString() + const auth = + incomingMessage.headers.authorization + ?.toLowerCase() + .startsWith("basic ") + ? Buffer.from( + incomingMessage.headers.authorization + .substring("basic ".length), "base64" + ).toString() : null; const url = `http://${auth ? `${auth}@` : ""}${process.env.HOST ?? "localhost"}${incomingMessage.url ?? "/"}`; @@ -55,12 +66,21 @@ export class Request { const headers = Request.headersFromNodeDict(incomingMessage.headers); - return new Request( - incomingMessage.method as Request.Method, - new URL(url), - headers, - incomingMessage - ) + return new Request(incomingMessage.method as Request.Method, new URL(url), headers, incomingMessage); + } + + /** + * @internal + */ + public static headersFromNodeDict(headers: Record): Headers { + return new Headers(Object.entries(headers) + .filter((e) => e[1] !== undefined) + .flatMap<[string, string]>(([key, value]) => + value instanceof Array + ? value.map<[string, string]>(v => [key, v]) + : [[key, String(value)]] + ) + ); } /** @@ -135,19 +155,6 @@ export class Request { public async text(): Promise { return (await this.blob()).text(); } - - /** - * @internal - */ - public static headersFromNodeDict(headers: Record): Headers { - return new Headers( - (Object.entries(headers) - .filter(([, v]) => v !== undefined) as [string, Exclude][]) - .flatMap<[string, string]>(([key, value]) =>value instanceof Array - ? value.map<[string, string]>(v => [key, v]) - : [[key, String(value)]]) - ); - } } export namespace Request { diff --git a/src/ServerErrorRegistry.ts b/src/ServerErrorRegistry.ts index a679732..1f35b9d 100644 --- a/src/ServerErrorRegistry.ts +++ b/src/ServerErrorRegistry.ts @@ -7,24 +7,41 @@ import {TextResponse} from "./response/TextResponse.js"; class ServerErrorRegistry { private readonly responses: Record; + /** + * Create a new server error registry initialised with default responses. + */ + public constructor() { + this.responses = { + [ServerErrorRegistry.ErrorCodes.BAD_URL]: + new TextResponse("Bad request URL.", 400), + + [ServerErrorRegistry.ErrorCodes.NO_ROUTE]: + new TextResponse("No route in this registry matches the request.", 404), + + [ServerErrorRegistry.ErrorCodes.INTERNAL]: + new TextResponse("An internal error occurred.", 500), + }; + } + + /** + * Replace server error response by registering a new custom response. + * @param code The server error code. + * @param response The response to send. + */ public register(code: ServerErrorRegistry.ErrorCodes, response: Response) { this.responses[code] = response; } + /** @internal */ public _get(code: ServerErrorRegistry.ErrorCodes): Response { return this.responses[code]; } - - public constructor() { - this.responses = { - [ServerErrorRegistry.ErrorCodes.BAD_URL]: new TextResponse("Bad request URL.", 400), - [ServerErrorRegistry.ErrorCodes.NO_ROUTE]: new TextResponse("No route in this registry matches the request.", 404), - [ServerErrorRegistry.ErrorCodes.INTERNAL]: new TextResponse("An internal error occurred.", 500), - }; - } } namespace ServerErrorRegistry { + /** + * Server error codes + */ export const enum ErrorCodes { BAD_URL, NO_ROUTE, diff --git a/src/response/JsonResponse.ts b/src/response/JsonResponse.ts index b75b362..00b0935 100644 --- a/src/response/JsonResponse.ts +++ b/src/response/JsonResponse.ts @@ -17,8 +17,8 @@ export class JsonResponse extends TextResponse { return v.toISOString(); if (typeof v === "bigint") return v <= BigInt(Number.MAX_SAFE_INTEGER) - ? Number(v) - : v.toString(); + ? Number(v) + : v.toString(); return v; })); } diff --git a/src/response/Response.ts b/src/response/Response.ts index cc4def5..1feb840 100644 --- a/src/response/Response.ts +++ b/src/response/Response.ts @@ -26,6 +26,13 @@ export abstract class Response { this.headers = new Headers(headers); } + /** + * @internal + */ + public _send(...args: Parameters): ReturnType { + return this.send(...args); + } + /** * Set the HTTP response status code and headers. */ @@ -38,11 +45,4 @@ export abstract class Response { * Called once by the server to send the response. */ protected abstract send(res: http.ServerResponse, server: Server, req?: Request): void | Promise; - - /** - * @internal - */ - public _send(...args: Parameters): ReturnType { - return this.send(...args); - } }