@sap-ux/adp-tooling 0.18.109 → 0.18.111

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,5 +1,6 @@
1
1
  import type { Editor } from 'mem-fs-editor';
2
2
  import type { ReaderCollection } from '@ui5/fs';
3
+ import type { ToolsLogger } from '@sap-ux/logger';
3
4
  import type { UI5Config } from '@sap-ux/ui5-config';
4
5
  import { type Inbound, AdaptationProjectType } from '@sap-ux/axios-extension';
5
6
  import { type ManifestNamespace, type Manifest } from '@sap-ux/project-access';
@@ -60,6 +61,14 @@ export declare function extractAdpConfig(ui5Conf: UI5Config): AdpPreviewConfig |
60
61
  * @returns {UI5YamlCustomTaskConfiguration} The CF build task.
61
62
  */
62
63
  export declare function extractCfBuildTask(ui5Conf: UI5Config): UI5YamlCustomTaskConfiguration;
64
+ /**
65
+ * Read space GUID from ui5.yaml customTasks app-variant-bundler-build.space.
66
+ *
67
+ * @param {string} rootPath - Project root (where ui5.yaml lives).
68
+ * @param {ToolsLogger} logger - Optional logger.
69
+ * @returns {Promise<string | undefined>} Space GUID or undefined if not found.
70
+ */
71
+ export declare function getSpaceGuidFromUi5Yaml(rootPath: string, logger?: ToolsLogger): Promise<string | undefined>;
63
72
  /**
64
73
  * Read the manifest from the build output folder.
65
74
  *
@@ -7,6 +7,7 @@ exports.isTypescriptSupported = isTypescriptSupported;
7
7
  exports.readUi5Config = readUi5Config;
8
8
  exports.extractAdpConfig = extractAdpConfig;
9
9
  exports.extractCfBuildTask = extractCfBuildTask;
10
+ exports.getSpaceGuidFromUi5Yaml = getSpaceGuidFromUi5Yaml;
10
11
  exports.readManifestFromBuildPath = readManifestFromBuildPath;
11
12
  exports.loadAppVariant = loadAppVariant;
12
13
  exports.getAdpConfig = getAdpConfig;
@@ -101,6 +102,24 @@ function extractCfBuildTask(ui5Conf) {
101
102
  }
102
103
  return buildTask;
103
104
  }
105
+ /**
106
+ * Read space GUID from ui5.yaml customTasks app-variant-bundler-build.space.
107
+ *
108
+ * @param {string} rootPath - Project root (where ui5.yaml lives).
109
+ * @param {ToolsLogger} logger - Optional logger.
110
+ * @returns {Promise<string | undefined>} Space GUID or undefined if not found.
111
+ */
112
+ async function getSpaceGuidFromUi5Yaml(rootPath, logger) {
113
+ try {
114
+ const ui5Config = await readUi5Config(rootPath, 'ui5.yaml');
115
+ const buildTask = extractCfBuildTask(ui5Config);
116
+ return buildTask?.space;
117
+ }
118
+ catch {
119
+ logger?.warn('Could not read space from ui5.yaml (app-variant-bundler-build).');
120
+ return undefined;
121
+ }
122
+ }
104
123
  /**
105
124
  * Read the manifest from the build output folder.
106
125
  *
@@ -16,19 +16,6 @@ export declare function getAppHostIds(serviceKeys: ServiceKeys[]): string[];
16
16
  * @returns {string[]} Array of backend URLs (including full paths) or empty array if none found.
17
17
  */
18
18
  export declare function getBackendUrlsFromServiceKeys(serviceKeys: ServiceKeys[]): string[];
19
- /**
20
- * Maps backend URLs to their corresponding OAuth paths based on destination matching
21
- * between xs-app.json routes and credentials.json endpoints.
22
- *
23
- * @param {ServiceKeys[]} serviceKeys - The service keys containing endpoints with destinations.
24
- * @param {string} basePath - Path to the .adp/reuse folder containing xs-app.json files.
25
- * @returns {Array<{ url: string; paths: string[]; pathRewrite?: string }>} Array of URL-to-paths mappings with optional pathRewrite.
26
- */
27
- export declare function getBackendUrlsWithPaths(serviceKeys: ServiceKeys[], basePath: string): Array<{
28
- url: string;
29
- paths: string[];
30
- pathRewrite?: string;
31
- }>;
32
19
  /**
33
20
  * Extract endpoint destinations from service keys.
34
21
  *
@@ -2,12 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getAppHostIds = getAppHostIds;
4
4
  exports.getBackendUrlsFromServiceKeys = getBackendUrlsFromServiceKeys;
5
- exports.getBackendUrlsWithPaths = getBackendUrlsWithPaths;
6
5
  exports.getServiceKeyDestinations = getServiceKeyDestinations;
7
6
  exports.getOAuthPathsFromXsApp = getOAuthPathsFromXsApp;
8
7
  exports.getCfApps = getCfApps;
9
- const node_fs_1 = require("node:fs");
10
- const node_path_1 = require("node:path");
11
8
  const i18n_1 = require("../../i18n");
12
9
  const utils_1 = require("../utils");
13
10
  const api_1 = require("../services/api");
@@ -52,25 +49,6 @@ function getBackendUrlsFromServiceKeys(serviceKeys) {
52
49
  }
53
50
  return urls;
54
51
  }
55
- /**
56
- * Extract destination to URL mapping from service key endpoints.
57
- *
58
- * @param {ServiceKeys[]} serviceKeys - The service keys containing endpoints.
59
- * @returns {Map<string, string>} Map of destination names to URLs.
60
- */
61
- function extractDestinationToUrlMap(serviceKeys) {
62
- const destinationToUrl = new Map();
63
- const endpoints = serviceKeys[0]?.credentials?.endpoints;
64
- if (endpoints && typeof endpoints === 'object') {
65
- for (const key in endpoints) {
66
- const endpoint = endpoints[key];
67
- if (endpoint?.url && endpoint.destination) {
68
- destinationToUrl.set(endpoint.destination, endpoint.url);
69
- }
70
- }
71
- }
72
- return destinationToUrl;
73
- }
74
52
  /**
75
53
  * Clean regex pattern from route source.
76
54
  *
@@ -95,95 +73,6 @@ function cleanRoutePath(source) {
95
73
  path = path.replace(/\/$/, '');
96
74
  return path;
97
75
  }
98
- /**
99
- * Process a route and extract path and pathRewrite from source and target.
100
- *
101
- * @param {XsAppRoute} route - The route object from xs-app.json.
102
- * @param {Map<string, { paths: Set<string>; pathRewrite?: string }>} destinationToPaths - Map to store destination info.
103
- */
104
- function processRouteForDestination(route, destinationToPaths) {
105
- const destination = route.destination;
106
- const service = route.service;
107
- if (!destination || service === 'html5-apps-repo-rt' || !route.source) {
108
- return;
109
- }
110
- const path = cleanRoutePath(route.source);
111
- if (path) {
112
- if (!destinationToPaths.has(destination)) {
113
- destinationToPaths.set(destination, { paths: new Set() });
114
- }
115
- const destInfo = destinationToPaths.get(destination);
116
- destInfo.paths.add(path);
117
- // Extract pathRewrite from target if available
118
- if (route.target && typeof route.target === 'string') {
119
- const pathRewrite = cleanRoutePath(route.target);
120
- if (pathRewrite && !destInfo.pathRewrite) {
121
- destInfo.pathRewrite = pathRewrite;
122
- }
123
- }
124
- }
125
- }
126
- /**
127
- * Extract destination to paths mapping from xs-app.json routes with pathRewrite info.
128
- *
129
- * @param {string} xsAppPath - Path to xs-app.json file.
130
- * @returns {Map<string, { paths: Set<string>; pathRewrite?: string }>} Map of destination names to path info.
131
- */
132
- function extractDestinationToPathsMap(xsAppPath) {
133
- const destinationToPaths = new Map();
134
- try {
135
- const xsAppContent = (0, node_fs_1.readFileSync)(xsAppPath, 'utf8');
136
- const xsApp = JSON.parse(xsAppContent);
137
- if (xsApp?.routes) {
138
- for (const route of xsApp.routes) {
139
- processRouteForDestination(route, destinationToPaths);
140
- }
141
- }
142
- }
143
- catch (e) {
144
- throw new Error((0, i18n_1.t)('error.invalidXsAppJson', { error: e.message }));
145
- }
146
- return destinationToPaths;
147
- }
148
- /**
149
- * Maps backend URLs to their corresponding OAuth paths based on destination matching
150
- * between xs-app.json routes and credentials.json endpoints.
151
- *
152
- * @param {ServiceKeys[]} serviceKeys - The service keys containing endpoints with destinations.
153
- * @param {string} basePath - Path to the .adp/reuse folder containing xs-app.json files.
154
- * @returns {Array<{ url: string; paths: string[]; pathRewrite?: string }>} Array of URL-to-paths mappings with optional pathRewrite.
155
- */
156
- function getBackendUrlsWithPaths(serviceKeys, basePath) {
157
- const destinationToUrl = extractDestinationToUrlMap(serviceKeys);
158
- const reuseXsAppPath = (0, node_path_1.join)(basePath, '.adp', 'reuse', 'xs-app.json');
159
- const distXsAppPath = (0, node_path_1.join)(basePath, 'dist', 'xs-app.json');
160
- let xsAppPath;
161
- if ((0, node_fs_1.existsSync)(reuseXsAppPath)) {
162
- xsAppPath = reuseXsAppPath;
163
- }
164
- else if ((0, node_fs_1.existsSync)(distXsAppPath)) {
165
- xsAppPath = distXsAppPath;
166
- }
167
- else {
168
- throw new Error((0, i18n_1.t)('error.xsAppJsonNotFound', { paths: `${reuseXsAppPath}, ${distXsAppPath}` }));
169
- }
170
- const destinationToPaths = extractDestinationToPathsMap(xsAppPath);
171
- const result = [];
172
- for (const [destination, pathInfo] of destinationToPaths.entries()) {
173
- const url = destinationToUrl.get(destination);
174
- if (url) {
175
- const entry = {
176
- url,
177
- paths: Array.from(pathInfo.paths)
178
- };
179
- if (pathInfo.pathRewrite) {
180
- entry.pathRewrite = pathInfo.pathRewrite;
181
- }
182
- result.push(entry);
183
- }
184
- }
185
- return result;
186
- }
187
76
  /**
188
77
  * Extract endpoint destinations from service keys.
189
78
  *
@@ -1,4 +1,4 @@
1
+ export * from './mta';
1
2
  export * from './yaml';
2
3
  export * from './yaml-loader';
3
- export * from './mta';
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./mta"), exports);
17
18
  __exportStar(require("./yaml"), exports);
18
19
  __exportStar(require("./yaml-loader"), exports);
19
- __exportStar(require("./mta"), exports);
20
20
  //# sourceMappingURL=index.js.map
@@ -1,5 +1,14 @@
1
1
  import type { ToolsLogger } from '@sap-ux/logger';
2
- import type { BusinessServiceResource, AppRouterType } from '../../types';
2
+ import type { BusinessServiceResource, AppRouterType, MtaYaml } from '../../types';
3
+ /**
4
+ * Builds VCAP_SERVICES by resolving MTA resources to service key credentials.
5
+ *
6
+ * @param {MtaYaml['resources']} resources - MTA YAML resources.
7
+ * @param {string} spaceGuid - The space GUID.
8
+ * @param {ToolsLogger} logger - Optional logger.
9
+ * @returns {Promise<Record<string, unknown>>} VCAP_SERVICES keyed by service name.
10
+ */
11
+ export declare function buildVcapServicesFromResources(resources: MtaYaml['resources'], spaceGuid: string, logger?: ToolsLogger): Promise<Record<string, unknown>>;
3
12
  /**
4
13
  * Get the approuter type.
5
14
  *
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.buildVcapServicesFromResources = buildVcapServicesFromResources;
36
37
  exports.getApprouterType = getApprouterType;
37
38
  exports.getModuleNames = getModuleNames;
38
39
  exports.getServicesForFile = getServicesForFile;
@@ -42,9 +43,36 @@ exports.getResources = getResources;
42
43
  exports.readMta = readMta;
43
44
  const path = __importStar(require("node:path"));
44
45
  const i18n_1 = require("../../i18n");
46
+ const api_1 = require("../services/api");
47
+ const cli_1 = require("../services/cli");
45
48
  const yaml_1 = require("./yaml");
46
49
  const yaml_loader_1 = require("./yaml-loader");
47
- const cli_1 = require("../services/cli");
50
+ const EXCLUDED_SERVICES_VCAP = new Set(['html5-apps-repo', 'portal']);
51
+ /**
52
+ * Builds VCAP_SERVICES by resolving MTA resources to service key credentials.
53
+ *
54
+ * @param {MtaYaml['resources']} resources - MTA YAML resources.
55
+ * @param {string} spaceGuid - The space GUID.
56
+ * @param {ToolsLogger} logger - Optional logger.
57
+ * @returns {Promise<Record<string, unknown>>} VCAP_SERVICES keyed by service name.
58
+ */
59
+ async function buildVcapServicesFromResources(resources, spaceGuid, logger) {
60
+ const vcapServices = {};
61
+ for (const resource of resources ?? []) {
62
+ const serviceName = resource.parameters?.service;
63
+ const serviceInstanceName = resource.parameters?.['service-name'];
64
+ const servicePlan = resource.parameters?.['service-plan'];
65
+ if (!serviceName || !serviceInstanceName || EXCLUDED_SERVICES_VCAP.has(serviceName)) {
66
+ continue;
67
+ }
68
+ const data = await (0, api_1.getServiceKeyCredentialsWithTags)(spaceGuid, serviceName, serviceInstanceName, servicePlan ?? '', logger);
69
+ if (!data?.credentials) {
70
+ throw new Error(`Credentials and tags for service '${serviceName}' ('${serviceInstanceName}') not found`);
71
+ }
72
+ vcapServices[serviceName] = [data];
73
+ }
74
+ return vcapServices;
75
+ }
48
76
  /**
49
77
  * Get the approuter type.
50
78
  *
@@ -1,6 +1,5 @@
1
1
  import type { Editor } from 'mem-fs-editor';
2
2
  import type { ToolsLogger } from '@sap-ux/logger';
3
- import type { UI5Config } from '@sap-ux/ui5-config';
4
3
  import type { AppParamsExtended, MtaYaml, ServiceKeys } from '../../types';
5
4
  import { AppRouterType } from '../../types';
6
5
  interface AdjustMtaYamlParams {
@@ -51,22 +50,5 @@ export declare function getAppParamsFromUI5Yaml(projectPath: string): AppParamsE
51
50
  * @returns {Promise<void>} The promise.
52
51
  */
53
52
  export declare function adjustMtaYaml({ projectPath, adpProjectName, appRouterType, businessSolutionName, businessService, serviceKeys, spaceGuid }: AdjustMtaYamlParams, memFs: Editor, timestamp: string, templatePathOverwrite?: string, logger?: ToolsLogger): Promise<MtaYaml>;
54
- /**
55
- * Add fiori-tools-servestatic configuration to ui5.yaml and removes previously added configuration.
56
- *
57
- * @param basePath - path to application root
58
- * @param ui5Config - UI5 configuration object
59
- * @param logger - logger instance
60
- */
61
- export declare function addServeStaticMiddleware(basePath: string, ui5Config: UI5Config, logger?: ToolsLogger): Promise<void>;
62
- /**
63
- * Add backend-proxy-middleware-cf configuration to ui5.yaml.
64
- *
65
- * @param basePath - path to application root
66
- * @param ui5Config - UI5 configuration object
67
- * @param serviceKeys - service keys from Cloud Foundry
68
- * @param logger - logger instance
69
- */
70
- export declare function addBackendProxyMiddleware(basePath: string, ui5Config: UI5Config, serviceKeys: ServiceKeys[], logger?: ToolsLogger): void;
71
53
  export {};
72
54
  //# sourceMappingURL=yaml.d.ts.map
@@ -41,8 +41,6 @@ exports.getSAPCloudService = getSAPCloudService;
41
41
  exports.getRouterType = getRouterType;
42
42
  exports.getAppParamsFromUI5Yaml = getAppParamsFromUI5Yaml;
43
43
  exports.adjustMtaYaml = adjustMtaYaml;
44
- exports.addServeStaticMiddleware = addServeStaticMiddleware;
45
- exports.addBackendProxyMiddleware = addBackendProxyMiddleware;
46
44
  const node_fs_1 = __importDefault(require("node:fs"));
47
45
  const path = __importStar(require("node:path"));
48
46
  const js_yaml_1 = __importDefault(require("js-yaml"));
@@ -50,8 +48,6 @@ const types_1 = require("../../types");
50
48
  const api_1 = require("../services/api");
51
49
  const yaml_loader_1 = require("./yaml-loader");
52
50
  const discovery_1 = require("../app/discovery");
53
- const helper_1 = require("../../base/helper");
54
- const ui5_app_info_1 = require("./ui5-app-info");
55
51
  const CF_MANAGED_SERVICE = 'org.cloudfoundry.managed-service';
56
52
  const HTML5_APPS_REPO = 'html5-apps-repo';
57
53
  const SAP_APPLICATION_CONTENT = 'com.sap.application.content';
@@ -454,77 +450,4 @@ async function adjustMtaYaml({ projectPath, adpProjectName, appRouterType, busin
454
450
  logger?.debug(`Adjusted MTA YAML for project ${projectPath}`);
455
451
  return yamlContent;
456
452
  }
457
- /**
458
- * Add fiori-tools-servestatic configuration to ui5.yaml and removes previously added configuration.
459
- *
460
- * @param basePath - path to application root
461
- * @param ui5Config - UI5 configuration object
462
- * @param logger - logger instance
463
- */
464
- async function addServeStaticMiddleware(basePath, ui5Config, logger) {
465
- try {
466
- if (ui5Config.findCustomMiddleware('fiori-tools-servestatic')) {
467
- ui5Config.removeCustomMiddleware('fiori-tools-servestatic');
468
- }
469
- const paths = [];
470
- // Add reusable library paths from ui5AppInfo.json if it exists
471
- paths.push(...(0, ui5_app_info_1.getReusableLibraryPaths)(basePath, logger));
472
- const variant = await (0, helper_1.getVariant)(basePath);
473
- const builtVariantId = variant.id.replaceAll('.', '_');
474
- paths.push({
475
- path: `/changes/${builtVariantId}`,
476
- src: './webapp/changes',
477
- fallthrough: true
478
- }, {
479
- path: `/${builtVariantId}/i18n`,
480
- src: './webapp/i18n',
481
- fallthrough: true
482
- });
483
- ui5Config.addCustomMiddleware([
484
- {
485
- name: 'fiori-tools-servestatic',
486
- beforeMiddleware: 'compression',
487
- configuration: {
488
- paths
489
- }
490
- }
491
- ]);
492
- }
493
- catch (error) {
494
- logger?.warn(`Could not add fiori-tools-servestatic configuration: ${error.message}`);
495
- throw error;
496
- }
497
- }
498
- /**
499
- * Add backend-proxy-middleware-cf configuration to ui5.yaml.
500
- *
501
- * @param basePath - path to application root
502
- * @param ui5Config - UI5 configuration object
503
- * @param serviceKeys - service keys from Cloud Foundry
504
- * @param logger - logger instance
505
- */
506
- function addBackendProxyMiddleware(basePath, ui5Config, serviceKeys, logger) {
507
- try {
508
- if (ui5Config.findCustomMiddleware('backend-proxy-middleware-cf')) {
509
- ui5Config.removeCustomMiddleware('backend-proxy-middleware-cf');
510
- }
511
- const urlsWithPaths = (0, discovery_1.getBackendUrlsWithPaths)(serviceKeys, basePath);
512
- if (urlsWithPaths.length === 0) {
513
- logger?.info('No backend URLs with paths found. Skipping backend-proxy-middleware-cf configuration.');
514
- return;
515
- }
516
- ui5Config.addCustomMiddleware([
517
- {
518
- name: 'backend-proxy-middleware-cf',
519
- afterMiddleware: 'compression',
520
- configuration: {
521
- backends: urlsWithPaths
522
- }
523
- }
524
- ]);
525
- }
526
- catch (error) {
527
- logger?.warn(`Could not add backend-proxy-middleware-cf configuration: ${error.message}`);
528
- }
529
- }
530
453
  //# sourceMappingURL=yaml.js.map
@@ -1,6 +1,6 @@
1
1
  import type { ToolsLogger } from '@sap-ux/logger';
2
2
  import type { ManifestNamespace } from '@sap-ux/project-access';
3
- import type { CfConfig, CFApp, RequestArguments, ServiceKeys, GetServiceInstanceParams, ServiceInstance, MtaYaml, ServiceInfo, CfUi5AppInfo } from '../../types';
3
+ import type { CfConfig, CFApp, RequestArguments, ServiceKeys, GetServiceInstanceParams, ServiceInstance, MtaYaml, ServiceInfo, CfUi5AppInfo, ServiceKeyCredentialsWithTags } from '../../types';
4
4
  interface CreateServiceOptions {
5
5
  xsSecurityProjectName?: string;
6
6
  templatePathOverwrite?: string;
@@ -98,5 +98,24 @@ export declare function getOrCreateServiceInstanceKeys(serviceInstanceQuery: Get
98
98
  * @returns {Promise<ServiceKeys[]>} The service instance keys.
99
99
  */
100
100
  export declare function getOrCreateServiceKeys(serviceInstance: ServiceInstance, logger?: ToolsLogger): Promise<ServiceKeys[]>;
101
+ /**
102
+ * Gets service tags for a given service name.
103
+ *
104
+ * @param {string} spaceGuid - The space GUID.
105
+ * @param {string} serviceName - The service name (e.g., 'xsuaa', 'hana').
106
+ * @returns {Promise<string[]>} The service tags.
107
+ */
108
+ export declare function getServiceTags(spaceGuid: string, serviceName: string): Promise<string[]>;
109
+ /**
110
+ * Fetches service tags and credentials for a single app-router resource (xsuaa/destination).
111
+ *
112
+ * @param {string} spaceGuid - The space GUID.
113
+ * @param {string} serviceName - The service name (e.g. 'xsuaa', 'destination').
114
+ * @param {string} serviceInstanceName - The service instance name.
115
+ * @param {string} plan - The service plan.
116
+ * @param {ToolsLogger} logger - Optional logger.
117
+ * @returns {Promise<ServiceKeyCredentialsWithTags | null>} Service key credentials with tags returned by the CF API.
118
+ */
119
+ export declare function getServiceKeyCredentialsWithTags(spaceGuid: string, serviceName: string, serviceInstanceName: string, plan: string, logger?: ToolsLogger): Promise<ServiceKeyCredentialsWithTags | null>;
101
120
  export {};
102
121
  //# sourceMappingURL=api.d.ts.map
@@ -46,6 +46,8 @@ exports.getServiceNameByTags = getServiceNameByTags;
46
46
  exports.createServices = createServices;
47
47
  exports.getOrCreateServiceInstanceKeys = getOrCreateServiceInstanceKeys;
48
48
  exports.getOrCreateServiceKeys = getOrCreateServiceKeys;
49
+ exports.getServiceTags = getServiceTags;
50
+ exports.getServiceKeyCredentialsWithTags = getServiceKeyCredentialsWithTags;
49
51
  const fs = __importStar(require("node:fs"));
50
52
  const axios_1 = __importDefault(require("axios"));
51
53
  const path = __importStar(require("node:path"));
@@ -374,4 +376,51 @@ async function getOrCreateServiceKeys(serviceInstance, logger) {
374
376
  throw new Error((0, i18n_1.t)('error.failedToGetOrCreateServiceKeys', { serviceInstanceName, error: e.message }));
375
377
  }
376
378
  }
379
+ /**
380
+ * Gets service tags for a given service name.
381
+ *
382
+ * @param {string} spaceGuid - The space GUID.
383
+ * @param {string} serviceName - The service name (e.g., 'xsuaa', 'hana').
384
+ * @returns {Promise<string[]>} The service tags.
385
+ */
386
+ async function getServiceTags(spaceGuid, serviceName) {
387
+ const json = await (0, cli_1.requestCfApi)(`/v3/service_offerings?per_page=1000&space_guids=${spaceGuid}&names=${serviceName}`);
388
+ const serviceOffering = json?.resources?.find((resource) => resource.name === serviceName);
389
+ return serviceOffering?.tags ?? [];
390
+ }
391
+ /**
392
+ * Fetches service tags and credentials for a single app-router resource (xsuaa/destination).
393
+ *
394
+ * @param {string} spaceGuid - The space GUID.
395
+ * @param {string} serviceName - The service name (e.g. 'xsuaa', 'destination').
396
+ * @param {string} serviceInstanceName - The service instance name.
397
+ * @param {string} plan - The service plan.
398
+ * @param {ToolsLogger} logger - Optional logger.
399
+ * @returns {Promise<ServiceKeyCredentialsWithTags | null>} Service key credentials with tags returned by the CF API.
400
+ */
401
+ async function getServiceKeyCredentialsWithTags(spaceGuid, serviceName, serviceInstanceName, plan, logger) {
402
+ try {
403
+ const tags = await getServiceTags(spaceGuid, serviceName);
404
+ const serviceInstances = await getServiceInstance({
405
+ names: [serviceInstanceName],
406
+ spaceGuids: [spaceGuid]
407
+ });
408
+ if (serviceInstances.length === 0) {
409
+ logger?.error(`Service instance '${serviceInstanceName}' not found, skipping`);
410
+ return null;
411
+ }
412
+ const credentials = await getOrCreateServiceKeys(serviceInstances[0], logger);
413
+ return {
414
+ label: serviceName,
415
+ name: serviceInstanceName,
416
+ tags,
417
+ plan,
418
+ credentials: credentials?.[0].credentials
419
+ };
420
+ }
421
+ catch (e) {
422
+ logger?.error(`Failed to get credentials and tags for service '${serviceName}' (instance: '${serviceInstanceName}'): ${e.message}`);
423
+ return null;
424
+ }
425
+ }
377
426
  //# sourceMappingURL=api.js.map
@@ -23,6 +23,13 @@ export declare function getServiceKeys(serviceInstanceGuid: string, sortBy?: Ser
23
23
  * @param {string} serviceKeyName - The service key name.
24
24
  */
25
25
  export declare function createServiceKey(serviceInstanceName: string, serviceKeyName: string): Promise<void>;
26
+ /**
27
+ * Updates a Cloud Foundry service instance with the given parameters.
28
+ *
29
+ * @param {string} serviceInstanceName - The service instance name.
30
+ * @param {object} parameters - The configuration parameters to update.
31
+ */
32
+ export declare function updateServiceInstance(serviceInstanceName: string, parameters: object): Promise<void>;
26
33
  /**
27
34
  * Request CF API.
28
35
  *
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isCfInstalled = isCfInstalled;
4
4
  exports.getServiceKeys = getServiceKeys;
5
5
  exports.createServiceKey = createServiceKey;
6
+ exports.updateServiceInstance = updateServiceInstance;
6
7
  exports.requestCfApi = requestCfApi;
7
8
  const cf_tools_1 = require("@sap/cf-tools");
8
9
  const i18n_1 = require("../../i18n");
@@ -96,6 +97,23 @@ async function createServiceKey(serviceInstanceName, serviceKeyName) {
96
97
  throw new Error((0, i18n_1.t)('error.createServiceKeyFailed', { serviceInstanceName, error: e.message }));
97
98
  }
98
99
  }
100
+ /**
101
+ * Updates a Cloud Foundry service instance with the given parameters.
102
+ *
103
+ * @param {string} serviceInstanceName - The service instance name.
104
+ * @param {object} parameters - The configuration parameters to update.
105
+ */
106
+ async function updateServiceInstance(serviceInstanceName, parameters) {
107
+ try {
108
+ const cliResult = await cf_tools_1.Cli.execute(['update-service', serviceInstanceName, '-c', JSON.stringify(parameters), '--wait'], ENV);
109
+ if (cliResult.exitCode !== 0) {
110
+ throw new Error(cliResult.stderr);
111
+ }
112
+ }
113
+ catch (e) {
114
+ throw new Error((0, i18n_1.t)('error.failedToUpdateServiceInstance', { serviceInstanceName, error: e.message }));
115
+ }
116
+ }
99
117
  /**
100
118
  * Request CF API.
101
119
  *
@@ -103,6 +103,7 @@
103
103
  "emptyCFAPIResponse": "Empty response from CF API. Please verify your CF login status with 'cf target' and re-authenticate if needed with 'cf login'.",
104
104
  "xsSecurityJsonCouldNotBeParsed": "The xs-security.json file could not be parsed. Ensure the xs-security.json file exists and try again.",
105
105
  "failedToCreateServiceInstance": "Failed to create the service instance: '{{serviceInstanceName}}'. Error: {{error}}",
106
+ "failedToUpdateServiceInstance": "Failed to update the service instance: '{{serviceInstanceName}}'. Error: {{error}}",
106
107
  "failedToGetFDCApps": "Retrieving FDC apps failed: {{error}}",
107
108
  "failedToGetFDCInbounds": "Retrieving inbounds from the UI5 Flexibility Design and Configuration service failed: {{error}}",
108
109
  "failedToConnectToFDCService": "Failed to connect to the FDC service: '{{status}}'",
package/dist/types.d.ts CHANGED
@@ -824,6 +824,23 @@ export interface ServiceInstance {
824
824
  name: string;
825
825
  guid: string;
826
826
  }
827
+ /**
828
+ * Service key credentials with tags returned by the CF API.
829
+ */
830
+ export interface ServiceKeyCredentialsWithTags {
831
+ label: string;
832
+ name: string;
833
+ tags: string[];
834
+ plan: string;
835
+ credentials: ServiceKeys['credentials'] | undefined;
836
+ }
837
+ export interface AppRouterEnvOptions {
838
+ 'VCAP_SERVICES'?: Record<string, unknown>;
839
+ destinations?: {
840
+ name: string;
841
+ url: string;
842
+ }[];
843
+ }
827
844
  export interface GetServiceInstanceParams {
828
845
  spaceGuids?: string[];
829
846
  planNames?: string[];
@@ -20,14 +20,13 @@ export declare function generateCf(basePath: string, config: CfAdpWriterConfig,
20
20
  */
21
21
  export declare function writeUi5AppInfo(basePath: string, ui5AppInfo: CfUi5AppInfo, logger?: ToolsLogger): Promise<void>;
22
22
  /**
23
- * Generate CF configuration for an adaptation project.
23
+ * Setup CF adaptation project for local preview.
24
+ * Fetches ui5AppInfo.json and builds the project.
24
25
  *
25
26
  * @param basePath - path to project root
26
27
  * @param yamlPath - path to the project configuration file in YAML format
27
28
  * @param cfConfig - CF configuration
28
29
  * @param logger - logger instance
29
- * @param fs - mem-fs editor instance
30
- * @returns updated mem-fs editor instance
31
30
  */
32
- export declare function generateCfConfig(basePath: string, yamlPath: string, cfConfig: CfConfig, logger?: ToolsLogger, fs?: Editor): Promise<Editor>;
31
+ export declare function setupCfPreview(basePath: string, yamlPath: string, cfConfig: CfConfig, logger?: ToolsLogger): Promise<void>;
33
32
  //# sourceMappingURL=cf.d.ts.map
package/dist/writer/cf.js CHANGED
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.generateCf = generateCf;
7
7
  exports.writeUi5AppInfo = writeUi5AppInfo;
8
- exports.generateCfConfig = generateCfConfig;
8
+ exports.setupCfPreview = setupCfPreview;
9
9
  const node_fs_1 = __importDefault(require("node:fs"));
10
10
  const node_path_1 = require("node:path");
11
11
  const mem_fs_1 = require("mem-fs");
@@ -95,17 +95,15 @@ async function writeUi5AppInfo(basePath, ui5AppInfo, logger) {
95
95
  }
96
96
  }
97
97
  /**
98
- * Generate CF configuration for an adaptation project.
98
+ * Setup CF adaptation project for local preview.
99
+ * Fetches ui5AppInfo.json and builds the project.
99
100
  *
100
101
  * @param basePath - path to project root
101
102
  * @param yamlPath - path to the project configuration file in YAML format
102
103
  * @param cfConfig - CF configuration
103
104
  * @param logger - logger instance
104
- * @param fs - mem-fs editor instance
105
- * @returns updated mem-fs editor instance
106
105
  */
107
- async function generateCfConfig(basePath, yamlPath, cfConfig, logger, fs) {
108
- fs ??= (0, mem_fs_editor_1.create)((0, mem_fs_1.create)());
106
+ async function setupCfPreview(basePath, yamlPath, cfConfig, logger) {
109
107
  const ui5Config = await (0, project_access_1.readUi5Yaml)(basePath, yamlPath);
110
108
  const bundlerTask = ui5Config.findCustomTask('app-variant-bundler-build');
111
109
  const serviceInstanceName = bundlerTask?.configuration?.serviceInstanceName;
@@ -126,10 +124,6 @@ async function generateCfConfig(basePath, yamlPath, cfConfig, logger, fs) {
126
124
  throw new Error('No app host IDs found in service keys.');
127
125
  }
128
126
  await writeUi5AppInfo(basePath, ui5AppInfo, logger);
129
- await (0, cf_1.addServeStaticMiddleware)(basePath, ui5Config, logger);
130
127
  await (0, project_builder_1.runBuild)(basePath, { ADP_BUILDER_MODE: 'preview' });
131
- (0, cf_1.addBackendProxyMiddleware)(basePath, ui5Config, serviceInfo.serviceKeys, logger);
132
- fs.write((0, node_path_1.join)(basePath, yamlPath), ui5Config.toString());
133
- return fs;
134
128
  }
135
129
  //# sourceMappingURL=cf.js.map
@@ -69,13 +69,7 @@ export declare function enhanceManifestChangeContentWithFlpConfig(flpConfigurati
69
69
  */
70
70
  export declare function enhanceUI5YamlWithCfCustomTask(ui5Config: UI5Config, config: CfAdpWriterConfig): void;
71
71
  /**
72
- * Generate custom configuration required for the ui5.yaml.
73
- *
74
- * @param {UI5Config} ui5Config - Configuration representing the ui5.yaml.
75
- * @param {CfAdpWriterConfig} config - Full project configuration.
76
- */
77
- /**
78
- * Generate custom middleware configuration (fiori-tools-proxy and fiori-tools-preview only).
72
+ * Generate custom middleware configuration for CF adaptation projects.
79
73
  *
80
74
  * @param {UI5Config} ui5Config - Configuration representing the ui5.yaml.
81
75
  */
@@ -332,13 +332,7 @@ function enhanceUI5YamlWithCfCustomTask(ui5Config, config) {
332
332
  ]);
333
333
  }
334
334
  /**
335
- * Generate custom configuration required for the ui5.yaml.
336
- *
337
- * @param {UI5Config} ui5Config - Configuration representing the ui5.yaml.
338
- * @param {CfAdpWriterConfig} config - Full project configuration.
339
- */
340
- /**
341
- * Generate custom middleware configuration (fiori-tools-proxy and fiori-tools-preview only).
335
+ * Generate custom middleware configuration for CF adaptation projects.
342
336
  *
343
337
  * @param {UI5Config} ui5Config - Configuration representing the ui5.yaml.
344
338
  */
@@ -346,8 +340,34 @@ function enhanceUI5YamlWithFioriToolsMiddleware(ui5Config) {
346
340
  const ui5ConfigOptions = {
347
341
  url: constants_1.UI5_CDN_URL
348
342
  };
349
- // Add fiori-tools-appreload for live reload during development
350
- ui5Config.addFioriToolsAppReloadMiddleware();
343
+ // Add backend-proxy-middleware-cf as the first middleware (after compression)
344
+ ui5Config.addCustomMiddleware([
345
+ {
346
+ name: 'backend-proxy-middleware-cf',
347
+ afterMiddleware: 'compression',
348
+ configuration: {
349
+ authenticationMethod: 'route',
350
+ allowServices: true,
351
+ appendAuthRoute: true,
352
+ debug: true,
353
+ xsappJsonPath: '.adp/reuse/xs-app.json',
354
+ allowLocalDir: true,
355
+ rewriteContent: false
356
+ }
357
+ }
358
+ ]);
359
+ // Add fiori-tools-appreload for live reload during development (after backend-proxy-middleware-cf)
360
+ ui5Config.addCustomMiddleware([
361
+ {
362
+ name: 'fiori-tools-appreload',
363
+ afterMiddleware: 'backend-proxy-middleware-cf',
364
+ configuration: {
365
+ port: 35729,
366
+ path: 'webapp',
367
+ delay: 300
368
+ }
369
+ }
370
+ ]);
351
371
  // Add fiori-tools-preview (for local preview)
352
372
  ui5Config.addCustomMiddleware([
353
373
  {
@@ -157,7 +157,6 @@ async function writeCfUI5Yaml(projectPath, data, fs) {
157
157
  /** Builder task */
158
158
  (0, options_1.enhanceUI5YamlWithCfCustomTask)(ui5Config, data);
159
159
  /** Middlewares */
160
- // Add fiori-tools-proxy and fiori-tools-preview for local development
161
160
  (0, options_1.enhanceUI5YamlWithFioriToolsMiddleware)(ui5Config);
162
161
  fs.write(ui5ConfigPath, ui5Config.toString());
163
162
  }
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "bugs": {
10
10
  "url": "https://github.com/SAP/open-ux-tools/issues?q=is%3Aopen+is%3Aissue+label%3Abug+label%3Aadp-tooling"
11
11
  },
12
- "version": "0.18.109",
12
+ "version": "0.18.111",
13
13
  "license": "Apache-2.0",
14
14
  "author": "@SAP/ux-tools-team",
15
15
  "main": "dist/index.js",
@@ -23,11 +23,11 @@
23
23
  "devDependencies": {
24
24
  "@sap-ux/create": "^0.15.9",
25
25
  "@sap/ui5-builder-webide-extension": "^1.1.9",
26
- "@sap-ux/backend-proxy-middleware-cf": "~0.0.0",
26
+ "@sap-ux/backend-proxy-middleware-cf": "^0.1.0",
27
27
  "@sapui5/ts-types": "^1.141.2",
28
28
  "@sap/ux-ui5-tooling": "1",
29
29
  "@ui5/cli": "^4.0.33",
30
- "@ui5/task-adaptation": "1.6.0-rc.4",
30
+ "@ui5/task-adaptation": "^1.6.3",
31
31
  "bestzip": "^2.2.1",
32
32
  "rimraf": "^6.1.2",
33
33
  "mbt": "^1.2.34"
@@ -1,14 +0,0 @@
1
- import type { ToolsLogger } from '@sap-ux/logger';
2
- /**
3
- * Extracts reusable library paths from ui5AppInfo.json if it exists.
4
- *
5
- * @param basePath - path to application root
6
- * @param logger - logger instance
7
- * @returns Array of path configurations for reusable libraries
8
- */
9
- export declare function getReusableLibraryPaths(basePath: string, logger?: ToolsLogger): Array<{
10
- path: string;
11
- src: string;
12
- fallthrough: boolean;
13
- }>;
14
- //# sourceMappingURL=ui5-app-info.d.ts.map
@@ -1,36 +0,0 @@
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.getReusableLibraryPaths = getReusableLibraryPaths;
7
- const node_fs_1 = __importDefault(require("node:fs"));
8
- const node_path_1 = __importDefault(require("node:path"));
9
- /**
10
- * Extracts reusable library paths from ui5AppInfo.json if it exists.
11
- *
12
- * @param basePath - path to application root
13
- * @param logger - logger instance
14
- * @returns Array of path configurations for reusable libraries
15
- */
16
- function getReusableLibraryPaths(basePath, logger) {
17
- const ui5AppInfoPath = node_path_1.default.join(basePath, 'ui5AppInfo.json');
18
- if (!node_fs_1.default.existsSync(ui5AppInfoPath)) {
19
- logger?.warn('ui5AppInfo.json not found in project root');
20
- return [];
21
- }
22
- const ui5AppInfoData = JSON.parse(node_fs_1.default.readFileSync(ui5AppInfoPath, 'utf-8'));
23
- const ui5AppInfo = ui5AppInfoData[Object.keys(ui5AppInfoData)[0]];
24
- const reusableLibs = ui5AppInfo.asyncHints?.libs?.filter((lib) => lib.html5AppName && lib.url && typeof lib.url === 'object' && lib.url.url !== undefined) ?? [];
25
- return reusableLibs.map((lib) => {
26
- const libName = String(lib.name);
27
- const html5AppName = String(lib.html5AppName);
28
- const resourcePath = '/resources/' + libName.replaceAll('.', '/');
29
- return {
30
- path: resourcePath,
31
- src: `./.adp/reuse/${html5AppName}`,
32
- fallthrough: true
33
- };
34
- });
35
- }
36
- //# sourceMappingURL=ui5-app-info.js.map