@sap-ux/preview-middleware 1.1.3 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +31 -29
  2. package/dist/base/config.d.ts +55 -2
  3. package/dist/base/config.js +158 -26
  4. package/dist/base/flp.d.ts +24 -0
  5. package/dist/base/flp.js +116 -18
  6. package/dist/client/adp/api-handler.js +5 -1
  7. package/dist/client/adp/api-handler.ts +11 -4
  8. package/dist/client/adp/controllers/ControllerExtension.controller.js +95 -35
  9. package/dist/client/adp/controllers/ControllerExtension.controller.ts +121 -42
  10. package/dist/client/adp/extend-controller.ts +1 -0
  11. package/dist/client/adp/quick-actions/common/add-controller-to-page.js +2 -2
  12. package/dist/client/adp/quick-actions/common/add-controller-to-page.ts +2 -2
  13. package/dist/client/adp/quick-actions/fe-v4/create-page-action.js +3 -2
  14. package/dist/client/adp/quick-actions/fe-v4/create-page-action.ts +3 -2
  15. package/dist/client/adp/quick-actions/fe-v4/create-table-action-config-change.js +3 -2
  16. package/dist/client/adp/quick-actions/fe-v4/create-table-action-config-change.ts +3 -2
  17. package/dist/client/adp/ui/ControllerExtension.fragment.xml +33 -6
  18. package/dist/client/adp/utils.js +73 -5
  19. package/dist/client/adp/utils.ts +84 -5
  20. package/dist/client/flp/WorkspaceConnector.js +7 -5
  21. package/dist/client/flp/WorkspaceConnector.ts +7 -5
  22. package/dist/client/flp/common.js +293 -1
  23. package/dist/client/flp/common.ts +344 -1
  24. package/dist/client/flp/sandbox1Init.js +187 -0
  25. package/dist/client/flp/sandbox1Init.ts +174 -0
  26. package/dist/client/flp/sandbox2AfterInit.js +66 -0
  27. package/dist/client/flp/sandbox2AfterInit.ts +63 -0
  28. package/dist/client/flp/sandbox2BeforeInit.js +67 -0
  29. package/dist/client/flp/sandbox2BeforeInit.ts +60 -0
  30. package/dist/client/messagebundle.properties +3 -0
  31. package/dist/types/index.d.ts +21 -0
  32. package/package.json +3 -3
  33. package/templates/flp/cdm.ejs +1 -1
  34. package/templates/flp/sandbox.ejs +1 -1
  35. package/templates/flp/sandbox2.ejs +12 -44
  36. package/dist/client/flp/init.js +0 -465
  37. package/dist/client/flp/init.ts +0 -498
package/README.md CHANGED
@@ -15,36 +15,38 @@ When this middleware is used together with the `reload-middleware`, then the ord
15
15
  ```
16
16
 
17
17
  ## [Configuration Options](#configuration-options)
18
- | Option | Value Type | Requirement Type | Default Value | Description |
19
- |-------------------------|------------|------------------------------------------------|------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
20
- | `flp` | --- | optional | --- | Configuration object for the local SAP Fiori launchpad |
21
- | `flp.path` | `string` | optional | `/test/flp.html` | The mount point of the local SAP Fiori launchpad. In case no file is found at the given path, a virtual endpoint will be instantiated. |
22
- | `flp.init` | `string` | optional | `undefined` | UI5 module/script to be executed after the standard initialization |
23
- | `flp.intent` | --- | optional | --- | Intent object to be used for the application |
24
- | `flp.intent.object` | `string` | optional | `app` | Name of the semantic object |
25
- | `flp.intent.action` | `string` | optional | `preview` | Name of the action |
26
- | `flp.apps` | `array` | optional | `undefined` | Additional local apps that are available in the local SAP Fiori launchpad |
27
- | `flp.libs` | `boolean` | optional | `false` | Flag to add a generic script fetching the paths of used libraries not available in UI5. To disable it, set it to `false`. If not set, then the project is checked for a `load-reuse-libs` script and, if available, the libraries are fetched as well |
28
- | `flp.theme` | `string` | optional | `(calculated)` | Name of the UI5 theme to be used (default is `sap_horizon` or the first entry in the sap.ui.supportedThemes list provided in the manifest.json file if `sap_horizon` is not contained in the list) |
29
- | `flp.enhancedHomePage` | `boolean` | optional | `false` | Flag for enabling enhanced FLP homepage, available only from UI5 version 1.123.0 onwards |
30
- | `adp.target` | --- | mandatory for adaptation projects | --- | Configuration object defining the connected back end |
31
- | `adp.ignoreCertErrors` | `boolean` | optional | `false` | Flag to ignore certification validation errors when working with development systems with self-signed certificates, for example |
32
- | `adp.cfBuildPath` | `string` | optional (experimental, CF only) | `undefined` | **Experimental**: For CF ADP projects only. Path to build output folder (e.g., `dist`) to serve built resources directly. When set, the middleware serves static files from this path and reads manifest.json from it. |
33
- | `rta` | --- | 🚫 deprecated</br> *use `editors.rta` instead* | --- | Configuration allowing to add mount points for runtime adaptation |
34
- | `editors` | `array` | optional | `undefined` | List of configurations allowing to add mount points for additional editors |
35
- | `editors.rta` | `array` | optional | `undefined` | Configuration allowing to add mount points for runtime adaptation |
36
- | `editors.rta.layer` | `string` | optional | `(calculated)` | Property for defining the runtime adaptation layer for changes (default is `CUSTOMER_BASE` or read from the project for adaptation projects) |
37
- | `editors.rta.endpoints` | `array` | optional | `undefined` | List of mount points for editing |
38
- | `editors.cardGenerator` | --- | optional | `undefined` | Configuration object that enables card generation for an application. The generated cards are only available when the application is deployed to an ABAP-based SAP Fiori launchpad, such as SAP Fiori launchpad in SAP S/4HANA Cloud Public Edition. Available only from UI5 version 1.149.0 onwards for CAP node apps and from UI5 version 1.121.0 onwards for ABAP backends |
39
- | `editors.cardGenerator.path` | `string` | optional | `test/flpGeneratorSandbox.html` | The mount point of the local SAP Fiori launchpad which will be considered for card generation. |
40
- | `test` | `array` | optional | `undefined` | List of configurations for automated testing. |
41
- | `debug` | `boolean` | optional | `false` | Enables the debug output |
18
+ | Option | Value Type | Requirement Type | Default Value | Description |
19
+ |------------------------------|------------|------------------------------------------------|---------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
20
+ | `flp` | --- | optional | --- | Configuration object for the local SAP Fiori launchpad |
21
+ | `flp.path` | `string` | optional | `/test/flp.html` | The mount point of the local SAP Fiori launchpad. In case no file is found at the given path, a virtual endpoint will be instantiated. |
22
+ | `flp.init` | `string` | optional | `undefined` | UI5 module/script to be executed after the standard initialization |
23
+ | `flp.intent` | --- | optional | --- | Intent object to be used for the application |
24
+ | `flp.intent.object` | `string` | optional | `app` | Name of the semantic object |
25
+ | `flp.intent.action` | `string` | optional | `preview` | Name of the action |
26
+ | `flp.apps` | `array` | optional | `undefined` | Additional local apps that are available in the local SAP Fiori launchpad |
27
+ | `flp.libs` | `boolean` | optional | `false` | Flag to add a generic script fetching the paths of used libraries not available in UI5. To disable it, set it to `false`. If not set, then the project is checked for a `load-reuse-libs` script and, if available, the libraries are fetched as well |
28
+ | `flp.theme` | `string` | optional | `(calculated)` | Name of the UI5 theme to be used (default is `sap_horizon` or the first entry in the sap.ui.supportedThemes list provided in the manifest.json file if `sap_horizon` is not contained in the list) |
29
+ | `flp.enhancedHomePage` | `boolean` | optional | `false` | Flag for enabling enhanced FLP homepage, available only from UI5 version 1.123.0 onwards |
30
+ | `flp.useNewSandbox` | `boolean` | optional | `false` | Set to `true` to opt in to the new FLP Sandbox instead of using the classic sandbox. Only has an effect when the UI5 version qualifies (>= 1.151 or legacy-free) |
31
+ | `flp.navigateToApp` | `boolean` | optional | `false` | Only applies when the new FLP Sandbox is active. Set to `true` to navigate directly to the app on startup instead of showing the FLP home screen first. |
32
+ | `adp.target` | --- | mandatory for adaptation projects | --- | Configuration object defining the connected back end |
33
+ | `adp.ignoreCertErrors` | `boolean` | optional | `false` | Flag to ignore certification validation errors when working with development systems with self-signed certificates, for example |
34
+ | `adp.cfBuildPath` | `string` | optional (experimental, CF only) | `undefined` | **Experimental**: For CF ADP projects only. Path to build output folder (e.g., `dist`) to serve built resources directly. When set, the middleware serves static files from this path and reads manifest.json from it. |
35
+ | `rta` | --- | 🚫 deprecated</br> *use `editors.rta` instead* | --- | Configuration allowing to add mount points for runtime adaptation |
36
+ | `editors` | `array` | optional | `undefined` | List of configurations allowing to add mount points for additional editors |
37
+ | `editors.rta` | `array` | optional | `undefined` | Configuration allowing to add mount points for runtime adaptation |
38
+ | `editors.rta.layer` | `string` | optional | `(calculated)` | Property for defining the runtime adaptation layer for changes (default is `CUSTOMER_BASE` or read from the project for adaptation projects) |
39
+ | `editors.rta.endpoints` | `array` | optional | `undefined` | List of mount points for editing |
40
+ | `editors.cardGenerator` | --- | optional | `undefined` | Configuration object that enables card generation for an application. The generated cards are only available when the application is deployed to an ABAP-based SAP Fiori launchpad, such as SAP Fiori launchpad in SAP S/4HANA Cloud Public Edition. Available only from UI5 version 1.149.0 onwards for CAP node apps and from UI5 version 1.121.0 onwards for ABAP backends |
41
+ | `editors.cardGenerator.path` | `string` | optional | `test/flpGeneratorSandbox.html` | The mount point of the local SAP Fiori launchpad which will be considered for card generation. |
42
+ | `test` | `array` | optional | `undefined` | List of configurations for automated testing. |
43
+ | `debug` | `boolean` | optional | `false` | Enables the debug output |
42
44
 
43
45
  ### [`flp.apps`](#configuration-option-flpapps)
44
46
  Array of additional application configurations:
45
47
 
46
48
  | Option | Value Type | Requirement Type | Default Value | Description |
47
- | ------------------------ |------------|------------------|----------------|-------------------------------------------------------------------------------------------------------------|
49
+ |--------------------------|------------|------------------|----------------|-------------------------------------------------------------------------------------------------------------|
48
50
  | `target` | `string` | mandatory | `undefined` | Target path of the additional application |
49
51
  | `local` or `componentId` | `string` | mandatory | `undefined` | Either a local path to a folder containing the application or the `componentId` of a remote app is required |
50
52
  | `intent` | --- | optional | --- | Intent object to be used for the application |
@@ -53,15 +55,15 @@ Array of additional application configurations:
53
55
 
54
56
  ### [`adp.target`](#configuration-option-adptarget)
55
57
  | Option | Value Type | Requirement Type | Default Value | Description |
56
- | ------------- |------------|-----------------------|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
58
+ |---------------|------------|-----------------------|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
57
59
  | `url` | `string` | mandatory (local) | `undefined` | Mandatory URL pointing to the back-end system. *Not required if destination is provided and the proxy is running SAP Business Application Studio |
58
60
  | `destination` | `string` | mandatory (if no URL) | `undefined` | Required if the back-end system is available as destination in SAP Business Application Studio. |
59
- | `client` | `string` | optional | `undefined` | Parameter for the SAP client |
61
+ | `client` | `string` | optional | `undefined` | Parameter for the SAP client |
60
62
  | `scp` | `boolean` | optional | `false` | Flag to execute the required OAuth routine for the ABAP environment on SAP BTP |
61
63
 
62
64
  ### [`editors`](#configuration-option-editors)
63
- | Option | Value Type | Requirement Type | Default Value | Description |
64
- |-------------------------------|------------|------------------|---------------|------------------------------------------------------------------------------------------------|
65
+ | Option | Value Type | Requirement Type | Default Value | Description |
66
+ |-------------------------------|------------|------------------|---------------|-----------------------------------------------------------------------------------------------|
65
67
  | `rta.endpoints.path` | `string` | mandatory | `undefined` | The mount point to be used for the editor. |
66
68
  | `rta.endpoints.developerMode` | `boolean` | optional | `false` | Flag to enable the runtime adaptation developer mode (only supported for adaptation projects) |
67
69
 
@@ -1,5 +1,5 @@
1
1
  import { ToolsLogger, type Logger } from '@sap-ux/logger';
2
- import type { App, DefaultFlpPath, DefaultIntent, FlpConfig, Intent, CompleteTestConfig, MiddlewareConfig, RtaConfig, TestConfig } from '../types/index.js';
2
+ import type { App, DefaultFlpPath, DefaultIntent, FlpConfig, Intent, CompleteTestConfig, MiddlewareConfig, RtaConfig, TestConfig, Ui5Version } from '../types/index.js';
3
3
  import { type Manifest, type UI5FlexLayer } from '@sap-ux/project-access';
4
4
  import { type Editor } from 'mem-fs-editor';
5
5
  import type { MergedAppDescriptor } from '@sap-ux/axios-extension';
@@ -8,6 +8,19 @@ export interface CustomConnector {
8
8
  writeConnector: string;
9
9
  custom: boolean;
10
10
  }
11
+ export interface SandboxAppConfig {
12
+ tiles: {
13
+ semanticObject: string;
14
+ action: string;
15
+ rootPath: string;
16
+ }[];
17
+ rootIntent?: string;
18
+ beforeFlpStart: string;
19
+ afterFlpStart: string;
20
+ restricted: {
21
+ flexibilityServices: (CustomConnector | FlexConnector)[];
22
+ };
23
+ }
11
24
  export interface FlexConnector {
12
25
  connector: string;
13
26
  layers: string[];
@@ -39,11 +52,31 @@ export interface TemplateConfig {
39
52
  applicationDependencies?: MergedAppDescriptor;
40
53
  }>;
41
54
  ui5: {
55
+ /**
56
+ * Comma-separated list of UI5 libraries to preload.
57
+ *
58
+ * @remarks Not rendered in sandbox2.ejs — the Sandbox 2.0 bootstrap manages its own library loading.
59
+ */
42
60
  libs: string;
43
61
  theme: string;
62
+ /**
63
+ * Flexibility service connector configuration.
64
+ *
65
+ * @remarks Rendered in sandbox.ejs as `data-sap-ui-flexibilityServices` for sandbox 1.
66
+ * Not used by sandbox 2 — `generateSandboxAppConfig` calls `getFlexSettings()` independently
67
+ * to populate `restricted.flexibilityServices` in the fioriSandboxAppConfig.json endpoint.
68
+ */
44
69
  flex: (CustomConnector | FlexConnector)[];
45
70
  bootstrapOptions: string;
46
71
  resources: Record<string, string>;
72
+ /**
73
+ * Major version of the UI5 framework being used.
74
+ *
75
+ * @remarks Mutated per request in flpGetHandler based on the resolved UI5 version.
76
+ * Used by sandbox2.ejs to conditionally include SandboxBootTask.js (major 1) or
77
+ * data-sap-ui-boot-manifest (major 2).
78
+ */
79
+ versionMajor: number;
47
80
  };
48
81
  init?: string;
49
82
  flexSettings?: {
@@ -158,9 +191,11 @@ export declare function remapResourcesForPath(config: TemplateConfig, newPagePat
158
191
  * @param manifest application manifest
159
192
  * @param resources additional resources
160
193
  * @param isAdp whether this is an adaptation project
194
+ * @param isCap whether this is a CAP project
195
+ * @param logger optional logger instance
161
196
  * @returns configuration object for the sandbox.html template
162
197
  */
163
- export declare function createFlpTemplateConfig(config: FlpConfig, manifest: Partial<Manifest>, resources?: Record<string, string>, isAdp?: boolean): TemplateConfig;
198
+ export declare function createFlpTemplateConfig(config: FlpConfig, manifest: Partial<Manifest>, resources?: Record<string, string>, isAdp?: boolean, isCap?: boolean, logger?: Logger): TemplateConfig;
164
199
  /**
165
200
  * Creates the configuration object for the test template.
166
201
  *
@@ -170,6 +205,17 @@ export declare function createFlpTemplateConfig(config: FlpConfig, manifest: Par
170
205
  * @returns configuration object for the test template
171
206
  */
172
207
  export declare function createTestTemplateConfig(config: CompleteTestConfig, id: string, theme: string): TestTemplateConfig;
208
+ /**
209
+ * Generates the fioriSandboxAppConfig.json content for Sandbox 2.0.
210
+ *
211
+ * @param templateConfig the current template configuration containing apps
212
+ * @param flpConfig the FLP configuration containing the intent
213
+ * @param isAdp whether this is an adaptation project - LocalStorageConnector is omitted for ADP
214
+ * @param isCap whether this is a CAP project
215
+ * @param logger optional logger instance
216
+ * @returns the sandbox app config object
217
+ */
218
+ export declare function generateSandboxAppConfig(templateConfig: TemplateConfig, flpConfig: FlpConfig, isAdp?: boolean, isCap?: boolean, logger?: Logger): SandboxAppConfig;
173
219
  /**
174
220
  * Returns the preview paths.
175
221
  *
@@ -178,6 +224,13 @@ export declare function createTestTemplateConfig(config: CompleteTestConfig, id:
178
224
  * @returns an array of preview paths
179
225
  */
180
226
  export declare function getPreviewPaths(config: MiddlewareConfig, logger?: ToolsLogger): PreviewUrls[];
227
+ /**
228
+ * Returns true if the given UI5 version qualifies for the new FLP Sandbox (2.0).
229
+ *
230
+ * @param ui5Version - the UI5 version to check
231
+ * @returns true if the version qualifies for the new sandbox
232
+ */
233
+ export declare function qualifiesForNewSandbox(ui5Version: Ui5Version): boolean;
181
234
  /**
182
235
  * Generates the preview files.
183
236
  *
@@ -2,7 +2,7 @@ import { ToolsLogger } from '@sap-ux/logger';
2
2
  import { render } from 'ejs';
3
3
  import { dirname, join, posix, resolve } from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
- import { createProjectAccess, getWebappPath } from '@sap-ux/project-access';
5
+ import { createProjectAccess, getWebappPath, getMinimumUI5Version, getProjectType } from '@sap-ux/project-access';
6
6
  const __dirname = dirname(fileURLToPath(import.meta.url));
7
7
  import { extractDoubleCurlyBracketsKey } from '@sap-ux/i18n';
8
8
  import { readFileSync } from 'node:fs';
@@ -111,7 +111,9 @@ export function getFlpConfigWithDefaults(config = {}) {
111
111
  libs: config.libs,
112
112
  theme: config.theme,
113
113
  init: config.init,
114
- enhancedHomePage: config.enhancedHomePage === true
114
+ enhancedHomePage: config.enhancedHomePage === true,
115
+ useNewSandbox: config.useNewSandbox === true,
116
+ navigateToApp: config.navigateToApp === true
115
117
  };
116
118
  if (!flpConfig.path.startsWith('/')) {
117
119
  flpConfig.path = `/${flpConfig.path}`;
@@ -165,20 +167,32 @@ export function sanitizeRtaConfig(deprecatedRtaConfig, logger) {
165
167
  * Retrieves the configuration settings for UI5 flexibility services.
166
168
  *
167
169
  * @param isAdp whether this is an adaptation project - LocalStorageConnector is omitted for ADP
170
+ * @param isCap whether this is a CAP project - LrepConnector is omitted for CAP
171
+ * @param logger optional logger instance
168
172
  * @returns An array of flexibility service configurations, each specifying a connector
169
173
  * and its options, such as the layers it applies to and its service URL, if applicable.
170
174
  */
171
- function getFlexSettings(isAdp = false) {
175
+ function getFlexSettings(isAdp = false, isCap = false, logger) {
172
176
  const localConnectorPath = 'open/ux/preview/client/flp/WorkspaceConnector';
177
+ if (isCap) {
178
+ logger?.debug(`The ABAP connector is not being used because this is a CAP project.`);
179
+ }
180
+ else {
181
+ logger?.debug(`The ABAP connector is being used.`);
182
+ }
173
183
  const connectors = [
174
- { connector: 'LrepConnector', layers: [], url: '/sap/bc/lrep' },
184
+ ...(!isCap ? [{ connector: 'LrepConnector', layers: [], url: '/sap/bc/lrep' }] : []),
175
185
  {
176
186
  applyConnector: localConnectorPath,
177
187
  writeConnector: localConnectorPath,
178
188
  custom: true
179
189
  }
180
190
  ];
181
- if (!isAdp) {
191
+ if (isAdp) {
192
+ logger?.debug(`The local storage connector is not being used because this is an ADP project.`);
193
+ }
194
+ else {
195
+ logger?.debug(`The local storage connector is being used.`);
182
196
  connectors.push({ connector: 'LocalStorageConnector', layers: ['CUSTOMER', 'USER'] });
183
197
  }
184
198
  return connectors;
@@ -284,10 +298,12 @@ export function remapResourcesForPath(config, newPagePath, appId) {
284
298
  * @param manifest application manifest
285
299
  * @param resources additional resources
286
300
  * @param isAdp whether this is an adaptation project
301
+ * @param isCap whether this is a CAP project
302
+ * @param logger optional logger instance
287
303
  * @returns configuration object for the sandbox.html template
288
304
  */
289
- export function createFlpTemplateConfig(config, manifest, resources = {}, isAdp = false) {
290
- const flex = getFlexSettings(isAdp);
305
+ export function createFlpTemplateConfig(config, manifest, resources = {}, isAdp = false, isCap = false, logger) {
306
+ const flex = getFlexSettings(isAdp, isCap, logger);
291
307
  const supportedThemes = manifest['sap.ui5']?.supportedThemes ?? [DEFAULT_THEME];
292
308
  const ui5Theme = config.theme ?? (supportedThemes.includes(DEFAULT_THEME) ? DEFAULT_THEME : supportedThemes[0]);
293
309
  const id = manifest['sap.app']?.id ?? '';
@@ -311,7 +327,8 @@ export function createFlpTemplateConfig(config, manifest, resources = {}, isAdp
311
327
  ...resources,
312
328
  [PREVIEW_URL.client.ns]: PREVIEW_URL.client.getUrl(basePath)
313
329
  },
314
- bootstrapOptions: ''
330
+ bootstrapOptions: '',
331
+ versionMajor: 1
315
332
  },
316
333
  locateReuseLibsScript: config.libs,
317
334
  enhancedHomePage: config.enhancedHomePage,
@@ -335,6 +352,52 @@ export function createTestTemplateConfig(config, id, theme) {
335
352
  theme
336
353
  };
337
354
  }
355
+ /**
356
+ * Generates the fioriSandboxAppConfig.json content for Sandbox 2.0.
357
+ *
358
+ * @param templateConfig the current template configuration containing apps
359
+ * @param flpConfig the FLP configuration containing the intent
360
+ * @param isAdp whether this is an adaptation project - LocalStorageConnector is omitted for ADP
361
+ * @param isCap whether this is a CAP project
362
+ * @param logger optional logger instance
363
+ * @returns the sandbox app config object
364
+ */
365
+ export function generateSandboxAppConfig(templateConfig, flpConfig, isAdp = false, isCap = false, logger) {
366
+ // Build a url→intent map: primary app + additional apps with explicit intent
367
+ const intentByUrl = new Map();
368
+ intentByUrl.set(templateConfig.apps[`${flpConfig.intent.object}-${flpConfig.intent.action}`]?.url ?? '', flpConfig.intent);
369
+ for (const app of flpConfig.apps) {
370
+ if (app.intent) {
371
+ intentByUrl.set(app.target, app.intent);
372
+ }
373
+ }
374
+ const tiles = Object.entries(templateConfig.apps).map(([appName, app]) => {
375
+ const rootPath = app.url.endsWith('/') ? app.url : `${app.url}/`;
376
+ const knownIntent = intentByUrl.get(app.url);
377
+ if (knownIntent) {
378
+ return { semanticObject: knownIntent.object, action: knownIntent.action, rootPath };
379
+ }
380
+ // Fallback for additional apps without explicit intent: appName is built by getAppName() as
381
+ // "<semanticObject>-<action>" where the fallback action is hardcoded to 'preview' (no dashes).
382
+ // lastIndexOf('-') is therefore safe — the last dash is always the object/action separator.
383
+ // If the fallback action ever contained a dash (e.g. 'my-preview'), this split would be wrong.
384
+ const dashIndex = appName.lastIndexOf('-');
385
+ const semanticObject = dashIndex === -1 ? appName : appName.substring(0, dashIndex);
386
+ const action = dashIndex === -1 ? '' : appName.substring(dashIndex + 1);
387
+ return { semanticObject, action, rootPath };
388
+ });
389
+ return {
390
+ tiles,
391
+ ...(flpConfig.navigateToApp && {
392
+ rootIntent: `${flpConfig.intent.object}-${flpConfig.intent.action}`
393
+ }),
394
+ beforeFlpStart: 'module:open/ux/preview/client/flp/sandbox2BeforeInit',
395
+ afterFlpStart: 'module:open/ux/preview/client/flp/sandbox2AfterInit',
396
+ restricted: {
397
+ flexibilityServices: getFlexSettings(isAdp, isCap, logger)
398
+ }
399
+ };
400
+ }
338
401
  /**
339
402
  * Returns the preview paths.
340
403
  *
@@ -399,6 +462,83 @@ function generateTestRunners(configs, manifest, fs, webappPath, flpTemplConfig)
399
462
  }
400
463
  }
401
464
  }
465
+ /**
466
+ * Generates the sandbox 2 HTML file and the companion fioriSandboxAppConfig.json.
467
+ * Also sets versionMajor on the template config based on the manifest minUI5Version.
468
+ *
469
+ * @param flpPath - absolute path of the FLP HTML file to write
470
+ * @param flpTemplConfig - the template configuration (mutated: versionMajor is set)
471
+ * @param flpConfig - the resolved FLP configuration
472
+ * @param manifest - the app manifest (must contain a valid minUI5Version)
473
+ * @param isAdp - whether this is an adaptation project
474
+ * @param isCap - whether this is a CAP project
475
+ * @param logger - optional logger instance
476
+ * @param fs - file system editor
477
+ */
478
+ function generateSandbox2Files(flpPath, flpTemplConfig, flpConfig, manifest, isAdp, isCap, logger, fs) {
479
+ const [major] = getMinimumUI5Version(manifest).split('.').map(Number);
480
+ flpTemplConfig.ui5.versionMajor = major;
481
+ fs.write(join(dirname(flpPath), 'fioriSandboxAppConfig.json'), JSON.stringify(generateSandboxAppConfig(flpTemplConfig, flpConfig, isAdp, isCap, logger), null, 4));
482
+ fs.write(flpPath, render(readFileSync(join(TEMPLATE_PATH, 'flp/sandbox2.ejs'), 'utf-8'), flpTemplConfig));
483
+ }
484
+ /**
485
+ * Returns true if sandbox 2 should be used for static file generation.
486
+ * Requires: useNewSandbox opted in, no legacy fioriSandboxConfig.json, enhancedHomePage not set, and manifest minUI5Version >= 1.150.
487
+ *
488
+ * @param manifest - the app manifest, if available
489
+ * @param flpConfig - the resolved FLP configuration
490
+ * @param basePath - path to the application root
491
+ * @param fs - file system editor
492
+ * @returns true if sandbox 2 files should be generated
493
+ */
494
+ function shouldUseSandbox2(manifest, flpConfig, basePath, fs) {
495
+ if (flpConfig.useNewSandbox !== true || flpConfig.enhancedHomePage || !manifest) {
496
+ return false;
497
+ }
498
+ if (fs.exists(join(basePath, 'appconfig/fioriSandboxConfig.json'))) {
499
+ return false;
500
+ }
501
+ const minVersion = getMinimumUI5Version(manifest);
502
+ if (!minVersion) {
503
+ return false;
504
+ }
505
+ const [major, minor] = minVersion.split('.').map(Number);
506
+ return qualifiesForNewSandbox({ major, minor, patch: 0, isCdn: false });
507
+ }
508
+ /**
509
+ * Returns true if the given UI5 version qualifies for the new FLP Sandbox (2.0).
510
+ *
511
+ * @param ui5Version - the UI5 version to check
512
+ * @returns true if the version qualifies for the new sandbox
513
+ */
514
+ export function qualifiesForNewSandbox(ui5Version) {
515
+ return (ui5Version.major > 1 ||
516
+ ui5Version.label?.includes('legacy-free') === true ||
517
+ (ui5Version.major === 1 && ui5Version.minor >= 151));
518
+ }
519
+ /**
520
+ * Adds additional apps from flpConfig.apps to the template configuration.
521
+ *
522
+ * @param flpConfig - the resolved FLP configuration
523
+ * @param basePath - path to the application root
524
+ * @param flpTemplConfig - the template configuration to extend
525
+ * @param fs - file system editor
526
+ * @param logger - logger instance
527
+ */
528
+ async function addAdditionalApps(flpConfig, basePath, flpTemplConfig, fs, logger) {
529
+ for (const app of flpConfig.apps) {
530
+ if (app.local) {
531
+ const appPath = await getWebappPath(join(basePath, app.local), fs);
532
+ if (fs.exists(join(appPath, 'manifest.json'))) {
533
+ const appManifest = (await fs.readJSON(join(appPath, 'manifest.json')));
534
+ await addApp(flpTemplConfig, appManifest, app, logger);
535
+ }
536
+ else {
537
+ logger.warn(`Could not add route for ${app}`);
538
+ }
539
+ }
540
+ }
541
+ }
402
542
  /**
403
543
  * Generates the preview files.
404
544
  *
@@ -413,9 +553,8 @@ export async function generatePreviewFiles(basePath, config, fs, logger = new To
413
553
  sanitizeConfig(config, logger);
414
554
  // create file system if not provided
415
555
  fs ??= create(createStorage());
416
- // generate FLP configuration
417
- const flpTemplate = readFileSync(join(TEMPLATE_PATH, 'flp/sandbox.ejs'), 'utf-8');
418
556
  const flpConfig = getFlpConfigWithDefaults(config.flp);
557
+ const isCap = (await getProjectType(basePath)) !== 'EDMXBackend';
419
558
  const webappPath = await getWebappPath(basePath, fs);
420
559
  let manifest;
421
560
  if (fs.exists(join(webappPath, 'manifest.json'))) {
@@ -424,7 +563,7 @@ export async function generatePreviewFiles(basePath, config, fs, logger = new To
424
563
  let flpTemplConfig;
425
564
  let flpPath;
426
565
  if (manifest) {
427
- flpTemplConfig = createFlpTemplateConfig(flpConfig, manifest);
566
+ flpTemplConfig = createFlpTemplateConfig(flpConfig, manifest, {}, false, isCap, logger);
428
567
  flpPath = join(webappPath, flpConfig.path);
429
568
  await addApp(flpTemplConfig, manifest, {
430
569
  target: flpTemplConfig.basePath,
@@ -434,24 +573,17 @@ export async function generatePreviewFiles(basePath, config, fs, logger = new To
434
573
  generateTestRunners(config.test, manifest, fs, webappPath, flpTemplConfig);
435
574
  }
436
575
  else {
437
- flpTemplConfig = createFlpTemplateConfig(flpConfig, {});
576
+ flpTemplConfig = createFlpTemplateConfig(flpConfig, {}, {}, false, isCap, logger);
438
577
  flpPath = join(basePath, flpConfig.path);
439
578
  }
440
- if (flpConfig.apps.length > 0) {
441
- for (const app of flpConfig.apps) {
442
- if (app.local) {
443
- const appPath = await getWebappPath(join(basePath, app.local), fs);
444
- if (fs.exists(join(appPath, 'manifest.json'))) {
445
- const appManifest = (await fs.readJSON(join(appPath, 'manifest.json')));
446
- await addApp(flpTemplConfig, appManifest, app, logger);
447
- }
448
- else {
449
- logger.warn(`Could not add route for ${app}`);
450
- }
451
- }
452
- }
579
+ await addAdditionalApps(flpConfig, basePath, flpTemplConfig, fs, logger);
580
+ if (shouldUseSandbox2(manifest, flpConfig, basePath, fs)) {
581
+ // manifest is guaranteed non-undefined here: shouldUseSandbox2 returns false when manifest is undefined
582
+ generateSandbox2Files(flpPath, flpTemplConfig, flpConfig, manifest, config.adp !== undefined, isCap, logger, fs);
583
+ }
584
+ else {
585
+ fs.write(flpPath, render(readFileSync(join(TEMPLATE_PATH, 'flp/sandbox.ejs'), 'utf-8'), flpTemplConfig));
453
586
  }
454
- fs.write(flpPath, render(flpTemplate, flpTemplConfig));
455
587
  return fs;
456
588
  }
457
589
  //# sourceMappingURL=config.js.map
@@ -78,6 +78,7 @@ export declare class FlpSandbox {
78
78
  * Also deletes the ABAP connector in case of a CAP project.
79
79
  * Deletes all connectors if UI5 version is < 1.84 and served from npmjs.
80
80
  *
81
+ * @param config - the template config to mutate (must be a per-request clone, not the shared this.templateConfig)
81
82
  * @param ui5VersionMajor - the major version of UI5
82
83
  * @param ui5VersionMinor - the minor version of UI5
83
84
  * @param isCDN - whether the UI5 sources are served from CDN
@@ -136,6 +137,17 @@ export declare class FlpSandbox {
136
137
  * @private
137
138
  */
138
139
  private flpGetHandler;
140
+ /**
141
+ * Handler for GET requests to fioriSandboxAppConfig.json (Sandbox 2.0).
142
+ * Serves a virtual config, optionally merged with a user-provided file.
143
+ * If a real HTML file exists at the FLP path, no virtual config is served.
144
+ *
145
+ * @param req incoming request
146
+ * @param res server response
147
+ * @param next next middleware function
148
+ * @param configJsonPath project-relative path to fioriSandboxAppConfig.json
149
+ */
150
+ private sandboxAppConfigGetHandler;
139
151
  /**
140
152
  * Add routes for html and scripts required for a local FLP.
141
153
  */
@@ -172,6 +184,7 @@ export declare class FlpSandbox {
172
184
  private getUi5Version;
173
185
  /**
174
186
  * Read the sandbox template file based on the given UI5 version.
187
+ * Also checks for a legacy 'appconfig/fioriSandboxConfig.json' and falls back to Sandbox 1 if found.
175
188
  *
176
189
  * @param ui5Version - the UI5 version
177
190
  * @returns the template for the sandbox HTML file
@@ -182,6 +195,17 @@ export declare class FlpSandbox {
182
195
  * to load the changes in an Adaptation project.
183
196
  */
184
197
  private removeAsyncHintsRequests;
198
+ /**
199
+ * Checks if a legacy 'appconfig/fioriSandboxConfig.json' file is present when using the new FLP Sandbox.
200
+ * If found, warns the user to migrate and returns true so the caller can fall back to the classic Sandbox
201
+ * for this request.
202
+ *
203
+ * @param ui5Version - the resolved UI5 version
204
+ * @param baseUrl - the base URL of the current request
205
+ * @returns true if the legacy file is present and sandbox 2 should be suppressed
206
+ * @private
207
+ */
208
+ private hasLegacySandboxConfig;
185
209
  /**
186
210
  * For UI5 versions below 1.120, flexExtensionPointEnabled must be removed from the application
187
211
  * dependencies manifest. Older UI5 versions cannot handle this property at bootstrap time.