jimpex 10.0.1 → 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.
Files changed (77) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/app/jimpex.js +8 -18
  3. package/dist/app/jimpex.js.map +1 -1
  4. package/dist/controllers/common/config.js +1 -4
  5. package/dist/controllers/common/config.js.map +1 -1
  6. package/dist/controllers/common/health.js +1 -4
  7. package/dist/controllers/common/health.js.map +1 -1
  8. package/dist/controllers/common/statics.js +1 -4
  9. package/dist/controllers/common/statics.js.map +1 -1
  10. package/dist/controllers/utils/gateway.js +1 -4
  11. package/dist/controllers/utils/gateway.js.map +1 -1
  12. package/dist/esm/app/jimpex.js +8 -15
  13. package/dist/esm/app/jimpex.js.map +1 -1
  14. package/dist/esm/{chunk-F3FYYIAV.js → chunk-V6TY7KAL.js} +2 -5
  15. package/dist/esm/controllers/common/config.js +1 -1
  16. package/dist/esm/controllers/common/health.js +1 -1
  17. package/dist/esm/controllers/common/statics.js +1 -1
  18. package/dist/esm/controllers/utils/gateway.js +1 -1
  19. package/dist/esm/middlewares/common/errorHandler.js +1 -1
  20. package/dist/esm/middlewares/common/forceHTTPS.js +2 -3
  21. package/dist/esm/middlewares/common/forceHTTPS.js.map +1 -1
  22. package/dist/esm/middlewares/common/hsts.js +1 -1
  23. package/dist/esm/middlewares/html/fastHTML.js +2 -3
  24. package/dist/esm/middlewares/html/fastHTML.js.map +1 -1
  25. package/dist/esm/middlewares/html/showHTML.js +1 -1
  26. package/dist/esm/middlewares/utils/versionValidator.js +1 -1
  27. package/dist/esm/services/common/appError.js +1 -1
  28. package/dist/esm/services/common/httpError.js +1 -1
  29. package/dist/esm/services/common/index.js +1 -1
  30. package/dist/esm/services/common/sendFile.js +1 -1
  31. package/dist/esm/services/frontend/frontendFs.js +1 -1
  32. package/dist/esm/services/frontend/index.js +1 -1
  33. package/dist/esm/services/html/htmlGenerator.js +3 -5
  34. package/dist/esm/services/html/htmlGenerator.js.map +1 -1
  35. package/dist/esm/services/html/index.js +1 -1
  36. package/dist/esm/services/http/apiClient.js +4 -7
  37. package/dist/esm/services/http/apiClient.js.map +1 -1
  38. package/dist/esm/services/http/http.js +1 -1
  39. package/dist/esm/services/http/index.js +1 -1
  40. package/dist/esm/services/http/responsesBuilder.js +2 -2
  41. package/dist/esm/services/http/responsesBuilder.js.map +1 -1
  42. package/dist/esm/services/utils/ensureBearerToken.js +1 -1
  43. package/dist/esm/services/utils/index.js +1 -1
  44. package/dist/esm/utils/fns/others.js +1 -1
  45. package/dist/esm/utils/fns/routes.js +1 -1
  46. package/dist/esm/utils/fns/statuses.js +1 -1
  47. package/dist/esm/utils/fns/text.js +1 -1
  48. package/dist/esm/utils/wrappers.js +1 -1
  49. package/dist/middlewares/common/errorHandler.js +1 -4
  50. package/dist/middlewares/common/errorHandler.js.map +1 -1
  51. package/dist/middlewares/common/forceHTTPS.js +2 -6
  52. package/dist/middlewares/common/forceHTTPS.js.map +1 -1
  53. package/dist/middlewares/common/hsts.js +1 -4
  54. package/dist/middlewares/common/hsts.js.map +1 -1
  55. package/dist/middlewares/html/fastHTML.js +2 -6
  56. package/dist/middlewares/html/fastHTML.js.map +1 -1
  57. package/dist/middlewares/html/showHTML.js +1 -4
  58. package/dist/middlewares/html/showHTML.js.map +1 -1
  59. package/dist/middlewares/utils/versionValidator.js +1 -4
  60. package/dist/middlewares/utils/versionValidator.js.map +1 -1
  61. package/dist/services/common/appError.js +1 -4
  62. package/dist/services/common/appError.js.map +1 -1
  63. package/dist/services/frontend/frontendFs.js +1 -4
  64. package/dist/services/frontend/frontendFs.js.map +1 -1
  65. package/dist/services/html/htmlGenerator.js +3 -8
  66. package/dist/services/html/htmlGenerator.js.map +1 -1
  67. package/dist/services/http/apiClient.js +4 -10
  68. package/dist/services/http/apiClient.js.map +1 -1
  69. package/dist/services/http/http.js +1 -4
  70. package/dist/services/http/http.js.map +1 -1
  71. package/dist/services/http/responsesBuilder.js +2 -5
  72. package/dist/services/http/responsesBuilder.js.map +1 -1
  73. package/dist/services/utils/ensureBearerToken.js +1 -4
  74. package/dist/services/utils/ensureBearerToken.js.map +1 -1
  75. package/package.json +39 -36
  76. package/src/services/http/responsesBuilder.ts +1 -1
  77. /package/dist/esm/{chunk-F3FYYIAV.js.map → chunk-V6TY7KAL.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/middlewares/html/fastHTML.ts"],"sourcesContent":["import { createRouteExpression, middlewareCreator, removeSlashes } from '../../utils';\nimport type { HTMLGenerator, SendFile } from '../../services';\nimport type { AsyncExpressMiddleware, Response, NextFunction, Events } from '../../types';\n/**\n * The options to customize the behavior of the middleware.\n *\n * @group Middlewares/FastHTML\n */\nexport type FastHTMLOptions = {\n /**\n * The name of the file the middleware will serve. If the {@link HTMLGenerator} service\n * is available, it will be overriden by the service.\n *\n * @default 'index.html'\n */\n file: string;\n /**\n * A list of regular expressions to match request paths that should be ignored by the\n * middleware.\n *\n * @default [/\\.ico$/i]\n */\n ignoredRoutes: RegExp[];\n /**\n * If `true`, {@link FastHTML} will get the list of all the routes controlled by the\n * application, and will use them to validate the incoming requests (in addition to the\n * `ignore` list): If a request URL doesn't match with any of the \"controlled routes\",\n * it will serve the HTML file.\n *\n * @default true\n */\n useAppRoutes: boolean;\n};\n/**\n * The options to construct a {@link FastHTML}.\n *\n * @group Middlewares/FastHTML\n */\nexport type FastHTMLConstructorOptions = Partial<FastHTMLOptions> & {\n /**\n * A dictionary with the dependencies to inject.\n */\n inject: {\n sendFile: SendFile;\n events: Events;\n /**\n * A function to get a possible {@link HTMLGenerator}. This is injected as a \"getter\"\n * to not interrupt the DIC \"lifecycle\": middlewares are initialized right when the\n * app starts, and injecting a reference would force the service to be initialized\n * too, even if a request is not being made.\n */\n getHTMLGenerator?: () => HTMLGenerator | undefined;\n };\n};\n/**\n * The options for the middleware creator that will mount an instance of {@link FastHTML}.\n *\n * @group Middlewares/FastHTML\n */\nexport type FastHTMLMiddlewareOptions = Partial<FastHTMLOptions> & {\n /**\n * The name of an {@link HTMLGenerator} service already available in the application.\n *\n * @default 'htmlGenerator'\n */\n htmlGeneratorServiceName?: string;\n};\n/**\n * It's common for an app to show an HTML view when no route was able to handle a request,\n * so the idea behind this middleware is to avoid going to every middleware and controller\n * and just specify that if the request is not for a route handled by a controller, just\n * serve the HTML and avoid processing unnecessary data.\n *\n * A simple example: The app has a route `/backend` that a frontend uses to get\n * information.\n * This middleware can be used to only allow the execution of middlewares and controllers\n * when the request route is for `/backend`.\n *\n * **Disclaimer**: Managing statics files with Express is not a best practice, but there\n * are scenarios where there is not other choice.\n *\n * @group Middleware Classes\n * @group Middlewares/FastHTML\n * @prettierignore\n */\nexport class FastHTML {\n /**\n * The service that serves a file.\n */\n protected readonly _sendFile: SendFile;\n /**\n * The application envent bus, to listen and get the list of \"controlled routes\" after\n * the application is started.\n */\n protected readonly _events: Events;\n /**\n * A function to get a possible {@link HTMLGenerator}. This is injected as a \"getter\"\n * to not interrupt the DIC \"lifecycle\": middlewares are initialized right when the\n * app starts, and injecting a reference would force the service to be initialized\n * too, even if a request is not being made.\n */\n protected readonly _getHTMLGenerator: () => HTMLGenerator | undefined;\n /**\n * The customization options for the middleware.\n */\n protected _options: FastHTMLOptions;\n /**\n * Whether or not the file is ready to be served. In case the middleware uses an\n * {@link HTMLGenerator} service, the file needs to be generated before being available,\n * and that's why this flag exists.\n */\n protected _fileReady: boolean = false;\n /**\n * A list of regular expression that match the routes controlled by the application.\n * This is in case the `useAppRoutes` option is set to `true`; when the application gets\n * started, an event listener will obtain all the top controlled routes, create regular\n * expressions, and save them on this property.\n */\n protected _routeExpressions: RegExp[] = [];\n /**\n * @param options The options to construct the class.\n * @throws If `ignoredRoutes` is empty and `useAppRoutes` is set to `false`.\n */\n constructor({ inject, ...options }: FastHTMLConstructorOptions) {\n this._sendFile = inject.sendFile;\n this._events = inject.events;\n this._getHTMLGenerator = inject.getHTMLGenerator || (() => undefined);\n this._options = {\n file: 'index.html',\n ignoredRoutes: [/\\.ico$/i],\n useAppRoutes: true,\n ...options,\n };\n\n if (!this._options.ignoredRoutes.length && !this._options.useAppRoutes) {\n throw new Error('You must provide either `ignoredRoutes` or `useAppRoutes`');\n }\n\n if (this._options.useAppRoutes) {\n this._setupEvents();\n }\n }\n /**\n * Generates the middleware that serves the HTML file.\n */\n getMiddleware(): AsyncExpressMiddleware {\n return async (req, res, next) => {\n // If the route should be ignored, move to the next middleware.\n if (this._shouldIgnoreRoute(req.originalUrl)) {\n next();\n return;\n }\n\n // If the file is ready to be served, serve it.\n if (this._fileReady) {\n this._sendResponse(res, next);\n return;\n }\n\n const htmlGenerator = this._getHTMLGenerator();\n // If there's no generator, switch the flag and just serve the file.\n if (!htmlGenerator) {\n this._fileReady = true;\n this._sendResponse(res, next);\n return;\n }\n\n try {\n // Wait for the HTML to be generated.\n await htmlGenerator.whenReady();\n // Update the local option.\n this._options.file = htmlGenerator.options.file;\n // Switch the flag and serve the file.\n this._fileReady = true;\n this._sendResponse(res, next);\n } catch (error) {\n next(error);\n }\n };\n }\n /**\n * The customization options.\n */\n get options(): Readonly<FastHTMLOptions> {\n return { ...this._options };\n }\n /**\n * Serves the HTML file to the response.\n *\n * @param res The response object generated by the application.\n * @param next The function to call the next middleware.\n */\n protected _sendResponse(res: Response, next: NextFunction): void {\n res.setHeader('Content-Type', 'text/html');\n this._sendFile({\n res,\n next,\n filepath: this._options.file,\n });\n }\n /**\n * Adds the event listener that obtains the list of \"controlled routes\" when\n * `useAppRoutes` is set to `true`.\n */\n protected _setupEvents() {\n this._events.once('afterStart', ({ app }) => {\n const [routeExpressions] = app.routes.reduce<[RegExp[], string[]]>(\n (acc, route) => {\n const [expressions, processed] = acc;\n const clean = removeSlashes(route).trim();\n if (!clean || processed.includes(clean)) return acc;\n expressions.push(createRouteExpression(clean));\n processed.push(clean);\n return acc;\n },\n [[], []],\n );\n this._routeExpressions.push(...routeExpressions);\n });\n }\n /**\n * Validates whether a route should be ignored or not. The method checks first against\n * the `ignore` option, and then against the list of \"controlled routes\" if\n * `useAppRoutes` is set to `true`.\n *\n * @param route The route to validate.\n */\n protected _shouldIgnoreRoute(route: string): boolean {\n return (\n this._options.ignoredRoutes.some((expression) => route.match(expression)) ||\n this._routeExpressions.some((expression) => route.match(expression))\n );\n }\n}\n/**\n * Creates the middleware that filters the routes and serves an HTML before the\n * application gets to evaluate whether there's a controller for the request or not.\n *\n * @group Middlewares\n * @group Middlewares/FastHTML\n */\nexport const fastHTMLMiddleware = middlewareCreator(\n (options: FastHTMLMiddlewareOptions = {}) =>\n (app) => {\n const { htmlGeneratorServiceName = 'htmlGenerator', ...rest } = options;\n return new FastHTML({\n inject: {\n events: app.get('events'),\n sendFile: app.get('sendFile'),\n getHTMLGenerator: () => app.try(htmlGeneratorServiceName),\n },\n ...rest,\n }).getMiddleware();\n },\n);\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/middlewares/html/fastHTML.ts"],"sourcesContent":["import { createRouteExpression, middlewareCreator, removeSlashes } from '../../utils';\nimport type { HTMLGenerator, SendFile } from '../../services';\nimport type { AsyncExpressMiddleware, Response, NextFunction, Events } from '../../types';\n/**\n * The options to customize the behavior of the middleware.\n *\n * @group Middlewares/FastHTML\n */\nexport type FastHTMLOptions = {\n /**\n * The name of the file the middleware will serve. If the {@link HTMLGenerator} service\n * is available, it will be overriden by the service.\n *\n * @default 'index.html'\n */\n file: string;\n /**\n * A list of regular expressions to match request paths that should be ignored by the\n * middleware.\n *\n * @default [/\\.ico$/i]\n */\n ignoredRoutes: RegExp[];\n /**\n * If `true`, {@link FastHTML} will get the list of all the routes controlled by the\n * application, and will use them to validate the incoming requests (in addition to the\n * `ignore` list): If a request URL doesn't match with any of the \"controlled routes\",\n * it will serve the HTML file.\n *\n * @default true\n */\n useAppRoutes: boolean;\n};\n/**\n * The options to construct a {@link FastHTML}.\n *\n * @group Middlewares/FastHTML\n */\nexport type FastHTMLConstructorOptions = Partial<FastHTMLOptions> & {\n /**\n * A dictionary with the dependencies to inject.\n */\n inject: {\n sendFile: SendFile;\n events: Events;\n /**\n * A function to get a possible {@link HTMLGenerator}. This is injected as a \"getter\"\n * to not interrupt the DIC \"lifecycle\": middlewares are initialized right when the\n * app starts, and injecting a reference would force the service to be initialized\n * too, even if a request is not being made.\n */\n getHTMLGenerator?: () => HTMLGenerator | undefined;\n };\n};\n/**\n * The options for the middleware creator that will mount an instance of {@link FastHTML}.\n *\n * @group Middlewares/FastHTML\n */\nexport type FastHTMLMiddlewareOptions = Partial<FastHTMLOptions> & {\n /**\n * The name of an {@link HTMLGenerator} service already available in the application.\n *\n * @default 'htmlGenerator'\n */\n htmlGeneratorServiceName?: string;\n};\n/**\n * It's common for an app to show an HTML view when no route was able to handle a request,\n * so the idea behind this middleware is to avoid going to every middleware and controller\n * and just specify that if the request is not for a route handled by a controller, just\n * serve the HTML and avoid processing unnecessary data.\n *\n * A simple example: The app has a route `/backend` that a frontend uses to get\n * information.\n * This middleware can be used to only allow the execution of middlewares and controllers\n * when the request route is for `/backend`.\n *\n * **Disclaimer**: Managing statics files with Express is not a best practice, but there\n * are scenarios where there is not other choice.\n *\n * @group Middleware Classes\n * @group Middlewares/FastHTML\n * @prettierignore\n */\nexport class FastHTML {\n /**\n * The service that serves a file.\n */\n protected readonly _sendFile: SendFile;\n /**\n * The application envent bus, to listen and get the list of \"controlled routes\" after\n * the application is started.\n */\n protected readonly _events: Events;\n /**\n * A function to get a possible {@link HTMLGenerator}. This is injected as a \"getter\"\n * to not interrupt the DIC \"lifecycle\": middlewares are initialized right when the\n * app starts, and injecting a reference would force the service to be initialized\n * too, even if a request is not being made.\n */\n protected readonly _getHTMLGenerator: () => HTMLGenerator | undefined;\n /**\n * The customization options for the middleware.\n */\n protected _options: FastHTMLOptions;\n /**\n * Whether or not the file is ready to be served. In case the middleware uses an\n * {@link HTMLGenerator} service, the file needs to be generated before being available,\n * and that's why this flag exists.\n */\n protected _fileReady: boolean = false;\n /**\n * A list of regular expression that match the routes controlled by the application.\n * This is in case the `useAppRoutes` option is set to `true`; when the application gets\n * started, an event listener will obtain all the top controlled routes, create regular\n * expressions, and save them on this property.\n */\n protected _routeExpressions: RegExp[] = [];\n /**\n * @param options The options to construct the class.\n * @throws If `ignoredRoutes` is empty and `useAppRoutes` is set to `false`.\n */\n constructor({ inject, ...options }: FastHTMLConstructorOptions) {\n this._sendFile = inject.sendFile;\n this._events = inject.events;\n this._getHTMLGenerator = inject.getHTMLGenerator || (() => undefined);\n this._options = {\n file: 'index.html',\n ignoredRoutes: [/\\.ico$/i],\n useAppRoutes: true,\n ...options,\n };\n\n if (!this._options.ignoredRoutes.length && !this._options.useAppRoutes) {\n throw new Error('You must provide either `ignoredRoutes` or `useAppRoutes`');\n }\n\n if (this._options.useAppRoutes) {\n this._setupEvents();\n }\n }\n /**\n * Generates the middleware that serves the HTML file.\n */\n getMiddleware(): AsyncExpressMiddleware {\n return async (req, res, next) => {\n // If the route should be ignored, move to the next middleware.\n if (this._shouldIgnoreRoute(req.originalUrl)) {\n next();\n return;\n }\n\n // If the file is ready to be served, serve it.\n if (this._fileReady) {\n this._sendResponse(res, next);\n return;\n }\n\n const htmlGenerator = this._getHTMLGenerator();\n // If there's no generator, switch the flag and just serve the file.\n if (!htmlGenerator) {\n this._fileReady = true;\n this._sendResponse(res, next);\n return;\n }\n\n try {\n // Wait for the HTML to be generated.\n await htmlGenerator.whenReady();\n // Update the local option.\n this._options.file = htmlGenerator.options.file;\n // Switch the flag and serve the file.\n this._fileReady = true;\n this._sendResponse(res, next);\n } catch (error) {\n next(error);\n }\n };\n }\n /**\n * The customization options.\n */\n get options(): Readonly<FastHTMLOptions> {\n return { ...this._options };\n }\n /**\n * Serves the HTML file to the response.\n *\n * @param res The response object generated by the application.\n * @param next The function to call the next middleware.\n */\n protected _sendResponse(res: Response, next: NextFunction): void {\n res.setHeader('Content-Type', 'text/html');\n this._sendFile({\n res,\n next,\n filepath: this._options.file,\n });\n }\n /**\n * Adds the event listener that obtains the list of \"controlled routes\" when\n * `useAppRoutes` is set to `true`.\n */\n protected _setupEvents() {\n this._events.once('afterStart', ({ app }) => {\n const [routeExpressions] = app.routes.reduce<[RegExp[], string[]]>(\n (acc, route) => {\n const [expressions, processed] = acc;\n const clean = removeSlashes(route).trim();\n if (!clean || processed.includes(clean)) return acc;\n expressions.push(createRouteExpression(clean));\n processed.push(clean);\n return acc;\n },\n [[], []],\n );\n this._routeExpressions.push(...routeExpressions);\n });\n }\n /**\n * Validates whether a route should be ignored or not. The method checks first against\n * the `ignore` option, and then against the list of \"controlled routes\" if\n * `useAppRoutes` is set to `true`.\n *\n * @param route The route to validate.\n */\n protected _shouldIgnoreRoute(route: string): boolean {\n return (\n this._options.ignoredRoutes.some((expression) => route.match(expression)) ||\n this._routeExpressions.some((expression) => route.match(expression))\n );\n }\n}\n/**\n * Creates the middleware that filters the routes and serves an HTML before the\n * application gets to evaluate whether there's a controller for the request or not.\n *\n * @group Middlewares\n * @group Middlewares/FastHTML\n */\nexport const fastHTMLMiddleware = middlewareCreator(\n (options: FastHTMLMiddlewareOptions = {}) =>\n (app) => {\n const { htmlGeneratorServiceName = 'htmlGenerator', ...rest } = options;\n return new FastHTML({\n inject: {\n events: app.get('events'),\n sendFile: app.get('sendFile'),\n getHTMLGenerator: () => app.try(htmlGeneratorServiceName),\n },\n ...rest,\n }).getMiddleware();\n },\n);\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  __publicField
3
- } from "../../chunk-F3FYYIAV.js";
3
+ } from "../../chunk-V6TY7KAL.js";
4
4
  import { middlewareCreator } from "../../utils";
5
5
  class ShowHTML {
6
6
  /**
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  __publicField
3
- } from "../../chunk-F3FYYIAV.js";
3
+ } from "../../chunk-V6TY7KAL.js";
4
4
  import { deepAssignWithOverwrite } from "@homer0/deep-assign";
5
5
  import { middlewareCreator } from "../../utils";
6
6
  class VersionValidator {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  __publicField
3
- } from "../../chunk-F3FYYIAV.js";
3
+ } from "../../chunk-V6TY7KAL.js";
4
4
  import { provider, statuses as statusesFn } from "../../utils";
5
5
  class AppError extends Error {
6
6
  /**
@@ -1,4 +1,4 @@
1
- import "../../chunk-F3FYYIAV.js";
1
+ import "../../chunk-V6TY7KAL.js";
2
2
  import { provider, statuses as statusesFn } from "../../utils";
3
3
  import { AppError } from "./appError";
4
4
  class HTTPError extends AppError {
@@ -1,4 +1,4 @@
1
- import "../../chunk-F3FYYIAV.js";
1
+ import "../../chunk-V6TY7KAL.js";
2
2
  import { providers } from "../../utils";
3
3
  import { appErrorProvider } from "./appError";
4
4
  import { httpErrorProvider } from "./httpError";
@@ -1,4 +1,4 @@
1
- import "../../chunk-F3FYYIAV.js";
1
+ import "../../chunk-V6TY7KAL.js";
2
2
  import { provider } from "../../utils";
3
3
  const sendFile = ({ inject: { pathUtils } }) => ({ res, filepath, from = "app", next = () => {
4
4
  } }) => {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  __publicField
3
- } from "../../chunk-F3FYYIAV.js";
3
+ } from "../../chunk-V6TY7KAL.js";
4
4
  import fs from "fs/promises";
5
5
  import { provider } from "../../utils";
6
6
  class FrontendFs {
@@ -1,4 +1,4 @@
1
- import "../../chunk-F3FYYIAV.js";
1
+ import "../../chunk-V6TY7KAL.js";
2
2
  import { providers } from "../../utils";
3
3
  import { frontendFsProvider } from "./frontendFs";
4
4
  const frontendServicesProvider = providers({
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  __publicField
3
- } from "../../chunk-F3FYYIAV.js";
3
+ } from "../../chunk-V6TY7KAL.js";
4
4
  import { get } from "@homer0/object-utils";
5
5
  import { deepAssignWithOverwrite } from "@homer0/deep-assign";
6
6
  import { deferred } from "@homer0/deferred";
@@ -77,10 +77,8 @@ class HTMLGenerator {
77
77
  * Generates the HTML file.
78
78
  */
79
79
  async generateHTML() {
80
- if (this._fileReady)
81
- return void 0;
82
- if (this._fileDeferred)
83
- return this._fileDeferred.promise;
80
+ if (this._fileReady) return void 0;
81
+ if (this._fileDeferred) return this._fileDeferred.promise;
84
82
  this._fileDeferred = deferred();
85
83
  const { template, deleteTemplateAfter, file, silent } = this._options;
86
84
  try {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/services/html/htmlGenerator.ts"],"sourcesContent":["import { get } from '@homer0/object-utils';\nimport { deepAssignWithOverwrite } from '@homer0/deep-assign';\nimport { deferred, type DeferredPromise } from '@homer0/deferred';\nimport { providerCreator } from '../../utils';\nimport type { Config, Logger } from '../../types';\nimport type { FrontendFs } from '../frontend';\n/**\n * The options to customize a {@link HTMLGenerator} instance.\n *\n * @group Services/HTMLGenerator\n */\nexport type HTMLGeneratorOptions = {\n /**\n * The name of the file it should use as template.\n *\n * @default 'index.tpl.html'\n */\n template: string;\n /**\n * The name of the generated file.\n *\n * @default 'index.html'\n */\n file: string;\n /**\n * If `true`, it won't log messages on the terminal when generating the file.\n *\n * @default false\n */\n silent: boolean;\n /**\n * Whether or not to delete the tempalte after generating the file.\n *\n * @default true\n */\n deleteTemplateAfter: boolean;\n /**\n * The placeholder string where the information will be written.\n *\n * @default /\\{\\{appConfi(?:guration)?\\}\\}/\n */\n replacePlaceholder: string | RegExp;\n /**\n * A regular expression for dynamic placeholders that will be replaced by values when\n * the file is generated.\n *\n * @default /\\{\\{(.*?)\\}\\}/gi\n */\n placeholderExpression: RegExp;\n /**\n * The name of the variable that will have the information on the file.\n *\n * @default 'appConfig'\n */\n variableName: string;\n /**\n * A list of settings from the app configuration that will be used as the information to\n * inject on the file.\n *\n * @default ['features', 'version', 'postMessagesPrefix']\n */\n configKeys: string[];\n};\n/**\n * An external service that can be used to provide the values the generator will replace\n * in the template.\n *\n * @group Services/HTMLGenerator\n */\nexport type HTMLGeneratorValuesService = {\n /**\n * A function that will be called to get the values to replace in the template.\n *\n * @param options The service customization options.\n */\n getValues: (options: HTMLGeneratorOptions) => Promise<Record<string, unknown>>;\n};\n/**\n * The options to construct a {@link HTMLGenerator}.\n *\n * @group Services/HTMLGenerator\n */\nexport type HTMLGeneratorConstructorOptions = Partial<HTMLGeneratorOptions> & {\n /**\n * A dictionary with the dependencies to inject.\n */\n inject: {\n config: Config;\n logger: Logger;\n frontendFs: FrontendFs;\n /**\n * A service that can provide the values to replace in the template. If specified, the\n * values from `configKeys` will be ignored.\n */\n valuesService?: HTMLGeneratorValuesService;\n };\n};\n/**\n * Custom options for the provider that will register an instance of {@link HTMLGenerator}\n * as a service.\n *\n * @group Services/HTMLGenerator\n */\nexport type HTMLGeneratorProviderOptions = Partial<HTMLGeneratorOptions> & {\n /**\n * The name that will be used to register the service on the container. This is to allow\n * multiple \"instances\" of the service to be created.\n *\n * @default 'htmlGenerator'\n */\n serviceName?: string;\n /**\n * The name of a service that the generator will use in order to read the values that\n * will be replaced on the template. If the service is available, the values from\n * `configKeys` will be ignored.\n *\n * @default 'htmlGeneratorValues'\n */\n valuesServiceName?: string;\n};\n/**\n * This is a utility service that generates an HTML file with custom information when the\n * application is started.\n *\n * @group Services\n * @group Services/HTMLGenerator\n */\nexport class HTMLGenerator {\n /**\n * The service customization options.\n */\n protected readonly _options: HTMLGeneratorOptions;\n /**\n * The application configuration service, to get the settings specified by the\n * `configKeys` option.\n */\n protected readonly _config: Config;\n /**\n * The service that logs messages on the terminal, in case the `silent` option is `false`.\n */\n protected readonly _logger: Logger;\n /**\n * The service that interacts with the filesystem.\n */\n protected readonly _frontendFs: FrontendFs;\n /**\n * A service that can provide values to be replaced in the template.\n */\n protected readonly _valuesService?: HTMLGeneratorValuesService;\n /**\n * Whether or not the file was already generated.\n */\n protected _fileReady: boolean = false;\n /**\n * A deferred promise to return when another service asks if the file has been\n * generated. Once this sevice finishes generating the file, the promise will be\n * resolved for all implementations that hold a reference to this deferred.\n */\n protected _fileDeferred?: DeferredPromise<void>;\n /**\n * @param options The options to construct the class.\n * @throws If `valuesService` is specified but it doesn't have a `getValues`\n * method.\n */\n constructor({\n inject: { config, logger, frontendFs, valuesService },\n ...options\n }: HTMLGeneratorConstructorOptions) {\n this._config = config;\n this._logger = logger;\n this._frontendFs = frontendFs;\n this._valuesService = valuesService;\n this._options = deepAssignWithOverwrite(\n {\n template: 'index.tpl.html',\n file: 'index.html',\n silent: false,\n deleteTemplateAfter: true,\n replacePlaceholder: /\\{\\{appConfig(?:uration)?\\}\\}/,\n placeholderExpression: /\\{\\{(.*?)\\}\\}/gi,\n variableName: 'appConfig',\n configKeys: ['features', 'version', 'postMessagesPrefix'],\n },\n options,\n );\n\n if (this._valuesService && typeof this._valuesService.getValues !== 'function') {\n throw new Error('The HTMLGenerator values service must have a `getValues` method');\n }\n }\n /**\n * Gets a promise that will be resolved when the file has been generated.\n */\n whenReady(): Promise<void> {\n return this._fileDeferred ? this._fileDeferred.promise : Promise.resolve();\n }\n /**\n * Generates the HTML file.\n */\n async generateHTML(): Promise<void> {\n // The file is already generated, and since this is async, return the promise.\n if (this._fileReady) return undefined;\n // If the file is not ready, but the deferred exists, return the reference to the promise.\n if (this._fileDeferred) return this._fileDeferred.promise;\n // Create the deferred promise.\n this._fileDeferred = deferred<void>();\n const { template, deleteTemplateAfter, file, silent } = this._options;\n try {\n // Get the template.\n const templateContents = await this._frontendFs.read(template);\n // Get the values to replace.\n const values = await this._getValues();\n // Replace/process the template.\n const html = this._processHTML(templateContents, values);\n // Write it in the filesystem.\n await this._frontendFs.write(file, html);\n if (!silent) {\n this._logger.success(`The HTML file was successfully generated (${file})`);\n }\n // Delete the template, if specified by the options.\n if (deleteTemplateAfter) {\n await this._frontendFs.delete(template);\n if (!silent) {\n this._logger.info(`The HTML template was successfully removed (${template})`);\n }\n }\n\n // Switch the flag, resolve the deferred promise, and delete it.\n this._fileReady = true;\n this._fileDeferred!.resolve();\n this._fileDeferred = undefined;\n return undefined;\n } catch (error) {\n this._fileDeferred!.reject(error);\n this._fileDeferred = undefined;\n if (!silent) {\n this._logger.error('There was an error while generating the HTML');\n }\n throw error;\n }\n }\n /**\n * Gets the customization options.\n */\n get options(): Readonly<HTMLGeneratorOptions> {\n return deepAssignWithOverwrite({}, this._options);\n }\n /**\n * Helper method to get the values that will be replaced in the template. If a \"values\n * service\" was specified in the constructor, it will get the values from there,\n * otherwise, it will use the `configKeys` option to get the values from the\n * application configuration.\n */\n protected _getValues(): Promise<Record<string, unknown>> {\n if (this._valuesService) {\n return this._valuesService.getValues(this._options);\n }\n\n const { configKeys } = this._options;\n if (configKeys && configKeys.length) {\n return Promise.resolve(this._config.get(configKeys));\n }\n\n return Promise.resolve({});\n }\n /**\n * Processes the HTML template by replacing the placeholders with the actual values.\n *\n * @param template The template for the HTML file.\n * @param values The values dictionary that should be replaced in the template.\n */\n protected _processHTML(template: string, values: Record<string, unknown>) {\n const { replacePlaceholder, placeholderExpression, variableName } = this._options;\n const htmlObject = JSON.stringify(values);\n let code = template.replace(\n replacePlaceholder,\n `window.${variableName} = ${htmlObject}`,\n );\n const matches: Array<{ string: string; value: string }> = [];\n let match = placeholderExpression.exec(code);\n while (match) {\n const [string, value] = match;\n if (string && value) {\n matches.push({\n string,\n value,\n });\n }\n\n match = placeholderExpression.exec(code);\n }\n\n matches.forEach((info) => {\n code = code.replace(info.string, String(get(values, info.value)));\n });\n\n return code;\n }\n}\n/**\n * The service provider that once registered on the container will set an instance of\n * {@link HTMLGenerator} as the `htmlGenerator` service. it will also hook itself to the\n * `after-start` event of the application in order to trigger the generator of the HTML\n * file.\n *\n * @example\n *\n * <caption>Basic usage</caption>\n *\n * // Register it on the container\n * container.register(htmlGeneratorProvider);\n * // Getting access to the service instance\n * const htmlGenerator = container.get<HTMLGenerator>('htmlGenerator');\n *\n * @example\n *\n * <caption>Using with custom options</caption>\n *\n * container.register(\n * htmlGeneratorProvider({\n * serviceName: 'myHtmlGenerator',\n * valuesServiceName: 'myValuesService',\n * template: 'my-template.tpl.html',\n * }),\n * );\n *\n * @group Providers\n * @group Services/HTMLGenerator\n */\nexport const htmlGeneratorProvider = providerCreator(\n (options: HTMLGeneratorProviderOptions = {}) =>\n (app) => {\n const {\n serviceName = 'htmlGenerator',\n valuesServiceName = 'htmlGeneratorValues',\n ...rest\n } = options;\n app.set(\n serviceName,\n () =>\n new HTMLGenerator({\n inject: {\n config: app.get('config'),\n logger: app.get('logger'),\n frontendFs: app.get('frontendFs'),\n valuesService: app.try(valuesServiceName),\n },\n ...rest,\n }),\n );\n\n app.once('afterStart', () => {\n app.get<HTMLGenerator>(serviceName).generateHTML();\n });\n },\n);\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/services/html/htmlGenerator.ts"],"sourcesContent":["import { get } from '@homer0/object-utils';\nimport { deepAssignWithOverwrite } from '@homer0/deep-assign';\nimport { deferred, type DeferredPromise } from '@homer0/deferred';\nimport { providerCreator } from '../../utils';\nimport type { Config, Logger } from '../../types';\nimport type { FrontendFs } from '../frontend';\n/**\n * The options to customize a {@link HTMLGenerator} instance.\n *\n * @group Services/HTMLGenerator\n */\nexport type HTMLGeneratorOptions = {\n /**\n * The name of the file it should use as template.\n *\n * @default 'index.tpl.html'\n */\n template: string;\n /**\n * The name of the generated file.\n *\n * @default 'index.html'\n */\n file: string;\n /**\n * If `true`, it won't log messages on the terminal when generating the file.\n *\n * @default false\n */\n silent: boolean;\n /**\n * Whether or not to delete the tempalte after generating the file.\n *\n * @default true\n */\n deleteTemplateAfter: boolean;\n /**\n * The placeholder string where the information will be written.\n *\n * @default /\\{\\{appConfi(?:guration)?\\}\\}/\n */\n replacePlaceholder: string | RegExp;\n /**\n * A regular expression for dynamic placeholders that will be replaced by values when\n * the file is generated.\n *\n * @default /\\{\\{(.*?)\\}\\}/gi\n */\n placeholderExpression: RegExp;\n /**\n * The name of the variable that will have the information on the file.\n *\n * @default 'appConfig'\n */\n variableName: string;\n /**\n * A list of settings from the app configuration that will be used as the information to\n * inject on the file.\n *\n * @default ['features', 'version', 'postMessagesPrefix']\n */\n configKeys: string[];\n};\n/**\n * An external service that can be used to provide the values the generator will replace\n * in the template.\n *\n * @group Services/HTMLGenerator\n */\nexport type HTMLGeneratorValuesService = {\n /**\n * A function that will be called to get the values to replace in the template.\n *\n * @param options The service customization options.\n */\n getValues: (options: HTMLGeneratorOptions) => Promise<Record<string, unknown>>;\n};\n/**\n * The options to construct a {@link HTMLGenerator}.\n *\n * @group Services/HTMLGenerator\n */\nexport type HTMLGeneratorConstructorOptions = Partial<HTMLGeneratorOptions> & {\n /**\n * A dictionary with the dependencies to inject.\n */\n inject: {\n config: Config;\n logger: Logger;\n frontendFs: FrontendFs;\n /**\n * A service that can provide the values to replace in the template. If specified, the\n * values from `configKeys` will be ignored.\n */\n valuesService?: HTMLGeneratorValuesService;\n };\n};\n/**\n * Custom options for the provider that will register an instance of {@link HTMLGenerator}\n * as a service.\n *\n * @group Services/HTMLGenerator\n */\nexport type HTMLGeneratorProviderOptions = Partial<HTMLGeneratorOptions> & {\n /**\n * The name that will be used to register the service on the container. This is to allow\n * multiple \"instances\" of the service to be created.\n *\n * @default 'htmlGenerator'\n */\n serviceName?: string;\n /**\n * The name of a service that the generator will use in order to read the values that\n * will be replaced on the template. If the service is available, the values from\n * `configKeys` will be ignored.\n *\n * @default 'htmlGeneratorValues'\n */\n valuesServiceName?: string;\n};\n/**\n * This is a utility service that generates an HTML file with custom information when the\n * application is started.\n *\n * @group Services\n * @group Services/HTMLGenerator\n */\nexport class HTMLGenerator {\n /**\n * The service customization options.\n */\n protected readonly _options: HTMLGeneratorOptions;\n /**\n * The application configuration service, to get the settings specified by the\n * `configKeys` option.\n */\n protected readonly _config: Config;\n /**\n * The service that logs messages on the terminal, in case the `silent` option is `false`.\n */\n protected readonly _logger: Logger;\n /**\n * The service that interacts with the filesystem.\n */\n protected readonly _frontendFs: FrontendFs;\n /**\n * A service that can provide values to be replaced in the template.\n */\n protected readonly _valuesService?: HTMLGeneratorValuesService;\n /**\n * Whether or not the file was already generated.\n */\n protected _fileReady: boolean = false;\n /**\n * A deferred promise to return when another service asks if the file has been\n * generated. Once this sevice finishes generating the file, the promise will be\n * resolved for all implementations that hold a reference to this deferred.\n */\n protected _fileDeferred?: DeferredPromise<void>;\n /**\n * @param options The options to construct the class.\n * @throws If `valuesService` is specified but it doesn't have a `getValues`\n * method.\n */\n constructor({\n inject: { config, logger, frontendFs, valuesService },\n ...options\n }: HTMLGeneratorConstructorOptions) {\n this._config = config;\n this._logger = logger;\n this._frontendFs = frontendFs;\n this._valuesService = valuesService;\n this._options = deepAssignWithOverwrite(\n {\n template: 'index.tpl.html',\n file: 'index.html',\n silent: false,\n deleteTemplateAfter: true,\n replacePlaceholder: /\\{\\{appConfig(?:uration)?\\}\\}/,\n placeholderExpression: /\\{\\{(.*?)\\}\\}/gi,\n variableName: 'appConfig',\n configKeys: ['features', 'version', 'postMessagesPrefix'],\n },\n options,\n );\n\n if (this._valuesService && typeof this._valuesService.getValues !== 'function') {\n throw new Error('The HTMLGenerator values service must have a `getValues` method');\n }\n }\n /**\n * Gets a promise that will be resolved when the file has been generated.\n */\n whenReady(): Promise<void> {\n return this._fileDeferred ? this._fileDeferred.promise : Promise.resolve();\n }\n /**\n * Generates the HTML file.\n */\n async generateHTML(): Promise<void> {\n // The file is already generated, and since this is async, return the promise.\n if (this._fileReady) return undefined;\n // If the file is not ready, but the deferred exists, return the reference to the promise.\n if (this._fileDeferred) return this._fileDeferred.promise;\n // Create the deferred promise.\n this._fileDeferred = deferred<void>();\n const { template, deleteTemplateAfter, file, silent } = this._options;\n try {\n // Get the template.\n const templateContents = await this._frontendFs.read(template);\n // Get the values to replace.\n const values = await this._getValues();\n // Replace/process the template.\n const html = this._processHTML(templateContents, values);\n // Write it in the filesystem.\n await this._frontendFs.write(file, html);\n if (!silent) {\n this._logger.success(`The HTML file was successfully generated (${file})`);\n }\n // Delete the template, if specified by the options.\n if (deleteTemplateAfter) {\n await this._frontendFs.delete(template);\n if (!silent) {\n this._logger.info(`The HTML template was successfully removed (${template})`);\n }\n }\n\n // Switch the flag, resolve the deferred promise, and delete it.\n this._fileReady = true;\n this._fileDeferred!.resolve();\n this._fileDeferred = undefined;\n return undefined;\n } catch (error) {\n this._fileDeferred!.reject(error);\n this._fileDeferred = undefined;\n if (!silent) {\n this._logger.error('There was an error while generating the HTML');\n }\n throw error;\n }\n }\n /**\n * Gets the customization options.\n */\n get options(): Readonly<HTMLGeneratorOptions> {\n return deepAssignWithOverwrite({}, this._options);\n }\n /**\n * Helper method to get the values that will be replaced in the template. If a \"values\n * service\" was specified in the constructor, it will get the values from there,\n * otherwise, it will use the `configKeys` option to get the values from the\n * application configuration.\n */\n protected _getValues(): Promise<Record<string, unknown>> {\n if (this._valuesService) {\n return this._valuesService.getValues(this._options);\n }\n\n const { configKeys } = this._options;\n if (configKeys && configKeys.length) {\n return Promise.resolve(this._config.get(configKeys));\n }\n\n return Promise.resolve({});\n }\n /**\n * Processes the HTML template by replacing the placeholders with the actual values.\n *\n * @param template The template for the HTML file.\n * @param values The values dictionary that should be replaced in the template.\n */\n protected _processHTML(template: string, values: Record<string, unknown>) {\n const { replacePlaceholder, placeholderExpression, variableName } = this._options;\n const htmlObject = JSON.stringify(values);\n let code = template.replace(\n replacePlaceholder,\n `window.${variableName} = ${htmlObject}`,\n );\n const matches: Array<{ string: string; value: string }> = [];\n let match = placeholderExpression.exec(code);\n while (match) {\n const [string, value] = match;\n if (string && value) {\n matches.push({\n string,\n value,\n });\n }\n\n match = placeholderExpression.exec(code);\n }\n\n matches.forEach((info) => {\n code = code.replace(info.string, String(get(values, info.value)));\n });\n\n return code;\n }\n}\n/**\n * The service provider that once registered on the container will set an instance of\n * {@link HTMLGenerator} as the `htmlGenerator` service. it will also hook itself to the\n * `after-start` event of the application in order to trigger the generator of the HTML\n * file.\n *\n * @example\n *\n * <caption>Basic usage</caption>\n *\n * // Register it on the container\n * container.register(htmlGeneratorProvider);\n * // Getting access to the service instance\n * const htmlGenerator = container.get<HTMLGenerator>('htmlGenerator');\n *\n * @example\n *\n * <caption>Using with custom options</caption>\n *\n * container.register(\n * htmlGeneratorProvider({\n * serviceName: 'myHtmlGenerator',\n * valuesServiceName: 'myValuesService',\n * template: 'my-template.tpl.html',\n * }),\n * );\n *\n * @group Providers\n * @group Services/HTMLGenerator\n */\nexport const htmlGeneratorProvider = providerCreator(\n (options: HTMLGeneratorProviderOptions = {}) =>\n (app) => {\n const {\n serviceName = 'htmlGenerator',\n valuesServiceName = 'htmlGeneratorValues',\n ...rest\n } = options;\n app.set(\n serviceName,\n () =>\n new HTMLGenerator({\n inject: {\n config: app.get('config'),\n logger: app.get('logger'),\n frontendFs: app.get('frontendFs'),\n valuesService: app.try(valuesServiceName),\n },\n ...rest,\n }),\n );\n\n app.once('afterStart', () => {\n app.get<HTMLGenerator>(serviceName).generateHTML();\n });\n },\n);\n"],"mappings":"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","names":[]}
@@ -1,4 +1,4 @@
1
- import "../../chunk-F3FYYIAV.js";
1
+ import "../../chunk-V6TY7KAL.js";
2
2
  import { providers } from "../../utils";
3
3
  import { htmlGeneratorProvider } from "./htmlGenerator";
4
4
  const htmlServicesProvider = providers({
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  __publicField
3
- } from "../../chunk-F3FYYIAV.js";
3
+ } from "../../chunk-V6TY7KAL.js";
4
4
  import {
5
5
  APIClient as APIClientBase
6
6
  } from "@homer0/api-utils";
@@ -50,13 +50,10 @@ class APIClient extends APIClientBase {
50
50
  */
51
51
  _getErrorMessageFromResponse(response) {
52
52
  const res = response;
53
- if (res.error)
54
- return res.error;
53
+ if (res.error) return res.error;
55
54
  if (res.data) {
56
- if (res.data.message)
57
- return res.data.message;
58
- if (res.data.error)
59
- return res.data.error;
55
+ if (res.data.message) return res.data.message;
56
+ if (res.data.error) return res.data.error;
60
57
  }
61
58
  return "Unexpected error";
62
59
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/services/http/apiClient.ts"],"sourcesContent":["import {\n APIClient as APIClientBase,\n type ErrorResponse,\n type APIClientOptions,\n type FetchClient,\n} from '@homer0/api-utils';\nimport { deepAssignWithOverwrite } from '@homer0/deep-assign';\nimport { providerCreator } from '../../utils';\nimport type { HTTP } from './http';\nimport type { HTTPErrorClass } from '../common';\n\nexport type { ErrorResponse };\n/**\n * The required settings needed to create the an API client.\n *\n * @group Services/APIClient\n */\nexport type APIClientConfig = Pick<APIClientOptions, 'url' | 'endpoints'>;\n/**\n * A dictionary of endpoints for the API client.\n * This is declared as standalone because it needs to reference them multiple times.\n *\n * @group Services/APIClient\n */\nexport type EndpointsType = APIClientOptions['endpoints'];\n/**\n * The format the settings needs to have in the application configuration in order to\n * create a valid API client.\n * The settings may include the endpoints dictionary in the `endpoints` property, or the\n * gateway `property`, with `endpoints` always having priority if both exists.\n * The reason for the `gateway` property to be valid, is in case the application also\n * implements a {@link GatewayController}, using the same property for both things will\n * help reduce the amount of duplicated definitions.\n *\n * @group Services/APIClient\n */\nexport type APIClientSettings = Omit<APIClientConfig, 'endpoints'> &\n (\n | {\n endpoints: EndpointsType;\n gateway?: EndpointsType;\n }\n | {\n endpoints?: EndpointsType;\n gateway: EndpointsType;\n }\n );\n/**\n * The options to construct a {@link APIClient}.\n *\n * @group Services/APIClient\n */\nexport type APIClientConstructorOptions = APIClientSettings & {\n /**\n * A dictionary with the dependencies to inject.\n */\n inject: {\n http: HTTP;\n HTTPError: HTTPErrorClass;\n };\n};\n/**\n * An API client for the application to use. What makes this service special is that it\n * formats received errors using the {@link _HTTPError} class, and as fetch client, it\n * uses the {@link HTTP} service, allowing the application to to internally handle all the\n * requests and responses.\n *\n * The only reason to use the class directly is if you want to subclass it, as you would\n * normally just register the {@link apiClientProvider}.\n *\n * @group Services\n * @group Services/APIClient\n */\nexport class APIClient extends APIClientBase {\n /**\n * The service that makes the requests to the API.\n */\n protected readonly _http: HTTP;\n /**\n * The class to generate possible errors in the requests.\n */\n protected readonly _HTTPError: HTTPErrorClass;\n /**\n * The configuration of the API it uses.\n */\n protected readonly _apiConfig: APIClientConfig;\n /**\n * @param options The options to construct the class.\n */\n constructor({ inject: { http, HTTPError }, ...rest }: APIClientConstructorOptions) {\n const { endpoints, gateway, url } = rest;\n const useEndpoints = (endpoints || gateway)!;\n const apiConfig = {\n url,\n endpoints: useEndpoints,\n };\n super({\n ...apiConfig,\n fetchClient: http.fetch as unknown as FetchClient,\n });\n\n this._http = http;\n this._HTTPError = HTTPError;\n this._apiConfig = deepAssignWithOverwrite({}, apiConfig);\n }\n /**\n * The configuration for the API.\n */\n get apiConfig(): Readonly<APIClientConfig> {\n return deepAssignWithOverwrite({}, this._apiConfig);\n }\n /**\n * Tries to obtain a message from an error caused on a failed request.\n *\n * @param response The response from the failed request.\n */\n protected _getErrorMessageFromResponse(response: unknown) {\n const res = response as {\n error?: string;\n data?: {\n message?: string;\n error?: string;\n };\n };\n if (res.error) return res.error;\n if (res.data) {\n if (res.data.message) return res.data.message;\n if (res.data.error) return res.data.error;\n }\n\n return 'Unexpected error';\n }\n /**\n * Generates an {@link _HTTPError} from the response of a failed request.\n *\n * @param response The response from the failed request.\n * @param status The status code of the response.\n */\n protected override formatError<ResponseType extends ErrorResponse>(\n response: ResponseType,\n status: number,\n ): Error {\n return new this._HTTPError(this._getErrorMessageFromResponse(response), status);\n }\n}\n/**\n * The options for the provider creator that registers an {@link APIClient} in the\n * container.\n * These options allow the application to register multiple instances for different APIs.\n *\n * @group Services/APIClient\n */\nexport type APIClientProviderOptions = {\n /**\n * The name of the service that will be registered into the app.\n *\n * @default 'apiClient'\n */\n serviceName?: string;\n /**\n * The name of the configuration setting that has the API information.\n *\n * @default 'api'\n */\n configSetting?: string;\n /**\n * The class the service will instantiate. It has to extend {@link APIClient}.\n *\n * @default APIClient\n */\n clientClass?: typeof APIClient;\n};\n/**\n * The provider creator to register an instance of {@link APIClient} on the container.\n *\n * @example\n *\n * <caption>Basic usage</caption>\n *\n * // Register it on the container\n * container.register(apiClientProvider);\n * // Getting access to the service instance\n * const apiClient = container.get<APIClient>('apiClient');\n *\n * @example\n *\n * <caption>With custom options</caption>\n *\n * container.register(\n * apiClientProvider({\n * serviceName: 'myApiClient',\n * configSetting: 'myApi',\n * }),\n * );\n *\n * @group Providers\n * @group Services/APIClient\n */\nexport const apiClientProvider = providerCreator(\n (options: APIClientProviderOptions = {}) =>\n (app) => {\n const defaultName = 'apiClient';\n const { serviceName = defaultName, clientClass: ClientClass = APIClient } = options;\n let { configSetting } = options;\n if (!configSetting) {\n configSetting = serviceName === defaultName ? 'api' : serviceName;\n }\n\n app.set(\n serviceName,\n () =>\n new ClientClass({\n inject: {\n http: app.get('http'),\n HTTPError: app.get('HTTPError'),\n },\n ...app.getConfig<APIClientSettings>(configSetting!),\n }),\n );\n },\n);\n"],"mappings":";;;AAAA;AAAA,EACE,aAAa;AAAA,OAIR;AACP,SAAS,+BAA+B;AACxC,SAAS,uBAAuB;AAkEzB,MAAM,kBAAkB,cAAc;AAAA;AAAA;AAAA;AAAA,EAgB3C,YAAY,EAAE,QAAQ,EAAE,MAAM,UAAU,GAAG,GAAG,KAAK,GAAgC;AACjF,UAAM,EAAE,WAAW,SAAS,IAAI,IAAI;AACpC,UAAM,eAAgB,aAAa;AACnC,UAAM,YAAY;AAAA,MAChB;AAAA,MACA,WAAW;AAAA,IACb;AACA,UAAM;AAAA,MACJ,GAAG;AAAA,MACH,aAAa,KAAK;AAAA,IACpB,CAAC;AAtBH;AAAA;AAAA;AAAA,wBAAmB;AAInB;AAAA;AAAA;AAAA,wBAAmB;AAInB;AAAA;AAAA;AAAA,wBAAmB;AAgBjB,SAAK,QAAQ;AACb,SAAK,aAAa;AAClB,SAAK,aAAa,wBAAwB,CAAC,GAAG,SAAS;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,YAAuC;AACzC,WAAO,wBAAwB,CAAC,GAAG,KAAK,UAAU;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,6BAA6B,UAAmB;AACxD,UAAM,MAAM;AAOZ,QAAI,IAAI;AAAO,aAAO,IAAI;AAC1B,QAAI,IAAI,MAAM;AACZ,UAAI,IAAI,KAAK;AAAS,eAAO,IAAI,KAAK;AACtC,UAAI,IAAI,KAAK;AAAO,eAAO,IAAI,KAAK;AAAA,IACtC;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOmB,YACjB,UACA,QACO;AACP,WAAO,IAAI,KAAK,WAAW,KAAK,6BAA6B,QAAQ,GAAG,MAAM;AAAA,EAChF;AACF;AAsDO,MAAM,oBAAoB;AAAA,EAC/B,CAAC,UAAoC,CAAC,MACpC,CAAC,QAAQ;AACP,UAAM,cAAc;AACpB,UAAM,EAAE,cAAc,aAAa,aAAa,cAAc,UAAU,IAAI;AAC5E,QAAI,EAAE,cAAc,IAAI;AACxB,QAAI,CAAC,eAAe;AAClB,sBAAgB,gBAAgB,cAAc,QAAQ;AAAA,IACxD;AAEA,QAAI;AAAA,MACF;AAAA,MACA,MACE,IAAI,YAAY;AAAA,QACd,QAAQ;AAAA,UACN,MAAM,IAAI,IAAI,MAAM;AAAA,UACpB,WAAW,IAAI,IAAI,WAAW;AAAA,QAChC;AAAA,QACA,GAAG,IAAI,UAA6B,aAAc;AAAA,MACpD,CAAC;AAAA,IACL;AAAA,EACF;AACJ;","names":[]}
1
+ {"version":3,"sources":["../../../../src/services/http/apiClient.ts"],"sourcesContent":["import {\n APIClient as APIClientBase,\n type ErrorResponse,\n type APIClientOptions,\n type FetchClient,\n} from '@homer0/api-utils';\nimport { deepAssignWithOverwrite } from '@homer0/deep-assign';\nimport { providerCreator } from '../../utils';\nimport type { HTTP } from './http';\nimport type { HTTPErrorClass } from '../common';\n\nexport type { ErrorResponse };\n/**\n * The required settings needed to create the an API client.\n *\n * @group Services/APIClient\n */\nexport type APIClientConfig = Pick<APIClientOptions, 'url' | 'endpoints'>;\n/**\n * A dictionary of endpoints for the API client.\n * This is declared as standalone because it needs to reference them multiple times.\n *\n * @group Services/APIClient\n */\nexport type EndpointsType = APIClientOptions['endpoints'];\n/**\n * The format the settings needs to have in the application configuration in order to\n * create a valid API client.\n * The settings may include the endpoints dictionary in the `endpoints` property, or the\n * gateway `property`, with `endpoints` always having priority if both exists.\n * The reason for the `gateway` property to be valid, is in case the application also\n * implements a {@link GatewayController}, using the same property for both things will\n * help reduce the amount of duplicated definitions.\n *\n * @group Services/APIClient\n */\nexport type APIClientSettings = Omit<APIClientConfig, 'endpoints'> &\n (\n | {\n endpoints: EndpointsType;\n gateway?: EndpointsType;\n }\n | {\n endpoints?: EndpointsType;\n gateway: EndpointsType;\n }\n );\n/**\n * The options to construct a {@link APIClient}.\n *\n * @group Services/APIClient\n */\nexport type APIClientConstructorOptions = APIClientSettings & {\n /**\n * A dictionary with the dependencies to inject.\n */\n inject: {\n http: HTTP;\n HTTPError: HTTPErrorClass;\n };\n};\n/**\n * An API client for the application to use. What makes this service special is that it\n * formats received errors using the {@link _HTTPError} class, and as fetch client, it\n * uses the {@link HTTP} service, allowing the application to to internally handle all the\n * requests and responses.\n *\n * The only reason to use the class directly is if you want to subclass it, as you would\n * normally just register the {@link apiClientProvider}.\n *\n * @group Services\n * @group Services/APIClient\n */\nexport class APIClient extends APIClientBase {\n /**\n * The service that makes the requests to the API.\n */\n protected readonly _http: HTTP;\n /**\n * The class to generate possible errors in the requests.\n */\n protected readonly _HTTPError: HTTPErrorClass;\n /**\n * The configuration of the API it uses.\n */\n protected readonly _apiConfig: APIClientConfig;\n /**\n * @param options The options to construct the class.\n */\n constructor({ inject: { http, HTTPError }, ...rest }: APIClientConstructorOptions) {\n const { endpoints, gateway, url } = rest;\n const useEndpoints = (endpoints || gateway)!;\n const apiConfig = {\n url,\n endpoints: useEndpoints,\n };\n super({\n ...apiConfig,\n fetchClient: http.fetch as unknown as FetchClient,\n });\n\n this._http = http;\n this._HTTPError = HTTPError;\n this._apiConfig = deepAssignWithOverwrite({}, apiConfig);\n }\n /**\n * The configuration for the API.\n */\n get apiConfig(): Readonly<APIClientConfig> {\n return deepAssignWithOverwrite({}, this._apiConfig);\n }\n /**\n * Tries to obtain a message from an error caused on a failed request.\n *\n * @param response The response from the failed request.\n */\n protected _getErrorMessageFromResponse(response: unknown) {\n const res = response as {\n error?: string;\n data?: {\n message?: string;\n error?: string;\n };\n };\n if (res.error) return res.error;\n if (res.data) {\n if (res.data.message) return res.data.message;\n if (res.data.error) return res.data.error;\n }\n\n return 'Unexpected error';\n }\n /**\n * Generates an {@link _HTTPError} from the response of a failed request.\n *\n * @param response The response from the failed request.\n * @param status The status code of the response.\n */\n protected override formatError<ResponseType extends ErrorResponse>(\n response: ResponseType,\n status: number,\n ): Error {\n return new this._HTTPError(this._getErrorMessageFromResponse(response), status);\n }\n}\n/**\n * The options for the provider creator that registers an {@link APIClient} in the\n * container.\n * These options allow the application to register multiple instances for different APIs.\n *\n * @group Services/APIClient\n */\nexport type APIClientProviderOptions = {\n /**\n * The name of the service that will be registered into the app.\n *\n * @default 'apiClient'\n */\n serviceName?: string;\n /**\n * The name of the configuration setting that has the API information.\n *\n * @default 'api'\n */\n configSetting?: string;\n /**\n * The class the service will instantiate. It has to extend {@link APIClient}.\n *\n * @default APIClient\n */\n clientClass?: typeof APIClient;\n};\n/**\n * The provider creator to register an instance of {@link APIClient} on the container.\n *\n * @example\n *\n * <caption>Basic usage</caption>\n *\n * // Register it on the container\n * container.register(apiClientProvider);\n * // Getting access to the service instance\n * const apiClient = container.get<APIClient>('apiClient');\n *\n * @example\n *\n * <caption>With custom options</caption>\n *\n * container.register(\n * apiClientProvider({\n * serviceName: 'myApiClient',\n * configSetting: 'myApi',\n * }),\n * );\n *\n * @group Providers\n * @group Services/APIClient\n */\nexport const apiClientProvider = providerCreator(\n (options: APIClientProviderOptions = {}) =>\n (app) => {\n const defaultName = 'apiClient';\n const { serviceName = defaultName, clientClass: ClientClass = APIClient } = options;\n let { configSetting } = options;\n if (!configSetting) {\n configSetting = serviceName === defaultName ? 'api' : serviceName;\n }\n\n app.set(\n serviceName,\n () =>\n new ClientClass({\n inject: {\n http: app.get('http'),\n HTTPError: app.get('HTTPError'),\n },\n ...app.getConfig<APIClientSettings>(configSetting!),\n }),\n );\n },\n);\n"],"mappings":";;;AAAA;AAAA,EACE,aAAa;AAAA,OAIR;AACP,SAAS,+BAA+B;AACxC,SAAS,uBAAuB;AAkEzB,MAAM,kBAAkB,cAAc;AAAA;AAAA;AAAA;AAAA,EAgB3C,YAAY,EAAE,QAAQ,EAAE,MAAM,UAAU,GAAG,GAAG,KAAK,GAAgC;AACjF,UAAM,EAAE,WAAW,SAAS,IAAI,IAAI;AACpC,UAAM,eAAgB,aAAa;AACnC,UAAM,YAAY;AAAA,MAChB;AAAA,MACA,WAAW;AAAA,IACb;AACA,UAAM;AAAA,MACJ,GAAG;AAAA,MACH,aAAa,KAAK;AAAA,IACpB,CAAC;AAtBH;AAAA;AAAA;AAAA,wBAAmB;AAInB;AAAA;AAAA;AAAA,wBAAmB;AAInB;AAAA;AAAA;AAAA,wBAAmB;AAgBjB,SAAK,QAAQ;AACb,SAAK,aAAa;AAClB,SAAK,aAAa,wBAAwB,CAAC,GAAG,SAAS;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,YAAuC;AACzC,WAAO,wBAAwB,CAAC,GAAG,KAAK,UAAU;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,6BAA6B,UAAmB;AACxD,UAAM,MAAM;AAOZ,QAAI,IAAI,MAAO,QAAO,IAAI;AAC1B,QAAI,IAAI,MAAM;AACZ,UAAI,IAAI,KAAK,QAAS,QAAO,IAAI,KAAK;AACtC,UAAI,IAAI,KAAK,MAAO,QAAO,IAAI,KAAK;AAAA,IACtC;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOmB,YACjB,UACA,QACO;AACP,WAAO,IAAI,KAAK,WAAW,KAAK,6BAA6B,QAAQ,GAAG,MAAM;AAAA,EAChF;AACF;AAsDO,MAAM,oBAAoB;AAAA,EAC/B,CAAC,UAAoC,CAAC,MACpC,CAAC,QAAQ;AACP,UAAM,cAAc;AACpB,UAAM,EAAE,cAAc,aAAa,aAAa,cAAc,UAAU,IAAI;AAC5E,QAAI,EAAE,cAAc,IAAI;AACxB,QAAI,CAAC,eAAe;AAClB,sBAAgB,gBAAgB,cAAc,QAAQ;AAAA,IACxD;AAEA,QAAI;AAAA,MACF;AAAA,MACA,MACE,IAAI,YAAY;AAAA,QACd,QAAQ;AAAA,UACN,MAAM,IAAI,IAAI,MAAM;AAAA,UACpB,WAAW,IAAI,IAAI,WAAW;AAAA,QAChC;AAAA,QACA,GAAG,IAAI,UAA6B,aAAc;AAAA,MACpD,CAAC;AAAA,IACL;AAAA,EACF;AACJ;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  __publicField
3
- } from "../../chunk-F3FYYIAV.js";
3
+ } from "../../chunk-V6TY7KAL.js";
4
4
  import urijs from "urijs";
5
5
  import { deepAssignWithOverwrite } from "@homer0/deep-assign";
6
6
  import { provider } from "../../utils";
@@ -1,4 +1,4 @@
1
- import "../../chunk-F3FYYIAV.js";
1
+ import "../../chunk-V6TY7KAL.js";
2
2
  import { providers } from "../../utils";
3
3
  import { apiClientProvider } from "./apiClient";
4
4
  import { httpProvider } from "./http";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  __publicField
3
- } from "../../chunk-F3FYYIAV.js";
3
+ } from "../../chunk-V6TY7KAL.js";
4
4
  import { provider } from "../../utils";
5
5
  const DEFAULT_CLOSE_DELAY_FOR_POST_MESSAGE = 700;
6
6
  class ResponsesBuilder {
@@ -128,7 +128,7 @@ class ResponsesBuilder {
128
128
  this._statuses(status);
129
129
  useStatus = status;
130
130
  }
131
- } catch (_) {
131
+ } catch {
132
132
  useStatus = this._statuses("ok");
133
133
  }
134
134
  return useStatus;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/services/http/responsesBuilder.ts"],"sourcesContent":["import type { Config, Response } from '../../types';\nimport { provider, type Statuses } from '../../utils';\n/**\n * The options to construct a {@link ResponsesBuilder}.\n *\n * @group Services/ResponsesBuilder\n */\nexport type ResponsesBuilderConstructorOptions = {\n /**\n * A dictionary with the dependencies to inject.\n */\n inject: {\n config: Config;\n statuses: Statuses;\n };\n};\n/**\n * The options to build a response for a post message.\n *\n * @group Services/ResponsesBuilder\n */\nexport type HTMLPostMessageResponseOptions = {\n /**\n * The response object generated by the application.\n */\n res: Response;\n /**\n * The title for the HTML.\n */\n title: string;\n /**\n * The contents of the post message.\n */\n message: string;\n /**\n * The status code for the response.\n *\n * @default 200\n */\n status?: number | string;\n /**\n * From which object will the `postMessage` method called from.\n *\n * @default 'window.opener'\n */\n target?: string;\n /**\n * Whether or not to call `window.close` after sending the message.\n *\n * @default true\n */\n close?: boolean;\n /**\n * In case `close` is set to `true`, this option is to specify how many milliseconds\n * should be waited before closing the window.\n *\n * @default 700\n */\n closeDelay?: number;\n};\n/**\n * The options to build a reponse for JSON.\n *\n * @group Services/ResponsesBuilder\n */\nexport type JSONResponseOptions = {\n /**\n * The response object generated by the application.\n */\n res: Response;\n /**\n * The actual data for the response. It will be added in a `data` property.\n */\n data: unknown;\n /**\n * The status code for the response.\n *\n * @default 200\n */\n status?: number | string;\n /**\n * Extra information to include inside the `metadata` object.\n */\n metadata?: object;\n};\n/**\n * The default time to wait before closing a window, in case it's enabled.\n */\nconst DEFAULT_CLOSE_DELAY_FOR_POST_MESSAGE = 700;\n/**\n * A utility service to build responses.\n *\n * @group Services\n * @group Services/ResponsesBuilder\n */\nexport class ResponsesBuilder {\n /**\n * The application configuration, to get the `version` and the `postMessagesPrefix`.\n */\n protected readonly _config: Config;\n /**\n * The uility service to get HTTP status codes.\n */\n protected readonly _statuses: Statuses;\n /**\n * @param options The options to construct the service.\n */\n constructor({ inject: { config, statuses } }: ResponsesBuilderConstructorOptions) {\n this._config = config;\n this._statuses = statuses;\n }\n /**\n * Generates and send an HTML response that emits a post message.\n * The post message will be prefixed with the value of the configuration setting\n * `postMessagesPrefix`.\n *\n * @param options The options to customize how the HTML is generated.\n */\n htmlPostMessage(options: HTMLPostMessageResponseOptions): void {\n const {\n res,\n title,\n message,\n status,\n target = 'window.opener',\n close = true,\n closeDelay = DEFAULT_CLOSE_DELAY_FOR_POST_MESSAGE,\n } = options;\n const prefix = this._config.get<string | undefined>('postMessagesPrefix') ?? '';\n const closeCode = close\n ? `setTimeout(function() { window.close(); }, ${closeDelay});`\n : '';\n\n const html = this._htmlTemplate(\n title,\n `\n (function() {\n if (${target}) {\n ${target}.postMessage('${prefix}${message}', '*');\n ${closeCode}\n }\n })();\n `,\n );\n\n const useStatus =\n typeof status === 'undefined'\n ? (this._statuses('ok') as number)\n : this._normalizeStatus(status);\n\n res.setHeader('Content-Type', 'text/html');\n res.setHeader('Cache-Control', 'no-cache, max-age=0, must-revalidate, no-store');\n res.status(useStatus);\n res.write(html);\n res.end();\n }\n /**\n * Generates and sends a JSON response.\n *\n * @param options The options to customize how the JSON is generated.\n * @example\n *\n * <caption>The generated looks like this.</caption>\n *\n * {\n * metadata: {\n * version: 'dev',\n * status: 200,\n * },\n * data: { foo: 'bar' },\n * }\n *\n */\n json(options: JSONResponseOptions): void {\n const { res, data, status, metadata = {} } = options;\n const useStatus =\n typeof status === 'undefined'\n ? (this._statuses('ok') as number)\n : this._normalizeStatus(status);\n\n res.status(useStatus);\n res.json({\n metadata: {\n version: this._config.get<string>('version'),\n status: useStatus,\n ...metadata,\n },\n data,\n });\n res.end();\n }\n /**\n * Generates a basic HTML template for the service to use when generating a post message\n * response.\n *\n * @param title The HTML `<title />` attribute.\n * @param code Javascript code to be wrapped on a `<script />` tag.\n */\n protected _htmlTemplate(title: string, code: string): string {\n return `\n <!DOCTYPE html>\n <html>\n <head>\n <meta charset=\"utf-8\" />\n <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>${title}</title>\n </head>\n <body>\n <script type=\"text/javascript\">\n ${code}\n </script>\n </body>\n </html>\n `;\n }\n /**\n * Utility method used to make sure a recevied status is a valid status code. If the\n * status is a string, the method will try to find the code from the `statuses` package.\n *\n * @param status The status to normalize.\n * @returns If `status` is a string, but there's no valid code, it will return 200.\n */\n protected _normalizeStatus(status: number | string): number {\n let useStatus: number;\n try {\n if (typeof status === 'string') {\n useStatus = this._statuses(status) as number;\n } else {\n this._statuses(status);\n useStatus = status;\n }\n } catch (_) {\n useStatus = this._statuses('ok') as number;\n }\n\n return useStatus;\n }\n}\n/**\n * The service provider that once registered on the container will set an instance of\n * {@link ResponsesBuilder} as the `responsesBuilder` service.\n *\n * @example\n *\n * // Register it on the container\n * container.register(responsesBuilderProvider);\n * // Getting access to the service instance\n * const responsesBuilder = container.get<ResponsesBuilder>('responsesBuilder');\n *\n * @group Providers\n * @group Services/ResponsesBuilder\n */\nexport const responsesBuilderProvider = provider((app) => {\n app.set(\n 'responsesBuilder',\n () =>\n new ResponsesBuilder({\n inject: {\n config: app.getConfig(),\n statuses: app.get('statuses'),\n },\n }),\n );\n});\n"],"mappings":";;;AACA,SAAS,gBAA+B;AAuFxC,MAAM,uCAAuC;AAOtC,MAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA,EAY5B,YAAY,EAAE,QAAQ,EAAE,QAAQ,SAAS,EAAE,GAAuC;AARlF;AAAA;AAAA;AAAA,wBAAmB;AAInB;AAAA;AAAA;AAAA,wBAAmB;AAKjB,SAAK,UAAU;AACf,SAAK,YAAY;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,gBAAgB,SAA+C;AAC7D,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,aAAa;AAAA,IACf,IAAI;AACJ,UAAM,SAAS,KAAK,QAAQ,IAAwB,oBAAoB,KAAK;AAC7E,UAAM,YAAY,QACd,8CAA8C,UAAU,OACxD;AAEJ,UAAM,OAAO,KAAK;AAAA,MAChB;AAAA,MACA;AAAA;AAAA,cAEQ,MAAM;AAAA,YACR,MAAM,iBAAiB,MAAM,GAAG,OAAO;AAAA,YACvC,SAAS;AAAA;AAAA;AAAA;AAAA,IAIjB;AAEA,UAAM,YACJ,OAAO,WAAW,cACb,KAAK,UAAU,IAAI,IACpB,KAAK,iBAAiB,MAAM;AAElC,QAAI,UAAU,gBAAgB,WAAW;AACzC,QAAI,UAAU,iBAAiB,gDAAgD;AAC/E,QAAI,OAAO,SAAS;AACpB,QAAI,MAAM,IAAI;AACd,QAAI,IAAI;AAAA,EACV;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,KAAK,SAAoC;AACvC,UAAM,EAAE,KAAK,MAAM,QAAQ,WAAW,CAAC,EAAE,IAAI;AAC7C,UAAM,YACJ,OAAO,WAAW,cACb,KAAK,UAAU,IAAI,IACpB,KAAK,iBAAiB,MAAM;AAElC,QAAI,OAAO,SAAS;AACpB,QAAI,KAAK;AAAA,MACP,UAAU;AAAA,QACR,SAAS,KAAK,QAAQ,IAAY,SAAS;AAAA,QAC3C,QAAQ;AAAA,QACR,GAAG;AAAA,MACL;AAAA,MACA;AAAA,IACF,CAAC;AACD,QAAI,IAAI;AAAA,EACV;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQU,cAAc,OAAe,MAAsB;AAC3D,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAOQ,KAAK;AAAA;AAAA;AAAA;AAAA,YAIZ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA,EAKd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQU,iBAAiB,QAAiC;AAC1D,QAAI;AACJ,QAAI;AACF,UAAI,OAAO,WAAW,UAAU;AAC9B,oBAAY,KAAK,UAAU,MAAM;AAAA,MACnC,OAAO;AACL,aAAK,UAAU,MAAM;AACrB,oBAAY;AAAA,MACd;AAAA,IACF,SAAS,GAAG;AACV,kBAAY,KAAK,UAAU,IAAI;AAAA,IACjC;AAEA,WAAO;AAAA,EACT;AACF;AAeO,MAAM,2BAA2B,SAAS,CAAC,QAAQ;AACxD,MAAI;AAAA,IACF;AAAA,IACA,MACE,IAAI,iBAAiB;AAAA,MACnB,QAAQ;AAAA,QACN,QAAQ,IAAI,UAAU;AAAA,QACtB,UAAU,IAAI,IAAI,UAAU;AAAA,MAC9B;AAAA,IACF,CAAC;AAAA,EACL;AACF,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../../../src/services/http/responsesBuilder.ts"],"sourcesContent":["import type { Config, Response } from '../../types';\nimport { provider, type Statuses } from '../../utils';\n/**\n * The options to construct a {@link ResponsesBuilder}.\n *\n * @group Services/ResponsesBuilder\n */\nexport type ResponsesBuilderConstructorOptions = {\n /**\n * A dictionary with the dependencies to inject.\n */\n inject: {\n config: Config;\n statuses: Statuses;\n };\n};\n/**\n * The options to build a response for a post message.\n *\n * @group Services/ResponsesBuilder\n */\nexport type HTMLPostMessageResponseOptions = {\n /**\n * The response object generated by the application.\n */\n res: Response;\n /**\n * The title for the HTML.\n */\n title: string;\n /**\n * The contents of the post message.\n */\n message: string;\n /**\n * The status code for the response.\n *\n * @default 200\n */\n status?: number | string;\n /**\n * From which object will the `postMessage` method called from.\n *\n * @default 'window.opener'\n */\n target?: string;\n /**\n * Whether or not to call `window.close` after sending the message.\n *\n * @default true\n */\n close?: boolean;\n /**\n * In case `close` is set to `true`, this option is to specify how many milliseconds\n * should be waited before closing the window.\n *\n * @default 700\n */\n closeDelay?: number;\n};\n/**\n * The options to build a reponse for JSON.\n *\n * @group Services/ResponsesBuilder\n */\nexport type JSONResponseOptions = {\n /**\n * The response object generated by the application.\n */\n res: Response;\n /**\n * The actual data for the response. It will be added in a `data` property.\n */\n data: unknown;\n /**\n * The status code for the response.\n *\n * @default 200\n */\n status?: number | string;\n /**\n * Extra information to include inside the `metadata` object.\n */\n metadata?: object;\n};\n/**\n * The default time to wait before closing a window, in case it's enabled.\n */\nconst DEFAULT_CLOSE_DELAY_FOR_POST_MESSAGE = 700;\n/**\n * A utility service to build responses.\n *\n * @group Services\n * @group Services/ResponsesBuilder\n */\nexport class ResponsesBuilder {\n /**\n * The application configuration, to get the `version` and the `postMessagesPrefix`.\n */\n protected readonly _config: Config;\n /**\n * The uility service to get HTTP status codes.\n */\n protected readonly _statuses: Statuses;\n /**\n * @param options The options to construct the service.\n */\n constructor({ inject: { config, statuses } }: ResponsesBuilderConstructorOptions) {\n this._config = config;\n this._statuses = statuses;\n }\n /**\n * Generates and send an HTML response that emits a post message.\n * The post message will be prefixed with the value of the configuration setting\n * `postMessagesPrefix`.\n *\n * @param options The options to customize how the HTML is generated.\n */\n htmlPostMessage(options: HTMLPostMessageResponseOptions): void {\n const {\n res,\n title,\n message,\n status,\n target = 'window.opener',\n close = true,\n closeDelay = DEFAULT_CLOSE_DELAY_FOR_POST_MESSAGE,\n } = options;\n const prefix = this._config.get<string | undefined>('postMessagesPrefix') ?? '';\n const closeCode = close\n ? `setTimeout(function() { window.close(); }, ${closeDelay});`\n : '';\n\n const html = this._htmlTemplate(\n title,\n `\n (function() {\n if (${target}) {\n ${target}.postMessage('${prefix}${message}', '*');\n ${closeCode}\n }\n })();\n `,\n );\n\n const useStatus =\n typeof status === 'undefined'\n ? (this._statuses('ok') as number)\n : this._normalizeStatus(status);\n\n res.setHeader('Content-Type', 'text/html');\n res.setHeader('Cache-Control', 'no-cache, max-age=0, must-revalidate, no-store');\n res.status(useStatus);\n res.write(html);\n res.end();\n }\n /**\n * Generates and sends a JSON response.\n *\n * @param options The options to customize how the JSON is generated.\n * @example\n *\n * <caption>The generated looks like this.</caption>\n *\n * {\n * metadata: {\n * version: 'dev',\n * status: 200,\n * },\n * data: { foo: 'bar' },\n * }\n *\n */\n json(options: JSONResponseOptions): void {\n const { res, data, status, metadata = {} } = options;\n const useStatus =\n typeof status === 'undefined'\n ? (this._statuses('ok') as number)\n : this._normalizeStatus(status);\n\n res.status(useStatus);\n res.json({\n metadata: {\n version: this._config.get<string>('version'),\n status: useStatus,\n ...metadata,\n },\n data,\n });\n res.end();\n }\n /**\n * Generates a basic HTML template for the service to use when generating a post message\n * response.\n *\n * @param title The HTML `<title />` attribute.\n * @param code Javascript code to be wrapped on a `<script />` tag.\n */\n protected _htmlTemplate(title: string, code: string): string {\n return `\n <!DOCTYPE html>\n <html>\n <head>\n <meta charset=\"utf-8\" />\n <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>${title}</title>\n </head>\n <body>\n <script type=\"text/javascript\">\n ${code}\n </script>\n </body>\n </html>\n `;\n }\n /**\n * Utility method used to make sure a recevied status is a valid status code. If the\n * status is a string, the method will try to find the code from the `statuses` package.\n *\n * @param status The status to normalize.\n * @returns If `status` is a string, but there's no valid code, it will return 200.\n */\n protected _normalizeStatus(status: number | string): number {\n let useStatus: number;\n try {\n if (typeof status === 'string') {\n useStatus = this._statuses(status) as number;\n } else {\n this._statuses(status);\n useStatus = status;\n }\n } catch {\n useStatus = this._statuses('ok') as number;\n }\n\n return useStatus;\n }\n}\n/**\n * The service provider that once registered on the container will set an instance of\n * {@link ResponsesBuilder} as the `responsesBuilder` service.\n *\n * @example\n *\n * // Register it on the container\n * container.register(responsesBuilderProvider);\n * // Getting access to the service instance\n * const responsesBuilder = container.get<ResponsesBuilder>('responsesBuilder');\n *\n * @group Providers\n * @group Services/ResponsesBuilder\n */\nexport const responsesBuilderProvider = provider((app) => {\n app.set(\n 'responsesBuilder',\n () =>\n new ResponsesBuilder({\n inject: {\n config: app.getConfig(),\n statuses: app.get('statuses'),\n },\n }),\n );\n});\n"],"mappings":";;;AACA,SAAS,gBAA+B;AAuFxC,MAAM,uCAAuC;AAOtC,MAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA,EAY5B,YAAY,EAAE,QAAQ,EAAE,QAAQ,SAAS,EAAE,GAAuC;AARlF;AAAA;AAAA;AAAA,wBAAmB;AAInB;AAAA;AAAA;AAAA,wBAAmB;AAKjB,SAAK,UAAU;AACf,SAAK,YAAY;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,gBAAgB,SAA+C;AAC7D,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,aAAa;AAAA,IACf,IAAI;AACJ,UAAM,SAAS,KAAK,QAAQ,IAAwB,oBAAoB,KAAK;AAC7E,UAAM,YAAY,QACd,8CAA8C,UAAU,OACxD;AAEJ,UAAM,OAAO,KAAK;AAAA,MAChB;AAAA,MACA;AAAA;AAAA,cAEQ,MAAM;AAAA,YACR,MAAM,iBAAiB,MAAM,GAAG,OAAO;AAAA,YACvC,SAAS;AAAA;AAAA;AAAA;AAAA,IAIjB;AAEA,UAAM,YACJ,OAAO,WAAW,cACb,KAAK,UAAU,IAAI,IACpB,KAAK,iBAAiB,MAAM;AAElC,QAAI,UAAU,gBAAgB,WAAW;AACzC,QAAI,UAAU,iBAAiB,gDAAgD;AAC/E,QAAI,OAAO,SAAS;AACpB,QAAI,MAAM,IAAI;AACd,QAAI,IAAI;AAAA,EACV;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,KAAK,SAAoC;AACvC,UAAM,EAAE,KAAK,MAAM,QAAQ,WAAW,CAAC,EAAE,IAAI;AAC7C,UAAM,YACJ,OAAO,WAAW,cACb,KAAK,UAAU,IAAI,IACpB,KAAK,iBAAiB,MAAM;AAElC,QAAI,OAAO,SAAS;AACpB,QAAI,KAAK;AAAA,MACP,UAAU;AAAA,QACR,SAAS,KAAK,QAAQ,IAAY,SAAS;AAAA,QAC3C,QAAQ;AAAA,QACR,GAAG;AAAA,MACL;AAAA,MACA;AAAA,IACF,CAAC;AACD,QAAI,IAAI;AAAA,EACV;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQU,cAAc,OAAe,MAAsB;AAC3D,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAOQ,KAAK;AAAA;AAAA;AAAA;AAAA,YAIZ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA,EAKd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQU,iBAAiB,QAAiC;AAC1D,QAAI;AACJ,QAAI;AACF,UAAI,OAAO,WAAW,UAAU;AAC9B,oBAAY,KAAK,UAAU,MAAM;AAAA,MACnC,OAAO;AACL,aAAK,UAAU,MAAM;AACrB,oBAAY;AAAA,MACd;AAAA,IACF,QAAQ;AACN,kBAAY,KAAK,UAAU,IAAI;AAAA,IACjC;AAEA,WAAO;AAAA,EACT;AACF;AAeO,MAAM,2BAA2B,SAAS,CAAC,QAAQ;AACxD,MAAI;AAAA,IACF;AAAA,IACA,MACE,IAAI,iBAAiB;AAAA,MACnB,QAAQ;AAAA,QACN,QAAQ,IAAI,UAAU;AAAA,QACtB,UAAU,IAAI,IAAI,UAAU;AAAA,MAC9B;AAAA,IACF,CAAC;AAAA,EACL;AACF,CAAC;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  __publicField
3
- } from "../../chunk-F3FYYIAV.js";
3
+ } from "../../chunk-V6TY7KAL.js";
4
4
  import { deepAssignWithOverwrite } from "@homer0/deep-assign";
5
5
  import { providerCreator } from "../../utils";
6
6
  class EnsureBearerToken {
@@ -1,4 +1,4 @@
1
- import "../../chunk-F3FYYIAV.js";
1
+ import "../../chunk-V6TY7KAL.js";
2
2
  import { providers } from "../../utils";
3
3
  import { ensureBearerTokenProvider } from "./ensureBearerToken";
4
4
  const utilsServicesProvider = providers({
@@ -1,4 +1,4 @@
1
- import "../../chunk-F3FYYIAV.js";
1
+ import "../../chunk-V6TY7KAL.js";
2
2
  const notUndefined = (value) => value !== void 0;
3
3
  export {
4
4
  notUndefined
@@ -1,4 +1,4 @@
1
- import "../../chunk-F3FYYIAV.js";
1
+ import "../../chunk-V6TY7KAL.js";
2
2
  import { escapeForRegExp } from "./text";
3
3
  const removeLeadingSlash = (url) => url.replace(/^\/+/, "");
4
4
  const removeTrailingSlash = (url) => url.replace(/\/+$/, "");
@@ -1,4 +1,4 @@
1
- import "../../chunk-F3FYYIAV.js";
1
+ import "../../chunk-V6TY7KAL.js";
2
2
  import statuses from "statuses";
3
3
  export {
4
4
  statuses
@@ -1,4 +1,4 @@
1
- import "../../chunk-F3FYYIAV.js";
1
+ import "../../chunk-V6TY7KAL.js";
2
2
  const escapeForRegExp = (text) => text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
3
3
  export {
4
4
  escapeForRegExp
@@ -1,4 +1,4 @@
1
- import "../chunk-F3FYYIAV.js";
1
+ import "../chunk-V6TY7KAL.js";
2
2
  import {
3
3
  createProvider,
4
4
  createProviderCreator,
@@ -17,10 +17,7 @@ var __copyProps = (to, from, except, desc) => {
17
17
  return to;
18
18
  };
19
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
- var __publicField = (obj, key, value) => {
21
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
22
- return value;
23
- };
20
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
24
21
  var errorHandler_exports = {};
25
22
  __export(errorHandler_exports, {
26
23
  ErrorHandler: () => ErrorHandler,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/middlewares/common/errorHandler.ts"],"sourcesContent":["import { deepAssignWithOverwrite } from '@homer0/deep-assign';\nimport { middlewareCreator, type Statuses } from '../../utils';\nimport type { DeepPartial, Logger, ExpressErrorHandler } from '../../types';\nimport { AppError, type HTTPErrorClass, type ResponsesBuilder } from '../../services';\n/**\n * The options for the responses the middleware will create.\n *\n * @group Middlewares/ErrorHandler\n */\nexport type ErrorHandlerResponseOptions = {\n /**\n * The message to show in case `showErrors` is set to `false`.\n *\n * @default 'Oops! Something went wrong, please try again'\n * @prettierignore\n */\n message: string;\n /**\n * The default status code for the responses.\n *\n * @default 500\n */\n status: number;\n};\n/**\n * The customization options for the middleware.\n *\n * @group Middlewares/ErrorHandler\n */\nexport type ErrorHandlerOptions = {\n /**\n * If `false`, unknown errors will show a generic message instead of real message. And\n * if `true`, it will not only show all kind of errors but it will also show the error\n * stack.\n *\n * By \"uknown errors\", it means that are not `AppError` nor `HTTPError`.\n */\n showErrors: boolean;\n /**\n * The options for the default response the middleware will create.\n */\n response: ErrorHandlerResponseOptions;\n};\n/**\n * A partial version of the {@link ErrorHandlerOptions}, to be used in the constructor and\n * the middleware creator.\n *\n * @group Middlewares/ErrorHandler\n */\nexport type ErrorHandlerPartialOptions = DeepPartial<ErrorHandlerOptions>;\n/**\n * The options to construct a {@link ErrorHandler}.\n *\n * @group Middlewares/ErrorHandler\n */\nexport type ErrorHandlerConstructorOptions = ErrorHandlerPartialOptions & {\n /**\n * A dictionary with the dependencies to inject.\n */\n inject: {\n logger: Logger;\n responsesBuilder: ResponsesBuilder;\n statuses: Statuses;\n HTTPError: HTTPErrorClass;\n };\n};\n/**\n * Creates a middleware that handles errors and generates the responses.\n *\n * @group Middleware Classes\n * @group Middlewares/ErrorHandler\n * @prettierignore\n */\nexport class ErrorHandler {\n /**\n * The service that will log the messages in the console.\n */\n protected readonly _logger: Logger;\n /**\n * The service to generate the responses.\n */\n protected readonly _responsesBuilder: ResponsesBuilder;\n /**\n * The uility service to get HTTP status codes.\n */\n protected readonly _statuses: Statuses;\n /**\n * The Error class used by the \"known errors\".\n */\n protected readonly _HTTPError: HTTPErrorClass;\n /**\n * The customization options.\n */\n protected readonly _options: ErrorHandlerOptions;\n /**\n * @param options The options to construct the class.\n */\n constructor({\n inject: { logger, responsesBuilder, statuses, HTTPError },\n ...options\n }: ErrorHandlerConstructorOptions) {\n this._logger = logger;\n this._responsesBuilder = responsesBuilder;\n this._statuses = statuses;\n this._HTTPError = HTTPError;\n this._options = deepAssignWithOverwrite(\n {\n showErrors: false,\n response: {\n message: 'Unexpected error',\n status: this._statuses('internal server error'),\n },\n },\n options,\n );\n }\n /**\n * Generates the middleware that handles the errors.\n */\n getMiddleware(): ExpressErrorHandler {\n return (err, _, res, next) => {\n // If there wasn't any error, continue the execution.\n if (!err) {\n next();\n return;\n }\n\n const { response, showErrors } = this._options;\n\n // Define the base status and response.\n let { status } = response;\n let data: {\n error: boolean;\n message: string;\n stack?: string[];\n } & Record<string, unknown> = {\n error: true,\n message: response.message,\n };\n\n const knownError = err instanceof AppError;\n // If it's a \"known error\" or the `showErrors` flag is set to `true`...\n if (showErrors || knownError) {\n // Get the real message.\n data.message = err.message;\n // If it's a \"known error\"...\n if (knownError) {\n // Try to extract information for the response.\n data = {\n ...data,\n ...err.getResponse(),\n };\n status = err.status || (this._statuses('bad request') as number);\n }\n /**\n * If the flag is set to `true`, and it's a \"valid error\", try to extract the\n * stack, format it, and include it in the response.\n */\n if (showErrors && err instanceof Error && err.stack) {\n const stack = err.stack.split('\\n').map((line) => line.trim());\n data.stack = stack;\n stack.splice(0, 1);\n this._logger.error(`ERROR: ${err.message}`);\n this._logger.info(stack);\n }\n }\n\n this._responsesBuilder.json({\n res,\n data,\n status,\n });\n };\n }\n /**\n * The handler customization options.\n */\n get options(): Readonly<ErrorHandlerOptions> {\n return deepAssignWithOverwrite({}, this._options);\n }\n}\n/**\n * Creates the middleware that handles errors.\n *\n * @group Middlewares\n * @group Middlewares/ErrorHandler\n */\nexport const errorHandlerMiddleware = middlewareCreator(\n (options: ErrorHandlerPartialOptions = {}) =>\n (app) => {\n const showErrors = app.getConfig<boolean | undefined>('debug.showErrors') === true;\n return new ErrorHandler({\n inject: {\n logger: app.get('logger'),\n responsesBuilder: app.get('responsesBuilder'),\n statuses: app.get('statuses'),\n HTTPError: app.get('HTTPError'),\n },\n showErrors,\n ...options,\n }).getMiddleware();\n },\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAAwC;AACxC,mBAAiD;AAEjD,sBAAqE;AAsE9D,MAAM,aAAa;AAAA;AAAA;AAAA;AAAA,EAwBxB,YAAY;AAAA,IACV,QAAQ,EAAE,QAAQ,kBAAkB,UAAU,UAAU;AAAA,IACxD,GAAG;AAAA,EACL,GAAmC;AAvBnC;AAAA;AAAA;AAAA,wBAAmB;AAInB;AAAA;AAAA;AAAA,wBAAmB;AAInB;AAAA;AAAA;AAAA,wBAAmB;AAInB;AAAA;AAAA;AAAA,wBAAmB;AAInB;AAAA;AAAA;AAAA,wBAAmB;AAQjB,SAAK,UAAU;AACf,SAAK,oBAAoB;AACzB,SAAK,YAAY;AACjB,SAAK,aAAa;AAClB,SAAK,eAAW;AAAA,MACd;AAAA,QACE,YAAY;AAAA,QACZ,UAAU;AAAA,UACR,SAAS;AAAA,UACT,QAAQ,KAAK,UAAU,uBAAuB;AAAA,QAChD;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAIA,gBAAqC;AACnC,WAAO,CAAC,KAAK,GAAG,KAAK,SAAS;AAE5B,UAAI,CAAC,KAAK;AACR,aAAK;AACL;AAAA,MACF;AAEA,YAAM,EAAE,UAAU,WAAW,IAAI,KAAK;AAGtC,UAAI,EAAE,OAAO,IAAI;AACjB,UAAI,OAI0B;AAAA,QAC5B,OAAO;AAAA,QACP,SAAS,SAAS;AAAA,MACpB;AAEA,YAAM,aAAa,eAAe;AAElC,UAAI,cAAc,YAAY;AAE5B,aAAK,UAAU,IAAI;AAEnB,YAAI,YAAY;AAEd,iBAAO;AAAA,YACL,GAAG;AAAA,YACH,GAAG,IAAI,YAAY;AAAA,UACrB;AACA,mBAAS,IAAI,UAAW,KAAK,UAAU,aAAa;AAAA,QACtD;AAKA,YAAI,cAAc,eAAe,SAAS,IAAI,OAAO;AACnD,gBAAM,QAAQ,IAAI,MAAM,MAAM,IAAI,EAAE,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC;AAC7D,eAAK,QAAQ;AACb,gBAAM,OAAO,GAAG,CAAC;AACjB,eAAK,QAAQ,MAAM,UAAU,IAAI,OAAO,EAAE;AAC1C,eAAK,QAAQ,KAAK,KAAK;AAAA,QACzB;AAAA,MACF;AAEA,WAAK,kBAAkB,KAAK;AAAA,QAC1B;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,UAAyC;AAC3C,eAAO,4CAAwB,CAAC,GAAG,KAAK,QAAQ;AAAA,EAClD;AACF;AAOO,MAAM,6BAAyB;AAAA,EACpC,CAAC,UAAsC,CAAC,MACtC,CAAC,QAAQ;AACP,UAAM,aAAa,IAAI,UAA+B,kBAAkB,MAAM;AAC9E,WAAO,IAAI,aAAa;AAAA,MACtB,QAAQ;AAAA,QACN,QAAQ,IAAI,IAAI,QAAQ;AAAA,QACxB,kBAAkB,IAAI,IAAI,kBAAkB;AAAA,QAC5C,UAAU,IAAI,IAAI,UAAU;AAAA,QAC5B,WAAW,IAAI,IAAI,WAAW;AAAA,MAChC;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACL,CAAC,EAAE,cAAc;AAAA,EACnB;AACJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/middlewares/common/errorHandler.ts"],"sourcesContent":["import { deepAssignWithOverwrite } from '@homer0/deep-assign';\nimport { middlewareCreator, type Statuses } from '../../utils';\nimport type { DeepPartial, Logger, ExpressErrorHandler } from '../../types';\nimport { AppError, type HTTPErrorClass, type ResponsesBuilder } from '../../services';\n/**\n * The options for the responses the middleware will create.\n *\n * @group Middlewares/ErrorHandler\n */\nexport type ErrorHandlerResponseOptions = {\n /**\n * The message to show in case `showErrors` is set to `false`.\n *\n * @default 'Oops! Something went wrong, please try again'\n * @prettierignore\n */\n message: string;\n /**\n * The default status code for the responses.\n *\n * @default 500\n */\n status: number;\n};\n/**\n * The customization options for the middleware.\n *\n * @group Middlewares/ErrorHandler\n */\nexport type ErrorHandlerOptions = {\n /**\n * If `false`, unknown errors will show a generic message instead of real message. And\n * if `true`, it will not only show all kind of errors but it will also show the error\n * stack.\n *\n * By \"uknown errors\", it means that are not `AppError` nor `HTTPError`.\n */\n showErrors: boolean;\n /**\n * The options for the default response the middleware will create.\n */\n response: ErrorHandlerResponseOptions;\n};\n/**\n * A partial version of the {@link ErrorHandlerOptions}, to be used in the constructor and\n * the middleware creator.\n *\n * @group Middlewares/ErrorHandler\n */\nexport type ErrorHandlerPartialOptions = DeepPartial<ErrorHandlerOptions>;\n/**\n * The options to construct a {@link ErrorHandler}.\n *\n * @group Middlewares/ErrorHandler\n */\nexport type ErrorHandlerConstructorOptions = ErrorHandlerPartialOptions & {\n /**\n * A dictionary with the dependencies to inject.\n */\n inject: {\n logger: Logger;\n responsesBuilder: ResponsesBuilder;\n statuses: Statuses;\n HTTPError: HTTPErrorClass;\n };\n};\n/**\n * Creates a middleware that handles errors and generates the responses.\n *\n * @group Middleware Classes\n * @group Middlewares/ErrorHandler\n * @prettierignore\n */\nexport class ErrorHandler {\n /**\n * The service that will log the messages in the console.\n */\n protected readonly _logger: Logger;\n /**\n * The service to generate the responses.\n */\n protected readonly _responsesBuilder: ResponsesBuilder;\n /**\n * The uility service to get HTTP status codes.\n */\n protected readonly _statuses: Statuses;\n /**\n * The Error class used by the \"known errors\".\n */\n protected readonly _HTTPError: HTTPErrorClass;\n /**\n * The customization options.\n */\n protected readonly _options: ErrorHandlerOptions;\n /**\n * @param options The options to construct the class.\n */\n constructor({\n inject: { logger, responsesBuilder, statuses, HTTPError },\n ...options\n }: ErrorHandlerConstructorOptions) {\n this._logger = logger;\n this._responsesBuilder = responsesBuilder;\n this._statuses = statuses;\n this._HTTPError = HTTPError;\n this._options = deepAssignWithOverwrite(\n {\n showErrors: false,\n response: {\n message: 'Unexpected error',\n status: this._statuses('internal server error'),\n },\n },\n options,\n );\n }\n /**\n * Generates the middleware that handles the errors.\n */\n getMiddleware(): ExpressErrorHandler {\n return (err, _, res, next) => {\n // If there wasn't any error, continue the execution.\n if (!err) {\n next();\n return;\n }\n\n const { response, showErrors } = this._options;\n\n // Define the base status and response.\n let { status } = response;\n let data: {\n error: boolean;\n message: string;\n stack?: string[];\n } & Record<string, unknown> = {\n error: true,\n message: response.message,\n };\n\n const knownError = err instanceof AppError;\n // If it's a \"known error\" or the `showErrors` flag is set to `true`...\n if (showErrors || knownError) {\n // Get the real message.\n data.message = err.message;\n // If it's a \"known error\"...\n if (knownError) {\n // Try to extract information for the response.\n data = {\n ...data,\n ...err.getResponse(),\n };\n status = err.status || (this._statuses('bad request') as number);\n }\n /**\n * If the flag is set to `true`, and it's a \"valid error\", try to extract the\n * stack, format it, and include it in the response.\n */\n if (showErrors && err instanceof Error && err.stack) {\n const stack = err.stack.split('\\n').map((line) => line.trim());\n data.stack = stack;\n stack.splice(0, 1);\n this._logger.error(`ERROR: ${err.message}`);\n this._logger.info(stack);\n }\n }\n\n this._responsesBuilder.json({\n res,\n data,\n status,\n });\n };\n }\n /**\n * The handler customization options.\n */\n get options(): Readonly<ErrorHandlerOptions> {\n return deepAssignWithOverwrite({}, this._options);\n }\n}\n/**\n * Creates the middleware that handles errors.\n *\n * @group Middlewares\n * @group Middlewares/ErrorHandler\n */\nexport const errorHandlerMiddleware = middlewareCreator(\n (options: ErrorHandlerPartialOptions = {}) =>\n (app) => {\n const showErrors = app.getConfig<boolean | undefined>('debug.showErrors') === true;\n return new ErrorHandler({\n inject: {\n logger: app.get('logger'),\n responsesBuilder: app.get('responsesBuilder'),\n statuses: app.get('statuses'),\n HTTPError: app.get('HTTPError'),\n },\n showErrors,\n ...options,\n }).getMiddleware();\n },\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAAwC;AACxC,mBAAiD;AAEjD,sBAAqE;AAsE9D,MAAM,aAAa;AAAA;AAAA;AAAA;AAAA,EAwBxB,YAAY;AAAA,IACV,QAAQ,EAAE,QAAQ,kBAAkB,UAAU,UAAU;AAAA,IACxD,GAAG;AAAA,EACL,GAAmC;AAvBnC;AAAA;AAAA;AAAA,wBAAmB;AAInB;AAAA;AAAA;AAAA,wBAAmB;AAInB;AAAA;AAAA;AAAA,wBAAmB;AAInB;AAAA;AAAA;AAAA,wBAAmB;AAInB;AAAA;AAAA;AAAA,wBAAmB;AAQjB,SAAK,UAAU;AACf,SAAK,oBAAoB;AACzB,SAAK,YAAY;AACjB,SAAK,aAAa;AAClB,SAAK,eAAW;AAAA,MACd;AAAA,QACE,YAAY;AAAA,QACZ,UAAU;AAAA,UACR,SAAS;AAAA,UACT,QAAQ,KAAK,UAAU,uBAAuB;AAAA,QAChD;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAIA,gBAAqC;AACnC,WAAO,CAAC,KAAK,GAAG,KAAK,SAAS;AAE5B,UAAI,CAAC,KAAK;AACR,aAAK;AACL;AAAA,MACF;AAEA,YAAM,EAAE,UAAU,WAAW,IAAI,KAAK;AAGtC,UAAI,EAAE,OAAO,IAAI;AACjB,UAAI,OAI0B;AAAA,QAC5B,OAAO;AAAA,QACP,SAAS,SAAS;AAAA,MACpB;AAEA,YAAM,aAAa,eAAe;AAElC,UAAI,cAAc,YAAY;AAE5B,aAAK,UAAU,IAAI;AAEnB,YAAI,YAAY;AAEd,iBAAO;AAAA,YACL,GAAG;AAAA,YACH,GAAG,IAAI,YAAY;AAAA,UACrB;AACA,mBAAS,IAAI,UAAW,KAAK,UAAU,aAAa;AAAA,QACtD;AAKA,YAAI,cAAc,eAAe,SAAS,IAAI,OAAO;AACnD,gBAAM,QAAQ,IAAI,MAAM,MAAM,IAAI,EAAE,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC;AAC7D,eAAK,QAAQ;AACb,gBAAM,OAAO,GAAG,CAAC;AACjB,eAAK,QAAQ,MAAM,UAAU,IAAI,OAAO,EAAE;AAC1C,eAAK,QAAQ,KAAK,KAAK;AAAA,QACzB;AAAA,MACF;AAEA,WAAK,kBAAkB,KAAK;AAAA,QAC1B;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,UAAyC;AAC3C,eAAO,4CAAwB,CAAC,GAAG,KAAK,QAAQ;AAAA,EAClD;AACF;AAOO,MAAM,6BAAyB;AAAA,EACpC,CAAC,UAAsC,CAAC,MACtC,CAAC,QAAQ;AACP,UAAM,aAAa,IAAI,UAA+B,kBAAkB,MAAM;AAC9E,WAAO,IAAI,aAAa;AAAA,MACtB,QAAQ;AAAA,QACN,QAAQ,IAAI,IAAI,QAAQ;AAAA,QACxB,kBAAkB,IAAI,IAAI,kBAAkB;AAAA,QAC5C,UAAU,IAAI,IAAI,UAAU;AAAA,QAC5B,WAAW,IAAI,IAAI,WAAW;AAAA,MAChC;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACL,CAAC,EAAE,cAAc;AAAA,EACnB;AACJ;","names":[]}
@@ -17,10 +17,7 @@ var __copyProps = (to, from, except, desc) => {
17
17
  return to;
18
18
  };
19
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
- var __publicField = (obj, key, value) => {
21
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
22
- return value;
23
- };
20
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
24
21
  var forceHTTPS_exports = {};
25
22
  __export(forceHTTPS_exports, {
26
23
  ForceHTTPS: () => ForceHTTPS,
@@ -67,8 +64,7 @@ class ForceHTTPS {
67
64
  const forceHTTPSMiddleware = (0, import_utils.middlewareCreator)(
68
65
  (options = {}) => (app) => {
69
66
  const enabled = app.getConfig("forceHTTPS");
70
- if (!enabled)
71
- return void 0;
67
+ if (!enabled) return void 0;
72
68
  return new ForceHTTPS(options).getMiddleware();
73
69
  }
74
70
  );
@@ -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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAkC;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,2BAAuB;AAAA,EAClC,CAAC,UAAoC,CAAC,MACpC,CAAC,QAAQ;AACP,UAAM,UAAU,IAAI,UAA+B,YAAY;AAC/D,QAAI,CAAC;AAAS,aAAO;AACrB,WAAO,IAAI,WAAW,OAAO,EAAE,cAAc;AAAA,EAC/C;AACJ;","names":[]}
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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAkC;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,2BAAuB;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":[]}
@@ -17,10 +17,7 @@ var __copyProps = (to, from, except, desc) => {
17
17
  return to;
18
18
  };
19
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
- var __publicField = (obj, key, value) => {
21
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
22
- return value;
23
- };
20
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
24
21
  var hsts_exports = {};
25
22
  __export(hsts_exports, {
26
23
  HSTS: () => HSTS,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/middlewares/common/hsts.ts"],"sourcesContent":["import { middlewareCreator } from '../../utils';\nimport { ExpressMiddleware } from '../../types';\n/**\n * The options to customize the HSTS header value.\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security}\n * @group Middlewares/HSTS\n */\nexport type HSTSMiddlewareOptions = {\n /**\n * The time, in seconds, that the browser should remember that a site is only to be\n * accessed using HTTPS.\n *\n * @default 31536000\n */\n maxAge: number;\n /**\n * Whether or not the rule should apply to all sub domains.\n *\n * @default true\n */\n includeSubDomains: boolean;\n /**\n * Whether or not to include on the major browsers'\n * preload list. This directive is not part of the specification, for more information\n * about it, you should check the MDN documentation for the header.\n *\n * @default false\n */\n preload: boolean;\n};\n/**\n * A partial version of the {@link HSTSMiddlewareOptions}, to be used in the constructor\n * and the middleware creator.\n *\n * @group Middlewares/HSTS\n */\nexport type HSTSMiddlewarePartialOptions = Partial<HSTSMiddlewareOptions>;\n/**\n * The options for the middleware creator that will create the middleware, or not,\n * depending on the `enabled` option.\n *\n * @group Middlewares/HSTS\n */\nexport type HSTSMiddlewareSettings = HSTSMiddlewarePartialOptions & {\n /**\n * If it's not `true`, it won't return the middleware.\n */\n enabled?: boolean;\n};\n/**\n * Generates a middleware that includes the HSTS header on the responses.\n *\n * @see {@link https://tools.ietf.org/html/rfc6797}\n * @group Middleware Classes\n * @group Middlewares/HSTS\n * @prettierignore\n */\nexport class HSTS {\n /**\n * The customization options for the header.\n */\n protected readonly _options: HSTSMiddlewareOptions;\n /**\n * The value of the header that will be included in the responses.\n */\n protected readonly _header: string;\n /**\n * @param options The options to construct the class.\n */\n constructor(options: HSTSMiddlewarePartialOptions = {}) {\n this._options = {\n maxAge: 31536000,\n includeSubDomains: true,\n preload: false,\n ...options,\n };\n this._header = this._buildHeader();\n }\n /**\n * Generates the middleware that includes the HSTS header on the responses.\n */\n getMiddleware(): ExpressMiddleware {\n return (_, res, next) => {\n res.setHeader('Strict-Transport-Security', this._header);\n next();\n };\n }\n /**\n * The customization options.\n */\n get options(): Readonly<HSTSMiddlewareOptions> {\n return { ...this._options };\n }\n /**\n * The value of the header that will be included in the responses.\n */\n get header(): string {\n return this._header;\n }\n /**\n * Creates the header value based on the customization options.\n */\n protected _buildHeader(): string {\n const { maxAge, includeSubDomains, preload } = this._options;\n const directives = [`max-age=${maxAge}`];\n if (includeSubDomains) {\n directives.push('includeSubDomains');\n }\n\n if (preload) {\n directives.push('preload');\n }\n\n return directives.join('; ');\n }\n}\n/**\n * Creates the middleware that includes the HSTS header on the responses.\n *\n * @group Middlewares\n * @group Middlewares/HSTS\n */\nexport const hstsMiddleware = middlewareCreator(\n (options: HSTSMiddlewareSettings = {}) =>\n (app) => {\n const setting = app.getConfig<HSTSMiddlewareSettings | undefined>('hsts');\n if (\n !setting?.enabled ||\n (typeof options.enabled !== 'undefined' && !options.enabled)\n )\n return undefined;\n return new HSTS(options).getMiddleware();\n },\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAkC;AA0D3B,MAAM,KAAK;AAAA;AAAA;AAAA;AAAA,EAYhB,YAAY,UAAwC,CAAC,GAAG;AARxD;AAAA;AAAA;AAAA,wBAAmB;AAInB;AAAA;AAAA;AAAA,wBAAmB;AAKjB,SAAK,WAAW;AAAA,MACd,QAAQ;AAAA,MACR,mBAAmB;AAAA,MACnB,SAAS;AAAA,MACT,GAAG;AAAA,IACL;AACA,SAAK,UAAU,KAAK,aAAa;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAIA,gBAAmC;AACjC,WAAO,CAAC,GAAG,KAAK,SAAS;AACvB,UAAI,UAAU,6BAA6B,KAAK,OAAO;AACvD,WAAK;AAAA,IACP;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,UAA2C;AAC7C,WAAO,EAAE,GAAG,KAAK,SAAS;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,SAAiB;AACnB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAIU,eAAuB;AAC/B,UAAM,EAAE,QAAQ,mBAAmB,QAAQ,IAAI,KAAK;AACpD,UAAM,aAAa,CAAC,WAAW,MAAM,EAAE;AACvC,QAAI,mBAAmB;AACrB,iBAAW,KAAK,mBAAmB;AAAA,IACrC;AAEA,QAAI,SAAS;AACX,iBAAW,KAAK,SAAS;AAAA,IAC3B;AAEA,WAAO,WAAW,KAAK,IAAI;AAAA,EAC7B;AACF;AAOO,MAAM,qBAAiB;AAAA,EAC5B,CAAC,UAAkC,CAAC,MAClC,CAAC,QAAQ;AACP,UAAM,UAAU,IAAI,UAA8C,MAAM;AACxE,QACE,CAAC,SAAS,WACT,OAAO,QAAQ,YAAY,eAAe,CAAC,QAAQ;AAEpD,aAAO;AACT,WAAO,IAAI,KAAK,OAAO,EAAE,cAAc;AAAA,EACzC;AACJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/middlewares/common/hsts.ts"],"sourcesContent":["import { middlewareCreator } from '../../utils';\nimport { ExpressMiddleware } from '../../types';\n/**\n * The options to customize the HSTS header value.\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security}\n * @group Middlewares/HSTS\n */\nexport type HSTSMiddlewareOptions = {\n /**\n * The time, in seconds, that the browser should remember that a site is only to be\n * accessed using HTTPS.\n *\n * @default 31536000\n */\n maxAge: number;\n /**\n * Whether or not the rule should apply to all sub domains.\n *\n * @default true\n */\n includeSubDomains: boolean;\n /**\n * Whether or not to include on the major browsers'\n * preload list. This directive is not part of the specification, for more information\n * about it, you should check the MDN documentation for the header.\n *\n * @default false\n */\n preload: boolean;\n};\n/**\n * A partial version of the {@link HSTSMiddlewareOptions}, to be used in the constructor\n * and the middleware creator.\n *\n * @group Middlewares/HSTS\n */\nexport type HSTSMiddlewarePartialOptions = Partial<HSTSMiddlewareOptions>;\n/**\n * The options for the middleware creator that will create the middleware, or not,\n * depending on the `enabled` option.\n *\n * @group Middlewares/HSTS\n */\nexport type HSTSMiddlewareSettings = HSTSMiddlewarePartialOptions & {\n /**\n * If it's not `true`, it won't return the middleware.\n */\n enabled?: boolean;\n};\n/**\n * Generates a middleware that includes the HSTS header on the responses.\n *\n * @see {@link https://tools.ietf.org/html/rfc6797}\n * @group Middleware Classes\n * @group Middlewares/HSTS\n * @prettierignore\n */\nexport class HSTS {\n /**\n * The customization options for the header.\n */\n protected readonly _options: HSTSMiddlewareOptions;\n /**\n * The value of the header that will be included in the responses.\n */\n protected readonly _header: string;\n /**\n * @param options The options to construct the class.\n */\n constructor(options: HSTSMiddlewarePartialOptions = {}) {\n this._options = {\n maxAge: 31536000,\n includeSubDomains: true,\n preload: false,\n ...options,\n };\n this._header = this._buildHeader();\n }\n /**\n * Generates the middleware that includes the HSTS header on the responses.\n */\n getMiddleware(): ExpressMiddleware {\n return (_, res, next) => {\n res.setHeader('Strict-Transport-Security', this._header);\n next();\n };\n }\n /**\n * The customization options.\n */\n get options(): Readonly<HSTSMiddlewareOptions> {\n return { ...this._options };\n }\n /**\n * The value of the header that will be included in the responses.\n */\n get header(): string {\n return this._header;\n }\n /**\n * Creates the header value based on the customization options.\n */\n protected _buildHeader(): string {\n const { maxAge, includeSubDomains, preload } = this._options;\n const directives = [`max-age=${maxAge}`];\n if (includeSubDomains) {\n directives.push('includeSubDomains');\n }\n\n if (preload) {\n directives.push('preload');\n }\n\n return directives.join('; ');\n }\n}\n/**\n * Creates the middleware that includes the HSTS header on the responses.\n *\n * @group Middlewares\n * @group Middlewares/HSTS\n */\nexport const hstsMiddleware = middlewareCreator(\n (options: HSTSMiddlewareSettings = {}) =>\n (app) => {\n const setting = app.getConfig<HSTSMiddlewareSettings | undefined>('hsts');\n if (\n !setting?.enabled ||\n (typeof options.enabled !== 'undefined' && !options.enabled)\n )\n return undefined;\n return new HSTS(options).getMiddleware();\n },\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAkC;AA0D3B,MAAM,KAAK;AAAA;AAAA;AAAA;AAAA,EAYhB,YAAY,UAAwC,CAAC,GAAG;AARxD;AAAA;AAAA;AAAA,wBAAmB;AAInB;AAAA;AAAA;AAAA,wBAAmB;AAKjB,SAAK,WAAW;AAAA,MACd,QAAQ;AAAA,MACR,mBAAmB;AAAA,MACnB,SAAS;AAAA,MACT,GAAG;AAAA,IACL;AACA,SAAK,UAAU,KAAK,aAAa;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAIA,gBAAmC;AACjC,WAAO,CAAC,GAAG,KAAK,SAAS;AACvB,UAAI,UAAU,6BAA6B,KAAK,OAAO;AACvD,WAAK;AAAA,IACP;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,UAA2C;AAC7C,WAAO,EAAE,GAAG,KAAK,SAAS;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,SAAiB;AACnB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAIU,eAAuB;AAC/B,UAAM,EAAE,QAAQ,mBAAmB,QAAQ,IAAI,KAAK;AACpD,UAAM,aAAa,CAAC,WAAW,MAAM,EAAE;AACvC,QAAI,mBAAmB;AACrB,iBAAW,KAAK,mBAAmB;AAAA,IACrC;AAEA,QAAI,SAAS;AACX,iBAAW,KAAK,SAAS;AAAA,IAC3B;AAEA,WAAO,WAAW,KAAK,IAAI;AAAA,EAC7B;AACF;AAOO,MAAM,qBAAiB;AAAA,EAC5B,CAAC,UAAkC,CAAC,MAClC,CAAC,QAAQ;AACP,UAAM,UAAU,IAAI,UAA8C,MAAM;AACxE,QACE,CAAC,SAAS,WACT,OAAO,QAAQ,YAAY,eAAe,CAAC,QAAQ;AAEpD,aAAO;AACT,WAAO,IAAI,KAAK,OAAO,EAAE,cAAc;AAAA,EACzC;AACJ;","names":[]}
@@ -17,10 +17,7 @@ var __copyProps = (to, from, except, desc) => {
17
17
  return to;
18
18
  };
19
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
- var __publicField = (obj, key, value) => {
21
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
22
- return value;
23
- };
20
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
24
21
  var fastHTML_exports = {};
25
22
  __export(fastHTML_exports, {
26
23
  FastHTML: () => FastHTML,
@@ -142,8 +139,7 @@ class FastHTML {
142
139
  (acc, route) => {
143
140
  const [expressions, processed] = acc;
144
141
  const clean = (0, import_utils.removeSlashes)(route).trim();
145
- if (!clean || processed.includes(clean))
146
- return acc;
142
+ if (!clean || processed.includes(clean)) return acc;
147
143
  expressions.push((0, import_utils.createRouteExpression)(clean));
148
144
  processed.push(clean);
149
145
  return acc;