@contentstack/cli-utilities 2.0.0-beta.1 → 2.0.0-beta.3
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/cli-ux.js +18 -6
- package/lib/constants/logging.js +2 -2
- package/lib/content-type-utils.js +1 -2
- package/lib/contentstack-management-sdk.js +9 -3
- package/lib/contentstack-marketplace-sdk.js +1 -1
- package/lib/fs-utility/core.d.ts +0 -1
- package/lib/fs-utility/core.js +2 -3
- package/lib/fs-utility/helper.js +2 -3
- package/lib/helpers.d.ts +1 -1
- package/lib/helpers.js +4 -4
- package/lib/http-client/client.d.ts +2 -2
- package/lib/http-client/client.js +19 -2
- package/lib/index.js +1 -1
- package/lib/inquirer-table-prompt.d.ts +49 -28
- package/lib/inquirer-table-prompt.js +144 -136
- package/lib/interfaces/index.d.ts +2 -0
- package/lib/logger/log.js +3 -3
- package/lib/logger/session-path.d.ts +5 -0
- package/lib/logger/session-path.js +17 -2
- package/lib/progress-summary/cli-progress-manager.js +1 -1
- package/lib/proxy-helper.d.ts +42 -1
- package/lib/proxy-helper.js +148 -7
- package/package.json +7 -6
package/lib/cli-ux.js
CHANGED
|
@@ -56,13 +56,25 @@ class CLIInterface {
|
|
|
56
56
|
cli_table_1.default.render(headers, data, flags, options);
|
|
57
57
|
}
|
|
58
58
|
async inquire(inquirePayload) {
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
var _a, _b;
|
|
60
|
+
try {
|
|
61
|
+
if (Array.isArray(inquirePayload)) {
|
|
62
|
+
return (await inquirer_1.default.prompt(inquirePayload));
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
inquirePayload.message = message_handler_1.default.parse(inquirePayload.message);
|
|
66
|
+
const result = (await inquirer_1.default.prompt(inquirePayload));
|
|
67
|
+
return result[inquirePayload.name];
|
|
68
|
+
}
|
|
61
69
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
70
|
+
catch (err) {
|
|
71
|
+
const isExitPrompt = (err === null || err === void 0 ? void 0 : err.name) === 'ExitPromptError' ||
|
|
72
|
+
((_a = err === null || err === void 0 ? void 0 : err.message) === null || _a === void 0 ? void 0 : _a.includes('SIGINT')) ||
|
|
73
|
+
((_b = err === null || err === void 0 ? void 0 : err.message) === null || _b === void 0 ? void 0 : _b.includes('force closed'));
|
|
74
|
+
if (isExitPrompt) {
|
|
75
|
+
process.exit(130);
|
|
76
|
+
}
|
|
77
|
+
throw err;
|
|
66
78
|
}
|
|
67
79
|
}
|
|
68
80
|
async prompt(message, options) {
|
package/lib/constants/logging.js
CHANGED
|
@@ -5,7 +5,7 @@ exports.logLevels = {
|
|
|
5
5
|
error: 0,
|
|
6
6
|
warn: 1,
|
|
7
7
|
info: 2,
|
|
8
|
-
success: 2,
|
|
8
|
+
success: 2, // Maps to info level but with different type
|
|
9
9
|
debug: 3,
|
|
10
10
|
verbose: 4,
|
|
11
11
|
};
|
|
@@ -13,7 +13,7 @@ exports.logLevels = {
|
|
|
13
13
|
exports.levelColors = {
|
|
14
14
|
error: 'red',
|
|
15
15
|
warn: 'yellow',
|
|
16
|
-
success: 'green',
|
|
16
|
+
success: 'green', // Custom color for success
|
|
17
17
|
info: 'white',
|
|
18
18
|
debug: 'blue',
|
|
19
19
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.readContentTypeSchemas =
|
|
3
|
+
exports.readContentTypeSchemas = readContentTypeSchemas;
|
|
4
4
|
const node_path_1 = require("node:path");
|
|
5
5
|
const fs_utility_1 = require("./fs-utility");
|
|
6
6
|
/**
|
|
@@ -39,4 +39,3 @@ function readContentTypeSchemas(dirPath, ignoredFiles = ['schema.json', '.DS_Sto
|
|
|
39
39
|
}
|
|
40
40
|
return contentTypes;
|
|
41
41
|
}
|
|
42
|
-
exports.readContentTypeSchemas = readContentTypeSchemas;
|
|
@@ -15,15 +15,21 @@ class ManagementSDKInitiator {
|
|
|
15
15
|
this.analyticsInfo = context === null || context === void 0 ? void 0 : context.analyticsInfo;
|
|
16
16
|
}
|
|
17
17
|
async createAPIClient(config) {
|
|
18
|
-
//
|
|
19
|
-
const
|
|
18
|
+
// Resolve host so NO_PROXY applies even when config.host is omitted (e.g. from region.cma)
|
|
19
|
+
const host = (0, proxy_helper_1.resolveRequestHost)(config);
|
|
20
|
+
// NO_PROXY has priority over HTTP_PROXY/HTTPS_PROXY and config-set proxy
|
|
21
|
+
const proxyConfig = (0, proxy_helper_1.getProxyConfigForHost)(host);
|
|
22
|
+
// When bypassing, clear proxy env immediately so SDK never see it (they may read at init or first request).
|
|
23
|
+
if (!proxyConfig) {
|
|
24
|
+
(0, proxy_helper_1.clearProxyEnv)();
|
|
25
|
+
}
|
|
20
26
|
const option = {
|
|
21
27
|
host: config.host,
|
|
22
28
|
maxContentLength: config.maxContentLength || 100000000,
|
|
23
29
|
maxBodyLength: config.maxBodyLength || 1000000000,
|
|
24
30
|
maxRequests: 10,
|
|
25
31
|
retryLimit: 3,
|
|
26
|
-
timeout: proxyConfig ? 10000 : 60000,
|
|
32
|
+
timeout: proxyConfig ? 10000 : 60000, // 10s timeout with proxy, 60s without
|
|
27
33
|
delayMs: config.delayMs,
|
|
28
34
|
httpsAgent: new node_https_1.Agent({
|
|
29
35
|
maxSockets: 100,
|
|
@@ -23,7 +23,7 @@ class MarketplaceSDKInitiator {
|
|
|
23
23
|
maxContentLength: 100000000,
|
|
24
24
|
maxBodyLength: 1000000000,
|
|
25
25
|
httpsAgent: new node_https_1.Agent({
|
|
26
|
-
timeout: 60000,
|
|
26
|
+
timeout: 60000, // active socket keepalive for 60 seconds
|
|
27
27
|
maxSockets: 100,
|
|
28
28
|
keepAlive: true,
|
|
29
29
|
maxFreeSockets: 10,
|
package/lib/fs-utility/core.d.ts
CHANGED
package/lib/fs-utility/core.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.getDirectories = getDirectories;
|
|
4
|
+
exports.getFileList = getFileList;
|
|
4
5
|
const tslib_1 = require("tslib");
|
|
5
6
|
const mkdirp_1 = tslib_1.__importDefault(require("mkdirp"));
|
|
6
7
|
const keys_1 = tslib_1.__importDefault(require("lodash/keys"));
|
|
@@ -358,7 +359,6 @@ function getDirectories(source) {
|
|
|
358
359
|
.filter((dirent) => dirent.isDirectory())
|
|
359
360
|
.map((dirent) => dirent.name);
|
|
360
361
|
}
|
|
361
|
-
exports.getDirectories = getDirectories;
|
|
362
362
|
async function getFileList(dirName, onlyName = true) {
|
|
363
363
|
if (!(0, node_fs_1.existsSync)(dirName))
|
|
364
364
|
return [];
|
|
@@ -375,4 +375,3 @@ async function getFileList(dirName, onlyName = true) {
|
|
|
375
375
|
}
|
|
376
376
|
return files;
|
|
377
377
|
}
|
|
378
|
-
exports.getFileList = getFileList;
|
package/lib/fs-utility/helper.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.mapKeyAndVal = mapKeyAndVal;
|
|
4
|
+
exports.getMetaData = getMetaData;
|
|
4
5
|
const tslib_1 = require("tslib");
|
|
5
6
|
const map_1 = tslib_1.__importDefault(require("lodash/map"));
|
|
6
7
|
const omit_1 = tslib_1.__importDefault(require("lodash/omit"));
|
|
@@ -22,7 +23,6 @@ function mapKeyAndVal(array, keyName, omitKeys = []) {
|
|
|
22
23
|
return { [row[keyName]]: (0, omit_1.default)(row, omitKeys) };
|
|
23
24
|
}));
|
|
24
25
|
}
|
|
25
|
-
exports.mapKeyAndVal = mapKeyAndVal;
|
|
26
26
|
function getMetaData(array, pickKeys, handler) {
|
|
27
27
|
if (handler instanceof Function)
|
|
28
28
|
handler(array);
|
|
@@ -30,4 +30,3 @@ function getMetaData(array, pickKeys, handler) {
|
|
|
30
30
|
return;
|
|
31
31
|
return (0, map_1.default)(array, (row) => (0, pick_1.default)(row, pickKeys));
|
|
32
32
|
}
|
|
33
|
-
exports.getMetaData = getMetaData;
|
package/lib/helpers.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ContentstackClient } from '.';
|
|
2
2
|
export declare const isAuthenticated: () => boolean;
|
|
3
3
|
export declare const doesBranchExist: (stack: any, branchName: any) => Promise<any>;
|
|
4
|
-
export declare const getBranchFromAlias: (stack: ReturnType<ContentstackClient[
|
|
4
|
+
export declare const getBranchFromAlias: (stack: ReturnType<ContentstackClient["stack"]>, branchAlias: string) => Promise<string>;
|
|
5
5
|
export declare const isManagementTokenValid: (stackAPIKey: any, managementToken: any) => Promise<{
|
|
6
6
|
valid: boolean;
|
|
7
7
|
message?: undefined;
|
package/lib/helpers.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
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
|
+
exports.clearProgressModuleSetting = clearProgressModuleSetting;
|
|
5
|
+
exports.getAuthenticationMethod = getAuthenticationMethod;
|
|
6
|
+
exports.createLogContext = createLogContext;
|
|
4
7
|
const tslib_1 = require("tslib");
|
|
5
8
|
const recheck_1 = require("recheck");
|
|
6
9
|
const traverse_1 = tslib_1.__importDefault(require("traverse"));
|
|
@@ -251,7 +254,6 @@ function clearProgressModuleSetting() {
|
|
|
251
254
|
_1.configHandler.set('log', logConfig);
|
|
252
255
|
}
|
|
253
256
|
}
|
|
254
|
-
exports.clearProgressModuleSetting = clearProgressModuleSetting;
|
|
255
257
|
/**
|
|
256
258
|
* Get authentication method from config
|
|
257
259
|
* @returns Authentication method string ('OAuth', 'Basic Auth', or empty string)
|
|
@@ -268,7 +270,6 @@ function getAuthenticationMethod() {
|
|
|
268
270
|
// Return empty string if unknown
|
|
269
271
|
return '';
|
|
270
272
|
}
|
|
271
|
-
exports.getAuthenticationMethod = getAuthenticationMethod;
|
|
272
273
|
/**
|
|
273
274
|
* Creates a standardized context object for logging
|
|
274
275
|
* This context contains all session-level metadata that should be in session.json
|
|
@@ -296,4 +297,3 @@ function createLogContext(commandId, apiKey, authenticationMethod) {
|
|
|
296
297
|
authenticationMethod: authMethod,
|
|
297
298
|
};
|
|
298
299
|
}
|
|
299
|
-
exports.createLogContext = createLogContext;
|
|
@@ -229,8 +229,8 @@ export declare class HttpClient implements IHttpClient {
|
|
|
229
229
|
* Get the axios instance for interceptor access
|
|
230
230
|
*/
|
|
231
231
|
get interceptors(): {
|
|
232
|
-
request: import("axios").AxiosInterceptorManager<import("axios").InternalAxiosRequestConfig
|
|
233
|
-
response: import("axios").AxiosInterceptorManager<AxiosResponse
|
|
232
|
+
request: import("axios").AxiosInterceptorManager<import("axios").InternalAxiosRequestConfig>;
|
|
233
|
+
response: import("axios").AxiosInterceptorManager<AxiosResponse>;
|
|
234
234
|
};
|
|
235
235
|
/**
|
|
236
236
|
* Returns the request payload depending on the selected request payload format.
|
|
@@ -7,6 +7,22 @@ const http_response_1 = require("./http-response");
|
|
|
7
7
|
const config_handler_1 = tslib_1.__importDefault(require("../config-handler"));
|
|
8
8
|
const auth_handler_1 = tslib_1.__importDefault(require("../auth-handler"));
|
|
9
9
|
const proxy_helper_1 = require("../proxy-helper");
|
|
10
|
+
/**
|
|
11
|
+
* Derive request host from baseURL or url for NO_PROXY checks.
|
|
12
|
+
*/
|
|
13
|
+
function getRequestHost(baseURL, url) {
|
|
14
|
+
const toTry = [baseURL, url].filter(Boolean);
|
|
15
|
+
for (const candidateUrl of toTry) {
|
|
16
|
+
try {
|
|
17
|
+
const parsed = new URL(candidateUrl.startsWith('http') ? candidateUrl : `https://${candidateUrl}`);
|
|
18
|
+
return parsed.hostname || undefined;
|
|
19
|
+
}
|
|
20
|
+
catch (_a) {
|
|
21
|
+
// Invalid URL; try next candidate (baseURL or url)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
10
26
|
class HttpClient {
|
|
11
27
|
/**
|
|
12
28
|
* Createa new pending HTTP request instance.
|
|
@@ -340,9 +356,10 @@ class HttpClient {
|
|
|
340
356
|
this.headers({ 'x-header-ea': Object.values(earlyAccessHeaders).join(',') });
|
|
341
357
|
}
|
|
342
358
|
}
|
|
343
|
-
// Configure proxy if available
|
|
359
|
+
// Configure proxy if available. NO_PROXY has priority: hosts in NO_PROXY never use proxy.
|
|
344
360
|
if (!this.request.proxy) {
|
|
345
|
-
const
|
|
361
|
+
const host = getRequestHost(this.request.baseURL, url);
|
|
362
|
+
const proxyConfig = host ? (0, proxy_helper_1.getProxyConfigForHost)(host) : (0, proxy_helper_1.getProxyConfig)();
|
|
346
363
|
if (proxyConfig) {
|
|
347
364
|
this.request.proxy = proxyConfig;
|
|
348
365
|
}
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DefaultProgressStrategy = exports.CustomProgressStrategy = exports.ProgressStrategyRegistry = exports.PrimaryProcessStrategy = exports.SummaryManager = exports.CLIProgressManager = exports.getSessionLogPath = 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.
|
|
3
|
+
exports.DefaultProgressStrategy = exports.CustomProgressStrategy = exports.ProgressStrategyRegistry = exports.PrimaryProcessStrategy = exports.SummaryManager = exports.CLIProgressManager = exports.getSessionLogPath = 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.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.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;
|
|
@@ -1,30 +1,51 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Table prompt for inquirer v12.
|
|
3
|
+
* Standalone implementation (no inquirer/lib) compatible with
|
|
4
|
+
* inquirer 12 legacy adapter: constructor(question, rl, answers) + run() returns Promise.
|
|
5
|
+
*/
|
|
6
|
+
import * as readline from 'readline';
|
|
7
|
+
interface ChoiceLike {
|
|
8
|
+
name?: string;
|
|
9
|
+
value?: string;
|
|
10
|
+
}
|
|
11
|
+
interface TableQuestion {
|
|
12
|
+
message?: string;
|
|
13
|
+
name?: string;
|
|
14
|
+
columns?: ChoiceLike[];
|
|
15
|
+
rows?: ChoiceLike[];
|
|
16
|
+
selectAll?: boolean;
|
|
17
|
+
pageSize?: number;
|
|
18
|
+
}
|
|
19
|
+
type ReadLine = readline.Interface & {
|
|
20
|
+
input: NodeJS.ReadableStream;
|
|
21
|
+
output: NodeJS.WritableStream;
|
|
22
|
+
};
|
|
23
|
+
declare class TablePrompt {
|
|
24
|
+
private question;
|
|
25
|
+
private rl;
|
|
26
|
+
private selectAll;
|
|
27
|
+
private columns;
|
|
28
|
+
private rows;
|
|
29
|
+
private pointer;
|
|
30
|
+
private horizontalPointer;
|
|
31
|
+
private values;
|
|
32
|
+
private pageSize;
|
|
33
|
+
private spaceKeyPressed;
|
|
34
|
+
private status;
|
|
35
|
+
private done;
|
|
36
|
+
private lastHeight;
|
|
37
|
+
constructor(question: TableQuestion, rl: ReadLine, _answers: Record<string, unknown>);
|
|
38
|
+
run(): Promise<(string | undefined)[]>;
|
|
39
|
+
private getCurrentValue;
|
|
40
|
+
private onSubmit;
|
|
41
|
+
private onUpKey;
|
|
42
|
+
private onDownKey;
|
|
43
|
+
private onLeftKey;
|
|
44
|
+
private onRightKey;
|
|
45
|
+
private selectAllValues;
|
|
46
|
+
private onSpaceKey;
|
|
47
|
+
private paginate;
|
|
48
|
+
private getMessage;
|
|
49
|
+
private render;
|
|
29
50
|
}
|
|
30
51
|
export = TablePrompt;
|
|
@@ -1,120 +1,125 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
]
|
|
29
|
-
: [];
|
|
30
|
-
this.columns = new Choices(this.opt.columns, []);
|
|
2
|
+
/**
|
|
3
|
+
* Table prompt for inquirer v12.
|
|
4
|
+
* Standalone implementation (no inquirer/lib) compatible with
|
|
5
|
+
* inquirer 12 legacy adapter: constructor(question, rl, answers) + run() returns Promise.
|
|
6
|
+
*/
|
|
7
|
+
const tslib_1 = require("tslib");
|
|
8
|
+
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
9
|
+
const figures_1 = tslib_1.__importDefault(require("figures"));
|
|
10
|
+
const cli_cursor_1 = tslib_1.__importDefault(require("cli-cursor"));
|
|
11
|
+
const cli_table_1 = tslib_1.__importDefault(require("cli-table"));
|
|
12
|
+
function pluckName(c) {
|
|
13
|
+
var _a, _b;
|
|
14
|
+
return (_a = c.name) !== null && _a !== void 0 ? _a : String((_b = c.value) !== null && _b !== void 0 ? _b : '');
|
|
15
|
+
}
|
|
16
|
+
function getValue(c) {
|
|
17
|
+
var _a, _b;
|
|
18
|
+
return (_b = (_a = c.value) !== null && _a !== void 0 ? _a : c.name) !== null && _b !== void 0 ? _b : '';
|
|
19
|
+
}
|
|
20
|
+
class TablePrompt {
|
|
21
|
+
constructor(question, rl, _answers) {
|
|
22
|
+
this.question = question;
|
|
23
|
+
this.rl = rl;
|
|
24
|
+
this.selectAll = Boolean(question.selectAll);
|
|
25
|
+
this.columns = Array.isArray(question.columns) ? question.columns : [];
|
|
26
|
+
this.rows = this.selectAll
|
|
27
|
+
? [{ name: 'Select All', value: 'selectAll' }, ...(question.rows || [])]
|
|
28
|
+
: Array.isArray(question.rows) ? question.rows : [];
|
|
31
29
|
this.pointer = 0;
|
|
32
30
|
this.horizontalPointer = 0;
|
|
33
|
-
this.
|
|
34
|
-
this.
|
|
35
|
-
this.
|
|
31
|
+
this.values = this.columns.map(() => undefined);
|
|
32
|
+
this.pageSize = Number(question.pageSize) || 5;
|
|
33
|
+
this.spaceKeyPressed = false;
|
|
34
|
+
this.status = 'idle';
|
|
35
|
+
this.done = null;
|
|
36
|
+
this.lastHeight = 0;
|
|
36
37
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
38
|
+
run() {
|
|
39
|
+
return new Promise((resolve) => {
|
|
40
|
+
this.done = (value) => {
|
|
41
|
+
this.status = 'answered';
|
|
42
|
+
cli_cursor_1.default.show();
|
|
43
|
+
resolve(value);
|
|
44
|
+
};
|
|
45
|
+
const onKeypress = (_str, key) => {
|
|
46
|
+
if (this.status === 'answered')
|
|
47
|
+
return;
|
|
48
|
+
if (key.ctrl && key.name === 'c')
|
|
49
|
+
return;
|
|
50
|
+
switch (key.name) {
|
|
51
|
+
case 'up':
|
|
52
|
+
this.onUpKey();
|
|
53
|
+
break;
|
|
54
|
+
case 'down':
|
|
55
|
+
this.onDownKey();
|
|
56
|
+
break;
|
|
57
|
+
case 'left':
|
|
58
|
+
this.onLeftKey();
|
|
59
|
+
break;
|
|
60
|
+
case 'right':
|
|
61
|
+
this.onRightKey();
|
|
62
|
+
break;
|
|
63
|
+
case 'space':
|
|
64
|
+
this.onSpaceKey();
|
|
65
|
+
break;
|
|
66
|
+
case 'enter':
|
|
67
|
+
case 'return':
|
|
68
|
+
this.onSubmit();
|
|
69
|
+
break;
|
|
70
|
+
default:
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
this.render();
|
|
74
|
+
};
|
|
75
|
+
this.rl.input.on('keypress', onKeypress);
|
|
76
|
+
cli_cursor_1.default.hide();
|
|
77
|
+
this.render();
|
|
56
78
|
});
|
|
57
|
-
events.normalizedUpKey.pipe(takeUntil(validation.success)).forEach(this.onUpKey.bind(this));
|
|
58
|
-
events.normalizedDownKey.pipe(takeUntil(validation.success)).forEach(this.onDownKey.bind(this));
|
|
59
|
-
events.spaceKey.pipe(takeUntil(validation.success)).forEach(this.onSpaceKey.bind(this));
|
|
60
|
-
if (this.rl.line) {
|
|
61
|
-
this.onKeypress();
|
|
62
|
-
}
|
|
63
|
-
cliCursor.hide();
|
|
64
|
-
this.render();
|
|
65
|
-
return this;
|
|
66
79
|
}
|
|
67
80
|
getCurrentValue() {
|
|
68
|
-
const
|
|
69
|
-
this.rows.
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
return
|
|
73
|
-
}
|
|
74
|
-
onDownKey() {
|
|
75
|
-
const length = this.rows.realLength;
|
|
76
|
-
this.pointer = this.pointer < length - 1 ? this.pointer + 1 : this.pointer;
|
|
77
|
-
this.render();
|
|
81
|
+
const out = [];
|
|
82
|
+
for (let i = 0; i < this.rows.length; i++) {
|
|
83
|
+
out.push(this.values[i]);
|
|
84
|
+
}
|
|
85
|
+
return out;
|
|
78
86
|
}
|
|
79
|
-
|
|
80
|
-
this.
|
|
81
|
-
|
|
82
|
-
this.
|
|
83
|
-
this.
|
|
84
|
-
|
|
85
|
-
if (this.selectAll) {
|
|
86
|
-
// remove select all row
|
|
87
|
-
const [, ...truncatedValue] = state.value;
|
|
88
|
-
this.done(truncatedValue);
|
|
87
|
+
onSubmit() {
|
|
88
|
+
if (!this.done)
|
|
89
|
+
return;
|
|
90
|
+
const raw = this.getCurrentValue();
|
|
91
|
+
if (this.selectAll && raw.length > 0) {
|
|
92
|
+
this.done(raw.slice(1));
|
|
89
93
|
}
|
|
90
94
|
else {
|
|
91
|
-
this.done(
|
|
95
|
+
this.done(raw);
|
|
92
96
|
}
|
|
93
97
|
}
|
|
94
|
-
|
|
95
|
-
this.
|
|
98
|
+
onUpKey() {
|
|
99
|
+
this.pointer = this.pointer > 0 ? this.pointer - 1 : this.pointer;
|
|
100
|
+
}
|
|
101
|
+
onDownKey() {
|
|
102
|
+
const len = this.rows.length;
|
|
103
|
+
this.pointer = this.pointer < len - 1 ? this.pointer + 1 : this.pointer;
|
|
96
104
|
}
|
|
97
105
|
onLeftKey() {
|
|
98
|
-
const
|
|
99
|
-
this.horizontalPointer = this.horizontalPointer > 0 ? this.horizontalPointer - 1 :
|
|
100
|
-
this.render();
|
|
106
|
+
const len = this.columns.length;
|
|
107
|
+
this.horizontalPointer = this.horizontalPointer > 0 ? this.horizontalPointer - 1 : len - 1;
|
|
101
108
|
}
|
|
102
109
|
onRightKey() {
|
|
103
|
-
const
|
|
104
|
-
this.horizontalPointer = this.horizontalPointer <
|
|
105
|
-
this.render();
|
|
110
|
+
const len = this.columns.length;
|
|
111
|
+
this.horizontalPointer = this.horizontalPointer < len - 1 ? this.horizontalPointer + 1 : 0;
|
|
106
112
|
}
|
|
107
113
|
selectAllValues(value) {
|
|
108
|
-
|
|
109
|
-
for (let i = 0; i < this.rows.length; i++) {
|
|
110
|
-
values.push(value);
|
|
111
|
-
}
|
|
112
|
-
this.values = values;
|
|
114
|
+
this.values = this.rows.map(() => value);
|
|
113
115
|
}
|
|
114
116
|
onSpaceKey() {
|
|
115
|
-
|
|
116
|
-
const
|
|
117
|
-
|
|
117
|
+
const col = this.columns[this.horizontalPointer];
|
|
118
|
+
const row = this.rows[this.pointer];
|
|
119
|
+
if (!col)
|
|
120
|
+
return;
|
|
121
|
+
const value = getValue(col);
|
|
122
|
+
const rowValue = row ? getValue(row) : '';
|
|
118
123
|
if (rowValue === 'selectAll') {
|
|
119
124
|
this.selectAllValues(value);
|
|
120
125
|
}
|
|
@@ -122,55 +127,58 @@ class TablePrompt extends Base {
|
|
|
122
127
|
this.values[this.pointer] = value;
|
|
123
128
|
}
|
|
124
129
|
this.spaceKeyPressed = true;
|
|
125
|
-
this.render();
|
|
126
|
-
}
|
|
127
|
-
onUpKey() {
|
|
128
|
-
this.pointer = this.pointer > 0 ? this.pointer - 1 : this.pointer;
|
|
129
|
-
this.render();
|
|
130
130
|
}
|
|
131
131
|
paginate() {
|
|
132
|
-
const
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
132
|
+
const mid = Math.floor(this.pageSize / 2);
|
|
133
|
+
const len = this.rows.length;
|
|
134
|
+
let first = Math.max(0, this.pointer - mid);
|
|
135
|
+
let last = Math.min(first + this.pageSize - 1, len - 1);
|
|
136
|
+
const offset = this.pageSize - 1 - (last - first);
|
|
137
|
+
first = Math.max(0, first - offset);
|
|
138
|
+
return [first, last];
|
|
137
139
|
}
|
|
138
|
-
|
|
139
|
-
let
|
|
140
|
-
let bottomContent = '';
|
|
140
|
+
getMessage() {
|
|
141
|
+
let msg = this.question.message || 'Select';
|
|
141
142
|
if (!this.spaceKeyPressed) {
|
|
142
|
-
|
|
143
|
-
'(Press ' +
|
|
144
|
-
|
|
143
|
+
msg +=
|
|
144
|
+
' (Press ' +
|
|
145
|
+
chalk_1.default.cyan.bold('<space>') +
|
|
145
146
|
' to select, ' +
|
|
146
|
-
|
|
147
|
-
'
|
|
148
|
-
|
|
149
|
-
'
|
|
147
|
+
chalk_1.default.cyan.bold('<Up/Down>') +
|
|
148
|
+
' rows, ' +
|
|
149
|
+
chalk_1.default.cyan.bold('<Left/Right>') +
|
|
150
|
+
' columns, ' +
|
|
151
|
+
chalk_1.default.cyan.bold('<Enter>') +
|
|
152
|
+
' to confirm)';
|
|
150
153
|
}
|
|
154
|
+
return msg;
|
|
155
|
+
}
|
|
156
|
+
render() {
|
|
151
157
|
const [firstIndex, lastIndex] = this.paginate();
|
|
152
|
-
const table = new
|
|
153
|
-
head: [
|
|
158
|
+
const table = new cli_table_1.default({
|
|
159
|
+
head: [chalk_1.default.reset.dim(`${firstIndex + 1}-${lastIndex + 1} of ${this.rows.length}`)].concat(this.columns.map((c) => chalk_1.default.reset.bold(pluckName(c)))),
|
|
154
160
|
});
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
161
|
+
for (let rowIndex = firstIndex; rowIndex <= lastIndex; rowIndex++) {
|
|
162
|
+
const row = this.rows[rowIndex];
|
|
163
|
+
if (!row)
|
|
164
|
+
continue;
|
|
158
165
|
const columnValues = [];
|
|
159
|
-
this.columns.
|
|
160
|
-
const isSelected = this.status !== 'answered' && this.pointer === rowIndex && this.horizontalPointer ===
|
|
161
|
-
const
|
|
162
|
-
columnValues.push(`${isSelected ? '[' : ' '} ${
|
|
163
|
-
}
|
|
164
|
-
const chalkModifier = this.status !== 'answered' && this.pointer === rowIndex ?
|
|
165
|
-
table.push({
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if (
|
|
171
|
-
|
|
166
|
+
for (let colIndex = 0; colIndex < this.columns.length; colIndex++) {
|
|
167
|
+
const isSelected = this.status !== 'answered' && this.pointer === rowIndex && this.horizontalPointer === colIndex;
|
|
168
|
+
const cellValue = getValue(this.columns[colIndex]) === this.values[rowIndex] ? figures_1.default.radioOn : figures_1.default.radioOff;
|
|
169
|
+
columnValues.push(`${isSelected ? '[' : ' '} ${cellValue} ${isSelected ? ']' : ' '}`);
|
|
170
|
+
}
|
|
171
|
+
const chalkModifier = this.status !== 'answered' && this.pointer === rowIndex ? chalk_1.default.reset.bold.cyan : chalk_1.default.reset;
|
|
172
|
+
table.push({ [chalkModifier(pluckName(row))]: columnValues });
|
|
173
|
+
}
|
|
174
|
+
const message = this.getMessage() + '\n\n' + table.toString();
|
|
175
|
+
const lines = message.split('\n').length;
|
|
176
|
+
const out = this.rl.output;
|
|
177
|
+
if (this.lastHeight > 0) {
|
|
178
|
+
out.write('\u001b[' + this.lastHeight + 'A\u001b[0J');
|
|
172
179
|
}
|
|
173
|
-
|
|
180
|
+
out.write(message);
|
|
181
|
+
this.lastHeight = lines;
|
|
174
182
|
}
|
|
175
183
|
}
|
|
176
184
|
module.exports = TablePrompt;
|
package/lib/logger/log.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.cliErrorHandler = exports.v2Logger = exports.getSessionLogPath = void 0;
|
|
4
|
+
exports.handleAndLogError = handleAndLogError;
|
|
5
|
+
exports.getLogPath = getLogPath;
|
|
4
6
|
const tslib_1 = require("tslib");
|
|
5
7
|
const fs = tslib_1.__importStar(require("fs"));
|
|
6
8
|
const os = tslib_1.__importStar(require("os"));
|
|
@@ -68,7 +70,6 @@ function handleAndLogError(error, context, errorMessage) {
|
|
|
68
70
|
meta: classified.meta,
|
|
69
71
|
});
|
|
70
72
|
}
|
|
71
|
-
exports.handleAndLogError = handleAndLogError;
|
|
72
73
|
/**
|
|
73
74
|
* Get the log path for centralized logging
|
|
74
75
|
* Priority:
|
|
@@ -102,7 +103,6 @@ function getLogPath() {
|
|
|
102
103
|
// 4. Fallback to home directory
|
|
103
104
|
return path.join(os.homedir(), 'contentstack', 'logs');
|
|
104
105
|
}
|
|
105
|
-
exports.getLogPath = getLogPath;
|
|
106
106
|
// Re-export getSessionLogPath for external use
|
|
107
107
|
var session_path_1 = require("./session-path");
|
|
108
108
|
Object.defineProperty(exports, "getSessionLogPath", { enumerable: true, get: function () { return session_path_1.getSessionLogPath; } });
|
|
@@ -5,3 +5,8 @@
|
|
|
5
5
|
* @returns The session-specific log directory path
|
|
6
6
|
*/
|
|
7
7
|
export declare function getSessionLogPath(): string;
|
|
8
|
+
/**
|
|
9
|
+
* Clear the cached session path. Used by tests so each test gets a fresh path.
|
|
10
|
+
* Not needed in normal CLI usage (one process = one command = one cache).
|
|
11
|
+
*/
|
|
12
|
+
export declare function clearSessionLogPathCache(): void;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getSessionLogPath =
|
|
3
|
+
exports.getSessionLogPath = getSessionLogPath;
|
|
4
|
+
exports.clearSessionLogPathCache = clearSessionLogPathCache;
|
|
4
5
|
const tslib_1 = require("tslib");
|
|
5
6
|
const fs = tslib_1.__importStar(require("fs"));
|
|
6
7
|
const os = tslib_1.__importStar(require("os"));
|
|
@@ -49,6 +50,10 @@ function createSessionMetadataFile(sessionPath, metadata) {
|
|
|
49
50
|
// The session folder and logs will still be created
|
|
50
51
|
}
|
|
51
52
|
}
|
|
53
|
+
// Cache session path for the process so multiple callers (e.g. Logger's 5 level
|
|
54
|
+
// loggers, export/import command at end, completeProgressWithMessage per module)
|
|
55
|
+
// get one folder instead of many.
|
|
56
|
+
let cachedSessionPath = null;
|
|
52
57
|
/**
|
|
53
58
|
* Get the session-based log path for date-organized logging
|
|
54
59
|
* Structure: {basePath}/{YYYY-MM-DD}/{command}-{YYYYMMDD-HHMMSS}-{sessionId}/
|
|
@@ -56,6 +61,9 @@ function createSessionMetadataFile(sessionPath, metadata) {
|
|
|
56
61
|
* @returns The session-specific log directory path
|
|
57
62
|
*/
|
|
58
63
|
function getSessionLogPath() {
|
|
64
|
+
if (cachedSessionPath) {
|
|
65
|
+
return cachedSessionPath;
|
|
66
|
+
}
|
|
59
67
|
// Get base log path
|
|
60
68
|
const basePath = (0, log_1.getLogPath)();
|
|
61
69
|
// Get current date in YYYY-MM-DD format
|
|
@@ -91,6 +99,13 @@ function getSessionLogPath() {
|
|
|
91
99
|
const metadata = generateSessionMetadata(__1.configHandler.get('currentCommandId') || commandId, sessionId, now);
|
|
92
100
|
createSessionMetadataFile(sessionPath, metadata);
|
|
93
101
|
}
|
|
102
|
+
cachedSessionPath = sessionPath;
|
|
94
103
|
return sessionPath;
|
|
95
104
|
}
|
|
96
|
-
|
|
105
|
+
/**
|
|
106
|
+
* Clear the cached session path. Used by tests so each test gets a fresh path.
|
|
107
|
+
* Not needed in normal CLI usage (one process = one command = one cache).
|
|
108
|
+
*/
|
|
109
|
+
function clearSessionLogPathCache() {
|
|
110
|
+
cachedSessionPath = null;
|
|
111
|
+
}
|
package/lib/proxy-helper.d.ts
CHANGED
|
@@ -8,10 +8,51 @@ export interface ProxyConfig {
|
|
|
8
8
|
};
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* Parse NO_PROXY / no_proxy env (both uppercase and lowercase).
|
|
12
|
+
* NO_PROXY has priority over HTTP_PROXY/HTTPS_PROXY: hosts in this list never use the proxy.
|
|
13
|
+
* Values are hostnames only, comma-separated; leading dot matches subdomains (e.g. .contentstack.io).
|
|
14
|
+
* The bypass list is fully dynamic: only env values are used (no hardcoded default).
|
|
15
|
+
* @returns List of trimmed entries, or empty array when NO_PROXY/no_proxy is unset
|
|
16
|
+
*/
|
|
17
|
+
export declare function getNoProxyList(): string[];
|
|
18
|
+
/**
|
|
19
|
+
* Check if the given host should bypass the proxy based on NO_PROXY / no_proxy.
|
|
20
|
+
* Supports: exact host, leading-dot subdomain match (e.g. .contentstack.io), and wildcard *.
|
|
21
|
+
* @param host - Request hostname (with or without port; will be normalized)
|
|
22
|
+
* @returns true if proxy should not be used for this host
|
|
23
|
+
*/
|
|
24
|
+
export declare function shouldBypassProxy(host: string): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Get proxy configuration. Sources (in order): env (HTTP_PROXY/HTTPS_PROXY), then global config
|
|
27
|
+
* from `csdx config:set:proxy --host --port --protocol `.
|
|
28
|
+
* For per-request use, prefer getProxyConfigForHost(host) so NO_PROXY overrides both sources.
|
|
12
29
|
* @returns ProxyConfig object or undefined if no proxy is configured
|
|
13
30
|
*/
|
|
14
31
|
export declare function getProxyConfig(): ProxyConfig | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Get proxy config only when the request host is not in NO_PROXY.
|
|
34
|
+
* NO_PROXY has priority over both HTTP_PROXY/HTTPS_PROXY and over proxy set via
|
|
35
|
+
* `csdx config:set:proxy` — if the host matches NO_PROXY, no proxy is used.
|
|
36
|
+
* Use this for all outbound requests so Contentstack and localhost bypass the proxy when set.
|
|
37
|
+
* @param host - Request hostname (e.g. api.contentstack.io or full URL like https://api.contentstack.io)
|
|
38
|
+
* @returns ProxyConfig or undefined if proxy is disabled or host should bypass (NO_PROXY)
|
|
39
|
+
*/
|
|
40
|
+
export declare function getProxyConfigForHost(host: string): ProxyConfig | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Resolve request host for proxy/NO_PROXY checks: config.host or default CMA from region.
|
|
43
|
+
* Use when the caller may omit host so NO_PROXY still applies (e.g. from region.cma).
|
|
44
|
+
* @param config - Object with optional host (e.g. API client config)
|
|
45
|
+
* @returns Host string (hostname or empty)
|
|
46
|
+
*/
|
|
47
|
+
export declare function resolveRequestHost(config: {
|
|
48
|
+
host?: string;
|
|
49
|
+
}): string;
|
|
50
|
+
/**
|
|
51
|
+
* Temporarily clear proxy-related env vars so SDK/axios cannot use them.
|
|
52
|
+
* Call the returned function to restore. Use when creating a client for a host in NO_PROXY.
|
|
53
|
+
* @returns Restore function (call to put env back)
|
|
54
|
+
*/
|
|
55
|
+
export declare function clearProxyEnv(): () => void;
|
|
15
56
|
/**
|
|
16
57
|
* Check if proxy is configured (from any source)
|
|
17
58
|
* @returns true if proxy is configured, false otherwise
|
package/lib/proxy-helper.js
CHANGED
|
@@ -1,14 +1,99 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.getNoProxyList = getNoProxyList;
|
|
4
|
+
exports.shouldBypassProxy = shouldBypassProxy;
|
|
5
|
+
exports.getProxyConfig = getProxyConfig;
|
|
6
|
+
exports.getProxyConfigForHost = getProxyConfigForHost;
|
|
7
|
+
exports.resolveRequestHost = resolveRequestHost;
|
|
8
|
+
exports.clearProxyEnv = clearProxyEnv;
|
|
9
|
+
exports.hasProxy = hasProxy;
|
|
10
|
+
exports.getProxyUrl = getProxyUrl;
|
|
4
11
|
const tslib_1 = require("tslib");
|
|
5
12
|
const config_handler_1 = tslib_1.__importDefault(require("./config-handler"));
|
|
6
13
|
/**
|
|
7
|
-
*
|
|
14
|
+
* Parse NO_PROXY / no_proxy env (both uppercase and lowercase).
|
|
15
|
+
* NO_PROXY has priority over HTTP_PROXY/HTTPS_PROXY: hosts in this list never use the proxy.
|
|
16
|
+
* Values are hostnames only, comma-separated; leading dot matches subdomains (e.g. .contentstack.io).
|
|
17
|
+
* The bypass list is fully dynamic: only env values are used (no hardcoded default).
|
|
18
|
+
* @returns List of trimmed entries, or empty array when NO_PROXY/no_proxy is unset
|
|
19
|
+
*/
|
|
20
|
+
function getNoProxyList() {
|
|
21
|
+
const raw = process.env.NO_PROXY || process.env.no_proxy || '';
|
|
22
|
+
return raw
|
|
23
|
+
.split(',')
|
|
24
|
+
.map((s) => s.trim())
|
|
25
|
+
.filter(Boolean);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Normalize host for NO_PROXY matching: strip protocol/URL, port, lowercase, handle IPv6 brackets.
|
|
29
|
+
* Accepts hostname, host:port, or full URL (e.g. https://api.contentstack.io).
|
|
30
|
+
*/
|
|
31
|
+
function normalizeHost(host) {
|
|
32
|
+
if (!host || typeof host !== 'string')
|
|
33
|
+
return '';
|
|
34
|
+
let h = host.trim().toLowerCase();
|
|
35
|
+
// If it looks like a URL, extract hostname so NO_PROXY matching works (e.g. region.cma is full URL)
|
|
36
|
+
if (h.includes('://')) {
|
|
37
|
+
try {
|
|
38
|
+
const u = new URL(h);
|
|
39
|
+
h = u.hostname;
|
|
40
|
+
}
|
|
41
|
+
catch (_a) {
|
|
42
|
+
// fall through to port stripping below
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const portIdx = h.lastIndexOf(':');
|
|
46
|
+
if (h.startsWith('[')) {
|
|
47
|
+
const close = h.indexOf(']');
|
|
48
|
+
if (close !== -1 && h.length > close + 1 && h[close + 1] === ':') {
|
|
49
|
+
h = h.slice(1, close);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else if (portIdx !== -1) {
|
|
53
|
+
const after = h.slice(portIdx + 1);
|
|
54
|
+
if (/^\d+$/.test(after)) {
|
|
55
|
+
h = h.slice(0, portIdx);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return h;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Check if the given host should bypass the proxy based on NO_PROXY / no_proxy.
|
|
62
|
+
* Supports: exact host, leading-dot subdomain match (e.g. .contentstack.io), and wildcard *.
|
|
63
|
+
* @param host - Request hostname (with or without port; will be normalized)
|
|
64
|
+
* @returns true if proxy should not be used for this host
|
|
65
|
+
*/
|
|
66
|
+
function shouldBypassProxy(host) {
|
|
67
|
+
const normalized = normalizeHost(host);
|
|
68
|
+
if (!normalized)
|
|
69
|
+
return false;
|
|
70
|
+
const list = getNoProxyList();
|
|
71
|
+
for (const entry of list) {
|
|
72
|
+
const e = entry.trim().toLowerCase();
|
|
73
|
+
if (!e)
|
|
74
|
+
continue;
|
|
75
|
+
if (e === '*')
|
|
76
|
+
return true;
|
|
77
|
+
if (e.startsWith('.')) {
|
|
78
|
+
const domain = e.slice(1);
|
|
79
|
+
if (normalized === domain || normalized.endsWith(e))
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
if (normalized === e)
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Get proxy configuration. Sources (in order): env (HTTP_PROXY/HTTPS_PROXY), then global config
|
|
91
|
+
* from `csdx config:set:proxy --host --port --protocol `.
|
|
92
|
+
* For per-request use, prefer getProxyConfigForHost(host) so NO_PROXY overrides both sources.
|
|
8
93
|
* @returns ProxyConfig object or undefined if no proxy is configured
|
|
9
94
|
*/
|
|
10
95
|
function getProxyConfig() {
|
|
11
|
-
// Priority 1:
|
|
96
|
+
// Priority 1: Environment variables (HTTPS_PROXY or HTTP_PROXY)
|
|
12
97
|
const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY;
|
|
13
98
|
if (proxyUrl) {
|
|
14
99
|
try {
|
|
@@ -35,7 +120,7 @@ function getProxyConfig() {
|
|
|
35
120
|
// Invalid URL, continue to check global config
|
|
36
121
|
}
|
|
37
122
|
}
|
|
38
|
-
// Priority 2:
|
|
123
|
+
// Priority 2: Global config (csdx config:set:proxy)
|
|
39
124
|
const globalProxyConfig = config_handler_1.default.get('proxy');
|
|
40
125
|
if (globalProxyConfig) {
|
|
41
126
|
if (typeof globalProxyConfig === 'object') {
|
|
@@ -72,7 +157,65 @@ function getProxyConfig() {
|
|
|
72
157
|
}
|
|
73
158
|
return undefined;
|
|
74
159
|
}
|
|
75
|
-
|
|
160
|
+
/**
|
|
161
|
+
* Get proxy config only when the request host is not in NO_PROXY.
|
|
162
|
+
* NO_PROXY has priority over both HTTP_PROXY/HTTPS_PROXY and over proxy set via
|
|
163
|
+
* `csdx config:set:proxy` — if the host matches NO_PROXY, no proxy is used.
|
|
164
|
+
* Use this for all outbound requests so Contentstack and localhost bypass the proxy when set.
|
|
165
|
+
* @param host - Request hostname (e.g. api.contentstack.io or full URL like https://api.contentstack.io)
|
|
166
|
+
* @returns ProxyConfig or undefined if proxy is disabled or host should bypass (NO_PROXY)
|
|
167
|
+
*/
|
|
168
|
+
function getProxyConfigForHost(host) {
|
|
169
|
+
if (shouldBypassProxy(host))
|
|
170
|
+
return undefined;
|
|
171
|
+
return getProxyConfig();
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Resolve request host for proxy/NO_PROXY checks: config.host or default CMA from region.
|
|
175
|
+
* Use when the caller may omit host so NO_PROXY still applies (e.g. from region.cma).
|
|
176
|
+
* @param config - Object with optional host (e.g. API client config)
|
|
177
|
+
* @returns Host string (hostname or empty)
|
|
178
|
+
*/
|
|
179
|
+
function resolveRequestHost(config) {
|
|
180
|
+
var _a;
|
|
181
|
+
if (config.host)
|
|
182
|
+
return config.host;
|
|
183
|
+
const cma = (_a = config_handler_1.default.get('region')) === null || _a === void 0 ? void 0 : _a.cma;
|
|
184
|
+
if (cma && typeof cma === 'string') {
|
|
185
|
+
if (cma.startsWith('http')) {
|
|
186
|
+
try {
|
|
187
|
+
const u = new URL(cma);
|
|
188
|
+
return u.hostname || cma;
|
|
189
|
+
}
|
|
190
|
+
catch (_b) {
|
|
191
|
+
return cma;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return cma;
|
|
195
|
+
}
|
|
196
|
+
return '';
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Temporarily clear proxy-related env vars so SDK/axios cannot use them.
|
|
200
|
+
* Call the returned function to restore. Use when creating a client for a host in NO_PROXY.
|
|
201
|
+
* @returns Restore function (call to put env back)
|
|
202
|
+
*/
|
|
203
|
+
function clearProxyEnv() {
|
|
204
|
+
const saved = {};
|
|
205
|
+
const keys = ['HTTP_PROXY', 'HTTPS_PROXY', 'http_proxy', 'https_proxy', 'ALL_PROXY', 'all_proxy'];
|
|
206
|
+
for (const k of keys) {
|
|
207
|
+
if (k in process.env) {
|
|
208
|
+
saved[k] = process.env[k];
|
|
209
|
+
delete process.env[k];
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return () => {
|
|
213
|
+
for (const k of keys) {
|
|
214
|
+
if (saved[k] !== undefined)
|
|
215
|
+
process.env[k] = saved[k];
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
}
|
|
76
219
|
/**
|
|
77
220
|
* Check if proxy is configured (from any source)
|
|
78
221
|
* @returns true if proxy is configured, false otherwise
|
|
@@ -80,7 +223,6 @@ exports.getProxyConfig = getProxyConfig;
|
|
|
80
223
|
function hasProxy() {
|
|
81
224
|
return !!getProxyConfig() || !!process.env.HTTPS_PROXY || !!process.env.HTTP_PROXY || !!config_handler_1.default.get('proxy');
|
|
82
225
|
}
|
|
83
|
-
exports.hasProxy = hasProxy;
|
|
84
226
|
/**
|
|
85
227
|
* Get proxy URL string for display purposes
|
|
86
228
|
* @returns Proxy URL string or 'proxy server' if not available
|
|
@@ -100,4 +242,3 @@ function getProxyUrl() {
|
|
|
100
242
|
}
|
|
101
243
|
return 'proxy server';
|
|
102
244
|
}
|
|
103
|
-
exports.getProxyUrl = getProxyUrl;
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentstack/cli-utilities",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.3",
|
|
4
4
|
"description": "Utilities for contentstack projects",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"prepack": "pnpm compile",
|
|
9
|
-
"
|
|
9
|
+
"build": "pnpm compile",
|
|
10
|
+
"clean": "rm -rf ./lib ./node_modules tsconfig.tsbuildinfo",
|
|
10
11
|
"compile": "tsc -b tsconfig.json",
|
|
11
12
|
"test:report": "tsc -p test && nyc --reporter=lcov --extension .ts mocha --forbid-only \"test/**/*.test.ts\"",
|
|
12
13
|
"pretest": "tsc -p test",
|
|
@@ -43,7 +44,7 @@
|
|
|
43
44
|
"conf": "^10.2.0",
|
|
44
45
|
"dotenv": "^16.6.1",
|
|
45
46
|
"figures": "^3.2.0",
|
|
46
|
-
"inquirer": "
|
|
47
|
+
"inquirer": "12.11.1",
|
|
47
48
|
"inquirer-search-checkbox": "^1.0.0",
|
|
48
49
|
"inquirer-search-list": "^1.2.6",
|
|
49
50
|
"js-yaml": "^4.1.1",
|
|
@@ -67,7 +68,7 @@
|
|
|
67
68
|
"@types/inquirer": "^9.0.8",
|
|
68
69
|
"@types/mkdirp": "^1.0.2",
|
|
69
70
|
"@types/mocha": "^10.0.10",
|
|
70
|
-
"@types/node": "^
|
|
71
|
+
"@types/node": "^18.11.9",
|
|
71
72
|
"@types/sinon": "^21.0.0",
|
|
72
73
|
"@types/traverse": "^0.6.37",
|
|
73
74
|
"chai": "^4.5.0",
|
|
@@ -79,6 +80,6 @@
|
|
|
79
80
|
"nyc": "^15.1.0",
|
|
80
81
|
"sinon": "^21.0.1",
|
|
81
82
|
"ts-node": "^10.9.2",
|
|
82
|
-
"typescript": "^
|
|
83
|
+
"typescript": "^5.0.0"
|
|
83
84
|
}
|
|
84
|
-
}
|
|
85
|
+
}
|