@ktmcp-cli/nowpayments 1.0.0 → 1.0.2

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.
@@ -1,184 +0,0 @@
1
- /**
2
- * Payout command
3
- *
4
- * Create and manage cryptocurrency payouts/withdrawals.
5
- */
6
-
7
- const { Command } = require('commander');
8
- const chalk = require('chalk');
9
- const Table = require('cli-table3');
10
- const { makeRequest, handleApiError, displayResponse } = require('../lib/api');
11
-
12
- const command = new Command('payout');
13
-
14
- command
15
- .description('Manage payouts and withdrawals')
16
- .summary('Create and query payout transactions');
17
-
18
- // Create a new payout
19
- command
20
- .command('create')
21
- .description('Create a new payout/withdrawal')
22
- .requiredOption('-a, --amount <amount>', 'Payout amount')
23
- .requiredOption('-c, --currency <currency>', 'Cryptocurrency (e.g., BTC)')
24
- .requiredOption('--address <address>', 'Destination wallet address')
25
- .option('--ipn-url <url>', 'IPN callback URL')
26
- .option('--extra-id <id>', 'Extra ID for currencies that require it (e.g., XRP destination tag)')
27
- .action(async (options) => {
28
- try {
29
- const amount = parseFloat(options.amount);
30
-
31
- if (isNaN(amount) || amount <= 0) {
32
- console.error(chalk.red('Error: Amount must be a positive number'));
33
- process.exit(1);
34
- }
35
-
36
- const payoutData = {
37
- withdrawals: [{
38
- address: options.address,
39
- currency: options.currency.toUpperCase(),
40
- amount: amount,
41
- ipn_callback_url: options.ipnUrl,
42
- extra_id: options.extraId
43
- }]
44
- };
45
-
46
- const data = await makeRequest(command.parent.parent, '/payout', {
47
- method: 'POST',
48
- body: payoutData
49
- });
50
-
51
- displayResponse(command.parent.parent, data, (response) => {
52
- console.log(chalk.green('\n✓ Payout created successfully'));
53
- console.log(chalk.cyan('\nPayout Details:'));
54
-
55
- if (response.withdrawals && response.withdrawals.length > 0) {
56
- const payout = response.withdrawals[0];
57
- console.log(chalk.bold(' Payout ID:'), payout.id);
58
- console.log(chalk.bold(' Status:'), payout.status);
59
- console.log(chalk.bold(' Amount:'), `${payout.amount} ${payout.currency}`);
60
- console.log(chalk.bold(' Address:'), payout.address);
61
-
62
- if (payout.extra_id) {
63
- console.log(chalk.bold(' Extra ID:'), payout.extra_id);
64
- }
65
- }
66
-
67
- console.log(chalk.yellow('\n⚠ Note: Some payouts may require 2FA verification'));
68
- });
69
- } catch (error) {
70
- handleApiError(error);
71
- }
72
- });
73
-
74
- // Verify payout (2FA)
75
- command
76
- .command('verify <payout-id> <verification-code>')
77
- .description('Verify a payout with 2FA code')
78
- .action(async (payoutId, code) => {
79
- try {
80
- const data = await makeRequest(command.parent.parent, `/payout/${payoutId}/verify`, {
81
- method: 'POST',
82
- body: { verification_code: code }
83
- });
84
-
85
- displayResponse(command.parent.parent, data, (response) => {
86
- console.log(chalk.green('\n✓ Payout verified successfully'));
87
- console.log(chalk.cyan('\nStatus:'), response.status || 'Verified');
88
- });
89
- } catch (error) {
90
- handleApiError(error);
91
- }
92
- });
93
-
94
- // Get payout details
95
- command
96
- .command('get <payout-id>')
97
- .description('Get payout details by ID')
98
- .action(async (payoutId) => {
99
- try {
100
- const data = await makeRequest(command.parent.parent, `/payout/${payoutId}`);
101
-
102
- displayResponse(command.parent.parent, data, (response) => {
103
- console.log(chalk.cyan('\nPayout Details:'));
104
-
105
- const table = new Table({
106
- chars: { 'mid': '', 'left-mid': '', 'mid-mid': '', 'right-mid': '' }
107
- });
108
-
109
- table.push(
110
- ['Payout ID', response.id],
111
- ['Status', response.status],
112
- ['Amount', `${response.amount} ${response.currency}`],
113
- ['Address', response.address]
114
- );
115
-
116
- if (response.extra_id) {
117
- table.push(['Extra ID', response.extra_id]);
118
- }
119
-
120
- if (response.hash) {
121
- table.push(['Transaction Hash', response.hash]);
122
- }
123
-
124
- table.push(
125
- ['Created', new Date(response.created_at).toLocaleString()]
126
- );
127
-
128
- console.log(table.toString());
129
- });
130
- } catch (error) {
131
- handleApiError(error);
132
- }
133
- });
134
-
135
- // List payouts
136
- command
137
- .command('list')
138
- .description('List all payouts')
139
- .option('-l, --limit <number>', 'Number of payouts to return', '10')
140
- .option('-p, --page <number>', 'Page number', '0')
141
- .action(async (options) => {
142
- try {
143
- const queryParams = {
144
- limit: parseInt(options.limit),
145
- page: parseInt(options.page)
146
- };
147
-
148
- const data = await makeRequest(command.parent.parent, '/payout', {
149
- queryParams
150
- });
151
-
152
- displayResponse(command.parent.parent, data, (response) => {
153
- const payouts = response.data || [];
154
-
155
- if (payouts.length === 0) {
156
- console.log(chalk.yellow('\nNo payouts found'));
157
- return;
158
- }
159
-
160
- console.log(chalk.cyan(`\nPayouts (${payouts.length}):`));
161
-
162
- const table = new Table({
163
- head: ['ID', 'Status', 'Amount', 'Currency', 'Created'],
164
- colWidths: [20, 15, 15, 10, 25]
165
- });
166
-
167
- payouts.forEach(payout => {
168
- table.push([
169
- payout.id?.toString().substring(0, 18) || 'N/A',
170
- payout.status || 'N/A',
171
- payout.amount || 'N/A',
172
- payout.currency || 'N/A',
173
- new Date(payout.created_at).toLocaleString()
174
- ]);
175
- });
176
-
177
- console.log(table.toString());
178
- });
179
- } catch (error) {
180
- handleApiError(error);
181
- }
182
- });
183
-
184
- module.exports = command;
@@ -1,28 +0,0 @@
1
- /**
2
- * Status command
3
- *
4
- * Check API status and availability.
5
- */
6
-
7
- const { Command } = require('commander');
8
- const chalk = require('chalk');
9
- const { makeRequest, handleApiError, displayResponse } = require('../lib/api');
10
-
11
- const command = new Command('status');
12
-
13
- command
14
- .description('Check NOWPayments API status')
15
- .summary('Verify API connectivity and status')
16
- .action(async () => {
17
- try {
18
- const data = await makeRequest(command.parent, '/status');
19
-
20
- displayResponse(command.parent, data, (response) => {
21
- console.log(chalk.green('✓ NOWPayments API is'), chalk.bold(response.message || 'OK'));
22
- });
23
- } catch (error) {
24
- handleApiError(error);
25
- }
26
- });
27
-
28
- module.exports = command;
package/src/lib/api.js DELETED
@@ -1,133 +0,0 @@
1
- /**
2
- * API client for NOWPayments
3
- *
4
- * Handles all HTTP requests to the NOWPayments API with proper error handling,
5
- * authentication, and response formatting.
6
- */
7
-
8
- const fetch = require('node-fetch');
9
- const chalk = require('chalk');
10
- const { getBaseUrl } = require('./config');
11
- const { getAuthHeaders } = require('./auth');
12
-
13
- /**
14
- * Make an API request to NOWPayments
15
- * @param {Object} program - Commander program instance
16
- * @param {string} endpoint - API endpoint (e.g., '/status')
17
- * @param {Object} options - Request options
18
- * @param {string} options.method - HTTP method (GET, POST, etc.)
19
- * @param {Object} options.body - Request body for POST/PUT requests
20
- * @param {Object} options.queryParams - URL query parameters
21
- * @returns {Promise<Object>} API response data
22
- */
23
- async function makeRequest(program, endpoint, options = {}) {
24
- const { method = 'GET', body = null, queryParams = {} } = options;
25
-
26
- // Build URL
27
- const baseUrl = getBaseUrl(program._sandbox);
28
- const url = new URL(`${baseUrl}${endpoint}`);
29
-
30
- // Add query parameters
31
- Object.keys(queryParams).forEach(key => {
32
- if (queryParams[key] !== undefined && queryParams[key] !== null) {
33
- url.searchParams.append(key, queryParams[key]);
34
- }
35
- });
36
-
37
- // Build request options
38
- const requestOptions = {
39
- method,
40
- headers: getAuthHeaders(program)
41
- };
42
-
43
- // Add body for POST/PUT requests
44
- if (body && (method === 'POST' || method === 'PUT' || method === 'PATCH')) {
45
- requestOptions.body = JSON.stringify(body);
46
- }
47
-
48
- if (program._debug) {
49
- console.log(chalk.gray(`[DEBUG] ${method} ${url.toString()}`));
50
- if (body) {
51
- console.log(chalk.gray(`[DEBUG] Body: ${JSON.stringify(body, null, 2)}`));
52
- }
53
- }
54
-
55
- try {
56
- const response = await fetch(url.toString(), requestOptions);
57
- const data = await response.json();
58
-
59
- if (program._debug) {
60
- console.log(chalk.gray(`[DEBUG] Status: ${response.status}`));
61
- console.log(chalk.gray(`[DEBUG] Response: ${JSON.stringify(data, null, 2)}`));
62
- }
63
-
64
- // Handle error responses
65
- if (!response.ok) {
66
- const error = new Error(data.message || `API request failed with status ${response.status}`);
67
- error.statusCode = response.status;
68
- error.data = data;
69
- throw error;
70
- }
71
-
72
- return data;
73
- } catch (error) {
74
- if (error.statusCode) {
75
- // API error
76
- throw error;
77
- } else if (error.code === 'ENOTFOUND' || error.code === 'ECONNREFUSED') {
78
- // Network error
79
- const networkError = new Error('Network error: Unable to reach NOWPayments API');
80
- networkError.originalError = error;
81
- throw networkError;
82
- } else {
83
- // Other error (parsing, etc.)
84
- throw error;
85
- }
86
- }
87
- }
88
-
89
- /**
90
- * Handle and format API errors for display
91
- * @param {Error} error - Error object
92
- */
93
- function handleApiError(error) {
94
- if (error.statusCode) {
95
- console.error(chalk.red(`\nAPI Error (${error.statusCode}):`));
96
- console.error(chalk.yellow(error.message));
97
-
98
- if (error.data && error.data.errors) {
99
- console.error(chalk.yellow('\nDetails:'));
100
- console.error(JSON.stringify(error.data.errors, null, 2));
101
- }
102
- } else if (error.originalError) {
103
- console.error(chalk.red('\nNetwork Error:'));
104
- console.error(chalk.yellow(error.message));
105
- } else {
106
- console.error(chalk.red('\nUnexpected Error:'));
107
- console.error(chalk.yellow(error.message));
108
- }
109
-
110
- process.exit(1);
111
- }
112
-
113
- /**
114
- * Format and display API response
115
- * @param {Object} program - Commander program instance
116
- * @param {Object} data - Response data
117
- * @param {Function} formatter - Optional custom formatter function
118
- */
119
- function displayResponse(program, data, formatter = null) {
120
- if (program._json) {
121
- console.log(JSON.stringify(data, null, 2));
122
- } else if (formatter) {
123
- formatter(data);
124
- } else {
125
- console.log(JSON.stringify(data, null, 2));
126
- }
127
- }
128
-
129
- module.exports = {
130
- makeRequest,
131
- handleApiError,
132
- displayResponse
133
- };
package/src/lib/auth.js DELETED
@@ -1,70 +0,0 @@
1
- /**
2
- * Authentication utilities for NOWPayments CLI
3
- *
4
- * Handles API key validation and authentication headers.
5
- */
6
-
7
- const chalk = require('chalk');
8
- const { getApiKey } = require('./config');
9
-
10
- /**
11
- * Validate that an API key is available
12
- * @param {Object} program - Commander program instance
13
- * @throws {Error} If no API key is found
14
- */
15
- function requireApiKey(program) {
16
- const apiKey = getApiKey(program);
17
-
18
- if (!apiKey) {
19
- console.error(chalk.red('Error: No API key found'));
20
- console.error(chalk.yellow('\nPlease set your API key using one of these methods:'));
21
- console.error(' 1. Environment variable: export NOWPAYMENTS_API_KEY=your_key');
22
- console.error(' 2. .env file: NOWPAYMENTS_API_KEY=your_key');
23
- console.error(' 3. Command flag: --api-key your_key');
24
- console.error(' 4. Save to config: nowpayments auth set your_key');
25
- console.error(chalk.cyan('\nGet your API key at: https://nowpayments.io'));
26
- process.exit(1);
27
- }
28
-
29
- return apiKey;
30
- }
31
-
32
- /**
33
- * Get authentication headers for API requests
34
- * @param {Object} program - Commander program instance
35
- * @returns {Object} Headers object with authentication
36
- */
37
- function getAuthHeaders(program) {
38
- const apiKey = requireApiKey(program);
39
-
40
- return {
41
- 'x-api-key': apiKey,
42
- 'Content-Type': 'application/json'
43
- };
44
- }
45
-
46
- /**
47
- * Validate API key format (basic check)
48
- * @param {string} apiKey - API key to validate
49
- * @returns {boolean} Whether the key appears valid
50
- */
51
- function validateApiKeyFormat(apiKey) {
52
- // Basic validation - NOWPayments API keys are typically alphanumeric
53
- if (!apiKey || typeof apiKey !== 'string') {
54
- return false;
55
- }
56
-
57
- // Check length (typical API keys are 32-64 characters)
58
- if (apiKey.length < 20 || apiKey.length > 100) {
59
- return false;
60
- }
61
-
62
- // Check for valid characters (alphanumeric and common symbols)
63
- return /^[a-zA-Z0-9_-]+$/.test(apiKey);
64
- }
65
-
66
- module.exports = {
67
- requireApiKey,
68
- getAuthHeaders,
69
- validateApiKeyFormat
70
- };
package/src/lib/config.js DELETED
@@ -1,110 +0,0 @@
1
- /**
2
- * Configuration management for NOWPayments CLI
3
- *
4
- * Handles API keys, environment selection, and persistent configuration.
5
- */
6
-
7
- const fs = require('fs');
8
- const path = require('path');
9
- const os = require('os');
10
-
11
- const CONFIG_DIR = path.join(os.homedir(), '.nowpayments');
12
- const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
13
-
14
- /**
15
- * Default configuration
16
- */
17
- const DEFAULT_CONFIG = {
18
- apiKey: null,
19
- sandbox: false,
20
- defaultCurrency: 'USD',
21
- defaultPayCurrency: 'BTC'
22
- };
23
-
24
- /**
25
- * Ensure config directory exists
26
- */
27
- function ensureConfigDir() {
28
- if (!fs.existsSync(CONFIG_DIR)) {
29
- fs.mkdirSync(CONFIG_DIR, { recursive: true });
30
- }
31
- }
32
-
33
- /**
34
- * Load configuration from file
35
- * @returns {Object} Configuration object
36
- */
37
- function loadConfig() {
38
- try {
39
- ensureConfigDir();
40
- if (fs.existsSync(CONFIG_FILE)) {
41
- const data = fs.readFileSync(CONFIG_FILE, 'utf8');
42
- return { ...DEFAULT_CONFIG, ...JSON.parse(data) };
43
- }
44
- } catch (error) {
45
- // Return defaults if config file doesn't exist or is invalid
46
- }
47
- return { ...DEFAULT_CONFIG };
48
- }
49
-
50
- /**
51
- * Save configuration to file
52
- * @param {Object} config - Configuration to save
53
- */
54
- function saveConfig(config) {
55
- ensureConfigDir();
56
- fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf8');
57
- }
58
-
59
- /**
60
- * Get a configuration value
61
- * @param {string} key - Configuration key
62
- * @returns {*} Configuration value
63
- */
64
- function getConfig(key) {
65
- const config = loadConfig();
66
- return config[key];
67
- }
68
-
69
- /**
70
- * Set a configuration value
71
- * @param {string} key - Configuration key
72
- * @param {*} value - Configuration value
73
- */
74
- function setConfig(key, value) {
75
- const config = loadConfig();
76
- config[key] = value;
77
- saveConfig(config);
78
- }
79
-
80
- /**
81
- * Get API key from config, environment, or command option
82
- * @param {Object} program - Commander program instance
83
- * @returns {string|null} API key
84
- */
85
- function getApiKey(program) {
86
- // Priority: command option > environment > config file
87
- return program._apiKey || process.env.NOWPAYMENTS_API_KEY || getConfig('apiKey');
88
- }
89
-
90
- /**
91
- * Get base URL based on environment
92
- * @param {boolean} sandbox - Whether to use sandbox environment
93
- * @returns {string} Base URL
94
- */
95
- function getBaseUrl(sandbox = false) {
96
- return sandbox
97
- ? 'https://api-sandbox.nowpayments.io/v1'
98
- : 'https://api.nowpayments.io/v1';
99
- }
100
-
101
- module.exports = {
102
- CONFIG_DIR,
103
- CONFIG_FILE,
104
- loadConfig,
105
- saveConfig,
106
- getConfig,
107
- setConfig,
108
- getApiKey,
109
- getBaseUrl
110
- };