UNPKG

@intuitionrobotics/thunderstorm

Version:
109 lines 3.95 kB
import compression from 'compression'; import cors from 'cors'; import { addItemToArray, LogLevel, Module } from "@intuitionrobotics/ts-common"; import { ServerApi } from "./server-api.js"; import { ApiException } from "../../exceptions.js"; import express from "express"; import { HeaderKey_FunctionExecutionId, HeaderKey_JWT } from '../_imports.js'; const DefaultHeaders = [ 'content-type', 'content-encoding', 'x-session-id', 'authorization' ]; const ExposedHeaders = [ HeaderKey_FunctionExecutionId, HeaderKey_JWT ]; export class HttpServer_Class extends Module { static expressMiddleware = []; express; constructor(_express, configElement) { super("HttpServer"); this.express = _express; this.setConfig(configElement); } static addMiddleware(middleware) { HttpServer_Class.expressMiddleware.push(middleware); return this; } getBaseUrl() { return this.config.baseUrl; } init() { this.setMinLevel(ServerApi.isDebug ? LogLevel.Verbose : LogLevel.Info); const baseUrl = this.config.baseUrl; if (baseUrl) { if (baseUrl.endsWith("/")) this.config.baseUrl = baseUrl.substring(0, baseUrl.length - 1); this.config.baseUrl = baseUrl.replace(/\/\//g, "/"); } this.express.use((req, res, next) => { if (req) req.url = req.url.replace(/\/\//g, "/"); next(); }); const parserLimit = this.config.bodyParserLimit; if (parserLimit) this.express.use(express.json({ limit: parserLimit })); this.express.use(compression()); const myCors = this.config.cors || {}; if (!myCors.exposedHeaders) myCors.exposedHeaders = ExposedHeaders; myCors.headers = DefaultHeaders.reduce((toRet, item) => { if (!toRet.includes(item)) addItemToArray(toRet, item); return toRet; }, myCors.headers || []); const corsOptions = { credentials: true, // Allow cookies/auth headers optionsSuccessStatus: 200, exposedHeaders: myCors.exposedHeaders }; // Handle origin configuration if (!myCors.origins || myCors.origins.length === 0) { // No origins specified - allow all corsOptions.origin = true; } else { // Single origin string or RegExp corsOptions.origin = myCors.origins; } const corsWithOptions = cors(corsOptions); this.express.use(corsWithOptions); for (const middleware of HttpServer_Class.expressMiddleware) { this.express.use(middleware); } this.express.options('*', corsWithOptions); } // v2.0 entrypoint: mount a user-built Express Router directly onto the // app. The hand-maintained routes.ts file constructs the Router using // the `mount()` helper and `Router.use(...)` for nesting, then this // method just `app.use`s it. No RouteResolver, no fs walk, no codegen // walker — Express owns the route table. // // `urlPrefix` is optional and matches what `Storm.setInitialRoutePath` // gave callers: a local-dev URL prefix (e.g. "/api"). When empty, the // router mounts at the application root. mountRouter(router, urlPrefix = "") { if (urlPrefix) this.express.use(urlPrefix, router); else this.express.use(router); } } export class HeaderKey { key; responseCode; constructor(key, responseCode = 400) { this.key = key; this.responseCode = responseCode; } get(request) { const value = request.header(this.key); if (!value) throw new ApiException(this.responseCode, `Missing expected header: ${this.key}`); return value; } } //# sourceMappingURL=HttpServer.js.map