@contentstack/cli-utilities 1.14.0 → 1.14.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/auth-handler.d.ts +2 -0
- package/lib/auth-handler.js +24 -1
- package/lib/authentication-handler.js +20 -11
- package/lib/helpers.d.ts +1 -1
- package/lib/helpers.js +30 -27
- package/lib/logger/cli-error-handler.js +3 -9
- package/lib/logger/log.js +7 -1
- package/lib/logger/logger.js +4 -0
- package/package.json +1 -1
package/lib/auth-handler.d.ts
CHANGED
|
@@ -25,8 +25,10 @@ declare class AuthHandler {
|
|
|
25
25
|
private oauthHandler;
|
|
26
26
|
private managementAPIClient;
|
|
27
27
|
private isRefreshingToken;
|
|
28
|
+
private cmaHost;
|
|
28
29
|
set host(contentStackHost: any);
|
|
29
30
|
constructor();
|
|
31
|
+
private getCmaHost;
|
|
30
32
|
initLog(): void;
|
|
31
33
|
setOAuthBaseURL(): Promise<void>;
|
|
32
34
|
initSDK(): Promise<void>;
|
package/lib/auth-handler.js
CHANGED
|
@@ -18,6 +18,8 @@ dotenv_1.default.config();
|
|
|
18
18
|
class AuthHandler {
|
|
19
19
|
set host(contentStackHost) {
|
|
20
20
|
this._host = contentStackHost;
|
|
21
|
+
// Update cmaHost when host is set
|
|
22
|
+
this.cmaHost = this.getCmaHost();
|
|
21
23
|
}
|
|
22
24
|
constructor() {
|
|
23
25
|
this.isRefreshingToken = false; // Flag to track if a refresh operation is in progress
|
|
@@ -55,6 +57,25 @@ class AuthHandler {
|
|
|
55
57
|
this.authorisationTypeKeyName,
|
|
56
58
|
],
|
|
57
59
|
};
|
|
60
|
+
this.cmaHost = this.getCmaHost();
|
|
61
|
+
}
|
|
62
|
+
getCmaHost() {
|
|
63
|
+
var _a;
|
|
64
|
+
if (this._host) {
|
|
65
|
+
return this._host;
|
|
66
|
+
}
|
|
67
|
+
const cma = (_a = config_handler_1.default.get('region')) === null || _a === void 0 ? void 0 : _a.cma;
|
|
68
|
+
if (cma && cma.startsWith('http')) {
|
|
69
|
+
try {
|
|
70
|
+
const u = new URL(cma);
|
|
71
|
+
if (u.host)
|
|
72
|
+
return u.host;
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
// If URL parsing fails, return the original cma value
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return cma;
|
|
58
79
|
}
|
|
59
80
|
initLog() {
|
|
60
81
|
this.logger = new logger_1.LoggerService(process.cwd(), 'cli-log');
|
|
@@ -68,7 +89,9 @@ class AuthHandler {
|
|
|
68
89
|
}
|
|
69
90
|
}
|
|
70
91
|
async initSDK() {
|
|
71
|
-
|
|
92
|
+
// Ensure we have a valid host for the SDK initialization
|
|
93
|
+
const host = this._host || this.getCmaHost();
|
|
94
|
+
this.managementAPIClient = await (0, contentstack_management_sdk_1.default)({ host });
|
|
72
95
|
this.oauthHandler = this.managementAPIClient.oauth({
|
|
73
96
|
appId: this.OAuthAppId,
|
|
74
97
|
clientId: this.OAuthClientId,
|
|
@@ -26,16 +26,17 @@ class AuthenticationHandler {
|
|
|
26
26
|
index_1.cliux.print('Session timed out, please login to proceed', {
|
|
27
27
|
color: 'yellow',
|
|
28
28
|
});
|
|
29
|
-
|
|
29
|
+
throw new Error('Session timed out, please login to proceed');
|
|
30
30
|
}
|
|
31
31
|
break;
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
catch (error) {
|
|
35
|
-
|
|
35
|
+
const formattedError = (0, index_1.formatError)(error);
|
|
36
|
+
index_1.cliux.print(`Error occurred while fetching auth details: ${formattedError}`, {
|
|
36
37
|
color: 'red',
|
|
37
38
|
});
|
|
38
|
-
|
|
39
|
+
throw error;
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
get isOauthEnabled() {
|
|
@@ -48,6 +49,7 @@ class AuthenticationHandler {
|
|
|
48
49
|
return this.token;
|
|
49
50
|
}
|
|
50
51
|
async refreshAccessToken(error, maxRetryCount = 1) {
|
|
52
|
+
var _a, _b;
|
|
51
53
|
// Add configurable delay only for CI/CD pipelines
|
|
52
54
|
const delayMs = process.env.DELAY_MS;
|
|
53
55
|
if (delayMs) {
|
|
@@ -71,7 +73,8 @@ class AuthenticationHandler {
|
|
|
71
73
|
if (refreshed) {
|
|
72
74
|
return this.refreshAccessToken(error, maxRetryCount); // Retry after refreshing the token
|
|
73
75
|
}
|
|
74
|
-
|
|
76
|
+
const errorDetails = (0, index_1.formatError)(error);
|
|
77
|
+
index_1.cliux.print(`Authentication failed: ${errorDetails}`, { color: 'red' });
|
|
75
78
|
// For Basic Auth, exit immediately without retrying
|
|
76
79
|
return;
|
|
77
80
|
}
|
|
@@ -79,10 +82,12 @@ class AuthenticationHandler {
|
|
|
79
82
|
case 429:
|
|
80
83
|
case 408:
|
|
81
84
|
if (maxRetryCount >= 3) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
});
|
|
85
|
-
|
|
85
|
+
const errorDetails = (0, index_1.formatError)(error);
|
|
86
|
+
const statusText = ((_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.status) === 429 ? 'Rate Limited' : 'Request Timeout';
|
|
87
|
+
index_1.cliux.print(`Max retry attempts exceeded (${maxRetryCount}/3)`, { color: 'red' });
|
|
88
|
+
index_1.cliux.print(`Status: ${(_b = error === null || error === void 0 ? void 0 : error.response) === null || _b === void 0 ? void 0 : _b.status} - ${statusText}`, { color: 'yellow' });
|
|
89
|
+
index_1.cliux.print(`Error: ${errorDetails}`, { color: 'white' });
|
|
90
|
+
return;
|
|
86
91
|
}
|
|
87
92
|
maxRetryCount++; // Increment for the next retry attempt
|
|
88
93
|
// These cases require a wait, adding a delay before retrying
|
|
@@ -99,7 +104,9 @@ class AuthenticationHandler {
|
|
|
99
104
|
index_1.cliux.print('Session timed out, please login to proceed', {
|
|
100
105
|
color: 'yellow',
|
|
101
106
|
});
|
|
102
|
-
|
|
107
|
+
index_1.cliux.print('\nTo fix this:', { color: 'cyan' });
|
|
108
|
+
index_1.cliux.print('• Run: "csdx auth:login"', { color: 'white' });
|
|
109
|
+
resolve(false);
|
|
103
110
|
}
|
|
104
111
|
else if (this.authType === 'OAUTH') {
|
|
105
112
|
index_1.authHandler.host = hostName;
|
|
@@ -111,7 +118,9 @@ class AuthenticationHandler {
|
|
|
111
118
|
resolve(true);
|
|
112
119
|
})
|
|
113
120
|
.catch((error) => {
|
|
114
|
-
|
|
121
|
+
const errorDetails = (0, index_1.formatError)(error);
|
|
122
|
+
index_1.cliux.print('OAuth Token Refresh Failed', { color: 'red' });
|
|
123
|
+
index_1.cliux.print(`Error: ${errorDetails}`, { color: 'white' });
|
|
115
124
|
resolve(false);
|
|
116
125
|
});
|
|
117
126
|
}
|
|
@@ -119,7 +128,7 @@ class AuthenticationHandler {
|
|
|
119
128
|
index_1.cliux.print('You do not have the permissions to perform this action, please login to proceed', {
|
|
120
129
|
color: 'yellow',
|
|
121
130
|
});
|
|
122
|
-
|
|
131
|
+
resolve(false);
|
|
123
132
|
}
|
|
124
133
|
});
|
|
125
134
|
}
|
package/lib/helpers.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export declare const sanitizePath: (str: string) => string;
|
|
|
19
19
|
export declare const validateUids: (uid: any) => boolean;
|
|
20
20
|
export declare const validateFileName: (fileName: any) => boolean;
|
|
21
21
|
export declare const validateRegex: (str: unknown) => import("recheck").Diagnostics;
|
|
22
|
-
export declare const formatError: (error: any) =>
|
|
22
|
+
export declare const formatError: (error: any) => string;
|
|
23
23
|
/**
|
|
24
24
|
* The function redactObject takes an object as input and replaces any sensitive keys with the string
|
|
25
25
|
* '[REDACTED]'.
|
package/lib/helpers.js
CHANGED
|
@@ -102,7 +102,7 @@ const validateRegex = (str) => {
|
|
|
102
102
|
};
|
|
103
103
|
exports.validateRegex = validateRegex;
|
|
104
104
|
const formatError = function (error) {
|
|
105
|
-
var _a, _b, _c, _d, _e;
|
|
105
|
+
var _a, _b, _c, _d, _e, _f;
|
|
106
106
|
let parsedError;
|
|
107
107
|
// Parse the error
|
|
108
108
|
try {
|
|
@@ -119,6 +119,26 @@ const formatError = function (error) {
|
|
|
119
119
|
catch (e) {
|
|
120
120
|
parsedError = error;
|
|
121
121
|
}
|
|
122
|
+
// Helper function to append error details
|
|
123
|
+
const appendErrorDetails = (message, errorObj) => {
|
|
124
|
+
if (errorObj.errors && typeof errorObj.errors === 'object' && Object.keys(errorObj.errors).length > 0) {
|
|
125
|
+
const entityNames = {
|
|
126
|
+
authorization: 'Authentication',
|
|
127
|
+
api_key: 'Stack API key',
|
|
128
|
+
uid: 'Content Type',
|
|
129
|
+
access_token: 'Delivery Token',
|
|
130
|
+
};
|
|
131
|
+
const errorList = Object.entries(errorObj.errors)
|
|
132
|
+
.map(([field, errors]) => {
|
|
133
|
+
const errorArray = Array.isArray(errors) ? errors : [errors];
|
|
134
|
+
const fieldName = entityNames[field] || field;
|
|
135
|
+
return ` • ${fieldName}: ${errorArray.join(', ')}`;
|
|
136
|
+
})
|
|
137
|
+
.join('\n');
|
|
138
|
+
return `${message}\n\nError Details:\n${errorList}\n`;
|
|
139
|
+
}
|
|
140
|
+
return message;
|
|
141
|
+
};
|
|
122
142
|
if (parsedError && typeof parsedError === 'object' && Object.keys(parsedError).length === 0) {
|
|
123
143
|
if (!parsedError.message &&
|
|
124
144
|
!parsedError.code &&
|
|
@@ -129,21 +149,21 @@ const formatError = function (error) {
|
|
|
129
149
|
}
|
|
130
150
|
}
|
|
131
151
|
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) {
|
|
132
|
-
return parsedError.response.data.errorMessage;
|
|
152
|
+
return appendErrorDetails(parsedError.response.data.errorMessage, ((_c = parsedError === null || parsedError === void 0 ? void 0 : parsedError.response) === null || _c === void 0 ? void 0 : _c.data) || parsedError);
|
|
133
153
|
}
|
|
134
154
|
if (parsedError === null || parsedError === void 0 ? void 0 : parsedError.errorMessage) {
|
|
135
|
-
return parsedError.errorMessage;
|
|
155
|
+
return appendErrorDetails(parsedError.errorMessage, parsedError);
|
|
136
156
|
}
|
|
137
|
-
const status = (parsedError === null || parsedError === void 0 ? void 0 : parsedError.status) || ((
|
|
138
|
-
const errorCode = (parsedError === null || parsedError === void 0 ? void 0 : parsedError.errorCode) || ((
|
|
157
|
+
const status = (parsedError === null || parsedError === void 0 ? void 0 : parsedError.status) || ((_d = parsedError === null || parsedError === void 0 ? void 0 : parsedError.response) === null || _d === void 0 ? void 0 : _d.status);
|
|
158
|
+
const errorCode = (parsedError === null || parsedError === void 0 ? void 0 : parsedError.errorCode) || ((_f = (_e = parsedError === null || parsedError === void 0 ? void 0 : parsedError.response) === null || _e === void 0 ? void 0 : _e.data) === null || _f === void 0 ? void 0 : _f.errorCode);
|
|
139
159
|
if (status === 422 && errorCode === 104) {
|
|
140
|
-
return 'Invalid email or password. Please check your credentials and try again.';
|
|
160
|
+
return appendErrorDetails('Invalid email or password. Please check your credentials and try again.', parsedError);
|
|
141
161
|
}
|
|
142
162
|
if (status === 401) {
|
|
143
|
-
return 'Authentication failed. Please check your credentials.';
|
|
163
|
+
return appendErrorDetails('Authentication failed. Please check your credentials.', parsedError);
|
|
144
164
|
}
|
|
145
165
|
if (status === 403) {
|
|
146
|
-
return 'Access denied. Please check your permissions.';
|
|
166
|
+
return appendErrorDetails('Access denied. Please check your permissions.', parsedError);
|
|
147
167
|
}
|
|
148
168
|
// Check for specific SSL error
|
|
149
169
|
if ((parsedError === null || parsedError === void 0 ? void 0 : parsedError.code) === 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY') {
|
|
@@ -172,25 +192,8 @@ const formatError = function (error) {
|
|
|
172
192
|
catch (e) {
|
|
173
193
|
// message is not in JSON format, no need to parse
|
|
174
194
|
}
|
|
175
|
-
//
|
|
176
|
-
|
|
177
|
-
const entityNames = {
|
|
178
|
-
authorization: 'Authentication',
|
|
179
|
-
api_key: 'Stack API key',
|
|
180
|
-
uid: 'Content Type',
|
|
181
|
-
// 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.
|
|
182
|
-
access_token: 'Delivery Token',
|
|
183
|
-
};
|
|
184
|
-
const errorList = Object.entries(parsedError.errors)
|
|
185
|
-
.map(([field, errors]) => {
|
|
186
|
-
const errorArray = Array.isArray(errors) ? errors : [errors];
|
|
187
|
-
const fieldName = entityNames[field] || field;
|
|
188
|
-
return ` • ${fieldName}: ${errorArray.join(', ')}`;
|
|
189
|
-
})
|
|
190
|
-
.join('\n');
|
|
191
|
-
message += `\n\nAPI Errors:\n${errorList}`;
|
|
192
|
-
}
|
|
193
|
-
return message;
|
|
195
|
+
// Always append error details at the end
|
|
196
|
+
return appendErrorDetails(message, parsedError);
|
|
194
197
|
};
|
|
195
198
|
exports.formatError = formatError;
|
|
196
199
|
/**
|
|
@@ -82,21 +82,15 @@ class CLIErrorHandler {
|
|
|
82
82
|
* Extracts a clear, concise error message from various error types.
|
|
83
83
|
*/
|
|
84
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
|
-
}
|
|
85
|
+
var _a, _b;
|
|
92
86
|
// Use existing formatError function for other cases
|
|
93
87
|
try {
|
|
94
88
|
const formattedMessage = (0, helpers_1.formatError)(error);
|
|
95
89
|
return formattedMessage || 'An error occurred. Please try again.';
|
|
96
90
|
}
|
|
97
|
-
catch (
|
|
91
|
+
catch (_c) {
|
|
98
92
|
// Fallback to basic error message extraction if formatError fails
|
|
99
|
-
if (typeof ((
|
|
93
|
+
if (typeof ((_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) === 'string') {
|
|
100
94
|
return error.response.data.errorMessage;
|
|
101
95
|
}
|
|
102
96
|
if (typeof (error === null || error === void 0 ? void 0 : error.errorMessage) === 'string') {
|
package/lib/logger/log.js
CHANGED
|
@@ -10,9 +10,15 @@ const cli_error_handler_1 = require("./cli-error-handler");
|
|
|
10
10
|
const __1 = require("..");
|
|
11
11
|
let loggerInstance = null;
|
|
12
12
|
function createLoggerInstance() {
|
|
13
|
+
var _a;
|
|
14
|
+
const logConfig = __1.configHandler.get('log');
|
|
15
|
+
const logLevel = (logConfig === null || logConfig === void 0 ? void 0 : logConfig.level) || 'info';
|
|
16
|
+
const showConsoleLogs = (_a = logConfig === null || logConfig === void 0 ? void 0 : logConfig['show-console-logs']) !== null && _a !== void 0 ? _a : false;
|
|
13
17
|
const config = {
|
|
14
18
|
basePath: getLogPath(),
|
|
15
|
-
logLevel:
|
|
19
|
+
logLevel: logLevel,
|
|
20
|
+
consoleLoggingEnabled: showConsoleLogs,
|
|
21
|
+
consoleLogLevel: logLevel,
|
|
16
22
|
};
|
|
17
23
|
return new logger_1.default(config);
|
|
18
24
|
}
|
package/lib/logger/logger.js
CHANGED
|
@@ -95,6 +95,10 @@ class Logger {
|
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
shouldLog(level, target) {
|
|
98
|
+
// If console logging is disabled, don't log to console
|
|
99
|
+
if (target === 'console' && this.config.consoleLoggingEnabled === false) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
98
102
|
const configLevel = target === 'console' ? this.config.consoleLogLevel : this.config.logLevel;
|
|
99
103
|
const minLevel = configLevel ? logging_1.logLevels[configLevel] : 2;
|
|
100
104
|
return logging_1.logLevels[level] <= minLevel;
|