@sap-ux/backend-proxy-middleware 0.9.19 → 0.10.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/dist/base/proxy.d.ts +11 -8
- package/dist/base/proxy.js +26 -17
- package/dist/base/types.d.ts +1 -0
- package/dist/ext/bsp.js +9 -6
- package/dist/middleware.js +9 -10
- package/package.json +8 -6
package/dist/base/proxy.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import type { ServerOptions } from 'http-proxy';
|
|
2
2
|
import type { RequestHandler, Options } from 'http-proxy-middleware';
|
|
3
3
|
import type { ClientRequest, IncomingMessage, ServerResponse } from 'http';
|
|
4
|
-
import type
|
|
5
|
-
import { ToolsLogger } from '@sap-ux/logger';
|
|
4
|
+
import { ToolsLogger, type Logger } from '@sap-ux/logger';
|
|
6
5
|
import type { BackendConfig, DestinationBackendConfig } from './types';
|
|
7
6
|
import type { BackendSystem } from '@sap-ux/store';
|
|
8
|
-
import type { Url } from 'url';
|
|
7
|
+
import type { Url } from 'node:url';
|
|
8
|
+
import type { Socket } from 'node:net';
|
|
9
|
+
import type { Request } from 'express';
|
|
10
|
+
import type connect from 'connect';
|
|
11
|
+
export type EnhancedIncomingMessage = (IncomingMessage & Pick<Request, 'originalUrl'>) | connect.IncomingMessage;
|
|
9
12
|
/**
|
|
10
13
|
* Collection of custom event handler for the proxy.
|
|
11
14
|
*/
|
|
@@ -18,7 +21,7 @@ export declare const ProxyEventHandlers: {
|
|
|
18
21
|
* @param _res (not used)
|
|
19
22
|
* @param _options (not used)
|
|
20
23
|
*/
|
|
21
|
-
|
|
24
|
+
proxyReq(proxyReq: ClientRequest, _req?: IncomingMessage, _res?: ServerResponse, _options?: ServerOptions): void;
|
|
22
25
|
/**
|
|
23
26
|
* Retrieve the set-cookie headers from the response and transform secure cookies to insecure ones.
|
|
24
27
|
*
|
|
@@ -26,7 +29,7 @@ export declare const ProxyEventHandlers: {
|
|
|
26
29
|
* @param _req (not used) original request
|
|
27
30
|
* @param _res (not used)
|
|
28
31
|
*/
|
|
29
|
-
|
|
32
|
+
proxyRes(proxyRes: IncomingMessage, _req?: IncomingMessage, _res?: ServerResponse): void;
|
|
30
33
|
};
|
|
31
34
|
/**
|
|
32
35
|
* Specifically handling errors due to unsigned certificates and empty errors.
|
|
@@ -42,13 +45,13 @@ export declare function proxyErrorHandler(err: Error & {
|
|
|
42
45
|
}, req: IncomingMessage & {
|
|
43
46
|
next?: Function;
|
|
44
47
|
originalUrl?: string;
|
|
45
|
-
}, logger: ToolsLogger, _res?: ServerResponse, _target?: string | Partial<Url>): void;
|
|
48
|
+
}, logger: ToolsLogger, _res?: ServerResponse | Socket, _target?: string | Partial<Url>): void;
|
|
46
49
|
/**
|
|
47
50
|
* Collection of path rewrite functions.
|
|
48
51
|
*/
|
|
49
52
|
export declare const PathRewriters: {
|
|
50
53
|
/**
|
|
51
|
-
* Generates a rewrite
|
|
54
|
+
* Generates a rewrite function that replaces the matched string with the prefix in the given string.
|
|
52
55
|
*
|
|
53
56
|
* @param match part of the path that is to be replaced
|
|
54
57
|
* @param prefix new path that is used as replacement
|
|
@@ -69,7 +72,7 @@ export declare const PathRewriters: {
|
|
|
69
72
|
* @param log logger instance
|
|
70
73
|
* @returns a path rewrite function
|
|
71
74
|
*/
|
|
72
|
-
getPathRewrite(config: BackendConfig, log: Logger): (
|
|
75
|
+
getPathRewrite(config: BackendConfig, log: Logger): (path: string, req: IncomingMessage) => string;
|
|
73
76
|
};
|
|
74
77
|
/**
|
|
75
78
|
* Initialize i18next with the translations for this module.
|
package/dist/base/proxy.js
CHANGED
|
@@ -33,7 +33,7 @@ exports.ProxyEventHandlers = {
|
|
|
33
33
|
* @param _res (not used)
|
|
34
34
|
* @param _options (not used)
|
|
35
35
|
*/
|
|
36
|
-
|
|
36
|
+
proxyReq(proxyReq, _req, _res, _options) {
|
|
37
37
|
if (proxyReq.path?.includes('Fiorilaunchpad.html') && !proxyReq.headersSent) {
|
|
38
38
|
proxyReq.setHeader('accept-encoding', '*');
|
|
39
39
|
}
|
|
@@ -45,7 +45,7 @@ exports.ProxyEventHandlers = {
|
|
|
45
45
|
* @param _req (not used) original request
|
|
46
46
|
* @param _res (not used)
|
|
47
47
|
*/
|
|
48
|
-
|
|
48
|
+
proxyRes(proxyRes, _req, _res) {
|
|
49
49
|
const header = proxyRes?.headers?.['set-cookie'];
|
|
50
50
|
if (header?.length) {
|
|
51
51
|
for (let i = header.length - 1; i >= 0; i--) {
|
|
@@ -108,7 +108,7 @@ async function getApiHubKey(logger) {
|
|
|
108
108
|
*/
|
|
109
109
|
exports.PathRewriters = {
|
|
110
110
|
/**
|
|
111
|
-
* Generates a rewrite
|
|
111
|
+
* Generates a rewrite function that replaces the matched string with the prefix in the given string.
|
|
112
112
|
*
|
|
113
113
|
* @param match part of the path that is to be replaced
|
|
114
114
|
* @param prefix new path that is used as replacement
|
|
@@ -143,6 +143,11 @@ exports.PathRewriters = {
|
|
|
143
143
|
*/
|
|
144
144
|
getPathRewrite(config, log) {
|
|
145
145
|
const functions = [];
|
|
146
|
+
functions.push((path, req) => {
|
|
147
|
+
// ensure that the path starts with the configured path
|
|
148
|
+
// it might get lost when you nest router instances
|
|
149
|
+
return req.originalUrl?.includes(path) ? req.originalUrl : path;
|
|
150
|
+
});
|
|
146
151
|
if (config.pathReplace) {
|
|
147
152
|
functions.push(exports.PathRewriters.replacePrefix(config.path, config.pathReplace));
|
|
148
153
|
}
|
|
@@ -150,9 +155,11 @@ exports.PathRewriters = {
|
|
|
150
155
|
functions.push(exports.PathRewriters.replaceClient(config.client));
|
|
151
156
|
}
|
|
152
157
|
if (functions.length > 0) {
|
|
153
|
-
return (path) => {
|
|
158
|
+
return (path, req) => {
|
|
154
159
|
let newPath = path;
|
|
155
|
-
|
|
160
|
+
for (const func of functions) {
|
|
161
|
+
newPath = func(newPath, req);
|
|
162
|
+
}
|
|
156
163
|
if (newPath !== path) {
|
|
157
164
|
log.info(`Rewrite path ${path} > ${newPath}`);
|
|
158
165
|
}
|
|
@@ -210,7 +217,7 @@ async function enhanceConfigsForDestination(proxyOptions, backend) {
|
|
|
210
217
|
}
|
|
211
218
|
}
|
|
212
219
|
else {
|
|
213
|
-
throw new Error();
|
|
220
|
+
throw new Error('Destination not found. Please check your configuration or user role assignment.');
|
|
214
221
|
}
|
|
215
222
|
}
|
|
216
223
|
}
|
|
@@ -262,20 +269,23 @@ async function enhanceConfigForSystem(proxyOptions, system, oAuthRequired, token
|
|
|
262
269
|
* @param logger optional logger instance
|
|
263
270
|
* @returns options for the http-proxy-middleware
|
|
264
271
|
*/
|
|
265
|
-
async function generateProxyMiddlewareOptions(backend, options = {}, logger = new logger_1.ToolsLogger(
|
|
272
|
+
async function generateProxyMiddlewareOptions(backend, options = {}, logger = new logger_1.ToolsLogger({
|
|
273
|
+
transports: [new logger_1.UI5ToolingTransport({ moduleName: 'backend-proxy-middleware' })]
|
|
274
|
+
})) {
|
|
266
275
|
// add required options
|
|
267
276
|
const proxyOptions = {
|
|
268
277
|
headers: {},
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
278
|
+
on: {
|
|
279
|
+
error: (err, req, res, target) => {
|
|
280
|
+
proxyErrorHandler(err, req, logger, res, target);
|
|
281
|
+
},
|
|
282
|
+
...exports.ProxyEventHandlers
|
|
272
283
|
},
|
|
273
|
-
...options
|
|
284
|
+
...options,
|
|
285
|
+
changeOrigin: true,
|
|
286
|
+
target: backend.url,
|
|
287
|
+
pathRewrite: exports.PathRewriters.getPathRewrite(backend, logger)
|
|
274
288
|
};
|
|
275
|
-
proxyOptions.changeOrigin = true;
|
|
276
|
-
proxyOptions.logProvider = () => logger;
|
|
277
|
-
// always set the target to the url provided in yaml
|
|
278
|
-
proxyOptions.target = backend.url;
|
|
279
289
|
// overwrite url if running in AppStudio
|
|
280
290
|
if ((0, btp_utils_1.isAppStudio)()) {
|
|
281
291
|
const destBackend = backend;
|
|
@@ -317,7 +327,6 @@ async function generateProxyMiddlewareOptions(backend, options = {}, logger = ne
|
|
|
317
327
|
if (!proxyOptions.auth && process.env.FIORI_TOOLS_USER && process.env.FIORI_TOOLS_PASSWORD) {
|
|
318
328
|
proxyOptions.auth = `${process.env.FIORI_TOOLS_USER}:${process.env.FIORI_TOOLS_PASSWORD}`;
|
|
319
329
|
}
|
|
320
|
-
proxyOptions.pathRewrite = exports.PathRewriters.getPathRewrite(backend, logger);
|
|
321
330
|
if (backend.bsp) {
|
|
322
331
|
await (0, bsp_1.addOptionsForEmbeddedBSP)(backend.bsp, proxyOptions, logger);
|
|
323
332
|
}
|
|
@@ -336,7 +345,7 @@ async function generateProxyMiddlewareOptions(backend, options = {}, logger = ne
|
|
|
336
345
|
if (backend.proxy) {
|
|
337
346
|
proxyOptions.agent = new https_proxy_agent_1.HttpsProxyAgent(backend.proxy);
|
|
338
347
|
}
|
|
339
|
-
logger.info(`Backend proxy created for ${proxyOptions.target}
|
|
348
|
+
logger.info(`Backend proxy created for ${proxyOptions.target}`);
|
|
340
349
|
return proxyOptions;
|
|
341
350
|
}
|
|
342
351
|
/**
|
package/dist/base/types.d.ts
CHANGED
|
@@ -59,6 +59,7 @@ export type BackendConfig = LocalBackendConfig | DestinationBackendConfig;
|
|
|
59
59
|
export interface BackendMiddlewareConfig {
|
|
60
60
|
backend: BackendConfig;
|
|
61
61
|
options?: Partial<Options>;
|
|
62
|
+
debug?: boolean;
|
|
62
63
|
}
|
|
63
64
|
export interface MiddlewareParameters<T> {
|
|
64
65
|
resources: object;
|
package/dist/ext/bsp.js
CHANGED
|
@@ -28,13 +28,13 @@ function convertAppDescriptorToManifest(bsp) {
|
|
|
28
28
|
*/
|
|
29
29
|
async function promptUserPass(log) {
|
|
30
30
|
if ((0, btp_utils_1.isAppStudio)()) {
|
|
31
|
-
const { authNeeded } = await (0, prompts_1.default)([
|
|
31
|
+
const { authNeeded } = (await (0, prompts_1.default)([
|
|
32
32
|
{
|
|
33
33
|
type: 'confirm',
|
|
34
34
|
name: 'authNeeded',
|
|
35
35
|
message: `${(0, chalk_1.cyan)(i18next_1.default.t('info.authNeeded'))}\n\n`
|
|
36
36
|
}
|
|
37
|
-
]);
|
|
37
|
+
]));
|
|
38
38
|
if (!authNeeded) {
|
|
39
39
|
return undefined;
|
|
40
40
|
}
|
|
@@ -42,7 +42,7 @@ async function promptUserPass(log) {
|
|
|
42
42
|
else {
|
|
43
43
|
log.info((0, chalk_1.yellow)(i18next_1.default.t('info.credentialsRequiredForFLP')));
|
|
44
44
|
}
|
|
45
|
-
const { username, password } = await (0, prompts_1.default)([
|
|
45
|
+
const { username, password } = (await (0, prompts_1.default)([
|
|
46
46
|
{
|
|
47
47
|
type: 'text',
|
|
48
48
|
name: 'username',
|
|
@@ -74,7 +74,7 @@ async function promptUserPass(log) {
|
|
|
74
74
|
log.info((0, chalk_1.yellow)(i18next_1.default.t('info.operationAborted')));
|
|
75
75
|
return process.exit(1);
|
|
76
76
|
}
|
|
77
|
-
});
|
|
77
|
+
}));
|
|
78
78
|
return `${username}:${password}`;
|
|
79
79
|
}
|
|
80
80
|
/**
|
|
@@ -88,8 +88,11 @@ async function addOptionsForEmbeddedBSP(bspPath, proxyOptions, logger) {
|
|
|
88
88
|
const regex = new RegExp('(' + bspPath + '/manifest\\.appdescr\\b)', 'i');
|
|
89
89
|
proxyOptions.router = (req) => {
|
|
90
90
|
// redirects the request for manifest.appdescr to localhost
|
|
91
|
-
if (req.
|
|
92
|
-
|
|
91
|
+
if (req.url?.match(regex)) {
|
|
92
|
+
const protocol = 'protocol' in req
|
|
93
|
+
? req.protocol
|
|
94
|
+
: req.headers.referer?.substring(0, req.headers.referer.indexOf(':')) ?? 'http';
|
|
95
|
+
return protocol + '://' + req.headers.host;
|
|
93
96
|
}
|
|
94
97
|
else {
|
|
95
98
|
return undefined;
|
package/dist/middleware.js
CHANGED
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const dotenv_1 = __importDefault(require("dotenv"));
|
|
7
7
|
const logger_1 = require("@sap-ux/logger");
|
|
8
|
+
const express_1 = __importDefault(require("express"));
|
|
8
9
|
const http_proxy_middleware_1 = require("http-proxy-middleware");
|
|
9
10
|
const proxy_1 = require("./base/proxy");
|
|
10
11
|
/**
|
|
@@ -21,10 +22,11 @@ function formatProxyForLogging(proxy) {
|
|
|
21
22
|
proxy = proxy.replace(proxy.slice(forwardSlashIndex + 2, atIndex), '***:***');
|
|
22
23
|
}
|
|
23
24
|
}
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
24
26
|
return proxy || 'none';
|
|
25
27
|
}
|
|
26
28
|
/**
|
|
27
|
-
* UI5 middleware allowing to
|
|
29
|
+
* UI5 middleware allowing to proxy backends.
|
|
28
30
|
*
|
|
29
31
|
* @param params input parameters for UI5 middleware
|
|
30
32
|
* @param params.options configuration options
|
|
@@ -32,28 +34,25 @@ function formatProxyForLogging(proxy) {
|
|
|
32
34
|
*/
|
|
33
35
|
module.exports = async ({ options }) => {
|
|
34
36
|
const logger = new logger_1.ToolsLogger({
|
|
37
|
+
logLevel: options.configuration?.debug ? logger_1.LogLevel.Debug : logger_1.LogLevel.Info,
|
|
35
38
|
transports: [new logger_1.UI5ToolingTransport({ moduleName: 'backend-proxy-middleware' })]
|
|
36
39
|
});
|
|
37
40
|
await (0, proxy_1.initI18n)();
|
|
38
41
|
dotenv_1.default.config();
|
|
42
|
+
const router = express_1.default.Router();
|
|
39
43
|
const backend = options.configuration.backend;
|
|
40
44
|
const configOptions = options.configuration.options ?? {};
|
|
41
45
|
configOptions.secure = configOptions.secure !== undefined ? !!configOptions.secure : true;
|
|
46
|
+
configOptions.logger = options.configuration?.debug ? logger : undefined;
|
|
42
47
|
try {
|
|
43
48
|
const proxyOptions = await (0, proxy_1.generateProxyMiddlewareOptions)(options.configuration.backend, configOptions, logger);
|
|
44
49
|
const proxyFn = (0, http_proxy_middleware_1.createProxyMiddleware)(proxyOptions);
|
|
45
50
|
logger.info(`Starting backend-proxy-middleware using following configuration:\nbackend: ${JSON.stringify({
|
|
46
51
|
...backend,
|
|
47
52
|
proxy: formatProxyForLogging(backend.proxy)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
proxyFn(req, res, next);
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
next();
|
|
55
|
-
}
|
|
56
|
-
};
|
|
53
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
54
|
+
})}\noptions: ${JSON.stringify(({ logger, ...rest } = configOptions) => rest)}'\nlog: '${options.configuration?.debug ? 'debug' : 'info'}'`);
|
|
55
|
+
return router.use(backend.path, proxyFn);
|
|
57
56
|
}
|
|
58
57
|
catch (e) {
|
|
59
58
|
const message = `Failed to register backend for ${backend.path}. Check configuration in yaml file. \n\t${e}`;
|
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%3Abackend-proxy-middleware"
|
|
11
11
|
},
|
|
12
|
-
"version": "0.
|
|
12
|
+
"version": "0.10.1",
|
|
13
13
|
"license": "Apache-2.0",
|
|
14
14
|
"author": "@SAP/ux-tools-team",
|
|
15
15
|
"main": "dist/index.js",
|
|
@@ -23,15 +23,15 @@
|
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"chalk": "4.1.2",
|
|
25
25
|
"dotenv": "16.3.1",
|
|
26
|
-
"http-proxy-middleware": "
|
|
26
|
+
"http-proxy-middleware": "3.0.5",
|
|
27
27
|
"https-proxy-agent": "5.0.1",
|
|
28
28
|
"i18next": "25.3.0",
|
|
29
29
|
"prompts": "2.4.2",
|
|
30
30
|
"proxy-from-env": "1.1.0",
|
|
31
|
-
"@sap-ux/axios-extension": "1.22.
|
|
32
|
-
"@sap-ux/btp-utils": "1.1.
|
|
31
|
+
"@sap-ux/axios-extension": "1.22.10",
|
|
32
|
+
"@sap-ux/btp-utils": "1.1.4",
|
|
33
33
|
"@sap-ux/logger": "0.7.0",
|
|
34
|
-
"@sap-ux/store": "1.1.
|
|
34
|
+
"@sap-ux/store": "1.1.5"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/express": "4.17.21",
|
|
@@ -42,7 +42,9 @@
|
|
|
42
42
|
"express": "4.21.2",
|
|
43
43
|
"nock": "13.4.0",
|
|
44
44
|
"supertest": "7.1.4",
|
|
45
|
-
"yaml": "2.2.2"
|
|
45
|
+
"yaml": "2.2.2",
|
|
46
|
+
"connect": "^3.7.0",
|
|
47
|
+
"@types/connect": "^3.4.38"
|
|
46
48
|
},
|
|
47
49
|
"ui5": {
|
|
48
50
|
"dependencies": []
|