@sap-ux/backend-proxy-middleware-cf 0.2.10 → 0.3.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.
@@ -1,6 +1,6 @@
1
1
  import createApprouter from '@sap/approuter';
2
2
  import type { ToolsLogger } from '@sap-ux/logger';
3
- import type { XsappConfig } from '../types';
3
+ import type { XsappConfig } from '../types.js';
4
4
  /**
5
5
  * Options for starting the approuter.
6
6
  */
@@ -1,19 +1,13 @@
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"));
1
+ import createApprouter from '@sap/approuter';
8
2
  /**
9
3
  * Start the approuter and register it globally for cleanup.
10
4
  *
11
5
  * @param options - Approuter start options.
12
6
  * @returns The started approuter instance.
13
7
  */
14
- function startApprouter(options) {
8
+ export function startApprouter(options) {
15
9
  const { port, xsappConfig, rootPath, modules, logger } = options;
16
- const approuter = (0, approuter_1.default)();
10
+ const approuter = createApprouter();
17
11
  try {
18
12
  approuter.start({
19
13
  port,
@@ -1,5 +1,5 @@
1
1
  import type { ToolsLogger } from '@sap-ux/logger';
2
- import type { ApprouterExtension, ExtensionModule, LoadedExtensions } from '../types';
2
+ import type { ApprouterExtension, ExtensionModule, LoadedExtensions } from '../types.js';
3
3
  /**
4
4
  * Load and prepare extension modules for the approuter.
5
5
  *
@@ -1,8 +1,4 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.loadExtensions = loadExtensions;
4
- exports.getExtensionRoutes = getExtensionRoutes;
5
- exports.toExtensionModule = toExtensionModule;
1
+ import { createRequire } from 'node:module';
6
2
  /**
7
3
  * Create a wrapper that injects parameters as 4th argument for approuter extension handlers.
8
4
  *
@@ -24,7 +20,7 @@ function createParametersInjector(middleware, params) {
24
20
  * @param logger - Logger instance.
25
21
  * @returns Loaded extension modules and list of extension routes (paths) they register.
26
22
  */
27
- function loadExtensions(rootPath, extensions, logger) {
23
+ export function loadExtensions(rootPath, extensions, logger) {
28
24
  const modules = (extensions ?? [])
29
25
  .map((extension) => toExtensionModule(extension, rootPath, logger))
30
26
  .filter((e) => e != null);
@@ -37,7 +33,7 @@ function loadExtensions(rootPath, extensions, logger) {
37
33
  * @param extensionModule - The extension module to inspect.
38
34
  * @returns Array of path strings from insertMiddleware entries that define a path.
39
35
  */
40
- function getExtensionRoutes(extensionModule) {
36
+ export function getExtensionRoutes(extensionModule) {
41
37
  const insertMiddleware = extensionModule.insertMiddleware;
42
38
  if (!insertMiddleware) {
43
39
  return [];
@@ -61,11 +57,11 @@ function getExtensionRoutes(extensionModule) {
61
57
  * @param logger - The logger to use.
62
58
  * @returns The extension module, or undefined if the module cannot be resolved.
63
59
  */
64
- function toExtensionModule(extension, rootPath, logger) {
60
+ export function toExtensionModule(extension, rootPath, logger) {
65
61
  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);
62
+ const esmRequire = createRequire(import.meta.url);
63
+ const extensionModulePath = esmRequire.resolve(extension.module, { paths: [rootPath] });
64
+ const originalModule = esmRequire(extensionModulePath);
69
65
  const insertMiddleware = originalModule?.insertMiddleware;
70
66
  if (!insertMiddleware) {
71
67
  return originalModule;
@@ -1,4 +1,4 @@
1
- import type { BackendProxyMiddlewareCfConfig, EffectiveOptions } from '../types';
1
+ import type { BackendProxyMiddlewareCfConfig, EffectiveOptions } from '../types.js';
2
2
  export declare const DEFAULT_REWRITE_CONTENT_TYPES: string[];
3
3
  /**
4
4
  * Merge user configuration with defaults.
@@ -1,9 +1,5 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_REWRITE_CONTENT_TYPES = void 0;
4
- exports.mergeEffectiveOptions = mergeEffectiveOptions;
5
- const adp_tooling_1 = require("@sap-ux/adp-tooling");
6
- exports.DEFAULT_REWRITE_CONTENT_TYPES = [
1
+ import { DEFAULT_TUNNEL_APP_NAME } from '@sap-ux/adp-tooling';
2
+ export const DEFAULT_REWRITE_CONTENT_TYPES = [
7
3
  'text/html',
8
4
  'application/json',
9
5
  'application/atom+xml',
@@ -15,7 +11,7 @@ exports.DEFAULT_REWRITE_CONTENT_TYPES = [
15
11
  * @param configuration - Configuration from ui5.yaml.
16
12
  * @returns Effective options with all defaults applied.
17
13
  */
18
- function mergeEffectiveOptions(configuration) {
14
+ export function mergeEffectiveOptions(configuration) {
19
15
  return {
20
16
  debug: false,
21
17
  port: 5000,
@@ -25,12 +21,12 @@ function mergeEffectiveOptions(configuration) {
25
21
  authenticationMethod: 'none',
26
22
  allowLocalDir: false,
27
23
  rewriteContent: true,
28
- rewriteContentTypes: [...exports.DEFAULT_REWRITE_CONTENT_TYPES],
24
+ rewriteContentTypes: [...DEFAULT_REWRITE_CONTENT_TYPES],
29
25
  appendAuthRoute: false,
30
26
  disableWelcomeFile: false,
31
27
  disableUi5ServerRoutes: false,
32
28
  disableSshTunnel: false,
33
- tunnelAppName: adp_tooling_1.DEFAULT_TUNNEL_APP_NAME,
29
+ tunnelAppName: DEFAULT_TUNNEL_APP_NAME,
34
30
  skipSshEnable: false,
35
31
  extensions: [],
36
32
  ...configuration
@@ -1,13 +1,10 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PROXY_MARKER_HEADER = exports.UI5_SERVER_DESTINATION = void 0;
4
1
  /**
5
2
  * Destination name for the local UI5 server (used in xs-app.json routes and env config).
6
3
  */
7
- exports.UI5_SERVER_DESTINATION = 'ui5-server';
4
+ export const UI5_SERVER_DESTINATION = 'ui5-server';
8
5
  /**
9
6
  * Header set by the proxy on requests forwarded to the approuter.
10
7
  * Used to detect approuter loop-back requests and prevent infinite loops.
11
8
  */
12
- exports.PROXY_MARKER_HEADER = 'x-backend-proxy-middleware-cf';
9
+ export const PROXY_MARKER_HEADER = 'x-backend-proxy-middleware-cf';
13
10
  //# sourceMappingURL=constants.js.map
@@ -1,6 +1,6 @@
1
1
  import type { ToolsLogger } from '@sap-ux/logger';
2
2
  import type { AppRouterEnvOptions } from '@sap-ux/adp-tooling';
3
- import type { ConnectivityProxyInfo, EffectiveOptions } from '../types';
3
+ import type { ConnectivityProxyInfo, EffectiveOptions } from '../types.js';
4
4
  /**
5
5
  * Extract connectivity proxy host and port from VCAP_SERVICES.
6
6
  *
@@ -1,23 +1,14 @@
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.getConnectivityProxyInfo = getConnectivityProxyInfo;
7
- exports.applyToProcessEnv = applyToProcessEnv;
8
- exports.loadEnvOptions = loadEnvOptions;
9
- exports.updateUi5ServerDestinationPort = updateUi5ServerDestinationPort;
10
- const node_fs_1 = __importDefault(require("node:fs"));
11
- const node_path_1 = __importDefault(require("node:path"));
12
- const adp_tooling_1 = require("@sap-ux/adp-tooling");
13
- const constants_1 = require("./constants");
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { buildVcapServicesFromResources, getSpaceGuidFromUi5Yaml, getYamlContent } from '@sap-ux/adp-tooling';
4
+ import { UI5_SERVER_DESTINATION } from './constants.js';
14
5
  /**
15
6
  * Extract connectivity proxy host and port from VCAP_SERVICES.
16
7
  *
17
8
  * @param vcapServices - Parsed VCAP_SERVICES object.
18
9
  * @returns Proxy info or undefined if no connectivity service is present.
19
10
  */
20
- function getConnectivityProxyInfo(vcapServices) {
11
+ export function getConnectivityProxyInfo(vcapServices) {
21
12
  if (!vcapServices) {
22
13
  return undefined;
23
14
  }
@@ -42,12 +33,12 @@ function getConnectivityProxyInfo(vcapServices) {
42
33
  * @returns Parsed options object.
43
34
  */
44
35
  function loadEnvOptionsFromFile(rootPath, envOptionsPath) {
45
- const resolvedPath = node_path_1.default.resolve(rootPath, envOptionsPath);
46
- if (!node_fs_1.default.existsSync(resolvedPath)) {
36
+ const resolvedPath = path.resolve(rootPath, envOptionsPath);
37
+ if (!fs.existsSync(resolvedPath)) {
47
38
  throw new Error(`Env options file not found at "${resolvedPath}" (envOptionsPath: "${envOptionsPath}").`);
48
39
  }
49
40
  try {
50
- const content = node_fs_1.default.readFileSync(resolvedPath, 'utf8');
41
+ const content = fs.readFileSync(resolvedPath, 'utf8');
51
42
  return JSON.parse(content);
52
43
  }
53
44
  catch (err) {
@@ -61,7 +52,7 @@ function loadEnvOptionsFromFile(rootPath, envOptionsPath) {
61
52
  *
62
53
  * @param options - Env options to apply.
63
54
  */
64
- function applyToProcessEnv(options) {
55
+ export function applyToProcessEnv(options) {
65
56
  if (options.VCAP_SERVICES) {
66
57
  const connectivity = options.VCAP_SERVICES['connectivity'];
67
58
  if (Array.isArray(connectivity)) {
@@ -91,7 +82,7 @@ function applyToProcessEnv(options) {
91
82
  * @param logger - Logger for CF path.
92
83
  * @returns Loaded and merged env options.
93
84
  */
94
- async function loadEnvOptions(rootPath, effectiveOptions, logger) {
85
+ export async function loadEnvOptions(rootPath, effectiveOptions, logger) {
95
86
  const { envOptionsPath, destinations: middlewareDestinations } = effectiveOptions;
96
87
  if (envOptionsPath) {
97
88
  const envOptions = loadEnvOptionsFromFile(rootPath, envOptionsPath);
@@ -100,16 +91,16 @@ async function loadEnvOptions(rootPath, effectiveOptions, logger) {
100
91
  : middlewareDestinations;
101
92
  return { ...envOptions, destinations };
102
93
  }
103
- const mtaPath = node_path_1.default.resolve(rootPath, '..', 'mta.yaml');
104
- const spaceGuid = await (0, adp_tooling_1.getSpaceGuidFromUi5Yaml)(rootPath, logger);
94
+ const mtaPath = path.resolve(rootPath, '..', 'mta.yaml');
95
+ const spaceGuid = await getSpaceGuidFromUi5Yaml(rootPath, logger);
105
96
  if (!spaceGuid) {
106
97
  throw new Error('No space GUID (from config or ui5.yaml). Cannot load CF env options.');
107
98
  }
108
- if (!node_fs_1.default.existsSync(mtaPath)) {
99
+ if (!fs.existsSync(mtaPath)) {
109
100
  throw new Error(`mta.yaml not found at "${mtaPath}". Cannot load CF env options.`);
110
101
  }
111
- const mtaYaml = (0, adp_tooling_1.getYamlContent)(mtaPath);
112
- const VCAP_SERVICES = await (0, adp_tooling_1.buildVcapServicesFromResources)(mtaYaml.resources, spaceGuid, logger);
102
+ const mtaYaml = getYamlContent(mtaPath);
103
+ const VCAP_SERVICES = await buildVcapServicesFromResources(mtaYaml.resources, spaceGuid, logger);
113
104
  return {
114
105
  VCAP_SERVICES,
115
106
  destinations: middlewareDestinations
@@ -130,14 +121,14 @@ async function loadEnvOptions(rootPath, effectiveOptions, logger) {
130
121
  * @param basExternalUrl - Optional BAS external URL; when set, used as the destination URL.
131
122
  * @returns True if destination was created or updated, false if no change needed.
132
123
  */
133
- function updateUi5ServerDestinationPort(effectiveOptions, actualPort, basExternalUrl) {
124
+ export function updateUi5ServerDestinationPort(effectiveOptions, actualPort, basExternalUrl) {
134
125
  const newUrl = basExternalUrl ? basExternalUrl.href : `http://localhost:${actualPort}`;
135
- let ui5ServerDest = effectiveOptions.destinations.find((d) => d.name === constants_1.UI5_SERVER_DESTINATION);
126
+ let ui5ServerDest = effectiveOptions.destinations.find((d) => d.name === UI5_SERVER_DESTINATION);
136
127
  if (!ui5ServerDest) {
137
- ui5ServerDest = { name: constants_1.UI5_SERVER_DESTINATION, url: newUrl };
128
+ ui5ServerDest = { name: UI5_SERVER_DESTINATION, url: newUrl };
138
129
  effectiveOptions.destinations.push(ui5ServerDest);
139
130
  const envDestinations = JSON.parse(process.env.destinations ?? '[]');
140
- envDestinations.push({ name: constants_1.UI5_SERVER_DESTINATION, url: newUrl });
131
+ envDestinations.push({ name: UI5_SERVER_DESTINATION, url: newUrl });
141
132
  process.env.destinations = JSON.stringify(envDestinations);
142
133
  return true;
143
134
  }
@@ -148,12 +139,12 @@ function updateUi5ServerDestinationPort(effectiveOptions, actualPort, basExterna
148
139
  }
149
140
  ui5ServerDest.url = newUrl;
150
141
  const envDestinations = JSON.parse(process.env.destinations ?? '[]');
151
- const envUi5ServerDest = envDestinations.find((d) => d.name === constants_1.UI5_SERVER_DESTINATION);
142
+ const envUi5ServerDest = envDestinations.find((d) => d.name === UI5_SERVER_DESTINATION);
152
143
  if (envUi5ServerDest) {
153
144
  envUi5ServerDest.url = newUrl;
154
145
  }
155
146
  else {
156
- envDestinations.push({ name: constants_1.UI5_SERVER_DESTINATION, url: newUrl });
147
+ envDestinations.push({ name: UI5_SERVER_DESTINATION, url: newUrl });
157
148
  }
158
149
  process.env.destinations = JSON.stringify(envDestinations);
159
150
  return true;
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export type { BackendProxyMiddlewareCfConfig, ApprouterDestination, ApprouterExtension } from './types';
1
+ export type { BackendProxyMiddlewareCfConfig, ApprouterDestination, ApprouterExtension } from './types.js';
2
2
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,3 +1,2 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ export {};
3
2
  //# sourceMappingURL=index.js.map
@@ -1,2 +1,16 @@
1
- export {};
1
+ import type { MiddlewareParameters } from '@ui5/server';
2
+ import type { RequestHandler } from 'express';
3
+ import type { BackendProxyMiddlewareCfConfig } from './types.js';
4
+ /**
5
+ * UI5 server middleware: runs `@sap/approuter` and proxies matching requests to it.
6
+ * Uses lazy initialization to detect the actual UI5 server port from the first request,
7
+ * enabling multi-instance support where hardcoded ports in ui5.yaml may differ from runtime.
8
+ *
9
+ * @param params - Middleware parameters from UI5 (options, middlewareUtil).
10
+ * @param params.options - Options containing configuration from ui5.yaml.
11
+ * @param params.middlewareUtil - UI5 middleware utilities (getProject, etc.).
12
+ * @returns Promise resolving to the proxy request handler.
13
+ */
14
+ declare function backendProxyMiddlewareCf({ options, middlewareUtil }: MiddlewareParameters<BackendProxyMiddlewareCfConfig>): Promise<RequestHandler>;
15
+ export default backendProxyMiddlewareCf;
2
16
  //# sourceMappingURL=middleware.d.ts.map
@@ -1,23 +1,18 @@
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
- const node_fs_1 = __importDefault(require("node:fs"));
7
- const dotenv_1 = __importDefault(require("dotenv"));
8
- const node_path_1 = __importDefault(require("node:path"));
9
- const logger_1 = require("@sap-ux/logger");
10
- const utils_1 = require("./utils");
11
- const proxy_1 = require("./proxy/proxy");
12
- const approuter_1 = require("./approuter/approuter");
13
- const extensions_1 = require("./approuter/extensions");
14
- const config_1 = require("./config/config");
15
- const xssecurity_1 = require("./platform/xssecurity");
16
- const bas_1 = require("./platform/bas");
17
- const routes_1 = require("./proxy/routes");
18
- const env_1 = require("./config/env");
19
- const tunnel_1 = require("./tunnel/tunnel");
20
- dotenv_1.default.config();
1
+ import fs from 'node:fs';
2
+ import dotenv from 'dotenv';
3
+ import path from 'node:path';
4
+ import { LogLevel, ToolsLogger, UI5ToolingTransport } from '@sap-ux/logger';
5
+ import { nextFreePort } from './utils.js';
6
+ import { createProxy } from './proxy/proxy.js';
7
+ import { startApprouter } from './approuter/approuter.js';
8
+ import { loadExtensions } from './approuter/extensions.js';
9
+ import { mergeEffectiveOptions } from './config/config.js';
10
+ import { updateXsuaaService } from './platform/xssecurity.js';
11
+ import { fetchBasUrlTemplate, resolveBasExternalUrl } from './platform/bas.js';
12
+ import { buildRouteEntries, loadAndPrepareXsappConfig } from './proxy/routes.js';
13
+ import { loadEnvOptions, updateUi5ServerDestinationPort, getConnectivityProxyInfo, applyToProcessEnv } from './config/env.js';
14
+ import { setupSshTunnel } from './tunnel/tunnel.js';
15
+ dotenv.config();
21
16
  /**
22
17
  * UI5 server middleware: runs `@sap/approuter` and proxies matching requests to it.
23
18
  * Uses lazy initialization to detect the actual UI5 server port from the first request,
@@ -33,36 +28,36 @@ async function backendProxyMiddlewareCf({ options, middlewareUtil }) {
33
28
  if (!configuration) {
34
29
  throw new Error('Backend proxy middleware (CF) has no configuration.');
35
30
  }
36
- const logger = new logger_1.ToolsLogger({
37
- logLevel: configuration.debug ? logger_1.LogLevel.Debug : logger_1.LogLevel.Info,
38
- transports: [new logger_1.UI5ToolingTransport({ moduleName: 'backend-proxy-middleware-cf' })]
31
+ const logger = new ToolsLogger({
32
+ logLevel: configuration.debug ? LogLevel.Debug : LogLevel.Info,
33
+ transports: [new UI5ToolingTransport({ moduleName: 'backend-proxy-middleware-cf' })]
39
34
  });
40
- const effectiveOptions = (0, config_1.mergeEffectiveOptions)(configuration);
35
+ const effectiveOptions = mergeEffectiveOptions(configuration);
41
36
  process.env.WS_ALLOWED_ORIGINS = process.env.WS_ALLOWED_ORIGINS ?? JSON.stringify([{ host: 'localhost' }]);
42
37
  process.env.XS_APP_LOG_LEVEL = process.env.XS_APP_LOG_LEVEL ?? (effectiveOptions.debug ? 'DEBUG' : 'ERROR');
43
38
  const project = middlewareUtil.getProject();
44
39
  const rootPath = project.getRootPath() ?? process.cwd();
45
- const xsappJsonPath = node_path_1.default.resolve(rootPath, effectiveOptions.xsappJsonPath);
46
- if (!node_fs_1.default.existsSync(xsappJsonPath)) {
40
+ const xsappJsonPath = path.resolve(rootPath, effectiveOptions.xsappJsonPath);
41
+ if (!fs.existsSync(xsappJsonPath)) {
47
42
  throw new Error(`xs-app.json not found at "${xsappJsonPath}"`);
48
43
  }
49
- const envOptions = await (0, env_1.loadEnvOptions)(rootPath, effectiveOptions, logger);
50
- const connectivityInfo = (0, env_1.getConnectivityProxyInfo)(envOptions.VCAP_SERVICES);
51
- (0, env_1.applyToProcessEnv)(envOptions);
52
- await (0, xssecurity_1.updateXsuaaService)(rootPath, logger);
44
+ const envOptions = await loadEnvOptions(rootPath, effectiveOptions, logger);
45
+ const connectivityInfo = getConnectivityProxyInfo(envOptions.VCAP_SERVICES);
46
+ applyToProcessEnv(envOptions);
47
+ await updateXsuaaService(rootPath, logger);
53
48
  if (!effectiveOptions.disableSshTunnel && connectivityInfo) {
54
- await (0, tunnel_1.setupSshTunnel)(rootPath, connectivityInfo, effectiveOptions, logger);
49
+ await setupSshTunnel(rootPath, connectivityInfo, effectiveOptions, logger);
55
50
  }
56
51
  const sourcePath = project.getSourcePath();
57
- const xsappConfig = (0, routes_1.loadAndPrepareXsappConfig)({
52
+ const xsappConfig = loadAndPrepareXsappConfig({
58
53
  rootPath,
59
54
  xsappJsonPath,
60
55
  effectiveOptions,
61
56
  sourcePath,
62
57
  logger
63
58
  });
64
- const { modules, routes: extensionsRoutes } = (0, extensions_1.loadExtensions)(rootPath, effectiveOptions.extensions, logger);
65
- const port = await (0, utils_1.nextFreePort)(effectiveOptions.port, logger);
59
+ const { modules, routes: extensionsRoutes } = loadExtensions(rootPath, effectiveOptions.extensions, logger);
60
+ const port = await nextFreePort(effectiveOptions.port, logger);
66
61
  if (port !== effectiveOptions.port) {
67
62
  logger.info(`Port ${effectiveOptions.port} already in use. Using next free port: ${port} for the AppRouter.`);
68
63
  }
@@ -77,23 +72,23 @@ async function backendProxyMiddlewareCf({ options, middlewareUtil }) {
77
72
  if (logoutEndpoint) {
78
73
  customRoutes.push(logoutEndpoint);
79
74
  }
80
- const basUrlTemplate = await (0, bas_1.fetchBasUrlTemplate)(logger);
75
+ const basUrlTemplate = await fetchBasUrlTemplate(logger);
81
76
  let initialized = false;
82
77
  let proxyMiddleware = null;
83
78
  return function lazyApprouterMiddleware(req, res, next) {
84
79
  if (!initialized) {
85
80
  try {
86
81
  const actualPort = req.socket.localPort ?? 8080;
87
- const basExternalUrl = (0, bas_1.resolveBasExternalUrl)(basUrlTemplate, actualPort);
82
+ const basExternalUrl = resolveBasExternalUrl(basUrlTemplate, actualPort);
88
83
  if (basExternalUrl) {
89
84
  logger.info(`BAS detected. External URL: ${basExternalUrl.href}`);
90
85
  }
91
- if ((0, env_1.updateUi5ServerDestinationPort)(effectiveOptions, actualPort, basExternalUrl)) {
86
+ if (updateUi5ServerDestinationPort(effectiveOptions, actualPort, basExternalUrl)) {
92
87
  logger.info(`Auto-configured ui5-server destination to port ${actualPort}`);
93
88
  }
94
- const routes = (0, routes_1.buildRouteEntries)({ xsappConfig, effectiveOptions, logger });
95
- (0, approuter_1.startApprouter)({ port, xsappConfig, rootPath, modules, logger });
96
- proxyMiddleware = (0, proxy_1.createProxy)({ customRoutes, routes, baseUri, effectiveOptions, basExternalUrl }, logger);
89
+ const routes = buildRouteEntries({ xsappConfig, effectiveOptions, logger });
90
+ startApprouter({ port, xsappConfig, rootPath, modules, logger });
91
+ proxyMiddleware = createProxy({ customRoutes, routes, baseUri, effectiveOptions, basExternalUrl }, logger);
97
92
  initialized = true;
98
93
  }
99
94
  catch (err) {
@@ -103,5 +98,5 @@ async function backendProxyMiddlewareCf({ options, middlewareUtil }) {
103
98
  proxyMiddleware(req, res, next);
104
99
  };
105
100
  }
106
- module.exports = backendProxyMiddlewareCf;
101
+ export default backendProxyMiddlewareCf;
107
102
  //# sourceMappingURL=middleware.js.map
@@ -1,8 +1,4 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.fetchBasUrlTemplate = fetchBasUrlTemplate;
4
- exports.resolveBasExternalUrl = resolveBasExternalUrl;
5
- const btp_utils_1 = require("@sap-ux/btp-utils");
1
+ import { isAppStudio, exposePort } from '@sap-ux/btp-utils';
6
2
  /** Port placeholder used to obtain a BAS URL template before the actual port is known. */
7
3
  const BAS_PORT_PLACEHOLDER = 0;
8
4
  /**
@@ -12,11 +8,11 @@ const BAS_PORT_PLACEHOLDER = 0;
12
8
  * @param logger - Logger instance.
13
9
  * @returns URL template string, or empty string when not in BAS.
14
10
  */
15
- async function fetchBasUrlTemplate(logger) {
16
- if (!(0, btp_utils_1.isAppStudio)()) {
11
+ export async function fetchBasUrlTemplate(logger) {
12
+ if (!isAppStudio()) {
17
13
  return '';
18
14
  }
19
- return (0, btp_utils_1.exposePort)(BAS_PORT_PLACEHOLDER, logger);
15
+ return exposePort(BAS_PORT_PLACEHOLDER, logger);
20
16
  }
21
17
  /**
22
18
  * Replace the placeholder port in a BAS URL template with the actual runtime port
@@ -26,7 +22,7 @@ async function fetchBasUrlTemplate(logger) {
26
22
  * @param actualPort - The real UI5 server port detected at runtime.
27
23
  * @returns Resolved URL, or undefined if the template is empty.
28
24
  */
29
- function resolveBasExternalUrl(basUrlTemplate, actualPort) {
25
+ export function resolveBasExternalUrl(basUrlTemplate, actualPort) {
30
26
  if (!basUrlTemplate) {
31
27
  return undefined;
32
28
  }
@@ -1,12 +1,6 @@
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.updateXsuaaService = updateXsuaaService;
7
- const node_fs_1 = __importDefault(require("node:fs"));
8
- const node_path_1 = __importDefault(require("node:path"));
9
- const adp_tooling_1 = require("@sap-ux/adp-tooling");
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { getServicesForFile, updateServiceInstance } from '@sap-ux/adp-tooling';
10
4
  /**
11
5
  * Update the XSUAA service instance with oauth2-configuration redirect-uris
12
6
  * so that OAuth redirects work correctly in the BAS environment.
@@ -14,34 +8,34 @@ const adp_tooling_1 = require("@sap-ux/adp-tooling");
14
8
  * @param rootPath - Project root path (app folder; mta.yaml and xs-security.json are one level up).
15
9
  * @param logger - Logger instance.
16
10
  */
17
- async function updateXsuaaService(rootPath, logger) {
11
+ export async function updateXsuaaService(rootPath, logger) {
18
12
  try {
19
- const projectRoot = node_path_1.default.resolve(rootPath, '..');
20
- const xsSecurityPath = node_path_1.default.resolve(projectRoot, 'xs-security.json');
21
- const mtaPath = node_path_1.default.resolve(projectRoot, 'mta.yaml');
22
- if (!node_fs_1.default.existsSync(xsSecurityPath)) {
13
+ const projectRoot = path.resolve(rootPath, '..');
14
+ const xsSecurityPath = path.resolve(projectRoot, 'xs-security.json');
15
+ const mtaPath = path.resolve(projectRoot, 'mta.yaml');
16
+ if (!fs.existsSync(xsSecurityPath)) {
23
17
  logger.warn(`xs-security.json not found at "${xsSecurityPath}", skipping XSUAA service update.`);
24
18
  return;
25
19
  }
26
- if (!node_fs_1.default.existsSync(mtaPath)) {
20
+ if (!fs.existsSync(mtaPath)) {
27
21
  logger.warn(`mta.yaml not found at "${mtaPath}", skipping XSUAA service update.`);
28
22
  return;
29
23
  }
30
- const xsSecurityContent = JSON.parse(node_fs_1.default.readFileSync(xsSecurityPath, 'utf-8'));
24
+ const xsSecurityContent = JSON.parse(fs.readFileSync(xsSecurityPath, 'utf-8'));
31
25
  const augmented = {
32
26
  ...xsSecurityContent,
33
27
  'oauth2-configuration': {
34
28
  'redirect-uris': ['https://**.applicationstudio.cloud.sap/**', 'http://localhost:*/**']
35
29
  }
36
30
  };
37
- const mtaServices = (0, adp_tooling_1.getServicesForFile)(mtaPath, logger);
31
+ const mtaServices = getServicesForFile(mtaPath, logger);
38
32
  const serviceInstanceName = mtaServices.find((s) => s.label === 'xsuaa')?.name;
39
33
  if (!serviceInstanceName) {
40
34
  logger.warn('No xsuaa service instance name found in mta.yaml, skipping XSUAA service update.');
41
35
  return;
42
36
  }
43
37
  logger.info(`Updating XSUAA service instance "${serviceInstanceName}" with BAS redirect-uris.`);
44
- await (0, adp_tooling_1.updateServiceInstance)(serviceInstanceName, augmented);
38
+ await updateServiceInstance(serviceInstanceName, augmented);
45
39
  logger.info(`XSUAA service instance "${serviceInstanceName}" updated successfully.`);
46
40
  }
47
41
  catch (e) {
@@ -1,7 +1,7 @@
1
1
  import type { RequestHandler } from 'express';
2
2
  import { responseInterceptor } from 'http-proxy-middleware';
3
3
  import type { ToolsLogger } from '@sap-ux/logger';
4
- import type { CreateProxyOptions, EffectiveOptions, RouteEntry } from '../types';
4
+ import type { CreateProxyOptions, EffectiveOptions, RouteEntry } from '../types.js';
5
5
  /**
6
6
  * Create the response interceptor for the proxy (content-type + URL rewriting).
7
7
  *
@@ -1,10 +1,6 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createResponseInterceptor = createResponseInterceptor;
4
- exports.createProxy = createProxy;
5
- const http_proxy_middleware_1 = require("http-proxy-middleware");
6
- const constants_1 = require("../config/constants");
7
- const utils_1 = require("./utils");
1
+ import { createProxyMiddleware, responseInterceptor } from 'http-proxy-middleware';
2
+ import { PROXY_MARKER_HEADER } from '../config/constants.js';
3
+ import { createProxyFilter, getMimeInfo, getRequestOrigin, replaceUrl } from './utils.js';
8
4
  /**
9
5
  * Create the response interceptor for the proxy (content-type + URL rewriting).
10
6
  *
@@ -12,22 +8,22 @@ const utils_1 = require("./utils");
12
8
  * @param effectiveOptions - Merged options (rewriteContent, rewriteContentTypes, debug).
13
9
  * @returns The interceptor function to pass to responseInterceptor().
14
10
  */
15
- function createResponseInterceptor(routes, effectiveOptions) {
16
- return (0, http_proxy_middleware_1.responseInterceptor)(async (responseBuffer, proxyRes, req, res) => {
11
+ export function createResponseInterceptor(routes, effectiveOptions) {
12
+ return responseInterceptor(async (responseBuffer, proxyRes, req, res) => {
17
13
  const url = req.url ?? '';
18
14
  const pathname = /^[^?]*/.exec(url)?.[0] ?? url;
19
- const { type, charset, contentType: ct } = (0, utils_1.getMimeInfo)(pathname, proxyRes.headers['content-type']);
15
+ const { type, charset, contentType: ct } = getMimeInfo(pathname, proxyRes.headers['content-type']);
20
16
  res.setHeader('content-type', ct);
21
17
  const route = routes.find((routeEntry) => routeEntry.sourcePattern.test(url));
22
18
  if (route?.path && route.url && effectiveOptions?.rewriteContentTypes?.includes(type?.toLowerCase() ?? '')) {
23
19
  const encoding = (charset ?? 'utf8');
24
20
  let data = responseBuffer.toString(encoding);
25
- const referrer = req.headers.referrer ?? req.headers.referer ?? (0, utils_1.getRequestOrigin)(req);
21
+ const referrer = req.headers.referrer ?? req.headers.referer ?? getRequestOrigin(req);
26
22
  const referrerUrl = new URL(route.path, referrer).toString();
27
23
  const routeUrlParsed = new URL(route.url);
28
24
  const hostAndPath = `${routeUrlParsed.host}${routeUrlParsed.pathname}`;
29
- data = (0, utils_1.replaceUrl)(data, `https://${hostAndPath}`, referrerUrl);
30
- data = (0, utils_1.replaceUrl)(data, `http://${hostAndPath}`, referrerUrl);
25
+ data = replaceUrl(data, `https://${hostAndPath}`, referrerUrl);
26
+ data = replaceUrl(data, `http://${hostAndPath}`, referrerUrl);
31
27
  return Buffer.from(data);
32
28
  }
33
29
  return responseBuffer;
@@ -41,11 +37,11 @@ function createResponseInterceptor(routes, effectiveOptions) {
41
37
  * @param logger - Logger instance.
42
38
  * @returns Express request handler (the proxy middleware).
43
39
  */
44
- function createProxy(options, logger) {
40
+ export function createProxy(options, logger) {
45
41
  const { customRoutes, routes, baseUri, effectiveOptions, basExternalUrl } = options;
46
42
  const intercept = createResponseInterceptor(routes, effectiveOptions);
47
- const proxyFilter = (0, utils_1.createProxyFilter)(customRoutes, routes);
48
- const proxyMiddleware = (0, http_proxy_middleware_1.createProxyMiddleware)({
43
+ const proxyFilter = createProxyFilter(customRoutes, routes);
44
+ const proxyMiddleware = createProxyMiddleware({
49
45
  logger: effectiveOptions.debug ? logger : undefined,
50
46
  target: baseUri,
51
47
  pathFilter: proxyFilter,
@@ -55,7 +51,7 @@ function createProxy(options, logger) {
55
51
  xfwd: true,
56
52
  on: {
57
53
  proxyReq: (proxyReq, req, res) => {
58
- proxyReq.setHeader(constants_1.PROXY_MARKER_HEADER, '1');
54
+ proxyReq.setHeader(PROXY_MARKER_HEADER, '1');
59
55
  const xfp = req.headers['x-forwarded-proto'];
60
56
  if (typeof xfp === 'string' && xfp.includes(',')) {
61
57
  const proto = xfp.split(',')[0];
@@ -1,4 +1,4 @@
1
- import type { BuildRouteEntriesOptions, PrepareXsappConfigOptions, RouteEntry, XsappConfig } from '../types';
1
+ import type { BuildRouteEntriesOptions, PrepareXsappConfigOptions, RouteEntry, XsappConfig } from '../types.js';
2
2
  /**
3
3
  * Load xs-app.json and prepare it for the approuter (filter routes, set auth, optionally append auth route).
4
4
  * Mutates and returns the config; does not build RouteEntry[].
@@ -1,13 +1,6 @@
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.loadAndPrepareXsappConfig = loadAndPrepareXsappConfig;
7
- exports.buildRouteEntries = buildRouteEntries;
8
- const node_fs_1 = __importDefault(require("node:fs"));
9
- const node_path_1 = __importDefault(require("node:path"));
10
- const constants_1 = require("../config/constants");
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { UI5_SERVER_DESTINATION } from '../config/constants.js';
11
4
  /**
12
5
  * Auth route for HTML pages - triggers XSUAA login.
13
6
  * Only this route is needed; /resources and /test-resources are handled
@@ -15,7 +8,7 @@ const constants_1 = require("../config/constants");
15
8
  */
16
9
  const UI5_SERVER_AUTH_ROUTE = {
17
10
  source: String.raw `^/(test|local)/.*\.html.*$`,
18
- destination: constants_1.UI5_SERVER_DESTINATION,
11
+ destination: UI5_SERVER_DESTINATION,
19
12
  authenticationType: 'xsuaa'
20
13
  };
21
14
  /**
@@ -29,12 +22,12 @@ const UI5_SERVER_AUTH_ROUTE = {
29
22
  * @param logger - Logger for info/warn messages.
30
23
  */
31
24
  function injectAdpLiveReloadRoutes(routes, rootPath, logger) {
32
- const manifestPath = node_path_1.default.join(rootPath, 'webapp', 'manifest.appdescr_variant');
33
- if (!node_fs_1.default.existsSync(manifestPath)) {
25
+ const manifestPath = path.join(rootPath, 'webapp', 'manifest.appdescr_variant');
26
+ if (!fs.existsSync(manifestPath)) {
34
27
  return;
35
28
  }
36
29
  try {
37
- const manifest = JSON.parse(node_fs_1.default.readFileSync(manifestPath, 'utf8'));
30
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
38
31
  const variantId = manifest.id.replaceAll('.', '_');
39
32
  routes.unshift({
40
33
  source: `^/changes/${variantId}/(.*)$`,
@@ -60,9 +53,9 @@ function injectAdpLiveReloadRoutes(routes, rootPath, logger) {
60
53
  * @param options - rootPath, xsappJsonPath, effectiveOptions, sourcePath.
61
54
  * @returns The loaded and mutated XsappConfig.
62
55
  */
63
- function loadAndPrepareXsappConfig(options) {
56
+ export function loadAndPrepareXsappConfig(options) {
64
57
  const { rootPath, xsappJsonPath, effectiveOptions, sourcePath, logger } = options;
65
- const xsappConfig = JSON.parse(node_fs_1.default.readFileSync(xsappJsonPath, 'utf8'));
58
+ const xsappConfig = JSON.parse(fs.readFileSync(xsappJsonPath, 'utf8'));
66
59
  const xsappRoutes = xsappConfig.routes ?? [];
67
60
  xsappConfig.routes = xsappRoutes.filter((route) => {
68
61
  if (route.service === 'html5-apps-repo-rt') {
@@ -84,7 +77,7 @@ function loadAndPrepareXsappConfig(options) {
84
77
  if (effectiveOptions.appendAuthRoute &&
85
78
  effectiveOptions.authenticationMethod &&
86
79
  effectiveOptions.authenticationMethod !== 'none') {
87
- const relativeSourcePath = node_path_1.default.relative(rootPath, sourcePath);
80
+ const relativeSourcePath = path.relative(rootPath, sourcePath);
88
81
  xsappConfig.routes.push({
89
82
  source: String.raw `^/([^.]+\\.html?(?:\?.*)?)$`,
90
83
  localDir: relativeSourcePath,
@@ -112,7 +105,7 @@ function loadAndPrepareXsappConfig(options) {
112
105
  * @param options - xsappConfig, effectiveOptions, logger.
113
106
  * @returns Route entries for the proxy.
114
107
  */
115
- function buildRouteEntries(options) {
108
+ export function buildRouteEntries(options) {
116
109
  const { xsappConfig, effectiveOptions, logger } = options;
117
110
  const routes = [];
118
111
  const destList = Array.isArray(effectiveOptions.destinations) ? effectiveOptions.destinations : [];
@@ -1,5 +1,5 @@
1
1
  import type { IncomingMessage } from 'node:http';
2
- import type { MimeInfo, RouteEntry } from '../types';
2
+ import type { MimeInfo, RouteEntry } from '../types.js';
3
3
  /**
4
4
  * Escape a string so it can be safely embedded in a RegExp.
5
5
  *
@@ -1,25 +1,13 @@
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");
1
+ import mime from 'mime-types';
2
+ import contentType from 'content-type';
3
+ import { PROXY_MARKER_HEADER } from '../config/constants.js';
16
4
  /**
17
5
  * Escape a string so it can be safely embedded in a RegExp.
18
6
  *
19
7
  * @param value - Raw string.
20
8
  * @returns Regex-safe string with all metacharacters escaped.
21
9
  */
22
- function escapeRegExp(value) {
10
+ export function escapeRegExp(value) {
23
11
  return value.replaceAll(/[-/\\^$*+?.()|[\]{}]/g, String.raw `\$&`);
24
12
  }
25
13
  /**
@@ -30,7 +18,7 @@ function escapeRegExp(value) {
30
18
  * @param newUrl - Replacement URL.
31
19
  * @returns Text with URLs replaced.
32
20
  */
33
- function replaceUrl(text, oldUrl, newUrl) {
21
+ export function replaceUrl(text, oldUrl, newUrl) {
34
22
  const regex = new RegExp(escapeRegExp(oldUrl), 'gi');
35
23
  return text.replace(regex, newUrl);
36
24
  }
@@ -41,7 +29,7 @@ function replaceUrl(text, oldUrl, newUrl) {
41
29
  * @param routes - Route entries with compiled regex.
42
30
  * @returns Filter function (pathname) => boolean.
43
31
  */
44
- function createPathFilter(customRoutes, routes) {
32
+ export function createPathFilter(customRoutes, routes) {
45
33
  const compiledCustomRoutes = customRoutes.map((route) => new RegExp(String.raw `^${escapeRegExp(route)}(\?.*)?$`));
46
34
  return (pathname) => {
47
35
  return (compiledCustomRoutes.some((customRoute) => customRoute.test(pathname)) ||
@@ -57,8 +45,8 @@ function createPathFilter(customRoutes, routes) {
57
45
  * @param req - Incoming request.
58
46
  * @returns True if request came from approuter.
59
47
  */
60
- function isRequestFromApprouter(req) {
61
- return !!req.headers[constants_1.PROXY_MARKER_HEADER];
48
+ export function isRequestFromApprouter(req) {
49
+ return !!req.headers[PROXY_MARKER_HEADER];
62
50
  }
63
51
  /**
64
52
  * Creates a proxy filter that checks both route matching and approuter origin.
@@ -68,7 +56,7 @@ function isRequestFromApprouter(req) {
68
56
  * @param routes - Route entries with compiled regex.
69
57
  * @returns Filter function (pathname, req) => boolean for http-proxy-middleware.
70
58
  */
71
- function createProxyFilter(customRoutes, routes) {
59
+ export function createProxyFilter(customRoutes, routes) {
72
60
  const pathFilter = createPathFilter(customRoutes, routes);
73
61
  return (pathname, req) => {
74
62
  return !isRequestFromApprouter(req) && pathFilter(pathname);
@@ -82,7 +70,7 @@ function createProxyFilter(customRoutes, routes) {
82
70
  * @param req.baseUrl - Optional base URL path.
83
71
  * @returns Origin URL string.
84
72
  */
85
- function getRequestOrigin(req) {
73
+ export function getRequestOrigin(req) {
86
74
  return `${String((req.headers['x-forwarded-proto'] ?? 'https').toString().split(',')[0])}://${req.headers['x-forwarded-host'] ?? ''}${req.baseUrl ?? ''}`;
87
75
  }
88
76
  /**
@@ -92,19 +80,19 @@ function getRequestOrigin(req) {
92
80
  * @param ctValue - Content-Type header value.
93
81
  * @returns MimeInfo object.
94
82
  */
95
- function getMimeInfo(pathname, ctValue) {
83
+ export function getMimeInfo(pathname, ctValue) {
96
84
  if (ctValue) {
97
- const parsed = content_type_1.default.parse(ctValue);
85
+ const parsed = contentType.parse(ctValue);
98
86
  const type = parsed.type ?? 'application/octet-stream';
99
- const charset = parsed.parameters?.charset ?? mime_types_1.default.charset(type) ?? 'utf-8';
87
+ const charset = parsed.parameters?.charset ?? mime.charset(type) ?? 'utf-8';
100
88
  return {
101
89
  type,
102
90
  charset,
103
- contentType: content_type_1.default.format({ type, parameters: parsed.parameters })
91
+ contentType: contentType.format({ type, parameters: parsed.parameters })
104
92
  };
105
93
  }
106
- const type = mime_types_1.default.lookup(pathname) || 'application/octet-stream';
107
- const charset = mime_types_1.default.charset(type) || 'utf-8';
94
+ const type = mime.lookup(pathname) || 'application/octet-stream';
95
+ const charset = mime.charset(type) || 'utf-8';
108
96
  return {
109
97
  type,
110
98
  charset,
@@ -1,13 +1,7 @@
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.hasOnPremiseDestination = hasOnPremiseDestination;
7
- const node_fs_1 = __importDefault(require("node:fs"));
8
- const node_path_1 = __importDefault(require("node:path"));
9
- const btp_utils_1 = require("@sap-ux/btp-utils");
10
- const adp_tooling_1 = require("@sap-ux/adp-tooling");
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { DestinationProxyType } from '@sap-ux/btp-utils';
4
+ import { getToken, getBtpDestinationConfig } from '@sap-ux/adp-tooling';
11
5
  /**
12
6
  * Extract unique destination names from the routes in webapp/xs-app.json.
13
7
  *
@@ -15,12 +9,12 @@ const adp_tooling_1 = require("@sap-ux/adp-tooling");
15
9
  * @returns Array of unique destination names, or empty array if no webapp/xs-app.json or no destinations.
16
10
  */
17
11
  function getWebappXsappDestinationNames(rootPath) {
18
- const xsappPath = node_path_1.default.join(rootPath, 'webapp', 'xs-app.json');
19
- if (!node_fs_1.default.existsSync(xsappPath)) {
12
+ const xsappPath = path.join(rootPath, 'webapp', 'xs-app.json');
13
+ if (!fs.existsSync(xsappPath)) {
20
14
  return [];
21
15
  }
22
16
  try {
23
- const xsappConfig = JSON.parse(node_fs_1.default.readFileSync(xsappPath, 'utf8'));
17
+ const xsappConfig = JSON.parse(fs.readFileSync(xsappPath, 'utf8'));
24
18
  const names = new Set();
25
19
  for (const route of xsappConfig.routes ?? []) {
26
20
  if (route.destination) {
@@ -71,7 +65,7 @@ function getBtpDestinationServiceAuth() {
71
65
  * @param logger - Logger instance.
72
66
  * @returns True if an OnPremise destination is found; false otherwise.
73
67
  */
74
- async function hasOnPremiseDestination(rootPath, logger) {
68
+ export async function hasOnPremiseDestination(rootPath, logger) {
75
69
  const destinationNames = getWebappXsappDestinationNames(rootPath);
76
70
  if (destinationNames.length === 0) {
77
71
  logger.debug('No webapp/xs-app.json or no destinations in routes, skipping OnPremise check.');
@@ -84,7 +78,7 @@ async function hasOnPremiseDestination(rootPath, logger) {
84
78
  }
85
79
  let token;
86
80
  try {
87
- token = await (0, adp_tooling_1.getToken)(auth.uaa, logger);
81
+ token = await getToken(auth.uaa, logger);
88
82
  }
89
83
  catch (e) {
90
84
  const message = e instanceof Error ? e.message : String(e);
@@ -93,8 +87,8 @@ async function hasOnPremiseDestination(rootPath, logger) {
93
87
  }
94
88
  for (const name of destinationNames) {
95
89
  try {
96
- const config = await (0, adp_tooling_1.getBtpDestinationConfig)(auth.uri, token, name, logger);
97
- if (config?.ProxyType === btp_utils_1.DestinationProxyType.ON_PREMISE) {
90
+ const config = await getBtpDestinationConfig(auth.uri, token, name, logger);
91
+ if (config?.ProxyType === DestinationProxyType.ON_PREMISE) {
98
92
  logger.info(`Destination "${name}" is OnPremise, SSH tunnel is needed.`);
99
93
  return true;
100
94
  }
@@ -1,6 +1,6 @@
1
1
  import type { ChildProcess } from 'node:child_process';
2
2
  import type { ToolsLogger } from '@sap-ux/logger';
3
- import type { ConnectivityProxyInfo, SshTunnelOptions, EffectiveOptions } from '../types';
3
+ import type { ConnectivityProxyInfo, SshTunnelOptions, EffectiveOptions } from '../types.js';
4
4
  /**
5
5
  * Start an SSH tunnel to the connectivity proxy if needed.
6
6
  * Skips if the port is already in use or if no connectivity service is present.
@@ -1,14 +1,7 @@
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.startSshTunnelIfNeeded = startSshTunnelIfNeeded;
7
- exports.setupSshTunnel = setupSshTunnel;
8
- const node_net_1 = __importDefault(require("node:net"));
9
- const node_child_process_1 = require("node:child_process");
10
- const adp_tooling_1 = require("@sap-ux/adp-tooling");
11
- const destination_check_1 = require("./destination-check");
1
+ import net from 'node:net';
2
+ import { spawn } from 'node:child_process';
3
+ import { ensureTunnelAppExists, enableSshAndRestart, DEFAULT_TUNNEL_APP_NAME } from '@sap-ux/adp-tooling';
4
+ import { hasOnPremiseDestination } from './destination-check.js';
12
5
  /**
13
6
  * Check if a port is already in use.
14
7
  *
@@ -17,7 +10,7 @@ const destination_check_1 = require("./destination-check");
17
10
  */
18
11
  function isPortInUse(port) {
19
12
  return new Promise((resolve) => {
20
- const server = node_net_1.default.createServer();
13
+ const server = net.createServer();
21
14
  server.once('error', () => resolve(true));
22
15
  server.once('listening', () => {
23
16
  server.close(() => resolve(false));
@@ -40,7 +33,7 @@ function waitForPort(port, timeoutMs) {
40
33
  resolve(false);
41
34
  return;
42
35
  }
43
- const socket = node_net_1.default.connect(port, '127.0.0.1');
36
+ const socket = net.connect(port, '127.0.0.1');
44
37
  socket.once('connect', () => {
45
38
  socket.destroy();
46
39
  resolve(true);
@@ -66,7 +59,7 @@ function waitForPort(port, timeoutMs) {
66
59
  function spawnSshTunnel(appName, localPort, remoteHost, remotePort, logger) {
67
60
  const tunnelArg = `${localPort}:${remoteHost}:${remotePort}`;
68
61
  logger.info(`Starting SSH tunnel: cf ssh ${appName} -N -T -L ${tunnelArg}`);
69
- const child = (0, node_child_process_1.spawn)('cf', ['ssh', appName, '-N', '-T', '-L', tunnelArg], {
62
+ const child = spawn('cf', ['ssh', appName, '-N', '-T', '-L', tunnelArg], {
70
63
  stdio: 'pipe',
71
64
  shell: process.platform === 'win32'
72
65
  });
@@ -111,7 +104,7 @@ function registerCleanup(tunnelProcess, logger) {
111
104
  * @param options - Optional tunnel configuration.
112
105
  * @returns The SSH tunnel child process, or undefined if not started.
113
106
  */
114
- async function startSshTunnelIfNeeded(connectivityInfo, tunnelAppName, logger, options) {
107
+ export async function startSshTunnelIfNeeded(connectivityInfo, tunnelAppName, logger, options) {
115
108
  try {
116
109
  const localPort = options?.localPort ?? connectivityInfo.port;
117
110
  if (await isPortInUse(localPort)) {
@@ -119,7 +112,7 @@ async function startSshTunnelIfNeeded(connectivityInfo, tunnelAppName, logger, o
119
112
  return undefined;
120
113
  }
121
114
  if (!options?.skipSshEnable) {
122
- await (0, adp_tooling_1.enableSshAndRestart)(tunnelAppName, logger);
115
+ await enableSshAndRestart(tunnelAppName, logger);
123
116
  }
124
117
  const child = spawnSshTunnel(tunnelAppName, localPort, connectivityInfo.host, connectivityInfo.port, logger);
125
118
  registerCleanup(child, logger);
@@ -147,14 +140,14 @@ async function startSshTunnelIfNeeded(connectivityInfo, tunnelAppName, logger, o
147
140
  * @param effectiveOptions - Merged middleware options.
148
141
  * @param logger - Logger instance.
149
142
  */
150
- async function setupSshTunnel(rootPath, connectivityInfo, effectiveOptions, logger) {
151
- const needsSshTunnel = await (0, destination_check_1.hasOnPremiseDestination)(rootPath, logger);
143
+ export async function setupSshTunnel(rootPath, connectivityInfo, effectiveOptions, logger) {
144
+ const needsSshTunnel = await hasOnPremiseDestination(rootPath, logger);
152
145
  if (!needsSshTunnel) {
153
146
  logger.info('No OnPremise destination found in webapp/xs-app.json, skipping SSH tunnel setup.');
154
147
  return;
155
148
  }
156
- const tunnelAppName = effectiveOptions.tunnelAppName ?? adp_tooling_1.DEFAULT_TUNNEL_APP_NAME;
157
- await (0, adp_tooling_1.ensureTunnelAppExists)(tunnelAppName, logger);
149
+ const tunnelAppName = effectiveOptions.tunnelAppName ?? DEFAULT_TUNNEL_APP_NAME;
150
+ await ensureTunnelAppExists(tunnelAppName, logger);
158
151
  await startSshTunnelIfNeeded(connectivityInfo, tunnelAppName, logger, {
159
152
  localPort: effectiveOptions.tunnelLocalPort,
160
153
  skipSshEnable: effectiveOptions.skipSshEnable
package/dist/types.js CHANGED
@@ -1,3 +1,2 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ export {};
3
2
  //# sourceMappingURL=types.js.map
package/dist/utils.js CHANGED
@@ -1,10 +1,4 @@
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"));
1
+ import portfinder from 'portfinder';
8
2
  /**
9
3
  * Returns the next free port starting from basePort.
10
4
  *
@@ -12,10 +6,10 @@ const portfinder_1 = __importDefault(require("portfinder"));
12
6
  * @param logger - Optional logger to warn if portfinder fails and basePort is used.
13
7
  * @returns A free port number.
14
8
  */
15
- async function nextFreePort(basePort, logger) {
9
+ export async function nextFreePort(basePort, logger) {
16
10
  try {
17
- portfinder_1.default.basePort = basePort;
18
- return await portfinder_1.default.getPortPromise();
11
+ portfinder.basePort = basePort;
12
+ return await portfinder.getPortPromise();
19
13
  }
20
14
  catch {
21
15
  logger?.warn(`portfinder failed, using base port ${basePort}.`);
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@sap-ux/backend-proxy-middleware-cf",
3
3
  "description": "UI5 server middleware using @sap/approuter for CF-style destinations and xs-app.json",
4
+ "type": "module",
4
5
  "repository": {
5
6
  "type": "git",
6
7
  "url": "https://github.com/SAP/open-ux-tools.git",
@@ -9,7 +10,7 @@
9
10
  "bugs": {
10
11
  "url": "https://github.com/SAP/open-ux-tools/issues?q=is%3Aopen+is%3Aissue+label%3Abug+label%3Abackend-proxy-middleware-cf"
11
12
  },
12
- "version": "0.2.10",
13
+ "version": "0.3.0",
13
14
  "license": "Apache-2.0",
14
15
  "author": "@SAP/ux-tools-team",
15
16
  "main": "dist/index.js",
@@ -27,11 +28,12 @@
27
28
  "http-proxy-middleware": "3.0.5",
28
29
  "mime-types": "^2.1.35",
29
30
  "portfinder": "^1.0.32",
30
- "@sap-ux/adp-tooling": "0.19.10",
31
- "@sap-ux/btp-utils": "1.2.1",
32
- "@sap-ux/logger": "0.9.0"
31
+ "@sap-ux/adp-tooling": "1.0.0",
32
+ "@sap-ux/btp-utils": "2.0.0",
33
+ "@sap-ux/logger": "1.0.0"
33
34
  },
34
35
  "devDependencies": {
36
+ "@jest/globals": "30.3.0",
35
37
  "@types/content-type": "^1.0.0",
36
38
  "@types/express": "4.17.21",
37
39
  "@types/http-proxy": "^1.17.5",
@@ -47,6 +49,6 @@
47
49
  "format": "prettier --write '**/*.{js,json,ts,yaml,yml}' --ignore-path ../../.prettierignore",
48
50
  "lint": "eslint",
49
51
  "lint:fix": "eslint --fix",
50
- "test": "jest --ci --forceExit --detectOpenHandles --colors"
52
+ "test": "cross-env NODE_OPTIONS='--experimental-vm-modules' jest --ci --forceExit --detectOpenHandles --colors"
51
53
  }
52
54
  }