@sap-ux/inquirer-common 0.4.9 → 0.5.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.
@@ -0,0 +1,239 @@
1
+ import { type Destination } from '@sap-ux/btp-utils';
2
+ import { type HostEnvironmentId } from '@sap-ux/fiori-generator-shared/src/types';
3
+ import { type Logger } from '@sap-ux/logger';
4
+ import { ValidationLink } from '../types';
5
+ /**
6
+ * Constants specific to error handling
7
+ */
8
+ export declare enum ERROR_TYPE {
9
+ AUTH = "AUTH",
10
+ AUTH_TIMEOUT = "AUTH_TIMEOUT",
11
+ REDIRECT = "REDIRECT",
12
+ CERT = "CERT",// General cert error
13
+ CERT_SELF_SIGNED = "CERT_SELF_SIGNED",
14
+ CERT_UKNOWN_OR_INVALID = "CERT_UKNOWN_OR_INVALID",
15
+ CERT_EXPIRED = "CERT_EXPIRED",
16
+ CERT_SELF_SIGNED_CERT_IN_CHAIN = "CERT_SELF_SIGNED_CERT_IN_CHAIN",
17
+ UNKNOWN = "UNKNOWN",
18
+ INVALID_URL = "INVALID_URL",
19
+ TIMEOUT = "TIMEOUT",
20
+ CONNECTION = "CONNECTION",
21
+ SERVICES_UNAVAILABLE = "SERVICES_UNAVAILABLE",// All services
22
+ SERVICE_UNAVAILABLE = "SERVICE_UNAVAILABLE",// HTTP 503 Not related to odata services
23
+ NO_ABAP_ENVS = "NO_ABAP_ENVS",
24
+ CATALOG_SERVICE_NOT_ACTIVE = "CATALOG_SERVICE_NOT_ACTIVE",
25
+ NO_SUCH_HOST = "NO_SUCH_HOST",
26
+ NOT_FOUND = "NOT_FOUND",
27
+ ODATA_URL_NOT_FOUND = "ODATA_URL_NOT_FOUND",
28
+ BAD_GATEWAY = "BAD_GATEWAY",// Can be caused by either local issue or endpoint configuration
29
+ INTERNAL_SERVER_ERROR = "INTERNAL_SERVER_ERROR",
30
+ DESTINATION_BAD_GATEWAY_503 = "DESTINATION_BAD_GATEWAY_503",// Caused by endpoint using a firewall or proxy
31
+ DESTINATION_UNAVAILABLE = "DESTINATION_UNAVAILABLE",
32
+ DESTINATION_NOT_FOUND = "DESTINATION_NOT_FOUND",
33
+ DESTINATION_MISCONFIGURED = "DESTINATION_MISCONFIGURED",
34
+ NO_V2_SERVICES = "NO_V2_SERVICES",
35
+ NO_V4_SERVICES = "NO_V4_SERVICES",
36
+ BAD_REQUEST = "BAD_REQUEST",
37
+ DESTINATION_CONNECTION_ERROR = "DESTINATION_CONNECTION_ERROR",// General destination connection error where a specific root cause cannot be determined e.g. In the case of an internal server error
38
+ SERVER_HTTP_ERROR = "SERVER_HTTP_ERROR"
39
+ }
40
+ export declare const ERROR_MAP: Record<ERROR_TYPE, RegExp[]>;
41
+ type ValidationLinkOrString = string | ValidationLink;
42
+ /**
43
+ * Maps errors to end-user messages using some basic root cause analysis based on regex matching.
44
+ * This class will also log errors and provide help links for validation errors in some limited use cases.
45
+ */
46
+ export declare class ErrorHandler {
47
+ /** The last error message generated */
48
+ private currentErrorMsg;
49
+ /** The last error message type generated if determined */
50
+ private currentErrorType;
51
+ private static _guidedAnswersEnabled;
52
+ private static _logger;
53
+ /**
54
+ * The current platform string to be reported in telemetry events. If not provided it will be determined from the environment.
55
+ */
56
+ private static _platform;
57
+ /**
58
+ * Get the current platform string that would be used by the error handler.
59
+ *
60
+ * @returns the platform string as defined by `HostEnvironmentId` or the value set by the user
61
+ */
62
+ static get platform(): HostEnvironmentId | undefined;
63
+ /**
64
+ * Set platform string usually defined by `HostEnvironmentId`
65
+ *
66
+ * @param value the platform string to set
67
+ */
68
+ static set platform(value: HostEnvironmentId | undefined);
69
+ /**
70
+ * The Guided Answers (help) trigger property sent with some telemetry events.
71
+ */
72
+ private static _guidedAnswersTrigger;
73
+ /**
74
+ * Get the Guided Answers (help) trigger property.
75
+ *
76
+ * @returns the Guided Answers trigger property
77
+ */
78
+ static get guidedAnswersTrigger(): string | undefined;
79
+ /**
80
+ * Set the Guided Answers (help) trigger property.
81
+ *
82
+ * @param value the Guided Answers trigger property
83
+ */
84
+ static set guidedAnswersTrigger(value: string | undefined);
85
+ private static readonly getMessageFromError;
86
+ private static readonly _errorTypeToMsg;
87
+ /**
88
+ *
89
+ * @param errorType
90
+ * @param error can be any object that will get stringified and passed to the specific error message for the error type entry, e.g. where the error message is parameterized
91
+ * @returns an error message for the specified error type
92
+ */
93
+ private static readonly _errorMsg;
94
+ /**
95
+ * Get the Guided Answers (help) node for the specified error type.
96
+ *
97
+ * @param errorType The error type for which a help node (help content id) may be returned
98
+ * @returns The Guided Answers node for the specified error type
99
+ */
100
+ private static readonly getHelpNode;
101
+ /**
102
+ * Find an error property for mapping to a general error type from most to least significant.
103
+ *
104
+ * @param error any type of error or object that has an error code, status, name or message
105
+ * @returns a value that can be used to look up a general error type
106
+ */
107
+ private static readonly findErrorValueForMapping;
108
+ /**
109
+ * Create an instance of the ErrorHandler.
110
+ *
111
+ * @param logger the logger instance to use
112
+ * @param enableGuidedAnswers if true, the end user validation errors will include guided answers to provide help
113
+ */
114
+ constructor(logger?: Logger, enableGuidedAnswers?: boolean);
115
+ /**
116
+ * Get Guided Answers (context help) enabled value.
117
+ *
118
+ * @returns true if Guided Answers is enabled
119
+ */
120
+ static get guidedAnswersEnabled(): boolean;
121
+ /**
122
+ * Toggle Guided Answers (context help) for validation errors.
123
+ */
124
+ static set guidedAnswersEnabled(value: boolean);
125
+ /**
126
+ * Set the logger to be used for error messages.
127
+ *
128
+ * @param logger the logger instance to use
129
+ */
130
+ static set logger(logger: Logger);
131
+ /**
132
+ * Get the logger used for error messages.
133
+ *
134
+ * @returns the logger instance
135
+ */
136
+ static get logger(): Logger;
137
+ /**
138
+ * Tests if the error is a general certificate error.
139
+ *
140
+ * @param status the error type
141
+ * @returns true if the error is a general certificate error
142
+ */
143
+ static isCertError(status: string | number): boolean;
144
+ /**
145
+ * Get the error type for the specified error, mapping status code, error code, error name, error message to a few general error types.
146
+ *
147
+ * @param error the error, string or status code to get the type for
148
+ * @returns the error type
149
+ */
150
+ static getErrorType(error: string | number | Error): ERROR_TYPE;
151
+ /**
152
+ * Maps errors to a few generic types, log a detailed error.
153
+ *
154
+ * @param error If the error is a string this will be logged as is. Otherwise it will be mapped to a general error internally, possibly retained and logged.
155
+ * @param userMsg If provided this will be set as the userErrorMsg instead of an error to msg map
156
+ * this allows a message more relevant to the context of where the error was generated to be used.
157
+ * @param retainError Defaults to true to retain the error state.
158
+ * @returns A user-friendly message for display in-line
159
+ */
160
+ logErrorMsgs(error: unknown, userMsg?: string, retainError?: boolean): string;
161
+ /**
162
+ * Maps an error to a user-friendly message. The specified error may by a string (e.g. error message), number (e.g. status code), Error, or Axios error.
163
+ *
164
+ * @param error The error to map
165
+ * @returns The mapped error message and error type
166
+ */
167
+ private static mapErrorToMsg;
168
+ /**
169
+ * Used by validate functions to report in-line user friendly errors.
170
+ * Checks if there is an existing error.
171
+ *
172
+ * @param error optional, if provided get the end user message that it maps to, otherwise get the previous error message, if a boolean is passed it will be interpreted as `reset`.
173
+ * @param reset optional, resets the previous error state if true, if error is omitted reset may be passed as the first argument
174
+ * @param fallback optional, return the message of the specified ERROR_TYPE if no previous end user message and no error specified
175
+ * @returns The error message
176
+ */
177
+ getErrorMsg(error?: any, reset?: boolean, fallback?: ERROR_TYPE): string | undefined;
178
+ /**
179
+ * Used by validate functions to report in-line user friendly errors messages with help links.
180
+ * If the error type is unknown, this will find a mapped error type and return the help (ValidationLink) if it exists.
181
+ * If an error is not provided the current error state will be used. This does not log the message to the console.
182
+ * If a system is provided, the error type may be refined to provide a more specific error message for the system which generatd the error.
183
+ *
184
+ * @param error optional, if provided get the help link message that it maps to, otherwise get the previously logged error message help link
185
+ * @param reset optional, resets the previous error state if true
186
+ * @param destination optional, if provided the destination may be used to determine a more relevant error message, specific to the system properties
187
+ * @returns An instance of @see {ValidationLink}
188
+ */
189
+ getValidationErrorHelp(error?: any, reset?: boolean, destination?: Destination): ValidationLinkOrString | undefined;
190
+ /**
191
+ * Get a more specific error type for the specified destination.
192
+ *
193
+ * @param errorType
194
+ * @param destination
195
+ * @returns
196
+ */
197
+ private static getDestinationSpecificError;
198
+ /**
199
+ * Get the error message for the specified error type.
200
+ *
201
+ * @param errorType The error type for which the message may be returned
202
+ * @param error optional, if provided may be used to get generate a more specific error message, or be included in the message
203
+ * @returns The error message for the specified error type
204
+ */
205
+ static getErrorMsgFromType(errorType: ERROR_TYPE, error?: any): string | undefined;
206
+ /**
207
+ * Checks if there is an existing error.
208
+ *
209
+ * @param reset - resets the current error state
210
+ * @returns true if there is an existing error
211
+ */
212
+ hasError(reset?: boolean): boolean;
213
+ /**
214
+ * Sets the current error state.
215
+ *
216
+ * @param errorType - the error type
217
+ * @param error - the original error, if any
218
+ */
219
+ setCurrentError(errorType: ERROR_TYPE, error?: any): void;
220
+ /**
221
+ * Gets the current error type state.
222
+ *
223
+ * @param reset - resets the current error state
224
+ * @returns The current error type
225
+ */
226
+ getCurrentErrorType(reset?: boolean): ERROR_TYPE | null;
227
+ /**
228
+ * Maps an error type to a validation link if help (Guided Answers topic) is available for the specified error.
229
+ * Otherwise the specified error message is returned. To retrieve the previous error state @see getValidationErrorHelp.
230
+ * Use this (getHelpForError) if the error type is known.
231
+ *
232
+ * @param errorType - the error type to be mapped to help link
233
+ * @param errorMsg - the message to appear with the help link
234
+ * @returns A validation help link or help link message
235
+ */
236
+ static getHelpForError(errorType: ERROR_TYPE, errorMsg?: string): ValidationLinkOrString | undefined;
237
+ }
238
+ export {};
239
+ //# sourceMappingURL=error-handler.d.ts.map
@@ -0,0 +1,610 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ErrorHandler = exports.ERROR_MAP = exports.ERROR_TYPE = void 0;
4
+ const btp_utils_1 = require("@sap-ux/btp-utils");
5
+ const fiori_generator_shared_1 = require("@sap-ux/fiori-generator-shared");
6
+ const guided_answers_helper_1 = require("@sap-ux/guided-answers-helper");
7
+ const logger_1 = require("@sap-ux/logger");
8
+ const i18n_1 = require("../i18n");
9
+ const telemetry_1 = require("../telemetry/telemetry");
10
+ const types_1 = require("../types");
11
+ // Telemetry event names specific to odata service error handling
12
+ const telemEventGALinkCreated = 'GA_LINK_CREATED';
13
+ const telemBasError = 'SERVICE_INQUIRER_BAS_ERROR';
14
+ /**
15
+ * Constants specific to error handling
16
+ */
17
+ var ERROR_TYPE;
18
+ (function (ERROR_TYPE) {
19
+ ERROR_TYPE["AUTH"] = "AUTH";
20
+ ERROR_TYPE["AUTH_TIMEOUT"] = "AUTH_TIMEOUT";
21
+ ERROR_TYPE["REDIRECT"] = "REDIRECT";
22
+ ERROR_TYPE["CERT"] = "CERT";
23
+ ERROR_TYPE["CERT_SELF_SIGNED"] = "CERT_SELF_SIGNED";
24
+ ERROR_TYPE["CERT_UKNOWN_OR_INVALID"] = "CERT_UKNOWN_OR_INVALID";
25
+ ERROR_TYPE["CERT_EXPIRED"] = "CERT_EXPIRED";
26
+ ERROR_TYPE["CERT_SELF_SIGNED_CERT_IN_CHAIN"] = "CERT_SELF_SIGNED_CERT_IN_CHAIN";
27
+ ERROR_TYPE["UNKNOWN"] = "UNKNOWN";
28
+ ERROR_TYPE["INVALID_URL"] = "INVALID_URL";
29
+ ERROR_TYPE["TIMEOUT"] = "TIMEOUT";
30
+ ERROR_TYPE["CONNECTION"] = "CONNECTION";
31
+ ERROR_TYPE["SERVICES_UNAVAILABLE"] = "SERVICES_UNAVAILABLE";
32
+ ERROR_TYPE["SERVICE_UNAVAILABLE"] = "SERVICE_UNAVAILABLE";
33
+ ERROR_TYPE["NO_ABAP_ENVS"] = "NO_ABAP_ENVS";
34
+ ERROR_TYPE["CATALOG_SERVICE_NOT_ACTIVE"] = "CATALOG_SERVICE_NOT_ACTIVE";
35
+ ERROR_TYPE["NO_SUCH_HOST"] = "NO_SUCH_HOST";
36
+ ERROR_TYPE["NOT_FOUND"] = "NOT_FOUND";
37
+ ERROR_TYPE["ODATA_URL_NOT_FOUND"] = "ODATA_URL_NOT_FOUND";
38
+ ERROR_TYPE["BAD_GATEWAY"] = "BAD_GATEWAY";
39
+ ERROR_TYPE["INTERNAL_SERVER_ERROR"] = "INTERNAL_SERVER_ERROR";
40
+ ERROR_TYPE["DESTINATION_BAD_GATEWAY_503"] = "DESTINATION_BAD_GATEWAY_503";
41
+ ERROR_TYPE["DESTINATION_UNAVAILABLE"] = "DESTINATION_UNAVAILABLE";
42
+ ERROR_TYPE["DESTINATION_NOT_FOUND"] = "DESTINATION_NOT_FOUND";
43
+ ERROR_TYPE["DESTINATION_MISCONFIGURED"] = "DESTINATION_MISCONFIGURED";
44
+ ERROR_TYPE["NO_V2_SERVICES"] = "NO_V2_SERVICES";
45
+ ERROR_TYPE["NO_V4_SERVICES"] = "NO_V4_SERVICES";
46
+ ERROR_TYPE["BAD_REQUEST"] = "BAD_REQUEST";
47
+ ERROR_TYPE["DESTINATION_CONNECTION_ERROR"] = "DESTINATION_CONNECTION_ERROR";
48
+ ERROR_TYPE["SERVER_HTTP_ERROR"] = "SERVER_HTTP_ERROR";
49
+ })(ERROR_TYPE || (exports.ERROR_TYPE = ERROR_TYPE = {}));
50
+ // Used to match regex expressions to error messages, etc. providing a way to return a consistent
51
+ // single error and error msg for multiple errors
52
+ exports.ERROR_MAP = {
53
+ [ERROR_TYPE.AUTH]: [
54
+ /401/,
55
+ /403/,
56
+ /Incorrect credentials were provided to login/, // API Hub error msg
57
+ /Unable to retrieve SAP Business Accelerator Hub key/ // API Hub error msg
58
+ ],
59
+ [ERROR_TYPE.AUTH_TIMEOUT]: [/UAATimeoutError/],
60
+ [ERROR_TYPE.TIMEOUT]: [/Timeout/],
61
+ [ERROR_TYPE.CERT]: [], // General cert error, unspecified root cause
62
+ [ERROR_TYPE.CERT_UKNOWN_OR_INVALID]: [
63
+ /UNABLE_TO_GET_ISSUER_CERT/,
64
+ /UNABLE_TO_GET_ISSUER_CERT_LOCALLY/,
65
+ /unable to get local issuer certificate/
66
+ ],
67
+ [ERROR_TYPE.CERT_EXPIRED]: [/CERT_HAS_EXPIRED/],
68
+ [ERROR_TYPE.CERT_SELF_SIGNED]: [/DEPTH_ZERO_SELF_SIGNED_CERT/],
69
+ [ERROR_TYPE.CERT_SELF_SIGNED_CERT_IN_CHAIN]: [/SELF_SIGNED_CERT_IN_CHAIN/],
70
+ [ERROR_TYPE.UNKNOWN]: [],
71
+ [ERROR_TYPE.CONNECTION]: [/ENOTFOUND/, /ECONNRESET/, /ECONNREFUSED/, /ConnectionError/],
72
+ [ERROR_TYPE.SERVICES_UNAVAILABLE]: [],
73
+ [ERROR_TYPE.SERVICE_UNAVAILABLE]: [/503/],
74
+ [ERROR_TYPE.INVALID_URL]: [/Invalid URL/, /ERR_INVALID_URL/],
75
+ [ERROR_TYPE.REDIRECT]: [/3\d\d/],
76
+ [ERROR_TYPE.NO_ABAP_ENVS]: [],
77
+ [ERROR_TYPE.CATALOG_SERVICE_NOT_ACTIVE]: [
78
+ /\/IWBEP\/CM_V4_COS\/014/,
79
+ /\/IWFND\/CM_V4_COS\/021/,
80
+ /Service group '\/IWFND\/CONFIG' not published/
81
+ ],
82
+ [ERROR_TYPE.NO_SUCH_HOST]: [/no such host/],
83
+ [ERROR_TYPE.NOT_FOUND]: [/404/],
84
+ [ERROR_TYPE.ODATA_URL_NOT_FOUND]: [],
85
+ [ERROR_TYPE.INTERNAL_SERVER_ERROR]: [/500/],
86
+ [ERROR_TYPE.BAD_GATEWAY]: [/502/],
87
+ [ERROR_TYPE.DESTINATION_BAD_GATEWAY_503]: [],
88
+ [ERROR_TYPE.DESTINATION_UNAVAILABLE]: [],
89
+ [ERROR_TYPE.DESTINATION_NOT_FOUND]: [],
90
+ [ERROR_TYPE.DESTINATION_MISCONFIGURED]: [],
91
+ [ERROR_TYPE.NO_V2_SERVICES]: [],
92
+ [ERROR_TYPE.NO_V4_SERVICES]: [],
93
+ [ERROR_TYPE.BAD_REQUEST]: [/400/],
94
+ [ERROR_TYPE.DESTINATION_CONNECTION_ERROR]: [],
95
+ [ERROR_TYPE.SERVER_HTTP_ERROR]: [/5\d\d/] // catch all for 5xx server errors
96
+ };
97
+ /**
98
+ * Maps errors to end-user messages using some basic root cause analysis based on regex matching.
99
+ * This class will also log errors and provide help links for validation errors in some limited use cases.
100
+ */
101
+ class ErrorHandler {
102
+ /** The last error message generated */
103
+ currentErrorMsg;
104
+ /** The last error message type generated if determined */
105
+ currentErrorType;
106
+ static _guidedAnswersEnabled;
107
+ static _logger;
108
+ /**
109
+ * The current platform string to be reported in telemetry events. If not provided it will be determined from the environment.
110
+ */
111
+ static _platform;
112
+ /**
113
+ * Get the current platform string that would be used by the error handler.
114
+ *
115
+ * @returns the platform string as defined by `HostEnvironmentId` or the value set by the user
116
+ */
117
+ static get platform() {
118
+ return ErrorHandler._platform;
119
+ }
120
+ /**
121
+ * Set platform string usually defined by `HostEnvironmentId`
122
+ *
123
+ * @param value the platform string to set
124
+ */
125
+ static set platform(value) {
126
+ ErrorHandler._platform = value;
127
+ }
128
+ /**
129
+ * The Guided Answers (help) trigger property sent with some telemetry events.
130
+ */
131
+ static _guidedAnswersTrigger;
132
+ /**
133
+ * Get the Guided Answers (help) trigger property.
134
+ *
135
+ * @returns the Guided Answers trigger property
136
+ */
137
+ static get guidedAnswersTrigger() {
138
+ return ErrorHandler._guidedAnswersTrigger;
139
+ }
140
+ /**
141
+ * Set the Guided Answers (help) trigger property.
142
+ *
143
+ * @param value the Guided Answers trigger property
144
+ */
145
+ static set guidedAnswersTrigger(value) {
146
+ ErrorHandler._guidedAnswersTrigger = value;
147
+ }
148
+ static getMessageFromError = (error) => {
149
+ return (error?.message ||
150
+ error?.status?.toString() ||
151
+ error?.response?.status?.toString() ||
152
+ (typeof error === 'string' ? error : JSON.stringify(error)));
153
+ };
154
+ // Get the localized parameterized error message for the specified error type
155
+ static _errorTypeToMsg = {
156
+ [ERROR_TYPE.CERT]: (error) => (0, i18n_1.t)('errors.certificateError', { errorMsg: ErrorHandler.getMessageFromError(error) }),
157
+ [ERROR_TYPE.CERT_EXPIRED]: () => (0, i18n_1.t)('errors.urlCertValidationError', { certErrorReason: (0, i18n_1.t)('texts.anExpiredCert') }),
158
+ [ERROR_TYPE.CERT_SELF_SIGNED]: () => (0, i18n_1.t)('errors.urlCertValidationError', {
159
+ certErrorReason: (0, i18n_1.t)('texts.aSelfSignedCert')
160
+ }),
161
+ [ERROR_TYPE.CERT_UKNOWN_OR_INVALID]: () => (0, i18n_1.t)('errors.urlCertValidationError', {
162
+ certErrorReason: (0, i18n_1.t)('texts.anUnknownOrInvalidCert')
163
+ }),
164
+ [ERROR_TYPE.CERT_SELF_SIGNED_CERT_IN_CHAIN]: () => (0, i18n_1.t)('errors.urlCertValidationError', {
165
+ certErrorReason: (0, i18n_1.t)('texts.anUntrustedRootCert')
166
+ }),
167
+ [ERROR_TYPE.AUTH]: (error) => (0, i18n_1.t)('errors.authenticationFailed', {
168
+ error: ErrorHandler.getMessageFromError(error)
169
+ }),
170
+ [ERROR_TYPE.AUTH_TIMEOUT]: () => (0, i18n_1.t)('errors.authenticationTimeout'),
171
+ [ERROR_TYPE.TIMEOUT]: (error) => (0, i18n_1.t)('errors.timeout', { errorMsg: ErrorHandler.getMessageFromError(error) }),
172
+ [ERROR_TYPE.INVALID_URL]: () => (0, i18n_1.t)('errors.invalidUrl'),
173
+ [ERROR_TYPE.CONNECTION]: (error) => (0, i18n_1.t)('errors.connectionError', {
174
+ error: ErrorHandler.getMessageFromError(error)
175
+ }),
176
+ [ERROR_TYPE.UNKNOWN]: (error) => (0, i18n_1.t)('errors.unknownError', {
177
+ error: ErrorHandler.getMessageFromError(error)
178
+ }),
179
+ [ERROR_TYPE.SERVICES_UNAVAILABLE]: () => (0, i18n_1.t)('errors.servicesUnavailable'),
180
+ [ERROR_TYPE.SERVICE_UNAVAILABLE]: (error) => (0, i18n_1.t)('errors.serverReturnedAnError', {
181
+ errorMsg: ErrorHandler.getMessageFromError(error)
182
+ }),
183
+ [ERROR_TYPE.CATALOG_SERVICE_NOT_ACTIVE]: () => (0, i18n_1.t)('errors.catalogServiceNotActive'),
184
+ [ERROR_TYPE.INTERNAL_SERVER_ERROR]: (error) => {
185
+ const errorMsg = ErrorHandler.getMessageFromError(error);
186
+ return (0, i18n_1.t)('errors.serverReturnedAnError', {
187
+ errorDesc: (0, i18n_1.t)('errors.internalServerError', { errorMsg })
188
+ });
189
+ },
190
+ [ERROR_TYPE.NOT_FOUND]: () => (0, i18n_1.t)('errors.urlNotFound'),
191
+ [ERROR_TYPE.ODATA_URL_NOT_FOUND]: () => (0, i18n_1.t)('errors.odataServiceUrlNotFound'),
192
+ [ERROR_TYPE.BAD_GATEWAY]: (error) => {
193
+ const errorMsg = ErrorHandler.getMessageFromError(error);
194
+ return (0, i18n_1.t)('errors.serverReturnedAnError', {
195
+ errorDesc: (0, i18n_1.t)('errors.badGateway', { errorMsg })
196
+ });
197
+ },
198
+ [ERROR_TYPE.DESTINATION_UNAVAILABLE]: () => (0, i18n_1.t)('errors.destination.unavailable'),
199
+ [ERROR_TYPE.DESTINATION_NOT_FOUND]: () => (0, i18n_1.t)('errors.destination.notFound'),
200
+ [ERROR_TYPE.DESTINATION_MISCONFIGURED]: (error) => (0, i18n_1.t)('errors.destination.misconfigured', {
201
+ destinationProperty: typeof error === 'string' ? error : ''
202
+ }),
203
+ [ERROR_TYPE.NO_V2_SERVICES]: () => (0, i18n_1.t)('errors.noServicesAvailable', { version: '2' }),
204
+ [ERROR_TYPE.NO_V4_SERVICES]: () => (0, i18n_1.t)('errors.noServicesAvailable', { version: '4' }),
205
+ [ERROR_TYPE.DESTINATION_BAD_GATEWAY_503]: () => (0, i18n_1.t)('errors.destination.unavailable'),
206
+ [ERROR_TYPE.REDIRECT]: () => (0, i18n_1.t)('errors.redirectError'),
207
+ [ERROR_TYPE.NO_SUCH_HOST]: () => (0, i18n_1.t)('errors.noSuchHostError'),
208
+ [ERROR_TYPE.NO_ABAP_ENVS]: () => (0, i18n_1.t)('errors.abapEnvsUnavailable'),
209
+ [ERROR_TYPE.BAD_REQUEST]: (error) => {
210
+ const errorMsg = ErrorHandler.getMessageFromError(error);
211
+ return (0, i18n_1.t)('errors.serverReturnedAnError', {
212
+ errorDesc: (0, i18n_1.t)('errors.badRequest', { errorMsg })
213
+ });
214
+ },
215
+ [ERROR_TYPE.DESTINATION_CONNECTION_ERROR]: () => (0, i18n_1.t)('errors.systemConnectionValidationFailed'),
216
+ [ERROR_TYPE.SERVER_HTTP_ERROR]: (error) => (0, i18n_1.t)('errors.serverReturnedAnError', {
217
+ errorDesc: ErrorHandler.getMessageFromError(error)
218
+ })
219
+ };
220
+ /**
221
+ *
222
+ * @param errorType
223
+ * @param error can be any object that will get stringified and passed to the specific error message for the error type entry, e.g. where the error message is parameterized
224
+ * @returns an error message for the specified error type
225
+ */
226
+ static _errorMsg = (errorType, error) => {
227
+ return ErrorHandler._errorTypeToMsg[errorType](error);
228
+ };
229
+ /**
230
+ * Get the Guided Answers (help) node for the specified error type.
231
+ *
232
+ * @param errorType The error type for which a help node (help content id) may be returned
233
+ * @returns The Guided Answers node for the specified error type
234
+ */
235
+ static getHelpNode = (errorType) => {
236
+ const errorToHelp = {
237
+ [ERROR_TYPE.SERVICES_UNAVAILABLE]: (0, btp_utils_1.isAppStudio)()
238
+ ? guided_answers_helper_1.HELP_NODES.BAS_CATALOG_SERVICES_REQUEST_FAILED
239
+ : undefined,
240
+ [ERROR_TYPE.CERT]: guided_answers_helper_1.HELP_NODES.CERTIFICATE_ERROR,
241
+ [ERROR_TYPE.CERT_SELF_SIGNED]: guided_answers_helper_1.HELP_NODES.CERTIFICATE_ERROR,
242
+ [ERROR_TYPE.CERT_UKNOWN_OR_INVALID]: guided_answers_helper_1.HELP_NODES.CERTIFICATE_ERROR,
243
+ [ERROR_TYPE.CERT_SELF_SIGNED_CERT_IN_CHAIN]: guided_answers_helper_1.HELP_NODES.CERTIFICATE_ERROR,
244
+ [ERROR_TYPE.DESTINATION_MISCONFIGURED]: guided_answers_helper_1.HELP_NODES.DESTINATION_MISCONFIGURED,
245
+ [ERROR_TYPE.DESTINATION_UNAVAILABLE]: guided_answers_helper_1.HELP_NODES.DESTINATION_UNAVAILABLE,
246
+ [ERROR_TYPE.DESTINATION_NOT_FOUND]: guided_answers_helper_1.HELP_NODES.DESTINATION_NOT_FOUND,
247
+ [ERROR_TYPE.BAD_GATEWAY]: guided_answers_helper_1.HELP_NODES.BAD_GATEWAY,
248
+ [ERROR_TYPE.DESTINATION_BAD_GATEWAY_503]: guided_answers_helper_1.HELP_NODES.DESTINATION_BAD_GATEWAY_503,
249
+ [ERROR_TYPE.NO_V4_SERVICES]: guided_answers_helper_1.HELP_NODES.NO_V4_SERVICES,
250
+ [ERROR_TYPE.AUTH]: undefined,
251
+ [ERROR_TYPE.AUTH_TIMEOUT]: undefined,
252
+ [ERROR_TYPE.REDIRECT]: undefined,
253
+ [ERROR_TYPE.CERT_EXPIRED]: undefined,
254
+ [ERROR_TYPE.UNKNOWN]: undefined,
255
+ [ERROR_TYPE.INVALID_URL]: undefined,
256
+ [ERROR_TYPE.CONNECTION]: undefined,
257
+ [ERROR_TYPE.SERVICE_UNAVAILABLE]: undefined,
258
+ [ERROR_TYPE.NO_ABAP_ENVS]: undefined,
259
+ [ERROR_TYPE.CATALOG_SERVICE_NOT_ACTIVE]: undefined,
260
+ [ERROR_TYPE.NO_SUCH_HOST]: undefined,
261
+ [ERROR_TYPE.NOT_FOUND]: undefined,
262
+ [ERROR_TYPE.ODATA_URL_NOT_FOUND]: undefined,
263
+ [ERROR_TYPE.INTERNAL_SERVER_ERROR]: undefined,
264
+ [ERROR_TYPE.NO_V2_SERVICES]: undefined,
265
+ [ERROR_TYPE.TIMEOUT]: undefined,
266
+ [ERROR_TYPE.BAD_REQUEST]: undefined,
267
+ [ERROR_TYPE.DESTINATION_CONNECTION_ERROR]: guided_answers_helper_1.HELP_NODES.DESTINATION_CONNECTION_ERRORS,
268
+ [ERROR_TYPE.SERVER_HTTP_ERROR]: undefined
269
+ };
270
+ return errorToHelp[errorType];
271
+ };
272
+ /**
273
+ * Find an error property for mapping to a general error type from most to least significant.
274
+ *
275
+ * @param error any type of error or object that has an error code, status, name or message
276
+ * @returns a value that can be used to look up a general error type
277
+ */
278
+ static findErrorValueForMapping = (error) => error.response?.data?.error?.code ||
279
+ error.response?.status ||
280
+ error.response?.data ||
281
+ error.code ||
282
+ (['TypeError', 'Error'].includes(error.name) ? error.message : error.name) || // For generic error types use the message otherwise the name is more relevant
283
+ error.message ||
284
+ error;
285
+ /**
286
+ * Create an instance of the ErrorHandler.
287
+ *
288
+ * @param logger the logger instance to use
289
+ * @param enableGuidedAnswers if true, the end user validation errors will include guided answers to provide help
290
+ */
291
+ constructor(logger, enableGuidedAnswers = false) {
292
+ ErrorHandler._logger = logger ?? new logger_1.ToolsLogger({ logPrefix: '@sap-ux/odata-service-inquirer' });
293
+ ErrorHandler.guidedAnswersEnabled = enableGuidedAnswers;
294
+ }
295
+ /**
296
+ * Get Guided Answers (context help) enabled value.
297
+ *
298
+ * @returns true if Guided Answers is enabled
299
+ */
300
+ static get guidedAnswersEnabled() {
301
+ return ErrorHandler._guidedAnswersEnabled;
302
+ }
303
+ /**
304
+ * Toggle Guided Answers (context help) for validation errors.
305
+ */
306
+ static set guidedAnswersEnabled(value) {
307
+ ErrorHandler._guidedAnswersEnabled = value;
308
+ }
309
+ /**
310
+ * Set the logger to be used for error messages.
311
+ *
312
+ * @param logger the logger instance to use
313
+ */
314
+ static set logger(logger) {
315
+ ErrorHandler._logger = logger;
316
+ }
317
+ /**
318
+ * Get the logger used for error messages.
319
+ *
320
+ * @returns the logger instance
321
+ */
322
+ static get logger() {
323
+ return ErrorHandler._logger;
324
+ }
325
+ /**
326
+ * Tests if the error is a general certificate error.
327
+ *
328
+ * @param status the error type
329
+ * @returns true if the error is a general certificate error
330
+ */
331
+ static isCertError(status) {
332
+ return [
333
+ ERROR_TYPE.CERT,
334
+ ERROR_TYPE.CERT_EXPIRED,
335
+ ERROR_TYPE.CERT_SELF_SIGNED,
336
+ ERROR_TYPE.CERT_UKNOWN_OR_INVALID,
337
+ ERROR_TYPE.CERT_SELF_SIGNED_CERT_IN_CHAIN
338
+ ].includes(ErrorHandler.getErrorType(status));
339
+ }
340
+ /**
341
+ * Get the error type for the specified error, mapping status code, error code, error name, error message to a few general error types.
342
+ *
343
+ * @param error the error, string or status code to get the type for
344
+ * @returns the error type
345
+ */
346
+ static getErrorType(error) {
347
+ let errorValueToFind = error;
348
+ if (error instanceof Error) {
349
+ errorValueToFind = ErrorHandler.findErrorValueForMapping(error);
350
+ }
351
+ return Object.keys(ERROR_TYPE).find((errorCodeType) => {
352
+ return exports.ERROR_MAP[errorCodeType].find((exp) => exp.test(errorValueToFind.toString()));
353
+ }, {});
354
+ }
355
+ /**
356
+ * Maps errors to a few generic types, log a detailed error.
357
+ *
358
+ * @param error If the error is a string this will be logged as is. Otherwise it will be mapped to a general error internally, possibly retained and logged.
359
+ * @param userMsg If provided this will be set as the userErrorMsg instead of an error to msg map
360
+ * this allows a message more relevant to the context of where the error was generated to be used.
361
+ * @param retainError Defaults to true to retain the error state.
362
+ * @returns A user-friendly message for display in-line
363
+ */
364
+ logErrorMsgs(error, userMsg, retainError = true) {
365
+ let resolvedError = {
366
+ errorMsg: '',
367
+ errorType: ERROR_TYPE.UNKNOWN
368
+ };
369
+ // Overloaded to allow ERROR_TYPE for convenience
370
+ if (Object.values(ERROR_TYPE).includes(error)) {
371
+ const errorType = error;
372
+ resolvedError.errorMsg = ErrorHandler.getErrorMsgFromType(errorType) ?? errorType.toString();
373
+ resolvedError.errorType = errorType;
374
+ }
375
+ else if (typeof error === 'string') {
376
+ resolvedError.errorMsg = error;
377
+ }
378
+ else {
379
+ resolvedError = ErrorHandler.mapErrorToMsg(error);
380
+ }
381
+ ErrorHandler._logger.error(userMsg ? `${userMsg} ${resolvedError.errorMsg}` : resolvedError.errorMsg);
382
+ if (retainError) {
383
+ this.currentErrorMsg = userMsg ?? resolvedError.errorMsg;
384
+ this.currentErrorType = resolvedError.errorType;
385
+ }
386
+ return resolvedError.errorMsg;
387
+ }
388
+ /**
389
+ * Maps an error to a user-friendly message. The specified error may by a string (e.g. error message), number (e.g. status code), Error, or Axios error.
390
+ *
391
+ * @param error The error to map
392
+ * @returns The mapped error message and error type
393
+ */
394
+ static mapErrorToMsg(error) {
395
+ let errorType;
396
+ if (Object.values(ERROR_TYPE).includes(error)) {
397
+ errorType = error;
398
+ }
399
+ else {
400
+ // Map error type using more to less specific information if available
401
+ errorType = ErrorHandler.getErrorType(this.findErrorValueForMapping(error)) ?? ERROR_TYPE.UNKNOWN;
402
+ }
403
+ return {
404
+ errorMsg: ErrorHandler._errorMsg(errorType, error),
405
+ errorType
406
+ };
407
+ }
408
+ /**
409
+ * Used by validate functions to report in-line user friendly errors.
410
+ * Checks if there is an existing error.
411
+ *
412
+ * @param error optional, if provided get the end user message that it maps to, otherwise get the previous error message, if a boolean is passed it will be interpreted as `reset`.
413
+ * @param reset optional, resets the previous error state if true, if error is omitted reset may be passed as the first argument
414
+ * @param fallback optional, return the message of the specified ERROR_TYPE if no previous end user message and no error specified
415
+ * @returns The error message
416
+ */
417
+ getErrorMsg(error, reset, fallback) {
418
+ let errorMsg;
419
+ if (error && typeof error !== 'boolean') {
420
+ errorMsg = ErrorHandler.mapErrorToMsg(error).errorMsg;
421
+ }
422
+ // Get previous error message
423
+ if (!errorMsg) {
424
+ errorMsg = this.currentErrorMsg ?? (fallback ? ErrorHandler.getErrorMsgFromType(fallback) : undefined);
425
+ }
426
+ if (error === true || reset) {
427
+ this.currentErrorMsg = null;
428
+ this.currentErrorType = null;
429
+ }
430
+ return errorMsg;
431
+ }
432
+ /**
433
+ * Used by validate functions to report in-line user friendly errors messages with help links.
434
+ * If the error type is unknown, this will find a mapped error type and return the help (ValidationLink) if it exists.
435
+ * If an error is not provided the current error state will be used. This does not log the message to the console.
436
+ * If a system is provided, the error type may be refined to provide a more specific error message for the system which generatd the error.
437
+ *
438
+ * @param error optional, if provided get the help link message that it maps to, otherwise get the previously logged error message help link
439
+ * @param reset optional, resets the previous error state if true
440
+ * @param destination optional, if provided the destination may be used to determine a more relevant error message, specific to the system properties
441
+ * @returns An instance of @see {ValidationLink}
442
+ */
443
+ getValidationErrorHelp(error, reset = false, destination) {
444
+ let errorHelp;
445
+ let resolvedErrorMsg;
446
+ let resolvedErrorType;
447
+ if (error) {
448
+ ({ errorMsg: resolvedErrorMsg, errorType: resolvedErrorType } = ErrorHandler.mapErrorToMsg(error));
449
+ }
450
+ else {
451
+ // Use the existing error if we have it
452
+ resolvedErrorMsg = this.currentErrorMsg ?? undefined;
453
+ if (this.currentErrorType) {
454
+ resolvedErrorType = this.currentErrorType;
455
+ }
456
+ }
457
+ if (resolvedErrorType) {
458
+ // If the destination is provided, we can refine the error type and therefore the generated help message, to be more specific
459
+ if (destination) {
460
+ const { errorType: destErrorType, errorMsg: destErrorMsg } = ErrorHandler.getDestinationSpecificError(resolvedErrorType, destination);
461
+ resolvedErrorMsg = destErrorMsg ?? resolvedErrorMsg;
462
+ resolvedErrorType = destErrorType ?? resolvedErrorType;
463
+ }
464
+ if (resolvedErrorType) {
465
+ errorHelp = ErrorHandler.getHelpForError(resolvedErrorType, resolvedErrorMsg);
466
+ }
467
+ }
468
+ if (reset) {
469
+ this.currentErrorMsg = null;
470
+ this.currentErrorType = null;
471
+ }
472
+ return errorHelp ?? resolvedErrorMsg; // We mau not have a help link, so return the resolvedend user message
473
+ }
474
+ /**
475
+ * Get a more specific error type for the specified destination.
476
+ *
477
+ * @param errorType
478
+ * @param destination
479
+ * @returns
480
+ */
481
+ static getDestinationSpecificError(errorType, destination) {
482
+ let destErrorType;
483
+ let destErrorMsg;
484
+ // Add more specific error types for destinations here
485
+ if (!(0, btp_utils_1.isHTML5DynamicConfigured)(destination)) {
486
+ destErrorType = ERROR_TYPE.DESTINATION_MISCONFIGURED;
487
+ destErrorMsg = this.getErrorMsgFromType(destErrorType, 'HTML5.DynamicDestination');
488
+ }
489
+ else if (errorType === ERROR_TYPE.SERVICE_UNAVAILABLE) {
490
+ if ((0, btp_utils_1.isOnPremiseDestination)(destination)) {
491
+ destErrorType = ERROR_TYPE.DESTINATION_BAD_GATEWAY_503; // Remap to specific gateway to allow GA link to be associated
492
+ }
493
+ else {
494
+ destErrorType = ERROR_TYPE.DESTINATION_CONNECTION_ERROR; // General destination connection error, GA link to connection page
495
+ }
496
+ }
497
+ else if (errorType === ERROR_TYPE.NOT_FOUND) {
498
+ destErrorType = ERROR_TYPE.DESTINATION_NOT_FOUND;
499
+ }
500
+ else if (ERROR_TYPE.INTERNAL_SERVER_ERROR === errorType || ERROR_TYPE.SERVER_HTTP_ERROR === errorType) {
501
+ // We cannot tell in BAS what this means, so we will just say the connection failed
502
+ destErrorType = ERROR_TYPE.DESTINATION_CONNECTION_ERROR;
503
+ }
504
+ // Always raise a telemetry event for destination related errors
505
+ (0, telemetry_1.sendTelemetryEvent)(telemBasError, {
506
+ basErrorType: destErrorType ?? errorType,
507
+ destODataType: (0, telemetry_1.getTelemPropertyDestinationType)(destination),
508
+ Platform: this._platform ?? (0, fiori_generator_shared_1.getHostEnvironment)().technical
509
+ });
510
+ return {
511
+ errorType: destErrorType ?? errorType,
512
+ errorMsg: destErrorMsg
513
+ };
514
+ }
515
+ /**
516
+ * Get the error message for the specified error type.
517
+ *
518
+ * @param errorType The error type for which the message may be returned
519
+ * @param error optional, if provided may be used to get generate a more specific error message, or be included in the message
520
+ * @returns The error message for the specified error type
521
+ */
522
+ static getErrorMsgFromType(errorType, error) {
523
+ if (ERROR_TYPE[errorType]) {
524
+ return ErrorHandler._errorMsg(ERROR_TYPE[errorType], error);
525
+ }
526
+ return undefined;
527
+ }
528
+ /**
529
+ * Checks if there is an existing error.
530
+ *
531
+ * @param reset - resets the current error state
532
+ * @returns true if there is an existing error
533
+ */
534
+ hasError(reset = false) {
535
+ const hasError = !!this.currentErrorMsg;
536
+ if (reset) {
537
+ this.currentErrorMsg = null;
538
+ this.currentErrorType = null;
539
+ }
540
+ return hasError;
541
+ }
542
+ /**
543
+ * Sets the current error state.
544
+ *
545
+ * @param errorType - the error type
546
+ * @param error - the original error, if any
547
+ */
548
+ setCurrentError(errorType, error) {
549
+ this.currentErrorMsg = ErrorHandler._errorMsg(ERROR_TYPE[errorType], error);
550
+ this.currentErrorType = errorType;
551
+ }
552
+ /**
553
+ * Gets the current error type state.
554
+ *
555
+ * @param reset - resets the current error state
556
+ * @returns The current error type
557
+ */
558
+ getCurrentErrorType(reset = false) {
559
+ const currentErrorType = this.currentErrorType;
560
+ if (reset) {
561
+ this.currentErrorMsg = null;
562
+ this.currentErrorType = null;
563
+ }
564
+ return currentErrorType;
565
+ }
566
+ /**
567
+ * Maps an error type to a validation link if help (Guided Answers topic) is available for the specified error.
568
+ * Otherwise the specified error message is returned. To retrieve the previous error state @see getValidationErrorHelp.
569
+ * Use this (getHelpForError) if the error type is known.
570
+ *
571
+ * @param errorType - the error type to be mapped to help link
572
+ * @param errorMsg - the message to appear with the help link
573
+ * @returns A validation help link or help link message
574
+ */
575
+ static getHelpForError(errorType, errorMsg) {
576
+ const helpNode = ErrorHandler.getHelpNode(errorType);
577
+ const mappedErrorMsg = errorMsg ?? ErrorHandler.getErrorMsgFromType(errorType);
578
+ if (helpNode) {
579
+ const valLink = {
580
+ message: mappedErrorMsg ?? '',
581
+ link: {
582
+ text: (0, i18n_1.t)('guidedAnswers.validationErrorHelpText'),
583
+ icon: guided_answers_helper_1.GUIDED_ANSWERS_ICON,
584
+ url: (0, guided_answers_helper_1.getHelpUrl)(guided_answers_helper_1.HELP_TREE.FIORI_TOOLS, [helpNode])
585
+ }
586
+ };
587
+ if (this.guidedAnswersEnabled) {
588
+ valLink.link.command = {
589
+ id: guided_answers_helper_1.GUIDED_ANSWERS_LAUNCH_CMD_ID,
590
+ params: {
591
+ treeId: guided_answers_helper_1.HELP_TREE.FIORI_TOOLS,
592
+ nodeIdPath: [helpNode],
593
+ trigger: this.guidedAnswersTrigger
594
+ }
595
+ };
596
+ }
597
+ // Report the GA link created event
598
+ (0, telemetry_1.sendTelemetryEvent)(telemEventGALinkCreated, {
599
+ errorType,
600
+ isGuidedAnswersEnabled: this.guidedAnswersEnabled,
601
+ nodeIdPath: `${helpNode}`,
602
+ Platform: this.platform ?? (0, fiori_generator_shared_1.getHostEnvironment)().technical
603
+ });
604
+ return new types_1.ValidationLink(valLink);
605
+ }
606
+ return mappedErrorMsg;
607
+ }
608
+ }
609
+ exports.ErrorHandler = ErrorHandler;
610
+ //# sourceMappingURL=error-handler.js.map
package/dist/i18n.js CHANGED
@@ -20,7 +20,21 @@ function addi18nResourceBundle() {
20
20
  * Initialize i18next with the translations for this module.
21
21
  */
22
22
  async function initI18nInquirerCommon() {
23
- await i18next_1.default.init({ lng: 'en', fallbackLng: 'en' }, () => addi18nResourceBundle());
23
+ await i18next_1.default.init({
24
+ lng: 'en',
25
+ fallbackLng: 'en',
26
+ missingInterpolationHandler: () => '',
27
+ interpolation: {
28
+ format: function (value, format) {
29
+ // If we have a value add a colon before outputting
30
+ if (format === 'addMsgWithColonFormatter') {
31
+ return value ? `: ${value}` : '';
32
+ }
33
+ return value;
34
+ }
35
+ }
36
+ });
37
+ addi18nResourceBundle();
24
38
  }
25
39
  /**
26
40
  * Helper function facading the call to i18next. Unless a namespace option is provided the local namespace will be used.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  export * from './prompts/utility';
2
2
  export * from './types';
3
3
  export * from './prompts/helpers';
4
+ export * from './error-handler/error-handler';
5
+ export * from './prompts/cf-helper';
6
+ export * from './telemetry/telemetry';
4
7
  export { addi18nResourceBundle } from './i18n';
5
8
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -18,6 +18,9 @@ exports.addi18nResourceBundle = void 0;
18
18
  __exportStar(require("./prompts/utility"), exports);
19
19
  __exportStar(require("./types"), exports);
20
20
  __exportStar(require("./prompts/helpers"), exports);
21
+ __exportStar(require("./error-handler/error-handler"), exports);
22
+ __exportStar(require("./prompts/cf-helper"), exports);
23
+ __exportStar(require("./telemetry/telemetry"), exports);
21
24
  var i18n_1 = require("./i18n");
22
25
  Object.defineProperty(exports, "addi18nResourceBundle", { enumerable: true, get: function () { return i18n_1.addi18nResourceBundle; } });
23
26
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,11 @@
1
+ import type { ServiceInstanceInfo } from '@sap/cf-tools';
2
+ import type { ListChoiceOptions } from 'inquirer';
3
+ import { type ErrorHandler } from '../error-handler/error-handler';
4
+ /**
5
+ * Get the name sorted list of ABAP instance choices from an active CF login. If not logged in, an error message is logged.
6
+ *
7
+ * @param errorHandler The error handler instance used to log and retain messages for use in prompts
8
+ * @returns The list of ABAP instance choices
9
+ */
10
+ export declare function getCFAbapInstanceChoices(errorHandler: ErrorHandler): Promise<ListChoiceOptions<ServiceInstanceInfo>[]>;
11
+ //# sourceMappingURL=cf-helper.d.ts.map
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getCFAbapInstanceChoices = getCFAbapInstanceChoices;
4
+ const cf_tools_1 = require("@sap/cf-tools");
5
+ const error_handler_1 = require("../error-handler/error-handler");
6
+ const i18n_1 = require("../i18n");
7
+ const AbapEnvType = {
8
+ ABAP: 'abap',
9
+ ABAP_TRIAL: 'abap-trial',
10
+ ABAP_CANARY: 'abap-canary',
11
+ ABAP_OEM: 'abap-oem',
12
+ ABAP_OEM_CANARY: 'abap-oem-canary',
13
+ ABAP_HAAS: 'abap-haas',
14
+ ABAP_STAGING: 'abap-staging',
15
+ ABAP_INTERNAL_STAGING: 'abap-internal-staging',
16
+ DESTINATION: 'destination'
17
+ };
18
+ /**
19
+ * Get the name sorted list of ABAP instance choices from an active CF login. If not logged in, an error message is logged.
20
+ *
21
+ * @param errorHandler The error handler instance used to log and retain messages for use in prompts
22
+ * @returns The list of ABAP instance choices
23
+ */
24
+ async function getCFAbapInstanceChoices(errorHandler) {
25
+ const choices = [];
26
+ try {
27
+ const filteredInstances = [
28
+ AbapEnvType.ABAP,
29
+ AbapEnvType.ABAP_TRIAL,
30
+ AbapEnvType.ABAP_CANARY,
31
+ AbapEnvType.ABAP_OEM,
32
+ AbapEnvType.ABAP_OEM_CANARY,
33
+ AbapEnvType.ABAP_HAAS,
34
+ AbapEnvType.ABAP_STAGING,
35
+ AbapEnvType.ABAP_INTERNAL_STAGING
36
+ ];
37
+ const serviceInstanceInfo = await (0, cf_tools_1.apiGetServicesInstancesFilteredByType)(filteredInstances);
38
+ if (serviceInstanceInfo.length > 0) {
39
+ serviceInstanceInfo.forEach((service) => {
40
+ choices.push({ name: service['label'], value: service });
41
+ });
42
+ }
43
+ else {
44
+ // No envs found
45
+ errorHandler.logErrorMsgs(error_handler_1.ERROR_TYPE.NO_ABAP_ENVS, (0, i18n_1.t)('errors.noAbapEnvsInCFSpace'));
46
+ }
47
+ }
48
+ catch (error) {
49
+ // Cannot connect to CF
50
+ errorHandler.logErrorMsgs(error_handler_1.ERROR_TYPE.NO_ABAP_ENVS, (0, i18n_1.t)('errors.abapEnvsCFDiscoveryFailed'));
51
+ }
52
+ return choices.sort((a, b) => (a.name ? a.name.localeCompare(b.name ?? '') : 0));
53
+ }
54
+ //# sourceMappingURL=cf-helper.js.map
@@ -0,0 +1,30 @@
1
+ import { type Destination } from '@sap-ux/btp-utils';
2
+ import type { TelemetryProperties, ToolsSuiteTelemetryClient } from '@sap-ux/telemetry';
3
+ import type { TelemPropertyDestinationType } from '../types';
4
+ /**
5
+ * Set the telemetry client for use with sending telemetry events.
6
+ *
7
+ * @param toolsSuiteTelemetryClient the telemetry client instance to use when sending telemetry events
8
+ */
9
+ export declare function setTelemetryClient(toolsSuiteTelemetryClient: ToolsSuiteTelemetryClient | undefined): void;
10
+ /**
11
+ * Get the telemetry client if set.
12
+ *
13
+ * @returns the telemetry client instance if previously set.
14
+ */
15
+ export declare function getTelemetryClient(): ToolsSuiteTelemetryClient | undefined;
16
+ /**
17
+ * Send telemetry event.
18
+ *
19
+ * @param eventName the name of the telemetry event
20
+ * @param telemetryData the telemetry values to report
21
+ */
22
+ export declare function sendTelemetryEvent(eventName: string, telemetryData: TelemetryProperties): void;
23
+ /**
24
+ * Used only to generate telemetry events in the case of destination errors.
25
+ *
26
+ * @param destination
27
+ * @returns the telemetry property destination type
28
+ */
29
+ export declare function getTelemPropertyDestinationType(destination: Destination): TelemPropertyDestinationType;
30
+ //# sourceMappingURL=telemetry.d.ts.map
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.setTelemetryClient = setTelemetryClient;
7
+ exports.getTelemetryClient = getTelemetryClient;
8
+ exports.sendTelemetryEvent = sendTelemetryEvent;
9
+ exports.getTelemPropertyDestinationType = getTelemPropertyDestinationType;
10
+ const btp_utils_1 = require("@sap-ux/btp-utils");
11
+ const telemetry_1 = require("@sap-ux/telemetry");
12
+ const os_name_1 = __importDefault(require("os-name"));
13
+ const fiori_generator_shared_1 = require("@sap-ux/fiori-generator-shared");
14
+ let telemetryClient;
15
+ const osVersionName = (0, os_name_1.default)();
16
+ /**
17
+ * Set the telemetry client for use with sending telemetry events.
18
+ *
19
+ * @param toolsSuiteTelemetryClient the telemetry client instance to use when sending telemetry events
20
+ */
21
+ function setTelemetryClient(toolsSuiteTelemetryClient) {
22
+ telemetryClient = toolsSuiteTelemetryClient;
23
+ }
24
+ /**
25
+ * Get the telemetry client if set.
26
+ *
27
+ * @returns the telemetry client instance if previously set.
28
+ */
29
+ function getTelemetryClient() {
30
+ return telemetryClient;
31
+ }
32
+ /**
33
+ * Send telemetry event.
34
+ *
35
+ * @param eventName the name of the telemetry event
36
+ * @param telemetryData the telemetry values to report
37
+ */
38
+ function sendTelemetryEvent(eventName, telemetryData) {
39
+ const telemetryEvent = createTelemetryEvent(eventName, telemetryData);
40
+ if (telemetryClient) {
41
+ // Do not wait for the telemetry event to be sent, it cannot be recovered if it fails, do not block the process
42
+ /* eslint-disable @typescript-eslint/no-floating-promises */
43
+ telemetryClient.reportEvent(telemetryEvent, telemetry_1.SampleRate.NoSampling);
44
+ }
45
+ }
46
+ /**
47
+ * Create telemetry event.
48
+ *
49
+ * @param eventName the name of the telemetry event
50
+ * @param telemetryData the telemetry values to add to he returned telemetry event
51
+ * @returns the telemetry event
52
+ */
53
+ function createTelemetryEvent(eventName, telemetryData) {
54
+ const telemProps = Object.assign(telemetryData, {
55
+ OperatingSystem: osVersionName,
56
+ Platform: telemetryData.Platform || (0, fiori_generator_shared_1.getHostEnvironment)().technical
57
+ });
58
+ return {
59
+ eventName,
60
+ properties: telemProps,
61
+ measurements: {}
62
+ };
63
+ }
64
+ /**
65
+ * Used only to generate telemetry events in the case of destination errors.
66
+ *
67
+ * @param destination
68
+ * @returns the telemetry property destination type
69
+ */
70
+ function getTelemPropertyDestinationType(destination) {
71
+ if ((0, btp_utils_1.isAbapODataDestination)(destination)) {
72
+ return 'AbapODataCatalogDest';
73
+ }
74
+ else if ((0, btp_utils_1.isFullUrlDestination)(destination)) {
75
+ return 'GenericODataFullUrlDest';
76
+ }
77
+ else if ((0, btp_utils_1.isPartialUrlDestination)(destination)) {
78
+ return 'GenericODataPartialUrlDest';
79
+ }
80
+ else {
81
+ return 'Unknown';
82
+ }
83
+ }
84
+ //# sourceMappingURL=telemetry.js.map
@@ -4,5 +4,53 @@
4
4
  "outOfMaintenance": "Out of maintenance",
5
5
  "version_one": "version",
6
6
  "version_other": "versions"
7
+ },
8
+ "errors": {
9
+ "destination": {
10
+ "unavailable": "The selected destination references an instance that is not available. Please check your destination configuration and try again.",
11
+ "notFound": "The destination is misconfigured, HTTP Error 404 returned, the requested resource could not be found.",
12
+ "notReachable": "The selected system is not reachable. System name: {{systemName}}, error: {{- error}}",
13
+ "misconfigured": "The destination is misconfigured. $t(errors.destination.missingPropMsg, {\"destinationProperty\": \"{{destinationProperty}}\" })",
14
+ "missingPropMsg": "The property: `{{destinationProperty}}` is missing.",
15
+ "httpConnectionError": "A connection error occurred with the selected destination. Http code: {{- code}}. $t(texts.seeLogForDetails)"
16
+ },
17
+ "cannotReadCapServiceMetadata": "An error occurred reading CAP service metadata: {{serviceName}}. $t(texts.seeLogForDetails).",
18
+ "capModelAndServicesLoadError": "An error occurred loading the CAP model and services. {{- error}}",
19
+ "capServiceUrlPathNotDefined": "An error occurred reading CAP service metadata: {{serviceName}}. CAP service property `urlPath` is not defined but is required.",
20
+ "unknownError": "An error occurred{{- error, addMsgWithColonFormatter}}",
21
+ "servicesUnavailable": "An error occurred retrieving service(s) for SAP System.",
22
+ "certificateError": "A certificate error has occurred{{- errorMsg, addMsgWithColonFormatter}}",
23
+ "urlCertValidationError": "The system URL is using {{certErrorReason}} security certificate.",
24
+ "authenticationFailed": "Authentication incorrect. {{- error}}",
25
+ "authenticationTimeout": "Authorization was not verified within the allowed time. Please ensure you have authenticated using the associated browser window.",
26
+ "invalidUrl": "Invalid URL{{-input, addMsgWithColonFormatter}}",
27
+ "connectionError": "A connection error occurred, please ensure the target host is available on the network: {{- error}}",
28
+ "timeout": "A connection timeout error occurred{{- errorMsg, addMsgWithColonFormatter}}",
29
+ "serverReturnedAnError": "The server returned an error. {{errorDesc}}",
30
+ "serverUnableToCompleteRequest": "The server was unable to complete the request",
31
+ "catalogServiceNotActive": "Catalog service is not active",
32
+ "urlNotFound": "URL not found",
33
+ "odataServiceUrlNotFound": "The service URL you have provided is not a valid OData Service. SAP Fiori applications require an OData service as the data source.",
34
+ "noServicesAvailable": "There are no V{{version}} OData services available from the selected system and the template you have chosen supports V{{version}} OData services only",
35
+ "redirectError": "A redirect response was received from the server",
36
+ "abapEnvsUnavailable": "ABAP environments unavailable",
37
+ "noSuchHostError": "No such host is known",
38
+ "noAbapEnvsInCFSpace": "No ABAP environments in CF space found.",
39
+ "abapEnvsCFDiscoveryFailed": "Discovering ABAP Environments failed. Please ensure you are logged into Cloud Foundry (see https://docs.cloudfoundry.org/cf-cli/getting-started.html#login).",
40
+ "systemConnectionValidationFailed": "A connection to the selected system could not be established.",
41
+ "internalServerError": "Internal server error{{-errorMsg, addMsgWithColonFormatter}}",
42
+ "badGateway": "Bad gateway{{- errorMsg, addMsgWithColonFormatter}}",
43
+ "badRequest": "Bad request{{- errorMsg, addMsgWithColonFormatter}}"
44
+ },
45
+ "guidedAnswers": {
46
+ "validationErrorHelpText": "Need help with this error?"
47
+ },
48
+ "texts": {
49
+ "anExpiredCert": "an expired",
50
+ "aSelfSignedCert": "a self-signed",
51
+ "anUnknownOrInvalidCert": "an unknown or invalid",
52
+ "anUntrustedRootCert": "an untrusted root",
53
+ "suggestedSystemNameClient": ", client {{client}}",
54
+ "seeLogForDetails": "See log for more details."
7
55
  }
8
56
  }
package/dist/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type IMessageSeverity } from '@sap-devx/yeoman-ui-types';
1
+ import type { IValidationLink, IMessageSeverity } from '@sap-devx/yeoman-ui-types';
2
2
  import type { Answers, ConfirmQuestion as BaseConfirmQuestion, InputQuestion as BaseInputQuestion, ListQuestion as BaseListQuestion, CheckboxQuestion as BaseCheckBoxQuestion, NumberQuestion as BaseNumberQuestion, EditorQuestion as BaseEditorQuestion, ListChoiceOptions, PromptFunction, PromptModule, Question, Validator, AsyncDynamicQuestionProperty } from 'inquirer';
3
3
  export interface UI5VersionChoice extends ListChoiceOptions {
4
4
  /**
@@ -86,4 +86,25 @@ export type CommonPromptOptions<T extends Answers = Answers> = {
86
86
  export type PromptDefaultValue<T> = {
87
87
  default?: AsyncDynamicQuestionProperty<T>;
88
88
  };
89
+ export type TelemPropertyDestinationType = 'AbapODataCatalogDest' | 'GenericODataFullUrlDest' | 'GenericODataPartialUrlDest' | 'Unknown';
90
+ /**
91
+ * Implementation of IValidationLink interface.
92
+ * Provides a toString() for serialization on CLI since IValidationLink rendering is only supported by YeomanUI.
93
+ */
94
+ export declare class ValidationLink implements IValidationLink {
95
+ message: IValidationLink['message'];
96
+ link: IValidationLink['link'];
97
+ /**
98
+ * Constructor for ValidationLink.
99
+ *
100
+ * @param validationLink The validation link object to be used for serialization
101
+ */
102
+ constructor(validationLink: IValidationLink);
103
+ /**
104
+ * Serialize the validation link object to a string.
105
+ *
106
+ * @returns The validation link object as a string
107
+ */
108
+ toString(): string;
109
+ }
89
110
  //# sourceMappingURL=types.d.ts.map
package/dist/types.js CHANGED
@@ -1,3 +1,30 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ValidationLink = void 0;
4
+ /**
5
+ * Implementation of IValidationLink interface.
6
+ * Provides a toString() for serialization on CLI since IValidationLink rendering is only supported by YeomanUI.
7
+ */
8
+ class ValidationLink {
9
+ // Having to redeclare properties from an interface should not be required see: https://github.com/Microsoft/TypeScript/issues/5326
10
+ message;
11
+ link;
12
+ /**
13
+ * Constructor for ValidationLink.
14
+ *
15
+ * @param validationLink The validation link object to be used for serialization
16
+ */
17
+ constructor(validationLink) {
18
+ Object.assign(this, validationLink);
19
+ }
20
+ /**
21
+ * Serialize the validation link object to a string.
22
+ *
23
+ * @returns The validation link object as a string
24
+ */
25
+ toString() {
26
+ return `${this.message} ${this.link.text}${this.link.url ? ' : ' + this.link.url : ''}`;
27
+ }
28
+ }
29
+ exports.ValidationLink = ValidationLink;
3
30
  //# sourceMappingURL=types.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sap-ux/inquirer-common",
3
3
  "description": "Commonly used shared functionality and types to support inquirer modules.",
4
- "version": "0.4.9",
4
+ "version": "0.5.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/SAP/open-ux-tools.git",
@@ -19,19 +19,29 @@
19
19
  "!dist/**/*.map"
20
20
  ],
21
21
  "dependencies": {
22
- "fuzzy": "0.1.3",
23
- "i18next": "23.5.1",
22
+ "@sap/cf-tools": "3.2.0",
23
+ "axios": "1.7.4",
24
24
  "chalk": "4.1.2",
25
25
  "figures": "3.2.0",
26
- "semver": "7.5.4",
26
+ "fuzzy": "0.1.3",
27
+ "i18next": "23.5.1",
27
28
  "lodash": "4.17.21",
28
- "@sap-ux/ui5-info": "0.8.2"
29
+ "os-name": "4.0.1",
30
+ "semver": "7.5.4",
31
+ "@sap-ux/btp-utils": "0.16.0",
32
+ "@sap-ux/feature-toggle": "0.2.2",
33
+ "@sap-ux/fiori-generator-shared": "0.7.7",
34
+ "@sap-ux/guided-answers-helper": "0.1.0",
35
+ "@sap-ux/telemetry": "0.5.42",
36
+ "@sap-ux/logger": "0.6.0",
37
+ "@sap-ux/ui5-info": "0.8.3"
29
38
  },
30
39
  "devDependencies": {
31
40
  "@sap-devx/yeoman-ui-types": "1.14.4",
32
41
  "@types/inquirer": "8.2.6",
33
42
  "@types/semver": "7.5.4",
34
- "@types/lodash": "4.14.202"
43
+ "@types/lodash": "4.14.202",
44
+ "jest-extended": "3.2.4"
35
45
  },
36
46
  "engines": {
37
47
  "node": ">=18.x"