@contentstack/cli-utilities 2.0.0-beta.1 → 2.0.0-beta.11

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.
Files changed (38) hide show
  1. package/lib/auth-handler.d.ts +5 -2
  2. package/lib/auth-handler.js +29 -29
  3. package/lib/chalk.d.ts +15 -0
  4. package/lib/chalk.js +66 -0
  5. package/lib/cli-ux.js +23 -10
  6. package/lib/config-handler.js +4 -4
  7. package/lib/constants/logging.d.ts +1 -1
  8. package/lib/constants/logging.js +3 -3
  9. package/lib/content-type-utils.d.ts +2 -2
  10. package/lib/content-type-utils.js +10 -8
  11. package/lib/contentstack-management-sdk.js +14 -4
  12. package/lib/contentstack-marketplace-sdk.d.ts +2 -2
  13. package/lib/contentstack-marketplace-sdk.js +1 -1
  14. package/lib/fs-utility/core.d.ts +0 -1
  15. package/lib/fs-utility/core.js +2 -6
  16. package/lib/fs-utility/helper.js +2 -3
  17. package/lib/helpers.d.ts +3 -1
  18. package/lib/helpers.js +14 -4
  19. package/lib/http-client/client.d.ts +2 -2
  20. package/lib/http-client/client.js +22 -2
  21. package/lib/http-client/http-response.d.ts +1 -1
  22. package/lib/http-client/http-response.js +1 -0
  23. package/lib/index.d.ts +3 -1
  24. package/lib/index.js +4 -1
  25. package/lib/inquirer-table-prompt.d.ts +49 -28
  26. package/lib/inquirer-table-prompt.js +144 -136
  27. package/lib/interfaces/index.d.ts +3 -1
  28. package/lib/logger/cli-error-handler.js +1 -1
  29. package/lib/logger/log.js +4 -4
  30. package/lib/logger/session-path.d.ts +5 -0
  31. package/lib/logger/session-path.js +18 -3
  32. package/lib/message-handler.d.ts +0 -3
  33. package/lib/message-handler.js +6 -10
  34. package/lib/progress-summary/cli-progress-manager.js +39 -35
  35. package/lib/progress-summary/summary-manager.js +30 -30
  36. package/lib/proxy-helper.d.ts +42 -1
  37. package/lib/proxy-helper.js +183 -32
  38. package/package.json +30 -28
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
- const chalk_1 = tslib_1.__importDefault(require("chalk"));
4
+ const chalk_1 = require("../chalk");
5
5
  const ora_1 = tslib_1.__importDefault(require("ora"));
6
6
  const cli_progress_1 = tslib_1.__importDefault(require("cli-progress"));
7
7
  const summary_manager_1 = tslib_1.__importDefault(require("./summary-manager"));
@@ -46,11 +46,11 @@ class CLIProgressManager {
46
46
  return;
47
47
  const safeBranchName = branchName || 'main';
48
48
  const branchInfo = headerTitle || `${safeBranchName === null || safeBranchName === void 0 ? void 0 : safeBranchName.toUpperCase()} CONTENT`;
49
- console.log('\n' + chalk_1.default.bold('='.repeat(80)));
49
+ console.log('\n' + (0, chalk_1.getChalk)().bold('='.repeat(80)));
50
50
  if (branchInfo) {
51
- console.log(chalk_1.default.bold.white(` ${branchInfo}`));
51
+ console.log((0, chalk_1.getChalk)().bold.white(` ${branchInfo}`));
52
52
  }
53
- console.log(chalk_1.default.bold('='.repeat(80)) + '\n');
53
+ console.log((0, chalk_1.getChalk)().bold('='.repeat(80)) + '\n');
54
54
  }
55
55
  /**
56
56
  * Print the final summary for all modules using strategies.
@@ -240,20 +240,20 @@ class CLIProgressManager {
240
240
  this.multiBar = new cli_progress_1.default.MultiBar({
241
241
  clearOnComplete: false,
242
242
  hideCursor: true,
243
- format: ' {label} |' + chalk_1.default.cyan('{bar}') + '| {percentage}% | {value}/{total} | {status}',
243
+ format: ' {label} |' + (0, chalk_1.getChalk)().cyan('{bar}') + '| {percentage}% | {value}/{total} | {status}',
244
244
  barCompleteChar: '\u2588',
245
245
  barIncompleteChar: '\u2591',
246
246
  }, cli_progress_1.default.Presets.shades_classic);
247
247
  if (!this.showConsoleLogs) {
248
- console.log(chalk_1.default.bold.cyan(`\n${this.moduleName}:`));
248
+ console.log((0, chalk_1.getChalk)().bold.cyan(`\n${this.moduleName}:`));
249
249
  }
250
250
  }
251
251
  else if (this.total > 0) {
252
252
  if (!this.showConsoleLogs) {
253
- console.log(chalk_1.default.bold.cyan(`\n${this.moduleName}:`));
253
+ console.log((0, chalk_1.getChalk)().bold.cyan(`\n${this.moduleName}:`));
254
254
  }
255
255
  this.progressBar = new cli_progress_1.default.SingleBar({
256
- format: ' {label} |' + chalk_1.default.cyan('{bar}') + '| {percentage}% | {value}/{total} | {status}',
256
+ format: ' {label} |' + (0, chalk_1.getChalk)().cyan('{bar}') + '| {percentage}% | {value}/{total} | {status}',
257
257
  barCompleteChar: '\u2588',
258
258
  barIncompleteChar: '\u2591',
259
259
  hideCursor: true,
@@ -261,13 +261,13 @@ class CLIProgressManager {
261
261
  const formattedName = this.formatModuleName(this.moduleName);
262
262
  const displayName = formattedName.length > 20 ? formattedName.substring(0, 17) + '...' : formattedName;
263
263
  this.progressBar.start(this.total, 0, {
264
- label: chalk_1.default.gray(` └─ ${displayName}`.padEnd(25)),
265
- status: chalk_1.default.gray('Starting...'),
264
+ label: (0, chalk_1.getChalk)().gray(` └─ ${displayName}`.padEnd(25)),
265
+ status: (0, chalk_1.getChalk)().gray('Starting...'),
266
266
  percentage: ' 0',
267
267
  });
268
268
  }
269
269
  else {
270
- this.spinner = (0, ora_1.default)(`${chalk_1.default.bold(this.moduleName)}: Processing...`).start();
270
+ this.spinner = (0, ora_1.default)(`${(0, chalk_1.getChalk)().bold(this.moduleName)}: Processing...`).start();
271
271
  }
272
272
  }
273
273
  /**
@@ -289,8 +289,8 @@ class CLIProgressManager {
289
289
  const displayName = this.formatProcessName(processName);
290
290
  const indentedLabel = ` ├─ ${displayName}`.padEnd(25);
291
291
  process.progressBar = this.multiBar.create(total, 0, {
292
- label: chalk_1.default.gray(indentedLabel),
293
- status: chalk_1.default.gray('Pending'),
292
+ label: (0, chalk_1.getChalk)().gray(indentedLabel),
293
+ status: (0, chalk_1.getChalk)().gray('Pending'),
294
294
  percentage: ' 0',
295
295
  });
296
296
  }
@@ -326,8 +326,8 @@ class CLIProgressManager {
326
326
  const displayName = this.formatProcessName(processName);
327
327
  const indentedLabel = ` ├─ ${displayName}`.padEnd(25);
328
328
  process.progressBar.update(0, {
329
- label: chalk_1.default.yellow(indentedLabel),
330
- status: chalk_1.default.yellow('Processing'),
329
+ label: (0, chalk_1.getChalk)().yellow(indentedLabel),
330
+ status: (0, chalk_1.getChalk)().yellow('Processing'),
331
331
  percentage: ' 0',
332
332
  });
333
333
  }
@@ -356,12 +356,12 @@ class CLIProgressManager {
356
356
  const percentage = Math.round((totalProcessed / process.total) * 100);
357
357
  const formattedPercentage = this.formatPercentage(percentage);
358
358
  const statusText = success
359
- ? chalk_1.default.green(`✓ Complete (${process.successCount}/${process.current})`)
360
- : chalk_1.default.red(`✗ Failed (${process.successCount}/${process.current})`);
359
+ ? (0, chalk_1.getChalk)().green(`✓ Complete (${process.successCount}/${process.current})`)
360
+ : (0, chalk_1.getChalk)().red(`✗ Failed (${process.successCount}/${process.current})`);
361
361
  const displayName = this.formatProcessName(processName);
362
362
  const indentedLabel = ` ├─ ${displayName}`.padEnd(25);
363
363
  process.progressBar.update(process.total, {
364
- label: success ? chalk_1.default.green(indentedLabel) : chalk_1.default.red(indentedLabel),
364
+ label: success ? (0, chalk_1.getChalk)().green(indentedLabel) : (0, chalk_1.getChalk)().red(indentedLabel),
365
365
  status: statusText,
366
366
  percentage: formattedPercentage,
367
367
  });
@@ -382,8 +382,8 @@ class CLIProgressManager {
382
382
  const displayName = this.formatProcessName(processName);
383
383
  const indentedLabel = ` ├─ ${displayName}`.padEnd(25);
384
384
  process.progressBar.update(process.current, {
385
- label: chalk_1.default.yellow(indentedLabel),
386
- status: chalk_1.default.yellow(message),
385
+ label: (0, chalk_1.getChalk)().yellow(indentedLabel),
386
+ status: (0, chalk_1.getChalk)().yellow(message),
387
387
  percentage: formattedPercentage,
388
388
  });
389
389
  }
@@ -394,13 +394,13 @@ class CLIProgressManager {
394
394
  const formattedName = this.formatModuleName(this.moduleName);
395
395
  const displayName = formattedName.length > 20 ? formattedName.substring(0, 17) + '...' : formattedName;
396
396
  this.progressBar.update(this.progressBar.getProgress() * this.total, {
397
- label: chalk_1.default.yellow(` └─ ${displayName}`.padEnd(25)),
398
- status: chalk_1.default.yellow(message),
397
+ label: (0, chalk_1.getChalk)().yellow(` └─ ${displayName}`.padEnd(25)),
398
+ status: (0, chalk_1.getChalk)().yellow(message),
399
399
  percentage: formattedPercentage,
400
400
  });
401
401
  }
402
402
  else if (this.spinner) {
403
- this.spinner.text = `${chalk_1.default.bold(this.moduleName)}: ${message}`;
403
+ this.spinner.text = `${(0, chalk_1.getChalk)().bold(this.moduleName)}: ${message}`;
404
404
  }
405
405
  }
406
406
  return this;
@@ -444,8 +444,8 @@ class CLIProgressManager {
444
444
  const displayName = this.formatProcessName(targetProcess);
445
445
  const indentedLabel = ` ├─ ${displayName}`.padEnd(25);
446
446
  process.progressBar.increment(1, {
447
- label: chalk_1.default.cyan(indentedLabel),
448
- status: chalk_1.default.cyan(statusText),
447
+ label: (0, chalk_1.getChalk)().cyan(indentedLabel),
448
+ status: (0, chalk_1.getChalk)().cyan(statusText),
449
449
  percentage: formattedPercentage,
450
450
  });
451
451
  }
@@ -461,10 +461,14 @@ class CLIProgressManager {
461
461
  // Show completion status when finished, otherwise show running count
462
462
  const statusText = totalProcessed >= this.total
463
463
  ? this.failureCount === 0
464
- ? chalk_1.default.green(`✓ Complete (${this.successCount}/${totalProcessed})`)
465
- : chalk_1.default.yellow(`✓ Complete (${this.successCount}/${totalProcessed})`)
466
- : chalk_1.default.cyan(`${this.successCount}✓ ${this.failureCount}✗`);
467
- const labelColor = totalProcessed >= this.total ? (this.failureCount === 0 ? chalk_1.default.green : chalk_1.default.yellow) : chalk_1.default.cyan;
464
+ ? (0, chalk_1.getChalk)().green(`✓ Complete (${this.successCount}/${totalProcessed})`)
465
+ : (0, chalk_1.getChalk)().yellow(`✓ Complete (${this.successCount}/${totalProcessed})`)
466
+ : (0, chalk_1.getChalk)().cyan(`${this.successCount}✓ ${this.failureCount}✗`);
467
+ const labelColor = totalProcessed >= this.total
468
+ ? this.failureCount === 0
469
+ ? (0, chalk_1.getChalk)().green
470
+ : (0, chalk_1.getChalk)().yellow
471
+ : (0, chalk_1.getChalk)().cyan;
468
472
  const formattedName = this.formatModuleName(this.moduleName);
469
473
  const displayName = formattedName.length > 20 ? formattedName.substring(0, 17) + '...' : formattedName;
470
474
  this.progressBar.increment(1, {
@@ -475,7 +479,7 @@ class CLIProgressManager {
475
479
  }
476
480
  else if (this.spinner) {
477
481
  const total = this.successCount + this.failureCount;
478
- this.spinner.text = `${chalk_1.default.bold(this.moduleName)}: ${total} items (${this.successCount}✓ ${this.failureCount}✗)`;
482
+ this.spinner.text = `${(0, chalk_1.getChalk)().bold(this.moduleName)}: ${total} items (${this.successCount}✓ ${this.failureCount}✗)`;
479
483
  }
480
484
  }
481
485
  }
@@ -520,13 +524,13 @@ class CLIProgressManager {
520
524
  }
521
525
  if (!this.enableNestedProgress) {
522
526
  // Simple summary for single progress
523
- this.log('\n' + chalk_1.default.bold(`${this.moduleName} Summary:`));
524
- this.log(`✓ Success: ${chalk_1.default.green(this.successCount)}`);
525
- this.log(`✗ Failures: ${chalk_1.default.red(this.failureCount)}`);
527
+ this.log('\n' + (0, chalk_1.getChalk)().bold(`${this.moduleName} Summary:`));
528
+ this.log(`✓ Success: ${(0, chalk_1.getChalk)().green(this.successCount)}`);
529
+ this.log(`✗ Failures: ${(0, chalk_1.getChalk)().red(this.failureCount)}`);
526
530
  return;
527
531
  }
528
532
  // Detailed summary for nested progress
529
- this.log('\n' + chalk_1.default.bold(`${this.moduleName} Detailed Summary:`));
533
+ this.log('\n' + (0, chalk_1.getChalk)().bold(`${this.moduleName} Detailed Summary:`));
530
534
  for (const [processName, process] of this.processes) {
531
535
  const status = process.status === 'completed'
532
536
  ? '✓'
@@ -546,5 +550,5 @@ class CLIProgressManager {
546
550
  return this.failureCount;
547
551
  }
548
552
  }
549
- exports.default = CLIProgressManager;
550
553
  CLIProgressManager.globalSummary = null;
554
+ exports.default = CLIProgressManager;
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
- const chalk_1 = tslib_1.__importDefault(require("chalk"));
3
+ const chalk_1 = require("../chalk");
5
4
  class SummaryManager {
6
5
  constructor({ operationName, context }) {
7
6
  this.modules = new Map();
@@ -83,16 +82,16 @@ class SummaryManager {
83
82
  const totalItems = Array.from(this.modules.values()).reduce((sum, m) => sum + m.successCount + m.failureCount, 0);
84
83
  const totalSuccess = Array.from(this.modules.values()).reduce((sum, m) => sum + m.successCount, 0);
85
84
  const totalFailures = Array.from(this.modules.values()).reduce((sum, m) => sum + m.failureCount, 0);
86
- console.log('\n' + chalk_1.default.bold('='.repeat(80)));
87
- console.log(chalk_1.default.bold(`${this.operationName} SUMMARY`));
88
- console.log('\n' + chalk_1.default.bold('Overall Statistics:'));
89
- console.log(` Total ${this.operationName} Time: ${chalk_1.default.cyan(this.formatDuration(totalDuration))}`);
90
- console.log(` Modules Processed: ${chalk_1.default.cyan(completedModules)}/${chalk_1.default.cyan(totalModules)}`);
91
- console.log(` Items Processed: ${chalk_1.default.green(totalSuccess)} success, ${chalk_1.default.red(totalFailures)} failed of ${chalk_1.default.cyan(totalItems)} total`);
92
- console.log(` Success Rate: ${chalk_1.default.cyan(this.calculateSuccessRate(totalSuccess, totalItems))}%`);
85
+ console.log('\n' + (0, chalk_1.getChalk)().bold('='.repeat(80)));
86
+ console.log((0, chalk_1.getChalk)().bold(`${this.operationName} SUMMARY`));
87
+ console.log('\n' + (0, chalk_1.getChalk)().bold('Overall Statistics:'));
88
+ console.log(` Total ${this.operationName} Time: ${(0, chalk_1.getChalk)().cyan(this.formatDuration(totalDuration))}`);
89
+ console.log(` Modules Processed: ${(0, chalk_1.getChalk)().cyan(completedModules)}/${(0, chalk_1.getChalk)().cyan(totalModules)}`);
90
+ console.log(` Items Processed: ${(0, chalk_1.getChalk)().green(totalSuccess)} success, ${(0, chalk_1.getChalk)().red(totalFailures)} failed of ${(0, chalk_1.getChalk)().cyan(totalItems)} total`);
91
+ console.log(` Success Rate: ${(0, chalk_1.getChalk)().cyan(this.calculateSuccessRate(totalSuccess, totalItems))}%`);
93
92
  // Module Details
94
- console.log('\n' + chalk_1.default.bold('Module Details:'));
95
- console.log(chalk_1.default.gray('-'.repeat(80)));
93
+ console.log('\n' + (0, chalk_1.getChalk)().bold('Module Details:'));
94
+ console.log((0, chalk_1.getChalk)().gray('-'.repeat(80)));
96
95
  Array.from(this.modules.values()).forEach((module) => {
97
96
  const status = this.getStatusIcon(module.status);
98
97
  const totalCount = module.successCount + module.failureCount;
@@ -104,18 +103,18 @@ class SummaryManager {
104
103
  `${duration.padStart(8)}`);
105
104
  });
106
105
  // Final Status
107
- console.log('\n' + chalk_1.default.bold('Final Status:'));
106
+ console.log('\n' + (0, chalk_1.getChalk)().bold('Final Status:'));
108
107
  if (!this.hasFailures() && failedModules === 0) {
109
- console.log(chalk_1.default.bold.green(`✅ ${this.operationName} completed successfully!`));
108
+ console.log((0, chalk_1.getChalk)().bold.green(`✅ ${this.operationName} completed successfully!`));
110
109
  }
111
110
  else if (this.hasFailures() || failedModules > 0) {
112
- console.log(chalk_1.default.bold.yellow(`⚠️ ${this.operationName} completed with failures, see the logs for more details.`));
111
+ console.log((0, chalk_1.getChalk)().bold.yellow(`⚠️ ${this.operationName} completed with failures, see the logs for more details.`));
113
112
  }
114
113
  else {
115
- console.log(chalk_1.default.bold.red(`❌ ${this.operationName} failed`));
114
+ console.log((0, chalk_1.getChalk)().bold.red(`❌ ${this.operationName} failed`));
116
115
  }
117
- console.log(chalk_1.default.bold('='.repeat(80)));
118
- console.log(chalk_1.default.bold('='.repeat(80)));
116
+ console.log((0, chalk_1.getChalk)().bold('='.repeat(80)));
117
+ console.log((0, chalk_1.getChalk)().bold('='.repeat(80)));
119
118
  // Simple failure summary with log reference
120
119
  this.printFailureSummaryWithLogReference();
121
120
  }
@@ -129,36 +128,37 @@ class SummaryManager {
129
128
  const modulesWithFailures = Array.from(this.modules.values()).filter((m) => m.failures.length > 0);
130
129
  if (modulesWithFailures.length === 0)
131
130
  return;
131
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars -- kept for future session log path / totals UX
132
132
  const totalFailures = modulesWithFailures.reduce((sum, m) => sum + m.failures.length, 0);
133
- console.log('\n' + chalk_1.default.bold.red('Failure Summary:'));
134
- console.log(chalk_1.default.red('-'.repeat(50)));
133
+ console.log('\n' + (0, chalk_1.getChalk)().bold.red('Failure Summary:'));
134
+ console.log((0, chalk_1.getChalk)().red('-'.repeat(50)));
135
135
  modulesWithFailures.forEach((module) => {
136
- console.log(`${chalk_1.default.bold.red('✗')} ${chalk_1.default.bold(module.name)}: ${chalk_1.default.red(module.failures.length)} failures`);
136
+ console.log(`${(0, chalk_1.getChalk)().bold.red('✗')} ${(0, chalk_1.getChalk)().bold(module.name)}: ${(0, chalk_1.getChalk)().red(module.failures.length)} failures`);
137
137
  // Show just first 2-3 failures briefly
138
138
  const preview = module.failures.slice(0, 2);
139
139
  preview.forEach((failure) => {
140
- console.log(` • ${chalk_1.default.gray(failure.item)}`);
140
+ console.log(` • ${(0, chalk_1.getChalk)().gray(failure.item)}`);
141
141
  });
142
142
  if (module.failures.length > 2) {
143
- console.log(` ${chalk_1.default.gray(`... and ${module.failures.length - 2} more`)}`);
143
+ console.log(` ${(0, chalk_1.getChalk)().gray(`... and ${module.failures.length - 2} more`)}`);
144
144
  }
145
145
  });
146
- console.log(chalk_1.default.blue('\n📋 For detailed error information, check the log files:'));
147
- //console.log(chalk.blue(` ${getSessionLogPath()}`));
148
- console.log(chalk_1.default.gray(' Recent errors are logged with full context and stack traces.'));
146
+ console.log((0, chalk_1.getChalk)().blue('\n📋 For detailed error information, check the log files:'));
147
+ //console.log(getChalk().blue(` ${getSessionLogPath()}`));
148
+ console.log((0, chalk_1.getChalk)().gray(' Recent errors are logged with full context and stack traces.'));
149
149
  }
150
150
  getStatusIcon(status) {
151
151
  switch (status) {
152
152
  case 'completed':
153
- return chalk_1.default.green('✓');
153
+ return (0, chalk_1.getChalk)().green('✓');
154
154
  case 'failed':
155
- return chalk_1.default.red('✗');
155
+ return (0, chalk_1.getChalk)().red('✗');
156
156
  case 'running':
157
- return chalk_1.default.yellow('●');
157
+ return (0, chalk_1.getChalk)().yellow('●');
158
158
  case 'pending':
159
- return chalk_1.default.gray('○');
159
+ return (0, chalk_1.getChalk)().gray('○');
160
160
  default:
161
- return chalk_1.default.gray('?');
161
+ return (0, chalk_1.getChalk)().gray('?');
162
162
  }
163
163
  }
164
164
  formatDuration(ms) {
@@ -8,10 +8,51 @@ export interface ProxyConfig {
8
8
  };
9
9
  }
10
10
  /**
11
- * Get proxy configuration with priority: Environment variables > Global config
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. Priority order (per spec):
27
+ * 1. Global CLI config from `csdx config:set:proxy --host <host> --port <port> --protocol <protocol>`
28
+ * 2. Environment variables (HTTPS_PROXY or HTTP_PROXY)
29
+ * For per-request use, prefer getProxyConfigForHost(host) so NO_PROXY overrides both sources.
12
30
  * @returns ProxyConfig object or undefined if no proxy is configured
13
31
  */
14
32
  export declare function getProxyConfig(): ProxyConfig | undefined;
33
+ /**
34
+ * Get proxy config only when the request host is not in NO_PROXY.
35
+ * NO_PROXY has priority over both HTTP_PROXY/HTTPS_PROXY and over proxy set via
36
+ * `csdx config:set:proxy` — if the host matches NO_PROXY, no proxy is used.
37
+ * Use this for all outbound requests so Contentstack and localhost bypass the proxy when set.
38
+ * @param host - Request hostname (e.g. api.contentstack.io or full URL like https://api.contentstack.io)
39
+ * @returns ProxyConfig or undefined if proxy is disabled or host should bypass (NO_PROXY)
40
+ */
41
+ export declare function getProxyConfigForHost(host: string): ProxyConfig | undefined;
42
+ /**
43
+ * Hostname for NO_PROXY / proxy. Prefer `region.cma` when set so callers that pass a
44
+ * default SDK host (e.g. bulk-entries -> api.contentstack.io) still match rules like
45
+ * `.csnonprod.com` against the real API host (e.g. dev11-api.csnonprod.com).
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
@@ -1,41 +1,100 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getProxyUrl = exports.hasProxy = exports.getProxyConfig = void 0;
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
- * Get proxy configuration with priority: Environment variables > Global config
8
- * @returns ProxyConfig object or undefined if no proxy is configured
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
9
19
  */
10
- function getProxyConfig() {
11
- // Priority 1: Check environment variables (HTTPS_PROXY or HTTP_PROXY)
12
- const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY;
13
- if (proxyUrl) {
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('://')) {
14
37
  try {
15
- const url = new URL(proxyUrl);
16
- const defaultPort = url.protocol === 'https:' ? 443 : 80;
17
- const port = url.port ? Number.parseInt(url.port, 10) : defaultPort;
18
- if (!Number.isNaN(port) && port >= 1 && port <= 65535) {
19
- const protocol = url.protocol.replace(':', '');
20
- const proxyConfig = {
21
- protocol: protocol,
22
- host: url.hostname,
23
- port: port,
24
- };
25
- if (url.username || url.password) {
26
- proxyConfig.auth = {
27
- username: url.username,
28
- password: url.password,
29
- };
30
- }
31
- return proxyConfig;
32
- }
38
+ const u = new URL(h);
39
+ h = u.hostname;
33
40
  }
34
41
  catch (_a) {
35
- // Invalid URL, continue to check global config
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;
36
85
  }
37
86
  }
38
- // Priority 2: Check global config store
87
+ return false;
88
+ }
89
+ /**
90
+ * Get proxy configuration. Priority order (per spec):
91
+ * 1. Global CLI config from `csdx config:set:proxy --host <host> --port <port> --protocol <protocol>`
92
+ * 2. Environment variables (HTTPS_PROXY or HTTP_PROXY)
93
+ * For per-request use, prefer getProxyConfigForHost(host) so NO_PROXY overrides both sources.
94
+ * @returns ProxyConfig object or undefined if no proxy is configured
95
+ */
96
+ function getProxyConfig() {
97
+ // Priority 1: Global config (csdx config:set:proxy)
39
98
  const globalProxyConfig = config_handler_1.default.get('proxy');
40
99
  if (globalProxyConfig) {
41
100
  if (typeof globalProxyConfig === 'object') {
@@ -65,14 +124,108 @@ function getProxyConfig() {
65
124
  return proxyConfig;
66
125
  }
67
126
  }
68
- catch (_b) {
69
- // Invalid URL, return undefined
127
+ catch (_a) {
128
+ // Invalid URL, continue to check environment
129
+ }
130
+ }
131
+ }
132
+ // Priority 2: Environment variables (HTTPS_PROXY or HTTP_PROXY)
133
+ const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY;
134
+ if (proxyUrl) {
135
+ try {
136
+ const url = new URL(proxyUrl);
137
+ const defaultPort = url.protocol === 'https:' ? 443 : 80;
138
+ const port = url.port ? Number.parseInt(url.port, 10) : defaultPort;
139
+ if (!Number.isNaN(port) && port >= 1 && port <= 65535) {
140
+ const protocol = url.protocol.replace(':', '');
141
+ const proxyConfig = {
142
+ protocol: protocol,
143
+ host: url.hostname,
144
+ port: port,
145
+ };
146
+ if (url.username || url.password) {
147
+ proxyConfig.auth = {
148
+ username: url.username,
149
+ password: url.password,
150
+ };
151
+ }
152
+ return proxyConfig;
70
153
  }
71
154
  }
155
+ catch (_b) {
156
+ // Invalid URL, return undefined
157
+ }
72
158
  }
73
159
  return undefined;
74
160
  }
75
- exports.getProxyConfig = getProxyConfig;
161
+ /**
162
+ * Get proxy config only when the request host is not in NO_PROXY.
163
+ * NO_PROXY has priority over both HTTP_PROXY/HTTPS_PROXY and over proxy set via
164
+ * `csdx config:set:proxy` — if the host matches NO_PROXY, no proxy is used.
165
+ * Use this for all outbound requests so Contentstack and localhost bypass the proxy when set.
166
+ * @param host - Request hostname (e.g. api.contentstack.io or full URL like https://api.contentstack.io)
167
+ * @returns ProxyConfig or undefined if proxy is disabled or host should bypass (NO_PROXY)
168
+ */
169
+ function getProxyConfigForHost(host) {
170
+ if (shouldBypassProxy(host))
171
+ return undefined;
172
+ return getProxyConfig();
173
+ }
174
+ function regionCmaHostname() {
175
+ var _a;
176
+ const cma = (_a = config_handler_1.default.get('region')) === null || _a === void 0 ? void 0 : _a.cma;
177
+ if (!cma || typeof cma !== 'string') {
178
+ return '';
179
+ }
180
+ if (cma.startsWith('http')) {
181
+ try {
182
+ const u = new URL(cma);
183
+ return u.hostname || cma;
184
+ }
185
+ catch (_b) {
186
+ return cma;
187
+ }
188
+ }
189
+ return cma;
190
+ }
191
+ /**
192
+ * Hostname for NO_PROXY / proxy. Prefer `region.cma` when set so callers that pass a
193
+ * default SDK host (e.g. bulk-entries -> api.contentstack.io) still match rules like
194
+ * `.csnonprod.com` against the real API host (e.g. dev11-api.csnonprod.com).
195
+ */
196
+ function resolveRequestHost(config) {
197
+ var _a;
198
+ const fromRegion = regionCmaHostname();
199
+ if (fromRegion) {
200
+ return normalizeHost(fromRegion) || fromRegion;
201
+ }
202
+ const raw = ((_a = config.host) === null || _a === void 0 ? void 0 : _a.trim()) || '';
203
+ if (!raw) {
204
+ return '';
205
+ }
206
+ return normalizeHost(raw) || raw;
207
+ }
208
+ /**
209
+ * Temporarily clear proxy-related env vars so SDK/axios cannot use them.
210
+ * Call the returned function to restore. Use when creating a client for a host in NO_PROXY.
211
+ * @returns Restore function (call to put env back)
212
+ */
213
+ function clearProxyEnv() {
214
+ const saved = {};
215
+ const keys = ['HTTP_PROXY', 'HTTPS_PROXY', 'http_proxy', 'https_proxy', 'ALL_PROXY', 'all_proxy'];
216
+ for (const k of keys) {
217
+ if (k in process.env) {
218
+ saved[k] = process.env[k];
219
+ delete process.env[k];
220
+ }
221
+ }
222
+ return () => {
223
+ for (const k of keys) {
224
+ if (saved[k] !== undefined)
225
+ process.env[k] = saved[k];
226
+ }
227
+ };
228
+ }
76
229
  /**
77
230
  * Check if proxy is configured (from any source)
78
231
  * @returns true if proxy is configured, false otherwise
@@ -80,7 +233,6 @@ exports.getProxyConfig = getProxyConfig;
80
233
  function hasProxy() {
81
234
  return !!getProxyConfig() || !!process.env.HTTPS_PROXY || !!process.env.HTTP_PROXY || !!config_handler_1.default.get('proxy');
82
235
  }
83
- exports.hasProxy = hasProxy;
84
236
  /**
85
237
  * Get proxy URL string for display purposes
86
238
  * @returns Proxy URL string or 'proxy server' if not available
@@ -100,4 +252,3 @@ function getProxyUrl() {
100
252
  }
101
253
  return 'proxy server';
102
254
  }
103
- exports.getProxyUrl = getProxyUrl;