@sap-ux/backend-proxy-middleware-cf 0.0.99 → 0.1.0

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
@@ -2,70 +2,42 @@
2
2
 
3
3
  # [`@sap-ux/backend-proxy-middleware-cf`](https://github.com/SAP/open-ux-tools/tree/main/packages/backend-proxy-middleware-cf)
4
4
 
5
- The `@sap-ux/backend-proxy-middleware-cf` is a [Custom UI5 Server Middleware](https://sap.github.io/ui5-tooling/pages/extensibility/CustomServerMiddleware) for proxying requests to Cloud Foundry destinations with OAuth2 authentication. It supports proxying multiple OData source paths to a single destination URL with automatic OAuth token management.
5
+ UI5 server middleware that uses `@sap/approuter` to make destinations configured in SAP Business Technology Platform (BTP) available for local development. Requests to destination routes are proxied to a local approuter instance via `http-proxy-middleware`.
6
6
 
7
7
  > **⚠️ Experimental**: This middleware is currently experimental and may be subject to breaking changes or even removal in future versions. Use with caution and be prepared to update your configuration or migrate to alternative solutions if needed.
8
8
 
9
- It can be used either with the `ui5 serve` or the `fiori run` commands.
9
+ ## [Prerequisites](#prerequisites)
10
10
 
11
- ## [Configuration Options](#configuration-options)
11
+ - [@ui5/cli](https://ui5.github.io/cli/) 4.0 or later (specVersion 4.0 and later in `ui5.yaml`)
12
12
 
13
- | Option | Value Type | Requirement Type | Default Value | Description |
14
- | ------------------- | ---------- | ---------------- | ------------- | ---------------------------------------------------------------------------------------------------------------- |
15
- | `url` | `string` | **required** | `undefined` | Destination URL to proxy requests to. |
16
- | `paths` | `string[]` | **required** | `[]` | Array of OData source paths to proxy to this destination. Each path represents an OData service that should be proxied. Requests matching these paths will have the path prefix removed before forwarding. |
17
- | `pathRewrite` | `string` | optional | `undefined` | Optional path rewriting. When specified, the matched path prefix will be replaced with this value before forwarding to the backend. If not specified, the matched path is simply removed. Example: path `/resources/lib/api` with pathRewrite `/api` transforms `/resources/lib/api/v1/Service` to `/api/v1/Service`. |
18
- | `credentials` | object | optional | `undefined` | Manual OAuth credentials. If not provided, middleware attempts to auto-detect from Cloud Foundry ADP project. |
19
- | `credentials.clientId` | `string` | mandatory (if credentials provided) | `undefined` | OAuth2 client ID. |
20
- | `credentials.clientSecret` | `string` | mandatory (if credentials provided) | `undefined` | OAuth2 client secret. |
21
- | `credentials.url` | `string` | mandatory (if credentials provided) | `undefined` | Base URL for the OAuth service. The token endpoint will be constructed as `{url}/oauth/token`. |
22
- | `debug` | `boolean` | optional | `false` | Enable debug logging for troubleshooting. |
13
+ ## [Install](#install)
23
14
 
24
- ## [Usage](#usage)
25
-
26
- ### [Basic Configuration](#basic-configuration)
27
-
28
- ```yaml
29
- server:
30
- customMiddleware:
31
- - name: backend-proxy-middleware-cf
32
- afterMiddleware: compression
33
- configuration:
34
- backends:
35
- - url: https://your-backend-service
36
- paths:
37
- - /odata/v4/visitorservice
38
- - /odata
15
+ ```bash
16
+ pnpm add -D @sap-ux/backend-proxy-middleware-cf
39
17
  ```
40
18
 
41
- ### [Automatic Detection (Recommended)](#automatic-detection-recommended)
42
-
43
- For Cloud Foundry adaptation projects, the middleware automatically detects the project configuration from `ui5.yaml` and extracts OAuth credentials from service keys. You only need to provide the `url` and `paths`:
19
+ ## [Configuration (ui5.yaml)](#configuration-ui5yaml)
20
+
21
+ | Option | Type | Default | Description |
22
+ |--------|------|---------|-------------|
23
+ | `debug` | `boolean` | `false` | Verbose logging |
24
+ | `port` | `number` | `5000` | Port for the local approuter |
25
+ | `xsappJsonPath` | `string` | `"./xs-app.json"` | Path to the CF-style approuter config (e.g. `xs-app.json`). Destination route sources should match the pattern `/[^/]*\/(.*\/)?[^/]*/` (e.g. `"^/backend/(.*)$"`). |
26
+ | `envOptionsPath` | `string` | — | Path (relative to project root) to a JSON file. Each top-level key is set on `process.env` (objects/arrays are JSON-stringified) so the approuter can read credentials and services. |
27
+ | `destinations` | `array` or `string` | `[]` | List of `{ name, url }` destinations (names must match routes in `xs-app.json`). |
28
+ | `allowServices` | `boolean` | `false` | Allow BTP services referenced in `xs-app.json` (requires authenticated BTP session). |
29
+ | `authenticationMethod` | `"none"` \| `"route"` | `"none"` | Authentication for routes |
30
+ | `allowLocalDir` | `boolean` | `false` | Allow approuter to serve static assets (usually ui5-server serves them). |
31
+ | `rewriteContent` | `boolean` | `true` | Replace proxied URLs in response body with the server URL |
32
+ | `rewriteContentTypes` | `string[]` | `["text/html", "application/json", "application/atom+xml", "application/xml"]` | Content types to rewrite when `rewriteContent` is true |
33
+ | `extensions` | `array` | `[]` | Approuter extensions: `{ module: string, parameters?: Record<string, string> }`. Parameters are passed as the 4th argument to extension handlers. |
34
+ | `appendAuthRoute` | `boolean` | `false` | Add a route for HTML pages to trigger XSUAA login when `authenticationMethod` is not `"none"`. |
35
+ | `disableWelcomeFile` | `boolean` | `false` | Disable welcome file handling from `xs-app.json`. |
36
+ | `disableUi5ServerRoutes` | `boolean` | `false` | Disable automatic injection of the `ui5-server` HTML auth route for `/test/*` and `/local/*` pages. |
44
37
 
45
- ```yaml
46
- server:
47
- customMiddleware:
48
- - name: backend-proxy-middleware-cf
49
- afterMiddleware: compression
50
- configuration:
51
- backends:
52
- - url: https://your-backend-service
53
- paths:
54
- - /odata/v4/visitorservice
55
- - /odata
56
- ```
57
-
58
- The middleware will:
59
-
60
- 1. Read the `app-variant-bundler-build` custom task from `ui5.yaml`
61
- 2. Extract `serviceInstanceName` and `serviceInstanceGuid`
62
- 3. Retrieve service keys using `@sap-ux/adp-tooling`
63
- 4. Extract UAA credentials and construct the token endpoint
64
- 5. Automatically add Bearer tokens to proxied requests
65
-
66
- ### [Manual Credentials](#manual-credentials)
38
+ ## [Usage](#usage)
67
39
 
68
- For custom setups or when auto-detection is not available, you can provide OAuth credentials manually:
40
+ 1. Add the middleware in `ui5.yaml`:
69
41
 
70
42
  ```yaml
71
43
  server:
@@ -73,140 +45,56 @@ server:
73
45
  - name: backend-proxy-middleware-cf
74
46
  afterMiddleware: compression
75
47
  configuration:
76
- backends:
77
- - url: https://your-backend-service
78
- paths:
79
- - /odata/v4/visitorservice
80
- - /odata
81
- credentials:
82
- clientId: "sb-your-service-instance!b123|your-app!b456"
83
- clientSecret: "your-client-secret"
84
- url: "https://example.authentication"
85
- debug: true
48
+ authenticationMethod: "none"
49
+ debug: true
50
+ port: 5000
51
+ xsappJsonPath: "./xs-app.json"
52
+ destinations:
53
+ - name: "backend"
54
+ url: "https://your-backend.example/path"
86
55
  ```
87
56
 
88
- The `credentials.url` should be the base URL of the UAA service (without `/oauth/token`). The middleware will automatically construct the full token endpoint.
89
-
90
- ### Multiple OData Sources
57
+ 2. Point your path to the location of xs-app.json.
91
58
 
92
- You can proxy multiple OData paths to the same destination:
93
-
94
- ```yaml
95
- server:
96
- customMiddleware:
97
- - name: backend-proxy-middleware-cf
98
- afterMiddleware: compression
99
- configuration:
100
- backends:
101
- - url: https://your-backend-service
102
- paths:
103
- - /odata/v4/service1
104
- - /odata/v4/service2
105
- - /odata/v2/legacy
106
- ```
59
+ ### [Env options file (VCAP_SERVICES, credentials)](#env-options-file-vcap_services-credentials)
107
60
 
108
- ### Path Rewriting with pathRewrite
61
+ To run the approuter with BTP-style credentials (e.g. XSUAA, destinations), point `envOptionsPath` to a JSON file. Each top-level key is applied to `process.env` so the approuter can find them; object and array values are stored as JSON strings. The key `destinations` in the file is ignored so that the middleware's `destinations` from ui5.yaml are used.
109
62
 
110
- When your application requests resources with a specific path prefix (e.g., from a UI5 library), but the backend API expects a different path structure, use `pathRewrite`:
63
+ Example shape (minimal):
111
64
 
112
- ```yaml
113
- server:
114
- customMiddleware:
115
- - name: backend-proxy-middleware-cf
116
- afterMiddleware: compression
117
- configuration:
118
- backends:
119
- - url: https://my-backend.example.com
120
- paths:
121
- - /resources/my/app/ui/api/example
122
- pathRewrite: /api/example
65
+ ```json
66
+ {
67
+ "VCAP_SERVICES": {
68
+ "xsuaa": [{ "label": "xsuaa", "credentials": { "clientid": "...", "clientsecret": "...", "url": "..." } }],
69
+ "destination": [{ "label": "destination", "credentials": { ... } }]
70
+ }
71
+ }
123
72
  ```
124
73
 
125
- **How it works:**
126
- - **Request from app:** `/resources/my/app/ui/api/example/v1/ExampleService/$metadata`
127
- - **Matched path:** `/resources/my/app/ui/api/example`
128
- - **Path rewriting:** `/api/example`
129
- - **Forwarded to backend:** `/api/example/v1/ExampleService/$metadata`
74
+ You can export a real `VCAP_SERVICES` (and optionally other keys) from your BTP app and save it to a file (e.g. `./default-env.json`); do not commit secrets. In ui5.yaml set `envOptionsPath: "./default-env.json"`.
75
+
76
+ ## [How it works](#how-it-works)
130
77
 
131
- Without `pathRewrite`, the matched path prefix is simply removed:
132
- - **Request:** `/odata/v4/service/EntitySet`
133
- - **Matched path:** `/odata`
134
- - **Forwarded:** `/v4/service/EntitySet`
78
+ The middleware starts a local `@sap/approuter` process with your `xs-app.json` and destinations. The UI5 server proxies requests that match approuter routes (e.g. login callback, welcome file, destination routes) to `http://localhost:<port>`. Response content can be rewritten so that backend URLs in the body are replaced with the server URL for the relevant content types.
135
79
 
136
- ### Multiple Backend Services
80
+ ## [Extensions](#extensions)
137
81
 
138
- You can proxy multiple backend services:
82
+ You can plug in approuter extensions and pass parameters:
139
83
 
140
84
  ```yaml
141
- server:
142
- customMiddleware:
143
- - name: backend-proxy-middleware-cf
144
- afterMiddleware: compression
145
- configuration:
146
- backends:
147
- - url: https://your-backend-service1
148
- paths:
149
- - /odata/v4/service1
150
- - /odata/v4/service2
151
- - /odata/v2/legacy
152
- - url: https://your-backend-service2
153
- paths:
154
- - /odata/v4/service1
155
- - /odata/v4/service2
156
- - /odata/v2/legacy
85
+ configuration:
86
+ extensions:
87
+ - module: ./approuter-local-ext.js
88
+ parameters:
89
+ userId: "user@example.com"
157
90
  ```
158
91
 
159
- ### With Debug Logging
160
-
161
- Enable debug logging to troubleshoot issues:
92
+ In the extension, parameters are available as the 4th argument: `function (req, res, next, params)`.
162
93
 
163
- ```yaml
164
- server:
165
- customMiddleware:
166
- - name: backend-proxy-middleware-cf
167
- afterMiddleware: compression
168
- configuration:
169
- backends:
170
- - url: https://your-backend-service.cfapps.eu12.hana.ondemand.com
171
- paths:
172
- - /odata
173
- debug: true
174
- ```
94
+ ## [Keywords](#keywords)
175
95
 
176
- ## How It Works
177
-
178
- 1. **Proxy Setup**: Creates HTTP proxy middleware for each configured path, proxying to the destination URL.
179
- 2. **Path Rewriting**: Removes the matched path prefix before forwarding requests (e.g., `/odata/v4/service` → `/service`).
180
- 3. **OAuth Detection**: For automatic mode, checks if the project is a CF ADP project by reading `ui5.yaml` and looking for the `app-variant-bundler-build` custom task.
181
- 4. **Credentials**: Extracts `serviceInstanceName` and `serviceInstanceGuid` from the custom task configuration.
182
- 5. **Service Keys**: Retrieves service keys using `@sap-ux/adp-tooling`, which communicates with Cloud Foundry CLI.
183
- 6. **Token Endpoint**: Constructs the token endpoint from the UAA base URL as `{url}/oauth/token`.
184
- 7. **Token Management**: Requests OAuth tokens using client credentials flow.
185
- 8. **Caching**: Caches tokens in memory and refreshes them automatically 60 seconds before expiry.
186
- 9. **Request Proxying**: Adds `Authorization: Bearer <token>` header to proxied requests before forwarding.
187
-
188
- ## Error Handling
189
-
190
- - If `url` is not provided, the middleware will be inactive and log a warning.
191
- - If no paths are configured, the middleware will be inactive and log a warning.
192
- - If auto-detection fails and no manual credentials are provided, the middleware will proxy requests without OAuth tokens (may fail if backend requires authentication).
193
- - If token request fails, an error is logged but the request may still proceed (depending on the backend's authentication requirements).
194
- - All errors are logged for debugging purposes.
195
-
196
- ## Security Considerations
197
-
198
- - Credentials are never logged in production mode.
199
- - Tokens are cached in memory only and never persisted to disk.
200
- - Token refresh happens automatically 60 seconds before expiry to avoid using expired tokens.
201
- - Service keys are obtained securely through Cloud Foundry CLI.
202
- - The middleware only proxies requests matching any of the configured path prefixes.
203
- - If no paths are configured, the middleware will be inactive and log a warning.
204
-
205
- ## Keywords
206
-
207
- - OAuth2 Middleware
208
- - Cloud Foundry ADP
209
- - Bearer Token
210
- - Fiori tools
211
- - SAP UI5
212
- - Proxy Middleware
96
+ - UI5 middleware
97
+ - Cloud Foundry
98
+ - Approuter
99
+ - Destination proxy
100
+ - SAP BTP
@@ -0,0 +1,27 @@
1
+ import createApprouter from '@sap/approuter';
2
+ import type { ToolsLogger } from '@sap-ux/logger';
3
+ import type { XsappConfig } from '../types';
4
+ /**
5
+ * Options for starting the approuter.
6
+ */
7
+ interface StartApprouterOptions {
8
+ /** Port to run the approuter on. */
9
+ port: number;
10
+ /** Parsed xs-app.json configuration. */
11
+ xsappConfig: XsappConfig;
12
+ /** Project root path (working directory for approuter). */
13
+ rootPath: string;
14
+ /** Approuter extension modules. */
15
+ modules: unknown[];
16
+ /** Logger instance. */
17
+ logger: ToolsLogger;
18
+ }
19
+ /**
20
+ * Start the approuter and register it globally for cleanup.
21
+ *
22
+ * @param options - Approuter start options.
23
+ * @returns The started approuter instance.
24
+ */
25
+ export declare function startApprouter(options: StartApprouterOptions): ReturnType<typeof createApprouter>;
26
+ export {};
27
+ //# sourceMappingURL=approuter.d.ts.map
@@ -0,0 +1,38 @@
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.startApprouter = startApprouter;
7
+ const approuter_1 = __importDefault(require("@sap/approuter"));
8
+ /**
9
+ * Start the approuter and register it globally for cleanup.
10
+ *
11
+ * @param options - Approuter start options.
12
+ * @returns The started approuter instance.
13
+ */
14
+ function startApprouter(options) {
15
+ const { port, xsappConfig, rootPath, modules, logger } = options;
16
+ const approuter = (0, approuter_1.default)();
17
+ try {
18
+ approuter.start({
19
+ port,
20
+ xsappConfig,
21
+ workingDir: rootPath,
22
+ extensions: modules
23
+ });
24
+ }
25
+ catch (err) {
26
+ const message = err instanceof Error ? err.message : String(err);
27
+ throw new Error(`Failed to start approuter on port ${port}: ${message}`);
28
+ }
29
+ logger.debug(`Approuter started on port ${port}`);
30
+ // Register approuter globally for cleanup
31
+ const globalKey = 'backend-proxy-middleware-cf';
32
+ const g = globalThis;
33
+ if (typeof g[globalKey]?.approuters === 'object') {
34
+ g[globalKey].approuters?.push(approuter);
35
+ }
36
+ return approuter;
37
+ }
38
+ //# sourceMappingURL=approuter.js.map
@@ -0,0 +1,29 @@
1
+ import type { ToolsLogger } from '@sap-ux/logger';
2
+ import type { ApprouterExtension, ExtensionModule, LoadedExtensions } from '../types';
3
+ /**
4
+ * Load and prepare extension modules for the approuter.
5
+ *
6
+ * @param rootPath - Project root path for resolving module paths.
7
+ * @param extensions - Extension configs from effectiveOptions.
8
+ * @param logger - Logger instance.
9
+ * @returns Loaded extension modules and list of extension routes (paths) they register.
10
+ */
11
+ export declare function loadExtensions(rootPath: string, extensions: ApprouterExtension[] | undefined, logger: ToolsLogger): LoadedExtensions;
12
+ /**
13
+ * Collect route paths registered by an extension module via insertMiddleware.
14
+ *
15
+ * @param extensionModule - The extension module to inspect.
16
+ * @returns Array of path strings from insertMiddleware entries that define a path.
17
+ */
18
+ export declare function getExtensionRoutes(extensionModule: ExtensionModule): string[];
19
+ /**
20
+ * Convert an extension config to a loaded extension module with parameter-injected handlers.
21
+ * Does not mutate any shared state; use getExtensionRoutes to obtain paths from the returned module.
22
+ *
23
+ * @param extension - The extension to convert.
24
+ * @param rootPath - The root path of the project for resolving the module.
25
+ * @param logger - The logger to use.
26
+ * @returns The extension module, or undefined if the module cannot be resolved.
27
+ */
28
+ export declare function toExtensionModule(extension: ApprouterExtension, rootPath: string, logger: ToolsLogger): ExtensionModule | undefined;
29
+ //# sourceMappingURL=extensions.d.ts.map
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadExtensions = loadExtensions;
4
+ exports.getExtensionRoutes = getExtensionRoutes;
5
+ exports.toExtensionModule = toExtensionModule;
6
+ /**
7
+ * Create a wrapper that injects parameters as 4th argument for approuter extension handlers.
8
+ *
9
+ * @param middleware - Original handler (req, res, next, params).
10
+ * @param params - Parameters to inject (from extension config).
11
+ * @returns Wrapper function with ≤3 args so approuter invokes it.
12
+ */
13
+ function createParametersInjector(middleware, params) {
14
+ return function injectParameters(req, res, next) {
15
+ req['backend-proxy-middleware-cf'] = { parameters: params };
16
+ middleware.apply(this, [req, res, next, params]);
17
+ };
18
+ }
19
+ /**
20
+ * Load and prepare extension modules for the approuter.
21
+ *
22
+ * @param rootPath - Project root path for resolving module paths.
23
+ * @param extensions - Extension configs from effectiveOptions.
24
+ * @param logger - Logger instance.
25
+ * @returns Loaded extension modules and list of extension routes (paths) they register.
26
+ */
27
+ function loadExtensions(rootPath, extensions, logger) {
28
+ const modules = (extensions ?? [])
29
+ .map((extension) => toExtensionModule(extension, rootPath, logger))
30
+ .filter((e) => e != null);
31
+ const routes = modules.flatMap(getExtensionRoutes);
32
+ return { modules, routes };
33
+ }
34
+ /**
35
+ * Collect route paths registered by an extension module via insertMiddleware.
36
+ *
37
+ * @param extensionModule - The extension module to inspect.
38
+ * @returns Array of path strings from insertMiddleware entries that define a path.
39
+ */
40
+ function getExtensionRoutes(extensionModule) {
41
+ const insertMiddleware = extensionModule.insertMiddleware;
42
+ if (!insertMiddleware) {
43
+ return [];
44
+ }
45
+ const paths = [];
46
+ for (const type of Object.keys(insertMiddleware)) {
47
+ for (const entry of insertMiddleware[type]) {
48
+ if (typeof entry !== 'function' && entry.path) {
49
+ paths.push(entry.path);
50
+ }
51
+ }
52
+ }
53
+ return paths;
54
+ }
55
+ /**
56
+ * Convert an extension config to a loaded extension module with parameter-injected handlers.
57
+ * Does not mutate any shared state; use getExtensionRoutes to obtain paths from the returned module.
58
+ *
59
+ * @param extension - The extension to convert.
60
+ * @param rootPath - The root path of the project for resolving the module.
61
+ * @param logger - The logger to use.
62
+ * @returns The extension module, or undefined if the module cannot be resolved.
63
+ */
64
+ function toExtensionModule(extension, rootPath, logger) {
65
+ try {
66
+ const extensionModulePath = require.resolve(extension.module, { paths: [rootPath] });
67
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- dynamic user extension path
68
+ const originalModule = require(extensionModulePath);
69
+ const insertMiddleware = originalModule?.insertMiddleware;
70
+ if (!insertMiddleware) {
71
+ return originalModule;
72
+ }
73
+ // Shallow-copy to avoid mutating the require'd module cache
74
+ const wrappedMiddleware = {};
75
+ for (const type of Object.keys(insertMiddleware)) {
76
+ wrappedMiddleware[type] = insertMiddleware[type].map((module) => {
77
+ if (typeof module === 'function') {
78
+ return createParametersInjector(module, extension.parameters);
79
+ }
80
+ return { ...module, handler: createParametersInjector(module.handler, extension.parameters) };
81
+ });
82
+ }
83
+ return { ...originalModule, insertMiddleware: wrappedMiddleware };
84
+ }
85
+ catch {
86
+ logger.warn(`Failed to resolve extension "${extension.module}". Extension will be ignored.`);
87
+ return undefined;
88
+ }
89
+ }
90
+ //# sourceMappingURL=extensions.js.map
@@ -0,0 +1,10 @@
1
+ import type { BackendProxyMiddlewareCfConfig, EffectiveOptions } from '../types';
2
+ export declare const DEFAULT_REWRITE_CONTENT_TYPES: string[];
3
+ /**
4
+ * Merge user configuration with defaults.
5
+ *
6
+ * @param configuration - Configuration from ui5.yaml.
7
+ * @returns Effective options with all defaults applied.
8
+ */
9
+ export declare function mergeEffectiveOptions(configuration: BackendProxyMiddlewareCfConfig): EffectiveOptions;
10
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_REWRITE_CONTENT_TYPES = void 0;
4
+ exports.mergeEffectiveOptions = mergeEffectiveOptions;
5
+ exports.DEFAULT_REWRITE_CONTENT_TYPES = [
6
+ 'text/html',
7
+ 'application/json',
8
+ 'application/atom+xml',
9
+ 'application/xml'
10
+ ];
11
+ /**
12
+ * Merge user configuration with defaults.
13
+ *
14
+ * @param configuration - Configuration from ui5.yaml.
15
+ * @returns Effective options with all defaults applied.
16
+ */
17
+ function mergeEffectiveOptions(configuration) {
18
+ return {
19
+ debug: false,
20
+ port: 5000,
21
+ xsappJsonPath: './xs-app.json',
22
+ destinations: [],
23
+ allowServices: false,
24
+ authenticationMethod: 'none',
25
+ allowLocalDir: false,
26
+ rewriteContent: true,
27
+ rewriteContentTypes: [...exports.DEFAULT_REWRITE_CONTENT_TYPES],
28
+ appendAuthRoute: false,
29
+ disableWelcomeFile: false,
30
+ disableUi5ServerRoutes: false,
31
+ extensions: [],
32
+ ...configuration
33
+ };
34
+ }
35
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Destination name for the local UI5 server (used in xs-app.json routes and env config).
3
+ */
4
+ export declare const UI5_SERVER_DESTINATION = "ui5-server";
5
+ /**
6
+ * Header set by the proxy on requests forwarded to the approuter.
7
+ * Used to detect approuter loop-back requests and prevent infinite loops.
8
+ */
9
+ export declare const PROXY_MARKER_HEADER = "x-backend-proxy-middleware-cf";
10
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PROXY_MARKER_HEADER = exports.UI5_SERVER_DESTINATION = void 0;
4
+ /**
5
+ * Destination name for the local UI5 server (used in xs-app.json routes and env config).
6
+ */
7
+ exports.UI5_SERVER_DESTINATION = 'ui5-server';
8
+ /**
9
+ * Header set by the proxy on requests forwarded to the approuter.
10
+ * Used to detect approuter loop-back requests and prevent infinite loops.
11
+ */
12
+ exports.PROXY_MARKER_HEADER = 'x-backend-proxy-middleware-cf';
13
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1,32 @@
1
+ import type { ToolsLogger } from '@sap-ux/logger';
2
+ import type { EffectiveOptions } from '../types';
3
+ /**
4
+ * Load env options from file or CF, apply to process.env, and add destinations from effectiveOptions.
5
+ *
6
+ * When effectiveOptions.envOptionsPath is set, loads that JSON file. When null, loads mta.yaml one level
7
+ * above rootPath and fetches VCAP_SERVICES from CF. effectiveOptions.destinations is applied so
8
+ * middleware config takes precedence over file/env.
9
+ *
10
+ * @param rootPath - Project root path.
11
+ * @param effectiveOptions - Merged config; envOptionsPath and destinations are used.
12
+ * @param logger - Logger for CF path.
13
+ * @returns Promise resolving when env options are loaded and applied.
14
+ */
15
+ export declare function loadAndApplyEnvOptions(rootPath: string, effectiveOptions: EffectiveOptions, logger: ToolsLogger): Promise<void>;
16
+ /**
17
+ * Ensure the ui5-server destination exists and has the correct URL.
18
+ * If ui5-server doesn't exist in configuration, it will be auto-created.
19
+ * If it exists but has a different port, it will be updated.
20
+ * In BAS, the external URL is used instead of localhost so the approuter
21
+ * builds correct redirect URIs.
22
+ *
23
+ * This enables multi-instance support and removes the need to manually
24
+ * configure ui5-server in ui5.yaml - it's auto-configured based on the actual port.
25
+ *
26
+ * @param effectiveOptions - Merged options containing destinations.
27
+ * @param actualPort - The actual port detected from the incoming request.
28
+ * @param basExternalUrl - Optional BAS external URL; when set, used as the destination URL.
29
+ * @returns True if destination was created or updated, false if no change needed.
30
+ */
31
+ export declare function updateUi5ServerDestinationPort(effectiveOptions: EffectiveOptions, actualPort: number, basExternalUrl?: URL): boolean;
32
+ //# sourceMappingURL=env.d.ts.map