@sap-ux/create 1.3.27 → 1.4.3

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
@@ -314,7 +314,8 @@ Options:
314
314
  - `--connection-type <string>` - Connection type (abap_catalog | generic_host | odata_service) _(default: `abap_catalog`)_
315
315
  - `--username <string>` - Username for basic authentication
316
316
  - `--password <string>` - To avoid plain-text credentials in the shell's history, pass an env reference: --password env:MY_VAR
317
- - `--skip-check` - Skip connection verification before saving
317
+ - `--skip-credentials-prompt` - Skip credential prompts. No credentials will be saved, but may be added later if required
318
+ - `--skip-connection-validation` - Skip connection verification before saving
318
319
 
319
320
  --------------------------------
320
321
 
@@ -456,7 +457,8 @@ Options:
456
457
  - `--username <string>` - New username
457
458
  - `--password <string>` - To avoid plain-text credentials in the shell's history, pass an env reference: --password env:MY_VAR
458
459
  - `--clear-credentials` - Remove stored credentials from the system
459
- - `--skip-check` - Skip connection verification before saving
460
+ - `--skip-connection-validation` - Skip connection verification before saving
461
+ - `--skip-check` - (Deprecated: use --skip-connection-validation) Skip connection verification before saving
460
462
 
461
463
  --------------------------------
462
464
 
@@ -6,6 +6,7 @@ import { validateClient } from '@sap-ux/project-input-validator';
6
6
  import { getLogger } from '../../tracing/index.js';
7
7
  import { promptForSystemConfig } from '../utils/system-prompts.js';
8
8
  import { checkConnectionOrPrompt } from '../utils/system-connection.js';
9
+ import { t } from '../../i18n.js';
9
10
  /**
10
11
  * Add the "add system" subcommand to a passed command.
11
12
  * Adds a new backend system to the saved systems store (~/.fioritools).
@@ -31,7 +32,8 @@ Example:
31
32
  .option('--connection-type <string>', `Connection type (${Object.values(ConnectionType).join(' | ')})`, ConnectionType.AbapCatalog)
32
33
  .option('--username <string>', 'Username for basic authentication')
33
34
  .option('--password <string>', "To avoid plain-text credentials in the shell's history, pass an env reference: --password env:MY_VAR")
34
- .option('--skip-check', 'Skip connection verification before saving')
35
+ .option('--skip-credentials-prompt', 'Skip credential prompts. No credentials will be saved, but may be added later if required')
36
+ .option('--skip-connection-validation', 'Skip connection verification before saving')
35
37
  .action(async (options) => {
36
38
  loadEnvConfig();
37
39
  await addSystem({
@@ -43,7 +45,8 @@ Example:
43
45
  connectionType: options.connectionType,
44
46
  username: options.username,
45
47
  password: options.password,
46
- skipCheck: !!options.skipCheck
48
+ skipCredentialsPrompt: !!options.skipCredentialsPrompt,
49
+ skipConnectionValidation: !!options.skipConnectionValidation
47
50
  });
48
51
  });
49
52
  }
@@ -62,7 +65,7 @@ Example:
62
65
  */
63
66
  function validateSystemConfig(config, logger) {
64
67
  if (!config.name || !config.url || !config.systemType || !config.authenticationType || !config.connectionType) {
65
- logger.error('Missing required fields. System was not added.');
68
+ logger.error('Missing required fields.');
66
69
  return false;
67
70
  }
68
71
  if (config.name.trim().length === 0) {
@@ -83,6 +86,8 @@ function validateSystemConfig(config, logger) {
83
86
  return false;
84
87
  }
85
88
  }
89
+ // Validate that provided type values are valid enum members
90
+ // (TypeScript types don't prevent invalid runtime values from CLI flags)
86
91
  const validSystemTypes = Object.values(SystemType);
87
92
  if (!validSystemTypes.includes(config.systemType)) {
88
93
  logger.error(`Invalid system type '${config.systemType}'. Valid values: ${validSystemTypes.join(', ')}`);
@@ -137,7 +142,8 @@ async function checkForDuplicates(config, service, logger) {
137
142
  * @param params.connectionType - connection type
138
143
  * @param params.username - optional username for basic auth
139
144
  * @param params.password - optional password for basic auth
140
- * @param params.skipCheck - skip connection verification
145
+ * @param params.skipCredentialsPrompt - skip credential prompts entirely
146
+ * @param params.skipConnectionValidation - skip connection verification
141
147
  */
142
148
  async function addSystem(params) {
143
149
  const logger = getLogger();
@@ -154,14 +160,17 @@ async function addSystem(params) {
154
160
  authenticationType: params.authenticationType,
155
161
  connectionType: params.connectionType,
156
162
  username: params.username,
157
- password: params.password
163
+ password: params.password,
164
+ skipCredentialsPrompt: params.skipCredentialsPrompt
158
165
  });
159
166
  replaceEnvVariables(config);
160
167
  if (!validateSystemConfig(config, logger)) {
168
+ logger.info(t('systemActions.systemNotAddedInvalidConfig'));
161
169
  return;
162
170
  }
163
171
  const service = await getService({ entityName: 'system' });
164
172
  if (!(await checkForDuplicates(config, service, logger))) {
173
+ logger.info(t('systemActions.systemNotAddedDuplicate'));
165
174
  return;
166
175
  }
167
176
  const shouldSave = await checkConnectionOrPrompt({
@@ -169,11 +178,12 @@ async function addSystem(params) {
169
178
  client: config.client,
170
179
  systemType: config.systemType,
171
180
  authenticationType: config.authenticationType,
181
+ connectionType: config.connectionType,
172
182
  username: config.username,
173
183
  password: config.password
174
- }, params.skipCheck || false);
184
+ }, params.skipConnectionValidation || false);
175
185
  if (!shouldSave) {
176
- logger.info('System was not saved.');
186
+ logger.info(t('systemActions.systemNotSaved'));
177
187
  return;
178
188
  }
179
189
  const system = new BackendSystem({
@@ -187,7 +197,7 @@ async function addSystem(params) {
187
197
  password: config.password
188
198
  });
189
199
  await service.write(system);
190
- logger.info(`System '${config.name}' added.`);
200
+ logger.info(t('systemActions.systemAdded', { name: config.name }));
191
201
  }
192
202
  catch (error) {
193
203
  logger.error(error.message);
@@ -2,6 +2,7 @@ import { isAppStudio } from '@sap-ux/btp-utils';
2
2
  import { getService, BackendSystemKey } from '@sap-ux/store';
3
3
  import { NullTransport, ToolsLogger } from '@sap-ux/logger';
4
4
  import { getLogger } from '../../tracing/index.js';
5
+ import { findSystemByUrl } from '../utils/system-lookup.js';
5
6
  /**
6
7
  * Add the "get system" subcommand to a passed command.
7
8
  * Retrieves details of a saved backend system identified by its URL and optional client.
@@ -45,9 +46,10 @@ async function getSystem(url, client, asJson) {
45
46
  entityName: 'system',
46
47
  logger: storeLogger
47
48
  });
48
- const key = new BackendSystemKey({ url, client });
49
- const system = await service.read(key);
49
+ // Use smart lookup to handle client mismatch scenarios
50
+ const system = await findSystemByUrl(url, client, service);
50
51
  if (!system) {
52
+ const key = new BackendSystemKey({ url, client });
51
53
  logger.error(`System not found: ${key.getId()}`);
52
54
  return;
53
55
  }
@@ -78,6 +80,9 @@ async function getSystem(url, client, asJson) {
78
80
  if (system.hasSensitiveData) {
79
81
  logger.info(`Credentials stored securely.`);
80
82
  }
83
+ else {
84
+ logger.info(`No credentials stored.`);
85
+ }
81
86
  }
82
87
  }
83
88
  catch (error) {
@@ -4,7 +4,7 @@ import { Command } from 'commander';
4
4
  *
5
5
  * @param argv - arguments, typically 'process.argv'
6
6
  */
7
- export declare function handleCreateFioriCommand(argv: string[]): void;
7
+ export declare function handleCreateFioriCommand(argv: string[]): Promise<void>;
8
8
  /**
9
9
  * Generates the full MCP specification for a top-level commander program.
10
10
  *
package/dist/cli/index.js CHANGED
@@ -4,6 +4,7 @@ import { fileURLToPath } from 'node:url';
4
4
  import { Command } from 'commander';
5
5
  const __dirname = dirname(fileURLToPath(import.meta.url));
6
6
  import { getLogger } from '../tracing/index.js';
7
+ import { initI18n } from '../i18n.js';
7
8
  import { getAddCommands } from './add/index.js';
8
9
  import { getRemoveCommands } from './remove/index.js';
9
10
  import { getGenerateCommands } from './generate/index.js';
@@ -24,12 +25,14 @@ import { getUpdateCommands } from './update/index.js';
24
25
  *
25
26
  * @param argv - arguments, typically 'process.argv'
26
27
  */
27
- export function handleCreateFioriCommand(argv) {
28
+ export async function handleCreateFioriCommand(argv) {
28
29
  const logger = getLogger();
29
30
  if (!Array.isArray(argv) || argv.length < 2) {
30
31
  throw Error(`This function must be called from command line interface (cli). Or provide meaningful arguments.`);
31
32
  }
32
33
  try {
34
+ // Initialize i18n before executing commands
35
+ await initI18n();
33
36
  const program = getCommanderProgram();
34
37
  program.parse(argv);
35
38
  }
@@ -2,6 +2,8 @@ import { isAppStudio } from '@sap-ux/btp-utils';
2
2
  import { getService, BackendSystemKey } from '@sap-ux/store';
3
3
  import { getLogger } from '../../tracing/index.js';
4
4
  import { promptForSystemIdentifier, promptForRemoveConfirmation } from '../utils/system-prompts.js';
5
+ import { findSystemByUrl } from '../utils/system-lookup.js';
6
+ import { t } from '../../i18n.js';
5
7
  /**
6
8
  * Add the "remove system" subcommand to a passed command.
7
9
  * Removes a saved backend system from the store (~/.fioritools) and deletes its credentials from the OS keychain.
@@ -39,9 +41,10 @@ async function removeSystem(url, client, force) {
39
41
  // Prompt for system identifier if not provided
40
42
  const identifier = await promptForSystemIdentifier({ url, client });
41
43
  const service = await getService({ entityName: 'system' });
42
- const key = new BackendSystemKey({ url: identifier.url, client: identifier.client });
43
- const system = await service.read(key);
44
+ // Use smart lookup to handle client mismatch scenarios
45
+ const system = await findSystemByUrl(identifier.url, identifier.client, service);
44
46
  if (!system) {
47
+ const key = new BackendSystemKey({ url: identifier.url, client: identifier.client });
45
48
  logger.error(`System not found: ${key.getId()}`);
46
49
  return;
47
50
  }
@@ -55,9 +58,10 @@ async function removeSystem(url, client, force) {
55
58
  }
56
59
  const deleted = await service.delete(system);
57
60
  if (deleted) {
58
- logger.info(`System '${system.name}' removed.`);
61
+ logger.info(t('systemActions.systemRemoved', { name: system.name }));
59
62
  }
60
63
  else {
64
+ const key = new BackendSystemKey({ url: system.url, client: system.client });
61
65
  logger.error(`Failed to remove system: ${key.getId()}`);
62
66
  }
63
67
  }
@@ -3,8 +3,10 @@ import { getService, BackendSystemKey, isSystemNameInUse } from '@sap-ux/store';
3
3
  import { replaceEnvVariables } from '@sap-ux/ui5-config';
4
4
  import { config as loadEnvConfig } from 'dotenv';
5
5
  import { getLogger } from '../../tracing/index.js';
6
- import { promptForSystemIdentifier, promptForUpdateFields, promptForFieldUpdates } from '../utils/system-prompts.js';
6
+ import { promptForSystemIdentifier, promptForUpdateFields, promptForFieldUpdates, ClearCredentialsCancelledError } from '../utils/system-prompts.js';
7
7
  import { checkConnectionOrPrompt } from '../utils/system-connection.js';
8
+ import { findSystemByUrl } from '../utils/system-lookup.js';
9
+ import { t } from '../../i18n.js';
8
10
  /**
9
11
  * Add the "update system" subcommand to a passed command.
10
12
  * Updates an existing backend system in the saved systems store (~/.fioritools).
@@ -26,7 +28,8 @@ Example:
26
28
  .option('--username <string>', 'New username')
27
29
  .option('--password <string>', "To avoid plain-text credentials in the shell's history, pass an env reference: --password env:MY_VAR")
28
30
  .option('--clear-credentials', 'Remove stored credentials from the system')
29
- .option('--skip-check', 'Skip connection verification before saving')
31
+ .option('--skip-connection-validation', 'Skip connection verification before saving')
32
+ .option('--skip-check', '(Deprecated: use --skip-connection-validation) Skip connection verification before saving')
30
33
  .action(async (options) => {
31
34
  loadEnvConfig();
32
35
  await updateSystem({
@@ -36,7 +39,7 @@ Example:
36
39
  username: options.username,
37
40
  password: options.password,
38
41
  clearCredentials: !!options.clearCredentials,
39
- skipCheck: !!options.skipCheck
42
+ skipConnectionValidation: !!options.skipConnectionValidation || !!options.skipCheck
40
43
  });
41
44
  });
42
45
  }
@@ -103,7 +106,25 @@ async function determinePatch(params, existing, logger) {
103
106
  return await buildPatchFromParams(params, existing, logger);
104
107
  }
105
108
  const fieldsToUpdate = await promptForUpdateFields(existing);
106
- return await promptForFieldUpdates(fieldsToUpdate, existing);
109
+ let updateValues;
110
+ try {
111
+ updateValues = await promptForFieldUpdates(fieldsToUpdate, existing);
112
+ }
113
+ catch (err) {
114
+ // User cancelled credential clearing operation
115
+ if (err instanceof ClearCredentialsCancelledError) {
116
+ logger.info(t('systemActions.operationCancelled'));
117
+ return null;
118
+ }
119
+ throw err;
120
+ }
121
+ // Check if clearCredentials was selected in interactive mode
122
+ if (updateValues.clearCredentials) {
123
+ updateValues.username = '';
124
+ updateValues.password = '';
125
+ delete updateValues.clearCredentials;
126
+ }
127
+ return updateValues;
107
128
  }
108
129
  /**
109
130
  * Verifies connection if credentials are being updated.
@@ -112,22 +133,35 @@ async function determinePatch(params, existing, logger) {
112
133
  * @param existing - existing system
113
134
  * @param params - update parameters
114
135
  * @param params.clearCredentials - whether credentials are being cleared
115
- * @param params.skipCheck - whether to skip connection check
136
+ * @param params.skipConnectionValidation - whether to skip connection check
116
137
  * @returns true if should proceed, false otherwise
117
138
  */
118
139
  async function verifyCredentialsUpdate(patch, existing, params) {
119
- const updatingCredentials = patch.username !== undefined || patch.password !== undefined;
120
- if (!updatingCredentials || params.clearCredentials) {
140
+ // Check if credentials are being updated (set to new values or cleared)
141
+ const hasUsernameChange = patch.username !== undefined;
142
+ const hasPasswordChange = patch.password !== undefined;
143
+ const updatingCredentials = hasUsernameChange || hasPasswordChange;
144
+ // Skip verification if:
145
+ // 1. No credential changes at all, OR
146
+ // 2. Explicitly clearing credentials (--clear-credentials flag), OR
147
+ // 3. Setting both to empty strings (clearing via interactive prompts)
148
+ if (!updatingCredentials) {
149
+ return true;
150
+ }
151
+ const clearingCredentials = params.clearCredentials || (patch.username === '' && patch.password === '');
152
+ if (clearingCredentials) {
121
153
  return true;
122
154
  }
155
+ // Otherwise, verify the new credentials work
123
156
  return await checkConnectionOrPrompt({
124
157
  url: existing.url,
125
158
  client: existing.client,
126
159
  systemType: existing.systemType,
127
160
  authenticationType: existing.authenticationType || 'basic',
161
+ connectionType: existing.connectionType,
128
162
  username: patch.username ?? existing.username,
129
163
  password: patch.password ?? existing.password
130
- }, params.skipCheck || false);
164
+ }, params.skipConnectionValidation || false);
131
165
  }
132
166
  /**
133
167
  * Updates a backend system in the saved systems store.
@@ -139,7 +173,7 @@ async function verifyCredentialsUpdate(patch, existing, params) {
139
173
  * @param params.username - optional new username
140
174
  * @param params.password - optional new password
141
175
  * @param params.clearCredentials - if true, clears stored credentials
142
- * @param params.skipCheck - skip connection verification
176
+ * @param params.skipConnectionValidation - skip connection verification
143
177
  */
144
178
  async function updateSystem(params) {
145
179
  const logger = getLogger();
@@ -153,28 +187,32 @@ async function updateSystem(params) {
153
187
  client: params.client
154
188
  });
155
189
  const service = await getService({ entityName: 'system' });
156
- const key = new BackendSystemKey({ url: identifier.url, client: identifier.client });
157
- const existing = await service.read(key);
190
+ // Use smart lookup to handle client mismatch scenarios
191
+ const existing = await findSystemByUrl(identifier.url, identifier.client, service);
158
192
  if (!existing) {
193
+ const key = new BackendSystemKey({ url: identifier.url, client: identifier.client });
159
194
  logger.error(`System not found: ${key.getId()}`);
160
195
  return;
161
196
  }
162
197
  const patchRecord = await determinePatch(params, existing, logger);
163
198
  if (!patchRecord) {
199
+ logger.info(t('systemActions.systemNotUpdated'));
164
200
  return;
165
201
  }
166
202
  replaceEnvVariables(patchRecord);
167
203
  if (!Object.keys(patchRecord).length) {
168
204
  logger.error('No fields to update. Provide at least one of: --name, --username, --password, --clear-credentials');
205
+ logger.info(t('systemActions.systemNotUpdated'));
169
206
  return;
170
207
  }
171
208
  const patch = patchRecord;
172
209
  if (!(await verifyCredentialsUpdate(patch, existing, params))) {
173
- logger.info('System was not updated.');
210
+ logger.info(t('systemActions.systemNotUpdated'));
174
211
  return;
175
212
  }
213
+ const key = new BackendSystemKey({ url: existing.url, client: existing.client });
176
214
  await service.partialUpdate(key, patch);
177
- logger.info(`System '${key.getId()}' updated.`);
215
+ logger.info(t('systemActions.systemUpdated', { name: existing.name }));
178
216
  }
179
217
  catch (error) {
180
218
  logger.error(error.message);
@@ -1,20 +1,24 @@
1
+ import type { SystemType } from '@sap-ux/store';
2
+ import { AuthenticationType, ConnectionType } from '@sap-ux/store';
1
3
  /**
2
- * Checks connection to a backend system.
4
+ * Checks connection to a backend system by validating based on the connection type.
3
5
  *
4
6
  * @param config - System configuration to test
5
- * @param config.url
6
- * @param config.client
7
- * @param config.systemType
8
- * @param config.authenticationType
9
- * @param config.username
10
- * @param config.password
7
+ * @param config.url - System URL
8
+ * @param config.client - SAP client (optional)
9
+ * @param config.systemType - System type (OnPrem, AbapCloud, etc.)
10
+ * @param config.authenticationType - Authentication type
11
+ * @param config.connectionType - Connection type (determines validation method)
12
+ * @param config.username - Username for basic auth (optional)
13
+ * @param config.password - Password for basic auth (optional)
11
14
  * @returns Connection check result with success status and optional error message
12
15
  */
13
16
  export declare function checkSystemConnection(config: {
14
17
  url: string;
15
18
  client?: string;
16
- systemType: string;
17
- authenticationType: string;
19
+ systemType: SystemType;
20
+ authenticationType: AuthenticationType;
21
+ connectionType: ConnectionType;
18
22
  username?: string;
19
23
  password?: string;
20
24
  }): Promise<{
@@ -23,24 +27,26 @@ export declare function checkSystemConnection(config: {
23
27
  }>;
24
28
  /**
25
29
  * Checks connection to a backend system, or prompts user whether to save anyway if check fails.
26
- * If skipCheck is true, always returns true without checking.
30
+ * If skipConnectionValidation is true, always returns true without checking.
27
31
  *
28
32
  * @param config - System configuration to test
29
- * @param config.url
30
- * @param config.client
31
- * @param config.systemType
32
- * @param config.authenticationType
33
- * @param config.username
34
- * @param config.password
35
- * @param skipCheck - If true, skip the connection check
33
+ * @param config.url - System URL
34
+ * @param config.client - SAP client (optional)
35
+ * @param config.systemType - System type (OnPrem, AbapCloud, etc.)
36
+ * @param config.authenticationType - Authentication type
37
+ * @param config.connectionType - Connection type (determines validation method)
38
+ * @param config.username - Username for basic auth (optional)
39
+ * @param config.password - Password for basic auth (optional)
40
+ * @param skipConnectionValidation - If true, skip the connection check
36
41
  * @returns True if connection succeeded or user chose to save anyway, false if user chose not to save
37
42
  */
38
43
  export declare function checkConnectionOrPrompt(config: {
39
44
  url: string;
40
45
  client?: string;
41
- systemType: string;
42
- authenticationType: string;
46
+ systemType: SystemType;
47
+ authenticationType: AuthenticationType;
48
+ connectionType: ConnectionType;
43
49
  username?: string;
44
50
  password?: string;
45
- }, skipCheck: boolean): Promise<boolean>;
51
+ }, skipConnectionValidation: boolean): Promise<boolean>;
46
52
  //# sourceMappingURL=system-connection.d.ts.map
@@ -1,15 +1,21 @@
1
1
  import prompts from 'prompts';
2
+ import { createAbapServiceProvider } from '@sap-ux/system-access';
3
+ import { ErrorHandler } from '@sap-ux/inquirer-common';
4
+ import { AuthenticationType, ConnectionType } from '@sap-ux/store';
5
+ import { ODataVersion } from '@sap-ux/axios-extension';
2
6
  import { getLogger } from '../../tracing/index.js';
7
+ import { t } from '../../i18n.js';
3
8
  /**
4
- * Checks connection to a backend system.
9
+ * Checks connection to a backend system by validating based on the connection type.
5
10
  *
6
11
  * @param config - System configuration to test
7
- * @param config.url
8
- * @param config.client
9
- * @param config.systemType
10
- * @param config.authenticationType
11
- * @param config.username
12
- * @param config.password
12
+ * @param config.url - System URL
13
+ * @param config.client - SAP client (optional)
14
+ * @param config.systemType - System type (OnPrem, AbapCloud, etc.)
15
+ * @param config.authenticationType - Authentication type
16
+ * @param config.connectionType - Connection type (determines validation method)
17
+ * @param config.username - Username for basic auth (optional)
18
+ * @param config.password - Password for basic auth (optional)
13
19
  * @returns Connection check result with success status and optional error message
14
20
  */
15
21
  export async function checkSystemConnection(config) {
@@ -18,44 +24,102 @@ export async function checkSystemConnection(config) {
18
24
  new URL(config.url);
19
25
  }
20
26
  catch {
21
- return { success: false, error: `Invalid URL: ${config.url}` };
27
+ return { success: false, error: t('systemConnection.invalidUrl', { url: config.url }) };
28
+ }
29
+ // Attempt actual connection check
30
+ try {
31
+ const logger = getLogger();
32
+ // Build target configuration for system-access
33
+ const target = {
34
+ url: config.url,
35
+ client: config.client,
36
+ authenticationType: config.authenticationType
37
+ };
38
+ // Build request options with auth if provided
39
+ // For basic auth with credentials, include them
40
+ // For reentranceTicket/oauth2, omit auth (will get 401 but proves reachability)
41
+ const requestOptions = config.authenticationType === AuthenticationType.Basic && config.username && config.password
42
+ ? {
43
+ auth: {
44
+ username: config.username,
45
+ password: config.password
46
+ }
47
+ }
48
+ : undefined;
49
+ // Create service provider using system-access utilities
50
+ // prompt=false because we're in non-interactive connection check mode
51
+ const service = await createAbapServiceProvider(target, requestOptions, false, logger);
52
+ // Validate based on connection type
53
+ if (config.connectionType === ConnectionType.AbapCatalog) {
54
+ // For ABAP catalog connections, request catalog services
55
+ const catalog = service.catalog(ODataVersion.v2);
56
+ const services = await catalog.listServices();
57
+ logger.info(t('systemConnection.catalogServicesFound', { count: services.length }));
58
+ return { success: true };
59
+ }
60
+ else if (config.connectionType === ConnectionType.ODataService) {
61
+ // For OData service URLs, attempt metadata request
62
+ const response = await service.get('/$metadata', { timeout: 5000 });
63
+ if (response.status === 200) {
64
+ logger.info(t('systemConnection.metadataRequestSuccessful'));
65
+ return { success: true };
66
+ }
67
+ return { success: false, error: t('systemConnection.unexpectedStatus', { status: response.status }) };
68
+ }
69
+ else if (config.connectionType === ConnectionType.GenericHost) {
70
+ // For generic host, basic connectivity check
71
+ await service.get('/', { timeout: 5000 });
72
+ return { success: true };
73
+ }
74
+ return { success: true };
75
+ }
76
+ catch (error) {
77
+ // 401 means system is reachable but requires auth - treat as success
78
+ if (error.response?.status === 401) {
79
+ return { success: true };
80
+ }
81
+ // Use ErrorHandler for comprehensive error analysis
82
+ const errorHandler = new ErrorHandler(getLogger(), false);
83
+ const errorMsg = errorHandler.logErrorMsgs(error, undefined, false);
84
+ // For other errors, provide detailed message
85
+ return {
86
+ success: false,
87
+ error: errorMsg || t('systemConnection.unknownError')
88
+ };
22
89
  }
23
- // For now, we just validate the URL format
24
- // A real implementation would attempt to connect to the backend
25
- // using the provided credentials and check if the system is reachable
26
- return { success: true };
27
90
  }
28
91
  /**
29
92
  * Checks connection to a backend system, or prompts user whether to save anyway if check fails.
30
- * If skipCheck is true, always returns true without checking.
93
+ * If skipConnectionValidation is true, always returns true without checking.
31
94
  *
32
95
  * @param config - System configuration to test
33
- * @param config.url
34
- * @param config.client
35
- * @param config.systemType
36
- * @param config.authenticationType
37
- * @param config.username
38
- * @param config.password
39
- * @param skipCheck - If true, skip the connection check
96
+ * @param config.url - System URL
97
+ * @param config.client - SAP client (optional)
98
+ * @param config.systemType - System type (OnPrem, AbapCloud, etc.)
99
+ * @param config.authenticationType - Authentication type
100
+ * @param config.connectionType - Connection type (determines validation method)
101
+ * @param config.username - Username for basic auth (optional)
102
+ * @param config.password - Password for basic auth (optional)
103
+ * @param skipConnectionValidation - If true, skip the connection check
40
104
  * @returns True if connection succeeded or user chose to save anyway, false if user chose not to save
41
105
  */
42
- export async function checkConnectionOrPrompt(config, skipCheck) {
106
+ export async function checkConnectionOrPrompt(config, skipConnectionValidation) {
43
107
  const logger = getLogger();
44
- if (skipCheck) {
45
- logger.info('Skipping connection check (--skip-check flag provided)');
108
+ if (skipConnectionValidation) {
109
+ logger.info(t('systemConnection.skippingCheck'));
46
110
  return true;
47
111
  }
48
- logger.info('Verifying connection to backend system...');
112
+ logger.info(t('systemConnection.verifying'));
49
113
  const result = await checkSystemConnection(config);
50
114
  if (result.success) {
51
- logger.info('✓ Connection successful');
115
+ logger.info(t('systemConnection.connectionSuccessful'));
52
116
  return true;
53
117
  }
54
- logger.warn(`Connection check failed: ${result.error || 'Unknown error'}`);
118
+ logger.warn(t('systemConnection.connectionFailed', { error: result.error ?? t('systemConnection.unknownError') }));
55
119
  const answer = await prompts({
56
120
  type: 'confirm',
57
121
  name: 'saveAnyway',
58
- message: 'Connection check failed. Save system anyway?',
122
+ message: t('systemConnection.saveAnywayPrompt'),
59
123
  initial: false
60
124
  });
61
125
  return answer.saveAnyway === true;
@@ -0,0 +1,17 @@
1
+ import type { BackendSystem, BackendSystemKey, Service } from '@sap-ux/store';
2
+ /**
3
+ * Finds a backend system by URL with smart matching when client is not specified or doesn't match.
4
+ *
5
+ * Logic:
6
+ * 1. Find all systems with the same URL (across all connection types).
7
+ * 2. If exactly one system found, use it automatically.
8
+ * 3. If multiple systems found, try exact match first, then prompt user to select if no exact match.
9
+ * 4. If none found, return undefined.
10
+ *
11
+ * @param url - URL of the backend system
12
+ * @param client - optional SAP client
13
+ * @param service - backend system service
14
+ * @returns the matched system, or undefined if not found or user cancelled
15
+ */
16
+ export declare function findSystemByUrl(url: string, client: string | undefined, service: Service<BackendSystem, BackendSystemKey>): Promise<BackendSystem | undefined>;
17
+ //# sourceMappingURL=system-lookup.d.ts.map