jimpex 10.0.0 → 10.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/app/jimpex.js +8 -18
- package/dist/app/jimpex.js.map +1 -1
- package/dist/controllers/common/config.js +1 -4
- package/dist/controllers/common/config.js.map +1 -1
- package/dist/controllers/common/health.js +1 -4
- package/dist/controllers/common/health.js.map +1 -1
- package/dist/controllers/common/statics.js +1 -4
- package/dist/controllers/common/statics.js.map +1 -1
- package/dist/controllers/utils/gateway.js +1 -4
- package/dist/controllers/utils/gateway.js.map +1 -1
- package/dist/esm/app/jimpex.js +8 -15
- package/dist/esm/app/jimpex.js.map +1 -1
- package/dist/esm/{chunk-F3FYYIAV.js → chunk-V6TY7KAL.js} +2 -5
- package/dist/esm/controllers/common/config.js +1 -1
- package/dist/esm/controllers/common/health.js +1 -1
- package/dist/esm/controllers/common/statics.js +1 -1
- package/dist/esm/controllers/utils/gateway.js +1 -1
- package/dist/esm/middlewares/common/errorHandler.js +1 -1
- package/dist/esm/middlewares/common/forceHTTPS.js +2 -3
- package/dist/esm/middlewares/common/forceHTTPS.js.map +1 -1
- package/dist/esm/middlewares/common/hsts.js +1 -1
- package/dist/esm/middlewares/html/fastHTML.js +2 -3
- package/dist/esm/middlewares/html/fastHTML.js.map +1 -1
- package/dist/esm/middlewares/html/showHTML.js +1 -1
- package/dist/esm/middlewares/utils/versionValidator.js +1 -1
- package/dist/esm/services/common/appError.js +1 -1
- package/dist/esm/services/common/httpError.js +1 -1
- package/dist/esm/services/common/index.js +1 -1
- package/dist/esm/services/common/sendFile.js +1 -1
- package/dist/esm/services/frontend/frontendFs.js +1 -1
- package/dist/esm/services/frontend/index.js +1 -1
- package/dist/esm/services/html/htmlGenerator.js +3 -5
- package/dist/esm/services/html/htmlGenerator.js.map +1 -1
- package/dist/esm/services/html/index.js +1 -1
- package/dist/esm/services/http/apiClient.js +4 -7
- package/dist/esm/services/http/apiClient.js.map +1 -1
- package/dist/esm/services/http/http.js +1 -1
- package/dist/esm/services/http/index.js +1 -1
- package/dist/esm/services/http/responsesBuilder.js +2 -2
- package/dist/esm/services/http/responsesBuilder.js.map +1 -1
- package/dist/esm/services/utils/ensureBearerToken.js +1 -1
- package/dist/esm/services/utils/index.js +1 -1
- package/dist/esm/utils/fns/others.js +1 -1
- package/dist/esm/utils/fns/routes.js +1 -1
- package/dist/esm/utils/fns/statuses.js +1 -1
- package/dist/esm/utils/fns/text.js +1 -1
- package/dist/esm/utils/wrappers.js +1 -1
- package/dist/middlewares/common/errorHandler.js +1 -4
- package/dist/middlewares/common/errorHandler.js.map +1 -1
- package/dist/middlewares/common/forceHTTPS.js +2 -6
- package/dist/middlewares/common/forceHTTPS.js.map +1 -1
- package/dist/middlewares/common/hsts.js +1 -4
- package/dist/middlewares/common/hsts.js.map +1 -1
- package/dist/middlewares/html/fastHTML.js +2 -6
- package/dist/middlewares/html/fastHTML.js.map +1 -1
- package/dist/middlewares/html/showHTML.js +1 -4
- package/dist/middlewares/html/showHTML.js.map +1 -1
- package/dist/middlewares/utils/versionValidator.js +1 -4
- package/dist/middlewares/utils/versionValidator.js.map +1 -1
- package/dist/services/common/appError.js +1 -4
- package/dist/services/common/appError.js.map +1 -1
- package/dist/services/frontend/frontendFs.js +1 -4
- package/dist/services/frontend/frontendFs.js.map +1 -1
- package/dist/services/html/htmlGenerator.js +3 -8
- package/dist/services/html/htmlGenerator.js.map +1 -1
- package/dist/services/http/apiClient.js +4 -10
- package/dist/services/http/apiClient.js.map +1 -1
- package/dist/services/http/http.js +1 -4
- package/dist/services/http/http.js.map +1 -1
- package/dist/services/http/responsesBuilder.js +2 -5
- package/dist/services/http/responsesBuilder.js.map +1 -1
- package/dist/services/utils/ensureBearerToken.js +1 -4
- package/dist/services/utils/ensureBearerToken.js.map +1 -1
- package/package.json +39 -39
- package/src/services/http/responsesBuilder.ts +1 -1
- /package/dist/esm/{chunk-F3FYYIAV.js.map → chunk-V6TY7KAL.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/controllers/utils/gateway.ts"],"sourcesContent":["import { deepAssignWithOverwrite } from '@homer0/deep-assign';\nimport { flat, unflat } from '@homer0/object-utils';\nimport type { APIClientOptions } from '@homer0/api-utils';\nimport {\n controllerProviderCreator,\n controller,\n createRouteExpression,\n removeSlashes,\n notUndefined,\n type MiddlewareLike,\n} from '../../utils';\nimport type { HTTP, HTTPFetchOptions } from '../../services';\nimport type { Jimpex } from '../../app';\nimport {\n RouterMethod,\n DeepPartial,\n Request,\n Response,\n NextFunction,\n HTTPResponse,\n Router,\n ExpressMiddleware,\n AsyncExpressMiddleware,\n} from '../../types';\n/**\n * The extended definition for endpoints.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayConfigEndpointProps = {\n /**\n * The path to the endpoint relative to the entry point. It can include placeholders for\n * parameters like `/:parameter/`.\n */\n path: string;\n /**\n * The router (HTTP) method for the endpoint.\n *\n * @default 'all'\n */\n method?: RouterMethod;\n};\n/**\n * The definition of an endpoint: it can be just the path, relative to the entry point, or\n * an object in which you can also specify things like the method.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayConfigEndpointDefinition = string | GatewayConfigEndpointProps;\n/**\n * The dictionary of endpoints the controller uses. The reason for this type is that this\n * could be a flat dictionary, or a nested one.\n *\n * @example\n *\n * <caption>A flat dictionary</caption>\n *\n * {\n * random: '/random',\n * users: '/users',\n * userById: {\n * path: '/users/:id',\n * method: 'get',\n * },\n * }\n *\n * @example\n *\n * <caption>A nested dictionary</caption>\n *\n * {\n * random: '/random',\n * users: {\n * list: '/users',\n * byId: {\n * path: '/users/:id',\n * method: 'get',\n * },\n * },\n * }\n *\n * @group Controllers/Gateway\n */\nexport type GatewayConfigEndpoints = {\n [key: string]: GatewayConfigEndpointDefinition | GatewayConfigEndpoints;\n};\n/**\n * The configuration for the gateway the controller uses.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayConfig = {\n /**\n * The entry point to the API the controller will make the requests to.\n */\n url: string;\n /**\n * The dictionary of enpoints the gateway will make available.\n */\n gateway: GatewayConfigEndpoints;\n};\n/**\n * The options for how the gateway will handle the headers from the requests and the\n * responses.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerHeaderOptions = {\n /**\n * Whether or not to include the header with the request's IP address.\n *\n * @default true\n */\n useXForwardedFor: boolean;\n /**\n * Whether or not to copy all custom headers from the request. By custom header, it\n * means all the headers which names start with `x-`.\n *\n * @default true\n */\n copyCustomHeaders: boolean;\n /**\n * A list of \"known\" headers the gateway will try to copy from the incoming request.\n *\n * @default ['authorization','content-type', 'referer', 'user-agent']\n */\n copy: string[];\n /**\n * A list of \"known\" headers the gateway will try to remove the response.\n *\n * @default ['server', 'x-powered-by']\n */\n remove: string[];\n};\n/**\n * The extra options for the gateway controller. They are \"extra\" because they are mostly\n * helpers for when used with an API client, or for optional features.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerExtraOptions = {\n /**\n * This is really a helper for when the gateway is used with an API client. The idea is\n * that, by default, the routes are mounted on the controller route, but with this\n * option, you can specify another sub path. For example: The controller is mounted on\n * `/routes`, and if you set `root` to `gateway`, all the routes will be on\n * `/routes/gateway`.\n *\n * This become important (and useful) when you get the API client configuration (with\n * `getAPIConfig`): The `url` will be the controller route, but all the endpoints will\n * be modified and prefixed with the `root`, that way, you can have multiple gateways in\n * the same \"base route\".\n *\n * It can also includes placeholders for parameters like `/:parameter/`, that will be\n * replaced with the `placeholders` option when `getAPIConfig` gets called.\n *\n * @default ''\n */\n root: string;\n /**\n * This is another option for when the gateway is used with an API client. When calling\n * `getAPIConfig`, all the endpoints will be wrapped inside an object named after this\n * option. For example: `{ url: '...', endpoints: { api: { ... } } }`.\n *\n * @default 'api'\n */\n apiConfigSetting: string;\n /**\n * The options for how the gateway will handle the headers from the requests and the\n * responses.\n */\n headers: GatewayControllerHeaderOptions;\n};\n/**\n * The required options for the gateway controller.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerOptions = {\n /**\n * The configuration for the API the gateway will make the requests to.\n */\n gatewayConfig: GatewayConfig;\n /**\n * The route where the controller is mounted.\n */\n route: string;\n} & DeepPartial<GatewayControllerExtraOptions>;\n/**\n * The information for a request the controller will make.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerRequest = {\n /**\n * The URL for the request.\n */\n url: string;\n /**\n * The options for the fetch client that will make the requests.\n */\n options: HTTPFetchOptions;\n};\n/**\n * The information for an endpoint the gateway is calling.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerEndpointInfo = {\n /**\n * The name of the endpoint in the configuration.\n */\n name: string;\n /**\n * The properties (path and method) of the endpoint.\n */\n definition: GatewayConfigEndpointDefinition;\n};\n/**\n * These are the base options sent to all the helper service functions.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayHelperServiceBaseFnOptions = {\n /**\n * The information of the endpoint the gateway is calling.\n */\n endpoint: GatewayControllerEndpointInfo;\n /**\n * The request recived by the application.\n */\n req: Request;\n /**\n * The response object created by the application.\n */\n res: Response;\n /**\n * The function to call the next middleware in the chain.\n */\n next: NextFunction;\n};\n/**\n * The information sent to the helper service in order to modify, or not, a request before\n * it is sent.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayHelperServiceRequestReducerOptions =\n GatewayHelperServiceBaseFnOptions & {\n /**\n * The options the controller created for the fetch client.\n */\n endpointReq: GatewayControllerRequest;\n };\n/**\n * A function that can be used to modify the information of an endpoint before making a\n * request.\n *\n * @param options The information of the request.\n * @group Controllers/Gateway\n */\nexport type GatewayHelperServiceRequestReducer = (\n options: GatewayHelperServiceRequestReducerOptions,\n) => Promise<GatewayControllerRequest>;\n/**\n * The information sent to the helper service in order to modify a response before\n * processing it, decide if it should be streamed or not, and even handle it.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayHelperServiceResponseReducerOptions =\n GatewayHelperServiceBaseFnOptions & {\n /**\n * The response from the endpoint request.\n */\n endpointRes: HTTPResponse;\n };\n/**\n * A function that can be used to modify the response of an endpoint before the controller\n * processes it.\n *\n * @param options The information of the response.\n * @group Controllers/Gateway\n */\nexport type GatewayHelperServiceResponseReducer = (\n options: GatewayHelperServiceResponseReducerOptions,\n) => Promise<HTTPResponse>;\n/**\n * A function that can be used to tell the controller to stream the response of an\n * endpoint or not.\n * If it returns `false`, the function to handle responses should be defined, otherwise,\n * an error will be generated.\n *\n * @param options The information of the response.\n * @group Controllers/Gateway\n */\nexport type GatewayHelperServiceStreamVerification = (\n options: GatewayHelperServiceResponseReducerOptions,\n) => Promise<boolean>;\n/**\n * A function to handle the response of an endpoint. This is called when the helper\n * service tells the controller that the endpoint shouldn't be streamed, so this method\n * should handle the response.\n *\n * @param options The information of the response.\n * @group Controllers/Gateway\n */\nexport type GatewayHelperServiceResponseHandler = (\n options: GatewayHelperServiceResponseReducerOptions,\n) => Promise<void>;\n/**\n * The information sent to the helper service in order to handle a failed request for an\n * endpoint.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayHelperServiceErrorHandlerOptions =\n GatewayHelperServiceBaseFnOptions & {\n /**\n * The error generated during the request.\n */\n error: Error;\n };\n/**\n * A function to handle the error of an endpoint request.\n *\n * @param options The information of the error.\n * @group Controllers/Gateway\n */\nexport type GatewayHelperServiceErrorHandler = (\n options: GatewayHelperServiceErrorHandlerOptions,\n) => void;\n/**\n * The interface of a helper service that can intercept/modify the requests and responses\n * the gateway makes.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayHelperService = Partial<{\n /**\n * A function that is called before an endpoint request is made.\n */\n reduceEndpointRequest: GatewayHelperServiceRequestReducer;\n /**\n * A function that is called with the response of an endpoint request.\n */\n reduceEndpointResponse: GatewayHelperServiceResponseReducer;\n /**\n * A function called in order to validate if an endpoint response should be streamed or\n * not. If the function returns `false`, `handleEndpointResponse` will be called.\n */\n shouldStreamEndpointResponse: GatewayHelperServiceStreamVerification;\n /**\n * A function called when `shouldStreamEndpointResponse` returns `false`. The function\n * should handle the response for the application.\n */\n handleEndpointResponse: GatewayHelperServiceResponseHandler;\n /**\n * A function called when an error is generated during an endpoint request/processing.\n */\n handleEndpointError: GatewayHelperServiceErrorHandler;\n}>;\n/**\n * Utility type for the options object sent to the \"proxy methods\" the controller has for\n * the helper service.\n *\n * @template T The type of the options for a specific helper service function.\n * @access protected\n * @group Controllers/Gateway\n */\nexport type GatewayControllerHelperOptions<T> = T & {\n /**\n * The reference for the helper service.\n */\n helper: GatewayHelperService;\n};\n/**\n * The information for a single HTTP method an endpoint can handle.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerRouteMethod = {\n /**\n * The method for the route.\n */\n method: RouterMethod;\n /**\n * The information of the endpoint.\n */\n endpoint: GatewayControllerEndpointInfo;\n};\n/**\n * The information for all the HTTP methods that can be handled for an endpoint.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerRoute = {\n /**\n * The path to the endpoint, relative to the entry point.\n */\n path: string;\n /**\n * The path for the route in the controller. This is different from `path` as it's possible for\n * the gateway to be implemented using the `root` option.\n */\n route: string;\n /**\n * A list with all the methods the controller uses on the route.\n */\n methods: GatewayControllerRouteMethod[];\n};\n/**\n * The API client configuration the gateway can generate for its endpoints.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerAPIConfig = {\n /**\n * The base URL for the API.\n */\n url: string;\n /**\n * The dictionary of endpoints the controller handles.\n */\n endpoints: APIClientOptions['endpoints'];\n};\n/**\n * The options sent to {@link GatewayController.getAPIConfig}.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerAPIConfigOptions = {\n /**\n * This can be used to overwrite the gateway's `apiConfigSetting` option, and set a new\n * setting as a wrapper for the endpoints.\n */\n setting?: string;\n /**\n * A dictionary of values for possible placeholders that were sent using the `root`\n * option.\n */\n placeholders?: Record<string, string>;\n};\n/**\n * The options to construct a {@link GatewayController}.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerConstructorOptions = GatewayControllerOptions & {\n /**\n * A dictionary with the dependencies to inject.\n */\n inject: {\n http: HTTP;\n /**\n * A function to get a possible helper service. This is injected as a \"getter\" to not\n * interrupt the DIC \"lifecycle\": controllers are initialized right when the app\n * starts, and injecting a reference would force the service to be initialized too,\n * even if a request is not being made.\n */\n getHelperService?: () => GatewayHelperService | undefined;\n };\n};\n/**\n * The options for {@link GatewayController._addRoute}.\n *\n * @access protected\n * @group Controllers/Gateway\n */\nexport type AddGatewayRouteOptions = {\n /**\n * The reference for the router in which the middlewares will be added.\n */\n router: Router;\n /**\n * The router method in which the middlewares will be added.\n */\n method: RouterMethod;\n /**\n * The route in which the middlewares will be added.\n */\n route: string;\n /**\n * The middleware created by {@link GatewayController}, that makes the request.\n */\n gatewayMiddleware: AsyncExpressMiddleware;\n /**\n * A list of extra middlewares to prepend to the gateway middleware.\n */\n middlewares: ExpressMiddleware[];\n};\n/**\n * A utility controller that generates routes that act as a gateway for a specific API.\n *\n * @group Controller Classes\n * @group Controllers/Gateway\n * @prettierignore\n */\nexport class GatewayController {\n /**\n * The service that makes HTTP requests.\n */\n protected readonly http: HTTP;\n /**\n * A function to get a possible helper service. This is injected as a \"getter\" to not\n * interrupt the DIC \"lifecycle\": controllers are initialized right when the app\n * starts, and injecting a reference would force the service to be initialized too,\n * even if a request is not being made.\n */\n protected readonly _getHelperService: () => GatewayHelperService | undefined;\n /**\n * The information, url and endpoints, for the gateway the controller will make requests to.\n */\n protected readonly _gatewayConfig: GatewayConfig;\n /**\n * The route in which the controller is mounted.\n */\n protected readonly _route: string;\n /**\n * A regular expression that will be used to remove the controller route from a\n * request path. This will allow the main middleware to extract the path to where the\n * request should be made.\n */\n protected readonly _routeExpression: RegExp;\n /**\n * The controller customization options.\n */\n protected readonly _options: GatewayControllerExtraOptions;\n /**\n * A flat dictionary with the endpoints information.\n */\n protected readonly _endpoints: Record<string, GatewayConfigEndpointDefinition>;\n /**\n * The entry URL for the API client configuration the controller can generate.\n */\n protected readonly _apiConfigUrl: string;\n /**\n * The generated endpoints for the API client configuration the controller can generate.\n */\n protected readonly _apiConfigEndpoints: APIClientOptions['endpoints'];\n /**\n * The list of routes the controller can handle.\n */\n protected readonly _routes: GatewayControllerRoute[];\n /**\n * @param options The options to construct the controller.\n */\n constructor({\n inject,\n route,\n gatewayConfig,\n ...options\n }: GatewayControllerConstructorOptions) {\n this.http = inject.http;\n this._getHelperService = inject.getHelperService || (() => undefined);\n this._route = removeSlashes(route);\n this._options = this._formatOptions(\n deepAssignWithOverwrite(\n {\n root: '',\n apiConfigSetting: 'api',\n headers: {\n useXForwardedFor: true,\n copyCustomHeaders: true,\n copy: ['authorization', 'content-type', 'referer', 'user-agent'],\n remove: ['server', 'x-powered-by', 'content-encoding'],\n },\n },\n options,\n ),\n );\n this._gatewayConfig = {\n ...gatewayConfig,\n url: removeSlashes(gatewayConfig.url, false, true),\n };\n this._routeExpression = createRouteExpression(\n this._options.root ? `${this._route}/${this._options.root}` : this._route,\n true,\n true,\n );\n this._endpoints = this._formatEndpoints();\n this._routes = this._createRoutes();\n const { url, endpoints } = this._createAPIConfig();\n this._apiConfigUrl = url;\n this._apiConfigEndpoints = endpoints;\n }\n /**\n * Generates an API client configuration based on the controller routes.\n *\n * @param options The options to customize the generated configuration.\n */\n getAPIConfig({\n setting,\n placeholders = {},\n }: GatewayControllerAPIConfigOptions = {}): Readonly<GatewayControllerAPIConfig> {\n const useSetting = setting || this._options.apiConfigSetting;\n let url: string;\n const placeholdersEntries = Object.entries(placeholders);\n if (placeholdersEntries.length) {\n url = placeholdersEntries.reduce<string>(\n (acc, [key, value]) => acc.replace(`:${key}`, value),\n this._apiConfigUrl,\n );\n } else {\n url = this._apiConfigUrl;\n }\n\n return {\n url,\n endpoints: {\n [useSetting]: this._apiConfigEndpoints,\n },\n };\n }\n /**\n * Mounts the middlewares in the router in order to make the requests.\n *\n * @param router A reference to the application router.\n * @param middlewares A list of extra middlewares to execute before the gateway\n * middleware.\n */\n addRoutes(router: Router, middlewares: ExpressMiddleware[] = []): Router {\n this._routes.forEach((route) => {\n route.methods.forEach((info) => {\n this._addRoute({\n router,\n method: info.method,\n route: route.route,\n gatewayMiddleware: this._createGatewayMiddleware(info.endpoint),\n middlewares,\n });\n });\n });\n\n return router;\n }\n /**\n * The customization options.\n */\n get options(): Readonly<GatewayControllerExtraOptions> {\n return { ...this._options };\n }\n /**\n * The configuration for the gateway the controller will make requests to.\n */\n get gatewayConfig(): Readonly<GatewayConfig> {\n return { ...this._gatewayConfig };\n }\n /**\n * Generates a middleware that will make the request to an endpoint and stream the\n * response.\n *\n * @param endpoint The information of the endpoint the middleware will handle.\n */\n protected _createGatewayMiddleware(\n endpoint: GatewayControllerEndpointInfo,\n ): AsyncExpressMiddleware {\n return async (req, res, next) => {\n const {\n _options: { headers: headersOptions },\n _gatewayConfig: { url: gatewayUrl },\n _routeExpression: routeExpression,\n } = this;\n // Remove the controller route from the requested URL.\n const reqPath = req.originalUrl.replace(routeExpression, '');\n // Process the headers for the request.\n let headers: Record<string, string> = {};\n // - Copy the headers from the incoming request.\n headersOptions.copy.forEach((name) => {\n if (req.headers[name]) {\n headers[name] = req.headers[name] as string;\n }\n });\n // - Copy the custom headers.\n if (headersOptions.copyCustomHeaders) {\n headers = deepAssignWithOverwrite<Record<string, string>>(\n headers,\n this.http.getCustomHeadersFromRequest(req),\n );\n }\n // - Include the IP on the X-Forwarded-For header, if enabled.\n if (headersOptions.useXForwardedFor) {\n const ip = this.http.getIPFromRequest(req);\n if (ip) {\n headers['x-forwarded-for'] = ip;\n }\n }\n\n const method = req.method.toUpperCase();\n // If the request has a body and the method is not `GET`, stringify it.\n let body: string | undefined;\n if (method !== 'GET' && typeof req.body === 'object') {\n body = JSON.stringify(req.body);\n // If there's no `content-type`, let's assume it's JSON.\n if (!headers['content-type']) {\n headers['content-type'] = 'application/json';\n }\n }\n\n /**\n * Get the helper service, if there's one, and define the base options for its\n * methods.\n */\n const helper = this._getHelperService() || {};\n const helperBasePayload = {\n endpoint,\n req,\n res,\n next,\n helper,\n };\n\n try {\n // Reduce the request information before using it.\n const request = await this._reduceEndpointRequest({\n endpointReq: {\n url: `${gatewayUrl}/${reqPath}`,\n options: {\n method,\n headers,\n body,\n },\n },\n ...helperBasePayload,\n });\n // Make the actual request.\n const responseRaw = await this.http.fetch(request.url, request.options);\n // Reduce the response information before using it.\n const response = await this._reduceEndpointResponse({\n endpointRes: responseRaw,\n ...helperBasePayload,\n });\n // Validate if the response should be streamed.\n const shouldStream = await this._shouldStreamEndpointResponse({\n endpointRes: responseRaw,\n ...helperBasePayload,\n });\n\n if (shouldStream) {\n if (response.body === null) {\n throw new Error('The response body is null');\n }\n\n /**\n * If the response should be streamed, set the status, remove unwanted headers,\n * and pipe it to the application response object.\n */\n res.status(response.status);\n response.headers.forEach((value, name) => {\n if (!headersOptions.remove.includes(name)) {\n res.setHeader(name, value);\n }\n });\n\n response.body.pipe(res).on('error', (error) => {\n next(error);\n });\n } else {\n /**\n * If the response should not be streamed, send it to the helper method to\n * handle it.\n */\n await this._handleEndpointResponse({\n endpointRes: response,\n ...helperBasePayload,\n });\n }\n } catch (error) {\n // Something failed, so let's pass the error to the helper service.\n this._handleEndpointError({\n error: error as Error,\n ...helperBasePayload,\n });\n }\n };\n }\n /**\n * Mounts the middleware(s) for an endpoint in the router.\n *\n * @param options The information of the endpoint and how it needs to be added.\n */\n protected _addRoute({\n router,\n method,\n route,\n gatewayMiddleware,\n middlewares,\n }: AddGatewayRouteOptions): void {\n router[method](route, [...middlewares, gatewayMiddleware]);\n }\n /**\n * Formats the endpoints for the gateway into a flat dictionary without nesting.\n */\n protected _formatEndpoints(): Record<string, GatewayConfigEndpointDefinition> {\n return flat({\n target: this._gatewayConfig.gateway,\n shouldFlatten: (_, value) => {\n const useValue = value as { path?: string };\n return typeof useValue.path === 'undefined';\n },\n });\n }\n /**\n * Based on the information from the endpoints, this method will create the routes the\n * controller will later add on a router.\n *\n * @throws If there's more than one endpoint using the same path with the same HTTP\n * method.\n */\n protected _createRoutes(): GatewayControllerRoute[] {\n const routes: Record<\n string,\n {\n path: string;\n methods: Partial<Record<RouterMethod, string>>;\n }\n > = {};\n Object.keys(this._endpoints).forEach((name) => {\n const endpoint = this._endpoints[name]!;\n let endpointPath: string;\n let endpointMethod: RouterMethod;\n if (typeof endpoint === 'string') {\n endpointPath = endpoint;\n endpointMethod = 'all';\n } else {\n endpointPath = endpoint.path;\n endpointMethod = endpoint.method\n ? this._validateHTTPMethod(endpoint.method)\n : 'all';\n }\n\n endpointPath = removeSlashes(endpointPath);\n if (!routes[endpointPath]) {\n routes[endpointPath] = {\n path: endpointPath,\n methods: {},\n };\n }\n\n if (routes[endpointPath]!.methods[endpointMethod]) {\n const repeatedEndpoint = routes[endpointPath]!.methods[endpointMethod];\n throw new Error(\n \"You can't have two gateway endpoints to the same path and with the same \" +\n `HTTP method: '${repeatedEndpoint}' and '${name}'`,\n );\n }\n\n routes[endpointPath]!.methods[endpointMethod] = name;\n });\n\n const routePrefixes = this._options.root ? `/${this._options.root}/` : '/';\n return Object.keys(routes).map((endpointPath) => {\n const info = routes[endpointPath]!;\n return {\n path: info.path,\n route: `${routePrefixes}${info.path}`,\n methods: Object.keys(info.methods).map((methodNameRaw) => {\n const methodName = methodNameRaw as RouterMethod;\n const endpointName = info.methods[methodName]!;\n const endpointDefinition = this._endpoints[endpointName]!;\n return {\n method: methodName,\n endpoint: {\n name: endpointName,\n definition: endpointDefinition,\n },\n };\n }),\n };\n });\n }\n /**\n * This is a \"proxy method\" to call the helper service's function that can modify an\n * endpoint request before it gets made.\n *\n * The reason this is a \"proxy method\" is in case the controller gets subclassed and\n * \"used itself as a helper\" instead of relying on a difference one.\n *\n * If the helper doesn't implement `reduceEndpointRequest`, it will just return\n * information for the request.\n *\n * @param options The information of the request and the reference to the helper.\n */\n protected _reduceEndpointRequest({\n helper,\n ...options\n }: GatewayControllerHelperOptions<GatewayHelperServiceRequestReducerOptions>): Promise<GatewayControllerRequest> {\n if (helper.reduceEndpointRequest) {\n return helper.reduceEndpointRequest(options);\n }\n\n return Promise.resolve(options.endpointReq);\n }\n /**\n * This is a \"proxy method\" to call the helper service's function that can modify an\n * endpoint response before it gets processed.\n *\n * The reason this is a \"proxy method\" is in case the controller gets subclassed and\n * \"used itself as a helper\" instead of relying on a difference one.\n *\n * If the helper doesn't implement `reduceEndpointResponse`, it will just return\n * information for the response.\n *\n * @param options The information of the response and the reference to the helper.\n */\n protected _reduceEndpointResponse({\n helper,\n ...options\n }: GatewayControllerHelperOptions<GatewayHelperServiceResponseReducerOptions>): Promise<HTTPResponse> {\n if (helper.reduceEndpointResponse) {\n return helper.reduceEndpointResponse(options);\n }\n\n return Promise.resolve(options.endpointRes);\n }\n /**\n * This is a \"proxy method\" to call the helper service's function that can decide if an\n * endpoint response should be streamed or not.\n *\n * The reason this is a \"proxy method\" is in case the controller gets subclassed and\n * \"used itself as a helper\" instead of relying on a difference one.\n *\n * If the helper doesn't implement `shouldStreamEndpointResponse`, it will just return\n * `true`.\n *\n * @param options The information of the response and the reference to the helper.\n */\n protected _shouldStreamEndpointResponse({\n helper,\n ...options\n }: GatewayControllerHelperOptions<GatewayHelperServiceResponseReducerOptions>): Promise<boolean> {\n if (helper.shouldStreamEndpointResponse) {\n return helper.shouldStreamEndpointResponse(options);\n }\n\n return Promise.resolve(true);\n }\n /**\n * This is a \"proxy method\" to call the helper service's function that handles a\n * response in case it already said that a response shouldn't be streamed.\n *\n * The reason this is a \"proxy method\" is in case the controller gets subclassed and\n * \"used itself as a helper\" instead of relying on a difference one.\n *\n * If the helper doesn't implement `shouldStreamEndpointResponse`, it will throw an\n * error.\n *\n * @param options The information of the response and the reference to the helper.\n * @throws If the helper doesn't implement `handleEndpointResponse`.\n */\n protected _handleEndpointResponse({\n helper,\n ...options\n }: GatewayControllerHelperOptions<GatewayHelperServiceResponseReducerOptions>): Promise<void> {\n if (!helper.handleEndpointResponse) {\n throw new Error('You must implement handleEndpointResponse');\n }\n\n return helper.handleEndpointResponse(options);\n }\n /**\n * This is a \"proxy method\" to call the helper service's function that handles an error\n * on an endpoint request.\n *\n * The reason this is a \"proxy method\" is in case the controller gets subclassed and\n * \"used itself as a helper\" instead of relying on a difference one.\n *\n * If the helper doesn't implement `handleEndpointError`, it will just send the error to\n * the next middleware/error handler.\n *\n * @param options The information of the response and the reference to the helper.\n */\n protected _handleEndpointError({\n helper,\n ...options\n }: GatewayControllerHelperOptions<GatewayHelperServiceErrorHandlerOptions>): void {\n if (helper.handleEndpointError) {\n return helper.handleEndpointError(options);\n }\n\n return options.next(options.error);\n }\n /**\n * Validates and formats the customization options sent to the controller.\n *\n * @param options The options sent to the constructor.\n */\n protected _formatOptions(\n options: GatewayControllerExtraOptions,\n ): GatewayControllerExtraOptions {\n if (options.root) {\n const root = removeSlashes(options.root).trim();\n return { ...options, root };\n }\n\n return options;\n }\n /**\n * Validates a router/HTTP method that the controller intends to use for an endpoint. If\n * it's not valid, it will return `all`.\n *\n * @param method The HTTP method for the endpoint.\n */\n protected _validateHTTPMethod(method: string): RouterMethod {\n const newMethod = method.toLowerCase();\n return [\n 'get',\n 'head',\n 'post',\n 'patch',\n 'put',\n 'delete',\n 'connect',\n 'options',\n 'trace',\n ].includes(newMethod)\n ? (newMethod as RouterMethod)\n : 'all';\n }\n /**\n * Creates the API client configuration based on the controller routes.\n */\n protected _createAPIConfig(): GatewayControllerAPIConfig {\n let endpoints: APIClientOptions['endpoints'];\n const { root } = this._options;\n if (root) {\n endpoints = Object.keys(this._endpoints).reduce<\n Record<string, GatewayConfigEndpointDefinition>\n >((acc, name) => {\n const endpoint = this._endpoints[name]!;\n let newEndpoint;\n if (typeof endpoint === 'string') {\n newEndpoint = removeSlashes(endpoint);\n newEndpoint = `${root}/${newEndpoint}`;\n } else {\n const endpointPath = removeSlashes(endpoint.path);\n newEndpoint = {\n ...endpoint,\n path: `${root}/${endpointPath}`,\n };\n }\n\n acc[name] = newEndpoint;\n return acc;\n }, {});\n } else {\n endpoints = this._endpoints;\n }\n\n return {\n url: `/${this._route}`,\n endpoints: unflat({ target: endpoints }),\n };\n }\n}\n/**\n * A function to generate a list of middlewares that can be executed before the tontroller\n * main middleware.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerGetMiddlewaresFn = (app: Jimpex) => MiddlewareLike[];\n/**\n * The options for the controller creator that mounts the {@link GatewayController}.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerCreatorOptions =\n DeepPartial<GatewayControllerExtraOptions> & {\n /**\n * The name the creator will use to register the controller in the container. No,\n * this is not a typo. The creator will register the controller so other services can\n * access the `getAPIConfig` method. The service will be available after the app\n * routes are mounted.\n * If this is overwritten, the creator will ensure that the name ends with `Gateway`;\n * and if overwritten, but it doesn't include `Gateway` at the end, and no\n * `gatewaySettingName` was defined, the creator will use the custom name (without\n * `Gatway`) for `gatewaySettingName`.\n *\n * @default 'apiGateway'\n */\n serviceName?: string;\n /**\n * The name of the helper service the creator will try to obtain from the container.\n * If `serviceName` is overwritten, the default for this will be\n * `${serviceName}Helper`.\n *\n * @default 'apiGatewayHelper'\n */\n helperServiceName?: string;\n /**\n * The name of the configuration setting where the gateway configuration is stored. If\n * not overwritten, check the description of `serviceName` to understand which will be\n * its default value.\n *\n * @default 'api'\n */\n gatewaySettingName?: string;\n /**\n * The class the creator will instantiate. Similar to the API Client, this allows for\n * extra customization as you can send a custom subclass of the\n * {@link GatewayController}.\n *\n * @default GatewayController\n */\n gatewayClass?: typeof GatewayController;\n /**\n * A function to generate a list of middlewares that can be executed before the\n * controller main middleware.\n */\n getMiddlewares?: GatewayControllerGetMiddlewaresFn;\n };\n/**\n * Creates a controller that allows the application to mount routes that will work like\n * gateway to a specific API.\n *\n * @group Controllers\n * @group Controllers/Gateway\n */\nexport const gatewayController = controllerProviderCreator(\n (options: GatewayControllerCreatorOptions = {}) =>\n (app, route) => {\n /**\n * Formats the name in order to keep consistency with the helper service and the\n * configuration setting: If the `serviceName` is different from the default, make\n * sure it ends with `Gateway`, set the default helper service name to\n * `${serviceName}Helper`, and the default configuration setting to the same as the\n * service name (without the `Gateway`).\n * This way, if you just use `myApi`, the service name will be `myApiGateway`, the\n * helper name will be `myApiGatewayHelper` and the configuration setting `myApi`.\n */\n const defaultServiceName = 'apiGateway';\n let defaultHelperServiceName = 'apiGatewayHelper';\n let defaultConfigSetting = 'api';\n let { serviceName = defaultServiceName } = options;\n if (serviceName !== defaultServiceName) {\n defaultConfigSetting = serviceName;\n if (!serviceName.match(/gateway$/i)) {\n serviceName = `${serviceName}Gateway`;\n }\n defaultHelperServiceName = `${serviceName}Helper`;\n }\n // Register the service.\n app.set(serviceName, () => {\n const {\n helperServiceName = defaultHelperServiceName,\n gatewaySettingName = defaultConfigSetting,\n gatewayClass: GatewayClass = GatewayController,\n } = options;\n\n const gtConfig = app.getConfig<GatewayConfig>(gatewaySettingName);\n\n return new GatewayClass({\n ...options,\n apiConfigSetting: gatewaySettingName,\n gatewayConfig: gtConfig,\n route,\n inject: {\n http: app.get('http'),\n getHelperService: () => app.try(helperServiceName),\n },\n });\n });\n\n return controller(() => {\n // Get the controller.\n const ctrl = app.get<GatewayController>(serviceName);\n /**\n * Check if there are actual middlewares to be included, and in case there are\n * Jimpex middlewares, connect them.\n */\n let useMiddlewares: ExpressMiddleware[] | undefined;\n if (options.getMiddlewares) {\n useMiddlewares = options\n .getMiddlewares(app)\n .map((middleware) => {\n if ('middleware' in middleware) {\n return middleware.connect(app) as ExpressMiddleware | undefined;\n }\n\n return middleware as ExpressMiddleware;\n })\n .filter(notUndefined);\n }\n\n // Add the routes to the router and return it.\n return ctrl.addRoutes(app.get('router'), useMiddlewares);\n });\n },\n);\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/controllers/utils/gateway.ts"],"sourcesContent":["import { deepAssignWithOverwrite } from '@homer0/deep-assign';\nimport { flat, unflat } from '@homer0/object-utils';\nimport type { APIClientOptions } from '@homer0/api-utils';\nimport {\n controllerProviderCreator,\n controller,\n createRouteExpression,\n removeSlashes,\n notUndefined,\n type MiddlewareLike,\n} from '../../utils';\nimport type { HTTP, HTTPFetchOptions } from '../../services';\nimport type { Jimpex } from '../../app';\nimport {\n RouterMethod,\n DeepPartial,\n Request,\n Response,\n NextFunction,\n HTTPResponse,\n Router,\n ExpressMiddleware,\n AsyncExpressMiddleware,\n} from '../../types';\n/**\n * The extended definition for endpoints.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayConfigEndpointProps = {\n /**\n * The path to the endpoint relative to the entry point. It can include placeholders for\n * parameters like `/:parameter/`.\n */\n path: string;\n /**\n * The router (HTTP) method for the endpoint.\n *\n * @default 'all'\n */\n method?: RouterMethod;\n};\n/**\n * The definition of an endpoint: it can be just the path, relative to the entry point, or\n * an object in which you can also specify things like the method.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayConfigEndpointDefinition = string | GatewayConfigEndpointProps;\n/**\n * The dictionary of endpoints the controller uses. The reason for this type is that this\n * could be a flat dictionary, or a nested one.\n *\n * @example\n *\n * <caption>A flat dictionary</caption>\n *\n * {\n * random: '/random',\n * users: '/users',\n * userById: {\n * path: '/users/:id',\n * method: 'get',\n * },\n * }\n *\n * @example\n *\n * <caption>A nested dictionary</caption>\n *\n * {\n * random: '/random',\n * users: {\n * list: '/users',\n * byId: {\n * path: '/users/:id',\n * method: 'get',\n * },\n * },\n * }\n *\n * @group Controllers/Gateway\n */\nexport type GatewayConfigEndpoints = {\n [key: string]: GatewayConfigEndpointDefinition | GatewayConfigEndpoints;\n};\n/**\n * The configuration for the gateway the controller uses.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayConfig = {\n /**\n * The entry point to the API the controller will make the requests to.\n */\n url: string;\n /**\n * The dictionary of enpoints the gateway will make available.\n */\n gateway: GatewayConfigEndpoints;\n};\n/**\n * The options for how the gateway will handle the headers from the requests and the\n * responses.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerHeaderOptions = {\n /**\n * Whether or not to include the header with the request's IP address.\n *\n * @default true\n */\n useXForwardedFor: boolean;\n /**\n * Whether or not to copy all custom headers from the request. By custom header, it\n * means all the headers which names start with `x-`.\n *\n * @default true\n */\n copyCustomHeaders: boolean;\n /**\n * A list of \"known\" headers the gateway will try to copy from the incoming request.\n *\n * @default ['authorization','content-type', 'referer', 'user-agent']\n */\n copy: string[];\n /**\n * A list of \"known\" headers the gateway will try to remove the response.\n *\n * @default ['server', 'x-powered-by']\n */\n remove: string[];\n};\n/**\n * The extra options for the gateway controller. They are \"extra\" because they are mostly\n * helpers for when used with an API client, or for optional features.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerExtraOptions = {\n /**\n * This is really a helper for when the gateway is used with an API client. The idea is\n * that, by default, the routes are mounted on the controller route, but with this\n * option, you can specify another sub path. For example: The controller is mounted on\n * `/routes`, and if you set `root` to `gateway`, all the routes will be on\n * `/routes/gateway`.\n *\n * This become important (and useful) when you get the API client configuration (with\n * `getAPIConfig`): The `url` will be the controller route, but all the endpoints will\n * be modified and prefixed with the `root`, that way, you can have multiple gateways in\n * the same \"base route\".\n *\n * It can also includes placeholders for parameters like `/:parameter/`, that will be\n * replaced with the `placeholders` option when `getAPIConfig` gets called.\n *\n * @default ''\n */\n root: string;\n /**\n * This is another option for when the gateway is used with an API client. When calling\n * `getAPIConfig`, all the endpoints will be wrapped inside an object named after this\n * option. For example: `{ url: '...', endpoints: { api: { ... } } }`.\n *\n * @default 'api'\n */\n apiConfigSetting: string;\n /**\n * The options for how the gateway will handle the headers from the requests and the\n * responses.\n */\n headers: GatewayControllerHeaderOptions;\n};\n/**\n * The required options for the gateway controller.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerOptions = {\n /**\n * The configuration for the API the gateway will make the requests to.\n */\n gatewayConfig: GatewayConfig;\n /**\n * The route where the controller is mounted.\n */\n route: string;\n} & DeepPartial<GatewayControllerExtraOptions>;\n/**\n * The information for a request the controller will make.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerRequest = {\n /**\n * The URL for the request.\n */\n url: string;\n /**\n * The options for the fetch client that will make the requests.\n */\n options: HTTPFetchOptions;\n};\n/**\n * The information for an endpoint the gateway is calling.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerEndpointInfo = {\n /**\n * The name of the endpoint in the configuration.\n */\n name: string;\n /**\n * The properties (path and method) of the endpoint.\n */\n definition: GatewayConfigEndpointDefinition;\n};\n/**\n * These are the base options sent to all the helper service functions.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayHelperServiceBaseFnOptions = {\n /**\n * The information of the endpoint the gateway is calling.\n */\n endpoint: GatewayControllerEndpointInfo;\n /**\n * The request recived by the application.\n */\n req: Request;\n /**\n * The response object created by the application.\n */\n res: Response;\n /**\n * The function to call the next middleware in the chain.\n */\n next: NextFunction;\n};\n/**\n * The information sent to the helper service in order to modify, or not, a request before\n * it is sent.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayHelperServiceRequestReducerOptions =\n GatewayHelperServiceBaseFnOptions & {\n /**\n * The options the controller created for the fetch client.\n */\n endpointReq: GatewayControllerRequest;\n };\n/**\n * A function that can be used to modify the information of an endpoint before making a\n * request.\n *\n * @param options The information of the request.\n * @group Controllers/Gateway\n */\nexport type GatewayHelperServiceRequestReducer = (\n options: GatewayHelperServiceRequestReducerOptions,\n) => Promise<GatewayControllerRequest>;\n/**\n * The information sent to the helper service in order to modify a response before\n * processing it, decide if it should be streamed or not, and even handle it.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayHelperServiceResponseReducerOptions =\n GatewayHelperServiceBaseFnOptions & {\n /**\n * The response from the endpoint request.\n */\n endpointRes: HTTPResponse;\n };\n/**\n * A function that can be used to modify the response of an endpoint before the controller\n * processes it.\n *\n * @param options The information of the response.\n * @group Controllers/Gateway\n */\nexport type GatewayHelperServiceResponseReducer = (\n options: GatewayHelperServiceResponseReducerOptions,\n) => Promise<HTTPResponse>;\n/**\n * A function that can be used to tell the controller to stream the response of an\n * endpoint or not.\n * If it returns `false`, the function to handle responses should be defined, otherwise,\n * an error will be generated.\n *\n * @param options The information of the response.\n * @group Controllers/Gateway\n */\nexport type GatewayHelperServiceStreamVerification = (\n options: GatewayHelperServiceResponseReducerOptions,\n) => Promise<boolean>;\n/**\n * A function to handle the response of an endpoint. This is called when the helper\n * service tells the controller that the endpoint shouldn't be streamed, so this method\n * should handle the response.\n *\n * @param options The information of the response.\n * @group Controllers/Gateway\n */\nexport type GatewayHelperServiceResponseHandler = (\n options: GatewayHelperServiceResponseReducerOptions,\n) => Promise<void>;\n/**\n * The information sent to the helper service in order to handle a failed request for an\n * endpoint.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayHelperServiceErrorHandlerOptions =\n GatewayHelperServiceBaseFnOptions & {\n /**\n * The error generated during the request.\n */\n error: Error;\n };\n/**\n * A function to handle the error of an endpoint request.\n *\n * @param options The information of the error.\n * @group Controllers/Gateway\n */\nexport type GatewayHelperServiceErrorHandler = (\n options: GatewayHelperServiceErrorHandlerOptions,\n) => void;\n/**\n * The interface of a helper service that can intercept/modify the requests and responses\n * the gateway makes.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayHelperService = Partial<{\n /**\n * A function that is called before an endpoint request is made.\n */\n reduceEndpointRequest: GatewayHelperServiceRequestReducer;\n /**\n * A function that is called with the response of an endpoint request.\n */\n reduceEndpointResponse: GatewayHelperServiceResponseReducer;\n /**\n * A function called in order to validate if an endpoint response should be streamed or\n * not. If the function returns `false`, `handleEndpointResponse` will be called.\n */\n shouldStreamEndpointResponse: GatewayHelperServiceStreamVerification;\n /**\n * A function called when `shouldStreamEndpointResponse` returns `false`. The function\n * should handle the response for the application.\n */\n handleEndpointResponse: GatewayHelperServiceResponseHandler;\n /**\n * A function called when an error is generated during an endpoint request/processing.\n */\n handleEndpointError: GatewayHelperServiceErrorHandler;\n}>;\n/**\n * Utility type for the options object sent to the \"proxy methods\" the controller has for\n * the helper service.\n *\n * @template T The type of the options for a specific helper service function.\n * @access protected\n * @group Controllers/Gateway\n */\nexport type GatewayControllerHelperOptions<T> = T & {\n /**\n * The reference for the helper service.\n */\n helper: GatewayHelperService;\n};\n/**\n * The information for a single HTTP method an endpoint can handle.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerRouteMethod = {\n /**\n * The method for the route.\n */\n method: RouterMethod;\n /**\n * The information of the endpoint.\n */\n endpoint: GatewayControllerEndpointInfo;\n};\n/**\n * The information for all the HTTP methods that can be handled for an endpoint.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerRoute = {\n /**\n * The path to the endpoint, relative to the entry point.\n */\n path: string;\n /**\n * The path for the route in the controller. This is different from `path` as it's possible for\n * the gateway to be implemented using the `root` option.\n */\n route: string;\n /**\n * A list with all the methods the controller uses on the route.\n */\n methods: GatewayControllerRouteMethod[];\n};\n/**\n * The API client configuration the gateway can generate for its endpoints.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerAPIConfig = {\n /**\n * The base URL for the API.\n */\n url: string;\n /**\n * The dictionary of endpoints the controller handles.\n */\n endpoints: APIClientOptions['endpoints'];\n};\n/**\n * The options sent to {@link GatewayController.getAPIConfig}.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerAPIConfigOptions = {\n /**\n * This can be used to overwrite the gateway's `apiConfigSetting` option, and set a new\n * setting as a wrapper for the endpoints.\n */\n setting?: string;\n /**\n * A dictionary of values for possible placeholders that were sent using the `root`\n * option.\n */\n placeholders?: Record<string, string>;\n};\n/**\n * The options to construct a {@link GatewayController}.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerConstructorOptions = GatewayControllerOptions & {\n /**\n * A dictionary with the dependencies to inject.\n */\n inject: {\n http: HTTP;\n /**\n * A function to get a possible helper service. This is injected as a \"getter\" to not\n * interrupt the DIC \"lifecycle\": controllers are initialized right when the app\n * starts, and injecting a reference would force the service to be initialized too,\n * even if a request is not being made.\n */\n getHelperService?: () => GatewayHelperService | undefined;\n };\n};\n/**\n * The options for {@link GatewayController._addRoute}.\n *\n * @access protected\n * @group Controllers/Gateway\n */\nexport type AddGatewayRouteOptions = {\n /**\n * The reference for the router in which the middlewares will be added.\n */\n router: Router;\n /**\n * The router method in which the middlewares will be added.\n */\n method: RouterMethod;\n /**\n * The route in which the middlewares will be added.\n */\n route: string;\n /**\n * The middleware created by {@link GatewayController}, that makes the request.\n */\n gatewayMiddleware: AsyncExpressMiddleware;\n /**\n * A list of extra middlewares to prepend to the gateway middleware.\n */\n middlewares: ExpressMiddleware[];\n};\n/**\n * A utility controller that generates routes that act as a gateway for a specific API.\n *\n * @group Controller Classes\n * @group Controllers/Gateway\n * @prettierignore\n */\nexport class GatewayController {\n /**\n * The service that makes HTTP requests.\n */\n protected readonly http: HTTP;\n /**\n * A function to get a possible helper service. This is injected as a \"getter\" to not\n * interrupt the DIC \"lifecycle\": controllers are initialized right when the app\n * starts, and injecting a reference would force the service to be initialized too,\n * even if a request is not being made.\n */\n protected readonly _getHelperService: () => GatewayHelperService | undefined;\n /**\n * The information, url and endpoints, for the gateway the controller will make requests to.\n */\n protected readonly _gatewayConfig: GatewayConfig;\n /**\n * The route in which the controller is mounted.\n */\n protected readonly _route: string;\n /**\n * A regular expression that will be used to remove the controller route from a\n * request path. This will allow the main middleware to extract the path to where the\n * request should be made.\n */\n protected readonly _routeExpression: RegExp;\n /**\n * The controller customization options.\n */\n protected readonly _options: GatewayControllerExtraOptions;\n /**\n * A flat dictionary with the endpoints information.\n */\n protected readonly _endpoints: Record<string, GatewayConfigEndpointDefinition>;\n /**\n * The entry URL for the API client configuration the controller can generate.\n */\n protected readonly _apiConfigUrl: string;\n /**\n * The generated endpoints for the API client configuration the controller can generate.\n */\n protected readonly _apiConfigEndpoints: APIClientOptions['endpoints'];\n /**\n * The list of routes the controller can handle.\n */\n protected readonly _routes: GatewayControllerRoute[];\n /**\n * @param options The options to construct the controller.\n */\n constructor({\n inject,\n route,\n gatewayConfig,\n ...options\n }: GatewayControllerConstructorOptions) {\n this.http = inject.http;\n this._getHelperService = inject.getHelperService || (() => undefined);\n this._route = removeSlashes(route);\n this._options = this._formatOptions(\n deepAssignWithOverwrite(\n {\n root: '',\n apiConfigSetting: 'api',\n headers: {\n useXForwardedFor: true,\n copyCustomHeaders: true,\n copy: ['authorization', 'content-type', 'referer', 'user-agent'],\n remove: ['server', 'x-powered-by', 'content-encoding'],\n },\n },\n options,\n ),\n );\n this._gatewayConfig = {\n ...gatewayConfig,\n url: removeSlashes(gatewayConfig.url, false, true),\n };\n this._routeExpression = createRouteExpression(\n this._options.root ? `${this._route}/${this._options.root}` : this._route,\n true,\n true,\n );\n this._endpoints = this._formatEndpoints();\n this._routes = this._createRoutes();\n const { url, endpoints } = this._createAPIConfig();\n this._apiConfigUrl = url;\n this._apiConfigEndpoints = endpoints;\n }\n /**\n * Generates an API client configuration based on the controller routes.\n *\n * @param options The options to customize the generated configuration.\n */\n getAPIConfig({\n setting,\n placeholders = {},\n }: GatewayControllerAPIConfigOptions = {}): Readonly<GatewayControllerAPIConfig> {\n const useSetting = setting || this._options.apiConfigSetting;\n let url: string;\n const placeholdersEntries = Object.entries(placeholders);\n if (placeholdersEntries.length) {\n url = placeholdersEntries.reduce<string>(\n (acc, [key, value]) => acc.replace(`:${key}`, value),\n this._apiConfigUrl,\n );\n } else {\n url = this._apiConfigUrl;\n }\n\n return {\n url,\n endpoints: {\n [useSetting]: this._apiConfigEndpoints,\n },\n };\n }\n /**\n * Mounts the middlewares in the router in order to make the requests.\n *\n * @param router A reference to the application router.\n * @param middlewares A list of extra middlewares to execute before the gateway\n * middleware.\n */\n addRoutes(router: Router, middlewares: ExpressMiddleware[] = []): Router {\n this._routes.forEach((route) => {\n route.methods.forEach((info) => {\n this._addRoute({\n router,\n method: info.method,\n route: route.route,\n gatewayMiddleware: this._createGatewayMiddleware(info.endpoint),\n middlewares,\n });\n });\n });\n\n return router;\n }\n /**\n * The customization options.\n */\n get options(): Readonly<GatewayControllerExtraOptions> {\n return { ...this._options };\n }\n /**\n * The configuration for the gateway the controller will make requests to.\n */\n get gatewayConfig(): Readonly<GatewayConfig> {\n return { ...this._gatewayConfig };\n }\n /**\n * Generates a middleware that will make the request to an endpoint and stream the\n * response.\n *\n * @param endpoint The information of the endpoint the middleware will handle.\n */\n protected _createGatewayMiddleware(\n endpoint: GatewayControllerEndpointInfo,\n ): AsyncExpressMiddleware {\n return async (req, res, next) => {\n const {\n _options: { headers: headersOptions },\n _gatewayConfig: { url: gatewayUrl },\n _routeExpression: routeExpression,\n } = this;\n // Remove the controller route from the requested URL.\n const reqPath = req.originalUrl.replace(routeExpression, '');\n // Process the headers for the request.\n let headers: Record<string, string> = {};\n // - Copy the headers from the incoming request.\n headersOptions.copy.forEach((name) => {\n if (req.headers[name]) {\n headers[name] = req.headers[name] as string;\n }\n });\n // - Copy the custom headers.\n if (headersOptions.copyCustomHeaders) {\n headers = deepAssignWithOverwrite<Record<string, string>>(\n headers,\n this.http.getCustomHeadersFromRequest(req),\n );\n }\n // - Include the IP on the X-Forwarded-For header, if enabled.\n if (headersOptions.useXForwardedFor) {\n const ip = this.http.getIPFromRequest(req);\n if (ip) {\n headers['x-forwarded-for'] = ip;\n }\n }\n\n const method = req.method.toUpperCase();\n // If the request has a body and the method is not `GET`, stringify it.\n let body: string | undefined;\n if (method !== 'GET' && typeof req.body === 'object') {\n body = JSON.stringify(req.body);\n // If there's no `content-type`, let's assume it's JSON.\n if (!headers['content-type']) {\n headers['content-type'] = 'application/json';\n }\n }\n\n /**\n * Get the helper service, if there's one, and define the base options for its\n * methods.\n */\n const helper = this._getHelperService() || {};\n const helperBasePayload = {\n endpoint,\n req,\n res,\n next,\n helper,\n };\n\n try {\n // Reduce the request information before using it.\n const request = await this._reduceEndpointRequest({\n endpointReq: {\n url: `${gatewayUrl}/${reqPath}`,\n options: {\n method,\n headers,\n body,\n },\n },\n ...helperBasePayload,\n });\n // Make the actual request.\n const responseRaw = await this.http.fetch(request.url, request.options);\n // Reduce the response information before using it.\n const response = await this._reduceEndpointResponse({\n endpointRes: responseRaw,\n ...helperBasePayload,\n });\n // Validate if the response should be streamed.\n const shouldStream = await this._shouldStreamEndpointResponse({\n endpointRes: responseRaw,\n ...helperBasePayload,\n });\n\n if (shouldStream) {\n if (response.body === null) {\n throw new Error('The response body is null');\n }\n\n /**\n * If the response should be streamed, set the status, remove unwanted headers,\n * and pipe it to the application response object.\n */\n res.status(response.status);\n response.headers.forEach((value, name) => {\n if (!headersOptions.remove.includes(name)) {\n res.setHeader(name, value);\n }\n });\n\n response.body.pipe(res).on('error', (error) => {\n next(error);\n });\n } else {\n /**\n * If the response should not be streamed, send it to the helper method to\n * handle it.\n */\n await this._handleEndpointResponse({\n endpointRes: response,\n ...helperBasePayload,\n });\n }\n } catch (error) {\n // Something failed, so let's pass the error to the helper service.\n this._handleEndpointError({\n error: error as Error,\n ...helperBasePayload,\n });\n }\n };\n }\n /**\n * Mounts the middleware(s) for an endpoint in the router.\n *\n * @param options The information of the endpoint and how it needs to be added.\n */\n protected _addRoute({\n router,\n method,\n route,\n gatewayMiddleware,\n middlewares,\n }: AddGatewayRouteOptions): void {\n router[method](route, [...middlewares, gatewayMiddleware]);\n }\n /**\n * Formats the endpoints for the gateway into a flat dictionary without nesting.\n */\n protected _formatEndpoints(): Record<string, GatewayConfigEndpointDefinition> {\n return flat({\n target: this._gatewayConfig.gateway,\n shouldFlatten: (_, value) => {\n const useValue = value as { path?: string };\n return typeof useValue.path === 'undefined';\n },\n });\n }\n /**\n * Based on the information from the endpoints, this method will create the routes the\n * controller will later add on a router.\n *\n * @throws If there's more than one endpoint using the same path with the same HTTP\n * method.\n */\n protected _createRoutes(): GatewayControllerRoute[] {\n const routes: Record<\n string,\n {\n path: string;\n methods: Partial<Record<RouterMethod, string>>;\n }\n > = {};\n Object.keys(this._endpoints).forEach((name) => {\n const endpoint = this._endpoints[name]!;\n let endpointPath: string;\n let endpointMethod: RouterMethod;\n if (typeof endpoint === 'string') {\n endpointPath = endpoint;\n endpointMethod = 'all';\n } else {\n endpointPath = endpoint.path;\n endpointMethod = endpoint.method\n ? this._validateHTTPMethod(endpoint.method)\n : 'all';\n }\n\n endpointPath = removeSlashes(endpointPath);\n if (!routes[endpointPath]) {\n routes[endpointPath] = {\n path: endpointPath,\n methods: {},\n };\n }\n\n if (routes[endpointPath]!.methods[endpointMethod]) {\n const repeatedEndpoint = routes[endpointPath]!.methods[endpointMethod];\n throw new Error(\n \"You can't have two gateway endpoints to the same path and with the same \" +\n `HTTP method: '${repeatedEndpoint}' and '${name}'`,\n );\n }\n\n routes[endpointPath]!.methods[endpointMethod] = name;\n });\n\n const routePrefixes = this._options.root ? `/${this._options.root}/` : '/';\n return Object.keys(routes).map((endpointPath) => {\n const info = routes[endpointPath]!;\n return {\n path: info.path,\n route: `${routePrefixes}${info.path}`,\n methods: Object.keys(info.methods).map((methodNameRaw) => {\n const methodName = methodNameRaw as RouterMethod;\n const endpointName = info.methods[methodName]!;\n const endpointDefinition = this._endpoints[endpointName]!;\n return {\n method: methodName,\n endpoint: {\n name: endpointName,\n definition: endpointDefinition,\n },\n };\n }),\n };\n });\n }\n /**\n * This is a \"proxy method\" to call the helper service's function that can modify an\n * endpoint request before it gets made.\n *\n * The reason this is a \"proxy method\" is in case the controller gets subclassed and\n * \"used itself as a helper\" instead of relying on a difference one.\n *\n * If the helper doesn't implement `reduceEndpointRequest`, it will just return\n * information for the request.\n *\n * @param options The information of the request and the reference to the helper.\n */\n protected _reduceEndpointRequest({\n helper,\n ...options\n }: GatewayControllerHelperOptions<GatewayHelperServiceRequestReducerOptions>): Promise<GatewayControllerRequest> {\n if (helper.reduceEndpointRequest) {\n return helper.reduceEndpointRequest(options);\n }\n\n return Promise.resolve(options.endpointReq);\n }\n /**\n * This is a \"proxy method\" to call the helper service's function that can modify an\n * endpoint response before it gets processed.\n *\n * The reason this is a \"proxy method\" is in case the controller gets subclassed and\n * \"used itself as a helper\" instead of relying on a difference one.\n *\n * If the helper doesn't implement `reduceEndpointResponse`, it will just return\n * information for the response.\n *\n * @param options The information of the response and the reference to the helper.\n */\n protected _reduceEndpointResponse({\n helper,\n ...options\n }: GatewayControllerHelperOptions<GatewayHelperServiceResponseReducerOptions>): Promise<HTTPResponse> {\n if (helper.reduceEndpointResponse) {\n return helper.reduceEndpointResponse(options);\n }\n\n return Promise.resolve(options.endpointRes);\n }\n /**\n * This is a \"proxy method\" to call the helper service's function that can decide if an\n * endpoint response should be streamed or not.\n *\n * The reason this is a \"proxy method\" is in case the controller gets subclassed and\n * \"used itself as a helper\" instead of relying on a difference one.\n *\n * If the helper doesn't implement `shouldStreamEndpointResponse`, it will just return\n * `true`.\n *\n * @param options The information of the response and the reference to the helper.\n */\n protected _shouldStreamEndpointResponse({\n helper,\n ...options\n }: GatewayControllerHelperOptions<GatewayHelperServiceResponseReducerOptions>): Promise<boolean> {\n if (helper.shouldStreamEndpointResponse) {\n return helper.shouldStreamEndpointResponse(options);\n }\n\n return Promise.resolve(true);\n }\n /**\n * This is a \"proxy method\" to call the helper service's function that handles a\n * response in case it already said that a response shouldn't be streamed.\n *\n * The reason this is a \"proxy method\" is in case the controller gets subclassed and\n * \"used itself as a helper\" instead of relying on a difference one.\n *\n * If the helper doesn't implement `shouldStreamEndpointResponse`, it will throw an\n * error.\n *\n * @param options The information of the response and the reference to the helper.\n * @throws If the helper doesn't implement `handleEndpointResponse`.\n */\n protected _handleEndpointResponse({\n helper,\n ...options\n }: GatewayControllerHelperOptions<GatewayHelperServiceResponseReducerOptions>): Promise<void> {\n if (!helper.handleEndpointResponse) {\n throw new Error('You must implement handleEndpointResponse');\n }\n\n return helper.handleEndpointResponse(options);\n }\n /**\n * This is a \"proxy method\" to call the helper service's function that handles an error\n * on an endpoint request.\n *\n * The reason this is a \"proxy method\" is in case the controller gets subclassed and\n * \"used itself as a helper\" instead of relying on a difference one.\n *\n * If the helper doesn't implement `handleEndpointError`, it will just send the error to\n * the next middleware/error handler.\n *\n * @param options The information of the response and the reference to the helper.\n */\n protected _handleEndpointError({\n helper,\n ...options\n }: GatewayControllerHelperOptions<GatewayHelperServiceErrorHandlerOptions>): void {\n if (helper.handleEndpointError) {\n return helper.handleEndpointError(options);\n }\n\n return options.next(options.error);\n }\n /**\n * Validates and formats the customization options sent to the controller.\n *\n * @param options The options sent to the constructor.\n */\n protected _formatOptions(\n options: GatewayControllerExtraOptions,\n ): GatewayControllerExtraOptions {\n if (options.root) {\n const root = removeSlashes(options.root).trim();\n return { ...options, root };\n }\n\n return options;\n }\n /**\n * Validates a router/HTTP method that the controller intends to use for an endpoint. If\n * it's not valid, it will return `all`.\n *\n * @param method The HTTP method for the endpoint.\n */\n protected _validateHTTPMethod(method: string): RouterMethod {\n const newMethod = method.toLowerCase();\n return [\n 'get',\n 'head',\n 'post',\n 'patch',\n 'put',\n 'delete',\n 'connect',\n 'options',\n 'trace',\n ].includes(newMethod)\n ? (newMethod as RouterMethod)\n : 'all';\n }\n /**\n * Creates the API client configuration based on the controller routes.\n */\n protected _createAPIConfig(): GatewayControllerAPIConfig {\n let endpoints: APIClientOptions['endpoints'];\n const { root } = this._options;\n if (root) {\n endpoints = Object.keys(this._endpoints).reduce<\n Record<string, GatewayConfigEndpointDefinition>\n >((acc, name) => {\n const endpoint = this._endpoints[name]!;\n let newEndpoint;\n if (typeof endpoint === 'string') {\n newEndpoint = removeSlashes(endpoint);\n newEndpoint = `${root}/${newEndpoint}`;\n } else {\n const endpointPath = removeSlashes(endpoint.path);\n newEndpoint = {\n ...endpoint,\n path: `${root}/${endpointPath}`,\n };\n }\n\n acc[name] = newEndpoint;\n return acc;\n }, {});\n } else {\n endpoints = this._endpoints;\n }\n\n return {\n url: `/${this._route}`,\n endpoints: unflat({ target: endpoints }),\n };\n }\n}\n/**\n * A function to generate a list of middlewares that can be executed before the tontroller\n * main middleware.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerGetMiddlewaresFn = (app: Jimpex) => MiddlewareLike[];\n/**\n * The options for the controller creator that mounts the {@link GatewayController}.\n *\n * @group Controllers/Gateway\n */\nexport type GatewayControllerCreatorOptions =\n DeepPartial<GatewayControllerExtraOptions> & {\n /**\n * The name the creator will use to register the controller in the container. No,\n * this is not a typo. The creator will register the controller so other services can\n * access the `getAPIConfig` method. The service will be available after the app\n * routes are mounted.\n * If this is overwritten, the creator will ensure that the name ends with `Gateway`;\n * and if overwritten, but it doesn't include `Gateway` at the end, and no\n * `gatewaySettingName` was defined, the creator will use the custom name (without\n * `Gatway`) for `gatewaySettingName`.\n *\n * @default 'apiGateway'\n */\n serviceName?: string;\n /**\n * The name of the helper service the creator will try to obtain from the container.\n * If `serviceName` is overwritten, the default for this will be\n * `${serviceName}Helper`.\n *\n * @default 'apiGatewayHelper'\n */\n helperServiceName?: string;\n /**\n * The name of the configuration setting where the gateway configuration is stored. If\n * not overwritten, check the description of `serviceName` to understand which will be\n * its default value.\n *\n * @default 'api'\n */\n gatewaySettingName?: string;\n /**\n * The class the creator will instantiate. Similar to the API Client, this allows for\n * extra customization as you can send a custom subclass of the\n * {@link GatewayController}.\n *\n * @default GatewayController\n */\n gatewayClass?: typeof GatewayController;\n /**\n * A function to generate a list of middlewares that can be executed before the\n * controller main middleware.\n */\n getMiddlewares?: GatewayControllerGetMiddlewaresFn;\n };\n/**\n * Creates a controller that allows the application to mount routes that will work like\n * gateway to a specific API.\n *\n * @group Controllers\n * @group Controllers/Gateway\n */\nexport const gatewayController = controllerProviderCreator(\n (options: GatewayControllerCreatorOptions = {}) =>\n (app, route) => {\n /**\n * Formats the name in order to keep consistency with the helper service and the\n * configuration setting: If the `serviceName` is different from the default, make\n * sure it ends with `Gateway`, set the default helper service name to\n * `${serviceName}Helper`, and the default configuration setting to the same as the\n * service name (without the `Gateway`).\n * This way, if you just use `myApi`, the service name will be `myApiGateway`, the\n * helper name will be `myApiGatewayHelper` and the configuration setting `myApi`.\n */\n const defaultServiceName = 'apiGateway';\n let defaultHelperServiceName = 'apiGatewayHelper';\n let defaultConfigSetting = 'api';\n let { serviceName = defaultServiceName } = options;\n if (serviceName !== defaultServiceName) {\n defaultConfigSetting = serviceName;\n if (!serviceName.match(/gateway$/i)) {\n serviceName = `${serviceName}Gateway`;\n }\n defaultHelperServiceName = `${serviceName}Helper`;\n }\n // Register the service.\n app.set(serviceName, () => {\n const {\n helperServiceName = defaultHelperServiceName,\n gatewaySettingName = defaultConfigSetting,\n gatewayClass: GatewayClass = GatewayController,\n } = options;\n\n const gtConfig = app.getConfig<GatewayConfig>(gatewaySettingName);\n\n return new GatewayClass({\n ...options,\n apiConfigSetting: gatewaySettingName,\n gatewayConfig: gtConfig,\n route,\n inject: {\n http: app.get('http'),\n getHelperService: () => app.try(helperServiceName),\n },\n });\n });\n\n return controller(() => {\n // Get the controller.\n const ctrl = app.get<GatewayController>(serviceName);\n /**\n * Check if there are actual middlewares to be included, and in case there are\n * Jimpex middlewares, connect them.\n */\n let useMiddlewares: ExpressMiddleware[] | undefined;\n if (options.getMiddlewares) {\n useMiddlewares = options\n .getMiddlewares(app)\n .map((middleware) => {\n if ('middleware' in middleware) {\n return middleware.connect(app) as ExpressMiddleware | undefined;\n }\n\n return middleware as ExpressMiddleware;\n })\n .filter(notUndefined);\n }\n\n // Add the routes to the router and return it.\n return ctrl.addRoutes(app.get('router'), useMiddlewares);\n });\n },\n);\n"],"mappings":"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","names":[]}
|
package/dist/esm/app/jimpex.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
__publicField
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-V6TY7KAL.js";
|
|
4
4
|
import * as path from "path";
|
|
5
5
|
import fs from "fs/promises";
|
|
6
6
|
import { createServer as createHTTPSServer } from "https";
|
|
@@ -186,8 +186,7 @@ class Jimpex extends Jimple {
|
|
|
186
186
|
* Stops the server instance.
|
|
187
187
|
*/
|
|
188
188
|
stop() {
|
|
189
|
-
if (!this._instance)
|
|
190
|
-
return;
|
|
189
|
+
if (!this._instance) return;
|
|
191
190
|
this._emitEvent("beforeStop", { app: this });
|
|
192
191
|
this._instance.close();
|
|
193
192
|
this._instance = void 0;
|
|
@@ -213,8 +212,7 @@ class Jimpex extends Jimple {
|
|
|
213
212
|
}
|
|
214
213
|
this._mountQueue.push((server) => {
|
|
215
214
|
const connected = useController.connect(this, route);
|
|
216
|
-
if (!connected)
|
|
217
|
-
return;
|
|
215
|
+
if (!connected) return;
|
|
218
216
|
const router = this._reduceWithEvent("controllerWillBeMounted", connected, {
|
|
219
217
|
route,
|
|
220
218
|
controller: useController,
|
|
@@ -382,12 +380,9 @@ class Jimpex extends Jimple {
|
|
|
382
380
|
this.register(pathUtilsProvider);
|
|
383
381
|
this.register(rootFileProvider);
|
|
384
382
|
const { services: enabledServices } = this._options;
|
|
385
|
-
if (enabledServices.common)
|
|
386
|
-
|
|
387
|
-
if (enabledServices.
|
|
388
|
-
this.register(httpServicesProvider);
|
|
389
|
-
if (enabledServices.utils)
|
|
390
|
-
this.register(utilsServicesProvider);
|
|
383
|
+
if (enabledServices.common) this.register(commonServicesProvider);
|
|
384
|
+
if (enabledServices.http) this.register(httpServicesProvider);
|
|
385
|
+
if (enabledServices.utils) this.register(utilsServicesProvider);
|
|
391
386
|
this.set("events", () => new EventsHub());
|
|
392
387
|
this.set("statuses", () => statuses);
|
|
393
388
|
}
|
|
@@ -497,8 +492,7 @@ class Jimpex extends Jimple {
|
|
|
497
492
|
* This method is called just before starting the application.
|
|
498
493
|
*/
|
|
499
494
|
async _setupConfig() {
|
|
500
|
-
if (this._configReady)
|
|
501
|
-
return;
|
|
495
|
+
if (this._configReady) return;
|
|
502
496
|
this._configReady = true;
|
|
503
497
|
const { config: options } = this._options;
|
|
504
498
|
let configsPath = options.path.replace(/\/$/, "");
|
|
@@ -583,8 +577,7 @@ class Jimpex extends Jimple {
|
|
|
583
577
|
const info = await Promise.all(
|
|
584
578
|
keys.map(async (key) => {
|
|
585
579
|
const filepath = credentialsInfo[key];
|
|
586
|
-
if (!filepath)
|
|
587
|
-
return void 0;
|
|
580
|
+
if (!filepath) return void 0;
|
|
588
581
|
const file = await fs.readFile(pathUtils.joinFrom(location, filepath), "utf8");
|
|
589
582
|
return {
|
|
590
583
|
key,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/app/jimpex.ts"],"sourcesContent":["import * as path from 'path';\nimport fs from 'fs/promises';\nimport { createServer as createHTTPSServer } from 'https';\nimport { Jimple } from '@homer0/jimple';\nimport { deepAssignWithOverwrite } from '@homer0/deep-assign';\nimport { appLoggerProvider } from '@homer0/simple-logger';\nimport { envUtilsProvider } from '@homer0/env-utils';\nimport { packageInfoProvider } from '@homer0/package-info';\nimport { pathUtilsProvider } from '@homer0/path-utils';\nimport { rootFileProvider } from '@homer0/root-file';\nimport { tsAsyncImport } from '@homer0/ts-async-import';\nimport { EventsHub } from '@homer0/events-hub';\nimport { simpleConfigProvider } from '@homer0/simple-config';\nimport compression from 'compression';\nimport bodyParser from 'body-parser';\nimport multer from 'multer';\nimport {\n createServer as createSpdyServer,\n type ServerOptions as SpdyServerOptions,\n} from 'spdy';\nimport express from 'express';\nimport {\n commonServicesProvider,\n httpServicesProvider,\n utilsServicesProvider,\n} from '../services';\nimport {\n statuses,\n type Controller,\n type ControllerLike,\n type MiddlewareLike,\n type MiddlewareProvider,\n type Middleware,\n} from '../utils';\nimport type {\n DeepPartial,\n Express,\n ExpressMiddlewareLike,\n PathUtils,\n Config,\n Logger,\n JimpexOptions,\n JimpexHTTPSCredentials,\n JimpexHTTP2Options,\n JimpexHTTPSOptions,\n JimpexStartCallback,\n JimpexServer,\n JimpexServerInstance,\n JimpexEventName,\n JimpexEventPayload,\n DeepReadonly,\n JimpexReducerEventName,\n JimpexReducerEventPayload,\n JimpexReducerEventTarget,\n JimpexEventNameLike,\n JimpexEventListener,\n JimpexHealthCheckFn,\n Router,\n} from '../types';\n/**\n * Jimpex is a mix of Jimple, a Javascript port of Pimple dependency injection container,\n * and Express, one of the most popular web frameworks for Node.\n *\n * @group Jimpex\n * @todo Implement `helmet`.\n */\nexport class Jimpex extends Jimple {\n /**\n * The customization settings for the application.\n */\n protected _options: JimpexOptions;\n /**\n * The Express application Jimpex uses under the hood.\n */\n protected _express: Express;\n /**\n * Since the configuration service has an async initialization, the class uses this flag\n * internally to validate if the configuration has been initialized or not.\n */\n protected _configReady: boolean = false;\n /**\n * A reference to the actuall HTTP the application will use. This can vary depending on\n * whether HTTPS, or HTTP2 are enabled. If HTTPS is not enabled, it will be the same as\n * the `express` property; if HTTPS is enabled, it will be an `https` server; and if\n * HTTP2 is enabled, it will be an `spdy` server.\n */\n protected _server?: JimpexServer;\n /**\n * The instance of the server that is listening for requests.\n */\n protected _instance?: JimpexServerInstance;\n /**\n * A list of functions that implement controllers and middlewares. When the application\n * starts, the queue will be processed and those controllers and middlewares will be\n * added to the server instance. The reason they are not added directly like with a\n * regular Express implementation is that services on Jimple use lazy loading, and\n * adding middlewares and controllers as they come could cause errors if they depend on\n * services that are not yet registered.\n */\n protected _mountQueue: Array<(server: Express) => void> = [];\n /**\n * A list with all the top routes controlled by the application. Every time a controller\n * is mounted, its route will be added here.\n */\n protected _controlledRoutes: string[] = [];\n /**\n * @param options Preferences to customize the application.\n * @param config The default settings for the configuration service. It's a\n * shortcuit for `options.config.default`\n */\n constructor(options: DeepPartial<JimpexOptions> = {}, config: unknown = {}) {\n super();\n\n this._options = deepAssignWithOverwrite(\n {\n filesizeLimit: '15MB',\n boot: true,\n path: {\n appPath: '',\n useParentPath: true,\n },\n config: {\n default: options?.config?.default || config,\n name: 'app',\n path: 'config/',\n hasFolder: false,\n loadFromEnvironment: true,\n environmentVariable: 'CONFIG',\n defaultConfigFilename: '[app-name].config.js',\n filenameFormat: '[app-name].[config-name].config.js',\n },\n statics: {\n enabled: true,\n onHome: false,\n route: 'statics',\n },\n express: {\n trustProxy: true,\n disableXPoweredBy: true,\n compression: true,\n bodyParser: true,\n multer: true,\n },\n services: {\n common: true,\n http: true,\n utils: true,\n },\n healthCheck: () => Promise.resolve(true),\n },\n options,\n this._initOptions(),\n );\n\n this._express = express();\n\n this._setupCoreServices();\n this._setupExpress();\n this._configurePath();\n\n this._init();\n if (this._options.boot) {\n this.boot();\n }\n }\n /**\n * This is where the app would register all its specific services, middlewares and controllers.\n */\n boot(): void {}\n /**\n * Disables the server TLS validation. Meant to be used for development purposes.\n */\n disableTLSValidation() {\n // eslint-disable-next-line no-process-env, dot-notation\n process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';\n this.logger.warn('TLS validation has been disabled');\n }\n /**\n * Starts the app server.\n *\n * @param onStart A callback function to be called when the server actually starts.\n * @returns The server instance.\n */\n async start(onStart?: JimpexStartCallback): Promise<JimpexServerInstance> {\n await Promise.all([this._setupConfig(), this._loadESMModules()]);\n const config = this.getConfig();\n const port = config.get<number | undefined>('port');\n if (!port) {\n throw new Error('No port configured');\n }\n this._emitEvent('beforeStart', { app: this });\n this._server = await this._createServer();\n this._instance = this._server!.listen(port, () => {\n this._emitEvent('start', { app: this });\n this._mountResources();\n this.logger.success(`Starting on port ${port}`);\n this._emitEvent('afterStart', { app: this });\n if (onStart) {\n onStart(config);\n }\n this._emitEvent('afterStartCallback', { app: this });\n });\n\n return this._instance!;\n }\n /**\n * This is an alias of `start`. The idea is for it to be used on serverless platforms,\n * where you don't get to start your app, you just have export it.\n *\n * @param port In case the configuration doesn't already have it,\n * this is the port where the application will use to run. If this\n * parameter is used, the method will overwrite the `port`\n * setting on the configuration service.\n * @param onStart A callback function to be called when the server starts.\n * @returns The server instance.\n */\n async listen(\n port?: number,\n onStart?: JimpexStartCallback,\n ): Promise<JimpexServerInstance> {\n if (port) {\n await Promise.all([this._setupConfig(), this._loadESMModules()]);\n const config = this.getConfig();\n config.set('port', port);\n }\n\n return this.start(onStart);\n }\n /**\n * Stops the server instance.\n */\n stop(): void {\n if (!this._instance) return;\n this._emitEvent('beforeStop', { app: this });\n this._instance.close();\n this._instance = undefined;\n this._emitEvent('afterStop', { app: this });\n }\n /**\n * Mounts a route controller or a middleware into a server routes.\n *\n * @param route The route for the controller/middleware.\n * @param controller The controller/middleware resource to be mounted.\n */\n mount(route: string, controller: ControllerLike): void {\n let useController: Controller | Middleware;\n if (\n 'register' in controller &&\n typeof controller.register === 'function' &&\n controller.provider === true\n ) {\n useController = controller.register(this, route);\n } else if (\n 'connect' in controller &&\n typeof controller.connect === 'function' &&\n (('middleware' in controller && controller.middleware === true) ||\n ('controller' in controller && controller.controller === true))\n ) {\n useController = controller;\n } else {\n useController = {\n middleware: true,\n connect: () => controller as ExpressMiddlewareLike,\n };\n }\n\n this._mountQueue.push((server) => {\n const connected = useController.connect(this, route);\n if (!connected) return;\n const router = this._reduceWithEvent('controllerWillBeMounted', connected, {\n route,\n controller: useController,\n app: this,\n });\n server.use(route, router);\n this._emitEvent('routeAdded', { route, app: this });\n this._controlledRoutes.push(route);\n });\n }\n /**\n * Adds a global middleware to the application.\n *\n * @param middleware The middleware resource to be added.\n */\n use(middleware: MiddlewareLike): void {\n const useMiddleware =\n 'register' in middleware && typeof middleware.register === 'function'\n ? (middleware as MiddlewareProvider).register(this)\n : (middleware as Middleware | ExpressMiddlewareLike);\n this._mountQueue.push((server) => {\n if ('connect' in useMiddleware && typeof useMiddleware.connect === 'function') {\n const handler = useMiddleware.connect(this);\n if (handler) {\n server.use(\n this._reduceWithEvent('middlewareWillBeUsed', handler, { app: this }),\n );\n }\n\n return;\n }\n\n server.use(\n this._reduceWithEvent(\n 'middlewareWillBeUsed',\n useMiddleware as ExpressMiddlewareLike,\n { app: this },\n ),\n );\n });\n }\n\n getConfig(): Config;\n getConfig<T = unknown>(setting: string | string[], asArray?: boolean): T;\n /**\n * Gets a setting from the configuration, or the configuration itself.\n *\n * @param setting The setting or settings to be retrieved. If is not specified, it\n * will return the entire configuration.\n * @param asArray If `true` and `setting` is an array, it will return the values as\n * an array instead of an object.\n * @template T The type of the setting to be retrieved.\n */\n getConfig<T = unknown>(\n setting?: string | string[],\n asArray: boolean = false,\n ): Config | T {\n const config = this.try<Config>('config');\n if (!config) {\n throw new Error('The config service is not available until the app starts');\n }\n if (typeof setting === 'undefined') {\n return config;\n }\n\n return config.get<T>(setting, asArray);\n }\n /**\n * Creates a new router instance.\n */\n getRouter(): Router {\n return this.get('router');\n }\n /**\n * The logger service.\n */\n get logger(): Logger {\n return this.get<Logger>('logger');\n }\n /**\n * The Express application Jimpex uses under the hood.\n */\n get express(): Express {\n return this._express;\n }\n /**\n * The server instance that gets created when the app is started.\n */\n get instance(): JimpexServerInstance | undefined {\n return this._instance;\n }\n /**\n * The application customization options.\n */\n get options(): DeepReadonly<JimpexOptions> {\n return deepAssignWithOverwrite({}, this._options);\n }\n /**\n * Gets the events service.\n */\n get eventsHub(): EventsHub {\n return this.get<EventsHub>('events');\n }\n /**\n * A list of the routes that have controllers mounted on them.\n */\n get routes(): string[] {\n return this._controlledRoutes.slice();\n }\n /**\n * Adds a listener for an application event.\n *\n * @param eventName The name of the event to listen for.\n * @param listener The listener function.\n * @returns A function to unsubscribe the listener.\n * @template EventName The name of the event, to match the type of the listener\n * function.\n */\n on<EventName extends JimpexEventNameLike>(\n eventName: EventName,\n listener: JimpexEventListener<EventName>,\n ): () => boolean {\n return this.eventsHub.on(eventName, listener);\n }\n /**\n * Adds a listener for an application event that will only be execuded once: the first\n * time the event is triggered.\n *\n * @param eventName The name of the event to listen for.\n * @param listener The listener function.\n * @returns A function to unsubscribe the listener.\n * @template EventName The name of the event, to match the type of the listener\n * function.\n */\n once<EventName extends JimpexEventNameLike>(\n eventName: EventName,\n listener: JimpexEventListener<EventName>,\n ): () => boolean {\n return this.eventsHub.once(eventName, listener);\n }\n /**\n * Based on the application options, it returns wheter the application is healthy or\n * not.\n */\n isHealthy(): ReturnType<JimpexHealthCheckFn> {\n return this._options.healthCheck(this);\n }\n /**\n * This method is like a \"lifecycle method\", it gets executed on the constructor right\n * before the \"boot step\". The idea is for the method to be a helper when the\n * application is defined by subclassing {@link Jimpex}: the application could register\n * all important services here and the routes on boot, then, if the implementation needs\n * to access or overwrite a something, it can send `boot: false`, access/register what\n * it needs, and then call `boot()`. That would be impossible for an application without\n * overwriting the constructor and the boot functionality.\n */\n protected _init(): void {}\n /**\n * It generates overwrites for the application options when it gets created. This method\n * is a helper for when the application is defined by subclassing {@link Jimpex}: It's\n * highly probable that if the application needs to change the default options, it would\n * want to do it right from the class, instead of having to do it on every\n * implementation. A way to do it would be overwriting the constructor and calling\n * `super` with the custom overwrites, but this method exists so that won't be\n * necessary: when creating the `options`, the constructor will merge the result of this\n * method on top of the default ones.\n */\n protected _initOptions(): DeepPartial<JimpexOptions> {\n return {};\n }\n /**\n * Registers the \"core services\" on the container: logger, events, utils, etc.\n */\n protected _setupCoreServices(): void {\n this.register(\n appLoggerProvider({\n serviceName: 'logger',\n }),\n );\n this.register(envUtilsProvider);\n this.register(packageInfoProvider);\n this.register(pathUtilsProvider);\n this.register(rootFileProvider);\n const { services: enabledServices } = this._options;\n if (enabledServices.common) this.register(commonServicesProvider);\n if (enabledServices.http) this.register(httpServicesProvider);\n if (enabledServices.utils) this.register(utilsServicesProvider);\n\n this.set('events', () => new EventsHub());\n this.set('statuses', () => statuses);\n }\n /**\n * Configures the Express application based on the class options.\n */\n protected _setupExpress(): void {\n const { statics, filesizeLimit, express: expressOptions } = this._options;\n if (expressOptions.trustProxy) {\n this._express.enable('trust proxy');\n }\n\n if (expressOptions.disableXPoweredBy) {\n this._express.disable('x-powered-by');\n }\n\n if (expressOptions.compression) {\n this._express.use(compression());\n }\n\n if (statics.enabled) {\n this._addStaticsFolder(statics.route, statics.folder, statics.onHome);\n }\n\n if (expressOptions.bodyParser) {\n this._express.use(\n bodyParser.json({\n limit: filesizeLimit,\n }),\n );\n this._express.use(\n bodyParser.urlencoded({\n extended: true,\n limit: filesizeLimit,\n }),\n );\n }\n\n if (expressOptions.multer) {\n this._express.use(multer().any());\n }\n\n this.set(\n 'router',\n this.factory(() => express.Router()),\n );\n }\n /**\n * Adds a static folder to the application.\n *\n * @param route The route to add the folder to.\n * @param folder The path to the folder in the file system. If not defined, it will\n * be use the same value as `route`. The path could be relative to the\n * project root, or where the application executable is located,\n * depending on the value of the `onHome` parameter.\n * @param onHome If `true`, the path to the folder will be relative to the project\n * root. If `false`, it will be relative to where the application\n * executable is located.\n */\n protected _addStaticsFolder(\n route: string,\n folder: string = '',\n onHome: boolean = false,\n ) {\n const location = onHome ? 'home' : 'app';\n const staticRoute = route.replace(/^\\/+/, '');\n const pathUtils = this.get<PathUtils>('pathUtils');\n const staticFolder = pathUtils.joinFrom(location, folder || staticRoute);\n this.mount(`/${staticRoute}`, {\n connect: () => express.static(staticFolder),\n controller: true,\n });\n }\n /**\n * This helper method validates the `path` options in order to register the `app`\n * location in the `pathUtils` service. The `app` location should be the path to where\n * the application executable is located, but due to how ESM works, we can't infer it\n * from the `module` object, so we need either recieved as the `appPath` setting, or try\n * to get it from the parent module.\n *\n * @throws If the method should use the path from the parent module, but can't find\n * it.\n */\n protected _configurePath(): void {\n const pathUtils = this.get<PathUtils>('pathUtils');\n const {\n path: { appPath, useParentPath },\n } = this._options;\n if (appPath) {\n pathUtils.addLocation('app', appPath);\n return;\n }\n let foundPath = false;\n if (useParentPath) {\n const stack = new Error().stack!;\n const stackList = stack.split('\\n');\n stackList.shift();\n const parentFromStack = stackList.find((line) => !line.includes(__filename));\n if (parentFromStack) {\n const parentFile = parentFromStack.replace(/^.*?\\s\\(([^\\s]+):\\d+:\\d+\\)/, '$1');\n if (parentFile !== parentFromStack) {\n foundPath = true;\n pathUtils.addLocation('app', path.dirname(parentFile));\n }\n }\n }\n\n if (!foundPath) {\n throw new Error(\n 'The app location cannot be determined. Please specify the appPath option.',\n );\n }\n }\n /**\n * Setups the configuration service. The new configuration service requires async calls\n * in order to load the configuration files (as it uses `import` instead of `require`),\n * so it can't be instantiated as the other services.\n * This method is called just before starting the application.\n */\n protected async _setupConfig(): Promise<void> {\n if (this._configReady) return;\n this._configReady = true;\n const { config: options } = this._options;\n\n let configsPath = options.path.replace(/\\/$/, '');\n if (options.hasFolder) {\n configsPath = `${configsPath}${path.sep}${options.name}${path.sep}`;\n }\n\n const filenameFormat = options.filenameFormat\n .replace(/\\[app-name\\]/gi, options.name)\n .replace(/\\[config-name\\]/gi, '[name]');\n const defaultConfigFilename = options.defaultConfigFilename.replace(\n /\\[app-name\\]/gi,\n options.name,\n );\n\n this.register(\n simpleConfigProvider({\n name: options.name,\n defaultConfig: options.default,\n defaultConfigFilename,\n envVarName: options.environmentVariable,\n path: configsPath,\n filenameFormat,\n }),\n );\n\n const config = this.getConfig();\n await config.loadFromFile('', true, false);\n if (options.loadFromEnvironment) {\n await config.loadFromEnv();\n }\n }\n /**\n * Loads the ESM modules that are needed by Jimpex. This is called just before the starting\n * the application so they'll be available for all the services.\n */\n protected async _loadESMModules(): Promise<void> {\n const { default: nodeFetch } =\n await tsAsyncImport<typeof import('node-fetch')>('node-fetch');\n const { default: mime } = await tsAsyncImport<typeof import('mime')>('mime');\n\n this.set('node-fetch', () => nodeFetch);\n this.set('mime', () => mime);\n }\n /**\n * Processes the resources from the mount queue (added with {@link Jimpex.mount} and\n * {@link Jimpex.use}), and adds them to the Express application.\n */\n protected _mountResources(): void {\n this._mountQueue.forEach((mount) => mount(this._express));\n this._mountQueue.length = 0;\n }\n /**\n * Emits an event using the `events` service.\n *\n * @param name The name of the event to emit.\n * @param payload The event payload.\n * @template EventName The literal name of the event, to type the event payload.\n */\n protected _emitEvent<EventName extends JimpexEventName>(\n name: EventName,\n payload: JimpexEventPayload<EventName>,\n ): void {\n this.eventsHub.emit(name, payload);\n }\n /**\n * Sends a target object to a list of reducer events so they can modify or replace it.\n *\n * @param name The name of the event to use.\n * @param target The object to reduce with the event.\n * @param payload Extra context for the listeners.\n */\n protected _reduceWithEvent<EventName extends JimpexReducerEventName>(\n name: EventName,\n target: JimpexReducerEventTarget<EventName>,\n payload: JimpexReducerEventPayload<EventName>,\n ): JimpexReducerEventTarget<EventName> {\n return this.eventsHub.reduceSync(name, target, payload);\n }\n /**\n * Loads the contents of a dictionary of credentials files that need to be used to\n * configure HTTPS.\n *\n * @param credentialsInfo The dictionary where the keys are the type of credentials\n * (`ca`, `cert`, `key`) and the values are the paths to the\n * files.\n * @param onHome If this is `true`, the path of the files will be relative\n * to the project root. If it is `false`, it will be relative\n * to where the application executable is located.\n * @returns\n */\n protected async _loadCredentials(\n credentialsInfo: JimpexHTTPSCredentials,\n onHome: boolean = true,\n ): Promise<JimpexHTTPSCredentials> {\n const location = onHome ? 'home' : 'app';\n const pathUtils = this.get<PathUtils>('pathUtils');\n const keys: Array<keyof JimpexHTTPSCredentials> = ['ca', 'cert', 'key'];\n const info = await Promise.all(\n keys.map(async (key) => {\n const filepath = credentialsInfo[key];\n if (!filepath) return undefined;\n const file = await fs.readFile(pathUtils.joinFrom(location, filepath), 'utf8');\n return {\n key,\n file,\n };\n }),\n );\n\n return info.reduce<JimpexHTTPSCredentials>((acc, item) => {\n if (item) {\n acc[item.key] = item.file;\n }\n\n return acc;\n }, {});\n }\n /**\n * Validates the configuration and chooses the server the application needs to use: If\n * HTTP2 is enabled, it will use Spdy; if HTTPS is enabled but HTTP is not, it will use\n * the native HTTPS server; otherwise, it will be just the Express instance.\n *\n * @returns {Server}\n * @throws {Error} If HTTP2 is enabled but HTTPS is not.\n * @throws {Error} If HTTPS is enabled but there's no `https.credentials` object.\n * @throws {Error} If HTTPS is enabled and no creadentials are found.\n * @access protected\n * @ignore\n */\n protected async _createServer(): Promise<JimpexServer> {\n const [http2Config = {}, httpsConfig = {}] = this.getConfig<\n [JimpexHTTP2Options, JimpexHTTPSOptions]\n >(['http2', 'https'], true);\n\n if (!http2Config.enabled && !httpsConfig.enabled) {\n return this._express;\n }\n\n if (http2Config.enabled && !httpsConfig.enabled) {\n throw new Error('HTTP2 requires for HTTPS to be enabled');\n }\n\n if (!httpsConfig.credentials) {\n throw new Error('The `credentials` object on the HTTPS settings is missing');\n }\n\n const credentials = await this._loadCredentials(\n httpsConfig.credentials,\n httpsConfig.credentials.onHome,\n );\n\n if (!Object.keys(credentials).length) {\n throw new Error('No credentials were found for HTTPS');\n }\n\n if (http2Config.enabled) {\n const serverOptions: SpdyServerOptions = {\n ...credentials,\n spdy: http2Config.spdy,\n };\n\n return createSpdyServer(serverOptions, this._express);\n }\n\n return createHTTPSServer(credentials, this._express);\n }\n}\n/**\n * Shorthand for `new Jimpex()`.\n *\n * @param args The same parameters as the {@link Jimpex} constructor.\n * @returns A new instance of {@link Jimpex}.\n * @group Jimpex\n */\nexport const jimpex = (...args: ConstructorParameters<typeof Jimpex>): Jimpex =>\n new Jimpex(...args);\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/app/jimpex.ts"],"sourcesContent":["import * as path from 'path';\nimport fs from 'fs/promises';\nimport { createServer as createHTTPSServer } from 'https';\nimport { Jimple } from '@homer0/jimple';\nimport { deepAssignWithOverwrite } from '@homer0/deep-assign';\nimport { appLoggerProvider } from '@homer0/simple-logger';\nimport { envUtilsProvider } from '@homer0/env-utils';\nimport { packageInfoProvider } from '@homer0/package-info';\nimport { pathUtilsProvider } from '@homer0/path-utils';\nimport { rootFileProvider } from '@homer0/root-file';\nimport { tsAsyncImport } from '@homer0/ts-async-import';\nimport { EventsHub } from '@homer0/events-hub';\nimport { simpleConfigProvider } from '@homer0/simple-config';\nimport compression from 'compression';\nimport bodyParser from 'body-parser';\nimport multer from 'multer';\nimport {\n createServer as createSpdyServer,\n type ServerOptions as SpdyServerOptions,\n} from 'spdy';\nimport express from 'express';\nimport {\n commonServicesProvider,\n httpServicesProvider,\n utilsServicesProvider,\n} from '../services';\nimport {\n statuses,\n type Controller,\n type ControllerLike,\n type MiddlewareLike,\n type MiddlewareProvider,\n type Middleware,\n} from '../utils';\nimport type {\n DeepPartial,\n Express,\n ExpressMiddlewareLike,\n PathUtils,\n Config,\n Logger,\n JimpexOptions,\n JimpexHTTPSCredentials,\n JimpexHTTP2Options,\n JimpexHTTPSOptions,\n JimpexStartCallback,\n JimpexServer,\n JimpexServerInstance,\n JimpexEventName,\n JimpexEventPayload,\n DeepReadonly,\n JimpexReducerEventName,\n JimpexReducerEventPayload,\n JimpexReducerEventTarget,\n JimpexEventNameLike,\n JimpexEventListener,\n JimpexHealthCheckFn,\n Router,\n} from '../types';\n/**\n * Jimpex is a mix of Jimple, a Javascript port of Pimple dependency injection container,\n * and Express, one of the most popular web frameworks for Node.\n *\n * @group Jimpex\n * @todo Implement `helmet`.\n */\nexport class Jimpex extends Jimple {\n /**\n * The customization settings for the application.\n */\n protected _options: JimpexOptions;\n /**\n * The Express application Jimpex uses under the hood.\n */\n protected _express: Express;\n /**\n * Since the configuration service has an async initialization, the class uses this flag\n * internally to validate if the configuration has been initialized or not.\n */\n protected _configReady: boolean = false;\n /**\n * A reference to the actuall HTTP the application will use. This can vary depending on\n * whether HTTPS, or HTTP2 are enabled. If HTTPS is not enabled, it will be the same as\n * the `express` property; if HTTPS is enabled, it will be an `https` server; and if\n * HTTP2 is enabled, it will be an `spdy` server.\n */\n protected _server?: JimpexServer;\n /**\n * The instance of the server that is listening for requests.\n */\n protected _instance?: JimpexServerInstance;\n /**\n * A list of functions that implement controllers and middlewares. When the application\n * starts, the queue will be processed and those controllers and middlewares will be\n * added to the server instance. The reason they are not added directly like with a\n * regular Express implementation is that services on Jimple use lazy loading, and\n * adding middlewares and controllers as they come could cause errors if they depend on\n * services that are not yet registered.\n */\n protected _mountQueue: Array<(server: Express) => void> = [];\n /**\n * A list with all the top routes controlled by the application. Every time a controller\n * is mounted, its route will be added here.\n */\n protected _controlledRoutes: string[] = [];\n /**\n * @param options Preferences to customize the application.\n * @param config The default settings for the configuration service. It's a\n * shortcuit for `options.config.default`\n */\n constructor(options: DeepPartial<JimpexOptions> = {}, config: unknown = {}) {\n super();\n\n this._options = deepAssignWithOverwrite(\n {\n filesizeLimit: '15MB',\n boot: true,\n path: {\n appPath: '',\n useParentPath: true,\n },\n config: {\n default: options?.config?.default || config,\n name: 'app',\n path: 'config/',\n hasFolder: false,\n loadFromEnvironment: true,\n environmentVariable: 'CONFIG',\n defaultConfigFilename: '[app-name].config.js',\n filenameFormat: '[app-name].[config-name].config.js',\n },\n statics: {\n enabled: true,\n onHome: false,\n route: 'statics',\n },\n express: {\n trustProxy: true,\n disableXPoweredBy: true,\n compression: true,\n bodyParser: true,\n multer: true,\n },\n services: {\n common: true,\n http: true,\n utils: true,\n },\n healthCheck: () => Promise.resolve(true),\n },\n options,\n this._initOptions(),\n );\n\n this._express = express();\n\n this._setupCoreServices();\n this._setupExpress();\n this._configurePath();\n\n this._init();\n if (this._options.boot) {\n this.boot();\n }\n }\n /**\n * This is where the app would register all its specific services, middlewares and controllers.\n */\n boot(): void {}\n /**\n * Disables the server TLS validation. Meant to be used for development purposes.\n */\n disableTLSValidation() {\n // eslint-disable-next-line no-process-env, dot-notation\n process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';\n this.logger.warn('TLS validation has been disabled');\n }\n /**\n * Starts the app server.\n *\n * @param onStart A callback function to be called when the server actually starts.\n * @returns The server instance.\n */\n async start(onStart?: JimpexStartCallback): Promise<JimpexServerInstance> {\n await Promise.all([this._setupConfig(), this._loadESMModules()]);\n const config = this.getConfig();\n const port = config.get<number | undefined>('port');\n if (!port) {\n throw new Error('No port configured');\n }\n this._emitEvent('beforeStart', { app: this });\n this._server = await this._createServer();\n this._instance = this._server!.listen(port, () => {\n this._emitEvent('start', { app: this });\n this._mountResources();\n this.logger.success(`Starting on port ${port}`);\n this._emitEvent('afterStart', { app: this });\n if (onStart) {\n onStart(config);\n }\n this._emitEvent('afterStartCallback', { app: this });\n });\n\n return this._instance!;\n }\n /**\n * This is an alias of `start`. The idea is for it to be used on serverless platforms,\n * where you don't get to start your app, you just have export it.\n *\n * @param port In case the configuration doesn't already have it,\n * this is the port where the application will use to run. If this\n * parameter is used, the method will overwrite the `port`\n * setting on the configuration service.\n * @param onStart A callback function to be called when the server starts.\n * @returns The server instance.\n */\n async listen(\n port?: number,\n onStart?: JimpexStartCallback,\n ): Promise<JimpexServerInstance> {\n if (port) {\n await Promise.all([this._setupConfig(), this._loadESMModules()]);\n const config = this.getConfig();\n config.set('port', port);\n }\n\n return this.start(onStart);\n }\n /**\n * Stops the server instance.\n */\n stop(): void {\n if (!this._instance) return;\n this._emitEvent('beforeStop', { app: this });\n this._instance.close();\n this._instance = undefined;\n this._emitEvent('afterStop', { app: this });\n }\n /**\n * Mounts a route controller or a middleware into a server routes.\n *\n * @param route The route for the controller/middleware.\n * @param controller The controller/middleware resource to be mounted.\n */\n mount(route: string, controller: ControllerLike): void {\n let useController: Controller | Middleware;\n if (\n 'register' in controller &&\n typeof controller.register === 'function' &&\n controller.provider === true\n ) {\n useController = controller.register(this, route);\n } else if (\n 'connect' in controller &&\n typeof controller.connect === 'function' &&\n (('middleware' in controller && controller.middleware === true) ||\n ('controller' in controller && controller.controller === true))\n ) {\n useController = controller;\n } else {\n useController = {\n middleware: true,\n connect: () => controller as ExpressMiddlewareLike,\n };\n }\n\n this._mountQueue.push((server) => {\n const connected = useController.connect(this, route);\n if (!connected) return;\n const router = this._reduceWithEvent('controllerWillBeMounted', connected, {\n route,\n controller: useController,\n app: this,\n });\n server.use(route, router);\n this._emitEvent('routeAdded', { route, app: this });\n this._controlledRoutes.push(route);\n });\n }\n /**\n * Adds a global middleware to the application.\n *\n * @param middleware The middleware resource to be added.\n */\n use(middleware: MiddlewareLike): void {\n const useMiddleware =\n 'register' in middleware && typeof middleware.register === 'function'\n ? (middleware as MiddlewareProvider).register(this)\n : (middleware as Middleware | ExpressMiddlewareLike);\n this._mountQueue.push((server) => {\n if ('connect' in useMiddleware && typeof useMiddleware.connect === 'function') {\n const handler = useMiddleware.connect(this);\n if (handler) {\n server.use(\n this._reduceWithEvent('middlewareWillBeUsed', handler, { app: this }),\n );\n }\n\n return;\n }\n\n server.use(\n this._reduceWithEvent(\n 'middlewareWillBeUsed',\n useMiddleware as ExpressMiddlewareLike,\n { app: this },\n ),\n );\n });\n }\n\n getConfig(): Config;\n getConfig<T = unknown>(setting: string | string[], asArray?: boolean): T;\n /**\n * Gets a setting from the configuration, or the configuration itself.\n *\n * @param setting The setting or settings to be retrieved. If is not specified, it\n * will return the entire configuration.\n * @param asArray If `true` and `setting` is an array, it will return the values as\n * an array instead of an object.\n * @template T The type of the setting to be retrieved.\n */\n getConfig<T = unknown>(\n setting?: string | string[],\n asArray: boolean = false,\n ): Config | T {\n const config = this.try<Config>('config');\n if (!config) {\n throw new Error('The config service is not available until the app starts');\n }\n if (typeof setting === 'undefined') {\n return config;\n }\n\n return config.get<T>(setting, asArray);\n }\n /**\n * Creates a new router instance.\n */\n getRouter(): Router {\n return this.get('router');\n }\n /**\n * The logger service.\n */\n get logger(): Logger {\n return this.get<Logger>('logger');\n }\n /**\n * The Express application Jimpex uses under the hood.\n */\n get express(): Express {\n return this._express;\n }\n /**\n * The server instance that gets created when the app is started.\n */\n get instance(): JimpexServerInstance | undefined {\n return this._instance;\n }\n /**\n * The application customization options.\n */\n get options(): DeepReadonly<JimpexOptions> {\n return deepAssignWithOverwrite({}, this._options);\n }\n /**\n * Gets the events service.\n */\n get eventsHub(): EventsHub {\n return this.get<EventsHub>('events');\n }\n /**\n * A list of the routes that have controllers mounted on them.\n */\n get routes(): string[] {\n return this._controlledRoutes.slice();\n }\n /**\n * Adds a listener for an application event.\n *\n * @param eventName The name of the event to listen for.\n * @param listener The listener function.\n * @returns A function to unsubscribe the listener.\n * @template EventName The name of the event, to match the type of the listener\n * function.\n */\n on<EventName extends JimpexEventNameLike>(\n eventName: EventName,\n listener: JimpexEventListener<EventName>,\n ): () => boolean {\n return this.eventsHub.on(eventName, listener);\n }\n /**\n * Adds a listener for an application event that will only be execuded once: the first\n * time the event is triggered.\n *\n * @param eventName The name of the event to listen for.\n * @param listener The listener function.\n * @returns A function to unsubscribe the listener.\n * @template EventName The name of the event, to match the type of the listener\n * function.\n */\n once<EventName extends JimpexEventNameLike>(\n eventName: EventName,\n listener: JimpexEventListener<EventName>,\n ): () => boolean {\n return this.eventsHub.once(eventName, listener);\n }\n /**\n * Based on the application options, it returns wheter the application is healthy or\n * not.\n */\n isHealthy(): ReturnType<JimpexHealthCheckFn> {\n return this._options.healthCheck(this);\n }\n /**\n * This method is like a \"lifecycle method\", it gets executed on the constructor right\n * before the \"boot step\". The idea is for the method to be a helper when the\n * application is defined by subclassing {@link Jimpex}: the application could register\n * all important services here and the routes on boot, then, if the implementation needs\n * to access or overwrite a something, it can send `boot: false`, access/register what\n * it needs, and then call `boot()`. That would be impossible for an application without\n * overwriting the constructor and the boot functionality.\n */\n protected _init(): void {}\n /**\n * It generates overwrites for the application options when it gets created. This method\n * is a helper for when the application is defined by subclassing {@link Jimpex}: It's\n * highly probable that if the application needs to change the default options, it would\n * want to do it right from the class, instead of having to do it on every\n * implementation. A way to do it would be overwriting the constructor and calling\n * `super` with the custom overwrites, but this method exists so that won't be\n * necessary: when creating the `options`, the constructor will merge the result of this\n * method on top of the default ones.\n */\n protected _initOptions(): DeepPartial<JimpexOptions> {\n return {};\n }\n /**\n * Registers the \"core services\" on the container: logger, events, utils, etc.\n */\n protected _setupCoreServices(): void {\n this.register(\n appLoggerProvider({\n serviceName: 'logger',\n }),\n );\n this.register(envUtilsProvider);\n this.register(packageInfoProvider);\n this.register(pathUtilsProvider);\n this.register(rootFileProvider);\n const { services: enabledServices } = this._options;\n if (enabledServices.common) this.register(commonServicesProvider);\n if (enabledServices.http) this.register(httpServicesProvider);\n if (enabledServices.utils) this.register(utilsServicesProvider);\n\n this.set('events', () => new EventsHub());\n this.set('statuses', () => statuses);\n }\n /**\n * Configures the Express application based on the class options.\n */\n protected _setupExpress(): void {\n const { statics, filesizeLimit, express: expressOptions } = this._options;\n if (expressOptions.trustProxy) {\n this._express.enable('trust proxy');\n }\n\n if (expressOptions.disableXPoweredBy) {\n this._express.disable('x-powered-by');\n }\n\n if (expressOptions.compression) {\n this._express.use(compression());\n }\n\n if (statics.enabled) {\n this._addStaticsFolder(statics.route, statics.folder, statics.onHome);\n }\n\n if (expressOptions.bodyParser) {\n this._express.use(\n bodyParser.json({\n limit: filesizeLimit,\n }),\n );\n this._express.use(\n bodyParser.urlencoded({\n extended: true,\n limit: filesizeLimit,\n }),\n );\n }\n\n if (expressOptions.multer) {\n this._express.use(multer().any());\n }\n\n this.set(\n 'router',\n this.factory(() => express.Router()),\n );\n }\n /**\n * Adds a static folder to the application.\n *\n * @param route The route to add the folder to.\n * @param folder The path to the folder in the file system. If not defined, it will\n * be use the same value as `route`. The path could be relative to the\n * project root, or where the application executable is located,\n * depending on the value of the `onHome` parameter.\n * @param onHome If `true`, the path to the folder will be relative to the project\n * root. If `false`, it will be relative to where the application\n * executable is located.\n */\n protected _addStaticsFolder(\n route: string,\n folder: string = '',\n onHome: boolean = false,\n ) {\n const location = onHome ? 'home' : 'app';\n const staticRoute = route.replace(/^\\/+/, '');\n const pathUtils = this.get<PathUtils>('pathUtils');\n const staticFolder = pathUtils.joinFrom(location, folder || staticRoute);\n this.mount(`/${staticRoute}`, {\n connect: () => express.static(staticFolder),\n controller: true,\n });\n }\n /**\n * This helper method validates the `path` options in order to register the `app`\n * location in the `pathUtils` service. The `app` location should be the path to where\n * the application executable is located, but due to how ESM works, we can't infer it\n * from the `module` object, so we need either recieved as the `appPath` setting, or try\n * to get it from the parent module.\n *\n * @throws If the method should use the path from the parent module, but can't find\n * it.\n */\n protected _configurePath(): void {\n const pathUtils = this.get<PathUtils>('pathUtils');\n const {\n path: { appPath, useParentPath },\n } = this._options;\n if (appPath) {\n pathUtils.addLocation('app', appPath);\n return;\n }\n let foundPath = false;\n if (useParentPath) {\n const stack = new Error().stack!;\n const stackList = stack.split('\\n');\n stackList.shift();\n const parentFromStack = stackList.find((line) => !line.includes(__filename));\n if (parentFromStack) {\n const parentFile = parentFromStack.replace(/^.*?\\s\\(([^\\s]+):\\d+:\\d+\\)/, '$1');\n if (parentFile !== parentFromStack) {\n foundPath = true;\n pathUtils.addLocation('app', path.dirname(parentFile));\n }\n }\n }\n\n if (!foundPath) {\n throw new Error(\n 'The app location cannot be determined. Please specify the appPath option.',\n );\n }\n }\n /**\n * Setups the configuration service. The new configuration service requires async calls\n * in order to load the configuration files (as it uses `import` instead of `require`),\n * so it can't be instantiated as the other services.\n * This method is called just before starting the application.\n */\n protected async _setupConfig(): Promise<void> {\n if (this._configReady) return;\n this._configReady = true;\n const { config: options } = this._options;\n\n let configsPath = options.path.replace(/\\/$/, '');\n if (options.hasFolder) {\n configsPath = `${configsPath}${path.sep}${options.name}${path.sep}`;\n }\n\n const filenameFormat = options.filenameFormat\n .replace(/\\[app-name\\]/gi, options.name)\n .replace(/\\[config-name\\]/gi, '[name]');\n const defaultConfigFilename = options.defaultConfigFilename.replace(\n /\\[app-name\\]/gi,\n options.name,\n );\n\n this.register(\n simpleConfigProvider({\n name: options.name,\n defaultConfig: options.default,\n defaultConfigFilename,\n envVarName: options.environmentVariable,\n path: configsPath,\n filenameFormat,\n }),\n );\n\n const config = this.getConfig();\n await config.loadFromFile('', true, false);\n if (options.loadFromEnvironment) {\n await config.loadFromEnv();\n }\n }\n /**\n * Loads the ESM modules that are needed by Jimpex. This is called just before the starting\n * the application so they'll be available for all the services.\n */\n protected async _loadESMModules(): Promise<void> {\n const { default: nodeFetch } =\n await tsAsyncImport<typeof import('node-fetch')>('node-fetch');\n const { default: mime } = await tsAsyncImport<typeof import('mime')>('mime');\n\n this.set('node-fetch', () => nodeFetch);\n this.set('mime', () => mime);\n }\n /**\n * Processes the resources from the mount queue (added with {@link Jimpex.mount} and\n * {@link Jimpex.use}), and adds them to the Express application.\n */\n protected _mountResources(): void {\n this._mountQueue.forEach((mount) => mount(this._express));\n this._mountQueue.length = 0;\n }\n /**\n * Emits an event using the `events` service.\n *\n * @param name The name of the event to emit.\n * @param payload The event payload.\n * @template EventName The literal name of the event, to type the event payload.\n */\n protected _emitEvent<EventName extends JimpexEventName>(\n name: EventName,\n payload: JimpexEventPayload<EventName>,\n ): void {\n this.eventsHub.emit(name, payload);\n }\n /**\n * Sends a target object to a list of reducer events so they can modify or replace it.\n *\n * @param name The name of the event to use.\n * @param target The object to reduce with the event.\n * @param payload Extra context for the listeners.\n */\n protected _reduceWithEvent<EventName extends JimpexReducerEventName>(\n name: EventName,\n target: JimpexReducerEventTarget<EventName>,\n payload: JimpexReducerEventPayload<EventName>,\n ): JimpexReducerEventTarget<EventName> {\n return this.eventsHub.reduceSync(name, target, payload);\n }\n /**\n * Loads the contents of a dictionary of credentials files that need to be used to\n * configure HTTPS.\n *\n * @param credentialsInfo The dictionary where the keys are the type of credentials\n * (`ca`, `cert`, `key`) and the values are the paths to the\n * files.\n * @param onHome If this is `true`, the path of the files will be relative\n * to the project root. If it is `false`, it will be relative\n * to where the application executable is located.\n * @returns\n */\n protected async _loadCredentials(\n credentialsInfo: JimpexHTTPSCredentials,\n onHome: boolean = true,\n ): Promise<JimpexHTTPSCredentials> {\n const location = onHome ? 'home' : 'app';\n const pathUtils = this.get<PathUtils>('pathUtils');\n const keys: Array<keyof JimpexHTTPSCredentials> = ['ca', 'cert', 'key'];\n const info = await Promise.all(\n keys.map(async (key) => {\n const filepath = credentialsInfo[key];\n if (!filepath) return undefined;\n const file = await fs.readFile(pathUtils.joinFrom(location, filepath), 'utf8');\n return {\n key,\n file,\n };\n }),\n );\n\n return info.reduce<JimpexHTTPSCredentials>((acc, item) => {\n if (item) {\n acc[item.key] = item.file;\n }\n\n return acc;\n }, {});\n }\n /**\n * Validates the configuration and chooses the server the application needs to use: If\n * HTTP2 is enabled, it will use Spdy; if HTTPS is enabled but HTTP is not, it will use\n * the native HTTPS server; otherwise, it will be just the Express instance.\n *\n * @returns {Server}\n * @throws {Error} If HTTP2 is enabled but HTTPS is not.\n * @throws {Error} If HTTPS is enabled but there's no `https.credentials` object.\n * @throws {Error} If HTTPS is enabled and no creadentials are found.\n * @access protected\n * @ignore\n */\n protected async _createServer(): Promise<JimpexServer> {\n const [http2Config = {}, httpsConfig = {}] = this.getConfig<\n [JimpexHTTP2Options, JimpexHTTPSOptions]\n >(['http2', 'https'], true);\n\n if (!http2Config.enabled && !httpsConfig.enabled) {\n return this._express;\n }\n\n if (http2Config.enabled && !httpsConfig.enabled) {\n throw new Error('HTTP2 requires for HTTPS to be enabled');\n }\n\n if (!httpsConfig.credentials) {\n throw new Error('The `credentials` object on the HTTPS settings is missing');\n }\n\n const credentials = await this._loadCredentials(\n httpsConfig.credentials,\n httpsConfig.credentials.onHome,\n );\n\n if (!Object.keys(credentials).length) {\n throw new Error('No credentials were found for HTTPS');\n }\n\n if (http2Config.enabled) {\n const serverOptions: SpdyServerOptions = {\n ...credentials,\n spdy: http2Config.spdy,\n };\n\n return createSpdyServer(serverOptions, this._express);\n }\n\n return createHTTPSServer(credentials, this._express);\n }\n}\n/**\n * Shorthand for `new Jimpex()`.\n *\n * @param args The same parameters as the {@link Jimpex} constructor.\n * @returns A new instance of {@link Jimpex}.\n * @group Jimpex\n */\nexport const jimpex = (...args: ConstructorParameters<typeof Jimpex>): Jimpex =>\n new Jimpex(...args);\n"],"mappings":"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","names":[]}
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
-
var __publicField = (obj, key, value) =>
|
|
4
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
|
-
return value;
|
|
6
|
-
};
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
7
4
|
|
|
8
5
|
export {
|
|
9
6
|
__publicField
|
|
10
7
|
};
|
|
11
|
-
//# sourceMappingURL=chunk-
|
|
8
|
+
//# sourceMappingURL=chunk-V6TY7KAL.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
__publicField
|
|
3
|
-
} from "../../chunk-
|
|
3
|
+
} from "../../chunk-V6TY7KAL.js";
|
|
4
4
|
import { middlewareCreator } from "../../utils";
|
|
5
5
|
class ForceHTTPS {
|
|
6
6
|
/**
|
|
@@ -41,8 +41,7 @@ class ForceHTTPS {
|
|
|
41
41
|
const forceHTTPSMiddleware = middlewareCreator(
|
|
42
42
|
(options = {}) => (app) => {
|
|
43
43
|
const enabled = app.getConfig("forceHTTPS");
|
|
44
|
-
if (!enabled)
|
|
45
|
-
return void 0;
|
|
44
|
+
if (!enabled) return void 0;
|
|
46
45
|
return new ForceHTTPS(options).getMiddleware();
|
|
47
46
|
}
|
|
48
47
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/middlewares/common/forceHTTPS.ts"],"sourcesContent":["import { middlewareCreator } from '../../utils';\nimport { ExpressMiddleware } from '../../types';\n/**\n * The customization options for the middleware.\n *\n * @group Middlewares/ForceHTTPS\n */\nexport type ForceHTTPSOptions = {\n /**\n * A list of regular expressions to match routes that should be ignored.\n *\n * @default [/^\\/service\\//]\n */\n ignoredRoutes: RegExp[];\n};\n/**\n * A partial version of the {@link ForceHTTPSOptions}, to be used in the constructor and\n * the middleware creator.\n *\n * @group Middlewares/ForceHTTPS\n */\nexport type ForceHTTPSPartialOptions = Partial<ForceHTTPSOptions>;\n/**\n * Creates a middleware that forces all the traffic to be through HTTPS.\n *\n * @group Middleware Classes\n * @group Middlewares/ForceHTTPS\n * @prettierignore\n */\nexport class ForceHTTPS {\n /**\n * The customization options.\n */\n protected readonly _options: ForceHTTPSOptions;\n /**\n * @param options The options to construct the class.\n */\n constructor(options: ForceHTTPSPartialOptions = {}) {\n this._options = {\n ignoredRoutes: [/^\\/service\\//],\n ...options,\n };\n }\n /**\n * Generates the middleware that redirects the traffic.\n */\n getMiddleware(): ExpressMiddleware {\n return (req, res, next) => {\n if (\n !req.secure &&\n req.get('X-Forwarded-Proto') !== 'https' &&\n !this._options.ignoredRoutes.some((expression) =>\n expression.test(req.originalUrl),\n )\n ) {\n const host = req.get('Host');\n res.redirect(`https://${host}${req.url}`);\n } else {\n next();\n }\n };\n }\n /**\n * The customization options.\n */\n get options(): Readonly<ForceHTTPSOptions> {\n return { ...this._options };\n }\n}\n/**\n * Creates the middleware that redirects the traffic to HTTPS.\n *\n * @group Middlewares\n * @group Middlewares/ForceHTTPS\n */\nexport const forceHTTPSMiddleware = middlewareCreator(\n (options: ForceHTTPSPartialOptions = {}) =>\n (app) => {\n const enabled = app.getConfig<boolean | undefined>('forceHTTPS');\n if (!enabled) return undefined;\n return new ForceHTTPS(options).getMiddleware();\n },\n);\n"],"mappings":";;;AAAA,SAAS,yBAAyB;AA6B3B,MAAM,WAAW;AAAA;AAAA;AAAA;AAAA,EAQtB,YAAY,UAAoC,CAAC,GAAG;AAJpD;AAAA;AAAA;AAAA,wBAAmB;AAKjB,SAAK,WAAW;AAAA,MACd,eAAe,CAAC,cAAc;AAAA,MAC9B,GAAG;AAAA,IACL;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAIA,gBAAmC;AACjC,WAAO,CAAC,KAAK,KAAK,SAAS;AACzB,UACE,CAAC,IAAI,UACL,IAAI,IAAI,mBAAmB,MAAM,WACjC,CAAC,KAAK,SAAS,cAAc;AAAA,QAAK,CAAC,eACjC,WAAW,KAAK,IAAI,WAAW;AAAA,MACjC,GACA;AACA,cAAM,OAAO,IAAI,IAAI,MAAM;AAC3B,YAAI,SAAS,WAAW,IAAI,GAAG,IAAI,GAAG,EAAE;AAAA,MAC1C,OAAO;AACL,aAAK;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,UAAuC;AACzC,WAAO,EAAE,GAAG,KAAK,SAAS;AAAA,EAC5B;AACF;AAOO,MAAM,uBAAuB;AAAA,EAClC,CAAC,UAAoC,CAAC,MACpC,CAAC,QAAQ;AACP,UAAM,UAAU,IAAI,UAA+B,YAAY;AAC/D,QAAI,CAAC
|
|
1
|
+
{"version":3,"sources":["../../../../src/middlewares/common/forceHTTPS.ts"],"sourcesContent":["import { middlewareCreator } from '../../utils';\nimport { ExpressMiddleware } from '../../types';\n/**\n * The customization options for the middleware.\n *\n * @group Middlewares/ForceHTTPS\n */\nexport type ForceHTTPSOptions = {\n /**\n * A list of regular expressions to match routes that should be ignored.\n *\n * @default [/^\\/service\\//]\n */\n ignoredRoutes: RegExp[];\n};\n/**\n * A partial version of the {@link ForceHTTPSOptions}, to be used in the constructor and\n * the middleware creator.\n *\n * @group Middlewares/ForceHTTPS\n */\nexport type ForceHTTPSPartialOptions = Partial<ForceHTTPSOptions>;\n/**\n * Creates a middleware that forces all the traffic to be through HTTPS.\n *\n * @group Middleware Classes\n * @group Middlewares/ForceHTTPS\n * @prettierignore\n */\nexport class ForceHTTPS {\n /**\n * The customization options.\n */\n protected readonly _options: ForceHTTPSOptions;\n /**\n * @param options The options to construct the class.\n */\n constructor(options: ForceHTTPSPartialOptions = {}) {\n this._options = {\n ignoredRoutes: [/^\\/service\\//],\n ...options,\n };\n }\n /**\n * Generates the middleware that redirects the traffic.\n */\n getMiddleware(): ExpressMiddleware {\n return (req, res, next) => {\n if (\n !req.secure &&\n req.get('X-Forwarded-Proto') !== 'https' &&\n !this._options.ignoredRoutes.some((expression) =>\n expression.test(req.originalUrl),\n )\n ) {\n const host = req.get('Host');\n res.redirect(`https://${host}${req.url}`);\n } else {\n next();\n }\n };\n }\n /**\n * The customization options.\n */\n get options(): Readonly<ForceHTTPSOptions> {\n return { ...this._options };\n }\n}\n/**\n * Creates the middleware that redirects the traffic to HTTPS.\n *\n * @group Middlewares\n * @group Middlewares/ForceHTTPS\n */\nexport const forceHTTPSMiddleware = middlewareCreator(\n (options: ForceHTTPSPartialOptions = {}) =>\n (app) => {\n const enabled = app.getConfig<boolean | undefined>('forceHTTPS');\n if (!enabled) return undefined;\n return new ForceHTTPS(options).getMiddleware();\n },\n);\n"],"mappings":";;;AAAA,SAAS,yBAAyB;AA6B3B,MAAM,WAAW;AAAA;AAAA;AAAA;AAAA,EAQtB,YAAY,UAAoC,CAAC,GAAG;AAJpD;AAAA;AAAA;AAAA,wBAAmB;AAKjB,SAAK,WAAW;AAAA,MACd,eAAe,CAAC,cAAc;AAAA,MAC9B,GAAG;AAAA,IACL;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAIA,gBAAmC;AACjC,WAAO,CAAC,KAAK,KAAK,SAAS;AACzB,UACE,CAAC,IAAI,UACL,IAAI,IAAI,mBAAmB,MAAM,WACjC,CAAC,KAAK,SAAS,cAAc;AAAA,QAAK,CAAC,eACjC,WAAW,KAAK,IAAI,WAAW;AAAA,MACjC,GACA;AACA,cAAM,OAAO,IAAI,IAAI,MAAM;AAC3B,YAAI,SAAS,WAAW,IAAI,GAAG,IAAI,GAAG,EAAE;AAAA,MAC1C,OAAO;AACL,aAAK;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,UAAuC;AACzC,WAAO,EAAE,GAAG,KAAK,SAAS;AAAA,EAC5B;AACF;AAOO,MAAM,uBAAuB;AAAA,EAClC,CAAC,UAAoC,CAAC,MACpC,CAAC,QAAQ;AACP,UAAM,UAAU,IAAI,UAA+B,YAAY;AAC/D,QAAI,CAAC,QAAS,QAAO;AACrB,WAAO,IAAI,WAAW,OAAO,EAAE,cAAc;AAAA,EAC/C;AACJ;","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
__publicField
|
|
3
|
-
} from "../../chunk-
|
|
3
|
+
} from "../../chunk-V6TY7KAL.js";
|
|
4
4
|
import { createRouteExpression, middlewareCreator, removeSlashes } from "../../utils";
|
|
5
5
|
class FastHTML {
|
|
6
6
|
/**
|
|
@@ -116,8 +116,7 @@ class FastHTML {
|
|
|
116
116
|
(acc, route) => {
|
|
117
117
|
const [expressions, processed] = acc;
|
|
118
118
|
const clean = removeSlashes(route).trim();
|
|
119
|
-
if (!clean || processed.includes(clean))
|
|
120
|
-
return acc;
|
|
119
|
+
if (!clean || processed.includes(clean)) return acc;
|
|
121
120
|
expressions.push(createRouteExpression(clean));
|
|
122
121
|
processed.push(clean);
|
|
123
122
|
return acc;
|