paymongo-cli 1.4.11 → 1.4.13
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/CHANGELOG.md +36 -0
- package/README.md +4 -3
- package/biome.json +72 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/commands/config/actions.js +13 -5
- package/dist/commands/config/analytics.js +75 -0
- package/dist/commands/config/helpers.js +14 -25
- package/dist/commands/config/rate-limit.js +3 -3
- package/dist/commands/config.js +7 -1
- package/dist/commands/dev/logs.js +13 -4
- package/dist/commands/dev/status.js +1 -1
- package/dist/commands/dev/stop.js +2 -2
- package/dist/commands/dev.js +10 -258
- package/dist/commands/doctor.js +241 -0
- package/dist/commands/env.js +10 -19
- package/dist/commands/generate/templates/index.js +3 -3
- package/dist/commands/generate.js +6 -6
- package/dist/commands/init.js +22 -36
- package/dist/commands/login.js +18 -29
- package/dist/commands/payments/actions.js +15 -15
- package/dist/commands/payments/helpers.js +6 -24
- package/dist/commands/payments.js +1 -1
- package/dist/commands/shared/auth.js +23 -0
- package/dist/commands/shared/runtime.js +35 -0
- package/dist/commands/team/index.js +3 -3
- package/dist/commands/trigger/actions.js +2 -2
- package/dist/commands/trigger/helpers.js +13 -9
- package/dist/commands/trigger.js +2 -2
- package/dist/commands/webhooks/actions.js +11 -11
- package/dist/commands/webhooks/helpers.js +5 -23
- package/dist/commands/webhooks.js +1 -1
- package/dist/index.js +37 -14
- package/dist/services/analytics/service.js +3 -3
- package/dist/services/api/client.js +8 -4
- package/dist/services/config/manager.js +3 -3
- package/dist/services/dev/process-manager.js +4 -4
- package/dist/services/dev/server.js +4 -6
- package/dist/services/dev/session.js +353 -0
- package/dist/services/team/service.js +1 -1
- package/dist/utils/bulk.js +11 -11
- package/dist/utils/cache.js +5 -5
- package/dist/utils/constants.js +1 -1
- package/dist/utils/webhook-store.js +3 -3
- package/package.json +11 -25
- package/vitest.config.ts +18 -0
- package/eslint.config.ts +0 -70
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { ApiKeyError, CommandError, NetworkError, PayMongoError } from '../utils/errors.js';
|
|
4
|
+
import { validateApiKey, validateWebhookUrl } from '../utils/validator.js';
|
|
5
|
+
import { createApiClient, createCommandContext } from './shared/runtime.js';
|
|
6
|
+
function statusIcon(status) {
|
|
7
|
+
switch (status) {
|
|
8
|
+
case 'pass':
|
|
9
|
+
return chalk.green('✓');
|
|
10
|
+
case 'warn':
|
|
11
|
+
return chalk.yellow('⚠');
|
|
12
|
+
case 'fail':
|
|
13
|
+
return chalk.red('✖');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function printCheck(check) {
|
|
17
|
+
console.log(`${statusIcon(check.status)} ${chalk.bold(check.name)}: ${check.message}`);
|
|
18
|
+
if (check.fix) {
|
|
19
|
+
console.log(chalk.gray(` Fix: ${check.fix}`));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function hasNgrokToken() {
|
|
23
|
+
const token = process.env.NGROK_AUTHTOKEN;
|
|
24
|
+
return typeof token === 'string' && token.trim().length > 0;
|
|
25
|
+
}
|
|
26
|
+
async function runDoctor(options) {
|
|
27
|
+
const { configManager } = createCommandContext();
|
|
28
|
+
const checks = [];
|
|
29
|
+
const config = await configManager.load();
|
|
30
|
+
if (!config) {
|
|
31
|
+
checks.push({
|
|
32
|
+
name: 'Configuration',
|
|
33
|
+
status: 'fail',
|
|
34
|
+
message: 'No .paymongo configuration found.',
|
|
35
|
+
fix: 'Run `paymongo init` to create project configuration.',
|
|
36
|
+
});
|
|
37
|
+
return checks;
|
|
38
|
+
}
|
|
39
|
+
checks.push({
|
|
40
|
+
name: 'Configuration',
|
|
41
|
+
status: 'pass',
|
|
42
|
+
message: `Loaded configuration for project "${config.projectName}".`,
|
|
43
|
+
});
|
|
44
|
+
const env = config.environment;
|
|
45
|
+
const envKeys = config.apiKeys[env];
|
|
46
|
+
if (!envKeys?.secret) {
|
|
47
|
+
checks.push({
|
|
48
|
+
name: 'Secret API Key',
|
|
49
|
+
status: 'fail',
|
|
50
|
+
message: `No secret key configured for ${env} environment.`,
|
|
51
|
+
fix: `Run \`paymongo config set apiKeys.${env}.secret YOUR_SECRET_KEY\`.`,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
else if (!validateApiKey(envKeys.secret, 'secret')) {
|
|
55
|
+
checks.push({
|
|
56
|
+
name: 'Secret API Key',
|
|
57
|
+
status: 'fail',
|
|
58
|
+
message: `Secret key format is invalid for ${env} environment.`,
|
|
59
|
+
fix: 'Use a valid PayMongo secret key starting with `sk_test_` or `sk_live_`.',
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
checks.push({
|
|
64
|
+
name: 'Secret API Key',
|
|
65
|
+
status: 'pass',
|
|
66
|
+
message: `Secret key format looks valid for ${env} environment.`,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
if (!envKeys?.public) {
|
|
70
|
+
checks.push({
|
|
71
|
+
name: 'Public API Key',
|
|
72
|
+
status: 'warn',
|
|
73
|
+
message: `No public key configured for ${env} environment.`,
|
|
74
|
+
fix: `Run \`paymongo config set apiKeys.${env}.public YOUR_PUBLIC_KEY\` if your integration needs it.`,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
else if (!validateApiKey(envKeys.public, 'public')) {
|
|
78
|
+
checks.push({
|
|
79
|
+
name: 'Public API Key',
|
|
80
|
+
status: 'fail',
|
|
81
|
+
message: `Public key format is invalid for ${env} environment.`,
|
|
82
|
+
fix: 'Use a valid PayMongo public key starting with `pk_test_` or `pk_live_`.',
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
checks.push({
|
|
87
|
+
name: 'Public API Key',
|
|
88
|
+
status: 'pass',
|
|
89
|
+
message: `Public key format looks valid for ${env} environment.`,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
if (config.webhooks.url) {
|
|
93
|
+
if (validateWebhookUrl(config.webhooks.url)) {
|
|
94
|
+
checks.push({
|
|
95
|
+
name: 'Webhook URL',
|
|
96
|
+
status: 'pass',
|
|
97
|
+
message: `Webhook URL is valid: ${config.webhooks.url}`,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
checks.push({
|
|
102
|
+
name: 'Webhook URL',
|
|
103
|
+
status: 'fail',
|
|
104
|
+
message: `Webhook URL is invalid: ${config.webhooks.url}`,
|
|
105
|
+
fix: 'Set a valid HTTPS or localhost webhook URL.',
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (config.dev.autoRegisterWebhook) {
|
|
110
|
+
if (hasNgrokToken()) {
|
|
111
|
+
checks.push({
|
|
112
|
+
name: 'ngrok Token',
|
|
113
|
+
status: 'pass',
|
|
114
|
+
message: 'NGROK_AUTHTOKEN is configured for `paymongo dev`.',
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
checks.push({
|
|
119
|
+
name: 'ngrok Token',
|
|
120
|
+
status: 'warn',
|
|
121
|
+
message: '`paymongo dev` auto-registration may fail because NGROK_AUTHTOKEN is not set.',
|
|
122
|
+
fix: 'Set `NGROK_AUTHTOKEN` or use `paymongo dev --ngrok-token YOUR_TOKEN`.',
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const secretCount = Object.keys(config.webhookSecrets || {}).length;
|
|
127
|
+
if (config.dev.verifyWebhookSignatures) {
|
|
128
|
+
if (secretCount > 0) {
|
|
129
|
+
checks.push({
|
|
130
|
+
name: 'Webhook Signatures',
|
|
131
|
+
status: 'pass',
|
|
132
|
+
message: `Signature verification is enabled and ${secretCount} webhook secret(s) are stored.`,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
checks.push({
|
|
137
|
+
name: 'Webhook Signatures',
|
|
138
|
+
status: 'warn',
|
|
139
|
+
message: 'Signature verification is enabled, but no webhook secrets are stored yet.',
|
|
140
|
+
fix: 'Create or auto-register a webhook so PayMongo returns and stores a webhook secret.',
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
checks.push({
|
|
146
|
+
name: 'Webhook Signatures',
|
|
147
|
+
status: 'warn',
|
|
148
|
+
message: 'Signature verification is disabled.',
|
|
149
|
+
fix: 'Enable it with `paymongo config set dev.verifySignatures true` for safer local testing.',
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
const registeredCount = config.registeredWebhooks?.length || 0;
|
|
153
|
+
checks.push({
|
|
154
|
+
name: 'Registered Webhooks',
|
|
155
|
+
status: registeredCount > 0 ? 'pass' : 'warn',
|
|
156
|
+
message: registeredCount > 0
|
|
157
|
+
? `${registeredCount} project-managed webhook(s) tracked for cleanup.`
|
|
158
|
+
: 'No project-managed webhooks are currently tracked.',
|
|
159
|
+
});
|
|
160
|
+
if (options.network !== false && envKeys?.secret && validateApiKey(envKeys.secret, 'secret')) {
|
|
161
|
+
const apiClient = createApiClient(config);
|
|
162
|
+
try {
|
|
163
|
+
await apiClient.validateApiKey();
|
|
164
|
+
checks.push({
|
|
165
|
+
name: 'PayMongo API',
|
|
166
|
+
status: 'pass',
|
|
167
|
+
message: `Secret API key authenticated successfully against the ${env} environment.`,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
const err = error;
|
|
172
|
+
let message = err.message;
|
|
173
|
+
let fix;
|
|
174
|
+
if (error instanceof ApiKeyError) {
|
|
175
|
+
message = 'API authentication failed.';
|
|
176
|
+
fix = 'Check your configured secret key in the PayMongo dashboard.';
|
|
177
|
+
}
|
|
178
|
+
else if (error instanceof NetworkError) {
|
|
179
|
+
message = 'Could not reach the PayMongo API.';
|
|
180
|
+
fix = 'Check your internet connection and firewall settings.';
|
|
181
|
+
}
|
|
182
|
+
else if (error instanceof PayMongoError && error.statusCode === 429) {
|
|
183
|
+
message = 'PayMongo API rate limit reached during validation.';
|
|
184
|
+
fix = 'Wait briefly, then rerun `paymongo doctor`.';
|
|
185
|
+
}
|
|
186
|
+
const check = {
|
|
187
|
+
name: 'PayMongo API',
|
|
188
|
+
status: 'fail',
|
|
189
|
+
message,
|
|
190
|
+
};
|
|
191
|
+
if (fix !== undefined) {
|
|
192
|
+
check.fix = fix;
|
|
193
|
+
}
|
|
194
|
+
checks.push(check);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
else if (options.network === false) {
|
|
198
|
+
checks.push({
|
|
199
|
+
name: 'PayMongo API',
|
|
200
|
+
status: 'warn',
|
|
201
|
+
message: 'Skipped live API validation because `--no-network` was used.',
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
return checks;
|
|
205
|
+
}
|
|
206
|
+
export async function doctorAction(options) {
|
|
207
|
+
try {
|
|
208
|
+
const checks = await runDoctor(options);
|
|
209
|
+
if (options.json) {
|
|
210
|
+
console.log(JSON.stringify({ checks }, null, 2));
|
|
211
|
+
const hasFailure = checks.some((check) => check.status === 'fail');
|
|
212
|
+
if (hasFailure) {
|
|
213
|
+
throw new CommandError();
|
|
214
|
+
}
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
console.log(chalk.bold('\nPayMongo CLI Doctor'));
|
|
218
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
219
|
+
checks.forEach(printCheck);
|
|
220
|
+
const failed = checks.filter((check) => check.status === 'fail').length;
|
|
221
|
+
const warned = checks.filter((check) => check.status === 'warn').length;
|
|
222
|
+
console.log('');
|
|
223
|
+
console.log(`${chalk.bold('Summary:')} ${chalk.red(failed.toString())} failed, ${chalk.yellow(warned.toString())} warning(s)`);
|
|
224
|
+
if (failed > 0) {
|
|
225
|
+
throw new CommandError();
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
if (error instanceof CommandError) {
|
|
230
|
+
throw error;
|
|
231
|
+
}
|
|
232
|
+
console.error(chalk.red('❌ Failed to run doctor:'), error.message);
|
|
233
|
+
throw new CommandError();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
const command = new Command('doctor')
|
|
237
|
+
.description('Run diagnostics for local PayMongo integration setup')
|
|
238
|
+
.option('-j, --json', 'Output checks as JSON')
|
|
239
|
+
.option('--no-network', 'Skip live PayMongo API validation')
|
|
240
|
+
.action(async (options) => doctorAction(options));
|
|
241
|
+
export default command;
|
package/dist/commands/env.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
1
|
import chalk from 'chalk';
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import { ApiKeyError, NetworkError, PayMongoError, CommandError } from '../utils/errors.js';
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { ApiKeyError, CommandError, NetworkError, PayMongoError } from '../utils/errors.js';
|
|
4
|
+
import { createApiClient, createCommandContext, loadCommandConfig, showNoConfigMessage, } from './shared/runtime.js';
|
|
7
5
|
const command = new Command('env');
|
|
8
6
|
command
|
|
9
7
|
.description('Manage PayMongo environments')
|
|
@@ -12,22 +10,16 @@ command
|
|
|
12
10
|
.arguments('<environment>')
|
|
13
11
|
.option('-f, --force', 'Skip API key validation')
|
|
14
12
|
.action(async (environment, options) => {
|
|
15
|
-
const spinner =
|
|
16
|
-
const configManager = new ConfigManager();
|
|
13
|
+
const { spinner, configManager } = createCommandContext();
|
|
17
14
|
try {
|
|
18
15
|
if (!['test', 'live'].includes(environment)) {
|
|
19
16
|
console.error(chalk.red('❌ Invalid environment. Must be "test" or "live"'));
|
|
20
17
|
throw new CommandError();
|
|
21
18
|
}
|
|
22
|
-
spinner
|
|
23
|
-
const config = await configManager.load();
|
|
19
|
+
const config = await loadCommandConfig(spinner, configManager);
|
|
24
20
|
if (!config) {
|
|
25
|
-
spinner.fail('No configuration found');
|
|
26
|
-
console.log(chalk.yellow('No PayMongo configuration found.'));
|
|
27
|
-
console.log(chalk.gray("Run 'paymongo init' to set up your project first."));
|
|
28
21
|
return;
|
|
29
22
|
}
|
|
30
|
-
spinner.succeed('Configuration loaded');
|
|
31
23
|
const envConfig = config.apiKeys[environment];
|
|
32
24
|
if (!envConfig?.secret || !envConfig?.public) {
|
|
33
25
|
spinner.fail(`Missing API keys for ${environment} environment`);
|
|
@@ -41,7 +33,7 @@ command
|
|
|
41
33
|
if (!options.force) {
|
|
42
34
|
spinner.start('Validating API keys...');
|
|
43
35
|
const testConfig = { ...config, environment: environment };
|
|
44
|
-
const apiClient =
|
|
36
|
+
const apiClient = createApiClient(testConfig);
|
|
45
37
|
try {
|
|
46
38
|
await apiClient.validateApiKey();
|
|
47
39
|
spinner.succeed('API keys validated');
|
|
@@ -102,20 +94,19 @@ command
|
|
|
102
94
|
}
|
|
103
95
|
}))
|
|
104
96
|
.addCommand(new Command('current').description('Show current environment').action(async () => {
|
|
105
|
-
const configManager =
|
|
97
|
+
const { configManager } = createCommandContext();
|
|
106
98
|
try {
|
|
107
99
|
const config = await configManager.load();
|
|
108
100
|
if (!config) {
|
|
109
|
-
|
|
110
|
-
console.log(chalk.gray("Run 'paymongo init' to set up your project first."));
|
|
101
|
+
showNoConfigMessage();
|
|
111
102
|
return;
|
|
112
103
|
}
|
|
113
104
|
const env = config.environment;
|
|
114
105
|
const envConfig = config.apiKeys[env];
|
|
115
106
|
console.log(chalk.bold('Current Environment:'));
|
|
116
107
|
console.log(`Environment: ${chalk.cyan(env.toUpperCase())}`);
|
|
117
|
-
console.log(`Public Key: ${envConfig?.public ? chalk.gray(envConfig.public.substring(0, 10)
|
|
118
|
-
console.log(`Secret Key: ${envConfig?.secret ? chalk.gray(envConfig.secret.substring(0, 10)
|
|
108
|
+
console.log(`Public Key: ${envConfig?.public ? chalk.gray(`${envConfig.public.substring(0, 10)}...`) : chalk.red('Not set')}`);
|
|
109
|
+
console.log(`Secret Key: ${envConfig?.secret ? chalk.gray(`${envConfig.secret.substring(0, 10)}...`) : chalk.red('Not set')}`);
|
|
119
110
|
if (env === 'live') {
|
|
120
111
|
console.log('');
|
|
121
112
|
console.log(chalk.yellow('⚠️ You are using LIVE environment!'));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export { getWebhookHandlerTemplate as getTypeScriptWebhookHandler } from './webhook-handler/typescript.js';
|
|
1
|
+
export { getCheckoutPageTemplate, getHtmlTemplate, getReactTemplate, getVueTemplate, } from './checkout-page/index.js';
|
|
3
2
|
export { getPaymentIntentTemplate as getJavaScriptPaymentIntent } from './payment-intent/javascript.js';
|
|
4
3
|
export { getPaymentIntentTemplate as getTypeScriptPaymentIntent } from './payment-intent/typescript.js';
|
|
5
|
-
export {
|
|
4
|
+
export { getWebhookHandlerTemplate as getJavaScriptWebhookHandler } from './webhook-handler/javascript.js';
|
|
5
|
+
export { getWebhookHandlerTemplate as getTypeScriptWebhookHandler } from './webhook-handler/typescript.js';
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
-
import
|
|
3
|
+
import { Command } from 'commander';
|
|
4
4
|
import ConfigManager from '../services/config/manager.js';
|
|
5
5
|
import Spinner from '../utils/spinner.js';
|
|
6
|
-
import {
|
|
6
|
+
import { getCheckoutPageTemplate, getJavaScriptPaymentIntent, getJavaScriptWebhookHandler, getTypeScriptPaymentIntent, getTypeScriptWebhookHandler, } from './generate/templates/index.js';
|
|
7
7
|
const command = new Command('generate');
|
|
8
8
|
command
|
|
9
9
|
.description('Generate boilerplate code for PayMongo integrations')
|
|
@@ -126,7 +126,7 @@ async function generateWebhookHandler(options) {
|
|
|
126
126
|
spinner.start(`Generating webhook handler...`);
|
|
127
127
|
await fs.writeFile(outputFile, code, 'utf-8');
|
|
128
128
|
spinner.succeed(`Webhook handler generated: ${outputFile}`);
|
|
129
|
-
console.log(
|
|
129
|
+
console.log(`\n${chalk.green('✅ Webhook handler generated successfully!')}`);
|
|
130
130
|
console.log(chalk.gray(`Events handled: ${events.join(', ')}`));
|
|
131
131
|
console.log(chalk.gray(`Language: ${options.language}`));
|
|
132
132
|
console.log(chalk.gray(`Framework: ${options.framework}`));
|
|
@@ -162,7 +162,7 @@ async function generatePaymentIntent(options) {
|
|
|
162
162
|
spinner.start(`Generating payment intent code...`);
|
|
163
163
|
await fs.writeFile(outputFile, code, 'utf-8');
|
|
164
164
|
spinner.succeed(`Payment intent code generated: ${outputFile}`);
|
|
165
|
-
console.log(
|
|
165
|
+
console.log(`\n${chalk.green('✅ Payment intent code generated successfully!')}`);
|
|
166
166
|
console.log(chalk.gray(`Payment methods: ${methods.join(', ')}`));
|
|
167
167
|
console.log(chalk.gray(`Language: ${options.language}`));
|
|
168
168
|
}
|
|
@@ -187,7 +187,7 @@ async function generateCheckoutPage(options) {
|
|
|
187
187
|
spinner.start(`Generating checkout page...`);
|
|
188
188
|
await fs.writeFile(outputFile, code, 'utf-8');
|
|
189
189
|
spinner.succeed(`Checkout page generated: ${outputFile}`);
|
|
190
|
-
console.log(
|
|
190
|
+
console.log(`\n${chalk.green('✅ Checkout page generated successfully!')}`);
|
|
191
191
|
console.log(chalk.gray(`Framework: ${options.language}`));
|
|
192
192
|
}
|
|
193
193
|
catch (error) {
|
package/dist/commands/init.js
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
import * as
|
|
3
|
-
import * as path from 'path';
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
4
3
|
import chalk from 'chalk';
|
|
5
|
-
import
|
|
6
|
-
import
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { ApiKeyError, CommandError, NetworkError, PayMongoError } from '../utils/errors.js';
|
|
7
6
|
import { validateApiKey } from '../utils/validator.js';
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
7
|
+
import { createCredentialValidationConfig } from './shared/auth.js';
|
|
8
|
+
import { createApiClient, createCommandContext } from './shared/runtime.js';
|
|
10
9
|
export async function initAction(options) {
|
|
11
|
-
const spinner =
|
|
12
|
-
const configManager = new ConfigManager();
|
|
10
|
+
const { spinner, configManager } = createCommandContext();
|
|
13
11
|
try {
|
|
14
12
|
if (await configManager.exists()) {
|
|
15
13
|
const { confirm } = await import('@inquirer/prompts');
|
|
@@ -107,28 +105,16 @@ export async function initAction(options) {
|
|
|
107
105
|
};
|
|
108
106
|
}
|
|
109
107
|
spinner.start('Validating API keys...');
|
|
110
|
-
const tempConfig = {
|
|
111
|
-
version: '1.0',
|
|
108
|
+
const tempConfig = createCredentialValidationConfig({
|
|
112
109
|
projectName: answers.projectName,
|
|
113
110
|
environment: answers.environment,
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
url: answers.webhookUrl || `http://localhost:${answers.port}/webhook`,
|
|
122
|
-
events: answers.events,
|
|
123
|
-
},
|
|
124
|
-
webhookSecrets: {},
|
|
125
|
-
dev: {
|
|
126
|
-
port: answers.port,
|
|
127
|
-
autoRegisterWebhook: true,
|
|
128
|
-
verifyWebhookSignatures: true,
|
|
129
|
-
},
|
|
130
|
-
};
|
|
131
|
-
const apiClient = new ApiClient({ config: tempConfig });
|
|
111
|
+
publicKey: answers.publicKey,
|
|
112
|
+
secretKey: answers.secretKey,
|
|
113
|
+
webhookUrl: answers.webhookUrl || `http://localhost:${answers.port}/webhook`,
|
|
114
|
+
events: answers.events,
|
|
115
|
+
port: answers.port,
|
|
116
|
+
});
|
|
117
|
+
const apiClient = createApiClient(tempConfig);
|
|
132
118
|
try {
|
|
133
119
|
await apiClient.validateApiKey();
|
|
134
120
|
spinner.succeed('API keys validated');
|
|
@@ -191,19 +177,19 @@ PAYMONGO_ENVIRONMENT=${answers.environment}
|
|
|
191
177
|
if (needsPaymongo) {
|
|
192
178
|
lines.push('.paymongo');
|
|
193
179
|
}
|
|
194
|
-
gitignoreContent += lines.join('\n')
|
|
180
|
+
gitignoreContent += `${lines.join('\n')}\n`;
|
|
195
181
|
fs.writeFileSync(gitignorePath, gitignoreContent);
|
|
196
182
|
console.log(chalk.green('✓ Added .env and .paymongo to .gitignore'));
|
|
197
183
|
}
|
|
198
|
-
console.log(
|
|
199
|
-
console.log(
|
|
184
|
+
console.log(`\n${chalk.green('🎉 PayMongo project initialized!')}`);
|
|
185
|
+
console.log(`\n${chalk.bold('Configuration saved to .paymongo')}`);
|
|
200
186
|
console.log(chalk.bold('Environment variables saved to .env'));
|
|
201
|
-
console.log(
|
|
202
|
-
console.log(
|
|
187
|
+
console.log(`\n${chalk.bold('Next steps:')}`);
|
|
188
|
+
console.log(` 1. Run ${chalk.cyan('paymongo dev')} to start development server`);
|
|
203
189
|
console.log(' 2. Configure your webhook handler at ' +
|
|
204
190
|
chalk.cyan(`http://localhost:${answers.port}/webhook`));
|
|
205
|
-
console.log(
|
|
206
|
-
console.log(
|
|
191
|
+
console.log(` 3. Visit ${chalk.cyan('https://dashboard.paymongo.com')} to view transactions`);
|
|
192
|
+
console.log(`\n${chalk.yellow('Happy building! 🚀')}`);
|
|
207
193
|
}
|
|
208
194
|
catch (error) {
|
|
209
195
|
spinner.stop();
|
package/dist/commands/login.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
import * as fs from 'fs';
|
|
3
|
-
import * as
|
|
4
|
-
import * as
|
|
5
|
-
import * as os from 'os';
|
|
1
|
+
import * as crypto from 'node:crypto';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as os from 'node:os';
|
|
4
|
+
import * as path from 'node:path';
|
|
6
5
|
import chalk from 'chalk';
|
|
7
|
-
import
|
|
8
|
-
import
|
|
6
|
+
import { Command } from 'commander';
|
|
7
|
+
import { ApiKeyError, CommandError, NetworkError, PayMongoError } from '../utils/errors.js';
|
|
9
8
|
import { validateApiKey } from '../utils/validator.js';
|
|
10
|
-
import {
|
|
11
|
-
import
|
|
9
|
+
import { createCredentialValidationConfig } from './shared/auth.js';
|
|
10
|
+
import { createApiClient, createCommandContext } from './shared/runtime.js';
|
|
12
11
|
class CredentialManager {
|
|
13
12
|
credentialsPath;
|
|
14
13
|
encryptionKey;
|
|
@@ -105,8 +104,7 @@ command
|
|
|
105
104
|
.option('-e, --env <environment>', 'Environment (test or live)', 'test')
|
|
106
105
|
.option('--logout', 'Clear stored credentials')
|
|
107
106
|
.action(async (options) => {
|
|
108
|
-
const spinner =
|
|
109
|
-
const configManager = new ConfigManager();
|
|
107
|
+
const { spinner, configManager } = createCommandContext();
|
|
110
108
|
const credentialManager = new CredentialManager();
|
|
111
109
|
try {
|
|
112
110
|
if (options.logout) {
|
|
@@ -171,21 +169,12 @@ command
|
|
|
171
169
|
};
|
|
172
170
|
}
|
|
173
171
|
spinner.start('Validating API key...');
|
|
174
|
-
const tempConfig = {
|
|
175
|
-
version: '1.0',
|
|
176
|
-
projectName: 'temp',
|
|
172
|
+
const tempConfig = createCredentialValidationConfig({
|
|
177
173
|
environment: answers.environment,
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
},
|
|
183
|
-
},
|
|
184
|
-
webhooks: { url: '', events: [] },
|
|
185
|
-
webhookSecrets: {},
|
|
186
|
-
dev: { port: 3000, autoRegisterWebhook: true, verifyWebhookSignatures: true },
|
|
187
|
-
};
|
|
188
|
-
const apiClient = new ApiClient({ config: tempConfig });
|
|
174
|
+
publicKey: answers.publicKey || '',
|
|
175
|
+
secretKey: answers.secretKey,
|
|
176
|
+
});
|
|
177
|
+
const apiClient = createApiClient(tempConfig);
|
|
189
178
|
try {
|
|
190
179
|
await apiClient.validateApiKey();
|
|
191
180
|
spinner.succeed('API key validated');
|
|
@@ -244,14 +233,14 @@ command
|
|
|
244
233
|
};
|
|
245
234
|
await configManager.save(config);
|
|
246
235
|
}
|
|
247
|
-
console.log(
|
|
248
|
-
console.log(
|
|
236
|
+
console.log(`\n${chalk.green('🔐 PayMongo Login Successful')}`);
|
|
237
|
+
console.log(`\n${chalk.bold('Current configuration:')}`);
|
|
249
238
|
console.log(` Environment: ${answers.environment}`);
|
|
250
239
|
console.log(` Secret Key: ${'*'.repeat(20)}...${answers.secretKey.slice(-4)}`);
|
|
251
240
|
if (answers.publicKey) {
|
|
252
241
|
console.log(` Public Key: ${'*'.repeat(20)}...${answers.publicKey.slice(-4)}`);
|
|
253
242
|
}
|
|
254
|
-
console.log(
|
|
243
|
+
console.log(`\n${chalk.gray("Use 'paymongo config show' to view settings")}`);
|
|
255
244
|
console.log(chalk.gray("Use 'paymongo login --logout' to clear credentials"));
|
|
256
245
|
}
|
|
257
246
|
catch (error) {
|
|
@@ -288,4 +277,4 @@ command
|
|
|
288
277
|
throw new CommandError();
|
|
289
278
|
}
|
|
290
279
|
});
|
|
291
|
-
export {
|
|
280
|
+
export { CredentialManager, command };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import Table from 'cli-table3';
|
|
2
1
|
import chalk from 'chalk';
|
|
2
|
+
import Table from 'cli-table3';
|
|
3
3
|
import { BulkOperations } from '../../utils/bulk.js';
|
|
4
4
|
import { createApiClient, createPaymentSimulator, createPaymentsContext, getStatusColor, handlePaymentsError, loadPaymentsConfig, parseBoundedInt, } from './helpers.js';
|
|
5
5
|
export async function exportAction(options) {
|
|
@@ -23,7 +23,7 @@ export async function exportAction(options) {
|
|
|
23
23
|
spinner.start(`Exporting to ${filename}...`);
|
|
24
24
|
await BulkOperations.exportPayments(payments, filename, config.environment);
|
|
25
25
|
spinner.succeed('Export completed');
|
|
26
|
-
console.log(
|
|
26
|
+
console.log(`\n${chalk.green('✅ Payments exported successfully!')}`);
|
|
27
27
|
console.log('');
|
|
28
28
|
console.log(`${chalk.bold('File:')} ${filename}`);
|
|
29
29
|
console.log(`${chalk.bold('Payments:')} ${payments.length}`);
|
|
@@ -44,18 +44,18 @@ export async function importAction(filename, options) {
|
|
|
44
44
|
console.log(JSON.stringify({ payments, metadata }, null, 2));
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
|
-
console.log(
|
|
47
|
+
console.log(`\n${chalk.green('✅ Payments imported successfully!')}`);
|
|
48
48
|
console.log('');
|
|
49
49
|
console.log(`${chalk.bold('Source:')} ${filename}`);
|
|
50
50
|
console.log(`${chalk.bold('Payments:')} ${payments.length}`);
|
|
51
51
|
console.log(`${chalk.bold('Exported from:')} ${metadata.environment} environment`);
|
|
52
52
|
console.log(`${chalk.bold('Export date:')} ${new Date(metadata.exported_at).toLocaleString()}`);
|
|
53
|
-
console.log(
|
|
53
|
+
console.log(`\n${chalk.yellow('⚠️ Important Notes:')}`);
|
|
54
54
|
console.log(chalk.gray('• Payment data imported for reference only'));
|
|
55
55
|
console.log(chalk.gray('• Actual payments cannot be recreated through the API'));
|
|
56
56
|
console.log(chalk.gray('• Use this for data analysis, migration planning, or testing'));
|
|
57
57
|
if (payments.length > 0) {
|
|
58
|
-
console.log(
|
|
58
|
+
console.log(`\n${chalk.bold('Sample Payment IDs:')}`);
|
|
59
59
|
payments.slice(0, 5).forEach((payment, index) => {
|
|
60
60
|
const amount = (payment.attributes.amount / 100).toFixed(2);
|
|
61
61
|
console.log(` ${index + 1}. ${payment.id} - ₱${amount} ${payment.attributes.currency}`);
|
|
@@ -111,10 +111,10 @@ export async function listAction(options) {
|
|
|
111
111
|
chalk.yellow(amount),
|
|
112
112
|
getStatusColor(status)(status),
|
|
113
113
|
chalk.gray(created),
|
|
114
|
-
chalk.white(description.length > 25 ? description.substring(0, 22)
|
|
114
|
+
chalk.white(description.length > 25 ? `${description.substring(0, 22)}...` : description),
|
|
115
115
|
]);
|
|
116
116
|
});
|
|
117
|
-
console.log(
|
|
117
|
+
console.log(`\n${chalk.bold('Recent Payments')}`);
|
|
118
118
|
console.log(chalk.gray('─'.repeat(95)));
|
|
119
119
|
console.log(table.toString());
|
|
120
120
|
console.log(chalk.gray(`Total: ${payments.length} payments`));
|
|
@@ -142,7 +142,7 @@ export async function showAction(id, options) {
|
|
|
142
142
|
const amount = (attrs.amount / 100).toFixed(2);
|
|
143
143
|
const fees = attrs.fees ? (attrs.fees / 100).toFixed(2) : '0.00';
|
|
144
144
|
const netAmount = attrs.net_amount ? (attrs.net_amount / 100).toFixed(2) : '0.00';
|
|
145
|
-
console.log(
|
|
145
|
+
console.log(`\n${chalk.bold('Payment Details')}`);
|
|
146
146
|
console.log(chalk.gray('─'.repeat(50)));
|
|
147
147
|
console.log(`${chalk.bold('ID:')} ${payment.id}`);
|
|
148
148
|
console.log(`${chalk.bold('Amount:')} ₱${amount} ${attrs.currency}`);
|
|
@@ -183,7 +183,7 @@ export async function createIntentAction(options) {
|
|
|
183
183
|
return;
|
|
184
184
|
}
|
|
185
185
|
const attrs = paymentIntent.attributes;
|
|
186
|
-
console.log(
|
|
186
|
+
console.log(`\n${chalk.bold('Payment Intent Created')}`);
|
|
187
187
|
console.log(chalk.gray('─'.repeat(50)));
|
|
188
188
|
console.log(`${chalk.bold('ID:')} ${paymentIntent.id}`);
|
|
189
189
|
console.log(`${chalk.bold('Amount:')} ₱${(attrs.amount / 100).toFixed(2)} ${attrs.currency}`);
|
|
@@ -222,10 +222,10 @@ export async function attachAction(intentId, options) {
|
|
|
222
222
|
throw new Error(`Invalid simulation outcome. Must be one of: ${validOutcomes.join(', ')}`);
|
|
223
223
|
}
|
|
224
224
|
const delayMs = options.delay ? parseInt(options.delay, 10) : undefined;
|
|
225
|
-
if (options.delay && (delayMs === undefined || isNaN(delayMs) || delayMs <= 0)) {
|
|
225
|
+
if (options.delay && (delayMs === undefined || Number.isNaN(delayMs) || delayMs <= 0)) {
|
|
226
226
|
throw new Error('Simulation delay must be a positive number in milliseconds');
|
|
227
227
|
}
|
|
228
|
-
console.log(
|
|
228
|
+
console.log(`\n${chalk.bold('🧪 Payment Simulation Mode')}`);
|
|
229
229
|
console.log(chalk.gray('─'.repeat(50)));
|
|
230
230
|
console.log(`${chalk.bold('Method:')} ${options.method.toUpperCase()}`);
|
|
231
231
|
console.log(`${chalk.bold('Outcome:')} ${options.outcome}`);
|
|
@@ -243,7 +243,7 @@ export async function attachAction(intentId, options) {
|
|
|
243
243
|
return;
|
|
244
244
|
}
|
|
245
245
|
const attrs = result.paymentIntent.attributes;
|
|
246
|
-
console.log(
|
|
246
|
+
console.log(`\n${chalk.bold('Payment Intent Confirmed (Simulated)')}`);
|
|
247
247
|
console.log(chalk.gray('─'.repeat(50)));
|
|
248
248
|
console.log(`${chalk.bold('ID:')} ${result.paymentIntent.id}`);
|
|
249
249
|
console.log(`${chalk.bold('Amount:')} ₱${(attrs.amount / 100).toFixed(2)} ${attrs.currency}`);
|
|
@@ -264,7 +264,7 @@ export async function attachAction(intentId, options) {
|
|
|
264
264
|
return;
|
|
265
265
|
}
|
|
266
266
|
const attrs = result.attributes;
|
|
267
|
-
console.log(
|
|
267
|
+
console.log(`\n${chalk.bold('Payment Method Attached')}`);
|
|
268
268
|
console.log(chalk.gray('─'.repeat(50)));
|
|
269
269
|
console.log(`${chalk.bold('ID:')} ${result.id}`);
|
|
270
270
|
console.log(`${chalk.bold('Amount:')} ₱${(attrs.amount / 100).toFixed(2)} ${attrs.currency}`);
|
|
@@ -295,7 +295,7 @@ export async function captureAction(intentId, options) {
|
|
|
295
295
|
return;
|
|
296
296
|
}
|
|
297
297
|
const attrs = result.attributes;
|
|
298
|
-
console.log(
|
|
298
|
+
console.log(`\n${chalk.bold('Payment Intent Captured')}`);
|
|
299
299
|
console.log(chalk.gray('─'.repeat(50)));
|
|
300
300
|
console.log(`${chalk.bold('ID:')} ${result.id}`);
|
|
301
301
|
console.log(`${chalk.bold('Amount:')} ₱${(attrs.amount / 100).toFixed(2)} ${attrs.currency}`);
|
|
@@ -331,7 +331,7 @@ export async function refundAction(paymentId, options) {
|
|
|
331
331
|
return;
|
|
332
332
|
}
|
|
333
333
|
const attrs = refund.attributes;
|
|
334
|
-
console.log(
|
|
334
|
+
console.log(`\n${chalk.bold('Refund Created')}`);
|
|
335
335
|
console.log(chalk.gray('─'.repeat(50)));
|
|
336
336
|
console.log(`${chalk.bold('ID:')} ${refund.id}`);
|
|
337
337
|
console.log(`${chalk.bold('Payment ID:')} ${attrs.payment_id}`);
|