@sap-ux/create 0.16.8 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -68,7 +68,7 @@ Command group for adding features to existing SAP Fiori applications. A subcomma
68
68
 
69
69
  Usage: `npx --yes @sap-ux/create@latest add [subcommand] [options]`
70
70
 
71
- The available subcommands are: `mockserver-config`, `smartlinks-config`, `eslint-config`, `cds-plugin-ui5`, `inbound-navigation`, `cards-editor`, `model`, `annotations`, `html`, `component-usages`, `deploy-config`, `variants-config`, `adp-cf-config` and `flp-embedded-config`
71
+ The available subcommands are: `mockserver-config`, `smartlinks-config`, `eslint-config`, `cds-plugin-ui5`, `inbound-navigation`, `cards-editor`, `model`, `annotations`, `html`, `component-usages`, `deploy-config`, `variants-config`, `adp-cf-config`, `system` and `flp-embedded-config`
72
72
 
73
73
 
74
74
  --------------------------------
@@ -271,6 +271,35 @@ Options:
271
271
 
272
272
  --------------------------------
273
273
 
274
+ ## [`add system`](#add-system)
275
+
276
+ Add a new back-end system to the saved systems store (`~/.fioritools`). Credentials are stored securely in the OS keychain.
277
+
278
+
279
+ System types: `AbapCloud`, `OnPrem`, `Generic`
280
+
281
+ Auth types: `basic`, `reentranceTicket`, `oauth2`, `oauth2ClientCredential`
282
+
283
+ Connection types: `abap_catalog`, `generic_host`, `odata_service`
284
+
285
+ Example:
286
+
287
+ `npx --yes @sap-ux/create@latest add system --name "My System" --url https://my-sap.example.com`
288
+
289
+ `npx --yes @sap-ux/create@latest add system --name "My System" --url https://my-sap.example.com --client 100 --username myuser`
290
+
291
+ Options:
292
+ - `--name <string>` _(required)_ - Display name for the system
293
+ - `--url <string>` _(required)_ - URL of the backend system
294
+ - `--client <string>` - SAP client number (optional)
295
+ - `--type <string>` - System type (AbapCloud | OnPrem | Generic) _(default: `OnPrem`)_
296
+ - `--auth <string>` - Authentication type (basic | reentranceTicket | oauth2 | oauth2ClientCredential) _(default: `basic`)_
297
+ - `--connection-type <string>` - Connection type (abap_catalog | generic_host | odata_service) _(default: `abap_catalog`)_
298
+ - `--username <string>` - Username for basic authentication
299
+ - `--password <string>` - To avoid plain-text credentials in the shell's history, pass an env reference: --password env:MY_VAR
300
+
301
+ --------------------------------
302
+
274
303
  ## [`add flp-embedded-config`](#add-flp-embedded-config)
275
304
 
276
305
  Add the necessary configuration for running a Fiori app in FLP Embedded Mode.
@@ -340,7 +369,7 @@ Command group for removing features from existing SAP Fiori applications. A subc
340
369
 
341
370
  Usage: `npx --yes @sap-ux/create@latest remove [subcommand] [options]`
342
371
 
343
- The available subcommands are: `mockserver-config`
372
+ The available subcommands are: `mockserver-config` and `system`
344
373
 
345
374
 
346
375
  --------------------------------
@@ -359,13 +388,29 @@ Options:
359
388
 
360
389
  --------------------------------
361
390
 
391
+ ## [`remove system`](#remove-system)
392
+
393
+ Remove a saved back-end system from the saved system store (`~/.fioritools`). Also deletes any stored credentials in the OS keychain.
394
+
395
+ Example:
396
+
397
+ `npx --yes @sap-ux/create@latest remove system --url https://my-sap.example.com`
398
+
399
+ `npx --yes @sap-ux/create@latest remove system --url https://my-sap.example.com --client 100`
400
+
401
+ Options:
402
+ - `--url <string>` _(required)_ - URL of the backend system to remove
403
+ - `--client <string>` - SAP client number (optional)
404
+
405
+ --------------------------------
406
+
362
407
  ## [`change`](#change)
363
408
 
364
409
  Command group for changing existing SAP Fiori applications. A subcommand is required.
365
410
 
366
411
  Usage: `npx --yes @sap-ux/create@latest change [subcommand] [options]`
367
412
 
368
- The available subcommands are: `data-source` and `inbound`
413
+ The available subcommands are: `data-source`, `inbound` and `system`
369
414
 
370
415
  --------------------------------
371
416
 
@@ -400,3 +445,80 @@ Example:
400
445
  Options:
401
446
  - `-s, --simulate` - Simulate only. Do not write or install.
402
447
 
448
+ --------------------------------
449
+
450
+ ## [`change system`](#change-system)
451
+
452
+ Update an existing backend system in the saved systems store (`~/.fioritools`). The system is identified by its URL and optional SAP client.
453
+
454
+
455
+ Example:
456
+
457
+ `npx --yes @sap-ux/create@latest change system --url https://my-sap.example.com --name "New Name"`
458
+
459
+ `npx --yes @sap-ux/create@latest change system --url https://my-sap.example.com --client 100 --username newuser`
460
+
461
+ Options:
462
+ - `--url <string>` _(required)_ - URL of the backend system to update
463
+ - `--client <string>` - SAP client number to identify the system (optional)
464
+ - `--name <string>` - New display name for the system
465
+ - `--username <string>` - New username
466
+ - `--password <string>` - To avoid plain-text credentials in the shell's history, pass an env reference: --password env:MY_VAR
467
+ - `--clear-credentials` - Remove stored credentials from the system
468
+
469
+ --------------------------------
470
+
471
+ ## [`list`](#list)
472
+
473
+ Command group for listing saved resources. A subcommand is required.
474
+
475
+ Usage: `npx --yes @sap-ux/create@latest list [subcommand] [options]`
476
+
477
+ The available subcommands are: `system`
478
+
479
+
480
+ --------------------------------
481
+
482
+ ## [`list system`](#list-system)
483
+
484
+ List all back-end systems in the saved system store (`~/.fioritools`). Sensitive data, such as passwords and tokens, is never included in the output.
485
+
486
+ Example:
487
+
488
+ `npx --yes @sap-ux/create@latest list system`
489
+
490
+ `npx --yes @sap-ux/create@latest list system --json`
491
+
492
+ Options:
493
+ - `--json` - Output as JSON, which is useful for automation and MCP integrations.
494
+
495
+ --------------------------------
496
+
497
+ ## [`get`](#get)
498
+
499
+ Command group for retrieving saved resources. A subcommand is required.
500
+
501
+ Usage: `npx --yes @sap-ux/create@latest get [subcommand] [options]`
502
+
503
+ The available subcommands are: `system`
504
+
505
+
506
+ --------------------------------
507
+
508
+ ## [`get system`](#get-system)
509
+
510
+ Retrieve details of a saved back-end system by URL. Sensitive data (passwords, tokens) is never included in the output.
511
+
512
+ Example:
513
+
514
+ `npx --yes @sap-ux/create@latest get system --url https://my-sap.example.com`
515
+
516
+ `npx --yes @sap-ux/create@latest get system --url https://my-sap.example.com --client 100`
517
+
518
+ `npx --yes @sap-ux/create@latest get system --url https://my-sap.example.com --json`
519
+
520
+ Options:
521
+ - `--url <string>` _(required)_ - URL of the backend system.
522
+ - `--client <string>` - SAP client number (optional).
523
+ - `--json` - Output as JSON, which is useful for automation and MCP integrations.
524
+
@@ -15,6 +15,7 @@ const deploy_config_1 = require("./deploy-config");
15
15
  const variants_config_1 = require("./variants-config");
16
16
  const adp_cf_config_1 = require("./adp-cf-config");
17
17
  const eslint_config_1 = require("./eslint-config");
18
+ const system_1 = require("./system");
18
19
  const flp_embedded_config_1 = require("./flp-embedded-config");
19
20
  /**
20
21
  * Return 'create-fiori add *' commands. Commands include also the handler action.
@@ -36,6 +37,7 @@ function getAddCommands() {
36
37
  (0, deploy_config_1.addDeployConfigCommand)(addCommands);
37
38
  (0, variants_config_1.addAddVariantsConfigCommand)(addCommands);
38
39
  (0, adp_cf_config_1.addAdaptationProjectCFConfigCommand)(addCommands);
40
+ (0, system_1.addSystemAddCommand)(addCommands);
39
41
  (0, flp_embedded_config_1.addFlpEmbeddedConfigCommand)(addCommands);
40
42
  return addCommands;
41
43
  }
@@ -0,0 +1,10 @@
1
+ import type { Command } from 'commander';
2
+ /**
3
+ * Add the "add system" subcommand to a passed command.
4
+ * Adds a new backend system to the saved systems store (~/.fioritools).
5
+ * Credentials are stored securely in the OS keychain.
6
+ *
7
+ * @param cmd - commander command to attach the system subcommand to
8
+ */
9
+ export declare function addSystemAddCommand(cmd: Command): void;
10
+ //# sourceMappingURL=system.d.ts.map
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addSystemAddCommand = addSystemAddCommand;
4
+ const btp_utils_1 = require("@sap-ux/btp-utils");
5
+ const store_1 = require("@sap-ux/store");
6
+ const ui5_config_1 = require("@sap-ux/ui5-config");
7
+ const dotenv_1 = require("dotenv");
8
+ const tracing_1 = require("../../tracing");
9
+ /**
10
+ * Add the "add system" subcommand to a passed command.
11
+ * Adds a new backend system to the saved systems store (~/.fioritools).
12
+ * Credentials are stored securely in the OS keychain.
13
+ *
14
+ * @param cmd - commander command to attach the system subcommand to
15
+ */
16
+ function addSystemAddCommand(cmd) {
17
+ cmd.command('system')
18
+ .description(`Add a new back-end system to the saved systems store (\`~/.fioritools\`). Credentials are stored securely in the OS keychain.\n
19
+ System types: \`${Object.values(store_1.SystemType).join('`, `')}\`
20
+ Auth types: \`${Object.values(store_1.AuthenticationType).join('`, `')}\`
21
+ Connection types: \`${Object.values(store_1.ConnectionType).join('`, `')}\`\n
22
+ Example:
23
+ \`npx --yes @sap-ux/create@latest add system --name "My System" --url https://my-sap.example.com\`
24
+ \`npx --yes @sap-ux/create@latest add system --name "My System" --url https://my-sap.example.com --client 100 --username myuser\``)
25
+ .requiredOption('--name <string>', 'Display name for the system')
26
+ .requiredOption('--url <string>', 'URL of the backend system')
27
+ .option('--client <string>', 'SAP client number (optional)')
28
+ .option('--type <string>', `System type (${Object.values(store_1.SystemType).join(' | ')})`, store_1.SystemType.AbapOnPrem)
29
+ .option('--auth <string>', `Authentication type (${Object.values(store_1.AuthenticationType).join(' | ')})`, store_1.AuthenticationType.Basic)
30
+ .option('--connection-type <string>', `Connection type (${Object.values(store_1.ConnectionType).join(' | ')})`, store_1.ConnectionType.AbapCatalog)
31
+ .option('--username <string>', 'Username for basic authentication')
32
+ .option('--password <string>', "To avoid plain-text credentials in the shell's history, pass an env reference: --password env:MY_VAR")
33
+ .action(async (options) => {
34
+ (0, dotenv_1.config)();
35
+ await addSystem({
36
+ name: options.name,
37
+ url: options.url,
38
+ client: options.client,
39
+ systemType: options.type,
40
+ authenticationType: options.auth,
41
+ connectionType: options.connectionType,
42
+ username: options.username,
43
+ password: options.password
44
+ });
45
+ });
46
+ }
47
+ /**
48
+ * Adds a backend system to the saved systems store.
49
+ *
50
+ * @param params - system parameters
51
+ * @param params.name - display name for the system
52
+ * @param params.url - URL of the backend system
53
+ * @param params.client - optional SAP client
54
+ * @param params.systemType - system type
55
+ * @param params.authenticationType - authentication type
56
+ * @param params.connectionType - connection type
57
+ * @param params.username - optional username for basic auth
58
+ * @param params.password - optional password for basic auth
59
+ */
60
+ async function addSystem(params) {
61
+ const logger = (0, tracing_1.getLogger)();
62
+ try {
63
+ if ((0, btp_utils_1.isAppStudio)()) {
64
+ logger.error('System management using the CLI is not supported in SAP Business Application Studio. Use the built-in system management instead.');
65
+ return;
66
+ }
67
+ try {
68
+ new URL(params.url);
69
+ }
70
+ catch {
71
+ logger.error(`Invalid URL: '${params.url}'`);
72
+ return;
73
+ }
74
+ const validSystemTypes = Object.values(store_1.SystemType);
75
+ if (!validSystemTypes.includes(params.systemType)) {
76
+ logger.error(`Invalid system type '${params.systemType}'. Valid values: ${validSystemTypes.join(', ')}`);
77
+ return;
78
+ }
79
+ const validAuthTypes = Object.values(store_1.AuthenticationType);
80
+ if (!validAuthTypes.includes(params.authenticationType)) {
81
+ logger.error(`Invalid auth type '${params.authenticationType}'. Valid values: ${validAuthTypes.join(', ')}`);
82
+ return;
83
+ }
84
+ const validConnectionTypes = Object.values(store_1.ConnectionType);
85
+ if (!validConnectionTypes.includes(params.connectionType)) {
86
+ logger.error(`Invalid connection type '${params.connectionType}'. Valid values: ${validConnectionTypes.join(', ')}`);
87
+ return;
88
+ }
89
+ const service = await (0, store_1.getService)({ entityName: 'system' });
90
+ const existingSystem = await service.read(new store_1.BackendSystemKey({ url: params.url, client: params.client }));
91
+ if (existingSystem) {
92
+ const clientSuffix = params.client ? ` (client ${params.client})` : '';
93
+ logger.error(`System '${params.url}'${clientSuffix} already exists. Use 'change system' to update it.`);
94
+ return;
95
+ }
96
+ (0, ui5_config_1.replaceEnvVariables)(params);
97
+ const system = new store_1.BackendSystem({
98
+ name: params.name,
99
+ url: params.url,
100
+ client: params.client,
101
+ systemType: params.systemType,
102
+ authenticationType: params.authenticationType,
103
+ connectionType: params.connectionType,
104
+ username: params.username,
105
+ password: params.password
106
+ });
107
+ await service.write(system);
108
+ logger.info(`System '${params.name}' added.`);
109
+ }
110
+ catch (error) {
111
+ logger.error(error.message);
112
+ logger.debug(error);
113
+ }
114
+ }
115
+ //# sourceMappingURL=system.js.map
@@ -4,6 +4,7 @@ exports.getChangeCommands = getChangeCommands;
4
4
  const commander_1 = require("commander");
5
5
  const change_data_source_1 = require("./change-data-source");
6
6
  const change_inbound_1 = require("./change-inbound");
7
+ const system_1 = require("./system");
7
8
  /**
8
9
  * Return 'create-fiori change *' commands. Commands include also the handler action.
9
10
  *
@@ -13,6 +14,7 @@ function getChangeCommands() {
13
14
  const changeCommands = new commander_1.Command('change');
14
15
  (0, change_data_source_1.addChangeDataSourceCommand)(changeCommands);
15
16
  (0, change_inbound_1.addChangeInboundCommand)(changeCommands);
17
+ (0, system_1.addSystemUpdateCommand)(changeCommands);
16
18
  return changeCommands;
17
19
  }
18
20
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,10 @@
1
+ import type { Command } from 'commander';
2
+ /**
3
+ * Add the "change system" subcommand to a passed command.
4
+ * Updates an existing backend system in the saved systems store (~/.fioritools).
5
+ * The system is identified by URL and optional SAP client.
6
+ *
7
+ * @param cmd - commander command to attach the system subcommand to
8
+ */
9
+ export declare function addSystemUpdateCommand(cmd: Command): void;
10
+ //# sourceMappingURL=system.d.ts.map
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addSystemUpdateCommand = addSystemUpdateCommand;
4
+ const btp_utils_1 = require("@sap-ux/btp-utils");
5
+ const store_1 = require("@sap-ux/store");
6
+ const ui5_config_1 = require("@sap-ux/ui5-config");
7
+ const dotenv_1 = require("dotenv");
8
+ const tracing_1 = require("../../tracing");
9
+ /**
10
+ * Add the "change system" subcommand to a passed command.
11
+ * Updates an existing backend system in the saved systems store (~/.fioritools).
12
+ * The system is identified by URL and optional SAP client.
13
+ *
14
+ * @param cmd - commander command to attach the system subcommand to
15
+ */
16
+ function addSystemUpdateCommand(cmd) {
17
+ cmd.command('system')
18
+ .description(`Update an existing backend system in the saved systems store (\`~/.fioritools\`). The system is identified by its URL and optional SAP client.\n
19
+
20
+ Example:
21
+ \`npx --yes @sap-ux/create@latest change system --url https://my-sap.example.com --name "New Name"\`
22
+ \`npx --yes @sap-ux/create@latest change system --url https://my-sap.example.com --client 100 --username newuser\``)
23
+ .requiredOption('--url <string>', 'URL of the backend system to update')
24
+ .option('--client <string>', 'SAP client number to identify the system (optional)')
25
+ .option('--name <string>', 'New display name for the system')
26
+ .option('--username <string>', 'New username')
27
+ .option('--password <string>', "To avoid plain-text credentials in the shell's history, pass an env reference: --password env:MY_VAR")
28
+ .option('--clear-credentials', 'Remove stored credentials from the system')
29
+ .action(async (options) => {
30
+ (0, dotenv_1.config)();
31
+ await updateSystem({
32
+ url: options.url,
33
+ client: options.client,
34
+ name: options.name,
35
+ username: options.username,
36
+ password: options.password,
37
+ clearCredentials: !!options.clearCredentials
38
+ });
39
+ });
40
+ }
41
+ /**
42
+ * Updates a backend system in the saved systems store.
43
+ *
44
+ * @param params - update parameters
45
+ * @param params.url - URL identifying the system
46
+ * @param params.client - optional SAP client identifying the system
47
+ * @param params.name - optional new display name
48
+ * @param params.username - optional new username
49
+ * @param params.password - optional new password
50
+ * @param params.clearCredentials - if true, clears stored credentials
51
+ */
52
+ async function updateSystem(params) {
53
+ const logger = (0, tracing_1.getLogger)();
54
+ try {
55
+ if ((0, btp_utils_1.isAppStudio)()) {
56
+ logger.error('System management using the CLI is not supported in SAP Business Application Studio. Use the built-in system management instead.');
57
+ return;
58
+ }
59
+ const patchRecord = {};
60
+ (0, ui5_config_1.replaceEnvVariables)(params);
61
+ if (params.name !== undefined) {
62
+ patchRecord.name = params.name;
63
+ }
64
+ if (params.clearCredentials) {
65
+ patchRecord.username = undefined;
66
+ patchRecord.password = undefined;
67
+ }
68
+ else if (params.username !== undefined || params.password !== undefined) {
69
+ if (params.username !== undefined) {
70
+ patchRecord.username = params.username;
71
+ }
72
+ if (params.password !== undefined) {
73
+ patchRecord.password = params.password;
74
+ }
75
+ }
76
+ const patch = patchRecord;
77
+ if (!Object.keys(patchRecord).length) {
78
+ logger.error('No fields to update. Provide at least one of: --name, --username, --password, --clear-credentials');
79
+ return;
80
+ }
81
+ const service = await (0, store_1.getService)({ entityName: 'system' });
82
+ const key = new store_1.BackendSystemKey({ url: params.url, client: params.client });
83
+ const existing = await service.read(key);
84
+ if (!existing) {
85
+ logger.error(`System not found: ${key.getId()}`);
86
+ return;
87
+ }
88
+ await service.partialUpdate(key, patch);
89
+ logger.info(`System '${key.getId()}' updated.`);
90
+ }
91
+ catch (error) {
92
+ logger.error(error.message);
93
+ // Log the full error object (including stack trace) at debug level so it
94
+ // is visible when --verbose / debug logging is enabled.
95
+ logger.debug(error);
96
+ }
97
+ }
98
+ //# sourceMappingURL=system.js.map
@@ -0,0 +1,8 @@
1
+ import { Command } from 'commander';
2
+ /**
3
+ * Return 'create-fiori get *' commands. Commands include also the handler action.
4
+ *
5
+ * @returns - commander command containing get <feature> commands
6
+ */
7
+ export declare function getGetCommands(): Command;
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getGetCommands = getGetCommands;
4
+ const commander_1 = require("commander");
5
+ const system_1 = require("./system");
6
+ /**
7
+ * Return 'create-fiori get *' commands. Commands include also the handler action.
8
+ *
9
+ * @returns - commander command containing get <feature> commands
10
+ */
11
+ function getGetCommands() {
12
+ const getCommands = new commander_1.Command('get');
13
+ (0, system_1.addSystemGetCommand)(getCommands);
14
+ return getCommands;
15
+ }
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,10 @@
1
+ import type { Command } from 'commander';
2
+ /**
3
+ * Add the "get system" subcommand to a passed command.
4
+ * Retrieves details of a saved backend system identified by its URL and optional client.
5
+ * Sensitive data (passwords, tokens) is never included in the output.
6
+ *
7
+ * @param cmd - commander command to attach the system subcommand to
8
+ */
9
+ export declare function addSystemGetCommand(cmd: Command): void;
10
+ //# sourceMappingURL=system.d.ts.map
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addSystemGetCommand = addSystemGetCommand;
4
+ const btp_utils_1 = require("@sap-ux/btp-utils");
5
+ const store_1 = require("@sap-ux/store");
6
+ const logger_1 = require("@sap-ux/logger");
7
+ const tracing_1 = require("../../tracing");
8
+ /**
9
+ * Add the "get system" subcommand to a passed command.
10
+ * Retrieves details of a saved backend system identified by its URL and optional client.
11
+ * Sensitive data (passwords, tokens) is never included in the output.
12
+ *
13
+ * @param cmd - commander command to attach the system subcommand to
14
+ */
15
+ function addSystemGetCommand(cmd) {
16
+ cmd.command('system')
17
+ .description(`Retrieve details of a saved back-end system by URL. Sensitive data (passwords, tokens) is never included in the output.\n
18
+ Example:
19
+ \`npx --yes @sap-ux/create@latest get system --url https://my-sap.example.com\`
20
+ \`npx --yes @sap-ux/create@latest get system --url https://my-sap.example.com --client 100\`
21
+ \`npx --yes @sap-ux/create@latest get system --url https://my-sap.example.com --json\``)
22
+ .requiredOption('--url <string>', 'URL of the backend system.')
23
+ .option('--client <string>', 'SAP client number (optional).')
24
+ .option('--json', 'Output as JSON, which is useful for automation and MCP integrations.')
25
+ .action(async (options) => {
26
+ await getSystem(options.url, options.client, !!options.json);
27
+ });
28
+ }
29
+ /**
30
+ * Retrieves a backend system from the store by its URL and optional client.
31
+ *
32
+ * @param url - URL of the backend system
33
+ * @param client - optional SAP client
34
+ * @param asJson - if true, output as JSON; otherwise print human-readable
35
+ */
36
+ async function getSystem(url, client, asJson) {
37
+ const logger = (0, tracing_1.getLogger)();
38
+ try {
39
+ if ((0, btp_utils_1.isAppStudio)()) {
40
+ logger.error('System management using the CLI is not supported in SAP Business Application Studio. Use the built-in system management instead.');
41
+ return;
42
+ }
43
+ // When emitting JSON, pass a silent logger to getService so that
44
+ // @sap-ux/store diagnostic messages do not appear on stdout before the
45
+ // JSON payload and break piped consumers.
46
+ const storeLogger = asJson ? new logger_1.ToolsLogger({ transports: [new logger_1.NullTransport()] }) : logger;
47
+ const service = await (0, store_1.getService)({
48
+ entityName: 'system',
49
+ logger: storeLogger
50
+ });
51
+ const key = new store_1.BackendSystemKey({ url, client });
52
+ const system = await service.read(key);
53
+ if (!system) {
54
+ logger.error(`System not found: ${key.getId()}`);
55
+ return;
56
+ }
57
+ const publicView = {
58
+ name: system.name,
59
+ url: system.url,
60
+ client: system.client,
61
+ systemType: system.systemType,
62
+ authenticationType: system.authenticationType,
63
+ connectionType: system.connectionType,
64
+ userDisplayName: system.userDisplayName,
65
+ hasSensitiveData: system.hasSensitiveData
66
+ };
67
+ if (asJson) {
68
+ // Use process.stdout.write so the output is pure JSON with no logger
69
+ // prefixes or timestamps — required for machine consumption and piping.
70
+ process.stdout.write(JSON.stringify(publicView, null, 2) + '\n');
71
+ }
72
+ else {
73
+ logger.info(`Name: ${system.name}`);
74
+ logger.info(`URL: ${system.url}`);
75
+ if (system.client) {
76
+ logger.info(`Client: ${system.client}`);
77
+ }
78
+ logger.info(`Type: ${system.systemType}`);
79
+ logger.info(`Auth: ${system.authenticationType ?? 'n/a'}`);
80
+ logger.info(`Connection: ${system.connectionType}`);
81
+ if (system.hasSensitiveData) {
82
+ logger.info(`Credentials stored securely.`);
83
+ }
84
+ }
85
+ }
86
+ catch (error) {
87
+ logger.error(error.message);
88
+ // Log the full error object (including stack trace) at debug level so it
89
+ // is visible when --verbose / debug logging is enabled.
90
+ logger.debug(error);
91
+ }
92
+ }
93
+ //# sourceMappingURL=system.js.map
package/dist/cli/index.js CHANGED
@@ -11,6 +11,8 @@ const remove_1 = require("./remove");
11
11
  const generate_1 = require("./generate");
12
12
  const change_1 = require("./change");
13
13
  const convert_1 = require("./convert");
14
+ const list_1 = require("./list");
15
+ const get_1 = require("./get");
14
16
  /*
15
17
  * We've chosen 'commander' over 'minimist' and 'yargs' for this CLI implementation. Reasons:
16
18
  * (if it still up: https://npmtrends.com/commander-vs-minimist-vs-yargs)
@@ -94,6 +96,18 @@ function getCommanderProgram() {
94
96
  Usage: \`npx --yes @sap-ux/create@latest change [subcommand] [options]\`
95
97
  The available subcommands are: ${getFeatureSummary(changeCommands.commands)}`);
96
98
  program.addCommand(changeCommands);
99
+ // Handler for create-fiori list <feature> ..
100
+ const listCommands = (0, list_1.getListCommands)();
101
+ listCommands.description(`Command group for listing saved resources. A subcommand is required.
102
+ Usage: \`npx --yes @sap-ux/create@latest list [subcommand] [options]\`
103
+ The available subcommands are: ${getFeatureSummary(listCommands.commands)}\n`);
104
+ program.addCommand(listCommands);
105
+ // Handler for create-fiori get <feature> ..
106
+ const getCommands = (0, get_1.getGetCommands)();
107
+ getCommands.description(`Command group for retrieving saved resources. A subcommand is required.
108
+ Usage: \`npx --yes @sap-ux/create@latest get [subcommand] [options]\`
109
+ The available subcommands are: ${getFeatureSummary(getCommands.commands)}\n`);
110
+ program.addCommand(getCommands);
97
111
  return program;
98
112
  }
99
113
  /**
@@ -0,0 +1,8 @@
1
+ import { Command } from 'commander';
2
+ /**
3
+ * Return 'create-fiori list *' commands. Commands include also the handler action.
4
+ *
5
+ * @returns - commander command containing list <feature> commands
6
+ */
7
+ export declare function getListCommands(): Command;
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getListCommands = getListCommands;
4
+ const commander_1 = require("commander");
5
+ const system_1 = require("./system");
6
+ /**
7
+ * Return 'create-fiori list *' commands. Commands include also the handler action.
8
+ *
9
+ * @returns - commander command containing list <feature> commands
10
+ */
11
+ function getListCommands() {
12
+ const listCommands = new commander_1.Command('list');
13
+ (0, system_1.addSystemListCommand)(listCommands);
14
+ return listCommands;
15
+ }
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,10 @@
1
+ import type { Command } from 'commander';
2
+ /**
3
+ * Add the "list system" subcommand to a passed command.
4
+ * Lists all backend systems saved in the store (~/.fioritools).
5
+ * Sensitive data, such as passwords and tokens, is never included in the output.
6
+ *
7
+ * @param cmd - commander command to attach the system subcommand to
8
+ */
9
+ export declare function addSystemListCommand(cmd: Command): void;
10
+ //# sourceMappingURL=system.d.ts.map
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addSystemListCommand = addSystemListCommand;
4
+ const btp_utils_1 = require("@sap-ux/btp-utils");
5
+ const store_1 = require("@sap-ux/store");
6
+ const logger_1 = require("@sap-ux/logger");
7
+ const tracing_1 = require("../../tracing");
8
+ /**
9
+ * Add the "list system" subcommand to a passed command.
10
+ * Lists all backend systems saved in the store (~/.fioritools).
11
+ * Sensitive data, such as passwords and tokens, is never included in the output.
12
+ *
13
+ * @param cmd - commander command to attach the system subcommand to
14
+ */
15
+ function addSystemListCommand(cmd) {
16
+ cmd.command('system')
17
+ .description(`List all back-end systems in the saved system store (\`~/.fioritools\`). Sensitive data, such as passwords and tokens, is never included in the output.\n
18
+ Example:
19
+ \`npx --yes @sap-ux/create@latest list system\`
20
+ \`npx --yes @sap-ux/create@latest list system --json\``)
21
+ .option('--json', 'Output as JSON, which is useful for automation and MCP integrations.')
22
+ .action(async (options) => {
23
+ await listSystems(!!options.json);
24
+ });
25
+ }
26
+ /**
27
+ * Lists all backend systems from the store.
28
+ * Sensitive fields are not shown.
29
+ *
30
+ * @param asJson - if true, output as JSON; otherwise print a human-readable list
31
+ */
32
+ async function listSystems(asJson) {
33
+ const logger = (0, tracing_1.getLogger)();
34
+ try {
35
+ if ((0, btp_utils_1.isAppStudio)()) {
36
+ logger.error('System management using the CLI is not supported in SAP Business Application Studio. Use the built-in system management instead.');
37
+ return;
38
+ }
39
+ // When emitting JSON, pass a silent logger to getService so that
40
+ // @sap-ux/store diagnostic messages (e.g. "Using KeyStoreManager…") do
41
+ // not appear on stdout before the JSON payload and break piped consumers.
42
+ const storeLogger = asJson ? new logger_1.ToolsLogger({ transports: [new logger_1.NullTransport()] }) : logger;
43
+ const service = await (0, store_1.getService)({
44
+ entityName: 'system',
45
+ logger: storeLogger
46
+ });
47
+ // Pass no filter so all systems are returned regardless of connection type
48
+ const systems = await service.getAll();
49
+ if (asJson) {
50
+ // Use process.stdout.write so the output is pure JSON with no logger
51
+ // prefixes or timestamps — required for machine consumption and piping.
52
+ process.stdout.write(JSON.stringify(systems.map(toPublicView), null, 2) + '\n');
53
+ }
54
+ else if (systems.length === 0) {
55
+ logger.info('No systems found.');
56
+ }
57
+ else {
58
+ logger.info(`Systems (${systems.length}):`);
59
+ for (const system of systems) {
60
+ printSystem(system, logger);
61
+ }
62
+ }
63
+ }
64
+ catch (error) {
65
+ logger.error(error.message);
66
+ // Log the full error object (including stack trace) at debug level so it
67
+ // is visible when --verbose / debug logging is enabled.
68
+ logger.debug(error);
69
+ }
70
+ }
71
+ /**
72
+ * Returns a view of a system with only non-sensitive fields.
73
+ *
74
+ * @param system - the backend system
75
+ * @returns non-sensitive system data
76
+ */
77
+ function toPublicView(system) {
78
+ return {
79
+ name: system.name,
80
+ url: system.url,
81
+ client: system.client,
82
+ systemType: system.systemType,
83
+ authenticationType: system.authenticationType,
84
+ connectionType: system.connectionType,
85
+ userDisplayName: system.userDisplayName,
86
+ hasSensitiveData: system.hasSensitiveData
87
+ };
88
+ }
89
+ /**
90
+ * Prints a single system to the logger in human-readable format.
91
+ *
92
+ * @param system - the backend system to print
93
+ * @param logger - logger instance
94
+ */
95
+ function printSystem(system, logger) {
96
+ const lines = [
97
+ ` Name: ${system.name}`,
98
+ ` URL: ${system.url}`,
99
+ system.client ? ` Client: ${system.client}` : undefined,
100
+ ` Type: ${system.systemType}`,
101
+ ` Auth: ${system.authenticationType ?? 'n/a'}`,
102
+ ` Connection: ${system.connectionType}`,
103
+ system.hasSensitiveData ? ` Credentials stored securely.` : undefined,
104
+ ` ---`
105
+ ];
106
+ for (const line of lines) {
107
+ if (line !== undefined) {
108
+ logger.info(line);
109
+ }
110
+ }
111
+ }
112
+ //# sourceMappingURL=system.js.map
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getRemoveCommands = getRemoveCommands;
4
4
  const commander_1 = require("commander");
5
5
  const mockserver_config_1 = require("./mockserver-config");
6
+ const system_1 = require("./system");
6
7
  /**
7
8
  * Return 'create-fiori remove *' commands. Commands include also the handler action.
8
9
  *
@@ -11,6 +12,7 @@ const mockserver_config_1 = require("./mockserver-config");
11
12
  function getRemoveCommands() {
12
13
  const removeCommands = new commander_1.Command('remove');
13
14
  (0, mockserver_config_1.addRemoveMockserverConfigCommand)(removeCommands);
15
+ (0, system_1.addSystemRemoveCommand)(removeCommands);
14
16
  return removeCommands;
15
17
  }
16
18
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,9 @@
1
+ import type { Command } from 'commander';
2
+ /**
3
+ * Add the "remove system" subcommand to a passed command.
4
+ * Removes a saved backend system from the store (~/.fioritools) and deletes its credentials from the OS keychain.
5
+ *
6
+ * @param cmd - commander command to attach the system subcommand to
7
+ */
8
+ export declare function addSystemRemoveCommand(cmd: Command): void;
9
+ //# sourceMappingURL=system.d.ts.map
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addSystemRemoveCommand = addSystemRemoveCommand;
4
+ const btp_utils_1 = require("@sap-ux/btp-utils");
5
+ const store_1 = require("@sap-ux/store");
6
+ const tracing_1 = require("../../tracing");
7
+ /**
8
+ * Add the "remove system" subcommand to a passed command.
9
+ * Removes a saved backend system from the store (~/.fioritools) and deletes its credentials from the OS keychain.
10
+ *
11
+ * @param cmd - commander command to attach the system subcommand to
12
+ */
13
+ function addSystemRemoveCommand(cmd) {
14
+ cmd.command('system')
15
+ .description(`Remove a saved back-end system from the saved system store (\`~/.fioritools\`). Also deletes any stored credentials in the OS keychain.\n
16
+ Example:
17
+ \`npx --yes @sap-ux/create@latest remove system --url https://my-sap.example.com\`
18
+ \`npx --yes @sap-ux/create@latest remove system --url https://my-sap.example.com --client 100\``)
19
+ .requiredOption('--url <string>', 'URL of the backend system to remove')
20
+ .option('--client <string>', 'SAP client number (optional)')
21
+ .action(async (options) => {
22
+ await removeSystem(options.url, options.client);
23
+ });
24
+ }
25
+ /**
26
+ * Removes a backend system from the saved systems store.
27
+ *
28
+ * @param url - URL of the system to remove
29
+ * @param client - optional SAP client
30
+ */
31
+ async function removeSystem(url, client) {
32
+ const logger = (0, tracing_1.getLogger)();
33
+ try {
34
+ if ((0, btp_utils_1.isAppStudio)()) {
35
+ logger.error('System management using the CLI is not supported in SAP Business Application Studio. Use the built-in system management instead.');
36
+ return;
37
+ }
38
+ const service = await (0, store_1.getService)({ entityName: 'system' });
39
+ const key = new store_1.BackendSystemKey({ url, client });
40
+ const system = await service.read(key);
41
+ if (!system) {
42
+ logger.error(`System not found: ${key.getId()}`);
43
+ return;
44
+ }
45
+ const deleted = await service.delete(system);
46
+ if (deleted) {
47
+ logger.info(`System '${system.name}' removed.`);
48
+ }
49
+ else {
50
+ logger.error(`Failed to remove system: ${key.getId()}`);
51
+ }
52
+ }
53
+ catch (error) {
54
+ logger.error(error.message);
55
+ logger.debug(error);
56
+ }
57
+ }
58
+ //# sourceMappingURL=system.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sap-ux/create",
3
3
  "description": "SAP Fiori tools module to add or remove features",
4
- "version": "0.16.8",
4
+ "version": "0.17.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/SAP/open-ux-tools.git",
@@ -28,6 +28,7 @@
28
28
  "chalk": "4.1.2",
29
29
  "commander": "14.0.3",
30
30
  "diff": "8.0.4",
31
+ "dotenv": "17.4.2",
31
32
  "mem-fs": "2.1.0",
32
33
  "mem-fs-editor": "9.4.0",
33
34
  "prompts": "2.4.2",
@@ -37,16 +38,17 @@
37
38
  "@sap-ux/btp-utils": "1.2.0",
38
39
  "@sap-ux/app-config-writer": "0.7.3",
39
40
  "@sap-ux/cap-config-writer": "0.13.3",
40
- "@sap-ux/logger": "0.9.0",
41
- "@sap-ux/mockserver-config-writer": "0.10.2",
42
- "@sap-ux/odata-service-writer": "0.32.2",
43
41
  "@sap-ux/preview-middleware": "0.26.7",
44
- "@sap-ux/project-access": "1.38.1",
42
+ "@sap-ux/odata-service-writer": "0.32.2",
45
43
  "@sap-ux/system-access": "0.8.0",
44
+ "@sap-ux/project-access": "1.38.1",
45
+ "@sap-ux/store": "1.6.0",
46
46
  "@sap-ux/ui5-config": "0.31.1",
47
47
  "@sap-ux/flp-config-inquirer": "0.5.6",
48
48
  "@sap-ux/nodejs-utils": "0.3.0",
49
- "@sap-ux/axios-extension": "1.26.0"
49
+ "@sap-ux/axios-extension": "1.26.0",
50
+ "@sap-ux/mockserver-config-writer": "0.10.2",
51
+ "@sap-ux/logger": "0.9.0"
50
52
  },
51
53
  "devDependencies": {
52
54
  "@types/diff": "8.0.0",