paymongo-cli 1.4.4 → 1.4.7

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 (155) hide show
  1. package/.github/copilot-instructions.md +95 -95
  2. package/CHANGELOG.md +85 -1
  3. package/LICENSE +20 -20
  4. package/dist/.tsbuildinfo +1 -1
  5. package/dist/commands/config.js +30 -15
  6. package/dist/commands/dev/logs.js +3 -3
  7. package/dist/commands/dev/status.js +2 -2
  8. package/dist/commands/dev/stop.js +3 -3
  9. package/dist/commands/dev.js +9 -8
  10. package/dist/commands/env.js +6 -6
  11. package/dist/commands/generate/templates/checkout-page/index.js +520 -520
  12. package/dist/commands/generate/templates/payment-intent/javascript.js +68 -68
  13. package/dist/commands/generate/templates/payment-intent/typescript.js +92 -92
  14. package/dist/commands/generate/templates/webhook-handler/javascript.js +192 -147
  15. package/dist/commands/generate/templates/webhook-handler/typescript.js +147 -117
  16. package/dist/commands/generate.js +43 -37
  17. package/dist/commands/init.js +25 -8
  18. package/dist/commands/login.js +56 -19
  19. package/dist/commands/payments.js +9 -8
  20. package/dist/commands/team/index.js +11 -9
  21. package/dist/commands/trigger.js +58 -18
  22. package/dist/commands/webhooks.js +8 -7
  23. package/dist/index.js +9 -2
  24. package/dist/services/analytics/service.js +24 -19
  25. package/dist/services/api/client.js +16 -16
  26. package/dist/services/config/manager.js +6 -8
  27. package/dist/services/dev/process-manager.js +30 -32
  28. package/dist/services/dev/server.js +45 -39
  29. package/dist/services/team/service.js +4 -1
  30. package/dist/types/schemas.js +38 -9
  31. package/dist/utils/bulk.js +36 -4
  32. package/dist/utils/constants.js +11 -1
  33. package/dist/utils/errors.js +6 -0
  34. package/dist/utils/validator.js +10 -9
  35. package/dist/utils/webhook-store.js +18 -15
  36. package/eslint.config.ts +70 -70
  37. package/package.json +2 -2
  38. package/coverage/base.css +0 -224
  39. package/coverage/block-navigation.js +0 -87
  40. package/coverage/favicon.png +0 -0
  41. package/coverage/index.html +0 -281
  42. package/coverage/lcov-report/base.css +0 -224
  43. package/coverage/lcov-report/block-navigation.js +0 -87
  44. package/coverage/lcov-report/favicon.png +0 -0
  45. package/coverage/lcov-report/index.html +0 -281
  46. package/coverage/lcov-report/prettify.css +0 -1
  47. package/coverage/lcov-report/prettify.js +0 -2
  48. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  49. package/coverage/lcov-report/sorter.js +0 -210
  50. package/coverage/lcov.info +0 -5053
  51. package/coverage/prettify.css +0 -1
  52. package/coverage/prettify.js +0 -2
  53. package/coverage/sort-arrow-sprite.png +0 -0
  54. package/coverage/sorter.js +0 -210
  55. package/dist/commands/config.d.ts +0 -21
  56. package/dist/commands/config.d.ts.map +0 -1
  57. package/dist/commands/config.js.map +0 -1
  58. package/dist/commands/dev.d.ts +0 -16
  59. package/dist/commands/dev.d.ts.map +0 -1
  60. package/dist/commands/dev.js.map +0 -1
  61. package/dist/commands/env.d.ts +0 -4
  62. package/dist/commands/env.d.ts.map +0 -1
  63. package/dist/commands/env.js.map +0 -1
  64. package/dist/commands/init.d.ts +0 -15
  65. package/dist/commands/init.d.ts.map +0 -1
  66. package/dist/commands/init.js.map +0 -1
  67. package/dist/commands/login.d.ts +0 -20
  68. package/dist/commands/login.d.ts.map +0 -1
  69. package/dist/commands/login.js.map +0 -1
  70. package/dist/commands/payments.d.ts +0 -41
  71. package/dist/commands/payments.d.ts.map +0 -1
  72. package/dist/commands/payments.js.map +0 -1
  73. package/dist/commands/team/index.d.ts +0 -4
  74. package/dist/commands/team/index.d.ts.map +0 -1
  75. package/dist/commands/team/index.js.map +0 -1
  76. package/dist/commands/trigger.d.ts +0 -4
  77. package/dist/commands/trigger.d.ts.map +0 -1
  78. package/dist/commands/trigger.js.map +0 -1
  79. package/dist/commands/webhooks.d.ts +0 -23
  80. package/dist/commands/webhooks.d.ts.map +0 -1
  81. package/dist/commands/webhooks.js.map +0 -1
  82. package/dist/index.d.ts +0 -3
  83. package/dist/index.d.ts.map +0 -1
  84. package/dist/index.js.map +0 -1
  85. package/dist/services/analytics/service.d.ts +0 -35
  86. package/dist/services/analytics/service.d.ts.map +0 -1
  87. package/dist/services/analytics/service.js.map +0 -1
  88. package/dist/services/api/client.d.ts +0 -26
  89. package/dist/services/api/client.d.ts.map +0 -1
  90. package/dist/services/api/client.js.map +0 -1
  91. package/dist/services/api/rate-limiter.d.ts +0 -64
  92. package/dist/services/api/rate-limiter.d.ts.map +0 -1
  93. package/dist/services/api/rate-limiter.js.map +0 -1
  94. package/dist/services/api/undici-client.d.ts +0 -39
  95. package/dist/services/api/undici-client.d.ts.map +0 -1
  96. package/dist/services/api/undici-client.js +0 -288
  97. package/dist/services/api/undici-client.js.map +0 -1
  98. package/dist/services/config/manager.d.ts +0 -16
  99. package/dist/services/config/manager.d.ts.map +0 -1
  100. package/dist/services/config/manager.js.map +0 -1
  101. package/dist/services/dev/process-manager.d.ts +0 -50
  102. package/dist/services/dev/process-manager.d.ts.map +0 -1
  103. package/dist/services/dev/process-manager.js.map +0 -1
  104. package/dist/services/github/auth.d.ts +0 -15
  105. package/dist/services/github/auth.d.ts.map +0 -1
  106. package/dist/services/github/auth.js +0 -79
  107. package/dist/services/github/auth.js.map +0 -1
  108. package/dist/services/github/client.d.ts +0 -95
  109. package/dist/services/github/client.d.ts.map +0 -1
  110. package/dist/services/github/client.js +0 -130
  111. package/dist/services/github/client.js.map +0 -1
  112. package/dist/services/github/sync.d.ts +0 -26
  113. package/dist/services/github/sync.d.ts.map +0 -1
  114. package/dist/services/github/sync.js +0 -203
  115. package/dist/services/github/sync.js.map +0 -1
  116. package/dist/services/payments/simulator.d.ts +0 -28
  117. package/dist/services/payments/simulator.d.ts.map +0 -1
  118. package/dist/services/payments/simulator.js.map +0 -1
  119. package/dist/services/team/service.d.ts +0 -44
  120. package/dist/services/team/service.d.ts.map +0 -1
  121. package/dist/services/team/service.js.map +0 -1
  122. package/dist/services/web/server.d.ts +0 -31
  123. package/dist/services/web/server.d.ts.map +0 -1
  124. package/dist/services/web/server.js +0 -206
  125. package/dist/services/web/server.js.map +0 -1
  126. package/dist/types/paymongo.d.ts +0 -204
  127. package/dist/types/paymongo.d.ts.map +0 -1
  128. package/dist/types/paymongo.js.map +0 -1
  129. package/dist/types/schemas.d.ts +0 -80
  130. package/dist/types/schemas.d.ts.map +0 -1
  131. package/dist/types/schemas.js.map +0 -1
  132. package/dist/utils/bulk.d.ts +0 -62
  133. package/dist/utils/bulk.d.ts.map +0 -1
  134. package/dist/utils/bulk.js.map +0 -1
  135. package/dist/utils/cache.d.ts +0 -22
  136. package/dist/utils/cache.d.ts.map +0 -1
  137. package/dist/utils/cache.js.map +0 -1
  138. package/dist/utils/constants.d.ts +0 -32
  139. package/dist/utils/constants.d.ts.map +0 -1
  140. package/dist/utils/constants.js.map +0 -1
  141. package/dist/utils/errors.d.ts +0 -34
  142. package/dist/utils/errors.d.ts.map +0 -1
  143. package/dist/utils/errors.js.map +0 -1
  144. package/dist/utils/logger.d.ts +0 -20
  145. package/dist/utils/logger.d.ts.map +0 -1
  146. package/dist/utils/logger.js.map +0 -1
  147. package/dist/utils/spinner.d.ts +0 -17
  148. package/dist/utils/spinner.d.ts.map +0 -1
  149. package/dist/utils/spinner.js.map +0 -1
  150. package/dist/utils/validator.d.ts +0 -10
  151. package/dist/utils/validator.d.ts.map +0 -1
  152. package/dist/utils/validator.js.map +0 -1
  153. package/dist/utils/webhook-store.d.ts +0 -22
  154. package/dist/utils/webhook-store.d.ts.map +0 -1
  155. package/dist/utils/webhook-store.js.map +0 -1
@@ -4,6 +4,8 @@ import * as fs from 'fs';
4
4
  import * as path from 'path';
5
5
  import ConfigManager from '../services/config/manager.js';
6
6
  import Spinner from '../utils/spinner.js';
7
+ import { validateConfig as zodValidateConfig } from '../types/schemas.js';
8
+ import { CommandError } from '../utils/errors.js';
7
9
  function validateImportedConfig(config) {
8
10
  if (typeof config !== 'object' || config === null) {
9
11
  throw new Error('Configuration must be an object');
@@ -154,7 +156,7 @@ export async function showAction(options) {
154
156
  else {
155
157
  console.error(chalk.red('❌ Failed to load configuration:'), err.message);
156
158
  }
157
- process.exit(1);
159
+ throw new CommandError();
158
160
  }
159
161
  }
160
162
  export async function setAction(key, value) {
@@ -218,7 +220,7 @@ export async function setAction(key, value) {
218
220
  spinner.stop();
219
221
  const err = error;
220
222
  console.error(chalk.red('❌ Failed to update configuration:'), err.message);
221
- process.exit(1);
223
+ throw new CommandError();
222
224
  }
223
225
  }
224
226
  export async function backupAction(options) {
@@ -270,7 +272,7 @@ export async function backupAction(options) {
270
272
  else {
271
273
  console.error(chalk.red('❌ Failed to create backup:'), err.message);
272
274
  }
273
- process.exit(1);
275
+ throw new CommandError();
274
276
  }
275
277
  }
276
278
  export async function resetAction() {
@@ -288,7 +290,7 @@ export async function resetAction() {
288
290
  spinner.stop();
289
291
  const err = error;
290
292
  console.error(chalk.red('❌ Failed to reset configuration:'), err.message);
291
- process.exit(1);
293
+ throw new CommandError();
292
294
  }
293
295
  }
294
296
  export async function importAction(filePath, options) {
@@ -299,7 +301,7 @@ export async function importAction(filePath, options) {
299
301
  if (!fs.existsSync(filePath)) {
300
302
  spinner.fail('File not found');
301
303
  console.error(chalk.red(`❌ Import file not found: ${filePath}`));
302
- process.exit(1);
304
+ throw new CommandError();
303
305
  }
304
306
  const fileContent = fs.readFileSync(filePath, 'utf-8');
305
307
  let importedConfig;
@@ -309,11 +311,18 @@ export async function importAction(filePath, options) {
309
311
  catch (_parseError) {
310
312
  spinner.fail('Invalid JSON');
311
313
  console.error(chalk.red('❌ Invalid JSON in import file'));
312
- process.exit(1);
314
+ throw new CommandError();
313
315
  }
314
316
  spinner.succeed('File read');
315
317
  spinner.start('Validating configuration...');
316
318
  validateImportedConfig(importedConfig);
319
+ const validation = zodValidateConfig(importedConfig);
320
+ if (!validation.success) {
321
+ spinner.fail('Invalid configuration');
322
+ console.error(chalk.red('❌ Configuration validation failed:'));
323
+ validation.errors?.forEach((err) => console.error(chalk.gray(` • ${err}`)));
324
+ throw new CommandError();
325
+ }
317
326
  spinner.succeed('Configuration validated');
318
327
  const existingConfig = await configManager.load();
319
328
  if (existingConfig && !options.force) {
@@ -327,7 +336,7 @@ export async function importAction(filePath, options) {
327
336
  });
328
337
  console.log('');
329
338
  console.log(chalk.bold('Use --force to overwrite existing configuration'));
330
- process.exit(1);
339
+ throw new CommandError();
331
340
  }
332
341
  spinner.succeed('No conflicts found');
333
342
  }
@@ -339,6 +348,12 @@ export async function importAction(filePath, options) {
339
348
  spinner.succeed(`Backup created: ${backupPath}`);
340
349
  }
341
350
  spinner.start('Importing configuration...');
351
+ if (!importedConfig.apiKeys) {
352
+ importedConfig.apiKeys = {};
353
+ }
354
+ if (!importedConfig.webhookSecrets) {
355
+ importedConfig.webhookSecrets = {};
356
+ }
342
357
  await configManager.save(importedConfig);
343
358
  spinner.succeed('Configuration imported');
344
359
  console.log(chalk.green('✓ Configuration imported successfully'));
@@ -348,7 +363,7 @@ export async function importAction(filePath, options) {
348
363
  spinner.stop();
349
364
  const err = error;
350
365
  console.error(chalk.red('❌ Failed to import configuration:'), err.message);
351
- process.exit(1);
366
+ throw new CommandError();
352
367
  }
353
368
  }
354
369
  export async function rateLimitEnableAction() {
@@ -385,7 +400,7 @@ export async function rateLimitEnableAction() {
385
400
  spinner.stop();
386
401
  const err = error;
387
402
  console.error(chalk.red('❌ Failed to enable rate limiting:'), err.message);
388
- process.exit(1);
403
+ throw new CommandError();
389
404
  }
390
405
  }
391
406
  export async function rateLimitDisableAction() {
@@ -414,7 +429,7 @@ export async function rateLimitDisableAction() {
414
429
  spinner.stop();
415
430
  const err = error;
416
431
  console.error(chalk.red('❌ Failed to disable rate limiting:'), err.message);
417
- process.exit(1);
432
+ throw new CommandError();
418
433
  }
419
434
  }
420
435
  export async function rateLimitSetMaxRequestsAction(requestsStr) {
@@ -424,7 +439,7 @@ export async function rateLimitSetMaxRequestsAction(requestsStr) {
424
439
  const requests = parseInt(requestsStr, 10);
425
440
  if (isNaN(requests) || requests < 1) {
426
441
  console.error(chalk.red('❌ Invalid number of requests. Must be a positive integer.'));
427
- process.exit(1);
442
+ throw new CommandError();
428
443
  }
429
444
  spinner.start('Loading configuration...');
430
445
  const config = await configManager.load();
@@ -455,7 +470,7 @@ export async function rateLimitSetMaxRequestsAction(requestsStr) {
455
470
  spinner.stop();
456
471
  const err = error;
457
472
  console.error(chalk.red('❌ Failed to update rate limit:'), err.message);
458
- process.exit(1);
473
+ throw new CommandError();
459
474
  }
460
475
  }
461
476
  export async function rateLimitSetWindowAction(secondsStr) {
@@ -465,7 +480,7 @@ export async function rateLimitSetWindowAction(secondsStr) {
465
480
  const seconds = parseInt(secondsStr, 10);
466
481
  if (isNaN(seconds) || seconds < 1) {
467
482
  console.error(chalk.red('❌ Invalid time window. Must be a positive integer (seconds).'));
468
- process.exit(1);
483
+ throw new CommandError();
469
484
  }
470
485
  spinner.start('Loading configuration...');
471
486
  const config = await configManager.load();
@@ -496,7 +511,7 @@ export async function rateLimitSetWindowAction(secondsStr) {
496
511
  spinner.stop();
497
512
  const err = error;
498
513
  console.error(chalk.red('❌ Failed to update rate limit window:'), err.message);
499
- process.exit(1);
514
+ throw new CommandError();
500
515
  }
501
516
  }
502
517
  export async function rateLimitStatusAction() {
@@ -543,7 +558,7 @@ export async function rateLimitStatusAction() {
543
558
  spinner.stop();
544
559
  const err = error;
545
560
  console.error(chalk.red('❌ Failed to check rate limiting status:'), err.message);
546
- process.exit(1);
561
+ throw new CommandError();
547
562
  }
548
563
  }
549
564
  const command = new Command('config');
@@ -9,12 +9,12 @@ const logsCommand = new Command('logs')
9
9
  .option('--clear', 'Clear the log file')
10
10
  .action(async (options) => {
11
11
  if (options.clear) {
12
- DevProcessManager.clearLogs();
12
+ await DevProcessManager.clearLogs();
13
13
  console.log(chalk.green('✓ Logs cleared'));
14
14
  return;
15
15
  }
16
- const logFile = DevProcessManager.getLogFile();
17
- const lines = DevProcessManager.readLogs(parseInt(options.lines));
16
+ const logFile = await DevProcessManager.getLogFile();
17
+ const lines = await DevProcessManager.readLogs(parseInt(options.lines));
18
18
  if (lines.length === 0) {
19
19
  console.log(chalk.yellow('No logs available.'));
20
20
  console.log(chalk.gray('Log file:'), logFile);
@@ -4,7 +4,7 @@ import { DevProcessManager } from '../../services/dev/process-manager.js';
4
4
  const statusCommand = new Command('status')
5
5
  .description('Check if dev server is running in background')
6
6
  .action(async () => {
7
- const state = DevProcessManager.loadState();
7
+ const state = await DevProcessManager.loadState();
8
8
  if (!state) {
9
9
  console.log(chalk.yellow('No dev server is running in background.'));
10
10
  console.log(chalk.gray('Start one with: paymongo dev --detach'));
@@ -13,7 +13,7 @@ const statusCommand = new Command('status')
13
13
  const isRunning = DevProcessManager.isProcessRunning(state.pid);
14
14
  if (!isRunning) {
15
15
  console.log(chalk.yellow('Dev server process is not running (stale state).'));
16
- DevProcessManager.clearState();
16
+ await DevProcessManager.clearState();
17
17
  console.log(chalk.gray('Start a new one with: paymongo dev --detach'));
18
18
  return;
19
19
  }
@@ -6,7 +6,7 @@ const stopCommand = new Command('stop')
6
6
  .description('Stop the background dev server')
7
7
  .action(async () => {
8
8
  const spinner = new Spinner();
9
- const state = DevProcessManager.loadState();
9
+ const state = await DevProcessManager.loadState();
10
10
  if (!state) {
11
11
  console.log(chalk.yellow('No dev server is running in background.'));
12
12
  return;
@@ -14,14 +14,14 @@ const stopCommand = new Command('stop')
14
14
  const isRunning = DevProcessManager.isProcessRunning(state.pid);
15
15
  if (!isRunning) {
16
16
  console.log(chalk.yellow('Dev server process is not running (cleaning up stale state).'));
17
- DevProcessManager.clearState();
17
+ await DevProcessManager.clearState();
18
18
  return;
19
19
  }
20
20
  spinner.start('Stopping dev server...');
21
21
  const killed = DevProcessManager.killProcess(state.pid);
22
22
  if (killed) {
23
23
  await new Promise((resolve) => setTimeout(resolve, 1000));
24
- DevProcessManager.clearState();
24
+ await DevProcessManager.clearState();
25
25
  spinner.succeed('Dev server stopped');
26
26
  console.log('');
27
27
  console.log(chalk.gray('Note: If the webhook was not cleaned up, it will be removed on next "paymongo dev" start.'));
@@ -5,7 +5,7 @@ import chalk from 'chalk';
5
5
  import ConfigManager from '../services/config/manager.js';
6
6
  import ApiClient from '../services/api/client.js';
7
7
  import Spinner from '../utils/spinner.js';
8
- import { withRetry } from '../utils/errors.js';
8
+ import { withRetry, CommandError } from '../utils/errors.js';
9
9
  import { DevProcessManager } from '../services/dev/process-manager.js';
10
10
  import { DevServer } from '../services/dev/server.js';
11
11
  import statusCommand from './dev/status.js';
@@ -24,7 +24,7 @@ command
24
24
  const configManager = new ConfigManager();
25
25
  let tunnel;
26
26
  if (options.detach) {
27
- const existingState = DevProcessManager.loadState();
27
+ const existingState = await DevProcessManager.loadState();
28
28
  if (existingState && DevProcessManager.isProcessRunning(existingState.pid)) {
29
29
  console.log(chalk.yellow('⚠️ Dev server is already running in background'));
30
30
  console.log('');
@@ -47,7 +47,7 @@ command
47
47
  if (options.ngrokToken) {
48
48
  args.push('--ngrok-token', options.ngrokToken);
49
49
  }
50
- const logFile = DevProcessManager.getLogFile();
50
+ const logFile = await DevProcessManager.getLogFile();
51
51
  const out = fs.openSync(logFile, 'a');
52
52
  const err = fs.openSync(logFile, 'a');
53
53
  const child = spawn(process.execPath, args, {
@@ -135,7 +135,8 @@ command
135
135
  }
136
136
  }
137
137
  let webhookId;
138
- if (!options.noRegister) {
138
+ const shouldRegister = !options.noRegister && config.dev.autoRegisterWebhook !== false;
139
+ if (shouldRegister) {
139
140
  spinner.start('Registering webhook...');
140
141
  const events = (options.events || 'payment.paid,payment.failed').split(',');
141
142
  const projectSlug = config.projectName.toLowerCase().replace(/[^a-z0-9]/g, '-');
@@ -199,7 +200,7 @@ command
199
200
  console.log('');
200
201
  console.log(chalk.gray('💡 Tip: Use the External URL in PayMongo dashboard, requests will forward to your local server'));
201
202
  console.log(chalk.gray('Press Ctrl+C to stop'));
202
- DevProcessManager.saveState({
203
+ await DevProcessManager.saveState({
203
204
  pid: process.pid,
204
205
  port,
205
206
  tunnelUrl: tunnelUrl ?? '',
@@ -212,7 +213,7 @@ command
212
213
  });
213
214
  const cleanup = async () => {
214
215
  console.log('\n' + chalk.yellow('Shutting down...'));
215
- DevProcessManager.clearState();
216
+ await DevProcessManager.clearState();
216
217
  try {
217
218
  if (tunnel) {
218
219
  await tunnel.close();
@@ -254,7 +255,7 @@ command
254
255
  console.log(chalk.gray('• Try a different port: paymongo dev --port 3001'));
255
256
  console.log(chalk.gray('• Visit https://ngrok.com for status updates'));
256
257
  }
257
- DevProcessManager.clearState();
258
+ await DevProcessManager.clearState();
258
259
  try {
259
260
  if (tunnel) {
260
261
  await tunnel.close();
@@ -262,7 +263,7 @@ command
262
263
  }
263
264
  catch {
264
265
  }
265
- process.exit(1);
266
+ throw new CommandError();
266
267
  }
267
268
  });
268
269
  command.addCommand(statusCommand);
@@ -3,7 +3,7 @@ import chalk from 'chalk';
3
3
  import ConfigManager from '../services/config/manager.js';
4
4
  import ApiClient from '../services/api/client.js';
5
5
  import Spinner from '../utils/spinner.js';
6
- import { ApiKeyError, NetworkError, PayMongoError } from '../utils/errors.js';
6
+ import { ApiKeyError, NetworkError, PayMongoError, CommandError } from '../utils/errors.js';
7
7
  const command = new Command('env');
8
8
  command
9
9
  .description('Manage PayMongo environments')
@@ -17,7 +17,7 @@ command
17
17
  try {
18
18
  if (!['test', 'live'].includes(environment)) {
19
19
  console.error(chalk.red('❌ Invalid environment. Must be "test" or "live"'));
20
- process.exit(1);
20
+ throw new CommandError();
21
21
  }
22
22
  spinner.start('Loading configuration...');
23
23
  const config = await configManager.load();
@@ -36,7 +36,7 @@ command
36
36
  console.log(`1. Get your ${environment} API keys from https://dashboard.paymongo.com/developers`);
37
37
  console.log(`2. Run: paymongo config set apiKeys.${environment}.secret YOUR_SECRET_KEY`);
38
38
  console.log(`3. Run: paymongo config set apiKeys.${environment}.public YOUR_PUBLIC_KEY`);
39
- process.exit(1);
39
+ throw new CommandError();
40
40
  }
41
41
  if (!options.force) {
42
42
  spinner.start('Validating API keys...');
@@ -74,7 +74,7 @@ command
74
74
  console.log(chalk.gray('Use --force to skip validation, but note that commands may fail.'));
75
75
  console.log('');
76
76
  console.log(chalk.yellow('💡 Get your API keys from: https://dashboard.paymongo.com/developers'));
77
- process.exit(1);
77
+ throw new CommandError();
78
78
  }
79
79
  }
80
80
  spinner.start(`Switching to ${environment} environment...`);
@@ -98,7 +98,7 @@ command
98
98
  spinner.stop();
99
99
  const err = error;
100
100
  console.error(chalk.red('❌ Failed to switch environment:'), err.message);
101
- process.exit(1);
101
+ throw new CommandError();
102
102
  }
103
103
  }))
104
104
  .addCommand(new Command('current').description('Show current environment').action(async () => {
@@ -124,7 +124,7 @@ command
124
124
  catch (error) {
125
125
  const err = error;
126
126
  console.error(chalk.red('❌ Failed to get current environment:'), err.message);
127
- process.exit(1);
127
+ throw new CommandError();
128
128
  }
129
129
  }));
130
130
  export default command;