@contentstack/cli-utilities 1.15.0 → 1.16.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/LICENSE +1 -1
- package/lib/auth-handler.js +8 -8
- package/lib/authentication-handler.js +0 -6
- package/lib/config-handler.js +1 -1
- package/lib/constants/logging.d.ts +0 -1
- package/lib/constants/logging.js +3 -4
- package/lib/contentstack-management-sdk.js +2 -0
- package/lib/flag-deprecation-check.js +5 -5
- package/lib/helpers.d.ts +25 -1
- package/lib/helpers.js +46 -9
- package/lib/http-client/client.d.ts +7 -0
- package/lib/http-client/client.js +6 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.js +3 -8
- package/lib/interfaces/index.d.ts +1 -50
- package/lib/logger/cli-error-handler.js +2 -1
- package/lib/logger/log.d.ts +1 -0
- package/lib/logger/log.js +5 -2
- package/lib/logger/logger.js +23 -40
- package/lib/logger/session-path.d.ts +7 -0
- package/lib/logger/session-path.js +96 -0
- package/lib/logger.js +1 -1
- package/lib/message-handler.js +1 -1
- package/package.json +5 -5
- package/lib/progress-summary/cli-progress-manager.d.ts +0 -121
- package/lib/progress-summary/cli-progress-manager.js +0 -530
- package/lib/progress-summary/index.d.ts +0 -4
- package/lib/progress-summary/index.js +0 -13
- package/lib/progress-summary/progress-strategy.d.ts +0 -25
- package/lib/progress-summary/progress-strategy.js +0 -54
- package/lib/progress-summary/summary-manager.d.ts +0 -24
- package/lib/progress-summary/summary-manager.js +0 -181
package/LICENSE
CHANGED
package/lib/auth-handler.js
CHANGED
|
@@ -114,7 +114,7 @@ class AuthHandler {
|
|
|
114
114
|
await this.openOAuthURL();
|
|
115
115
|
}
|
|
116
116
|
catch (error) {
|
|
117
|
-
this.logger.error('OAuth login failed', error.message);
|
|
117
|
+
this.logger.error('OAuth login failed!', error.message);
|
|
118
118
|
throw error;
|
|
119
119
|
}
|
|
120
120
|
}
|
|
@@ -123,20 +123,20 @@ class AuthHandler {
|
|
|
123
123
|
const server = http_1.default.createServer(async (req, res) => {
|
|
124
124
|
const queryObject = url_1.default.parse(req.url, true).query;
|
|
125
125
|
if (!queryObject.code) {
|
|
126
|
-
cli_ux_1.default.error('Error
|
|
126
|
+
cli_ux_1.default.error('Error occurred while logging in with OAuth!');
|
|
127
127
|
return sendErrorResponse(res);
|
|
128
128
|
}
|
|
129
129
|
cli_ux_1.default.print('Auth code successfully fetched.');
|
|
130
130
|
try {
|
|
131
131
|
await this.getAccessToken(queryObject.code);
|
|
132
132
|
await this.setOAuthBaseURL();
|
|
133
|
-
cli_ux_1.default.print('Access token fetched using auth code
|
|
133
|
+
cli_ux_1.default.print('Access token successfully fetched using auth code.');
|
|
134
134
|
cli_ux_1.default.print(`You can review the access permissions on the page - ${this.OAuthBaseURL}/#!/marketplace/authorized-apps`);
|
|
135
135
|
sendSuccessResponse(res);
|
|
136
136
|
stopServer();
|
|
137
137
|
}
|
|
138
138
|
catch (error) {
|
|
139
|
-
cli_ux_1.default.error('Error
|
|
139
|
+
cli_ux_1.default.error('Error occurred while logging in with OAuth!');
|
|
140
140
|
cli_ux_1.default.error(error);
|
|
141
141
|
sendErrorResponse(res);
|
|
142
142
|
stopServer();
|
|
@@ -301,8 +301,8 @@ class AuthHandler {
|
|
|
301
301
|
}
|
|
302
302
|
}
|
|
303
303
|
else {
|
|
304
|
-
cli_ux_1.default.error('Invalid
|
|
305
|
-
throw new Error('Invalid
|
|
304
|
+
cli_ux_1.default.error('Invalid or empty access token.');
|
|
305
|
+
throw new Error('Invalid or empty access token.');
|
|
306
306
|
}
|
|
307
307
|
}
|
|
308
308
|
async oauthLogout() {
|
|
@@ -346,7 +346,7 @@ class AuthHandler {
|
|
|
346
346
|
const oauthValidUpto = new Date();
|
|
347
347
|
oauthValidUpto.setTime(oauthDate.getTime() + 59 * 60 * 1000);
|
|
348
348
|
if (force) {
|
|
349
|
-
cli_ux_1.default.print('
|
|
349
|
+
cli_ux_1.default.print('Forcing token refresh...');
|
|
350
350
|
return this.refreshToken();
|
|
351
351
|
}
|
|
352
352
|
else {
|
|
@@ -373,7 +373,7 @@ class AuthHandler {
|
|
|
373
373
|
}
|
|
374
374
|
}
|
|
375
375
|
else {
|
|
376
|
-
cli_ux_1.default.print('No OAuth set');
|
|
376
|
+
cli_ux_1.default.print('No OAuth configuration set.');
|
|
377
377
|
this.unsetConfigData();
|
|
378
378
|
}
|
|
379
379
|
}
|
|
@@ -50,12 +50,6 @@ class AuthenticationHandler {
|
|
|
50
50
|
}
|
|
51
51
|
async refreshAccessToken(error, maxRetryCount = 1) {
|
|
52
52
|
var _a, _b;
|
|
53
|
-
// Add configurable delay only for CI/CD pipelines
|
|
54
|
-
const delayMs = process.env.DELAY_MS;
|
|
55
|
-
if (delayMs) {
|
|
56
|
-
const delay = parseInt(delayMs, 10);
|
|
57
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
58
|
-
}
|
|
59
53
|
if (error.response && error.response.status) {
|
|
60
54
|
switch (error.response.status) {
|
|
61
55
|
case 401:
|
package/lib/config-handler.js
CHANGED
package/lib/constants/logging.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.levelColors = exports.logLevels = void 0;
|
|
4
4
|
exports.logLevels = {
|
|
5
5
|
error: 0,
|
|
6
6
|
warn: 1,
|
|
7
7
|
info: 2,
|
|
8
8
|
success: 2,
|
|
9
9
|
debug: 3,
|
|
10
|
-
verbose: 4
|
|
10
|
+
verbose: 4
|
|
11
11
|
};
|
|
12
12
|
// 2. Create color mappings (for console only)
|
|
13
13
|
exports.levelColors = {
|
|
@@ -15,6 +15,5 @@ exports.levelColors = {
|
|
|
15
15
|
warn: 'yellow',
|
|
16
16
|
success: 'green',
|
|
17
17
|
info: 'white',
|
|
18
|
-
debug: 'blue'
|
|
18
|
+
debug: 'blue'
|
|
19
19
|
};
|
|
20
|
-
exports.PROGRESS_SUPPORTED_MODULES = ['export', 'import'];
|
|
@@ -19,6 +19,7 @@ class ManagementSDKInitiator {
|
|
|
19
19
|
maxRequests: 10,
|
|
20
20
|
retryLimit: 3,
|
|
21
21
|
timeout: 60000,
|
|
22
|
+
delayMs: config.delayMs,
|
|
22
23
|
httpsAgent: new node_https_1.Agent({
|
|
23
24
|
maxSockets: 100,
|
|
24
25
|
maxFreeSockets: 10,
|
|
@@ -36,6 +37,7 @@ class ManagementSDKInitiator {
|
|
|
36
37
|
case 401:
|
|
37
38
|
case 429:
|
|
38
39
|
case 408:
|
|
40
|
+
case 422:
|
|
39
41
|
return true;
|
|
40
42
|
default:
|
|
41
43
|
return false;
|
|
@@ -22,17 +22,17 @@ function default_1(deprecatedFlags = [], suggestions = [], customMessage) {
|
|
|
22
22
|
}
|
|
23
23
|
});
|
|
24
24
|
if (isCommandHasDeprecationFlag) {
|
|
25
|
-
let
|
|
25
|
+
let deprecationMessage = '';
|
|
26
26
|
if (customMessage) {
|
|
27
|
-
|
|
27
|
+
deprecationMessage = customMessage;
|
|
28
28
|
}
|
|
29
29
|
else {
|
|
30
|
-
|
|
30
|
+
deprecationMessage = `WARNING!!! You're using the old (soon to be deprecated) Contentstack CLI flags (${deprecatedFlags.join(', ')}).`;
|
|
31
31
|
if (suggestions.length > 0) {
|
|
32
|
-
|
|
32
|
+
deprecationMessage += ` We recommend you to use the updated flags (${suggestions.join(', ')}).`;
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
-
cli_ux_1.default.print(
|
|
35
|
+
cli_ux_1.default.print(deprecationMessage, { color: 'yellow' });
|
|
36
36
|
}
|
|
37
37
|
return input;
|
|
38
38
|
};
|
package/lib/helpers.d.ts
CHANGED
|
@@ -27,4 +27,28 @@ export declare const formatError: (error: any) => string;
|
|
|
27
27
|
* from.
|
|
28
28
|
*/
|
|
29
29
|
export declare const redactObject: (obj: any) => any;
|
|
30
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Get authentication method from config
|
|
32
|
+
* @returns Authentication method string ('OAuth', 'Basic Auth', or empty string)
|
|
33
|
+
*/
|
|
34
|
+
export declare function getAuthenticationMethod(): string;
|
|
35
|
+
/**
|
|
36
|
+
* Creates a standardized context object for logging
|
|
37
|
+
* This context contains all session-level metadata that should be in session.json
|
|
38
|
+
* The apiKey is stored in configHandler so it's available for session.json generation
|
|
39
|
+
*
|
|
40
|
+
* @param commandId - The command ID (e.g., 'cm:stacks:export')
|
|
41
|
+
* @param apiKey - The API key for the stack (will be stored in configHandler for session.json)
|
|
42
|
+
* @param authenticationMethod - Optional authentication method
|
|
43
|
+
* @returns Context object with all session-level metadata
|
|
44
|
+
*/
|
|
45
|
+
export declare function createLogContext(commandId: string, apiKey: string, authenticationMethod?: string): {
|
|
46
|
+
command: string;
|
|
47
|
+
module: string;
|
|
48
|
+
userId: string;
|
|
49
|
+
email: string;
|
|
50
|
+
sessionId: string;
|
|
51
|
+
apiKey: string;
|
|
52
|
+
orgId: string;
|
|
53
|
+
authenticationMethod: string;
|
|
54
|
+
};
|
package/lib/helpers.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.createLogContext = exports.getAuthenticationMethod = exports.redactObject = exports.formatError = exports.validateRegex = exports.validateFileName = exports.validateUids = exports.sanitizePath = exports.escapeRegExp = exports.validatePath = exports.createDeveloperHubUrl = exports.isManagementTokenValid = exports.getBranchFromAlias = exports.doesBranchExist = exports.isAuthenticated = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const recheck_1 = require("recheck");
|
|
6
6
|
const traverse_1 = tslib_1.__importDefault(require("traverse"));
|
|
@@ -185,8 +185,8 @@ const formatError = function (error) {
|
|
|
185
185
|
// If message is in JSON format, parse it to extract the actual message string
|
|
186
186
|
try {
|
|
187
187
|
const parsedMessage = JSON.parse(message);
|
|
188
|
-
if (typeof parsedMessage === 'object'
|
|
189
|
-
message = (parsedMessage === null || parsedMessage === void 0 ? void 0 : parsedMessage.message) ||
|
|
188
|
+
if (typeof parsedMessage === 'object') {
|
|
189
|
+
message = (parsedMessage === null || parsedMessage === void 0 ? void 0 : parsedMessage.message) || message;
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
192
|
catch (e) {
|
|
@@ -238,11 +238,48 @@ const sensitiveKeys = [
|
|
|
238
238
|
/management[-._]?token/i,
|
|
239
239
|
/delivery[-._]?token/i,
|
|
240
240
|
];
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
241
|
+
/**
|
|
242
|
+
* Get authentication method from config
|
|
243
|
+
* @returns Authentication method string ('OAuth', 'Basic Auth', or empty string)
|
|
244
|
+
*/
|
|
245
|
+
function getAuthenticationMethod() {
|
|
246
|
+
const authType = _1.configHandler.get('authorisationType');
|
|
247
|
+
if (authType === 'OAUTH') {
|
|
248
|
+
return 'OAuth';
|
|
249
|
+
}
|
|
250
|
+
else if (authType === 'BASIC') {
|
|
251
|
+
return 'Basic Auth';
|
|
252
|
+
}
|
|
253
|
+
// Management token detection is command-specific and not stored globally
|
|
254
|
+
// Return empty string if unknown
|
|
255
|
+
return '';
|
|
256
|
+
}
|
|
257
|
+
exports.getAuthenticationMethod = getAuthenticationMethod;
|
|
258
|
+
/**
|
|
259
|
+
* Creates a standardized context object for logging
|
|
260
|
+
* This context contains all session-level metadata that should be in session.json
|
|
261
|
+
* The apiKey is stored in configHandler so it's available for session.json generation
|
|
262
|
+
*
|
|
263
|
+
* @param commandId - The command ID (e.g., 'cm:stacks:export')
|
|
264
|
+
* @param apiKey - The API key for the stack (will be stored in configHandler for session.json)
|
|
265
|
+
* @param authenticationMethod - Optional authentication method
|
|
266
|
+
* @returns Context object with all session-level metadata
|
|
267
|
+
*/
|
|
268
|
+
function createLogContext(commandId, apiKey, authenticationMethod) {
|
|
269
|
+
// Store apiKey in configHandler so it's available for session.json
|
|
270
|
+
if (apiKey) {
|
|
271
|
+
_1.configHandler.set('apiKey', apiKey);
|
|
246
272
|
}
|
|
273
|
+
const authMethod = authenticationMethod || getAuthenticationMethod();
|
|
274
|
+
return {
|
|
275
|
+
command: commandId,
|
|
276
|
+
module: '',
|
|
277
|
+
userId: _1.configHandler.get('clientId') || '',
|
|
278
|
+
email: _1.configHandler.get('email') || '',
|
|
279
|
+
sessionId: _1.configHandler.get('sessionId') || '',
|
|
280
|
+
apiKey: apiKey || '',
|
|
281
|
+
orgId: _1.configHandler.get('oauthOrgUid') || '',
|
|
282
|
+
authenticationMethod: authMethod,
|
|
283
|
+
};
|
|
247
284
|
}
|
|
248
|
-
exports.
|
|
285
|
+
exports.createLogContext = createLogContext;
|
|
@@ -225,6 +225,13 @@ export declare class HttpClient implements IHttpClient {
|
|
|
225
225
|
* @returns {Request}
|
|
226
226
|
*/
|
|
227
227
|
createAndSendRequest(method: HttpMethod, url: string): Promise<AxiosResponse>;
|
|
228
|
+
/**
|
|
229
|
+
* Get the axios instance for interceptor access
|
|
230
|
+
*/
|
|
231
|
+
get interceptors(): {
|
|
232
|
+
request: import("axios").AxiosInterceptorManager<import("axios").InternalAxiosRequestConfig<any>>;
|
|
233
|
+
response: import("axios").AxiosInterceptorManager<AxiosResponse<any, any, {}>>;
|
|
234
|
+
};
|
|
228
235
|
/**
|
|
229
236
|
* Returns the request payload depending on the selected request payload format.
|
|
230
237
|
*/
|
|
@@ -334,6 +334,12 @@ class HttpClient {
|
|
|
334
334
|
return await this.axiosInstance(Object.assign(Object.assign({ url,
|
|
335
335
|
method, withCredentials: true }, this.request), { data: this.prepareRequestPayload() }));
|
|
336
336
|
}
|
|
337
|
+
/**
|
|
338
|
+
* Get the axios instance for interceptor access
|
|
339
|
+
*/
|
|
340
|
+
get interceptors() {
|
|
341
|
+
return this.axiosInstance.interceptors;
|
|
342
|
+
}
|
|
337
343
|
/**
|
|
338
344
|
* Returns the request payload depending on the selected request payload format.
|
|
339
345
|
*/
|
package/lib/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export * from './fs-utility';
|
|
|
13
13
|
export { default as NodeCrypto } from './encrypter';
|
|
14
14
|
export { Args as args, Flags as flags, Command } from './cli-ux';
|
|
15
15
|
export * from './helpers';
|
|
16
|
+
export { createLogContext } from './helpers';
|
|
16
17
|
export * from './interfaces';
|
|
17
18
|
export * from './date-time';
|
|
18
19
|
export * from './add-locale';
|
|
@@ -25,4 +26,3 @@ export { default as TablePrompt } from './inquirer-table-prompt';
|
|
|
25
26
|
export { Logger };
|
|
26
27
|
export { default as authenticationHandler } from './authentication-handler';
|
|
27
28
|
export { v2Logger as log, cliErrorHandler, handleAndLogError, getLogPath } from './logger/log';
|
|
28
|
-
export { CLIProgressManager, SummaryManager, PrimaryProcessStrategy, ProgressStrategyRegistry, CustomProgressStrategy, DefaultProgressStrategy } from './progress-summary';
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
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.createLogContext = 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;
|
|
@@ -34,6 +34,8 @@ Object.defineProperty(exports, "args", { enumerable: true, get: function () { re
|
|
|
34
34
|
Object.defineProperty(exports, "flags", { enumerable: true, get: function () { return cli_ux_2.Flags; } });
|
|
35
35
|
Object.defineProperty(exports, "Command", { enumerable: true, get: function () { return cli_ux_2.Command; } });
|
|
36
36
|
tslib_1.__exportStar(require("./helpers"), exports);
|
|
37
|
+
var helpers_1 = require("./helpers");
|
|
38
|
+
Object.defineProperty(exports, "createLogContext", { enumerable: true, get: function () { return helpers_1.createLogContext; } });
|
|
37
39
|
tslib_1.__exportStar(require("./interfaces"), exports);
|
|
38
40
|
tslib_1.__exportStar(require("./date-time"), exports);
|
|
39
41
|
tslib_1.__exportStar(require("./add-locale"), exports);
|
|
@@ -69,10 +71,3 @@ Object.defineProperty(exports, "log", { enumerable: true, get: function () { ret
|
|
|
69
71
|
Object.defineProperty(exports, "cliErrorHandler", { enumerable: true, get: function () { return log_1.cliErrorHandler; } });
|
|
70
72
|
Object.defineProperty(exports, "handleAndLogError", { enumerable: true, get: function () { return log_1.handleAndLogError; } });
|
|
71
73
|
Object.defineProperty(exports, "getLogPath", { enumerable: true, get: function () { return log_1.getLogPath; } });
|
|
72
|
-
var progress_summary_1 = require("./progress-summary");
|
|
73
|
-
Object.defineProperty(exports, "CLIProgressManager", { enumerable: true, get: function () { return progress_summary_1.CLIProgressManager; } });
|
|
74
|
-
Object.defineProperty(exports, "SummaryManager", { enumerable: true, get: function () { return progress_summary_1.SummaryManager; } });
|
|
75
|
-
Object.defineProperty(exports, "PrimaryProcessStrategy", { enumerable: true, get: function () { return progress_summary_1.PrimaryProcessStrategy; } });
|
|
76
|
-
Object.defineProperty(exports, "ProgressStrategyRegistry", { enumerable: true, get: function () { return progress_summary_1.ProgressStrategyRegistry; } });
|
|
77
|
-
Object.defineProperty(exports, "CustomProgressStrategy", { enumerable: true, get: function () { return progress_summary_1.CustomProgressStrategy; } });
|
|
78
|
-
Object.defineProperty(exports, "DefaultProgressStrategy", { enumerable: true, get: function () { return progress_summary_1.DefaultProgressStrategy; } });
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { logLevels } from
|
|
2
|
-
import ProgressBar from 'cli-progress';
|
|
1
|
+
import { logLevels } from "../constants/logging";
|
|
3
2
|
export interface IPromptOptions {
|
|
4
3
|
prompt?: string;
|
|
5
4
|
type?: 'normal' | 'mask' | 'hide' | 'single';
|
|
@@ -102,51 +101,3 @@ export interface ErrorContextBase {
|
|
|
102
101
|
export type ErrorContext = ErrorContextBase & {
|
|
103
102
|
[key: string]: unknown;
|
|
104
103
|
};
|
|
105
|
-
export interface Failure {
|
|
106
|
-
item: string;
|
|
107
|
-
error: string | null;
|
|
108
|
-
process?: string;
|
|
109
|
-
}
|
|
110
|
-
export interface ProcessProgress {
|
|
111
|
-
name: string;
|
|
112
|
-
total: number;
|
|
113
|
-
current: number;
|
|
114
|
-
status: 'pending' | 'active' | 'completed' | 'failed';
|
|
115
|
-
successCount: number;
|
|
116
|
-
failureCount: number;
|
|
117
|
-
failures: Failure[];
|
|
118
|
-
progressBar?: ProgressBar.SingleBar;
|
|
119
|
-
}
|
|
120
|
-
export interface ProgressManagerOptions {
|
|
121
|
-
showConsoleLogs?: boolean;
|
|
122
|
-
total?: number;
|
|
123
|
-
moduleName?: string;
|
|
124
|
-
enableNestedProgress?: boolean;
|
|
125
|
-
}
|
|
126
|
-
export interface ModuleResult {
|
|
127
|
-
name: string;
|
|
128
|
-
status: 'pending' | 'running' | 'completed' | 'failed';
|
|
129
|
-
startTime?: number;
|
|
130
|
-
endTime?: number;
|
|
131
|
-
totalItems: number;
|
|
132
|
-
successCount: number;
|
|
133
|
-
failureCount: number;
|
|
134
|
-
failures: Array<{
|
|
135
|
-
item: string;
|
|
136
|
-
error: string;
|
|
137
|
-
}>;
|
|
138
|
-
processes?: Array<{
|
|
139
|
-
processName: string;
|
|
140
|
-
[key: string]: any;
|
|
141
|
-
}>;
|
|
142
|
-
}
|
|
143
|
-
export interface SummaryOptions {
|
|
144
|
-
operationName: string;
|
|
145
|
-
context?: any;
|
|
146
|
-
branchName?: string;
|
|
147
|
-
}
|
|
148
|
-
export interface ProgressResult {
|
|
149
|
-
total: number;
|
|
150
|
-
success: number;
|
|
151
|
-
failures: number;
|
|
152
|
-
}
|
|
@@ -114,7 +114,8 @@ class CLIErrorHandler {
|
|
|
114
114
|
if (typeof error === 'object') {
|
|
115
115
|
try {
|
|
116
116
|
const errorObj = error;
|
|
117
|
-
const
|
|
117
|
+
const message = errorObj.message || errorObj.error || errorObj.statusText || 'Unknown error';
|
|
118
|
+
const normalizedError = new Error(message);
|
|
118
119
|
// Only copy essential properties
|
|
119
120
|
const essentialProps = [
|
|
120
121
|
'code',
|
package/lib/logger/log.d.ts
CHANGED
|
@@ -29,4 +29,5 @@ declare function handleAndLogError(error: unknown, context?: ErrorContext, error
|
|
|
29
29
|
* 4. Home directory (~/contentstack/logs) (fallback)
|
|
30
30
|
*/
|
|
31
31
|
declare function getLogPath(): string;
|
|
32
|
+
export { getSessionLogPath } from './session-path';
|
|
32
33
|
export { v2Logger, cliErrorHandler, handleAndLogError, getLogPath };
|
package/lib/logger/log.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getLogPath = exports.handleAndLogError = exports.cliErrorHandler = exports.v2Logger = void 0;
|
|
3
|
+
exports.getLogPath = exports.handleAndLogError = exports.cliErrorHandler = exports.v2Logger = exports.getSessionLogPath = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const fs = tslib_1.__importStar(require("fs"));
|
|
6
6
|
const os = tslib_1.__importStar(require("os"));
|
|
@@ -13,7 +13,7 @@ function createLoggerInstance() {
|
|
|
13
13
|
var _a;
|
|
14
14
|
const logConfig = __1.configHandler.get('log');
|
|
15
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
|
|
16
|
+
const showConsoleLogs = (_a = logConfig === null || logConfig === void 0 ? void 0 : logConfig['show-console-logs']) !== null && _a !== void 0 ? _a : false;
|
|
17
17
|
const config = {
|
|
18
18
|
basePath: getLogPath(),
|
|
19
19
|
logLevel: logLevel,
|
|
@@ -103,3 +103,6 @@ function getLogPath() {
|
|
|
103
103
|
return path.join(os.homedir(), 'contentstack', 'logs');
|
|
104
104
|
}
|
|
105
105
|
exports.getLogPath = getLogPath;
|
|
106
|
+
// Re-export getSessionLogPath for external use
|
|
107
|
+
var session_path_1 = require("./session-path");
|
|
108
|
+
Object.defineProperty(exports, "getSessionLogPath", { enumerable: true, get: function () { return session_path_1.getSessionLogPath; } });
|
package/lib/logger/logger.js
CHANGED
|
@@ -6,7 +6,7 @@ const full_1 = require("klona/full");
|
|
|
6
6
|
const path_1 = require("path");
|
|
7
7
|
const winston = tslib_1.__importStar(require("winston"));
|
|
8
8
|
const logging_1 = require("../constants/logging");
|
|
9
|
-
const
|
|
9
|
+
const session_path_1 = require("./session-path");
|
|
10
10
|
class Logger {
|
|
11
11
|
constructor(config) {
|
|
12
12
|
this.consoleSensitiveKeys = [
|
|
@@ -32,57 +32,40 @@ class Logger {
|
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
34
|
getLoggerInstance(level = 'info') {
|
|
35
|
-
|
|
35
|
+
// Use session-based path for date-organized logging
|
|
36
|
+
const sessionPath = (0, session_path_1.getSessionLogPath)();
|
|
37
|
+
const filePath = (0, path_1.normalize)(sessionPath).replace(/^(\.\.(\/|\\|$))+/, '');
|
|
36
38
|
return this.createLogger(level === 'hidden' ? 'error' : level, filePath);
|
|
37
39
|
}
|
|
38
40
|
get loggerOptions() {
|
|
39
41
|
return {
|
|
40
42
|
filename: '',
|
|
41
|
-
maxFiles:
|
|
43
|
+
maxFiles: 50,
|
|
42
44
|
tailable: true,
|
|
43
|
-
maxsize:
|
|
45
|
+
maxsize: 5000000, // 5MB
|
|
44
46
|
};
|
|
45
47
|
}
|
|
46
48
|
createLogger(level, filePath) {
|
|
47
|
-
var _a;
|
|
48
|
-
const transports = [
|
|
49
|
-
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) => {
|
|
50
|
-
// Apply minimal redaction for files (debugging info preserved)
|
|
51
|
-
const redactedInfo = this.redact(info, false);
|
|
52
|
-
return JSON.stringify(redactedInfo);
|
|
53
|
-
})) })),
|
|
54
|
-
];
|
|
55
|
-
// Determine console logging based on configuration
|
|
56
|
-
let showConsoleLogs = true;
|
|
57
|
-
if (__1.configHandler && typeof __1.configHandler.get === 'function') {
|
|
58
|
-
const logConfig = __1.configHandler.get('log') || {};
|
|
59
|
-
const currentModule = logConfig.progressSupportedModule;
|
|
60
|
-
const hasProgressSupport = currentModule && logging_1.PROGRESS_SUPPORTED_MODULES.includes(currentModule);
|
|
61
|
-
if (hasProgressSupport) {
|
|
62
|
-
// Plugin has progress bars - respect user's showConsoleLogs setting
|
|
63
|
-
showConsoleLogs = (_a = logConfig.showConsoleLogs) !== null && _a !== void 0 ? _a : true;
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
// Plugin doesn't have progress support - always show console logs
|
|
67
|
-
showConsoleLogs = true;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
if (showConsoleLogs) {
|
|
71
|
-
transports.push(new winston.transports.Console({
|
|
72
|
-
format: winston.format.combine(winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.printf((info) => {
|
|
73
|
-
// Apply full redaction for console (user-facing)
|
|
74
|
-
const redactedInfo = this.redact(info, true);
|
|
75
|
-
const colorizer = winston.format.colorize();
|
|
76
|
-
const levelText = redactedInfo.level.toUpperCase();
|
|
77
|
-
const { timestamp, message } = redactedInfo;
|
|
78
|
-
return colorizer.colorize(redactedInfo.level, `[${timestamp}] ${levelText}: ${message}`);
|
|
79
|
-
})),
|
|
80
|
-
}));
|
|
81
|
-
}
|
|
82
49
|
return winston.createLogger({
|
|
83
50
|
levels: logging_1.logLevels,
|
|
84
51
|
level,
|
|
85
|
-
transports
|
|
52
|
+
transports: [
|
|
53
|
+
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) => {
|
|
54
|
+
// Apply minimal redaction for files (debugging info preserved)
|
|
55
|
+
const redactedInfo = this.redact(info, false);
|
|
56
|
+
return JSON.stringify(redactedInfo);
|
|
57
|
+
})) })),
|
|
58
|
+
new winston.transports.Console({
|
|
59
|
+
format: winston.format.combine(winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.printf((info) => {
|
|
60
|
+
// Apply full redaction for console (user-facing)
|
|
61
|
+
const redactedInfo = this.redact(info, true);
|
|
62
|
+
const colorizer = winston.format.colorize();
|
|
63
|
+
const levelText = redactedInfo.level.toUpperCase();
|
|
64
|
+
const { timestamp, message } = redactedInfo;
|
|
65
|
+
return colorizer.colorize(redactedInfo.level, `[${timestamp}] ${levelText}: ${message}`);
|
|
66
|
+
})),
|
|
67
|
+
}),
|
|
68
|
+
],
|
|
86
69
|
});
|
|
87
70
|
}
|
|
88
71
|
isSensitiveKey(keyStr, consoleMode = false) {
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getSessionLogPath = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const fs = tslib_1.__importStar(require("fs"));
|
|
6
|
+
const os = tslib_1.__importStar(require("os"));
|
|
7
|
+
const path = tslib_1.__importStar(require("path"));
|
|
8
|
+
const __1 = require("..");
|
|
9
|
+
const log_1 = require("./log");
|
|
10
|
+
/**
|
|
11
|
+
* Extract module name from command ID
|
|
12
|
+
* Example: "cm:stacks:audit" -> "audit"
|
|
13
|
+
*/
|
|
14
|
+
function extractModule(commandId) {
|
|
15
|
+
if (!commandId || commandId === 'unknown') {
|
|
16
|
+
return '';
|
|
17
|
+
}
|
|
18
|
+
// Split by colon and get the last part
|
|
19
|
+
const parts = commandId.split(':');
|
|
20
|
+
return parts[parts.length - 1] || '';
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Generate session metadata object for session.json
|
|
24
|
+
* Uses createLogContext() to get base context, then adds session-specific metadata
|
|
25
|
+
*/
|
|
26
|
+
function generateSessionMetadata(commandId, sessionId, startTimestamp) {
|
|
27
|
+
const originalCommandId = __1.configHandler.get('currentCommandId') || commandId;
|
|
28
|
+
const module = extractModule(originalCommandId);
|
|
29
|
+
const apiKey = __1.configHandler.get('apiKey') || '';
|
|
30
|
+
const baseContext = (0, __1.createLogContext)(originalCommandId, apiKey);
|
|
31
|
+
return Object.assign(Object.assign({}, baseContext), { module: module, sessionId: sessionId, startTimestamp: startTimestamp.toISOString(), MachineEnvironment: {
|
|
32
|
+
nodeVersion: process.version,
|
|
33
|
+
os: os.platform(),
|
|
34
|
+
hostname: os.hostname(),
|
|
35
|
+
CLI_VERSION: __1.configHandler.get('CLI_VERSION') || '',
|
|
36
|
+
} });
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Create session.json metadata file in the session directory
|
|
40
|
+
*/
|
|
41
|
+
function createSessionMetadataFile(sessionPath, metadata) {
|
|
42
|
+
const metadataPath = path.join(sessionPath, 'session.json');
|
|
43
|
+
try {
|
|
44
|
+
fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2), 'utf8');
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
// Silently fail if metadata file cannot be created
|
|
48
|
+
// Logging here would cause circular dependency
|
|
49
|
+
// The session folder and logs will still be created
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Get the session-based log path for date-organized logging
|
|
54
|
+
* Structure: {basePath}/{YYYY-MM-DD}/{command}-{YYYYMMDD-HHMMSS}-{sessionId}/
|
|
55
|
+
*
|
|
56
|
+
* @returns The session-specific log directory path
|
|
57
|
+
*/
|
|
58
|
+
function getSessionLogPath() {
|
|
59
|
+
// Get base log path
|
|
60
|
+
const basePath = (0, log_1.getLogPath)();
|
|
61
|
+
// Get current date in YYYY-MM-DD format
|
|
62
|
+
const now = new Date();
|
|
63
|
+
const dateStr = now.toISOString().split('T')[0]; // YYYY-MM-DD
|
|
64
|
+
// Get command ID (fallback to 'unknown' if not set)
|
|
65
|
+
let commandId = __1.configHandler.get('currentCommandId') || 'unknown';
|
|
66
|
+
// Sanitize command ID - remove colons and replace with hyphens for folder name
|
|
67
|
+
commandId = commandId === null || commandId === void 0 ? void 0 : commandId.replace(/:/g, '-');
|
|
68
|
+
// Use helper methods to format date and time
|
|
69
|
+
const dateStrFormatted = (0, __1.formatDate)(now); // YYYYMMDD
|
|
70
|
+
const timeStrFormatted = (0, __1.formatTime)(now); // HHMMSS
|
|
71
|
+
const timestamp = `${dateStrFormatted}-${timeStrFormatted}`; // YYYYMMDD-HHMMSS
|
|
72
|
+
let sessionId = __1.configHandler.get('sessionId');
|
|
73
|
+
if (!sessionId) {
|
|
74
|
+
// Format: first 8 chars of command + timestamp (YYYYMMDDHHMMSS)
|
|
75
|
+
const timestampForId = `${dateStrFormatted}${timeStrFormatted}`; // YYYYMMDDHHMMSS
|
|
76
|
+
const commandHash = commandId.substring(0, 8).padEnd(8, '0'); // Use first 8 chars of command
|
|
77
|
+
sessionId = `${commandHash}-${timestampForId}`;
|
|
78
|
+
}
|
|
79
|
+
// Create session folder name: command-YYYYMMDD-HHMMSS-sessionId
|
|
80
|
+
const sessionFolderName = `${commandId}-${timestamp}-${sessionId}`;
|
|
81
|
+
// Build full session path
|
|
82
|
+
const sessionPath = path.join(basePath, dateStr, sessionFolderName);
|
|
83
|
+
// Ensure directory exists
|
|
84
|
+
const isNewSession = !fs.existsSync(sessionPath);
|
|
85
|
+
if (isNewSession) {
|
|
86
|
+
fs.mkdirSync(sessionPath, { recursive: true });
|
|
87
|
+
}
|
|
88
|
+
// Create session.json metadata file for new sessions
|
|
89
|
+
// This ensures metadata is created before any logs are written
|
|
90
|
+
if (isNewSession) {
|
|
91
|
+
const metadata = generateSessionMetadata(__1.configHandler.get('currentCommandId') || commandId, sessionId, now);
|
|
92
|
+
createSessionMetadataFile(sessionPath, metadata);
|
|
93
|
+
}
|
|
94
|
+
return sessionPath;
|
|
95
|
+
}
|
|
96
|
+
exports.getSessionLogPath = getSessionLogPath;
|
package/lib/logger.js
CHANGED
|
@@ -26,7 +26,7 @@ class LoggerService {
|
|
|
26
26
|
stringifiedParam = JSON.stringify(info.obj);
|
|
27
27
|
}
|
|
28
28
|
catch (error) {
|
|
29
|
-
console.log('
|
|
29
|
+
console.log('Warning: Failed to log the result');
|
|
30
30
|
}
|
|
31
31
|
// parse message
|
|
32
32
|
info.message = index_1.messageHandler.parse(info.message);
|