TypeDoc all the thngs

This commit is contained in:
2021-03-25 08:50:13 -05:00
parent 7cb0546b01
commit fad1184afe
52 changed files with 976 additions and 3 deletions

View File

@@ -12,8 +12,14 @@ export interface HTTPCookie {
options?: HTTPCookieOptions,
}
/**
* Type alias for something that is either an HTTP cookie, or undefined.
*/
export type MaybeHTTPCookie = HTTPCookie | undefined;
/**
* Interface describing the available cookie options.
*/
export interface HTTPCookieOptions {
domain?: string,
expires?: Date, // encodeURIComponent
@@ -25,21 +31,36 @@ export interface HTTPCookieOptions {
sameSite?: 'strict' | 'lax' | 'none-secure',
}
/**
* Class for accessing and managing cookies in the associated request.
*/
export class HTTPCookieJar {
/** The cookies parsed from the request. */
protected parsed: {[key: string]: HTTPCookie} = {}
constructor(
/** The request whose cookies should be loaded. */
protected request: Request,
) {
this.parseCookies()
}
/**
* Gets the HTTPCookie by name, if it exists.
* @param name
*/
get(name: string): MaybeHTTPCookie {
if ( name in this.parsed ) {
return this.parsed[name]
}
}
/**
* Set a new cookie using the specified options.
* @param name
* @param value
* @param options
*/
set(name: string, value: any, options?: HTTPCookieOptions) {
this.parsed[name] = {
key: name,
@@ -50,10 +71,23 @@ export class HTTPCookieJar {
}
}
/**
* Returns true if a cookie exists with the given name.
* @param name
*/
has(name: string) {
return !!this.parsed[name]
}
/**
* Clears the given cookie.
*
* Important: if the cookie was set with any `options`, the SAME options
* must be provided here in order for the cookie to be cleared on the client.
*
* @param name
* @param options
*/
clear(name: string, options?: HTTPCookieOptions) {
if ( !options ) options = {}
options.expires = new Date(0)
@@ -67,6 +101,9 @@ export class HTTPCookieJar {
}
}
/**
* Get an array of `Set-Cookie` headers to include in the response.
*/
getSetCookieHeaders(): string[] {
const headers: string[] = []
@@ -119,6 +156,7 @@ export class HTTPCookieJar {
return headers
}
/** Parse the cookies from the request. */
private parseCookies() {
const cookies = String(this.request.getHeader('cookie'))
cookies.split(';').forEach(cookie => {

View File

@@ -10,10 +10,27 @@ import {error} from "../response/ErrorResponseFactory";
* Interface for fluently registering kernel modules into the kernel.
*/
export interface ModuleRegistrationFluency {
/**
* If no argument is provided, the module will be registered before the core module.
* If an argument is provided, the module will be registered before the other specified module.
* @param other
*/
before: (other?: Instantiable<HTTPKernelModule>) => HTTPKernel,
/**
* If no argument is provided, the module will be registered after the core module.
* If an argument is provided, the module will be registered after the other specified module.
* @param other
*/
after: (other?: Instantiable<HTTPKernelModule>) => HTTPKernel,
/** The module will be registered as the first module in the preflight. */
first: () => HTTPKernel,
/** The module will be registered as the last module in the postflight. */
last: () => HTTPKernel,
/** The module will be registered as the core handler for the request. */
core: () => HTTPKernel,
}
@@ -27,6 +44,9 @@ export class KernelModuleNotFoundError extends Error {
}
}
/**
* A singleton class that handles requests, applying logic in modular layers.
*/
@Singleton()
export class HTTPKernel extends AppClass {
@Inject()

View File

@@ -3,8 +3,19 @@ import {AppClass} from "../../lifecycle/AppClass";
import {HTTPKernel} from "./HTTPKernel";
import {Request} from "../lifecycle/Request";
/**
* Base class for modules that define logic that is applied to requests
* handled by the HTTP kernel.
*/
@Injectable()
export class HTTPKernelModule extends AppClass {
/**
* By default, if a kernel module interrupts the request flow to send a response
* (for example, if an error occurs), subsequent modules are skipped.
*
* However, a module can override this property to be true and its logic will still
* be applied, even after a module has interrupted the request flow.
*/
public readonly executeWithBlockingWriteback: boolean = false
/**

View File

@@ -5,7 +5,16 @@ import {plaintext} from "../../response/StringResponseFactory";
import {ResponseFactory} from "../../response/ResponseFactory";
import {json} from "../../response/JSONResponseFactory";
/**
* Base class for HTTP kernel modules that apply some response from a route handler to the request.
*/
export abstract class AbstractResolvedRouteHandlerHTTPModule extends HTTPKernelModule {
/**
* Given a response object, write the response to the request in the appropriate format.
* @param object
* @param request
* @protected
*/
protected async applyResponseObject(object: ResponseObject, request: Request) {
if ( (typeof object === 'string') || (typeof object === 'number') ) {
object = plaintext(String(object))

View File

@@ -6,6 +6,11 @@ import {http} from "../../response/HTTPErrorResponseFactory";
import {HTTPStatus} from "@extollo/util";
import {AbstractResolvedRouteHandlerHTTPModule} from "./AbstractResolvedRouteHandlerHTTPModule";
/**
* HTTP kernel module that runs the handler for the request's route.
*
* In most cases, this is the controller method defined by the route.
*/
export class ExecuteResolvedRouteHandlerHTTPModule extends AbstractResolvedRouteHandlerHTTPModule {
public static register(kernel: HTTPKernel) {
kernel.register(this).core()

View File

@@ -5,6 +5,11 @@ import {ResponseObject} from "../../routing/Route";
import {AbstractResolvedRouteHandlerHTTPModule} from "./AbstractResolvedRouteHandlerHTTPModule";
import {PersistSessionHTTPModule} from "./PersistSessionHTTPModule";
/**
* HTTP kernel module that executes the postflight handlers for the route.
*
* Usually, this is post middleware.
*/
export class ExecuteResolvedRoutePostflightHTTPModule extends AbstractResolvedRouteHandlerHTTPModule {
public static register(kernel: HTTPKernel) {
kernel.register(this).before(PersistSessionHTTPModule)

View File

@@ -5,6 +5,11 @@ import {ActivatedRoute} from "../../routing/ActivatedRoute";
import {ResponseObject} from "../../routing/Route";
import {AbstractResolvedRouteHandlerHTTPModule} from "./AbstractResolvedRouteHandlerHTTPModule";
/**
* HTTP Kernel module that executes the preflight handlers for the route.
*
* Usually, this is the pre middleware.
*/
export class ExecuteResolvedRoutePreflightHTTPModule extends AbstractResolvedRouteHandlerHTTPModule {
public static register(kernel: HTTPKernel) {
kernel.register(this).after(MountActivatedRouteHTTPModule)

View File

@@ -7,6 +7,10 @@ import {SetSessionCookieHTTPModule} from "./SetSessionCookieHTTPModule";
import {SessionFactory} from "../../session/SessionFactory";
import {Session} from "../../session/Session";
/**
* HTTP kernel middleware that creates the session using the configured driver
* and loads its data using the request's session cookie.
*/
@Injectable()
export class InjectSessionHTTPModule extends HTTPKernelModule {
public readonly executeWithBlockingWriteback = true

View File

@@ -6,6 +6,10 @@ import {Routing} from "../../../service/Routing";
import {ActivatedRoute} from "../../routing/ActivatedRoute";
import {Logging} from "../../../service/Logging";
/**
* HTTP kernel middleware that tries to find a registered route matching the request's
* path and creates an ActivatedRoute instance from it.
*/
@Injectable()
export class MountActivatedRouteHTTPModule extends HTTPKernelModule {
public readonly executeWithBlockingWriteback = true

View File

@@ -4,6 +4,10 @@ import {HTTPKernel} from "../HTTPKernel";
import {Request} from "../../lifecycle/Request";
import {Session} from "../../session/Session";
/**
* HTTP kernel module that runs after the main logic in the request to persist
* the session data to the driver's backend.
*/
@Injectable()
export class PersistSessionHTTPModule extends HTTPKernelModule {
public readonly executeWithBlockingWriteback = true

View File

@@ -4,6 +4,9 @@ import {Injectable, Inject} from "@extollo/di"
import {HTTPKernel} from "../HTTPKernel";
import {Config} from "../../../service/Config";
/**
* HTTP kernel middleware that sets the `X-Powered-By` header.
*/
@Injectable()
export class PoweredByHeaderInjectionHTTPModule extends HTTPKernelModule {
public readonly executeWithBlockingWriteback = true

View File

@@ -5,6 +5,10 @@ import {HTTPKernel} from "../HTTPKernel";
import {Request} from "../../lifecycle/Request";
import {Logging} from "../../../service/Logging";
/**
* HTTP kernel middleware that tries to look up the session ID from the request.
* If none exists, generates a new one and sets the cookie.
*/
@Injectable()
export class SetSessionCookieHTTPModule extends HTTPKernelModule {
public readonly executeWithBlockingWriteback = true