/** Constructs the base URL from the headers from the given request. */ import fastify, {FastifyInstance, FastifyRequest} from "fastify"; import {Server, ServerOptions, ServerRequestHandler} from "slash-create"; export function getBaseUrl(request: FastifyRequest): string { const hostHeader = request.hostname ?? "localhost" const proto = getFirstValue(request.headers["x-forwarded-proto"]) ?? "http" const path = getFirstValue(request.headers["x-base-path"]) ?? "/" return `${proto}://${hostHeader}${path}` } /** Translates a zero-to-many set of strings to one or zero strings. */ export function getFirstValue(value: string | string[] | undefined): string | undefined { return typeof value === "string" ? value : Array.isArray(value) ? value[0] : undefined } /** * A server for Fastify applications. * @see https://fastify.io */ export class FastifyServerButItWorksUnlikeTheRealOne extends Server { readonly app: FastifyInstance; /** * @param app The fastify application * @param opts The server options */ constructor(app?: FastifyInstance, opts?: ServerOptions) { super(opts); this.app = app || fastify(); } /** * Adds middleware to the Fastify server. * This requires you to have the 'middie' module registered to the server before using. * @param middleware The middleware to add. * @see https://www.fastify.io/docs/latest/Middleware/ */ addMiddleware(middleware: Function) { // @ts-ignore if ('use' in this.app) this.app.use(middleware); else throw new Error( "In order to use Express-like middleware, you must initialize the server and register the 'middie' module." ); return this; } /** Alias for {@link FastifyServerButItWorksUnlikeTheRealOne#addMiddleware} */ use(middleware: Function) { return this.addMiddleware(middleware); } /** @private */ createEndpoint(path: string, handler: ServerRequestHandler) { this.app.post(path, (req: any, res: any) => handler( { headers: req.headers, body: req.body, request: req, response: res }, async (response) => { res.status(response.status || 200); if (response.headers) res.headers(response.headers); res.send(response.body); } ) ); } /** @private */ async listen(port = 8030, host = 'localhost') { if (this.alreadyListening) return; await this.app.listen(port, host); } }