@contentstack/cli-utilities 1.13.1 → 1.13.2
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/helpers.js +9 -6
- package/lib/logger/cli-error-handler.js +38 -7
- package/lib/logger/logger.d.ts +2 -1
- package/lib/logger/logger.js +21 -11
- package/package.json +1 -1
package/lib/helpers.js
CHANGED
|
@@ -157,7 +157,7 @@ const formatError = function (error) {
|
|
|
157
157
|
// message is not in JSON format, no need to parse
|
|
158
158
|
}
|
|
159
159
|
// Append detailed error information if available
|
|
160
|
-
if (parsedError.errors && Object.keys(parsedError.errors).length > 0) {
|
|
160
|
+
if (parsedError.errors && typeof parsedError.errors === 'object' && Object.keys(parsedError.errors).length > 0) {
|
|
161
161
|
const entityNames = {
|
|
162
162
|
authorization: 'Authentication',
|
|
163
163
|
api_key: 'Stack API key',
|
|
@@ -165,11 +165,14 @@ const formatError = function (error) {
|
|
|
165
165
|
// deepcode ignore HardcodedNonCryptoSecret: The hardcoded value 'access_token' is used as a key in an error message mapping object and does not represent a sensitive secret or cryptographic key.
|
|
166
166
|
access_token: 'Delivery Token',
|
|
167
167
|
};
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
168
|
+
const errorList = Object.entries(parsedError.errors)
|
|
169
|
+
.map(([field, errors]) => {
|
|
170
|
+
const errorArray = Array.isArray(errors) ? errors : [errors];
|
|
171
|
+
const fieldName = entityNames[field] || field;
|
|
172
|
+
return ` • ${fieldName}: ${errorArray.join(', ')}`;
|
|
173
|
+
})
|
|
174
|
+
.join('\n');
|
|
175
|
+
message += `\n\nAPI Errors:\n${errorList}`;
|
|
173
176
|
}
|
|
174
177
|
return message;
|
|
175
178
|
};
|
|
@@ -82,7 +82,7 @@ class CLIErrorHandler {
|
|
|
82
82
|
* Extracts a clear, concise error message from various error types.
|
|
83
83
|
*/
|
|
84
84
|
extractClearMessage(error) {
|
|
85
|
-
var _a, _b;
|
|
85
|
+
var _a, _b, _c, _d;
|
|
86
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
87
|
return error.response.data.errorMessage;
|
|
88
88
|
}
|
|
@@ -94,8 +94,14 @@ class CLIErrorHandler {
|
|
|
94
94
|
const formattedMessage = (0, helpers_1.formatError)(error);
|
|
95
95
|
return formattedMessage || 'An error occurred. Please try again.';
|
|
96
96
|
}
|
|
97
|
-
catch (
|
|
98
|
-
|
|
97
|
+
catch (_e) {
|
|
98
|
+
// Fallback to basic error message extraction if formatError fails
|
|
99
|
+
if (typeof ((_d = (_c = error === null || error === void 0 ? void 0 : error.response) === null || _c === void 0 ? void 0 : _c.data) === null || _d === void 0 ? void 0 : _d.errorMessage) === 'string') {
|
|
100
|
+
return error.response.data.errorMessage;
|
|
101
|
+
}
|
|
102
|
+
if (typeof (error === null || error === void 0 ? void 0 : error.errorMessage) === 'string') {
|
|
103
|
+
return error.errorMessage;
|
|
104
|
+
}
|
|
99
105
|
}
|
|
100
106
|
}
|
|
101
107
|
/**
|
|
@@ -117,7 +123,18 @@ class CLIErrorHandler {
|
|
|
117
123
|
const message = errorObj.message || errorObj.error || errorObj.statusText || 'Unknown error';
|
|
118
124
|
const normalizedError = new Error(message);
|
|
119
125
|
// Only copy essential properties
|
|
120
|
-
const essentialProps = [
|
|
126
|
+
const essentialProps = [
|
|
127
|
+
'code',
|
|
128
|
+
'status',
|
|
129
|
+
'statusText',
|
|
130
|
+
'response',
|
|
131
|
+
'request',
|
|
132
|
+
'message',
|
|
133
|
+
'errorMessage',
|
|
134
|
+
'error_message',
|
|
135
|
+
'error',
|
|
136
|
+
'errors',
|
|
137
|
+
];
|
|
121
138
|
essentialProps.forEach((prop) => {
|
|
122
139
|
if (errorObj[prop] !== undefined) {
|
|
123
140
|
normalizedError[prop] = errorObj[prop];
|
|
@@ -163,7 +180,7 @@ class CLIErrorHandler {
|
|
|
163
180
|
* Extracts only essential error payload information for clear debugging.
|
|
164
181
|
*/
|
|
165
182
|
extractErrorPayload(error) {
|
|
166
|
-
var _a, _b;
|
|
183
|
+
var _a, _b, _c, _d;
|
|
167
184
|
const { name, message, code, status, response, request, config, statusText } = error;
|
|
168
185
|
const payload = {
|
|
169
186
|
name,
|
|
@@ -174,6 +191,20 @@ class CLIErrorHandler {
|
|
|
174
191
|
payload.code = code;
|
|
175
192
|
if (status || (response === null || response === void 0 ? void 0 : response.status))
|
|
176
193
|
payload.status = status || (response === null || response === void 0 ? void 0 : response.status);
|
|
194
|
+
// Add detailed field-level errors if available
|
|
195
|
+
if (((_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.errors) && typeof response.data.errors === 'object') {
|
|
196
|
+
payload.errors = response.data.errors;
|
|
197
|
+
}
|
|
198
|
+
else if ((error === null || error === void 0 ? void 0 : error.errors) && typeof error.errors === 'object') {
|
|
199
|
+
payload.errors = error.errors;
|
|
200
|
+
}
|
|
201
|
+
// Add error code if available
|
|
202
|
+
if ((_b = response === null || response === void 0 ? void 0 : response.data) === null || _b === void 0 ? void 0 : _b.error_code) {
|
|
203
|
+
payload.errorCode = response.data.error_code;
|
|
204
|
+
}
|
|
205
|
+
else if (error === null || error === void 0 ? void 0 : error.error_code) {
|
|
206
|
+
payload.errorCode = error.error_code;
|
|
207
|
+
}
|
|
177
208
|
// Add request context with sensitive data redaction
|
|
178
209
|
if (request || config) {
|
|
179
210
|
const requestData = {
|
|
@@ -200,12 +231,12 @@ class CLIErrorHandler {
|
|
|
200
231
|
payload.response = (0, helpers_2.redactObject)(responseData);
|
|
201
232
|
}
|
|
202
233
|
// Extract user-friendly error message for API errors
|
|
203
|
-
if ((
|
|
234
|
+
if ((_c = response === null || response === void 0 ? void 0 : response.data) === null || _c === void 0 ? void 0 : _c.errorMessage) {
|
|
204
235
|
payload.userFriendlyMessage = response.data.errorMessage;
|
|
205
236
|
}
|
|
206
237
|
// Add stack trace only for non-API errors to avoid clutter
|
|
207
238
|
if (![errorTypes_1.ERROR_TYPES.API_ERROR, errorTypes_1.ERROR_TYPES.SERVER_ERROR].includes(this.determineErrorType(error))) {
|
|
208
|
-
payload.stack = (
|
|
239
|
+
payload.stack = (_d = error.stack) === null || _d === void 0 ? void 0 : _d.split('\n').slice(0, 5).join('\n');
|
|
209
240
|
}
|
|
210
241
|
return payload;
|
|
211
242
|
}
|
package/lib/logger/logger.d.ts
CHANGED
|
@@ -3,7 +3,8 @@ import { LoggerConfig } from '../interfaces/index';
|
|
|
3
3
|
export default class Logger {
|
|
4
4
|
private loggers;
|
|
5
5
|
private config;
|
|
6
|
-
private
|
|
6
|
+
private consoleSensitiveKeys;
|
|
7
|
+
private logSensitiveKeys;
|
|
7
8
|
constructor(config: LoggerConfig);
|
|
8
9
|
getLoggerInstance(level?: 'error' | 'info' | 'warn' | 'debug' | 'hidden'): winston.Logger;
|
|
9
10
|
private get loggerOptions();
|
package/lib/logger/logger.js
CHANGED
|
@@ -8,9 +8,8 @@ const winston = tslib_1.__importStar(require("winston"));
|
|
|
8
8
|
const logging_1 = require("../constants/logging");
|
|
9
9
|
class Logger {
|
|
10
10
|
constructor(config) {
|
|
11
|
-
this.
|
|
11
|
+
this.consoleSensitiveKeys = [
|
|
12
12
|
/authtoken/i,
|
|
13
|
-
/^email$/i,
|
|
14
13
|
/^password$/i,
|
|
15
14
|
/secret/i,
|
|
16
15
|
/token/i,
|
|
@@ -20,6 +19,7 @@ class Logger {
|
|
|
20
19
|
/orgid/i,
|
|
21
20
|
/stack/i,
|
|
22
21
|
];
|
|
22
|
+
this.logSensitiveKeys = [/authtoken/i, /secret/i, /token/i, /management[-._]?token/i, /delivery[-._]?token/i];
|
|
23
23
|
this.config = config;
|
|
24
24
|
winston.addColors(logging_1.levelColors);
|
|
25
25
|
this.loggers = {
|
|
@@ -47,10 +47,15 @@ class Logger {
|
|
|
47
47
|
levels: logging_1.logLevels,
|
|
48
48
|
level,
|
|
49
49
|
transports: [
|
|
50
|
-
new winston.transports.File(Object.assign(Object.assign({}, this.loggerOptions), { filename: `${filePath}/${level}.log`, format: winston.format.combine(winston.format.timestamp(), winston.format.
|
|
50
|
+
new winston.transports.File(Object.assign(Object.assign({}, this.loggerOptions), { filename: `${filePath}/${level}.log`, format: winston.format.combine(winston.format.timestamp(), winston.format.printf((info) => {
|
|
51
|
+
// Apply minimal redaction for files (debugging info preserved)
|
|
52
|
+
const redactedInfo = this.redact(info, false);
|
|
53
|
+
return JSON.stringify(redactedInfo);
|
|
54
|
+
})) })),
|
|
51
55
|
new winston.transports.Console({
|
|
52
56
|
format: winston.format.combine(winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.printf((info) => {
|
|
53
|
-
|
|
57
|
+
// Apply full redaction for console (user-facing)
|
|
58
|
+
const redactedInfo = this.redact(info, true);
|
|
54
59
|
const colorizer = winston.format.colorize();
|
|
55
60
|
const levelText = redactedInfo.level.toUpperCase();
|
|
56
61
|
const { timestamp, message } = redactedInfo;
|
|
@@ -60,24 +65,29 @@ class Logger {
|
|
|
60
65
|
],
|
|
61
66
|
});
|
|
62
67
|
}
|
|
63
|
-
isSensitiveKey(keyStr) {
|
|
64
|
-
|
|
68
|
+
isSensitiveKey(keyStr, consoleMode = false) {
|
|
69
|
+
if (keyStr && typeof keyStr === 'string') {
|
|
70
|
+
const keysToCheck = consoleMode ? this.consoleSensitiveKeys : this.logSensitiveKeys;
|
|
71
|
+
return keysToCheck.some((regex) => regex.test(keyStr));
|
|
72
|
+
}
|
|
73
|
+
return false;
|
|
65
74
|
}
|
|
66
|
-
redactObject(obj) {
|
|
75
|
+
redactObject(obj, consoleMode = false) {
|
|
67
76
|
const self = this;
|
|
68
77
|
(0, traverse_1.default)(obj).forEach(function redactor() {
|
|
69
|
-
if (this.key && self.isSensitiveKey(this.key)) {
|
|
78
|
+
if (this.key && self.isSensitiveKey(this.key, consoleMode)) {
|
|
70
79
|
this.update('[REDACTED]');
|
|
71
80
|
}
|
|
72
81
|
});
|
|
82
|
+
return obj;
|
|
73
83
|
}
|
|
74
|
-
redact(info) {
|
|
84
|
+
redact(info, consoleMode = false) {
|
|
75
85
|
try {
|
|
76
86
|
const copy = (0, full_1.klona)(info);
|
|
77
|
-
this.redactObject(copy);
|
|
87
|
+
this.redactObject(copy, consoleMode);
|
|
78
88
|
const splat = copy[Symbol.for('splat')];
|
|
79
89
|
if (splat)
|
|
80
|
-
this.redactObject(splat);
|
|
90
|
+
this.redactObject(splat, consoleMode);
|
|
81
91
|
return copy;
|
|
82
92
|
}
|
|
83
93
|
catch (_a) {
|