plugin-utils.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import { notNullOrUndefined } from '@vendure/common/lib/shared-utils';
  2. import { RequestHandler } from 'express';
  3. import proxy from 'http-proxy-middleware';
  4. import { APIExtensionDefinition, Logger, VendureConfig, VendurePlugin } from '../config';
  5. /**
  6. * @description
  7. * Options to configure proxy middleware via {@link createProxyHandler}.
  8. *
  9. * @docsCategory Plugin
  10. */
  11. export interface ProxyOptions {
  12. /**
  13. * @description
  14. * A human-readable label for the service which is being proxied. Used to
  15. * generate more informative logs.
  16. */
  17. label: string;
  18. /**
  19. * @description
  20. * The route of the Vendure server which will act as the proxy url.
  21. */
  22. route: string;
  23. /**
  24. * @description
  25. * The port on which the service being proxied is running.
  26. */
  27. port: number;
  28. /**
  29. * @description
  30. * The hostname of the server on which the service being proxied is running.
  31. *
  32. * @default 'localhost'
  33. */
  34. hostname?: string;
  35. }
  36. /**
  37. * @description
  38. * Creates a proxy middleware which proxies the given route to the given port.
  39. * Useful for plugins which start their own servers but should be accessible
  40. * via the main Vendure url.
  41. *
  42. * @example
  43. * ```ts
  44. * // Example usage in the `configure` method of a VendurePlugin.
  45. * // Imagine that we have started a Node server on port 5678
  46. * // running some service which we want to access via the `/my-plugin/`
  47. * // route of the main Vendure server.
  48. * configure(config: Required<VendureConfig>): Required<VendureConfig> {
  49. * config.middleware.push({
  50. * handler: createProxyHandler({
  51. * label: 'Admin UI',
  52. * route: 'my-plugin',
  53. * port: 5678,
  54. * }),
  55. * route: 'my-plugin',
  56. * });
  57. * return config;
  58. * }
  59. * ```
  60. *
  61. * @docsCategory Plugin
  62. */
  63. export function createProxyHandler(options: ProxyOptions): RequestHandler {
  64. const route = options.route.charAt(0) === '/' ? options.route : '/' + options.route;
  65. const proxyHostname = options.hostname || 'localhost';
  66. const middleware = proxy({
  67. // TODO: how do we detect https?
  68. target: `http://${proxyHostname}:${options.port}`,
  69. pathRewrite: {
  70. [`^${route}`]: `/`,
  71. },
  72. logProvider(provider: proxy.LogProvider): proxy.LogProvider {
  73. return {
  74. log(message: string) {
  75. Logger.debug(message, options.label);
  76. },
  77. debug(message: string) {
  78. Logger.debug(message, options.label);
  79. },
  80. info(message: string) {
  81. Logger.debug(message, options.label);
  82. },
  83. warn(message: string) {
  84. Logger.warn(message, options.label);
  85. },
  86. error(message: string) {
  87. Logger.error(message, options.label);
  88. },
  89. };
  90. },
  91. });
  92. // Attach the options to the middleware function to allow
  93. // the info to be logged after bootstrap.
  94. (middleware as any).proxyMiddleware = options;
  95. return middleware;
  96. }
  97. /**
  98. * If any proxy middleware has been set up using the createProxyHandler function, log this information.
  99. */
  100. export function logProxyMiddlewares(config: VendureConfig) {
  101. for (const middleware of config.middleware || []) {
  102. if ((middleware.handler as any).proxyMiddleware) {
  103. const { port, hostname, label, route } = (middleware.handler as any).proxyMiddleware as ProxyOptions;
  104. Logger.info(`${label}: http://${config.hostname || 'localhost'}:${config.port}/${route}/ -> http://${hostname || 'localhost'}:${port}`);
  105. }
  106. }
  107. }
  108. /**
  109. * Given an array of VendurePlugins, returns a flattened array of all APIExtensionDefinitions.
  110. */
  111. export function getPluginAPIExtensions(
  112. plugins: VendurePlugin[],
  113. apiType: 'shop' | 'admin',
  114. ): APIExtensionDefinition[] {
  115. const extensions =
  116. apiType === 'shop'
  117. ? plugins.map(p => (p.extendShopAPI ? p.extendShopAPI() : undefined))
  118. : plugins.map(p => (p.extendAdminAPI ? p.extendAdminAPI() : undefined));
  119. return extensions.filter(notNullOrUndefined);
  120. }