@contentstack/cli-utilities 1.13.1 → 1.14.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/helpers.d.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import { ContentstackClient } from '.';
1
2
  export declare const isAuthenticated: () => boolean;
2
3
  export declare const doesBranchExist: (stack: any, branchName: any) => Promise<any>;
4
+ export declare const getBranchFromAlias: (stack: ReturnType<ContentstackClient['stack']>, branchAlias: string) => Promise<string>;
3
5
  export declare const isManagementTokenValid: (stackAPIKey: any, managementToken: any) => Promise<{
4
6
  valid: boolean;
5
7
  message?: undefined;
package/lib/helpers.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.redactObject = exports.formatError = exports.validateRegex = exports.validateFileName = exports.validateUids = exports.sanitizePath = exports.escapeRegExp = exports.validatePath = exports.createDeveloperHubUrl = exports.isManagementTokenValid = exports.doesBranchExist = exports.isAuthenticated = void 0;
3
+ 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"));
@@ -17,6 +17,22 @@ const doesBranchExist = async (stack, branchName) => {
17
17
  });
18
18
  };
19
19
  exports.doesBranchExist = doesBranchExist;
20
+ const getBranchFromAlias = async (stack, branchAlias) => {
21
+ if (!stack || !branchAlias || typeof branchAlias !== 'string') {
22
+ throw new Error('Invalid input. Both stack and branch alias are required.');
23
+ }
24
+ try {
25
+ const response = await stack.branchAlias(branchAlias).fetch();
26
+ if (!(response === null || response === void 0 ? void 0 : response.uid)) {
27
+ throw new Error(`Invalid Branch Alias. No Branch found for the branch alias: ${branchAlias}`);
28
+ }
29
+ return response.uid;
30
+ }
31
+ catch (error) {
32
+ throw error;
33
+ }
34
+ };
35
+ exports.getBranchFromAlias = getBranchFromAlias;
20
36
  const isManagementTokenValid = async (stackAPIKey, managementToken) => {
21
37
  var _a;
22
38
  const httpClient = new _1.HttpClient({ headers: { api_key: stackAPIKey, authorization: managementToken } });
@@ -157,7 +173,7 @@ const formatError = function (error) {
157
173
  // message is not in JSON format, no need to parse
158
174
  }
159
175
  // Append detailed error information if available
160
- if (parsedError.errors && Object.keys(parsedError.errors).length > 0) {
176
+ if (parsedError.errors && typeof parsedError.errors === 'object' && Object.keys(parsedError.errors).length > 0) {
161
177
  const entityNames = {
162
178
  authorization: 'Authentication',
163
179
  api_key: 'Stack API key',
@@ -165,11 +181,14 @@ const formatError = function (error) {
165
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.
166
182
  access_token: 'Delivery Token',
167
183
  };
168
- message +=
169
- ' ' +
170
- Object.entries(parsedError.errors)
171
- .map(([key, value]) => `${entityNames[key] || key} ${value}`)
172
- .join(' ');
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}`;
173
192
  }
174
193
  return message;
175
194
  };
@@ -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 (_c) {
98
- return 'An error occurred. Please try again.';
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 = ['code', 'status', 'statusText', 'response', 'request', 'config'];
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 ((_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.errorMessage) {
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 = (_b = error.stack) === null || _b === void 0 ? void 0 : _b.split('\n').slice(0, 5).join('\n');
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
  }
@@ -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 sensitiveKeys;
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();
@@ -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.sensitiveKeys = [
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.json()) })),
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
- const redactedInfo = this.redact(info);
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
- return typeof keyStr === 'string' ? this.sensitiveKeys.some((regex) => regex.test(keyStr)) : false;
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) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentstack/cli-utilities",
3
- "version": "1.13.1",
3
+ "version": "1.14.0",
4
4
  "description": "Utilities for contentstack projects",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",