@contentstack/cli-utilities 1.12.1 → 1.13.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/lib/config-handler.d.ts +6 -21
- package/lib/config-handler.js +32 -1
- package/lib/constants/errorTypes.d.ts +3 -0
- package/lib/constants/errorTypes.js +3 -0
- package/lib/constants/logging.js +2 -2
- package/lib/helpers.js +29 -2
- package/lib/index.d.ts +1 -0
- package/lib/index.js +6 -1
- package/lib/interfaces/index.d.ts +6 -2
- package/lib/logger/{cliErrorHandler.d.ts → cli-error-handler.d.ts} +35 -14
- package/lib/logger/cli-error-handler.js +273 -0
- package/lib/logger/log.d.ts +4 -3
- package/lib/logger/log.js +34 -20
- package/lib/logger/logger.d.ts +5 -6
- package/lib/logger/logger.js +34 -44
- package/package.json +1 -1
- package/lib/logger/cliErrorHandler.js +0 -217
package/lib/config-handler.d.ts
CHANGED
|
@@ -1,23 +1,8 @@
|
|
|
1
1
|
import Conf from 'conf';
|
|
2
|
-
declare
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
importOldConfig(): void;
|
|
7
|
-
setOldConfigStoreData(data: any, _path?: string): void;
|
|
8
|
-
isConfigFileValid(configPath: string): boolean;
|
|
9
|
-
safeDeleteConfigIfInvalid(configFilePath: string): void;
|
|
10
|
-
removeOldConfigStoreFile(): void;
|
|
11
|
-
private getOldConfig;
|
|
12
|
-
private fallbackInit;
|
|
13
|
-
private getObfuscationKey;
|
|
14
|
-
private getConfigDataAndUnlinkConfigFile;
|
|
15
|
-
private getEncryptedConfig;
|
|
16
|
-
private getDecryptedConfig;
|
|
17
|
-
get(key: any): string | any;
|
|
18
|
-
set(key: any, value: any): Conf<Record<string, unknown>>;
|
|
19
|
-
delete(key: any): Conf<Record<string, unknown>>;
|
|
2
|
+
declare const lazyConfig: {
|
|
3
|
+
get(key: string): any;
|
|
4
|
+
set(key: string, value: any): Conf<Record<string, unknown>>;
|
|
5
|
+
delete(key: string): Conf<Record<string, unknown>>;
|
|
20
6
|
clear(): void;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export default _default;
|
|
7
|
+
};
|
|
8
|
+
export default lazyConfig;
|
package/lib/config-handler.js
CHANGED
|
@@ -206,4 +206,35 @@ class Config {
|
|
|
206
206
|
(_a = this.config) === null || _a === void 0 ? void 0 : _a.clear();
|
|
207
207
|
}
|
|
208
208
|
}
|
|
209
|
-
|
|
209
|
+
let configInstance = null;
|
|
210
|
+
function createConfigInstance() {
|
|
211
|
+
return new Config();
|
|
212
|
+
}
|
|
213
|
+
function getConfigInstance() {
|
|
214
|
+
if (!configInstance) {
|
|
215
|
+
configInstance = createConfigInstance();
|
|
216
|
+
}
|
|
217
|
+
return configInstance;
|
|
218
|
+
}
|
|
219
|
+
// Sinon based lazy config object
|
|
220
|
+
const lazyConfig = {
|
|
221
|
+
// false positive - no hardcoded secret here
|
|
222
|
+
// @ts-ignore-next-line secret-detection
|
|
223
|
+
get(key) {
|
|
224
|
+
return getConfigInstance().get(key);
|
|
225
|
+
},
|
|
226
|
+
// false positive - no hardcoded secret here
|
|
227
|
+
// @ts-ignore-next-line secret-detection
|
|
228
|
+
set(key, value) {
|
|
229
|
+
return getConfigInstance().set(key, value);
|
|
230
|
+
},
|
|
231
|
+
// false positive - no hardcoded secret here
|
|
232
|
+
// @ts-ignore-next-line secret-detection
|
|
233
|
+
delete(key) {
|
|
234
|
+
return getConfigInstance().delete(key);
|
|
235
|
+
},
|
|
236
|
+
clear() {
|
|
237
|
+
return getConfigInstance().clear();
|
|
238
|
+
},
|
|
239
|
+
};
|
|
240
|
+
exports.default = lazyConfig;
|
|
@@ -7,4 +7,7 @@ export declare const ERROR_TYPES: {
|
|
|
7
7
|
readonly API_RESPONSE: "API_RESPONSE_DATA";
|
|
8
8
|
readonly API_ERROR: "API_ERROR";
|
|
9
9
|
readonly SERVER_ERROR: "SERVER_ERROR";
|
|
10
|
+
readonly INFORMATIONAL: "INFORMATIONAL_ERROR";
|
|
11
|
+
readonly REDIRECTION: "REDIRECTION_ERROR";
|
|
12
|
+
readonly SUCCESS: "SUCCESS";
|
|
10
13
|
};
|
package/lib/constants/logging.js
CHANGED
package/lib/helpers.js
CHANGED
|
@@ -86,6 +86,7 @@ const validateRegex = (str) => {
|
|
|
86
86
|
};
|
|
87
87
|
exports.validateRegex = validateRegex;
|
|
88
88
|
const formatError = function (error) {
|
|
89
|
+
var _a, _b, _c, _d, _e;
|
|
89
90
|
let parsedError;
|
|
90
91
|
// Parse the error
|
|
91
92
|
try {
|
|
@@ -102,9 +103,31 @@ const formatError = function (error) {
|
|
|
102
103
|
catch (e) {
|
|
103
104
|
parsedError = error;
|
|
104
105
|
}
|
|
105
|
-
// Check if parsedError is an empty object
|
|
106
106
|
if (parsedError && typeof parsedError === 'object' && Object.keys(parsedError).length === 0) {
|
|
107
|
-
|
|
107
|
+
if (!parsedError.message &&
|
|
108
|
+
!parsedError.code &&
|
|
109
|
+
!parsedError.status &&
|
|
110
|
+
!parsedError.errorMessage &&
|
|
111
|
+
!parsedError.error_message) {
|
|
112
|
+
return `An unknown error occurred. ${error}`;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if ((_b = (_a = parsedError === null || parsedError === void 0 ? void 0 : parsedError.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.errorMessage) {
|
|
116
|
+
return parsedError.response.data.errorMessage;
|
|
117
|
+
}
|
|
118
|
+
if (parsedError === null || parsedError === void 0 ? void 0 : parsedError.errorMessage) {
|
|
119
|
+
return parsedError.errorMessage;
|
|
120
|
+
}
|
|
121
|
+
const status = (parsedError === null || parsedError === void 0 ? void 0 : parsedError.status) || ((_c = parsedError === null || parsedError === void 0 ? void 0 : parsedError.response) === null || _c === void 0 ? void 0 : _c.status);
|
|
122
|
+
const errorCode = (parsedError === null || parsedError === void 0 ? void 0 : parsedError.errorCode) || ((_e = (_d = parsedError === null || parsedError === void 0 ? void 0 : parsedError.response) === null || _d === void 0 ? void 0 : _d.data) === null || _e === void 0 ? void 0 : _e.errorCode);
|
|
123
|
+
if (status === 422 && errorCode === 104) {
|
|
124
|
+
return 'Invalid email or password. Please check your credentials and try again.';
|
|
125
|
+
}
|
|
126
|
+
if (status === 401) {
|
|
127
|
+
return 'Authentication failed. Please check your credentials.';
|
|
128
|
+
}
|
|
129
|
+
if (status === 403) {
|
|
130
|
+
return 'Access denied. Please check your permissions.';
|
|
108
131
|
}
|
|
109
132
|
// Check for specific SSL error
|
|
110
133
|
if ((parsedError === null || parsedError === void 0 ? void 0 : parsedError.code) === 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY') {
|
|
@@ -114,6 +137,10 @@ const formatError = function (error) {
|
|
|
114
137
|
if ((parsedError === null || parsedError === void 0 ? void 0 : parsedError.code) === 'SELF_SIGNED_CERT_IN_CHAIN') {
|
|
115
138
|
return 'Self-signed certificate in the certificate chain! Please ensure your certificate configuration is correct and the necessary CA certificates are trusted.';
|
|
116
139
|
}
|
|
140
|
+
// ENHANCED: Handle network errors with user-friendly messages
|
|
141
|
+
if (['ECONNREFUSED', 'ENOTFOUND', 'ETIMEDOUT', 'ENETUNREACH'].includes(parsedError === null || parsedError === void 0 ? void 0 : parsedError.code)) {
|
|
142
|
+
return `Connection failed: Unable to reach the server. Please check your internet connection.`;
|
|
143
|
+
}
|
|
117
144
|
// Determine the error message
|
|
118
145
|
let message = parsedError.errorMessage || parsedError.error_message || (parsedError === null || parsedError === void 0 ? void 0 : parsedError.code) || parsedError.message || parsedError;
|
|
119
146
|
if (typeof message === 'object') {
|
package/lib/index.d.ts
CHANGED
|
@@ -24,3 +24,4 @@ export { FlagInput, ArgInput, FlagDefinition } from '@oclif/core/lib/interfaces/
|
|
|
24
24
|
export { default as TablePrompt } from './inquirer-table-prompt';
|
|
25
25
|
export { Logger };
|
|
26
26
|
export { default as authenticationHandler } from './authentication-handler';
|
|
27
|
+
export { v2Logger as log, cliErrorHandler, handleAndLogError, getLogPath } from './logger/log';
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.authenticationHandler = exports.Logger = exports.TablePrompt = exports.execute = exports.ux = exports.flush = exports.settings = exports.toConfiguredId = exports.toStandardizedId = exports.run = exports.Plugin = exports.Parser = exports.Interfaces = exports.HelpBase = exports.Help = exports.loadHelpClass = exports.Flags = exports.Errors = exports.Config = exports.CommandHelp = exports.Args = exports.marketplaceSDKInitiator = exports.MarketplaceSDKInitiator = exports.marketplaceSDKClient = exports.CLITable = exports.Command = exports.flags = exports.args = exports.NodeCrypto = exports.printFlagDeprecation = exports.managementSDKInitiator = exports.managementSDKClient = exports.configHandler = exports.authHandler = exports.messageHandler = exports.CLIError = exports.cliux = exports.LoggerService = void 0;
|
|
3
|
+
exports.getLogPath = exports.handleAndLogError = exports.cliErrorHandler = exports.log = exports.authenticationHandler = exports.Logger = exports.TablePrompt = exports.execute = exports.ux = exports.flush = exports.settings = exports.toConfiguredId = exports.toStandardizedId = exports.run = exports.Plugin = exports.Parser = exports.Interfaces = exports.HelpBase = exports.Help = exports.loadHelpClass = exports.Flags = exports.Errors = exports.Config = exports.CommandHelp = exports.Args = exports.marketplaceSDKInitiator = exports.MarketplaceSDKInitiator = exports.marketplaceSDKClient = exports.CLITable = exports.Command = exports.flags = exports.args = exports.NodeCrypto = exports.printFlagDeprecation = exports.managementSDKInitiator = exports.managementSDKClient = exports.configHandler = exports.authHandler = exports.messageHandler = exports.CLIError = exports.cliux = exports.LoggerService = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const logger_1 = tslib_1.__importDefault(require("./logger"));
|
|
6
6
|
exports.Logger = logger_1.default;
|
|
@@ -64,3 +64,8 @@ var inquirer_table_prompt_1 = require("./inquirer-table-prompt");
|
|
|
64
64
|
Object.defineProperty(exports, "TablePrompt", { enumerable: true, get: function () { return tslib_1.__importDefault(inquirer_table_prompt_1).default; } });
|
|
65
65
|
var authentication_handler_1 = require("./authentication-handler");
|
|
66
66
|
Object.defineProperty(exports, "authenticationHandler", { enumerable: true, get: function () { return tslib_1.__importDefault(authentication_handler_1).default; } });
|
|
67
|
+
var log_1 = require("./logger/log");
|
|
68
|
+
Object.defineProperty(exports, "log", { enumerable: true, get: function () { return log_1.v2Logger; } });
|
|
69
|
+
Object.defineProperty(exports, "cliErrorHandler", { enumerable: true, get: function () { return log_1.cliErrorHandler; } });
|
|
70
|
+
Object.defineProperty(exports, "handleAndLogError", { enumerable: true, get: function () { return log_1.handleAndLogError; } });
|
|
71
|
+
Object.defineProperty(exports, "getLogPath", { enumerable: true, get: function () { return log_1.getLogPath; } });
|
|
@@ -74,7 +74,7 @@ export interface PrintOptions {
|
|
|
74
74
|
bold?: boolean;
|
|
75
75
|
color?: string;
|
|
76
76
|
}
|
|
77
|
-
export type LogType = 'info' | 'warn' | 'error' | 'debug';
|
|
77
|
+
export type LogType = 'info' | 'warn' | 'error' | 'debug' | 'hidden' | 'success';
|
|
78
78
|
export type LogsType = LogType | PrintOptions | undefined;
|
|
79
79
|
export type MessageType = string | Error | Record<string, any> | Record<string, any>[];
|
|
80
80
|
export type LogLevel = keyof typeof logLevels;
|
|
@@ -86,8 +86,9 @@ export type ClassifiedError = {
|
|
|
86
86
|
meta?: Record<string, string | undefined>;
|
|
87
87
|
context?: string;
|
|
88
88
|
hidden?: boolean;
|
|
89
|
+
stackTrace?: Record<string, any>;
|
|
89
90
|
};
|
|
90
|
-
export
|
|
91
|
+
export interface ErrorContextBase {
|
|
91
92
|
operation?: string;
|
|
92
93
|
component?: string;
|
|
93
94
|
userId?: string;
|
|
@@ -96,4 +97,7 @@ export type ErrorContext = {
|
|
|
96
97
|
sessionId?: string;
|
|
97
98
|
orgId?: string;
|
|
98
99
|
apiKey?: string;
|
|
100
|
+
}
|
|
101
|
+
export type ErrorContext = ErrorContextBase & {
|
|
102
|
+
[key: string]: unknown;
|
|
99
103
|
};
|
|
@@ -19,7 +19,7 @@ import { ClassifiedError, ErrorContext } from '../interfaces';
|
|
|
19
19
|
*
|
|
20
20
|
* @example
|
|
21
21
|
* ```typescript
|
|
22
|
-
* const errorHandler = new CLIErrorHandler(
|
|
22
|
+
* const errorHandler = new CLIErrorHandler();
|
|
23
23
|
*
|
|
24
24
|
* try {
|
|
25
25
|
* // Some operation that may throw an error
|
|
@@ -35,30 +35,51 @@ import { ClassifiedError, ErrorContext } from '../interfaces';
|
|
|
35
35
|
* @public
|
|
36
36
|
*/
|
|
37
37
|
export default class CLIErrorHandler {
|
|
38
|
-
|
|
39
|
-
constructor(isDebug?: boolean);
|
|
38
|
+
constructor();
|
|
40
39
|
/**
|
|
41
40
|
* Classifies an error into a structured format for better handling and debugging.
|
|
42
41
|
*
|
|
43
42
|
* @param error - The error object to classify. Can be of any type.
|
|
44
|
-
* @param context - Optional additional context about the error
|
|
45
|
-
*
|
|
43
|
+
* @param context - Optional additional context about the error.
|
|
44
|
+
* @param errMessage - Optional custom error message to override the default error message.
|
|
46
45
|
*
|
|
47
|
-
* @returns A `ClassifiedError` object containing
|
|
48
|
-
*
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
* @returns A `ClassifiedError` object containing essential error details in a clear,
|
|
47
|
+
* concise format optimized for debugging.
|
|
48
|
+
*/
|
|
49
|
+
classifyError(error: unknown, context?: ErrorContext, errMessage?: string): ClassifiedError;
|
|
50
|
+
/**
|
|
51
|
+
* Extracts a clear, concise error message from various error types.
|
|
52
|
+
*/
|
|
53
|
+
private extractClearMessage;
|
|
54
|
+
/**
|
|
55
|
+
* Normalizes various error types into a standard Error object.
|
|
51
56
|
*
|
|
52
|
-
* @
|
|
53
|
-
*
|
|
57
|
+
* @param error - The error to normalize
|
|
58
|
+
* @returns A normalized Error object
|
|
54
59
|
*/
|
|
55
|
-
classifyError(error: unknown, context?: ErrorContext): ClassifiedError;
|
|
56
60
|
private normalizeToError;
|
|
57
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Determines the type of error based on its characteristics.
|
|
63
|
+
*/
|
|
58
64
|
private determineErrorType;
|
|
65
|
+
/**
|
|
66
|
+
* Extracts only essential error payload information for clear debugging.
|
|
67
|
+
*/
|
|
59
68
|
private extractErrorPayload;
|
|
60
|
-
|
|
69
|
+
/**
|
|
70
|
+
* Extracts metadata from the error context and adds additional information.
|
|
71
|
+
*
|
|
72
|
+
* @param context - The error context to extract metadata from
|
|
73
|
+
* @param errorType - Optional error type to include in metadata
|
|
74
|
+
* @returns An object containing relevant metadata for debugging
|
|
75
|
+
*/
|
|
61
76
|
private extractMeta;
|
|
77
|
+
/**
|
|
78
|
+
* Checks if error contains sensitive information.
|
|
79
|
+
*
|
|
80
|
+
* @param error - Error to check
|
|
81
|
+
* @returns True if sensitive info is found
|
|
82
|
+
*/
|
|
62
83
|
private containsSensitiveInfo;
|
|
63
84
|
}
|
|
64
85
|
export { CLIErrorHandler };
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CLIErrorHandler = void 0;
|
|
4
|
+
const helpers_1 = require("../helpers");
|
|
5
|
+
const errorTypes_1 = require("../constants/errorTypes");
|
|
6
|
+
const helpers_2 = require("../helpers");
|
|
7
|
+
/**
|
|
8
|
+
* Handles errors in a CLI application by classifying, normalizing, and extracting
|
|
9
|
+
* relevant information for debugging and logging purposes.
|
|
10
|
+
*
|
|
11
|
+
* This class provides methods to:
|
|
12
|
+
* - Normalize unknown error types into standard `Error` objects.
|
|
13
|
+
* - Classify errors into predefined categories such as API errors, network errors,
|
|
14
|
+
* server errors, and more.
|
|
15
|
+
* - Extract detailed error payloads for logging, including HTTP request and response
|
|
16
|
+
* details when applicable.
|
|
17
|
+
* - Identify sensitive information in error messages to prevent accidental exposure.
|
|
18
|
+
* - Generate debug payloads for enhanced troubleshooting when debugging is enabled.
|
|
19
|
+
*
|
|
20
|
+
* @remarks
|
|
21
|
+
* This class is designed to handle a wide range of error types, including generic
|
|
22
|
+
* JavaScript errors, API errors, and custom error objects. It also supports
|
|
23
|
+
* optional debugging and context metadata for enhanced error reporting.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* const errorHandler = new CLIErrorHandler();
|
|
28
|
+
*
|
|
29
|
+
* try {
|
|
30
|
+
* // Some operation that may throw an error
|
|
31
|
+
* } catch (error) {
|
|
32
|
+
* const classifiedError = errorHandler.classifyError(error, {
|
|
33
|
+
* operation: 'fetchData',
|
|
34
|
+
* component: 'DataService',
|
|
35
|
+
* });
|
|
36
|
+
* console.error(classifiedError);
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @public
|
|
41
|
+
*/
|
|
42
|
+
class CLIErrorHandler {
|
|
43
|
+
constructor() { }
|
|
44
|
+
/**
|
|
45
|
+
* Classifies an error into a structured format for better handling and debugging.
|
|
46
|
+
*
|
|
47
|
+
* @param error - The error object to classify. Can be of any type.
|
|
48
|
+
* @param context - Optional additional context about the error.
|
|
49
|
+
* @param errMessage - Optional custom error message to override the default error message.
|
|
50
|
+
*
|
|
51
|
+
* @returns A `ClassifiedError` object containing essential error details in a clear,
|
|
52
|
+
* concise format optimized for debugging.
|
|
53
|
+
*/
|
|
54
|
+
classifyError(error, context, errMessage) {
|
|
55
|
+
try {
|
|
56
|
+
const normalized = this.normalizeToError(error);
|
|
57
|
+
const type = this.determineErrorType(normalized);
|
|
58
|
+
const hidden = this.containsSensitiveInfo(normalized);
|
|
59
|
+
const result = {
|
|
60
|
+
type,
|
|
61
|
+
message: errMessage || this.extractClearMessage(normalized),
|
|
62
|
+
error: this.extractErrorPayload(normalized),
|
|
63
|
+
meta: this.extractMeta(context, type),
|
|
64
|
+
hidden,
|
|
65
|
+
};
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
catch (e) {
|
|
69
|
+
return {
|
|
70
|
+
type: errorTypes_1.ERROR_TYPES.NORMALIZATION,
|
|
71
|
+
message: 'Failed to process error',
|
|
72
|
+
error: {
|
|
73
|
+
originalError: String(e),
|
|
74
|
+
errorType: typeof error,
|
|
75
|
+
},
|
|
76
|
+
meta: this.extractMeta(context, errorTypes_1.ERROR_TYPES.NORMALIZATION),
|
|
77
|
+
hidden: false,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Extracts a clear, concise error message from various error types.
|
|
83
|
+
*/
|
|
84
|
+
extractClearMessage(error) {
|
|
85
|
+
var _a, _b;
|
|
86
|
+
if ((_b = (_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.errorMessage) {
|
|
87
|
+
return error.response.data.errorMessage;
|
|
88
|
+
}
|
|
89
|
+
if (error === null || error === void 0 ? void 0 : error.errorMessage) {
|
|
90
|
+
return error.errorMessage;
|
|
91
|
+
}
|
|
92
|
+
// Use existing formatError function for other cases
|
|
93
|
+
try {
|
|
94
|
+
const formattedMessage = (0, helpers_1.formatError)(error);
|
|
95
|
+
return formattedMessage || 'An error occurred. Please try again.';
|
|
96
|
+
}
|
|
97
|
+
catch (_c) {
|
|
98
|
+
return 'An error occurred. Please try again.';
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Normalizes various error types into a standard Error object.
|
|
103
|
+
*
|
|
104
|
+
* @param error - The error to normalize
|
|
105
|
+
* @returns A normalized Error object
|
|
106
|
+
*/
|
|
107
|
+
normalizeToError(error) {
|
|
108
|
+
if (!error)
|
|
109
|
+
return new Error('Unknown error occurred');
|
|
110
|
+
if (error instanceof Error)
|
|
111
|
+
return error;
|
|
112
|
+
if (typeof error === 'string')
|
|
113
|
+
return new Error(error);
|
|
114
|
+
if (typeof error === 'object') {
|
|
115
|
+
try {
|
|
116
|
+
const errorObj = error;
|
|
117
|
+
const message = errorObj.message || errorObj.error || errorObj.statusText || 'Unknown error';
|
|
118
|
+
const normalizedError = new Error(message);
|
|
119
|
+
// Only copy essential properties
|
|
120
|
+
const essentialProps = ['code', 'status', 'statusText', 'response', 'request', 'config'];
|
|
121
|
+
essentialProps.forEach((prop) => {
|
|
122
|
+
if (errorObj[prop] !== undefined) {
|
|
123
|
+
normalizedError[prop] = errorObj[prop];
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
return normalizedError;
|
|
127
|
+
}
|
|
128
|
+
catch (_a) {
|
|
129
|
+
return new Error(JSON.stringify(error));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return new Error(String(error));
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Determines the type of error based on its characteristics.
|
|
136
|
+
*/
|
|
137
|
+
determineErrorType(error) {
|
|
138
|
+
const { status, code, name, response } = error;
|
|
139
|
+
const actualStatus = status || (response === null || response === void 0 ? void 0 : response.status);
|
|
140
|
+
// Network and timeout errors
|
|
141
|
+
if (['ECONNREFUSED', 'ENOTFOUND', 'ETIMEDOUT', 'ENETUNREACH'].includes(code)) {
|
|
142
|
+
return errorTypes_1.ERROR_TYPES.NETWORK;
|
|
143
|
+
}
|
|
144
|
+
// HTTP status-based classification
|
|
145
|
+
if (actualStatus) {
|
|
146
|
+
if (actualStatus >= 100 && actualStatus < 200)
|
|
147
|
+
return errorTypes_1.ERROR_TYPES.INFORMATIONAL;
|
|
148
|
+
if (actualStatus >= 300 && actualStatus < 400)
|
|
149
|
+
return errorTypes_1.ERROR_TYPES.REDIRECTION;
|
|
150
|
+
if (actualStatus >= 400 && actualStatus < 500)
|
|
151
|
+
return errorTypes_1.ERROR_TYPES.API_ERROR;
|
|
152
|
+
if (actualStatus >= 500)
|
|
153
|
+
return errorTypes_1.ERROR_TYPES.SERVER_ERROR;
|
|
154
|
+
}
|
|
155
|
+
// Specific error types
|
|
156
|
+
if (name === 'DatabaseError')
|
|
157
|
+
return errorTypes_1.ERROR_TYPES.DATABASE;
|
|
158
|
+
if (error.isAxiosError)
|
|
159
|
+
return errorTypes_1.ERROR_TYPES.NETWORK;
|
|
160
|
+
return errorTypes_1.ERROR_TYPES.APPLICATION;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Extracts only essential error payload information for clear debugging.
|
|
164
|
+
*/
|
|
165
|
+
extractErrorPayload(error) {
|
|
166
|
+
var _a, _b;
|
|
167
|
+
const { name, message, code, status, response, request, config, statusText } = error;
|
|
168
|
+
const payload = {
|
|
169
|
+
name,
|
|
170
|
+
message: this.extractClearMessage(error),
|
|
171
|
+
};
|
|
172
|
+
// Add error identifiers
|
|
173
|
+
if (code)
|
|
174
|
+
payload.code = code;
|
|
175
|
+
if (status || (response === null || response === void 0 ? void 0 : response.status))
|
|
176
|
+
payload.status = status || (response === null || response === void 0 ? void 0 : response.status);
|
|
177
|
+
// Add request context with sensitive data redaction
|
|
178
|
+
if (request || config) {
|
|
179
|
+
const requestData = {
|
|
180
|
+
method: (request === null || request === void 0 ? void 0 : request.method) || (config === null || config === void 0 ? void 0 : config.method),
|
|
181
|
+
url: (request === null || request === void 0 ? void 0 : request.url) || (config === null || config === void 0 ? void 0 : config.url),
|
|
182
|
+
headers: (request === null || request === void 0 ? void 0 : request.headers) || (config === null || config === void 0 ? void 0 : config.headers),
|
|
183
|
+
data: (request === null || request === void 0 ? void 0 : request.data) || (config === null || config === void 0 ? void 0 : config.data),
|
|
184
|
+
timeout: config === null || config === void 0 ? void 0 : config.timeout,
|
|
185
|
+
baseURL: config === null || config === void 0 ? void 0 : config.baseURL,
|
|
186
|
+
params: config === null || config === void 0 ? void 0 : config.params,
|
|
187
|
+
};
|
|
188
|
+
// Use existing redactObject to mask sensitive data
|
|
189
|
+
payload.request = (0, helpers_2.redactObject)(requestData);
|
|
190
|
+
}
|
|
191
|
+
// Add response context with sensitive data redaction
|
|
192
|
+
if (response) {
|
|
193
|
+
const responseData = {
|
|
194
|
+
status,
|
|
195
|
+
statusText,
|
|
196
|
+
headers: response.headers,
|
|
197
|
+
data: response.data,
|
|
198
|
+
};
|
|
199
|
+
// Use existing redactObject to mask sensitive data
|
|
200
|
+
payload.response = (0, helpers_2.redactObject)(responseData);
|
|
201
|
+
}
|
|
202
|
+
// Extract user-friendly error message for API errors
|
|
203
|
+
if ((_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.errorMessage) {
|
|
204
|
+
payload.userFriendlyMessage = response.data.errorMessage;
|
|
205
|
+
}
|
|
206
|
+
// Add stack trace only for non-API errors to avoid clutter
|
|
207
|
+
if (![errorTypes_1.ERROR_TYPES.API_ERROR, errorTypes_1.ERROR_TYPES.SERVER_ERROR].includes(this.determineErrorType(error))) {
|
|
208
|
+
payload.stack = (_b = error.stack) === null || _b === void 0 ? void 0 : _b.split('\n').slice(0, 5).join('\n');
|
|
209
|
+
}
|
|
210
|
+
return payload;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Extracts metadata from the error context and adds additional information.
|
|
214
|
+
*
|
|
215
|
+
* @param context - The error context to extract metadata from
|
|
216
|
+
* @param errorType - Optional error type to include in metadata
|
|
217
|
+
* @returns An object containing relevant metadata for debugging
|
|
218
|
+
*/
|
|
219
|
+
extractMeta(context, errorType) {
|
|
220
|
+
if (!context)
|
|
221
|
+
return {};
|
|
222
|
+
const baseMeta = {};
|
|
223
|
+
if (context.operation)
|
|
224
|
+
baseMeta.operation = context.operation;
|
|
225
|
+
if (context.component)
|
|
226
|
+
baseMeta.component = context.component;
|
|
227
|
+
if (context.userId)
|
|
228
|
+
baseMeta.userId = context.userId;
|
|
229
|
+
if (context.sessionId)
|
|
230
|
+
baseMeta.sessionId = context.sessionId;
|
|
231
|
+
if (context.orgId)
|
|
232
|
+
baseMeta.orgId = context.orgId;
|
|
233
|
+
if (errorType)
|
|
234
|
+
baseMeta.errorType = errorType;
|
|
235
|
+
if (context.email)
|
|
236
|
+
baseMeta.email = context.email;
|
|
237
|
+
return baseMeta;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Checks if error contains sensitive information.
|
|
241
|
+
*
|
|
242
|
+
* @param error - Error to check
|
|
243
|
+
* @returns True if sensitive info is found
|
|
244
|
+
*/
|
|
245
|
+
containsSensitiveInfo(error) {
|
|
246
|
+
try {
|
|
247
|
+
const content = `${error.message} ${error.stack || ''}`.toLowerCase();
|
|
248
|
+
const sensitiveTerms = [
|
|
249
|
+
'password',
|
|
250
|
+
'token',
|
|
251
|
+
'secret',
|
|
252
|
+
'credentials',
|
|
253
|
+
'api_key',
|
|
254
|
+
'api-key',
|
|
255
|
+
'authorization',
|
|
256
|
+
'sessionid',
|
|
257
|
+
'authtoken',
|
|
258
|
+
'x-api-key',
|
|
259
|
+
'tfa_token',
|
|
260
|
+
'otp',
|
|
261
|
+
'security_code',
|
|
262
|
+
'bearer',
|
|
263
|
+
'cookie',
|
|
264
|
+
];
|
|
265
|
+
return sensitiveTerms.some((term) => content.includes(term));
|
|
266
|
+
}
|
|
267
|
+
catch (_a) {
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
exports.default = CLIErrorHandler;
|
|
273
|
+
exports.CLIErrorHandler = CLIErrorHandler;
|
package/lib/logger/log.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { default as Logger } from './logger';
|
|
2
|
-
import { CLIErrorHandler } from './
|
|
2
|
+
import { CLIErrorHandler } from './cli-error-handler';
|
|
3
3
|
import { ErrorContext } from '../interfaces';
|
|
4
4
|
declare const v2Logger: Logger;
|
|
5
5
|
declare const cliErrorHandler: CLIErrorHandler;
|
|
@@ -19,5 +19,6 @@ declare const cliErrorHandler: CLIErrorHandler;
|
|
|
19
19
|
* - If debug information is available, it is logged separately with a more specific
|
|
20
20
|
* debug type and additional details.
|
|
21
21
|
*/
|
|
22
|
-
declare function handleAndLogError(error: unknown, context?: ErrorContext): void;
|
|
23
|
-
|
|
22
|
+
declare function handleAndLogError(error: unknown, context?: ErrorContext, errorMessage?: string): void;
|
|
23
|
+
declare function getLogPath(): string;
|
|
24
|
+
export { v2Logger, cliErrorHandler, handleAndLogError, getLogPath };
|
package/lib/logger/log.js
CHANGED
|
@@ -1,13 +1,34 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.handleAndLogError = exports.cliErrorHandler = exports.v2Logger = void 0;
|
|
3
|
+
exports.getLogPath = exports.handleAndLogError = exports.cliErrorHandler = exports.v2Logger = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const path = tslib_1.__importStar(require("path"));
|
|
6
6
|
const logger_1 = tslib_1.__importDefault(require("./logger"));
|
|
7
|
-
const
|
|
8
|
-
const
|
|
7
|
+
const cli_error_handler_1 = require("./cli-error-handler");
|
|
8
|
+
const __1 = require("..");
|
|
9
|
+
let loggerInstance = null;
|
|
10
|
+
function createLoggerInstance() {
|
|
11
|
+
const config = {
|
|
12
|
+
basePath: getLogPath(),
|
|
13
|
+
logLevel: __1.configHandler.get('log.level') || 'info',
|
|
14
|
+
};
|
|
15
|
+
return new logger_1.default(config);
|
|
16
|
+
}
|
|
17
|
+
// Lazy proxy object that behaves like a Logger
|
|
18
|
+
const v2Logger = new Proxy({}, {
|
|
19
|
+
get(_, prop) {
|
|
20
|
+
if (!loggerInstance) {
|
|
21
|
+
loggerInstance = createLoggerInstance();
|
|
22
|
+
}
|
|
23
|
+
const targetProp = loggerInstance[prop];
|
|
24
|
+
if (typeof targetProp === 'function') {
|
|
25
|
+
return targetProp.bind(loggerInstance);
|
|
26
|
+
}
|
|
27
|
+
return targetProp;
|
|
28
|
+
},
|
|
29
|
+
});
|
|
9
30
|
exports.v2Logger = v2Logger;
|
|
10
|
-
const cliErrorHandler = new
|
|
31
|
+
const cliErrorHandler = new cli_error_handler_1.CLIErrorHandler(); // Enable debug mode for error classification
|
|
11
32
|
exports.cliErrorHandler = cliErrorHandler;
|
|
12
33
|
/**
|
|
13
34
|
* Handles and logs an error by classifying it and logging the relevant details.
|
|
@@ -25,28 +46,21 @@ exports.cliErrorHandler = cliErrorHandler;
|
|
|
25
46
|
* - If debug information is available, it is logged separately with a more specific
|
|
26
47
|
* debug type and additional details.
|
|
27
48
|
*/
|
|
28
|
-
function handleAndLogError(error, context) {
|
|
29
|
-
|
|
49
|
+
function handleAndLogError(error, context, errorMessage) {
|
|
50
|
+
var _a;
|
|
51
|
+
const classified = cliErrorHandler.classifyError(error, context, errorMessage);
|
|
30
52
|
// Always log the error
|
|
31
53
|
v2Logger.logError({
|
|
32
54
|
type: classified.type,
|
|
33
|
-
message: classified.message,
|
|
55
|
+
message: errorMessage || ((_a = classified.error) === null || _a === void 0 ? void 0 : _a.message) || classified.message,
|
|
34
56
|
error: classified.error,
|
|
35
|
-
context: classified.context,
|
|
57
|
+
context: typeof classified.context === 'string' ? { message: classified.context } : classified.context,
|
|
36
58
|
hidden: classified.hidden,
|
|
37
59
|
meta: classified.meta,
|
|
38
60
|
});
|
|
39
|
-
// Log debug information if available
|
|
40
|
-
if (classified.debug) {
|
|
41
|
-
v2Logger.logDebug({
|
|
42
|
-
type: `${classified.type}_DEBUG`,
|
|
43
|
-
message: `${classified.message} [DEBUG]`,
|
|
44
|
-
debug: Object.assign(Object.assign({}, classified.debug), {
|
|
45
|
-
// Ensure stack trace is included if not already there
|
|
46
|
-
stackTrace: classified.debug.stackTrace || classified.error.stack }),
|
|
47
|
-
context: classified.context,
|
|
48
|
-
meta: classified.meta,
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
61
|
}
|
|
52
62
|
exports.handleAndLogError = handleAndLogError;
|
|
63
|
+
function getLogPath() {
|
|
64
|
+
return process.env.CS_CLI_LOG_PATH || __1.configHandler.get('log.path') || path.join(__dirname, 'logs');
|
|
65
|
+
}
|
|
66
|
+
exports.getLogPath = getLogPath;
|
package/lib/logger/logger.d.ts
CHANGED
|
@@ -11,7 +11,6 @@ export default class Logger {
|
|
|
11
11
|
private isSensitiveKey;
|
|
12
12
|
private redactObject;
|
|
13
13
|
private redact;
|
|
14
|
-
private isLogEntry;
|
|
15
14
|
private shouldLog;
|
|
16
15
|
error(message: string, meta?: any): void;
|
|
17
16
|
warn(message: string, meta?: any): void;
|
|
@@ -22,7 +21,7 @@ export default class Logger {
|
|
|
22
21
|
type: string;
|
|
23
22
|
message: string;
|
|
24
23
|
error: any;
|
|
25
|
-
context?: string
|
|
24
|
+
context?: Record<string, any>;
|
|
26
25
|
hidden?: boolean;
|
|
27
26
|
meta?: Record<string, any>;
|
|
28
27
|
}): void;
|
|
@@ -30,28 +29,28 @@ export default class Logger {
|
|
|
30
29
|
type: string;
|
|
31
30
|
message: string;
|
|
32
31
|
warn?: any;
|
|
33
|
-
context?: string
|
|
32
|
+
context?: Record<string, any>;
|
|
34
33
|
meta?: Record<string, any>;
|
|
35
34
|
}): void;
|
|
36
35
|
logInfo(params: {
|
|
37
36
|
type: string;
|
|
38
37
|
message: string;
|
|
39
38
|
info?: any;
|
|
40
|
-
context?: string
|
|
39
|
+
context?: Record<string, any>;
|
|
41
40
|
meta?: Record<string, any>;
|
|
42
41
|
}): void;
|
|
43
42
|
logSuccess(params: {
|
|
44
43
|
type: string;
|
|
45
44
|
message: string;
|
|
46
45
|
data?: any;
|
|
47
|
-
context?: string
|
|
46
|
+
context?: Record<string, any>;
|
|
48
47
|
meta?: Record<string, any>;
|
|
49
48
|
}): void;
|
|
50
49
|
logDebug(params: {
|
|
51
50
|
type: string;
|
|
52
51
|
message: string;
|
|
53
52
|
debug?: any;
|
|
54
|
-
context?: string
|
|
53
|
+
context?: Record<string, any>;
|
|
55
54
|
meta?: Record<string, any>;
|
|
56
55
|
}): void;
|
|
57
56
|
}
|
package/lib/logger/logger.js
CHANGED
|
@@ -18,8 +18,10 @@ class Logger {
|
|
|
18
18
|
/management[-._]?token/i,
|
|
19
19
|
/sessionid/i,
|
|
20
20
|
/orgid/i,
|
|
21
|
+
/stack/i,
|
|
21
22
|
];
|
|
22
23
|
this.config = config;
|
|
24
|
+
winston.addColors(logging_1.levelColors);
|
|
23
25
|
this.loggers = {
|
|
24
26
|
error: this.getLoggerInstance('error'),
|
|
25
27
|
warn: this.getLoggerInstance('warn'),
|
|
@@ -30,10 +32,7 @@ class Logger {
|
|
|
30
32
|
}
|
|
31
33
|
getLoggerInstance(level = 'info') {
|
|
32
34
|
const filePath = (0, path_1.normalize)(process.env.CS_CLI_LOG_PATH || this.config.basePath).replace(/^(\.\.(\/|\\|$))+/, '');
|
|
33
|
-
|
|
34
|
-
return this.createLogger('error', filePath);
|
|
35
|
-
}
|
|
36
|
-
return this.createLogger(level, filePath);
|
|
35
|
+
return this.createLogger(level === 'hidden' ? 'error' : level, filePath);
|
|
37
36
|
}
|
|
38
37
|
get loggerOptions() {
|
|
39
38
|
return {
|
|
@@ -46,31 +45,23 @@ class Logger {
|
|
|
46
45
|
createLogger(level, filePath) {
|
|
47
46
|
return winston.createLogger({
|
|
48
47
|
levels: logging_1.logLevels,
|
|
49
|
-
level
|
|
48
|
+
level,
|
|
50
49
|
transports: [
|
|
51
50
|
new winston.transports.File(Object.assign(Object.assign({}, this.loggerOptions), { filename: `${filePath}/${level}.log`, format: winston.format.combine(winston.format.timestamp(), winston.format.json()) })),
|
|
52
51
|
new winston.transports.Console({
|
|
53
52
|
format: winston.format.combine(winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.printf((info) => {
|
|
53
|
+
const redactedInfo = this.redact(info);
|
|
54
54
|
const colorizer = winston.format.colorize();
|
|
55
|
-
const levelText =
|
|
56
|
-
const timestamp =
|
|
57
|
-
|
|
58
|
-
const meta = info.meta;
|
|
59
|
-
let fullLine = `[${timestamp}] ${levelText}: ${message}`;
|
|
60
|
-
if (meta && (info.level !== 'info' && info.level !== 'success')) {
|
|
61
|
-
const redactedMeta = this.isLogEntry(meta) ? JSON.stringify(this.redact(meta)) : JSON.stringify(this.redact(meta));
|
|
62
|
-
fullLine += ` - ${redactedMeta}`;
|
|
63
|
-
}
|
|
64
|
-
return colorizer.colorize(info.level, fullLine);
|
|
55
|
+
const levelText = redactedInfo.level.toUpperCase();
|
|
56
|
+
const { timestamp, message } = redactedInfo;
|
|
57
|
+
return colorizer.colorize(redactedInfo.level, `[${timestamp}] ${levelText}: ${message}`);
|
|
65
58
|
})),
|
|
66
59
|
}),
|
|
67
60
|
],
|
|
68
61
|
});
|
|
69
62
|
}
|
|
70
63
|
isSensitiveKey(keyStr) {
|
|
71
|
-
return
|
|
72
|
-
? this.sensitiveKeys.some((regex) => regex.test(keyStr))
|
|
73
|
-
: false;
|
|
64
|
+
return typeof keyStr === 'string' ? this.sensitiveKeys.some((regex) => regex.test(keyStr)) : false;
|
|
74
65
|
}
|
|
75
66
|
redactObject(obj) {
|
|
76
67
|
const self = this;
|
|
@@ -89,43 +80,39 @@ class Logger {
|
|
|
89
80
|
this.redactObject(splat);
|
|
90
81
|
return copy;
|
|
91
82
|
}
|
|
92
|
-
catch (
|
|
83
|
+
catch (_a) {
|
|
93
84
|
return info;
|
|
94
85
|
}
|
|
95
86
|
}
|
|
96
|
-
isLogEntry(obj) {
|
|
97
|
-
return typeof obj === 'object' && 'level' in obj && 'message' in obj;
|
|
98
|
-
}
|
|
99
87
|
shouldLog(level, target) {
|
|
100
88
|
const configLevel = target === 'console' ? this.config.consoleLogLevel : this.config.logLevel;
|
|
101
|
-
const minLevel = configLevel ? logging_1.logLevels[configLevel] : 2;
|
|
102
|
-
|
|
103
|
-
return entryLevel <= minLevel;
|
|
89
|
+
const minLevel = configLevel ? logging_1.logLevels[configLevel] : 2;
|
|
90
|
+
return logging_1.logLevels[level] <= minLevel;
|
|
104
91
|
}
|
|
105
92
|
/* === Public Log Methods === */
|
|
106
93
|
error(message, meta) {
|
|
107
94
|
if (this.shouldLog('error', 'console') || this.shouldLog('error', 'file')) {
|
|
108
|
-
this.loggers.error.error(message, meta);
|
|
95
|
+
this.loggers.error.error(message, Object.assign(Object.assign({}, meta), { level: 'error' }));
|
|
109
96
|
}
|
|
110
97
|
}
|
|
111
98
|
warn(message, meta) {
|
|
112
99
|
if (this.shouldLog('warn', 'console') || this.shouldLog('warn', 'file')) {
|
|
113
|
-
this.loggers.warn.warn(message, meta);
|
|
100
|
+
this.loggers.warn.warn(message, Object.assign(Object.assign({}, meta), { level: 'warn' }));
|
|
114
101
|
}
|
|
115
102
|
}
|
|
116
103
|
info(message, meta) {
|
|
117
104
|
if (this.shouldLog('info', 'console') || this.shouldLog('info', 'file')) {
|
|
118
|
-
this.loggers.info.info(message, meta);
|
|
105
|
+
this.loggers.info.info(message, Object.assign(Object.assign({}, meta), { level: 'info' }));
|
|
119
106
|
}
|
|
120
107
|
}
|
|
121
108
|
success(message, meta) {
|
|
122
|
-
if (this.shouldLog('
|
|
123
|
-
this.loggers.success.
|
|
109
|
+
if (this.shouldLog('success', 'console') || this.shouldLog('success', 'file')) {
|
|
110
|
+
this.loggers.success.log('success', message, Object.assign({}, meta));
|
|
124
111
|
}
|
|
125
112
|
}
|
|
126
113
|
debug(message, meta) {
|
|
127
114
|
if (this.shouldLog('debug', 'console') || this.shouldLog('debug', 'file')) {
|
|
128
|
-
this.loggers.debug.debug(message, meta);
|
|
115
|
+
this.loggers.debug.debug(message, Object.assign(Object.assign({}, meta), { level: 'debug' }));
|
|
129
116
|
}
|
|
130
117
|
}
|
|
131
118
|
/* === Structured Logging === */
|
|
@@ -133,12 +120,16 @@ class Logger {
|
|
|
133
120
|
const logPayload = {
|
|
134
121
|
level: logging_1.logLevels.error,
|
|
135
122
|
message: params.message,
|
|
136
|
-
|
|
137
|
-
meta: Object.assign({ type: params.type, error: params.error, context: params.context }, params.meta),
|
|
123
|
+
meta: Object.assign(Object.assign({ type: params.type, error: params.error }, (params.context || {})), (params.meta || {})),
|
|
138
124
|
};
|
|
139
|
-
|
|
140
|
-
if (this.shouldLog(
|
|
141
|
-
this.loggers
|
|
125
|
+
// Always log to error file, but respect hidden parameter for console
|
|
126
|
+
if (this.shouldLog('error', 'file')) {
|
|
127
|
+
this.loggers.error.error(logPayload);
|
|
128
|
+
}
|
|
129
|
+
// For console, use debug level if hidden, otherwise error level
|
|
130
|
+
const consoleLevel = params.hidden ? 'debug' : 'error';
|
|
131
|
+
if (this.shouldLog(consoleLevel, 'console')) {
|
|
132
|
+
this.loggers[consoleLevel].error(logPayload);
|
|
142
133
|
}
|
|
143
134
|
}
|
|
144
135
|
logWarn(params) {
|
|
@@ -146,7 +137,7 @@ class Logger {
|
|
|
146
137
|
level: logging_1.logLevels.warn,
|
|
147
138
|
message: params.message,
|
|
148
139
|
timestamp: new Date(),
|
|
149
|
-
meta: Object.assign({ type: params.type,
|
|
140
|
+
meta: Object.assign(Object.assign({ type: params.type, warn: params.warn }, (params.context || {})), (params.meta || {})),
|
|
150
141
|
};
|
|
151
142
|
if (this.shouldLog('warn', 'console') || this.shouldLog('warn', 'file')) {
|
|
152
143
|
this.loggers.warn.warn(logPayload);
|
|
@@ -157,7 +148,7 @@ class Logger {
|
|
|
157
148
|
level: logging_1.logLevels.info,
|
|
158
149
|
message: params.message,
|
|
159
150
|
timestamp: new Date(),
|
|
160
|
-
meta: Object.assign({ type: params.type, info: params.info,
|
|
151
|
+
meta: Object.assign(Object.assign({ type: params.type, info: params.info }, (params.context || {})), (params.meta || {})),
|
|
161
152
|
};
|
|
162
153
|
if (this.shouldLog('info', 'console') || this.shouldLog('info', 'file')) {
|
|
163
154
|
this.loggers.info.info(logPayload);
|
|
@@ -165,21 +156,20 @@ class Logger {
|
|
|
165
156
|
}
|
|
166
157
|
logSuccess(params) {
|
|
167
158
|
const logPayload = {
|
|
168
|
-
level:
|
|
159
|
+
level: 'success',
|
|
169
160
|
message: params.message,
|
|
170
161
|
timestamp: new Date(),
|
|
171
|
-
meta: Object.assign({ type: params.type, data: params.data,
|
|
162
|
+
meta: Object.assign(Object.assign({ type: params.type, data: params.data }, (params.context || {})), (params.meta || {})),
|
|
172
163
|
};
|
|
173
|
-
if (this.shouldLog('
|
|
174
|
-
this.loggers.success.
|
|
164
|
+
if (this.shouldLog('success', 'console') || this.shouldLog('success', 'file')) {
|
|
165
|
+
this.loggers.success.log(logPayload);
|
|
175
166
|
}
|
|
176
167
|
}
|
|
177
168
|
logDebug(params) {
|
|
178
169
|
const logPayload = {
|
|
179
170
|
level: logging_1.logLevels.debug,
|
|
180
171
|
message: params.message,
|
|
181
|
-
|
|
182
|
-
meta: Object.assign({ type: params.type, debug: params.debug, context: params.context }, params.meta),
|
|
172
|
+
meta: Object.assign(Object.assign({ type: params.type, debug: params.debug }, (params.context || {})), (params.meta || {})),
|
|
183
173
|
};
|
|
184
174
|
if (this.shouldLog('debug', 'console') || this.shouldLog('debug', 'file')) {
|
|
185
175
|
this.loggers.debug.debug(logPayload);
|
package/package.json
CHANGED
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CLIErrorHandler = void 0;
|
|
4
|
-
const helpers_1 = require("../helpers");
|
|
5
|
-
const errorTypes_1 = require("../constants/errorTypes");
|
|
6
|
-
/**
|
|
7
|
-
* Handles errors in a CLI application by classifying, normalizing, and extracting
|
|
8
|
-
* relevant information for debugging and logging purposes.
|
|
9
|
-
*
|
|
10
|
-
* This class provides methods to:
|
|
11
|
-
* - Normalize unknown error types into standard `Error` objects.
|
|
12
|
-
* - Classify errors into predefined categories such as API errors, network errors,
|
|
13
|
-
* server errors, and more.
|
|
14
|
-
* - Extract detailed error payloads for logging, including HTTP request and response
|
|
15
|
-
* details when applicable.
|
|
16
|
-
* - Identify sensitive information in error messages to prevent accidental exposure.
|
|
17
|
-
* - Generate debug payloads for enhanced troubleshooting when debugging is enabled.
|
|
18
|
-
*
|
|
19
|
-
* @remarks
|
|
20
|
-
* This class is designed to handle a wide range of error types, including generic
|
|
21
|
-
* JavaScript errors, API errors, and custom error objects. It also supports
|
|
22
|
-
* optional debugging and context metadata for enhanced error reporting.
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* ```typescript
|
|
26
|
-
* const errorHandler = new CLIErrorHandler(true);
|
|
27
|
-
*
|
|
28
|
-
* try {
|
|
29
|
-
* // Some operation that may throw an error
|
|
30
|
-
* } catch (error) {
|
|
31
|
-
* const classifiedError = errorHandler.classifyError(error, {
|
|
32
|
-
* operation: 'fetchData',
|
|
33
|
-
* component: 'DataService',
|
|
34
|
-
* });
|
|
35
|
-
* console.error(classifiedError);
|
|
36
|
-
* }
|
|
37
|
-
* ```
|
|
38
|
-
*
|
|
39
|
-
* @public
|
|
40
|
-
*/
|
|
41
|
-
class CLIErrorHandler {
|
|
42
|
-
constructor(isDebug = false) {
|
|
43
|
-
this.isDebug = isDebug;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Classifies an error into a structured format for better handling and debugging.
|
|
47
|
-
*
|
|
48
|
-
* @param error - The error object to classify. Can be of any type.
|
|
49
|
-
* @param context - Optional additional context about the error, typically used to provide
|
|
50
|
-
* more information about where or why the error occurred.
|
|
51
|
-
*
|
|
52
|
-
* @returns A `ClassifiedError` object containing details about the error, including its type,
|
|
53
|
-
* message, payload, context, metadata, and whether it contains sensitive information.
|
|
54
|
-
* If the error is an API error or debugging is enabled, additional debug information
|
|
55
|
-
* is included.
|
|
56
|
-
*
|
|
57
|
-
* @throws This method handles its own errors and will return a `ClassifiedError` with type
|
|
58
|
-
* `ERROR_TYPES.NORMALIZATION` if it fails to normalize or classify the input error.
|
|
59
|
-
*/
|
|
60
|
-
classifyError(error, context) {
|
|
61
|
-
try {
|
|
62
|
-
const normalized = this.normalizeToError(error);
|
|
63
|
-
const isApi = this.isApiError(normalized);
|
|
64
|
-
const type = this.determineErrorType(normalized);
|
|
65
|
-
const hidden = this.containsSensitiveInfo(normalized);
|
|
66
|
-
const result = {
|
|
67
|
-
type,
|
|
68
|
-
message: normalized.message || 'Unhandled error',
|
|
69
|
-
error: this.extractErrorPayload(normalized),
|
|
70
|
-
context: context ? JSON.stringify(context) : undefined,
|
|
71
|
-
meta: this.extractMeta(context),
|
|
72
|
-
hidden,
|
|
73
|
-
};
|
|
74
|
-
if (isApi || this.isDebug) {
|
|
75
|
-
result.debug = this.extractDebugPayload(normalized, context);
|
|
76
|
-
}
|
|
77
|
-
return result;
|
|
78
|
-
}
|
|
79
|
-
catch (e) {
|
|
80
|
-
return {
|
|
81
|
-
type: errorTypes_1.ERROR_TYPES.NORMALIZATION,
|
|
82
|
-
message: 'Failed to normalize or classify error',
|
|
83
|
-
error: { message: String(e) },
|
|
84
|
-
context: context ? JSON.stringify(context) : undefined,
|
|
85
|
-
meta: this.extractMeta(context),
|
|
86
|
-
hidden: false,
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
normalizeToError(error) {
|
|
91
|
-
if (!error)
|
|
92
|
-
return new Error('Unknown error occurred');
|
|
93
|
-
if (error instanceof Error)
|
|
94
|
-
return error;
|
|
95
|
-
if (typeof error === 'string')
|
|
96
|
-
return new Error(error);
|
|
97
|
-
if (typeof error === 'object') {
|
|
98
|
-
try {
|
|
99
|
-
const msg = error.message;
|
|
100
|
-
const err = new Error(msg || 'Unknown error');
|
|
101
|
-
Object.assign(err, error);
|
|
102
|
-
return err;
|
|
103
|
-
}
|
|
104
|
-
catch (_a) {
|
|
105
|
-
return new Error(JSON.stringify(error));
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
return new Error(String(error));
|
|
109
|
-
}
|
|
110
|
-
isApiError(error) {
|
|
111
|
-
return (error.isAxiosError ||
|
|
112
|
-
typeof error.status === 'number' ||
|
|
113
|
-
typeof error.statusText === 'string' ||
|
|
114
|
-
error.request !== undefined);
|
|
115
|
-
}
|
|
116
|
-
determineErrorType(error) {
|
|
117
|
-
var _a;
|
|
118
|
-
const status = error.status || ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status);
|
|
119
|
-
//Ignore 4XX errors
|
|
120
|
-
if (status >= 400 && status < 500) {
|
|
121
|
-
return errorTypes_1.ERROR_TYPES.API_ERROR;
|
|
122
|
-
}
|
|
123
|
-
//Server-side HTTP errors
|
|
124
|
-
if (status >= 500) {
|
|
125
|
-
return errorTypes_1.ERROR_TYPES.SERVER_ERROR;
|
|
126
|
-
}
|
|
127
|
-
//Network-related error
|
|
128
|
-
if (error.code === 'ECONNREFUSED' || error.code === 'ENOTFOUND' || error.code === 'ETIMEDOUT') {
|
|
129
|
-
return errorTypes_1.ERROR_TYPES.NETWORK;
|
|
130
|
-
}
|
|
131
|
-
//Database error
|
|
132
|
-
if (error.name === 'DatabaseError') {
|
|
133
|
-
return errorTypes_1.ERROR_TYPES.DATABASE;
|
|
134
|
-
}
|
|
135
|
-
//Axios errors without 4XX
|
|
136
|
-
if (error.isAxiosError) {
|
|
137
|
-
return errorTypes_1.ERROR_TYPES.NETWORK;
|
|
138
|
-
}
|
|
139
|
-
//Default
|
|
140
|
-
return errorTypes_1.ERROR_TYPES.APPLICATION;
|
|
141
|
-
}
|
|
142
|
-
extractErrorPayload(error) {
|
|
143
|
-
var _a, _b, _c, _d, _e, _f;
|
|
144
|
-
const code = error.code || error.errorCode;
|
|
145
|
-
const status = error.status || ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status);
|
|
146
|
-
const statusText = error.statusText || ((_b = error.response) === null || _b === void 0 ? void 0 : _b.statusText);
|
|
147
|
-
const method = ((_c = error.request) === null || _c === void 0 ? void 0 : _c.method) || ((_d = error.config) === null || _d === void 0 ? void 0 : _d.method) || 'UNKNOWN';
|
|
148
|
-
const url = ((_e = error.request) === null || _e === void 0 ? void 0 : _e.url) || ((_f = error.config) === null || _f === void 0 ? void 0 : _f.url);
|
|
149
|
-
const endpoint = url ? new URL(url, 'http://dummy').pathname : 'UNKNOWN';
|
|
150
|
-
const payload = {
|
|
151
|
-
name: error.name,
|
|
152
|
-
message: (0, helpers_1.formatError)(error),
|
|
153
|
-
code,
|
|
154
|
-
status,
|
|
155
|
-
statusText,
|
|
156
|
-
method,
|
|
157
|
-
endpoint,
|
|
158
|
-
};
|
|
159
|
-
if (this.isDebug) {
|
|
160
|
-
payload.stack = error.stack;
|
|
161
|
-
}
|
|
162
|
-
return payload;
|
|
163
|
-
}
|
|
164
|
-
extractDebugPayload(error, context) {
|
|
165
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
166
|
-
const method = ((_a = error.request) === null || _a === void 0 ? void 0 : _a.method) || ((_b = error.config) === null || _b === void 0 ? void 0 : _b.method);
|
|
167
|
-
const url = ((_c = error.request) === null || _c === void 0 ? void 0 : _c.url) || ((_d = error.config) === null || _d === void 0 ? void 0 : _d.url);
|
|
168
|
-
const status = error.status || ((_e = error.response) === null || _e === void 0 ? void 0 : _e.status);
|
|
169
|
-
const statusText = error.statusText || ((_f = error.response) === null || _f === void 0 ? void 0 : _f.statusText);
|
|
170
|
-
const data = error.data || ((_g = error.response) === null || _g === void 0 ? void 0 : _g.data) || error.errors || error.error;
|
|
171
|
-
return {
|
|
172
|
-
command: context === null || context === void 0 ? void 0 : context.operation,
|
|
173
|
-
module: context === null || context === void 0 ? void 0 : context.component,
|
|
174
|
-
request: {
|
|
175
|
-
method,
|
|
176
|
-
url,
|
|
177
|
-
headers: (_h = error.request) === null || _h === void 0 ? void 0 : _h.headers,
|
|
178
|
-
data: (_j = error.request) === null || _j === void 0 ? void 0 : _j.data,
|
|
179
|
-
},
|
|
180
|
-
response: {
|
|
181
|
-
status,
|
|
182
|
-
statusText,
|
|
183
|
-
data,
|
|
184
|
-
},
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
extractMeta(context) {
|
|
188
|
-
return {
|
|
189
|
-
email: context === null || context === void 0 ? void 0 : context.email,
|
|
190
|
-
sessionId: context === null || context === void 0 ? void 0 : context.sessionId,
|
|
191
|
-
userId: context === null || context === void 0 ? void 0 : context.userId,
|
|
192
|
-
apiKey: context === null || context === void 0 ? void 0 : context.apiKey,
|
|
193
|
-
orgId: context === null || context === void 0 ? void 0 : context.orgId,
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
containsSensitiveInfo(error) {
|
|
197
|
-
try {
|
|
198
|
-
const content = `${error.message} ${error.stack || ''}`.toLowerCase();
|
|
199
|
-
return [
|
|
200
|
-
'password',
|
|
201
|
-
'token',
|
|
202
|
-
'secret',
|
|
203
|
-
'credentials',
|
|
204
|
-
'api_key',
|
|
205
|
-
'api-key',
|
|
206
|
-
'authorization',
|
|
207
|
-
'sessionid',
|
|
208
|
-
'email',
|
|
209
|
-
].some((term) => content.includes(term));
|
|
210
|
-
}
|
|
211
|
-
catch (_a) {
|
|
212
|
-
return false;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
exports.default = CLIErrorHandler;
|
|
217
|
-
exports.CLIErrorHandler = CLIErrorHandler;
|