@sap-ux/backend-proxy-middleware-cf 0.0.99 → 0.1.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.
@@ -0,0 +1,65 @@
1
+ import type { IncomingMessage } from 'node:http';
2
+ import type { MimeInfo, RouteEntry } from '../types';
3
+ /**
4
+ * Escape a string so it can be safely embedded in a RegExp.
5
+ *
6
+ * @param value - Raw string.
7
+ * @returns Regex-safe string with all metacharacters escaped.
8
+ */
9
+ export declare function escapeRegExp(value: string): string;
10
+ /**
11
+ * Replaces oldUrl with newUrl in text (regex-safe).
12
+ *
13
+ * @param text - Full text to replace in.
14
+ * @param oldUrl - URL to replace (will be escaped for regex).
15
+ * @param newUrl - Replacement URL.
16
+ * @returns Text with URLs replaced.
17
+ */
18
+ export declare function replaceUrl(text: string, oldUrl: string, newUrl: string): string;
19
+ /**
20
+ * Returns a path filter that accepts pathnames matching any custom route pattern or any destination route regex.
21
+ *
22
+ * @param customRoutes - Route path patterns (e.g. '/', '/login/callback').
23
+ * @param routes - Route entries with compiled regex.
24
+ * @returns Filter function (pathname) => boolean.
25
+ */
26
+ export declare function createPathFilter(customRoutes: string[], routes: RouteEntry[]): (pathname: string) => boolean;
27
+ /**
28
+ * Check if request originated from the approuter (server-to-server).
29
+ * Detects the custom marker header that was set when the proxy originally
30
+ * forwarded this request to the approuter. The approuter preserves it
31
+ * when proxying back to the ui5-server destination.
32
+ *
33
+ * @param req - Incoming request.
34
+ * @returns True if request came from approuter.
35
+ */
36
+ export declare function isRequestFromApprouter(req: IncomingMessage): boolean;
37
+ /**
38
+ * Creates a proxy filter that checks both route matching and approuter origin.
39
+ * Skips proxying when the request comes from the approuter to prevent infinite loops.
40
+ *
41
+ * @param customRoutes - Route path patterns (e.g. '/', '/login/callback').
42
+ * @param routes - Route entries with compiled regex.
43
+ * @returns Filter function (pathname, req) => boolean for http-proxy-middleware.
44
+ */
45
+ export declare function createProxyFilter(customRoutes: string[], routes: RouteEntry[]): (pathname: string, req: IncomingMessage) => boolean;
46
+ /**
47
+ * Build origin URL from request headers (x-forwarded-proto, x-forwarded-host) and baseUrl.
48
+ *
49
+ * @param req - Request-like object.
50
+ * @param req.headers - Request headers.
51
+ * @param req.baseUrl - Optional base URL path.
52
+ * @returns Origin URL string.
53
+ */
54
+ export declare function getRequestOrigin(req: IncomingMessage & {
55
+ baseUrl?: string;
56
+ }): string;
57
+ /**
58
+ * Get mime type, charset and content-type header value from pathname and optional Content-Type header.
59
+ *
60
+ * @param pathname - Request path (used when no ctValue).
61
+ * @param ctValue - Content-Type header value.
62
+ * @returns MimeInfo object.
63
+ */
64
+ export declare function getMimeInfo(pathname: string, ctValue: string | undefined): MimeInfo;
65
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.escapeRegExp = escapeRegExp;
7
+ exports.replaceUrl = replaceUrl;
8
+ exports.createPathFilter = createPathFilter;
9
+ exports.isRequestFromApprouter = isRequestFromApprouter;
10
+ exports.createProxyFilter = createProxyFilter;
11
+ exports.getRequestOrigin = getRequestOrigin;
12
+ exports.getMimeInfo = getMimeInfo;
13
+ const mime_types_1 = __importDefault(require("mime-types"));
14
+ const content_type_1 = __importDefault(require("content-type"));
15
+ const constants_1 = require("../config/constants");
16
+ /**
17
+ * Escape a string so it can be safely embedded in a RegExp.
18
+ *
19
+ * @param value - Raw string.
20
+ * @returns Regex-safe string with all metacharacters escaped.
21
+ */
22
+ function escapeRegExp(value) {
23
+ return value.replaceAll(/[-/\\^$*+?.()|[\]{}]/g, String.raw `\$&`);
24
+ }
25
+ /**
26
+ * Replaces oldUrl with newUrl in text (regex-safe).
27
+ *
28
+ * @param text - Full text to replace in.
29
+ * @param oldUrl - URL to replace (will be escaped for regex).
30
+ * @param newUrl - Replacement URL.
31
+ * @returns Text with URLs replaced.
32
+ */
33
+ function replaceUrl(text, oldUrl, newUrl) {
34
+ const regex = new RegExp(escapeRegExp(oldUrl), 'gi');
35
+ return text.replace(regex, newUrl);
36
+ }
37
+ /**
38
+ * Returns a path filter that accepts pathnames matching any custom route pattern or any destination route regex.
39
+ *
40
+ * @param customRoutes - Route path patterns (e.g. '/', '/login/callback').
41
+ * @param routes - Route entries with compiled regex.
42
+ * @returns Filter function (pathname) => boolean.
43
+ */
44
+ function createPathFilter(customRoutes, routes) {
45
+ const compiledCustomRoutes = customRoutes.map((route) => new RegExp(String.raw `^${escapeRegExp(route)}(\?.*)?$`));
46
+ return (pathname) => {
47
+ return (compiledCustomRoutes.some((customRoute) => customRoute.test(pathname)) ||
48
+ routes.some((route) => route.sourcePattern.test(pathname)));
49
+ };
50
+ }
51
+ /**
52
+ * Check if request originated from the approuter (server-to-server).
53
+ * Detects the custom marker header that was set when the proxy originally
54
+ * forwarded this request to the approuter. The approuter preserves it
55
+ * when proxying back to the ui5-server destination.
56
+ *
57
+ * @param req - Incoming request.
58
+ * @returns True if request came from approuter.
59
+ */
60
+ function isRequestFromApprouter(req) {
61
+ return !!req.headers[constants_1.PROXY_MARKER_HEADER];
62
+ }
63
+ /**
64
+ * Creates a proxy filter that checks both route matching and approuter origin.
65
+ * Skips proxying when the request comes from the approuter to prevent infinite loops.
66
+ *
67
+ * @param customRoutes - Route path patterns (e.g. '/', '/login/callback').
68
+ * @param routes - Route entries with compiled regex.
69
+ * @returns Filter function (pathname, req) => boolean for http-proxy-middleware.
70
+ */
71
+ function createProxyFilter(customRoutes, routes) {
72
+ const pathFilter = createPathFilter(customRoutes, routes);
73
+ return (pathname, req) => {
74
+ return !isRequestFromApprouter(req) && pathFilter(pathname);
75
+ };
76
+ }
77
+ /**
78
+ * Build origin URL from request headers (x-forwarded-proto, x-forwarded-host) and baseUrl.
79
+ *
80
+ * @param req - Request-like object.
81
+ * @param req.headers - Request headers.
82
+ * @param req.baseUrl - Optional base URL path.
83
+ * @returns Origin URL string.
84
+ */
85
+ function getRequestOrigin(req) {
86
+ return `${String((req.headers['x-forwarded-proto'] ?? 'https').toString().split(',')[0])}://${req.headers['x-forwarded-host'] ?? ''}${req.baseUrl ?? ''}`;
87
+ }
88
+ /**
89
+ * Get mime type, charset and content-type header value from pathname and optional Content-Type header.
90
+ *
91
+ * @param pathname - Request path (used when no ctValue).
92
+ * @param ctValue - Content-Type header value.
93
+ * @returns MimeInfo object.
94
+ */
95
+ function getMimeInfo(pathname, ctValue) {
96
+ if (ctValue) {
97
+ const parsed = content_type_1.default.parse(ctValue);
98
+ const type = parsed.type ?? 'application/octet-stream';
99
+ const charset = parsed.parameters?.charset ?? mime_types_1.default.charset(type) ?? 'utf-8';
100
+ return {
101
+ type,
102
+ charset,
103
+ contentType: content_type_1.default.format({ type, parameters: parsed.parameters })
104
+ };
105
+ }
106
+ const type = mime_types_1.default.lookup(pathname) || 'application/octet-stream';
107
+ const charset = mime_types_1.default.charset(type) || 'utf-8';
108
+ return {
109
+ type,
110
+ charset,
111
+ contentType: `${type}; charset=${charset}`
112
+ };
113
+ }
114
+ //# sourceMappingURL=utils.js.map
package/dist/types.d.ts CHANGED
@@ -1,55 +1,152 @@
1
+ import type { ToolsLogger } from '@sap-ux/logger';
1
2
  /**
2
- * Configuration for a single backend destination.
3
+ * Destination configuration for approuter (name must match routes in xs-app.json).
3
4
  */
4
- export interface BackendDestination {
5
- /**
6
- * Destination URL to proxy requests to.
7
- */
5
+ export interface ApprouterDestination {
6
+ /** Destination name used in xs-app.json routes */
7
+ name: string;
8
+ /** URI of the host to proxy to */
8
9
  url: string;
9
- /**
10
- * Array of OData source paths to proxy to this destination.
11
- * Each path represents an OData service that should be proxied to the destination URL.
12
- * Requests matching these paths will have the path prefix removed before forwarding.
13
- */
14
- paths: string[];
15
- /**
16
- * Optional path rewriting. When specified, the matched path prefix will be replaced
17
- * with this value before forwarding to the backend.
18
- * If not specified, the matched path is simply removed.
19
- */
20
- pathRewrite?: string;
21
- }
22
- /**
23
- * Configuration for Cloud Foundry OAuth middleware.
24
- */
25
- export interface CfOAuthMiddlewareConfig {
26
- /**
27
- * Array of backend destinations.
28
- * Each destination has its own URL and paths.
29
- */
30
- backends: BackendDestination[];
31
- /**
32
- * Manual OAuth credentials (optional).
33
- * If not provided, middleware will attempt to auto-detect from Cloud Foundry ADP project.
34
- */
35
- credentials?: {
36
- /**
37
- * OAuth2 client ID.
38
- */
39
- clientId: string;
40
- /**
41
- * OAuth2 client secret.
42
- */
43
- clientSecret: string;
44
- /**
45
- * Base URL for the OAuth token endpoint.
46
- * The token endpoint will be constructed as: {url}/oauth/token
47
- */
48
- url: string;
49
- };
50
- /**
51
- * Enable debug logging.
52
- */
10
+ }
11
+ /**
12
+ * Extension to be required and injected into the local approuter instance.
13
+ */
14
+ export interface ApprouterExtension {
15
+ /** Local path (e.g. "./my-extension.js") or module path (e.g. "@scope/package/extension.js") */
16
+ module: string;
17
+ /** Optional parameters injected into the extension handler as 4th argument */
18
+ parameters?: Record<string, string>;
19
+ }
20
+ /**
21
+ * Configuration for the backend-proxy-middleware-cf (approuter-based).
22
+ * Options are merged with defaults; configuration can be partial.
23
+ */
24
+ export interface BackendProxyMiddlewareCfConfig {
25
+ /** Verbose logging */
53
26
  debug?: boolean;
27
+ /** Port to run the underlying approuter on */
28
+ port?: number;
29
+ /** Path to xs-app.json (relative to project root). Defaults to './xs-app.json'. */
30
+ xsappJsonPath?: string;
31
+ /** Path to the environment options file (relative to project root) */
32
+ envOptionsPath?: string;
33
+ /** Destinations: array of { name, url } (e.g. from default-env.json). Destination names must match routes in xs-app.json. */
34
+ destinations?: ApprouterDestination[] | string;
35
+ /** Allow BTP services configured in xs-app.json (requires authenticated BTP session) */
36
+ allowServices?: boolean;
37
+ /** Authentication method for routes */
38
+ authenticationMethod?: 'none' | 'route';
39
+ /** Allow static assets to be served by approuter (default false; usually ui5-server serves them) */
40
+ allowLocalDir?: boolean;
41
+ /** Subdomain for multitenancy (optional) */
42
+ subdomain?: string | null;
43
+ /** Replace proxied URL in response body with server URL */
44
+ rewriteContent?: boolean;
45
+ /** Content types to rewrite when rewriteContent is true */
46
+ rewriteContentTypes?: string[];
47
+ /** Approuter extensions (module path + optional parameters) */
48
+ extensions?: ApprouterExtension[];
49
+ /** Add route for HTML pages to trigger XSUAA login when authenticationMethod !== 'none' */
50
+ appendAuthRoute?: boolean;
51
+ /** Disable welcome file handling from xs-app.json */
52
+ disableWelcomeFile?: boolean;
53
+ /** Disable automatic injection of ui5-server routes (resources, test-resources, catch-all) */
54
+ disableUi5ServerRoutes?: boolean;
55
+ }
56
+ /** Effective options with defaults applied. */
57
+ export interface EffectiveOptions extends BackendProxyMiddlewareCfConfig {
58
+ port: number;
59
+ xsappJsonPath: string;
60
+ destinations: ApprouterDestination[];
61
+ rewriteContentTypes: string[];
62
+ extensions: ApprouterExtension[];
63
+ }
64
+ /** Route entry with compiled regex and resolved destination URL. */
65
+ export interface RouteEntry {
66
+ sourcePattern: RegExp;
67
+ path: string;
68
+ url?: string;
69
+ source: string;
70
+ destination?: string;
71
+ }
72
+ /** Mime info for response handling. */
73
+ export interface MimeInfo {
74
+ type: string;
75
+ charset: string;
76
+ contentType: string;
77
+ }
78
+ /** Single route entry in xs-app.json (minimal shape we use). */
79
+ export interface XsappRoute {
80
+ source: string;
81
+ destination?: string;
82
+ endpoint?: string;
83
+ localDir?: string;
84
+ service?: string;
85
+ authenticationType?: string;
86
+ target?: string;
87
+ cacheControl?: string;
88
+ }
89
+ /** Parsed xs-app.json shape (minimal for our use). */
90
+ export interface XsappConfig {
91
+ routes?: XsappRoute[];
92
+ welcomeFile?: string;
93
+ authenticationMethod?: string;
94
+ login?: {
95
+ callbackEndpoint?: string;
96
+ };
97
+ logout?: {
98
+ logoutEndpoint?: string;
99
+ };
100
+ }
101
+ /**
102
+ * Options for building RouteEntry[] from a prepared xsappConfig
103
+ */
104
+ export interface BuildRouteEntriesOptions {
105
+ xsappConfig: XsappConfig;
106
+ effectiveOptions: EffectiveOptions;
107
+ logger: ToolsLogger;
108
+ }
109
+ /**
110
+ * Options for loading and preparing xs-app.json (no destinations needed)
111
+ */
112
+ export interface PrepareXsappConfigOptions {
113
+ rootPath: string;
114
+ xsappJsonPath: string;
115
+ effectiveOptions: EffectiveOptions;
116
+ sourcePath: string;
117
+ logger: ToolsLogger;
118
+ }
119
+ /** Options for creating the proxy middleware. */
120
+ export interface CreateProxyOptions {
121
+ /** Path patterns to proxy (e.g. '/', '/login/callback', logout endpoint). */
122
+ customRoutes: string[];
123
+ /** Route entries from xs-app (regex + destination URL). */
124
+ routes: RouteEntry[];
125
+ /** Target base URI (e.g. http://localhost:port). */
126
+ baseUri: string;
127
+ /** Merged options (debug, rewriteContent, etc.). */
128
+ effectiveOptions: EffectiveOptions;
129
+ /** External URL for BAS (from exposePort). Overrides x-forwarded-host/proto in proxy requests. */
130
+ basExternalUrl?: URL;
131
+ }
132
+ /**
133
+ * Approuter extension handler: Express-like (req, res, next) with optional 4th params from config
134
+ */
135
+ export type ExtensionHandler = (req: unknown, res: unknown, next: unknown, params?: Record<string, string>) => void;
136
+ /**
137
+ * Extension module shape expected from approuter extensions
138
+ */
139
+ export interface ExtensionModule {
140
+ insertMiddleware?: Record<string, Array<ExtensionHandler | {
141
+ path?: string;
142
+ handler: ExtensionHandler;
143
+ }>>;
144
+ }
145
+ /**
146
+ * Loaded extension modules and list of extension routes (paths) they register.
147
+ */
148
+ export interface LoadedExtensions {
149
+ modules: ExtensionModule[];
150
+ routes: string[];
54
151
  }
55
152
  //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,10 @@
1
+ import type { ToolsLogger } from '@sap-ux/logger';
2
+ /**
3
+ * Returns the next free port starting from basePort.
4
+ *
5
+ * @param basePort - Base port to start searching from.
6
+ * @param logger - Optional logger to warn if portfinder fails and basePort is used.
7
+ * @returns A free port number.
8
+ */
9
+ export declare function nextFreePort(basePort: number, logger?: ToolsLogger): Promise<number>;
10
+ //# sourceMappingURL=utils.d.ts.map
package/dist/utils.js ADDED
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.nextFreePort = nextFreePort;
7
+ const portfinder_1 = __importDefault(require("portfinder"));
8
+ /**
9
+ * Returns the next free port starting from basePort.
10
+ *
11
+ * @param basePort - Base port to start searching from.
12
+ * @param logger - Optional logger to warn if portfinder fails and basePort is used.
13
+ * @returns A free port number.
14
+ */
15
+ async function nextFreePort(basePort, logger) {
16
+ try {
17
+ portfinder_1.default.basePort = basePort;
18
+ return await portfinder_1.default.getPortPromise();
19
+ }
20
+ catch {
21
+ logger?.warn(`portfinder failed, using base port ${basePort}.`);
22
+ return basePort;
23
+ }
24
+ }
25
+ //# sourceMappingURL=utils.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap-ux/backend-proxy-middleware-cf",
3
- "description": "OAuth2 Bearer token middleware for Cloud Foundry adaptation projects",
3
+ "description": "UI5 server middleware using @sap/approuter for CF-style destinations and xs-app.json",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/SAP/open-ux-tools.git",
@@ -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-cf"
11
11
  },
12
- "version": "0.0.99",
12
+ "version": "0.1.1",
13
13
  "license": "Apache-2.0",
14
14
  "author": "@SAP/ux-tools-team",
15
15
  "main": "dist/index.js",
@@ -21,21 +21,21 @@
21
21
  "!dist/**/*.map"
22
22
  ],
23
23
  "dependencies": {
24
- "axios": "1.13.6",
24
+ "@sap/approuter": "^20.8.0",
25
+ "content-type": "^1.0.5",
26
+ "dotenv": "^16.4.5",
25
27
  "http-proxy-middleware": "3.0.5",
26
- "@sap-ux/adp-tooling": "0.18.109",
27
- "@sap-ux/logger": "0.8.4",
28
- "@sap-ux/project-access": "1.35.18"
28
+ "mime-types": "^2.1.35",
29
+ "portfinder": "^1.0.32",
30
+ "@sap-ux/adp-tooling": "0.18.111",
31
+ "@sap-ux/btp-utils": "1.1.12",
32
+ "@sap-ux/logger": "0.8.4"
29
33
  },
30
34
  "devDependencies": {
35
+ "@types/content-type": "^1.0.0",
31
36
  "@types/express": "4.17.21",
32
37
  "@types/http-proxy": "^1.17.5",
33
- "@types/supertest": "7.2.0",
34
- "express": "4.22.1",
35
- "nock": "14.0.11",
36
- "supertest": "7.2.2",
37
- "connect": "^3.7.0",
38
- "@types/connect": "^3.4.38"
38
+ "@types/mime-types": "^2.1.4"
39
39
  },
40
40
  "engines": {
41
41
  "node": ">=20.x"
package/ui5.yaml CHANGED
@@ -1,4 +1,4 @@
1
- specVersion: '2.6'
1
+ specVersion: '3.0'
2
2
  metadata:
3
3
  name: backend-proxy-middleware-cf
4
4
  kind: extension
package/dist/proxy.d.ts DELETED
@@ -1,42 +0,0 @@
1
- import type connect from 'connect';
2
- import { type Request, Router } from 'express';
3
- import type { Options } from 'http-proxy-middleware';
4
- import type { IncomingMessage } from 'node:http';
5
- import type { ToolsLogger } from '@sap-ux/logger';
6
- import type { OAuthTokenProvider } from './token';
7
- export type EnhancedIncomingMessage = (IncomingMessage & Pick<Request, 'originalUrl'>) | connect.IncomingMessage;
8
- /**
9
- * Creates proxy options for http-proxy-middleware.
10
- *
11
- * @param {string} targetUrl - The target URL to proxy to.
12
- * @param {string} matchedPath - The path prefix that was matched by the router.
13
- * @param {string | undefined} pathRewrite - Optional replacement path.
14
- * @param {ToolsLogger} logger - Logger instance.
15
- * @returns {Options} Proxy options configuration.
16
- */
17
- export declare function createProxyOptions(targetUrl: string, matchedPath: string, pathRewrite: string | undefined, logger: ToolsLogger): Options;
18
- /**
19
- * Registers a proxy route for a given path.
20
- *
21
- * @param {string} path - Path to register.
22
- * @param {string} destinationUrl - Target URL for proxying.
23
- * @param {string | undefined} pathRewrite - Optional rewrite path.
24
- * @param {OAuthTokenProvider} tokenProvider - Token provider instance.
25
- * @param {ToolsLogger} logger - Logger instance.
26
- * @param {Router} router - Express router instance.
27
- */
28
- export declare function registerProxyRoute(path: string, destinationUrl: string, pathRewrite: string | undefined, tokenProvider: OAuthTokenProvider, logger: ToolsLogger, router: Router): void;
29
- /**
30
- * Sets up all proxy routes for the configured backends.
31
- *
32
- * @param {Array<{url: string, paths: string[], pathRewrite?: string}>} backends - Array of backend configurations.
33
- * @param {OAuthTokenProvider} tokenProvider - Token provider instance.
34
- * @param {ToolsLogger} logger - Logger instance.
35
- * @returns {Router} Configured Express router.
36
- */
37
- export declare function setupProxyRoutes(backends: Array<{
38
- url: string;
39
- paths: string[];
40
- pathRewrite?: string;
41
- }>, tokenProvider: OAuthTokenProvider, logger: ToolsLogger): Router;
42
- //# sourceMappingURL=proxy.d.ts.map
package/dist/proxy.js DELETED
@@ -1,91 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createProxyOptions = createProxyOptions;
4
- exports.registerProxyRoute = registerProxyRoute;
5
- exports.setupProxyRoutes = setupProxyRoutes;
6
- const express_1 = require("express");
7
- const http_proxy_middleware_1 = require("http-proxy-middleware");
8
- /**
9
- * Creates proxy options for http-proxy-middleware.
10
- *
11
- * @param {string} targetUrl - The target URL to proxy to.
12
- * @param {string} matchedPath - The path prefix that was matched by the router.
13
- * @param {string | undefined} pathRewrite - Optional replacement path.
14
- * @param {ToolsLogger} logger - Logger instance.
15
- * @returns {Options} Proxy options configuration.
16
- */
17
- function createProxyOptions(targetUrl, matchedPath, pathRewrite, logger) {
18
- return {
19
- target: targetUrl,
20
- changeOrigin: true,
21
- pathRewrite: (path, req) => {
22
- // Express router.use() strips the matched path from req.url,
23
- // use originalUrl to get the full path before Express stripped it
24
- const originalUrl = req.originalUrl ?? req.url ?? path;
25
- const urlPath = originalUrl.split('?')?.[0];
26
- const queryString = originalUrl.includes('?') ? originalUrl.substring(originalUrl.indexOf('?')) : '';
27
- // Strip the matched path prefix
28
- let rewrittenPath = urlPath;
29
- if (urlPath.startsWith(matchedPath)) {
30
- rewrittenPath = urlPath.substring(matchedPath.length);
31
- }
32
- // Add the replacement prefix if specified
33
- if (pathRewrite !== undefined) {
34
- const sanitizedRewrite = pathRewrite.replace(/\/$/, ''); // Remove trailing slash
35
- rewrittenPath = sanitizedRewrite + rewrittenPath;
36
- }
37
- const finalPath = rewrittenPath + queryString;
38
- logger.debug(`Rewrite path ${originalUrl} > ${finalPath}`);
39
- return finalPath;
40
- },
41
- on: {
42
- error: (err, req, _res, _target) => {
43
- logger.error(`Proxy error for ${req.originalUrl ?? req.url}: ${err.message}`);
44
- if (typeof req.next === 'function') {
45
- req.next(err);
46
- }
47
- }
48
- }
49
- };
50
- }
51
- /**
52
- * Registers a proxy route for a given path.
53
- *
54
- * @param {string} path - Path to register.
55
- * @param {string} destinationUrl - Target URL for proxying.
56
- * @param {string | undefined} pathRewrite - Optional rewrite path.
57
- * @param {OAuthTokenProvider} tokenProvider - Token provider instance.
58
- * @param {ToolsLogger} logger - Logger instance.
59
- * @param {Router} router - Express router instance.
60
- */
61
- function registerProxyRoute(path, destinationUrl, pathRewrite, tokenProvider, logger, router) {
62
- const proxyOptions = createProxyOptions(destinationUrl, path, pathRewrite, logger);
63
- const proxyFn = (0, http_proxy_middleware_1.createProxyMiddleware)(proxyOptions);
64
- const tokenMiddleware = tokenProvider.createTokenMiddleware();
65
- router.use(path, tokenMiddleware, proxyFn);
66
- const rewriteInfo = pathRewrite ? ` (rewrite to: ${pathRewrite})` : ' (strip prefix)';
67
- logger.info(`Registered proxy for path: ${path} -> ${destinationUrl}${rewriteInfo}`);
68
- }
69
- /**
70
- * Sets up all proxy routes for the configured backends.
71
- *
72
- * @param {Array<{url: string, paths: string[], pathRewrite?: string}>} backends - Array of backend configurations.
73
- * @param {OAuthTokenProvider} tokenProvider - Token provider instance.
74
- * @param {ToolsLogger} logger - Logger instance.
75
- * @returns {Router} Configured Express router.
76
- */
77
- function setupProxyRoutes(backends, tokenProvider, logger) {
78
- const router = (0, express_1.Router)();
79
- for (const backend of backends) {
80
- for (const path of backend.paths) {
81
- try {
82
- registerProxyRoute(path, backend.url, backend.pathRewrite, tokenProvider, logger, router);
83
- }
84
- catch (e) {
85
- throw new Error(`Failed to register proxy for ${path}. Check configuration in yaml file. \n\t${e.message}`);
86
- }
87
- }
88
- }
89
- return router;
90
- }
91
- //# sourceMappingURL=proxy.js.map
@@ -1,41 +0,0 @@
1
- import type { ToolsLogger } from '@sap-ux/logger';
2
- import type { ServiceKeys } from '@sap-ux/adp-tooling';
3
- import { OAuthTokenProvider } from './provider';
4
- import type { CfOAuthMiddlewareConfig } from '../types';
5
- /**
6
- * Creates an OAuthTokenProvider from service keys (extracted from Cloud Foundry service instance).
7
- *
8
- * @param {ServiceKeys} serviceKeys - Service keys containing UAA information.
9
- * @param {ToolsLogger} logger - Logger instance.
10
- * @returns {OAuthTokenProvider} OAuthTokenProvider instance.
11
- * @throws {Error} If service keys are invalid.
12
- */
13
- export declare function createManagerFromServiceKeys(serviceKeys: ServiceKeys, logger: ToolsLogger): OAuthTokenProvider;
14
- /**
15
- * Creates an OAuthTokenProvider from direct OAuth credentials (provided in configuration).
16
- *
17
- * @param {string} clientId - OAuth2 client ID.
18
- * @param {string} clientSecret - OAuth2 client secret.
19
- * @param {string} baseUrl - Base URL for the OAuth service (token endpoint will be constructed as {baseUrl}/oauth/token).
20
- * @param {ToolsLogger} logger - Logger instance.
21
- * @returns {OAuthTokenProvider} OAuthTokenProvider instance.
22
- */
23
- export declare function createManagerFromDirectCredentials(clientId: string, clientSecret: string, baseUrl: string, logger: ToolsLogger): OAuthTokenProvider;
24
- /**
25
- * Creates an OAuth token provider based on configuration.
26
- *
27
- * @param {CfOAuthMiddlewareConfig} config - Configuration options.
28
- * @param {ToolsLogger} logger - Logger instance.
29
- * @returns {Promise<OAuthTokenProvider>} Token provider instance.
30
- * @throws {Error} If token provider cannot be created.
31
- */
32
- export declare function createTokenProvider(config: CfOAuthMiddlewareConfig, logger: ToolsLogger): Promise<OAuthTokenProvider>;
33
- /**
34
- * Creates an OAuthTokenProvider from CF ADP project configuration (auto-detection).
35
- *
36
- * @param {string} projectPath - Path to the project root.
37
- * @param {ToolsLogger} logger - Logger instance.
38
- * @returns {Promise<OAuthTokenProvider>} Token provider instance.
39
- */
40
- export declare function createManagerFromCfAdpProject(projectPath: string, logger: ToolsLogger): Promise<OAuthTokenProvider>;
41
- //# sourceMappingURL=factory.d.ts.map