@sap-ux/ui5-proxy-middleware 1.5.12 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,14 +3,17 @@
3
3
  The `@sap-ux/ui5-proxy-middleware` is a [Custom UI5 Server Middleware](https://sap.github.io/ui5-tooling/pages/extensibility/CustomServerMiddleware) for loading the UI5 sources in your application. It can be used either with the `ui5 serve` or the `fiori run` commands.
4
4
 
5
5
  ## Configuration Options
6
- | Option | Default Value | Description |
7
- | ------------ | ------------- | ----------- |
8
- | `ui5` | `object` | List of mount paths and target urls that should be handled by the proxy. If not provided then `/resources` and `/test-resources` are proxied to `https://ui5.sap.com` |
9
- | `version` | `undefined` | The UI5 version. If this property is not defined, then the `minUI5Version` from the `manifest.json` will be used |
10
- | `secure` | true | Defines if SSL certs should be verified |
11
- | `debug` | false | Enables debug output |
12
- | `proxy` | `undefined` | Use for adding corporate proxy configuration |
13
- | `directLoad` | false | Defines whether the UI5 sources should be loaded directly from UI5 CDN |
6
+ | Option | Value Type | Requirement Type | Default Value | Description |
7
+ | ------------ | ------------- |------------- | ----------- |----------- |
8
+ | `ui5` | object | optional | --- | Configuration object for the UI5 proxy middleware |
9
+ | `ui5.path` | string | optional | `/resources`, `/test-resources` | Path that is to be proxied |
10
+ | `ui5.url` | string | optional |`https://ui5.sap.com` | URL pointing to the resources |
11
+ | `ui5.pathReplace`| string | optional | `undefined` | If provided then the path will be replaced with this value before forwarding |
12
+ | `ui5.version` | string | optional |`undefined` | The UI5 version. If this property is not defined, then the `minUI5Version` from the `manifest.json` will be used |
13
+ | `secure` | boolean | optional | true | Defines if SSL certs should be verified |
14
+ | `debug` | boolean | optional | false | Enables debug output |
15
+ | `proxy` | string | optional | `undefined` | Use for adding corporate proxy configuration |
16
+ | `directLoad` | boolean | optional | false | Defines whether the UI5 sources should be loaded directly from UI5 CDN |
14
17
 
15
18
  ## Usage
16
19
  In order to use the middleware this is the minimal configuration that you need to provide in the `ui5.yaml` of your application. All requests to `/resources` and `/test-resources` will be proxied to the latest UI5 version at https://ui5.sap.com.
@@ -40,7 +43,7 @@ server:
40
43
  url: https://ui5.sap.com
41
44
  ```
42
45
 
43
- Alternatively you can use the following syntax if all paths should be proxied to the same url.
46
+ Alternatively you can use the following syntax if all paths should be proxied to the same URL.
44
47
 
45
48
  ```Yaml
46
49
  server:
@@ -54,10 +57,11 @@ server:
54
57
  - /test-resources
55
58
  url: https://ui5.sap.com
56
59
  ```
57
- **NOTE: You can't mix both syntaxes!**
60
+
61
+ **NOTE: You can't mix the syntaxes!**
58
62
 
59
63
  ### Loading a specific UI5 version
60
- To load a specific a UI5 version in your application you can use the `version` parameter, e.g.
64
+ To load a specific UI5 version in your application you can use the `version` parameter, e.g.
61
65
 
62
66
  ```Yaml
63
67
  server:
@@ -92,6 +96,23 @@ server:
92
96
  directLoad: true
93
97
  ```
94
98
 
99
+ ### Loading UI5 sources from a different Host
100
+ If you want to load UI5 sources from a different host, then you can set the property `pathReplace` to point to the desired resources. If provided then the `path` will be replaced with this value before forwarding.
101
+
102
+ **NOTE: using `pathReplace` will not consider a specified UI5 version. If a specific UI5 version is needed, then it needs to be part of the `pathReplace`.**
103
+
104
+ ```Yaml
105
+ server:
106
+ customMiddleware:
107
+ - name: ui5-proxy-middleware
108
+ afterMiddleware: compression
109
+ configuration:
110
+ ui5:
111
+ - path: /resources
112
+ url: https://my.backend.example:1234
113
+ pathReplace: /sap/public/ui5/resources
114
+ ```
115
+
95
116
  ### Adding corporate proxy configuration
96
117
  By default the `ui5-proxy-middleware` will read the proxy configuration from the OS environment variables `HTTP_PROXY`, `HTTPS_PROXY` and `NO_PROXY` or from the Node.js environment variables `proxy`, `https-proxy`, and `noproxy`. If those variables are not set, then you can also provide the proxy configuration in the `ui5.yaml` file.
97
118
 
@@ -1,12 +1,15 @@
1
1
  import type { Filter, Options } from 'http-proxy-middleware';
2
+ import type { IncomingMessage, ServerResponse } from 'http';
2
3
  import type { ProxyConfig } from './types';
4
+ import { ToolsLogger } from '@sap-ux/logger';
3
5
  /**
4
6
  * Function for proxying UI5 sources.
5
7
  *
6
8
  * @param config - proxy configuration
7
9
  * @param options - additional configuration options
8
10
  * @param filter - custom filter function which will be applied to all requests
11
+ * @param logger - optional logger instance
9
12
  * @returns Proxy function to use
10
13
  */
11
- export declare const ui5Proxy: (config: ProxyConfig, options?: Options, filter?: Filter) => import("http-proxy-middleware").RequestHandler;
14
+ export declare const ui5Proxy: (config: ProxyConfig, options?: Options, filter?: Filter, logger?: ToolsLogger) => import("http-proxy-middleware").RequestHandler<IncomingMessage, ServerResponse<IncomingMessage>, (err?: any) => void>;
12
15
  //# sourceMappingURL=proxy.d.ts.map
@@ -12,28 +12,36 @@ const https_proxy_agent_1 = require("https-proxy-agent");
12
12
  * @param config - proxy configuration
13
13
  * @param options - additional configuration options
14
14
  * @param filter - custom filter function which will be applied to all requests
15
+ * @param logger - optional logger instance
15
16
  * @returns Proxy function to use
16
17
  */
17
- const ui5Proxy = (config, options, filter) => {
18
- const logger = new logger_1.ToolsLogger({
19
- transports: [new logger_1.UI5ToolingTransport({ moduleName: 'ui5-proxy-middleware' })]
20
- });
18
+ const ui5Proxy = (config, options, filter, logger = new logger_1.ToolsLogger({
19
+ transports: [new logger_1.UI5ToolingTransport({ moduleName: 'ui5-proxy-middleware' })]
20
+ })) => {
21
21
  const today = new Date();
22
22
  const etag = `W/"${config.version || 'ui5-latest-' + today.getDate() + today.getMonth() + today.getFullYear()}"`;
23
23
  const ui5Ver = config.version ? `/${config.version}` : '';
24
+ let proxyFilter = utils_1.filterCompressedHtmlFiles;
25
+ if (filter) {
26
+ proxyFilter = filter;
27
+ }
24
28
  const proxyConfig = {
29
+ on: {
30
+ proxyReq: (proxyReq, _req, res) => {
31
+ (0, utils_1.proxyRequestHandler)(proxyReq, res, etag);
32
+ },
33
+ proxyRes: (proxyRes) => {
34
+ (0, utils_1.proxyResponseHandler)(proxyRes, etag);
35
+ },
36
+ error: (err, req, res, target) => {
37
+ (0, utils_1.proxyErrorHandler)(err, req, logger, res, target);
38
+ }
39
+ },
25
40
  target: config.url,
26
41
  changeOrigin: true,
27
- onProxyReq: (proxyReq, _req, res) => {
28
- (0, utils_1.proxyRequestHandler)(proxyReq, res, etag, logger);
29
- },
30
- pathRewrite: { [config.path]: ui5Ver + config.path },
31
- onProxyRes: (proxyRes) => {
32
- (0, utils_1.proxyResponseHandler)(proxyRes, etag);
33
- },
34
- onError: (err, req, res, target) => {
35
- (0, utils_1.proxyErrorHandler)(err, req, logger, res, target);
36
- }
42
+ pathRewrite: (0, utils_1.getPathRewrite)(config, ui5Ver),
43
+ pathFilter: proxyFilter,
44
+ ...options
37
45
  };
38
46
  // update proxy config with values coming from args or ui5.yaml
39
47
  (0, utils_1.updateProxyEnv)(config.proxy);
@@ -41,12 +49,7 @@ const ui5Proxy = (config, options, filter) => {
41
49
  if (corporateProxy) {
42
50
  proxyConfig.agent = new https_proxy_agent_1.HttpsProxyAgent(corporateProxy);
43
51
  }
44
- Object.assign(proxyConfig, options);
45
- let proxyFilter = utils_1.filterCompressedHtmlFiles;
46
- if (filter) {
47
- proxyFilter = filter;
48
- }
49
- return (0, http_proxy_middleware_1.createProxyMiddleware)(proxyFilter, proxyConfig);
52
+ return (0, http_proxy_middleware_1.createProxyMiddleware)(proxyConfig);
50
53
  };
51
54
  exports.ui5Proxy = ui5Proxy;
52
55
  //# sourceMappingURL=proxy.js.map
@@ -1,9 +1,25 @@
1
1
  import type { NextFunction } from 'express';
2
2
  import type { IncomingMessage } from 'http';
3
3
  export interface ProxyConfig {
4
+ /**
5
+ * Path that is to be proxied.
6
+ */
4
7
  path: string;
8
+ /**
9
+ * If provided then the path will be replaced with this value before forwarding.
10
+ */
11
+ pathReplace?: string;
12
+ /**
13
+ * The target URL to proxy the request to.
14
+ */
5
15
  url: string;
16
+ /**
17
+ * If provided then the proxy will try to load the specified version of UI5 resources.
18
+ */
6
19
  version?: string;
20
+ /**
21
+ * If set then it will override the proxy settings from node.
22
+ */
7
23
  proxy?: string;
8
24
  }
9
25
  export interface UI5ProxyRequest {
@@ -1,4 +1,5 @@
1
1
  import type { ClientRequest, IncomingMessage, ServerResponse } from 'http';
2
+ import type { Options } from 'http-proxy-middleware';
2
3
  import type { ToolsLogger } from '@sap-ux/logger';
3
4
  import { type Manifest } from '@sap-ux/project-access';
4
5
  import type { RequestHandler, NextFunction, Request, Response } from 'express';
@@ -6,6 +7,7 @@ import type http from 'http';
6
7
  import type { ProxyConfig } from './types';
7
8
  import type { Url } from 'url';
8
9
  import type { ReaderCollection } from '@ui5/fs';
10
+ import type { Socket } from 'node:net';
9
11
  /**
10
12
  * Handler for the proxy response event.
11
13
  * Sets an Etag which will be used for re-validation of the cached UI5 sources.
@@ -22,9 +24,8 @@ export declare const proxyResponseHandler: (proxyRes: IncomingMessage, etag: str
22
24
  * @param proxyReq - proxy request object
23
25
  * @param res - server response object
24
26
  * @param etag - Etag of the cached UI5 sources, normally the UI5 version
25
- * @param logger - Logger for loging the requests
26
27
  */
27
- export declare const proxyRequestHandler: (proxyReq: ClientRequest, res: ServerResponse, etag: string, logger: ToolsLogger) => void;
28
+ export declare const proxyRequestHandler: (proxyReq: ClientRequest, res: ServerResponse, etag: string) => void;
28
29
  /**
29
30
  * Get user's proxy configuration.
30
31
  *
@@ -94,8 +95,9 @@ export declare function injectUI5Url(originalHtml: string, ui5Configs: ProxyConf
94
95
  * @param next - the next function, used to forward the request to the next available handler
95
96
  * @param ui5Configs - the UI5 configuration of the ui5-proxy-middleware
96
97
  * @param rootProject - the root project
98
+ * @param logger - logger to be used
97
99
  */
98
- export declare const injectScripts: (req: Request, res: Response, next: NextFunction, ui5Configs: ProxyConfig[], rootProject: ReaderCollection) => Promise<void>;
100
+ export declare const injectScripts: (req: Request, res: Response, next: NextFunction, ui5Configs: ProxyConfig[], rootProject: ReaderCollection, logger?: ToolsLogger) => Promise<void>;
99
101
  /**
100
102
  * Filters comressed html files from UI5 CDN.
101
103
  * Avoid ERR_CONTENT_DECODING_FAILED on http request for gzip'd html files.
@@ -120,7 +122,7 @@ export declare function proxyErrorHandler(err: Error & {
120
122
  }, req: IncomingMessage & {
121
123
  next?: Function;
122
124
  originalUrl?: string;
123
- }, logger: ToolsLogger, _res?: ServerResponse, _target?: string | Partial<Url>): void;
125
+ }, logger: ToolsLogger, _res?: ServerResponse | Socket, _target?: string | Partial<Url>): void;
124
126
  /**
125
127
  * Adjust UI5 bootstrap URLs to load directly from UI5 CDN.
126
128
  *
@@ -130,4 +132,12 @@ export declare function proxyErrorHandler(err: Error & {
130
132
  * @returns RequestHandler to adjust bootstraps
131
133
  */
132
134
  export declare function directLoadProxy(ui5Configs: ProxyConfig[], rootProject: ReaderCollection, logger: ToolsLogger): RequestHandler;
135
+ /**
136
+ * Create a rewrite based on the provided configuration.
137
+ *
138
+ * @param config proxy configuration
139
+ * @param ui5Ver UI5 version string
140
+ * @returns a path rewrite
141
+ */
142
+ export declare function getPathRewrite(config: ProxyConfig, ui5Ver: string): Options['pathRewrite'];
133
143
  //# sourceMappingURL=utils.d.ts.map
@@ -6,6 +6,7 @@ exports.resolveUI5Version = resolveUI5Version;
6
6
  exports.injectUI5Url = injectUI5Url;
7
7
  exports.proxyErrorHandler = proxyErrorHandler;
8
8
  exports.directLoadProxy = directLoadProxy;
9
+ exports.getPathRewrite = getPathRewrite;
9
10
  const project_access_1 = require("@sap-ux/project-access");
10
11
  const constants_1 = require("./constants");
11
12
  const i18n_1 = require("../i18n");
@@ -29,10 +30,8 @@ exports.proxyResponseHandler = proxyResponseHandler;
29
30
  * @param proxyReq - proxy request object
30
31
  * @param res - server response object
31
32
  * @param etag - Etag of the cached UI5 sources, normally the UI5 version
32
- * @param logger - Logger for loging the requests
33
33
  */
34
- const proxyRequestHandler = (proxyReq, res, etag, logger) => {
35
- logger.debug(proxyReq.path);
34
+ const proxyRequestHandler = (proxyReq, res, etag) => {
36
35
  if (proxyReq.getHeader('if-none-match') === etag) {
37
36
  res.statusCode = 304;
38
37
  res.end();
@@ -232,12 +231,14 @@ function injectUI5Url(originalHtml, ui5Configs) {
232
231
  * @param next - the next function, used to forward the request to the next available handler
233
232
  * @param ui5Configs - the UI5 configuration of the ui5-proxy-middleware
234
233
  * @param rootProject - the root project
234
+ * @param logger - logger to be used
235
235
  */
236
- const injectScripts = async (req, res, next, ui5Configs, rootProject) => {
236
+ const injectScripts = async (req, res, next, ui5Configs, rootProject, logger) => {
237
237
  try {
238
238
  const htmlFileName = (0, exports.getHtmlFile)(req.url);
239
239
  const files = await rootProject.byGlob(`**/${htmlFileName}`);
240
240
  if (files.length === 0) {
241
+ logger?.warn('No HTML file found for direct load injection.');
241
242
  next();
242
243
  }
243
244
  else {
@@ -302,7 +303,7 @@ function proxyErrorHandler(err, req, logger, _res, _target) {
302
303
  function directLoadProxy(ui5Configs, rootProject, logger) {
303
304
  return async (req, res, next) => {
304
305
  try {
305
- await (0, exports.injectScripts)(req, res, next, ui5Configs, rootProject);
306
+ await (0, exports.injectScripts)(req, res, next, ui5Configs, rootProject, logger);
306
307
  }
307
308
  catch (error) {
308
309
  logger.error(error);
@@ -310,4 +311,19 @@ function directLoadProxy(ui5Configs, rootProject, logger) {
310
311
  }
311
312
  };
312
313
  }
314
+ /**
315
+ * Create a rewrite based on the provided configuration.
316
+ *
317
+ * @param config proxy configuration
318
+ * @param ui5Ver UI5 version string
319
+ * @returns a path rewrite
320
+ */
321
+ function getPathRewrite(config, ui5Ver) {
322
+ if (config.pathReplace) {
323
+ // Remove trailing slash from pathReplace if present
324
+ const sanitizedPathReplace = config.pathReplace?.replace(/\/$/, '');
325
+ return (path) => path.replace(config.path, sanitizedPathReplace);
326
+ }
327
+ return (path) => (path.startsWith(config.path) ? ui5Ver + path : ui5Ver + config.path + path);
328
+ }
313
329
  //# sourceMappingURL=utils.js.map
@@ -17,8 +17,7 @@ const dotenv_1 = __importDefault(require("dotenv"));
17
17
  function createProxyOptions(logger, config) {
18
18
  return {
19
19
  secure: config.secure !== undefined ? !!config.secure : true,
20
- logLevel: config.debug ? 'debug' : 'info',
21
- logProvider: () => logger
20
+ logger: config.debug ? logger : undefined
22
21
  };
23
22
  }
24
23
  /**
@@ -51,6 +50,7 @@ async function loadManifest(rootProject) {
51
50
  }
52
51
  module.exports = async ({ resources, options }) => {
53
52
  const logger = new logger_1.ToolsLogger({
53
+ logLevel: options.configuration?.debug ? logger_1.LogLevel.Debug : logger_1.LogLevel.Info,
54
54
  transports: [new logger_1.UI5ToolingTransport({ moduleName: 'ui5-proxy-middleware' })]
55
55
  });
56
56
  dotenv_1.default.config();
@@ -76,7 +76,7 @@ module.exports = async ({ resources, options }) => {
76
76
  // hide user and pass from proxy configuration for displaying it in the terminal
77
77
  const proxyInfo = (0, base_1.hideProxyCredentials)(corporateProxyServer);
78
78
  const proxyOptions = createProxyOptions(logger, config);
79
- logger.info(`Starting ui5-proxy-middleware using following configuration:\nproxy: '${proxyInfo}'\nsecure: '${proxyOptions.secure}'\nlog: '${proxyOptions.logLevel}''\ndirectLoad: '${directLoad}'`);
79
+ logger.info(`Starting ui5-proxy-middleware using following configuration:\nproxy: '${proxyInfo}'\nsecure: '${proxyOptions.secure}'\nlog: '${config.debug ? 'debug' : 'info'}' \ndirectLoad: '${directLoad}'`);
80
80
  const configs = Array.isArray(config.ui5) ? config.ui5 : [config.ui5];
81
81
  const ui5Configs = [];
82
82
  const routes = [];
@@ -89,7 +89,7 @@ module.exports = async ({ resources, options }) => {
89
89
  version: ui5Version,
90
90
  proxy: config.proxy
91
91
  };
92
- routes.push({ route: ui5Config.path, handler: (0, base_1.ui5Proxy)(ui5Config, proxyOptions) });
92
+ routes.push({ route: ui5Config.path, handler: (0, base_1.ui5Proxy)(ui5Config, proxyOptions, undefined, logger) });
93
93
  ui5Configs.push(ui5Config);
94
94
  }
95
95
  }
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "bugs": {
10
10
  "url": "https://github.com/SAP/open-ux-tools/issues?q=is%3Aopen+is%3Aissue+label%3Abug+label%3Aui5-proxy-middleware"
11
11
  },
12
- "version": "1.5.12",
12
+ "version": "1.6.1",
13
13
  "license": "Apache-2.0",
14
14
  "author": "@SAP/ux-tools-team",
15
15
  "main": "dist/index.js",
@@ -22,7 +22,7 @@
22
22
  ],
23
23
  "dependencies": {
24
24
  "dotenv": "16.3.1",
25
- "http-proxy-middleware": "2.0.9",
25
+ "http-proxy-middleware": "3.0.5",
26
26
  "https-proxy-agent": "5.0.1",
27
27
  "i18next": "25.3.0",
28
28
  "proxy-from-env": "1.1.0",