api-response-manager 1.0.0
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/README.md +356 -0
- package/bin/arm.js +180 -0
- package/commands/config.js +76 -0
- package/commands/login.js +88 -0
- package/commands/logout.js +21 -0
- package/commands/logs.js +24 -0
- package/commands/project.js +206 -0
- package/commands/tunnel.js +230 -0
- package/commands/webhook.js +223 -0
- package/package.json +50 -0
- package/utils/api.js +145 -0
- package/utils/config.js +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
# ARM CLI - API Response Manager Command Line Interface
|
|
2
|
+
|
|
3
|
+
Command-line interface for API Response Manager. Manage tunnels, webhooks, and projects from your terminal.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
### Option 1: Install from npm (Recommended)
|
|
8
|
+
```bash
|
|
9
|
+
npm install -g @arm/cli
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
After installation, verify:
|
|
13
|
+
```bash
|
|
14
|
+
arm --version
|
|
15
|
+
arm --help
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Option 2: Install from Source
|
|
19
|
+
```bash
|
|
20
|
+
# Clone the repository
|
|
21
|
+
git clone https://github.com/vijaypurohit322/api-response-manager.git
|
|
22
|
+
cd api-response-manager/cli
|
|
23
|
+
|
|
24
|
+
# Install dependencies
|
|
25
|
+
npm install
|
|
26
|
+
|
|
27
|
+
# Link globally
|
|
28
|
+
npm link
|
|
29
|
+
|
|
30
|
+
# Verify installation
|
|
31
|
+
arm --version
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Option 3: Use with npx (No Installation)
|
|
35
|
+
```bash
|
|
36
|
+
npx @arm/cli login
|
|
37
|
+
npx @arm/cli tunnel 3000
|
|
38
|
+
npx @arm/cli webhook
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Quick Start
|
|
42
|
+
|
|
43
|
+
### 1. Login
|
|
44
|
+
```bash
|
|
45
|
+
arm login
|
|
46
|
+
# Or provide credentials directly
|
|
47
|
+
arm login -e your@email.com -p yourpassword
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 2. Start a Tunnel
|
|
51
|
+
```bash
|
|
52
|
+
# Expose local port 3000
|
|
53
|
+
arm tunnel 3000
|
|
54
|
+
|
|
55
|
+
# With custom subdomain
|
|
56
|
+
arm tunnel 3000 --subdomain myapi
|
|
57
|
+
|
|
58
|
+
# With authentication
|
|
59
|
+
arm tunnel 3000 --auth --rate-limit 100
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 3. Create a Webhook
|
|
63
|
+
```bash
|
|
64
|
+
# Basic webhook
|
|
65
|
+
arm webhook
|
|
66
|
+
|
|
67
|
+
# With forwarding to URL
|
|
68
|
+
arm webhook --forward http://localhost:4000/webhook
|
|
69
|
+
|
|
70
|
+
# With forwarding to tunnel
|
|
71
|
+
arm webhook --tunnel <tunnel-id>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Commands
|
|
75
|
+
|
|
76
|
+
### Authentication
|
|
77
|
+
|
|
78
|
+
#### `arm login`
|
|
79
|
+
Authenticate with API Response Manager
|
|
80
|
+
```bash
|
|
81
|
+
arm login
|
|
82
|
+
arm login -e email@example.com -p password
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
#### `arm logout`
|
|
86
|
+
Logout from API Response Manager
|
|
87
|
+
```bash
|
|
88
|
+
arm logout
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Tunnels
|
|
92
|
+
|
|
93
|
+
#### `arm tunnel <port>`
|
|
94
|
+
Start a tunnel to expose local server
|
|
95
|
+
```bash
|
|
96
|
+
arm tunnel 3000
|
|
97
|
+
arm tunnel 3000 --subdomain myapi --name "My API"
|
|
98
|
+
arm tunnel 3000 --auth --rate-limit 100
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Options:
|
|
102
|
+
- `-s, --subdomain <subdomain>` - Custom subdomain
|
|
103
|
+
- `-n, --name <name>` - Tunnel name
|
|
104
|
+
- `-a, --auth` - Enable basic authentication
|
|
105
|
+
- `-r, --rate-limit <limit>` - Rate limit (requests per minute, default: 60)
|
|
106
|
+
|
|
107
|
+
#### `arm tunnel:list`
|
|
108
|
+
List all active tunnels
|
|
109
|
+
```bash
|
|
110
|
+
arm tunnel:list
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
#### `arm tunnel:stop <tunnelId>`
|
|
114
|
+
Stop a tunnel
|
|
115
|
+
```bash
|
|
116
|
+
arm tunnel:stop 507f1f77bcf86cd799439011
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### `arm tunnel:logs <tunnelId>`
|
|
120
|
+
View tunnel request logs
|
|
121
|
+
```bash
|
|
122
|
+
arm tunnel:logs 507f1f77bcf86cd799439011
|
|
123
|
+
arm tunnel:logs 507f1f77bcf86cd799439011 --follow
|
|
124
|
+
arm tunnel:logs 507f1f77bcf86cd799439011 --lines 100
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Options:
|
|
128
|
+
- `-f, --follow` - Follow log output (real-time)
|
|
129
|
+
- `-n, --lines <number>` - Number of lines to show (default: 50)
|
|
130
|
+
|
|
131
|
+
### Webhooks
|
|
132
|
+
|
|
133
|
+
#### `arm webhook`
|
|
134
|
+
Create a new webhook
|
|
135
|
+
```bash
|
|
136
|
+
arm webhook
|
|
137
|
+
arm webhook --name "GitHub Webhook"
|
|
138
|
+
arm webhook --forward http://localhost:4000/webhook
|
|
139
|
+
arm webhook --tunnel 507f1f77bcf86cd799439011
|
|
140
|
+
arm webhook --expires 48
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Options:
|
|
144
|
+
- `-n, --name <name>` - Webhook name
|
|
145
|
+
- `-f, --forward <url>` - Forward URL
|
|
146
|
+
- `-t, --tunnel <tunnelId>` - Forward to tunnel
|
|
147
|
+
- `-e, --expires <hours>` - Expiration time in hours (default: 24)
|
|
148
|
+
|
|
149
|
+
#### `arm webhook:list`
|
|
150
|
+
List all webhooks
|
|
151
|
+
```bash
|
|
152
|
+
arm webhook:list
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
#### `arm webhook:delete <webhookId>`
|
|
156
|
+
Delete a webhook
|
|
157
|
+
```bash
|
|
158
|
+
arm webhook:delete a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
#### `arm webhook:logs <webhookId>`
|
|
162
|
+
View webhook request logs
|
|
163
|
+
```bash
|
|
164
|
+
arm webhook:logs a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
|
|
165
|
+
arm webhook:logs a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6 --follow
|
|
166
|
+
arm webhook:logs a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6 --lines 100
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Options:
|
|
170
|
+
- `-f, --follow` - Follow log output (real-time)
|
|
171
|
+
- `-n, --lines <number>` - Number of lines to show (default: 50)
|
|
172
|
+
|
|
173
|
+
#### `arm webhook:replay <webhookId> <requestId>`
|
|
174
|
+
Replay a webhook request
|
|
175
|
+
```bash
|
|
176
|
+
arm webhook:replay a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6 507f1f77bcf86cd799439011
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Projects
|
|
180
|
+
|
|
181
|
+
#### `arm projects`
|
|
182
|
+
List all projects
|
|
183
|
+
```bash
|
|
184
|
+
arm projects
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
#### `arm project:create <name>`
|
|
188
|
+
Create a new project
|
|
189
|
+
```bash
|
|
190
|
+
arm project:create "My API Project"
|
|
191
|
+
arm project:create "My API Project" --description "Testing API endpoints"
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Options:
|
|
195
|
+
- `-d, --description <description>` - Project description
|
|
196
|
+
|
|
197
|
+
#### `arm project:share <projectId>`
|
|
198
|
+
Get shareable link for a project
|
|
199
|
+
```bash
|
|
200
|
+
arm project:share 507f1f77bcf86cd799439011
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
#### `arm project:responses <projectId>`
|
|
204
|
+
View project API responses
|
|
205
|
+
```bash
|
|
206
|
+
arm project:responses 507f1f77bcf86cd799439011
|
|
207
|
+
arm project:responses 507f1f77bcf86cd799439011 --limit 20
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Options:
|
|
211
|
+
- `-n, --limit <number>` - Number of responses to show (default: 10)
|
|
212
|
+
|
|
213
|
+
### Logs
|
|
214
|
+
|
|
215
|
+
#### `arm logs <id>`
|
|
216
|
+
View logs for tunnels or webhooks (auto-detects type)
|
|
217
|
+
```bash
|
|
218
|
+
arm logs 507f1f77bcf86cd799439011
|
|
219
|
+
arm logs a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6 --follow
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Options:
|
|
223
|
+
- `-f, --follow` - Follow log output (real-time)
|
|
224
|
+
- `-n, --lines <number>` - Number of lines to show (default: 50)
|
|
225
|
+
|
|
226
|
+
### Configuration
|
|
227
|
+
|
|
228
|
+
#### `arm config:set <key> <value>`
|
|
229
|
+
Set configuration value
|
|
230
|
+
```bash
|
|
231
|
+
arm config:set apiUrl http://localhost:5000/api
|
|
232
|
+
arm config:set defaultTunnelPort 8080
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
#### `arm config:get [key]`
|
|
236
|
+
Get configuration value (omit key to show all)
|
|
237
|
+
```bash
|
|
238
|
+
arm config:get apiUrl
|
|
239
|
+
arm config:get
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
#### `arm config:delete <key>`
|
|
243
|
+
Delete configuration value
|
|
244
|
+
```bash
|
|
245
|
+
arm config:delete apiUrl
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Configuration
|
|
249
|
+
|
|
250
|
+
Configuration is stored in `~/.config/arm-cli/config.json`
|
|
251
|
+
|
|
252
|
+
Default configuration:
|
|
253
|
+
```json
|
|
254
|
+
{
|
|
255
|
+
"apiUrl": "http://localhost:5000/api",
|
|
256
|
+
"token": null,
|
|
257
|
+
"userId": null,
|
|
258
|
+
"email": null,
|
|
259
|
+
"defaultTunnelPort": 3000,
|
|
260
|
+
"defaultWebhookExpiry": 86400
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Examples
|
|
265
|
+
|
|
266
|
+
### Expose Local Development Server
|
|
267
|
+
```bash
|
|
268
|
+
# Login
|
|
269
|
+
arm login
|
|
270
|
+
|
|
271
|
+
# Start tunnel on port 3000
|
|
272
|
+
arm tunnel 3000 --subdomain myapp
|
|
273
|
+
|
|
274
|
+
# Your local server is now accessible at:
|
|
275
|
+
# https://myapp.tunnel.arm.dev
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Test Webhooks Locally
|
|
279
|
+
```bash
|
|
280
|
+
# Create webhook that forwards to local server
|
|
281
|
+
arm webhook --forward http://localhost:4000/webhook --name "Test Webhook"
|
|
282
|
+
|
|
283
|
+
# Send test request
|
|
284
|
+
curl -X POST <webhook-url> -d '{"test": "data"}'
|
|
285
|
+
|
|
286
|
+
# View logs
|
|
287
|
+
arm webhook:logs <webhook-id>
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### CI/CD Integration
|
|
291
|
+
```bash
|
|
292
|
+
# In your CI/CD pipeline
|
|
293
|
+
export ARM_TOKEN="your-auth-token"
|
|
294
|
+
|
|
295
|
+
# Start tunnel for testing
|
|
296
|
+
arm tunnel 3000 --subdomain ci-test-${CI_BUILD_ID}
|
|
297
|
+
|
|
298
|
+
# Run your tests against the public URL
|
|
299
|
+
npm test
|
|
300
|
+
|
|
301
|
+
# Stop tunnel
|
|
302
|
+
arm tunnel:stop <tunnel-id>
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
## Troubleshooting
|
|
306
|
+
|
|
307
|
+
### Authentication Issues
|
|
308
|
+
```bash
|
|
309
|
+
# Check if logged in
|
|
310
|
+
arm config:get email
|
|
311
|
+
|
|
312
|
+
# Re-login
|
|
313
|
+
arm logout
|
|
314
|
+
arm login
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Connection Issues
|
|
318
|
+
```bash
|
|
319
|
+
# Check API URL
|
|
320
|
+
arm config:get apiUrl
|
|
321
|
+
|
|
322
|
+
# Update API URL
|
|
323
|
+
arm config:set apiUrl https://your-api-url.com/api
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### View All Configuration
|
|
327
|
+
```bash
|
|
328
|
+
arm config:get
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
## Publishing to npm
|
|
332
|
+
|
|
333
|
+
See [PUBLISHING.md](./PUBLISHING.md) for detailed instructions on publishing this package to npm.
|
|
334
|
+
|
|
335
|
+
### Quick Publish
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
# Login to npm
|
|
339
|
+
npm login
|
|
340
|
+
|
|
341
|
+
# Update version
|
|
342
|
+
npm version patch # or minor/major
|
|
343
|
+
|
|
344
|
+
# Publish
|
|
345
|
+
npm publish --access public
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
## Support
|
|
349
|
+
|
|
350
|
+
- GitHub: https://github.com/vijaypurohit322/api-response-manager
|
|
351
|
+
- Issues: https://github.com/vijaypurohit322/api-response-manager/issues
|
|
352
|
+
- Email: vijaypurohit322@gmail.com
|
|
353
|
+
|
|
354
|
+
## License
|
|
355
|
+
|
|
356
|
+
MIT License - see LICENSE file for details
|
package/bin/arm.js
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { program } = require('commander');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const pkg = require('../package.json');
|
|
6
|
+
|
|
7
|
+
// Check for updates (optional feature, can be added later with dynamic import)
|
|
8
|
+
// const updateNotifier = require('update-notifier');
|
|
9
|
+
// const notifier = updateNotifier({ pkg });
|
|
10
|
+
// notifier.notify();
|
|
11
|
+
|
|
12
|
+
// Import commands
|
|
13
|
+
const loginCommand = require('../commands/login');
|
|
14
|
+
const logoutCommand = require('../commands/logout');
|
|
15
|
+
const tunnelCommand = require('../commands/tunnel');
|
|
16
|
+
const webhookCommand = require('../commands/webhook');
|
|
17
|
+
const projectCommand = require('../commands/project');
|
|
18
|
+
const logsCommand = require('../commands/logs');
|
|
19
|
+
const configCommand = require('../commands/config');
|
|
20
|
+
|
|
21
|
+
// CLI setup
|
|
22
|
+
program
|
|
23
|
+
.name('arm')
|
|
24
|
+
.description('API Response Manager CLI - Tunneling, Webhooks, and API Testing')
|
|
25
|
+
.version(pkg.version);
|
|
26
|
+
|
|
27
|
+
// Login command
|
|
28
|
+
program
|
|
29
|
+
.command('login')
|
|
30
|
+
.description('Authenticate with API Response Manager')
|
|
31
|
+
.option('-e, --email <email>', 'Email address')
|
|
32
|
+
.option('-p, --password <password>', 'Password')
|
|
33
|
+
.action(loginCommand);
|
|
34
|
+
|
|
35
|
+
// Logout command
|
|
36
|
+
program
|
|
37
|
+
.command('logout')
|
|
38
|
+
.description('Logout from API Response Manager')
|
|
39
|
+
.action(logoutCommand);
|
|
40
|
+
|
|
41
|
+
// Tunnel commands
|
|
42
|
+
program
|
|
43
|
+
.command('tunnel')
|
|
44
|
+
.description('Manage tunnels')
|
|
45
|
+
.argument('[port]', 'Local port to expose')
|
|
46
|
+
.option('-s, --subdomain <subdomain>', 'Custom subdomain')
|
|
47
|
+
.option('-n, --name <name>', 'Tunnel name')
|
|
48
|
+
.option('-a, --auth', 'Enable basic authentication')
|
|
49
|
+
.option('-r, --rate-limit <limit>', 'Rate limit (requests per minute)', '60')
|
|
50
|
+
.action(tunnelCommand.start);
|
|
51
|
+
|
|
52
|
+
program
|
|
53
|
+
.command('tunnel:list')
|
|
54
|
+
.description('List all active tunnels')
|
|
55
|
+
.action(tunnelCommand.list);
|
|
56
|
+
|
|
57
|
+
program
|
|
58
|
+
.command('tunnel:stop')
|
|
59
|
+
.description('Stop a tunnel')
|
|
60
|
+
.argument('<tunnelId>', 'Tunnel ID to stop')
|
|
61
|
+
.action(tunnelCommand.stop);
|
|
62
|
+
|
|
63
|
+
program
|
|
64
|
+
.command('tunnel:logs')
|
|
65
|
+
.description('View tunnel request logs')
|
|
66
|
+
.argument('<tunnelId>', 'Tunnel ID')
|
|
67
|
+
.option('-f, --follow', 'Follow log output')
|
|
68
|
+
.option('-n, --lines <number>', 'Number of lines to show', '50')
|
|
69
|
+
.action(tunnelCommand.logs);
|
|
70
|
+
|
|
71
|
+
// Webhook commands
|
|
72
|
+
program
|
|
73
|
+
.command('webhook')
|
|
74
|
+
.description('Create a new webhook')
|
|
75
|
+
.option('-n, --name <name>', 'Webhook name')
|
|
76
|
+
.option('-f, --forward <url>', 'Forward URL')
|
|
77
|
+
.option('-t, --tunnel <tunnelId>', 'Forward to tunnel')
|
|
78
|
+
.option('-e, --expires <hours>', 'Expiration time in hours', '24')
|
|
79
|
+
.action(webhookCommand.create);
|
|
80
|
+
|
|
81
|
+
program
|
|
82
|
+
.command('webhook:list')
|
|
83
|
+
.description('List all webhooks')
|
|
84
|
+
.action(webhookCommand.list);
|
|
85
|
+
|
|
86
|
+
program
|
|
87
|
+
.command('webhook:id')
|
|
88
|
+
.description('Get webhook ID by name')
|
|
89
|
+
.argument('<name>', 'Webhook name')
|
|
90
|
+
.action(webhookCommand.getIdByName);
|
|
91
|
+
|
|
92
|
+
program
|
|
93
|
+
.command('webhook:delete')
|
|
94
|
+
.description('Delete a webhook')
|
|
95
|
+
.argument('<webhookId>', 'Webhook ID to delete')
|
|
96
|
+
.action(webhookCommand.delete);
|
|
97
|
+
|
|
98
|
+
program
|
|
99
|
+
.command('webhook:logs')
|
|
100
|
+
.description('View webhook request logs')
|
|
101
|
+
.argument('<webhookId>', 'Webhook ID')
|
|
102
|
+
.option('-f, --follow', 'Follow log output')
|
|
103
|
+
.option('-n, --lines <number>', 'Number of lines to show', '50')
|
|
104
|
+
.action(webhookCommand.logs);
|
|
105
|
+
|
|
106
|
+
program
|
|
107
|
+
.command('webhook:replay')
|
|
108
|
+
.description('Replay a webhook request')
|
|
109
|
+
.argument('<webhookId>', 'Webhook ID')
|
|
110
|
+
.argument('<requestId>', 'Request ID to replay')
|
|
111
|
+
.action(webhookCommand.replay);
|
|
112
|
+
|
|
113
|
+
// Project commands
|
|
114
|
+
program
|
|
115
|
+
.command('projects')
|
|
116
|
+
.description('List all projects')
|
|
117
|
+
.action(projectCommand.list);
|
|
118
|
+
|
|
119
|
+
program
|
|
120
|
+
.command('project:create')
|
|
121
|
+
.description('Create a new project')
|
|
122
|
+
.argument('<name>', 'Project name')
|
|
123
|
+
.option('-d, --description <description>', 'Project description')
|
|
124
|
+
.action(projectCommand.create);
|
|
125
|
+
|
|
126
|
+
program
|
|
127
|
+
.command('project:id')
|
|
128
|
+
.description('Get project ID by name')
|
|
129
|
+
.argument('<name>', 'Project name')
|
|
130
|
+
.action(projectCommand.getIdByName);
|
|
131
|
+
|
|
132
|
+
program
|
|
133
|
+
.command('project:share')
|
|
134
|
+
.description('Get shareable link for a project')
|
|
135
|
+
.argument('<projectId>', 'Project ID')
|
|
136
|
+
.action(projectCommand.share);
|
|
137
|
+
|
|
138
|
+
program
|
|
139
|
+
.command('project:responses')
|
|
140
|
+
.description('View project API responses')
|
|
141
|
+
.argument('<projectId>', 'Project ID')
|
|
142
|
+
.option('-n, --limit <number>', 'Number of responses to show', '10')
|
|
143
|
+
.action(projectCommand.responses);
|
|
144
|
+
|
|
145
|
+
// Logs command
|
|
146
|
+
program
|
|
147
|
+
.command('logs')
|
|
148
|
+
.description('View logs for tunnels or webhooks')
|
|
149
|
+
.argument('<id>', 'Tunnel or Webhook ID')
|
|
150
|
+
.option('-f, --follow', 'Follow log output')
|
|
151
|
+
.option('-n, --lines <number>', 'Number of lines to show', '50')
|
|
152
|
+
.action(logsCommand);
|
|
153
|
+
|
|
154
|
+
// Config commands
|
|
155
|
+
program
|
|
156
|
+
.command('config:set')
|
|
157
|
+
.description('Set configuration value')
|
|
158
|
+
.argument('<key>', 'Configuration key')
|
|
159
|
+
.argument('<value>', 'Configuration value')
|
|
160
|
+
.action(configCommand.set);
|
|
161
|
+
|
|
162
|
+
program
|
|
163
|
+
.command('config:get')
|
|
164
|
+
.description('Get configuration value')
|
|
165
|
+
.argument('[key]', 'Configuration key (omit to show all)')
|
|
166
|
+
.action(configCommand.get);
|
|
167
|
+
|
|
168
|
+
program
|
|
169
|
+
.command('config:delete')
|
|
170
|
+
.description('Delete configuration value')
|
|
171
|
+
.argument('<key>', 'Configuration key')
|
|
172
|
+
.action(configCommand.delete);
|
|
173
|
+
|
|
174
|
+
// Parse arguments
|
|
175
|
+
program.parse(process.argv);
|
|
176
|
+
|
|
177
|
+
// Show help if no command provided
|
|
178
|
+
if (!process.argv.slice(2).length) {
|
|
179
|
+
program.outputHelp();
|
|
180
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const config = require('../utils/config');
|
|
3
|
+
const Table = require('cli-table3');
|
|
4
|
+
|
|
5
|
+
// Set config value
|
|
6
|
+
function set(key, value) {
|
|
7
|
+
try {
|
|
8
|
+
config.set(key, value);
|
|
9
|
+
console.log(chalk.green(`\n✓ Configuration updated: ${key} = ${value}\n`));
|
|
10
|
+
} catch (error) {
|
|
11
|
+
console.error(chalk.red(`\n✗ Failed to set configuration: ${error.message}\n`));
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Get config value
|
|
17
|
+
function get(key) {
|
|
18
|
+
try {
|
|
19
|
+
if (key) {
|
|
20
|
+
const value = config.get(key);
|
|
21
|
+
if (value === undefined) {
|
|
22
|
+
console.log(chalk.yellow(`\n⚠ Configuration key '${key}' not found\n`));
|
|
23
|
+
} else {
|
|
24
|
+
console.log(chalk.white(`\n${key}: ${value}\n`));
|
|
25
|
+
}
|
|
26
|
+
} else {
|
|
27
|
+
// Show all config
|
|
28
|
+
const allConfig = config.store;
|
|
29
|
+
|
|
30
|
+
console.log(chalk.blue.bold('\n⚙️ Configuration\n'));
|
|
31
|
+
|
|
32
|
+
const table = new Table({
|
|
33
|
+
head: ['Key', 'Value'],
|
|
34
|
+
style: {
|
|
35
|
+
head: ['cyan']
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
Object.entries(allConfig).forEach(([key, value]) => {
|
|
40
|
+
// Hide sensitive values
|
|
41
|
+
const displayValue = key === 'token' && value
|
|
42
|
+
? value.substring(0, 20) + '...'
|
|
43
|
+
: String(value);
|
|
44
|
+
table.push([key, displayValue]);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
console.log(table.toString());
|
|
48
|
+
console.log(chalk.gray(`\nConfig file: ${config.path}\n`));
|
|
49
|
+
}
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.error(chalk.red(`\n✗ Failed to get configuration: ${error.message}\n`));
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Delete config value
|
|
57
|
+
function deleteConfig(key) {
|
|
58
|
+
try {
|
|
59
|
+
if (!config.has(key)) {
|
|
60
|
+
console.log(chalk.yellow(`\n⚠ Configuration key '${key}' not found\n`));
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
config.delete(key);
|
|
65
|
+
console.log(chalk.green(`\n✓ Configuration deleted: ${key}\n`));
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error(chalk.red(`\n✗ Failed to delete configuration: ${error.message}\n`));
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
module.exports = {
|
|
73
|
+
set,
|
|
74
|
+
get,
|
|
75
|
+
delete: deleteConfig
|
|
76
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
const inquirer = require('inquirer');
|
|
2
|
+
const chalk = require('chalk');
|
|
3
|
+
const ora = require('ora');
|
|
4
|
+
const api = require('../utils/api');
|
|
5
|
+
const config = require('../utils/config');
|
|
6
|
+
|
|
7
|
+
async function login(options) {
|
|
8
|
+
console.log(chalk.blue.bold('\n🔐 API Response Manager - Login\n'));
|
|
9
|
+
|
|
10
|
+
let email = options.email;
|
|
11
|
+
let password = options.password;
|
|
12
|
+
|
|
13
|
+
// Prompt for credentials if not provided
|
|
14
|
+
if (!email || !password) {
|
|
15
|
+
const answers = await inquirer.prompt([
|
|
16
|
+
{
|
|
17
|
+
type: 'input',
|
|
18
|
+
name: 'email',
|
|
19
|
+
message: 'Email:',
|
|
20
|
+
when: !email,
|
|
21
|
+
validate: (input) => {
|
|
22
|
+
if (!input) return 'Email is required';
|
|
23
|
+
if (!/\S+@\S+\.\S+/.test(input)) return 'Invalid email format';
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
type: 'password',
|
|
29
|
+
name: 'password',
|
|
30
|
+
message: 'Password:',
|
|
31
|
+
when: !password,
|
|
32
|
+
mask: '*',
|
|
33
|
+
validate: (input) => {
|
|
34
|
+
if (!input) return 'Password is required';
|
|
35
|
+
if (input.length < 6) return 'Password must be at least 6 characters';
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
email = email || answers.email;
|
|
42
|
+
password = password || answers.password;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const spinner = ora('Authenticating...').start();
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const response = await api.login(email, password);
|
|
49
|
+
|
|
50
|
+
if (!response.token) {
|
|
51
|
+
throw new Error('No token received from server');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Store credentials
|
|
55
|
+
api.setToken(response.token);
|
|
56
|
+
|
|
57
|
+
const userId = response.user?._id || response.user?.id;
|
|
58
|
+
const userEmail = response.user?.email || email;
|
|
59
|
+
|
|
60
|
+
if (userId) {
|
|
61
|
+
config.set('userId', userId);
|
|
62
|
+
}
|
|
63
|
+
if (userEmail) {
|
|
64
|
+
config.set('email', userEmail);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
spinner.succeed(chalk.green('Login successful!'));
|
|
68
|
+
|
|
69
|
+
console.log(chalk.gray('\nUser:'), chalk.white(userEmail));
|
|
70
|
+
console.log(chalk.gray('Token saved to:'), chalk.white(config.path));
|
|
71
|
+
console.log(chalk.green('\n✓ You can now use all ARM CLI commands\n'));
|
|
72
|
+
|
|
73
|
+
} catch (error) {
|
|
74
|
+
spinner.fail(chalk.red('Login failed'));
|
|
75
|
+
|
|
76
|
+
if (error.response?.status === 401) {
|
|
77
|
+
console.error(chalk.red('\n✗ Invalid email or password\n'));
|
|
78
|
+
} else if (error.response?.data?.msg) {
|
|
79
|
+
console.error(chalk.red(`\n✗ ${error.response.data.msg}\n`));
|
|
80
|
+
} else {
|
|
81
|
+
console.error(chalk.red(`\n✗ ${error.message}\n`));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
module.exports = login;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const api = require('../utils/api');
|
|
3
|
+
const config = require('../utils/config');
|
|
4
|
+
|
|
5
|
+
async function logout() {
|
|
6
|
+
const email = config.get('email');
|
|
7
|
+
|
|
8
|
+
if (!email) {
|
|
9
|
+
console.log(chalk.yellow('\n⚠ You are not logged in\n'));
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Clear stored credentials
|
|
14
|
+
api.clearToken();
|
|
15
|
+
config.delete('userId');
|
|
16
|
+
config.delete('email');
|
|
17
|
+
|
|
18
|
+
console.log(chalk.green(`\n✓ Logged out successfully (${email})\n`));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = logout;
|