paymongo-cli 1.4.6 → 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.
@@ -5,6 +5,7 @@ import * as path from 'path';
5
5
  import ConfigManager from '../services/config/manager.js';
6
6
  import Spinner from '../utils/spinner.js';
7
7
  import { validateConfig as zodValidateConfig } from '../types/schemas.js';
8
+ import { CommandError } from '../utils/errors.js';
8
9
  function validateImportedConfig(config) {
9
10
  if (typeof config !== 'object' || config === null) {
10
11
  throw new Error('Configuration must be an object');
@@ -155,7 +156,7 @@ export async function showAction(options) {
155
156
  else {
156
157
  console.error(chalk.red('❌ Failed to load configuration:'), err.message);
157
158
  }
158
- process.exit(1);
159
+ throw new CommandError();
159
160
  }
160
161
  }
161
162
  export async function setAction(key, value) {
@@ -219,7 +220,7 @@ export async function setAction(key, value) {
219
220
  spinner.stop();
220
221
  const err = error;
221
222
  console.error(chalk.red('❌ Failed to update configuration:'), err.message);
222
- process.exit(1);
223
+ throw new CommandError();
223
224
  }
224
225
  }
225
226
  export async function backupAction(options) {
@@ -271,7 +272,7 @@ export async function backupAction(options) {
271
272
  else {
272
273
  console.error(chalk.red('❌ Failed to create backup:'), err.message);
273
274
  }
274
- process.exit(1);
275
+ throw new CommandError();
275
276
  }
276
277
  }
277
278
  export async function resetAction() {
@@ -289,7 +290,7 @@ export async function resetAction() {
289
290
  spinner.stop();
290
291
  const err = error;
291
292
  console.error(chalk.red('❌ Failed to reset configuration:'), err.message);
292
- process.exit(1);
293
+ throw new CommandError();
293
294
  }
294
295
  }
295
296
  export async function importAction(filePath, options) {
@@ -300,7 +301,7 @@ export async function importAction(filePath, options) {
300
301
  if (!fs.existsSync(filePath)) {
301
302
  spinner.fail('File not found');
302
303
  console.error(chalk.red(`❌ Import file not found: ${filePath}`));
303
- process.exit(1);
304
+ throw new CommandError();
304
305
  }
305
306
  const fileContent = fs.readFileSync(filePath, 'utf-8');
306
307
  let importedConfig;
@@ -310,7 +311,7 @@ export async function importAction(filePath, options) {
310
311
  catch (_parseError) {
311
312
  spinner.fail('Invalid JSON');
312
313
  console.error(chalk.red('❌ Invalid JSON in import file'));
313
- process.exit(1);
314
+ throw new CommandError();
314
315
  }
315
316
  spinner.succeed('File read');
316
317
  spinner.start('Validating configuration...');
@@ -320,7 +321,7 @@ export async function importAction(filePath, options) {
320
321
  spinner.fail('Invalid configuration');
321
322
  console.error(chalk.red('❌ Configuration validation failed:'));
322
323
  validation.errors?.forEach((err) => console.error(chalk.gray(` • ${err}`)));
323
- process.exit(1);
324
+ throw new CommandError();
324
325
  }
325
326
  spinner.succeed('Configuration validated');
326
327
  const existingConfig = await configManager.load();
@@ -335,7 +336,7 @@ export async function importAction(filePath, options) {
335
336
  });
336
337
  console.log('');
337
338
  console.log(chalk.bold('Use --force to overwrite existing configuration'));
338
- process.exit(1);
339
+ throw new CommandError();
339
340
  }
340
341
  spinner.succeed('No conflicts found');
341
342
  }
@@ -362,7 +363,7 @@ export async function importAction(filePath, options) {
362
363
  spinner.stop();
363
364
  const err = error;
364
365
  console.error(chalk.red('❌ Failed to import configuration:'), err.message);
365
- process.exit(1);
366
+ throw new CommandError();
366
367
  }
367
368
  }
368
369
  export async function rateLimitEnableAction() {
@@ -399,7 +400,7 @@ export async function rateLimitEnableAction() {
399
400
  spinner.stop();
400
401
  const err = error;
401
402
  console.error(chalk.red('❌ Failed to enable rate limiting:'), err.message);
402
- process.exit(1);
403
+ throw new CommandError();
403
404
  }
404
405
  }
405
406
  export async function rateLimitDisableAction() {
@@ -428,7 +429,7 @@ export async function rateLimitDisableAction() {
428
429
  spinner.stop();
429
430
  const err = error;
430
431
  console.error(chalk.red('❌ Failed to disable rate limiting:'), err.message);
431
- process.exit(1);
432
+ throw new CommandError();
432
433
  }
433
434
  }
434
435
  export async function rateLimitSetMaxRequestsAction(requestsStr) {
@@ -438,7 +439,7 @@ export async function rateLimitSetMaxRequestsAction(requestsStr) {
438
439
  const requests = parseInt(requestsStr, 10);
439
440
  if (isNaN(requests) || requests < 1) {
440
441
  console.error(chalk.red('❌ Invalid number of requests. Must be a positive integer.'));
441
- process.exit(1);
442
+ throw new CommandError();
442
443
  }
443
444
  spinner.start('Loading configuration...');
444
445
  const config = await configManager.load();
@@ -469,7 +470,7 @@ export async function rateLimitSetMaxRequestsAction(requestsStr) {
469
470
  spinner.stop();
470
471
  const err = error;
471
472
  console.error(chalk.red('❌ Failed to update rate limit:'), err.message);
472
- process.exit(1);
473
+ throw new CommandError();
473
474
  }
474
475
  }
475
476
  export async function rateLimitSetWindowAction(secondsStr) {
@@ -479,7 +480,7 @@ export async function rateLimitSetWindowAction(secondsStr) {
479
480
  const seconds = parseInt(secondsStr, 10);
480
481
  if (isNaN(seconds) || seconds < 1) {
481
482
  console.error(chalk.red('❌ Invalid time window. Must be a positive integer (seconds).'));
482
- process.exit(1);
483
+ throw new CommandError();
483
484
  }
484
485
  spinner.start('Loading configuration...');
485
486
  const config = await configManager.load();
@@ -510,7 +511,7 @@ export async function rateLimitSetWindowAction(secondsStr) {
510
511
  spinner.stop();
511
512
  const err = error;
512
513
  console.error(chalk.red('❌ Failed to update rate limit window:'), err.message);
513
- process.exit(1);
514
+ throw new CommandError();
514
515
  }
515
516
  }
516
517
  export async function rateLimitStatusAction() {
@@ -557,7 +558,7 @@ export async function rateLimitStatusAction() {
557
558
  spinner.stop();
558
559
  const err = error;
559
560
  console.error(chalk.red('❌ Failed to check rate limiting status:'), err.message);
560
- process.exit(1);
561
+ throw new CommandError();
561
562
  }
562
563
  }
563
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, {
@@ -200,7 +200,7 @@ command
200
200
  console.log('');
201
201
  console.log(chalk.gray('💡 Tip: Use the External URL in PayMongo dashboard, requests will forward to your local server'));
202
202
  console.log(chalk.gray('Press Ctrl+C to stop'));
203
- DevProcessManager.saveState({
203
+ await DevProcessManager.saveState({
204
204
  pid: process.pid,
205
205
  port,
206
206
  tunnelUrl: tunnelUrl ?? '',
@@ -213,7 +213,7 @@ command
213
213
  });
214
214
  const cleanup = async () => {
215
215
  console.log('\n' + chalk.yellow('Shutting down...'));
216
- DevProcessManager.clearState();
216
+ await DevProcessManager.clearState();
217
217
  try {
218
218
  if (tunnel) {
219
219
  await tunnel.close();
@@ -255,7 +255,7 @@ command
255
255
  console.log(chalk.gray('• Try a different port: paymongo dev --port 3001'));
256
256
  console.log(chalk.gray('• Visit https://ngrok.com for status updates'));
257
257
  }
258
- DevProcessManager.clearState();
258
+ await DevProcessManager.clearState();
259
259
  try {
260
260
  if (tunnel) {
261
261
  await tunnel.close();
@@ -263,7 +263,7 @@ command
263
263
  }
264
264
  catch {
265
265
  }
266
- process.exit(1);
266
+ throw new CommandError();
267
267
  }
268
268
  });
269
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;
@@ -6,7 +6,7 @@ import ConfigManager from '../services/config/manager.js';
6
6
  import ApiClient from '../services/api/client.js';
7
7
  import { validateApiKey } from '../utils/validator.js';
8
8
  import Spinner from '../utils/spinner.js';
9
- import { ApiKeyError, NetworkError, PayMongoError } from '../utils/errors.js';
9
+ import { ApiKeyError, NetworkError, PayMongoError, CommandError } from '../utils/errors.js';
10
10
  export async function initAction(options) {
11
11
  const spinner = new Spinner();
12
12
  const configManager = new ConfigManager();
@@ -156,7 +156,7 @@ export async function initAction(options) {
156
156
  else {
157
157
  console.error(chalk.red('❌ Unexpected error during validation. Please try again.'));
158
158
  }
159
- process.exit(1);
159
+ throw new CommandError();
160
160
  }
161
161
  spinner.start('Saving configuration...');
162
162
  await configManager.save(tempConfig);
@@ -239,7 +239,7 @@ PAYMONGO_ENVIRONMENT=${answers.environment}
239
239
  console.log('');
240
240
  console.log(chalk.yellow('💡 For help, visit: https://developers.paymongo.com/docs'));
241
241
  }
242
- process.exit(1);
242
+ throw new CommandError();
243
243
  }
244
244
  }
245
245
  const command = new Command('init');
@@ -7,7 +7,7 @@ import chalk from 'chalk';
7
7
  import ConfigManager from '../services/config/manager.js';
8
8
  import ApiClient from '../services/api/client.js';
9
9
  import { validateApiKey } from '../utils/validator.js';
10
- import { ApiKeyError, NetworkError, PayMongoError } from '../utils/errors.js';
10
+ import { ApiKeyError, NetworkError, PayMongoError, CommandError } from '../utils/errors.js';
11
11
  import Spinner from '../utils/spinner.js';
12
12
  class CredentialManager {
13
13
  credentialsPath;
@@ -213,7 +213,7 @@ command
213
213
  else {
214
214
  console.error(chalk.red('❌ Unexpected error during validation. Please try again.'));
215
215
  }
216
- process.exit(1);
216
+ throw new CommandError();
217
217
  }
218
218
  spinner.start('Storing credentials securely...');
219
219
  const credentials = {
@@ -285,7 +285,7 @@ command
285
285
  console.log('');
286
286
  console.log(chalk.yellow('💡 For help, visit: https://developers.paymongo.com'));
287
287
  }
288
- process.exit(1);
288
+ throw new CommandError();
289
289
  }
290
290
  });
291
291
  export { command, CredentialManager };
@@ -6,6 +6,7 @@ import ApiClient from '../services/api/client.js';
6
6
  import { PaymentSimulator } from '../services/payments/simulator.js';
7
7
  import { BulkOperations } from '../utils/bulk.js';
8
8
  import Spinner from '../utils/spinner.js';
9
+ import { CommandError } from '../utils/errors.js';
9
10
  export async function exportAction(options) {
10
11
  const spinner = new Spinner();
11
12
  const configManager = new ConfigManager();
@@ -52,7 +53,7 @@ export async function exportAction(options) {
52
53
  spinner.stop();
53
54
  const err = error;
54
55
  console.error(chalk.red('❌ Failed to export payments:'), err.message);
55
- process.exit(1);
56
+ throw new CommandError();
56
57
  }
57
58
  }
58
59
  export async function importAction(filename, options) {
@@ -90,7 +91,7 @@ export async function importAction(filename, options) {
90
91
  spinner.stop();
91
92
  const err = error;
92
93
  console.error(chalk.red('❌ Failed to import payments:'), err.message);
93
- process.exit(1);
94
+ throw new CommandError();
94
95
  }
95
96
  }
96
97
  export async function listAction(options) {
@@ -155,7 +156,7 @@ export async function listAction(options) {
155
156
  spinner.stop();
156
157
  const err = error;
157
158
  console.error(chalk.red('❌ Failed to fetch payments:'), err.message);
158
- process.exit(1);
159
+ throw new CommandError();
159
160
  }
160
161
  }
161
162
  export async function showAction(id, options) {
@@ -208,7 +209,7 @@ export async function showAction(id, options) {
208
209
  spinner.stop();
209
210
  const err = error;
210
211
  console.error(chalk.red('❌ Failed to fetch payment:'), err.message);
211
- process.exit(1);
212
+ throw new CommandError();
212
213
  }
213
214
  }
214
215
  export async function createIntentAction(options) {
@@ -252,7 +253,7 @@ export async function createIntentAction(options) {
252
253
  spinner.stop();
253
254
  const err = error;
254
255
  console.error(chalk.red('❌ Failed to create payment intent:'), err.message);
255
- process.exit(1);
256
+ throw new CommandError();
256
257
  }
257
258
  }
258
259
  export async function confirmAction(intentId, options) {
@@ -349,7 +350,7 @@ export async function confirmAction(intentId, options) {
349
350
  spinner.stop();
350
351
  const err = error;
351
352
  console.error(chalk.red('❌ Failed to confirm payment intent:'), err.message);
352
- process.exit(1);
353
+ throw new CommandError();
353
354
  }
354
355
  }
355
356
  export async function captureAction(intentId, options) {
@@ -389,7 +390,7 @@ export async function captureAction(intentId, options) {
389
390
  spinner.stop();
390
391
  const err = error;
391
392
  console.error(chalk.red('❌ Failed to capture payment intent:'), err.message);
392
- process.exit(1);
393
+ throw new CommandError();
393
394
  }
394
395
  }
395
396
  export async function refundAction(paymentId, options) {
@@ -435,7 +436,7 @@ export async function refundAction(paymentId, options) {
435
436
  spinner.stop();
436
437
  const err = error;
437
438
  console.error(chalk.red('❌ Failed to create refund:'), err.message);
438
- process.exit(1);
439
+ throw new CommandError();
439
440
  }
440
441
  }
441
442
  const command = new Command('payments');
@@ -4,6 +4,7 @@ import Spinner from '../../utils/spinner.js';
4
4
  import chalk from 'chalk';
5
5
  import { ConfigManager } from '../../services/config/manager.js';
6
6
  import { TeamService } from '../../services/team/service.js';
7
+ import { CommandError } from '../../utils/errors.js';
7
8
  const command = new Command('team')
8
9
  .description('Team collaboration with API key sharing')
9
10
  .showHelpAfterError();
@@ -23,7 +24,7 @@ command
23
24
  if (invalidEnvs.length > 0) {
24
25
  console.error(chalk.red(`❌ Invalid environments: ${invalidEnvs.join(', ')}`));
25
26
  console.log(`Valid environments: ${validEnvs.join(', ')}`);
26
- process.exit(1);
27
+ throw new CommandError();
27
28
  }
28
29
  spinner.start(`Creating key bundle for ${environments.join(', ')}...`);
29
30
  const bundle = await teamService.createKeyBundle(environments);
@@ -70,7 +71,7 @@ command
70
71
  spinner.stop();
71
72
  const err = error;
72
73
  console.error(chalk.red('❌ Failed to create key bundle:'), err.message);
73
- process.exit(1);
74
+ throw new CommandError();
74
75
  }
75
76
  });
76
77
  command
@@ -127,7 +128,7 @@ command
127
128
  spinner.stop();
128
129
  const err = error;
129
130
  console.error(chalk.red('❌ Failed to import keys:'), err.message);
130
- process.exit(1);
131
+ throw new CommandError();
131
132
  }
132
133
  });
133
134
  command
@@ -190,7 +191,7 @@ command
190
191
  spinner.stop();
191
192
  const err = error;
192
193
  console.error(chalk.red('❌ Failed to load team members:'), err.message);
193
- process.exit(1);
194
+ throw new CommandError();
194
195
  }
195
196
  });
196
197
  command
@@ -211,7 +212,7 @@ command
211
212
  spinner.stop();
212
213
  const err = error;
213
214
  console.error(chalk.red('❌ Failed to rename team:'), err.message);
214
- process.exit(1);
215
+ throw new CommandError();
215
216
  }
216
217
  });
217
218
  command
@@ -242,7 +243,7 @@ command
242
243
  spinner.stop();
243
244
  const err = error;
244
245
  console.error(chalk.red('❌ Failed to remove team member:'), err.message);
245
- process.exit(1);
246
+ throw new CommandError();
246
247
  }
247
248
  });
248
249
  export default command;
@@ -6,6 +6,8 @@ import Spinner from '../utils/spinner.js';
6
6
  import Logger from '../utils/logger.js';
7
7
  import WebhookEventStore from '../utils/webhook-store.js';
8
8
  import crypto from 'crypto';
9
+ import { CLI_VERSION } from '../utils/constants.js';
10
+ import { CommandError } from '../utils/errors.js';
9
11
  function buildSignatureHeader(config, webhookUrl, body) {
10
12
  if (!config?.webhookSecrets || Object.keys(config.webhookSecrets).length === 0) {
11
13
  return undefined;
@@ -119,11 +121,11 @@ async function sendWebhookEvent(options) {
119
121
  }
120
122
  if (!webhookUrl) {
121
123
  console.error(chalk.red('❌ No webhook URL provided. Use --url option or configure in .paymongo file'));
122
- process.exit(1);
124
+ throw new CommandError();
123
125
  }
124
126
  if (!selectedEvent) {
125
127
  console.error(chalk.red('❌ No event selected'));
126
- process.exit(1);
128
+ throw new CommandError();
127
129
  }
128
130
  spinner.start('Generating webhook payload...');
129
131
  const webhookPayload = generateWebhookPayload(selectedEvent);
@@ -158,7 +160,7 @@ async function sendWebhookEvent(options) {
158
160
  method: 'POST',
159
161
  headers: {
160
162
  'Content-Type': 'application/json',
161
- 'User-Agent': 'PayMongo-CLI/1.0.0',
163
+ 'User-Agent': `PayMongo-CLI/${CLI_VERSION}`,
162
164
  ...(signatureHeader ? { 'paymongo-signature': signatureHeader } : {}),
163
165
  },
164
166
  body,
@@ -187,7 +189,7 @@ async function sendWebhookEvent(options) {
187
189
  console.log(chalk.yellow('💡 To fix:'));
188
190
  console.log(chalk.gray(` • Verify your server has a POST handler at: ${webhookUrl}`));
189
191
  console.log(chalk.gray(' • Check that your server is running and accessible'));
190
- process.exit(1);
192
+ throw new CommandError();
191
193
  }
192
194
  else if (response.statusCode >= 400 && response.statusCode < 500) {
193
195
  spinner.fail(`Webhook rejected by server (HTTP ${response.statusCode})`);
@@ -204,7 +206,7 @@ async function sendWebhookEvent(options) {
204
206
  console.log(chalk.gray(' • Invalid request format or headers'));
205
207
  console.log(chalk.gray(' • Authentication/authorization failure'));
206
208
  console.log(chalk.gray(' • Webhook signature verification failed'));
207
- process.exit(1);
209
+ throw new CommandError();
208
210
  }
209
211
  else if (response.statusCode >= 500) {
210
212
  spinner.fail(`Webhook endpoint error (HTTP ${response.statusCode})`);
@@ -220,7 +222,7 @@ async function sendWebhookEvent(options) {
220
222
  console.log(chalk.yellow('💡 This is a server-side error. Check:'));
221
223
  console.log(chalk.gray(' • Server logs for the specific error'));
222
224
  console.log(chalk.gray(' • Webhook handler code for exceptions'));
223
- process.exit(1);
225
+ throw new CommandError();
224
226
  }
225
227
  }
226
228
  catch (error) {
@@ -238,7 +240,7 @@ async function sendWebhookEvent(options) {
238
240
  console.log(chalk.yellow('💡 To fix:'));
239
241
  console.log(chalk.gray(' • Start your local server'));
240
242
  console.log(chalk.gray(` • Verify the server is listening on the correct port`));
241
- process.exit(1);
243
+ throw new CommandError();
242
244
  }
243
245
  else if (err.code === 'ENOTFOUND') {
244
246
  spinner.fail('Host not found');
@@ -249,7 +251,7 @@ async function sendWebhookEvent(options) {
249
251
  console.log(chalk.gray(' • The URL is spelled correctly'));
250
252
  console.log(chalk.gray(' • Your internet connection is working'));
251
253
  console.log(chalk.gray(' • DNS is resolving correctly'));
252
- process.exit(1);
254
+ throw new CommandError();
253
255
  }
254
256
  else if (err.code === 'ETIMEDOUT' || err.message.includes('timeout')) {
255
257
  spinner.fail('Request timed out');
@@ -264,7 +266,7 @@ async function sendWebhookEvent(options) {
264
266
  console.log(chalk.yellow('💡 To fix:'));
265
267
  console.log(chalk.gray(' • Check your webhook handler for slow operations'));
266
268
  console.log(chalk.gray(' • Ensure async operations are handled properly'));
267
- process.exit(1);
269
+ throw new CommandError();
268
270
  }
269
271
  else {
270
272
  spinner.fail(`Webhook delivery failed: ${err.message}`);
@@ -274,7 +276,7 @@ async function sendWebhookEvent(options) {
274
276
  if (err.code) {
275
277
  console.log(chalk.gray(` Code: ${err.code}`));
276
278
  }
277
- process.exit(1);
279
+ throw new CommandError();
278
280
  }
279
281
  }
280
282
  }
@@ -282,7 +284,7 @@ async function sendWebhookEvent(options) {
282
284
  const err = error;
283
285
  spinner.fail('Failed to trigger webhook event');
284
286
  logger.error('Trigger command error:', err.message);
285
- process.exit(1);
287
+ throw new CommandError();
286
288
  }
287
289
  }
288
290
  function generateWebhookPayload(eventType) {
@@ -497,7 +499,7 @@ async function replayWebhookEvent(eventId, options) {
497
499
  if (!event) {
498
500
  console.log(chalk.red(`❌ Event not found: ${eventId}`));
499
501
  console.log(chalk.gray('Use "paymongo trigger replay --list" to see available events.'));
500
- process.exit(1);
502
+ throw new CommandError();
501
503
  }
502
504
  const webhookUrl = options.url || event.url;
503
505
  console.log(chalk.bold.blue('\n🔄 Replaying Webhook Event'));
@@ -516,7 +518,7 @@ async function replayWebhookEvent(eventId, options) {
516
518
  method: 'POST',
517
519
  headers: {
518
520
  'Content-Type': 'application/json',
519
- 'User-Agent': 'PayMongo-CLI/1.0.0',
521
+ 'User-Agent': `PayMongo-CLI/${CLI_VERSION}`,
520
522
  ...(signatureHeader ? { 'paymongo-signature': signatureHeader } : {}),
521
523
  },
522
524
  body,
@@ -537,7 +539,7 @@ async function replayWebhookEvent(eventId, options) {
537
539
  else {
538
540
  spinner.fail(`Webhook replay failed (HTTP ${response.statusCode})`);
539
541
  console.log(chalk.red(`Server responded with: ${response.statusCode}`));
540
- process.exit(1);
542
+ throw new CommandError();
541
543
  }
542
544
  }
543
545
  catch (error) {
@@ -549,14 +551,14 @@ async function replayWebhookEvent(eventId, options) {
549
551
  else {
550
552
  console.log(chalk.red(`❌ Error: ${err.message}`));
551
553
  }
552
- process.exit(1);
554
+ throw new CommandError();
553
555
  }
554
556
  }
555
557
  }
556
558
  catch (error) {
557
559
  const err = error;
558
560
  console.error(chalk.red(`❌ Failed to replay webhook: ${err.message}`));
559
- process.exit(1);
561
+ throw new CommandError();
560
562
  }
561
563
  }
562
564
  function generateId() {