api-response-manager 1.0.0 ā 2.3.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/CLI_UPDATES.md +196 -0
- package/README.md +248 -10
- package/bin/arm.js +59 -0
- package/commands/login.js +122 -0
- package/commands/tunnel.js +142 -1
- package/package.json +9 -8
- package/utils/api.js +45 -0
package/CLI_UPDATES.md
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# CLI Updates for Advanced Tunnel Features
|
|
2
|
+
|
|
3
|
+
## ā
Changes Made
|
|
4
|
+
|
|
5
|
+
### 1. Enhanced `tunnel` Command
|
|
6
|
+
Added new options to the main tunnel command:
|
|
7
|
+
```bash
|
|
8
|
+
arm tunnel [port] [options]
|
|
9
|
+
|
|
10
|
+
Options:
|
|
11
|
+
-s, --subdomain <subdomain> Custom subdomain
|
|
12
|
+
-n, --name <name> Tunnel name
|
|
13
|
+
-a, --auth Enable basic authentication
|
|
14
|
+
-r, --rate-limit <limit> Rate limit (requests per minute)
|
|
15
|
+
-p, --protocol <protocol> Protocol (http, https, tcp, ws, wss)
|
|
16
|
+
--ssl Enable SSL/HTTPS
|
|
17
|
+
-d, --domain <domain> Custom domain
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### 2. New Commands Added
|
|
21
|
+
|
|
22
|
+
#### Custom Domain
|
|
23
|
+
```bash
|
|
24
|
+
arm tunnel:domain <tunnelId> <domain>
|
|
25
|
+
```
|
|
26
|
+
Example:
|
|
27
|
+
```bash
|
|
28
|
+
arm tunnel:domain abc123 api.yourdomain.com
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
#### SSL Certificate Upload
|
|
32
|
+
```bash
|
|
33
|
+
arm tunnel:ssl <tunnelId> --cert <path> --key <path> [--ca <path>]
|
|
34
|
+
```
|
|
35
|
+
Example:
|
|
36
|
+
```bash
|
|
37
|
+
arm tunnel:ssl abc123 --cert cert.pem --key key.pem --ca ca.pem
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
#### OAuth Configuration
|
|
41
|
+
```bash
|
|
42
|
+
arm tunnel:auth:oauth <tunnelId> [options]
|
|
43
|
+
|
|
44
|
+
Options:
|
|
45
|
+
--provider <provider> OAuth provider (google, github, microsoft, custom)
|
|
46
|
+
--client-id <id> OAuth client ID
|
|
47
|
+
--client-secret <secret> OAuth client secret
|
|
48
|
+
--callback-url <url> OAuth callback URL
|
|
49
|
+
--scope <scope> OAuth scope (comma-separated)
|
|
50
|
+
```
|
|
51
|
+
Example:
|
|
52
|
+
```bash
|
|
53
|
+
arm tunnel:auth:oauth abc123 \
|
|
54
|
+
--provider google \
|
|
55
|
+
--client-id YOUR_CLIENT_ID \
|
|
56
|
+
--client-secret YOUR_SECRET \
|
|
57
|
+
--callback-url https://yourtunnel.arm.dev/auth/callback \
|
|
58
|
+
--scope openid,email,profile
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
#### OIDC Configuration
|
|
62
|
+
```bash
|
|
63
|
+
arm tunnel:auth:oidc <tunnelId> [options]
|
|
64
|
+
|
|
65
|
+
Options:
|
|
66
|
+
--issuer <url> OIDC issuer URL
|
|
67
|
+
--client-id <id> OIDC client ID
|
|
68
|
+
--client-secret <secret> OIDC client secret
|
|
69
|
+
--callback-url <url> OIDC callback URL
|
|
70
|
+
```
|
|
71
|
+
Example:
|
|
72
|
+
```bash
|
|
73
|
+
arm tunnel:auth:oidc abc123 \
|
|
74
|
+
--issuer https://accounts.google.com \
|
|
75
|
+
--client-id YOUR_CLIENT_ID \
|
|
76
|
+
--client-secret YOUR_SECRET \
|
|
77
|
+
--callback-url https://yourtunnel.arm.dev/auth/callback
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
#### SAML Configuration
|
|
81
|
+
```bash
|
|
82
|
+
arm tunnel:auth:saml <tunnelId> [options]
|
|
83
|
+
|
|
84
|
+
Options:
|
|
85
|
+
--entry-point <url> SAML entry point URL
|
|
86
|
+
--issuer <issuer> SAML issuer
|
|
87
|
+
--cert <path> Path to IdP certificate file
|
|
88
|
+
--callback-url <url> SAML callback URL
|
|
89
|
+
```
|
|
90
|
+
Example:
|
|
91
|
+
```bash
|
|
92
|
+
arm tunnel:auth:saml abc123 \
|
|
93
|
+
--entry-point https://idp.example.com/saml/sso \
|
|
94
|
+
--issuer https://yourtunnel.arm.dev \
|
|
95
|
+
--cert idp-cert.pem \
|
|
96
|
+
--callback-url https://yourtunnel.arm.dev/auth/saml/callback
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
#### Ingress Configuration
|
|
100
|
+
```bash
|
|
101
|
+
arm tunnel:ingress <tunnelId> <rules> [--tls]
|
|
102
|
+
|
|
103
|
+
Rules format: "/path=host:port,/path2=host:port"
|
|
104
|
+
```
|
|
105
|
+
Example:
|
|
106
|
+
```bash
|
|
107
|
+
arm tunnel:ingress abc123 "/api=localhost:3000,/admin=localhost:4000" --tls
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## š Usage Examples
|
|
111
|
+
|
|
112
|
+
### Example 1: Create HTTPS Tunnel
|
|
113
|
+
```bash
|
|
114
|
+
arm tunnel 3000 --protocol https --ssl --subdomain myapi
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Example 2: Create TCP Tunnel
|
|
118
|
+
```bash
|
|
119
|
+
arm tunnel 5432 --protocol tcp --subdomain postgres
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Example 3: Create Tunnel with Custom Domain
|
|
123
|
+
```bash
|
|
124
|
+
# Create tunnel
|
|
125
|
+
arm tunnel 3000 --protocol https --ssl
|
|
126
|
+
|
|
127
|
+
# Set custom domain
|
|
128
|
+
arm tunnel:domain <tunnel-id> api.mycompany.com
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Example 4: Create Tunnel with OAuth
|
|
132
|
+
```bash
|
|
133
|
+
# Create tunnel
|
|
134
|
+
arm tunnel 3000 --protocol https --ssl --subdomain myapi
|
|
135
|
+
|
|
136
|
+
# Configure OAuth
|
|
137
|
+
arm tunnel:auth:oauth <tunnel-id> \
|
|
138
|
+
--provider google \
|
|
139
|
+
--client-id YOUR_CLIENT_ID \
|
|
140
|
+
--client-secret YOUR_SECRET \
|
|
141
|
+
--callback-url https://myapi.tunnel.arm.dev/auth/callback
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Example 5: Create Tunnel with Ingress
|
|
145
|
+
```bash
|
|
146
|
+
# Create tunnel
|
|
147
|
+
arm tunnel 3000 --protocol https --ssl
|
|
148
|
+
|
|
149
|
+
# Configure ingress rules
|
|
150
|
+
arm tunnel:ingress <tunnel-id> \
|
|
151
|
+
"/v1=localhost:3000,/v2=localhost:4000" \
|
|
152
|
+
--tls
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## š§ Updated Files
|
|
156
|
+
|
|
157
|
+
1. **cli/bin/arm.js** - Added new commands
|
|
158
|
+
2. **cli/commands/tunnel.js** - Added new functions
|
|
159
|
+
3. **cli/utils/api.js** - Added new API methods
|
|
160
|
+
|
|
161
|
+
## š¦ No New Dependencies Required
|
|
162
|
+
|
|
163
|
+
All new features use existing dependencies.
|
|
164
|
+
|
|
165
|
+
## š Testing
|
|
166
|
+
|
|
167
|
+
Test the new commands:
|
|
168
|
+
```bash
|
|
169
|
+
# Test HTTPS tunnel
|
|
170
|
+
arm tunnel 3000 --protocol https --ssl
|
|
171
|
+
|
|
172
|
+
# Test custom domain
|
|
173
|
+
arm tunnel:domain <tunnel-id> test.example.com
|
|
174
|
+
|
|
175
|
+
# Test SSL upload
|
|
176
|
+
arm tunnel:ssl <tunnel-id> --cert cert.pem --key key.pem
|
|
177
|
+
|
|
178
|
+
# Test OAuth
|
|
179
|
+
arm tunnel:auth:oauth <tunnel-id> --provider google --client-id test --client-secret test --callback-url http://localhost/callback
|
|
180
|
+
|
|
181
|
+
# Test ingress
|
|
182
|
+
arm tunnel:ingress <tunnel-id> "/api=localhost:3000" --tls
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## š Help Output
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
arm --help
|
|
189
|
+
arm tunnel --help
|
|
190
|
+
arm tunnel:domain --help
|
|
191
|
+
arm tunnel:ssl --help
|
|
192
|
+
arm tunnel:auth:oauth --help
|
|
193
|
+
arm tunnel:auth:oidc --help
|
|
194
|
+
arm tunnel:auth:saml --help
|
|
195
|
+
arm tunnel:ingress --help
|
|
196
|
+
```
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Command-line interface for API Response Manager. Manage tunnels, webhooks, and p
|
|
|
6
6
|
|
|
7
7
|
### Option 1: Install from npm (Recommended)
|
|
8
8
|
```bash
|
|
9
|
-
npm install -g @arm/cli
|
|
9
|
+
npm install -g @vijaypurohit322-arm/cli
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
After installation, verify:
|
|
@@ -33,20 +33,44 @@ arm --version
|
|
|
33
33
|
|
|
34
34
|
### Option 3: Use with npx (No Installation)
|
|
35
35
|
```bash
|
|
36
|
-
npx @arm/cli login
|
|
37
|
-
npx @arm/cli tunnel 3000
|
|
38
|
-
npx @arm/cli webhook
|
|
36
|
+
npx @vijaypurohit322-arm/cli login
|
|
37
|
+
npx @vijaypurohit322-arm/cli tunnel 3000
|
|
38
|
+
npx @vijaypurohit322-arm/cli webhook
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
## Quick Start
|
|
42
42
|
|
|
43
43
|
### 1. Login
|
|
44
|
+
|
|
45
|
+
**Interactive Login (Recommended)**
|
|
44
46
|
```bash
|
|
45
47
|
arm login
|
|
46
|
-
#
|
|
48
|
+
# Choose from: Email/Password, Google, GitHub, or Microsoft
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Email & Password**
|
|
52
|
+
```bash
|
|
47
53
|
arm login -e your@email.com -p yourpassword
|
|
48
54
|
```
|
|
49
55
|
|
|
56
|
+
**Social Login (OAuth)**
|
|
57
|
+
```bash
|
|
58
|
+
# Login with Google
|
|
59
|
+
arm login --provider google
|
|
60
|
+
|
|
61
|
+
# Login with GitHub
|
|
62
|
+
arm login --provider github
|
|
63
|
+
|
|
64
|
+
# Login with Microsoft
|
|
65
|
+
arm login --provider microsoft
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The CLI will:
|
|
69
|
+
1. Generate a unique device code
|
|
70
|
+
2. Open your browser automatically
|
|
71
|
+
3. Wait for you to authenticate
|
|
72
|
+
4. Store your credentials securely
|
|
73
|
+
|
|
50
74
|
### 2. Start a Tunnel
|
|
51
75
|
```bash
|
|
52
76
|
# Expose local port 3000
|
|
@@ -77,9 +101,59 @@ arm webhook --tunnel <tunnel-id>
|
|
|
77
101
|
|
|
78
102
|
#### `arm login`
|
|
79
103
|
Authenticate with API Response Manager
|
|
104
|
+
|
|
105
|
+
**Options:**
|
|
106
|
+
- `-e, --email <email>` - Email address (for email/password login)
|
|
107
|
+
- `-p, --password <password>` - Password (for email/password login)
|
|
108
|
+
- `--provider <provider>` - OAuth provider: google, github, or microsoft
|
|
109
|
+
|
|
110
|
+
**Examples:**
|
|
80
111
|
```bash
|
|
112
|
+
# Interactive login (choose method)
|
|
81
113
|
arm login
|
|
82
|
-
|
|
114
|
+
|
|
115
|
+
# Email & Password
|
|
116
|
+
arm login -e user@example.com -p mypassword
|
|
117
|
+
|
|
118
|
+
# Social Login (OAuth Device Flow)
|
|
119
|
+
arm login --provider github
|
|
120
|
+
arm login --provider google
|
|
121
|
+
arm login --provider microsoft
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**OAuth Device Flow:**
|
|
125
|
+
When using social login, the CLI will:
|
|
126
|
+
1. Generate a unique device code (e.g., `ABCD-EFGH`)
|
|
127
|
+
2. Display a verification URL
|
|
128
|
+
3. Automatically open your browser
|
|
129
|
+
4. Wait for you to complete authentication
|
|
130
|
+
5. Store your token securely
|
|
131
|
+
|
|
132
|
+
Example output:
|
|
133
|
+
```bash
|
|
134
|
+
$ arm login --provider github
|
|
135
|
+
|
|
136
|
+
š Logging in with github...
|
|
137
|
+
|
|
138
|
+
š Please complete authentication:
|
|
139
|
+
|
|
140
|
+
1. Visit: https://localhost:5173/device
|
|
141
|
+
2. Enter code: ABCD-EFGH
|
|
142
|
+
|
|
143
|
+
Code expires in 600 seconds
|
|
144
|
+
|
|
145
|
+
? Open browser automatically? (Y/n)
|
|
146
|
+
|
|
147
|
+
ā Browser opened
|
|
148
|
+
|
|
149
|
+
ā Waiting for authentication...
|
|
150
|
+
ā Authentication successful!
|
|
151
|
+
|
|
152
|
+
User: John Doe
|
|
153
|
+
Provider: github
|
|
154
|
+
Token saved to: ~/.config/arm-cli/config.json
|
|
155
|
+
|
|
156
|
+
ā You can now use all ARM CLI commands
|
|
83
157
|
```
|
|
84
158
|
|
|
85
159
|
#### `arm logout`
|
|
@@ -93,9 +167,23 @@ arm logout
|
|
|
93
167
|
#### `arm tunnel <port>`
|
|
94
168
|
Start a tunnel to expose local server
|
|
95
169
|
```bash
|
|
170
|
+
# Basic HTTP tunnel
|
|
96
171
|
arm tunnel 3000
|
|
97
|
-
|
|
98
|
-
|
|
172
|
+
|
|
173
|
+
# HTTPS tunnel with SSL
|
|
174
|
+
arm tunnel 3000 --protocol https --ssl
|
|
175
|
+
|
|
176
|
+
# TCP tunnel (for databases, etc.)
|
|
177
|
+
arm tunnel 5432 --protocol tcp --subdomain postgres
|
|
178
|
+
|
|
179
|
+
# WebSocket tunnel
|
|
180
|
+
arm tunnel 8080 --protocol ws
|
|
181
|
+
|
|
182
|
+
# With custom subdomain and authentication
|
|
183
|
+
arm tunnel 3000 --subdomain myapi --name "My API" --auth --rate-limit 100
|
|
184
|
+
|
|
185
|
+
# With custom domain
|
|
186
|
+
arm tunnel 3000 --protocol https --ssl --domain api.yourdomain.com
|
|
99
187
|
```
|
|
100
188
|
|
|
101
189
|
Options:
|
|
@@ -103,6 +191,9 @@ Options:
|
|
|
103
191
|
- `-n, --name <name>` - Tunnel name
|
|
104
192
|
- `-a, --auth` - Enable basic authentication
|
|
105
193
|
- `-r, --rate-limit <limit>` - Rate limit (requests per minute, default: 60)
|
|
194
|
+
- `-p, --protocol <protocol>` - Protocol: http, https, tcp, ws, wss (default: http)
|
|
195
|
+
- `--ssl` - Enable SSL/HTTPS
|
|
196
|
+
- `-d, --domain <domain>` - Custom domain
|
|
106
197
|
|
|
107
198
|
#### `arm tunnel:list`
|
|
108
199
|
List all active tunnels
|
|
@@ -128,6 +219,91 @@ Options:
|
|
|
128
219
|
- `-f, --follow` - Follow log output (real-time)
|
|
129
220
|
- `-n, --lines <number>` - Number of lines to show (default: 50)
|
|
130
221
|
|
|
222
|
+
#### `arm tunnel:domain <tunnelId> <domain>`
|
|
223
|
+
Set custom domain for tunnel
|
|
224
|
+
```bash
|
|
225
|
+
arm tunnel:domain 507f1f77bcf86cd799439011 api.yourdomain.com
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
#### `arm tunnel:ssl <tunnelId>`
|
|
229
|
+
Upload SSL certificate for tunnel
|
|
230
|
+
```bash
|
|
231
|
+
arm tunnel:ssl 507f1f77bcf86cd799439011 --cert cert.pem --key key.pem
|
|
232
|
+
arm tunnel:ssl 507f1f77bcf86cd799439011 --cert cert.pem --key key.pem --ca ca.pem
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Options:
|
|
236
|
+
- `--cert <path>` - Path to certificate file
|
|
237
|
+
- `--key <path>` - Path to private key file
|
|
238
|
+
- `--ca <path>` - Path to CA certificate file (optional)
|
|
239
|
+
|
|
240
|
+
#### `arm tunnel:auth:oauth <tunnelId>`
|
|
241
|
+
Configure OAuth authentication for tunnel
|
|
242
|
+
```bash
|
|
243
|
+
arm tunnel:auth:oauth 507f1f77bcf86cd799439011 \
|
|
244
|
+
--provider google \
|
|
245
|
+
--client-id YOUR_CLIENT_ID \
|
|
246
|
+
--client-secret YOUR_SECRET \
|
|
247
|
+
--callback-url https://yourtunnel.arm.dev/auth/callback \
|
|
248
|
+
--scope openid,email,profile
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Options:
|
|
252
|
+
- `--provider <provider>` - OAuth provider: google, github, microsoft, custom
|
|
253
|
+
- `--client-id <id>` - OAuth client ID
|
|
254
|
+
- `--client-secret <secret>` - OAuth client secret
|
|
255
|
+
- `--callback-url <url>` - OAuth callback URL
|
|
256
|
+
- `--scope <scope>` - OAuth scope (comma-separated)
|
|
257
|
+
|
|
258
|
+
#### `arm tunnel:auth:oidc <tunnelId>`
|
|
259
|
+
Configure OpenID Connect authentication for tunnel
|
|
260
|
+
```bash
|
|
261
|
+
arm tunnel:auth:oidc 507f1f77bcf86cd799439011 \
|
|
262
|
+
--issuer https://accounts.google.com \
|
|
263
|
+
--client-id YOUR_CLIENT_ID \
|
|
264
|
+
--client-secret YOUR_SECRET \
|
|
265
|
+
--callback-url https://yourtunnel.arm.dev/auth/callback
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Options:
|
|
269
|
+
- `--issuer <url>` - OIDC issuer URL
|
|
270
|
+
- `--client-id <id>` - OIDC client ID
|
|
271
|
+
- `--client-secret <secret>` - OIDC client secret
|
|
272
|
+
- `--callback-url <url>` - OIDC callback URL
|
|
273
|
+
|
|
274
|
+
#### `arm tunnel:auth:saml <tunnelId>`
|
|
275
|
+
Configure SAML authentication for tunnel
|
|
276
|
+
```bash
|
|
277
|
+
arm tunnel:auth:saml 507f1f77bcf86cd799439011 \
|
|
278
|
+
--entry-point https://idp.example.com/saml/sso \
|
|
279
|
+
--issuer https://yourtunnel.arm.dev \
|
|
280
|
+
--cert idp-cert.pem \
|
|
281
|
+
--callback-url https://yourtunnel.arm.dev/auth/saml/callback
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Options:
|
|
285
|
+
- `--entry-point <url>` - SAML entry point URL
|
|
286
|
+
- `--issuer <issuer>` - SAML issuer
|
|
287
|
+
- `--cert <path>` - Path to IdP certificate file
|
|
288
|
+
- `--callback-url <url>` - SAML callback URL
|
|
289
|
+
|
|
290
|
+
#### `arm tunnel:ingress <tunnelId> <rules>`
|
|
291
|
+
Configure ingress rules for tunnel (path-based routing)
|
|
292
|
+
```bash
|
|
293
|
+
# Route different paths to different backends
|
|
294
|
+
arm tunnel:ingress 507f1f77bcf86cd799439011 \
|
|
295
|
+
"/api=localhost:3000,/admin=localhost:4000" \
|
|
296
|
+
--tls
|
|
297
|
+
|
|
298
|
+
# Single rule
|
|
299
|
+
arm tunnel:ingress 507f1f77bcf86cd799439011 "/api=localhost:3000"
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Options:
|
|
303
|
+
- `--tls` - Enable TLS for ingress
|
|
304
|
+
|
|
305
|
+
Rules format: `/path=host:port,/path2=host:port`
|
|
306
|
+
|
|
131
307
|
### Webhooks
|
|
132
308
|
|
|
133
309
|
#### `arm webhook`
|
|
@@ -268,13 +444,53 @@ Default configuration:
|
|
|
268
444
|
# Login
|
|
269
445
|
arm login
|
|
270
446
|
|
|
271
|
-
# Start tunnel on port 3000
|
|
272
|
-
arm tunnel 3000 --subdomain myapp
|
|
447
|
+
# Start HTTPS tunnel on port 3000
|
|
448
|
+
arm tunnel 3000 --protocol https --ssl --subdomain myapp
|
|
273
449
|
|
|
274
450
|
# Your local server is now accessible at:
|
|
275
451
|
# https://myapp.tunnel.arm.dev
|
|
276
452
|
```
|
|
277
453
|
|
|
454
|
+
### Secure Tunnel with OAuth Authentication
|
|
455
|
+
```bash
|
|
456
|
+
# Create HTTPS tunnel
|
|
457
|
+
arm tunnel 3000 --protocol https --ssl --subdomain myapi
|
|
458
|
+
|
|
459
|
+
# Configure Google OAuth
|
|
460
|
+
arm tunnel:auth:oauth <tunnel-id> \
|
|
461
|
+
--provider google \
|
|
462
|
+
--client-id YOUR_GOOGLE_CLIENT_ID \
|
|
463
|
+
--client-secret YOUR_GOOGLE_SECRET \
|
|
464
|
+
--callback-url https://myapi.tunnel.arm.dev/auth/callback
|
|
465
|
+
|
|
466
|
+
# Now your tunnel requires Google login to access
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### TCP Tunnel for Database
|
|
470
|
+
```bash
|
|
471
|
+
# Expose PostgreSQL database
|
|
472
|
+
arm tunnel 5432 --protocol tcp --subdomain mydb
|
|
473
|
+
|
|
474
|
+
# Connect from anywhere:
|
|
475
|
+
# psql -h mydb.tunnel.arm.dev -p 5432 -U username -d database
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
### Multi-Service Routing with Ingress
|
|
479
|
+
```bash
|
|
480
|
+
# Create tunnel
|
|
481
|
+
arm tunnel 3000 --protocol https --ssl
|
|
482
|
+
|
|
483
|
+
# Configure path-based routing
|
|
484
|
+
arm tunnel:ingress <tunnel-id> \
|
|
485
|
+
"/api/v1=localhost:3000,/api/v2=localhost:4000,/admin=localhost:5000" \
|
|
486
|
+
--tls
|
|
487
|
+
|
|
488
|
+
# Now:
|
|
489
|
+
# https://yourtunnel.arm.dev/api/v1 -> localhost:3000
|
|
490
|
+
# https://yourtunnel.arm.dev/api/v2 -> localhost:4000
|
|
491
|
+
# https://yourtunnel.arm.dev/admin -> localhost:5000
|
|
492
|
+
```
|
|
493
|
+
|
|
278
494
|
### Test Webhooks Locally
|
|
279
495
|
```bash
|
|
280
496
|
# Create webhook that forwards to local server
|
|
@@ -328,6 +544,28 @@ arm config:set apiUrl https://your-api-url.com/api
|
|
|
328
544
|
arm config:get
|
|
329
545
|
```
|
|
330
546
|
|
|
547
|
+
## Troubleshooting
|
|
548
|
+
|
|
549
|
+
### Command Not Found After Installation
|
|
550
|
+
|
|
551
|
+
If you get `arm: command not found` after installing:
|
|
552
|
+
|
|
553
|
+
**Windows:**
|
|
554
|
+
1. Check npm prefix: `npm config get prefix`
|
|
555
|
+
2. Add to PATH: `C:\Users\<YourUsername>\AppData\Roaming\npm`
|
|
556
|
+
3. Restart terminal
|
|
557
|
+
|
|
558
|
+
**macOS/Linux:**
|
|
559
|
+
```bash
|
|
560
|
+
echo 'export PATH="$(npm config get prefix)/bin:$PATH"' >> ~/.bashrc
|
|
561
|
+
source ~/.bashrc
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
**Alternative - Use npx:**
|
|
565
|
+
```bash
|
|
566
|
+
npx @vijaypurohit322-arm/cli login
|
|
567
|
+
```
|
|
568
|
+
|
|
331
569
|
## Publishing to npm
|
|
332
570
|
|
|
333
571
|
See [PUBLISHING.md](./PUBLISHING.md) for detailed instructions on publishing this package to npm.
|
package/bin/arm.js
CHANGED
|
@@ -30,6 +30,7 @@ program
|
|
|
30
30
|
.description('Authenticate with API Response Manager')
|
|
31
31
|
.option('-e, --email <email>', 'Email address')
|
|
32
32
|
.option('-p, --password <password>', 'Password')
|
|
33
|
+
.option('--provider <provider>', 'OAuth provider (google, github, microsoft)')
|
|
33
34
|
.action(loginCommand);
|
|
34
35
|
|
|
35
36
|
// Logout command
|
|
@@ -47,6 +48,9 @@ program
|
|
|
47
48
|
.option('-n, --name <name>', 'Tunnel name')
|
|
48
49
|
.option('-a, --auth', 'Enable basic authentication')
|
|
49
50
|
.option('-r, --rate-limit <limit>', 'Rate limit (requests per minute)', '60')
|
|
51
|
+
.option('-p, --protocol <protocol>', 'Protocol (http, https, tcp, ws, wss)', 'http')
|
|
52
|
+
.option('--ssl', 'Enable SSL/HTTPS')
|
|
53
|
+
.option('-d, --domain <domain>', 'Custom domain')
|
|
50
54
|
.action(tunnelCommand.start);
|
|
51
55
|
|
|
52
56
|
program
|
|
@@ -68,6 +72,61 @@ program
|
|
|
68
72
|
.option('-n, --lines <number>', 'Number of lines to show', '50')
|
|
69
73
|
.action(tunnelCommand.logs);
|
|
70
74
|
|
|
75
|
+
program
|
|
76
|
+
.command('tunnel:domain')
|
|
77
|
+
.description('Set custom domain for tunnel')
|
|
78
|
+
.argument('<tunnelId>', 'Tunnel ID')
|
|
79
|
+
.argument('<domain>', 'Custom domain (e.g., api.yourdomain.com)')
|
|
80
|
+
.action(tunnelCommand.setDomain);
|
|
81
|
+
|
|
82
|
+
program
|
|
83
|
+
.command('tunnel:ssl')
|
|
84
|
+
.description('Upload SSL certificate for tunnel')
|
|
85
|
+
.argument('<tunnelId>', 'Tunnel ID')
|
|
86
|
+
.option('--cert <path>', 'Path to certificate file')
|
|
87
|
+
.option('--key <path>', 'Path to private key file')
|
|
88
|
+
.option('--ca <path>', 'Path to CA certificate file (optional)')
|
|
89
|
+
.action(tunnelCommand.uploadSSL);
|
|
90
|
+
|
|
91
|
+
program
|
|
92
|
+
.command('tunnel:auth:oauth')
|
|
93
|
+
.description('Configure OAuth authentication')
|
|
94
|
+
.argument('<tunnelId>', 'Tunnel ID')
|
|
95
|
+
.option('--provider <provider>', 'OAuth provider (google, github, microsoft, custom)')
|
|
96
|
+
.option('--client-id <id>', 'OAuth client ID')
|
|
97
|
+
.option('--client-secret <secret>', 'OAuth client secret')
|
|
98
|
+
.option('--callback-url <url>', 'OAuth callback URL')
|
|
99
|
+
.option('--scope <scope>', 'OAuth scope (comma-separated)')
|
|
100
|
+
.action(tunnelCommand.configureOAuth);
|
|
101
|
+
|
|
102
|
+
program
|
|
103
|
+
.command('tunnel:auth:oidc')
|
|
104
|
+
.description('Configure OIDC authentication')
|
|
105
|
+
.argument('<tunnelId>', 'Tunnel ID')
|
|
106
|
+
.option('--issuer <url>', 'OIDC issuer URL')
|
|
107
|
+
.option('--client-id <id>', 'OIDC client ID')
|
|
108
|
+
.option('--client-secret <secret>', 'OIDC client secret')
|
|
109
|
+
.option('--callback-url <url>', 'OIDC callback URL')
|
|
110
|
+
.action(tunnelCommand.configureOIDC);
|
|
111
|
+
|
|
112
|
+
program
|
|
113
|
+
.command('tunnel:auth:saml')
|
|
114
|
+
.description('Configure SAML authentication')
|
|
115
|
+
.argument('<tunnelId>', 'Tunnel ID')
|
|
116
|
+
.option('--entry-point <url>', 'SAML entry point URL')
|
|
117
|
+
.option('--issuer <issuer>', 'SAML issuer')
|
|
118
|
+
.option('--cert <path>', 'Path to IdP certificate file')
|
|
119
|
+
.option('--callback-url <url>', 'SAML callback URL')
|
|
120
|
+
.action(tunnelCommand.configureSAML);
|
|
121
|
+
|
|
122
|
+
program
|
|
123
|
+
.command('tunnel:ingress')
|
|
124
|
+
.description('Configure ingress rules for tunnel')
|
|
125
|
+
.argument('<tunnelId>', 'Tunnel ID')
|
|
126
|
+
.argument('<rules>', 'Ingress rules (e.g., "/api=localhost:3000,/admin=localhost:4000")')
|
|
127
|
+
.option('--tls', 'Enable TLS for ingress')
|
|
128
|
+
.action(tunnelCommand.configureIngress);
|
|
129
|
+
|
|
71
130
|
// Webhook commands
|
|
72
131
|
program
|
|
73
132
|
.command('webhook')
|
package/commands/login.js
CHANGED
|
@@ -1,12 +1,38 @@
|
|
|
1
1
|
const inquirer = require('inquirer');
|
|
2
2
|
const chalk = require('chalk');
|
|
3
3
|
const ora = require('ora');
|
|
4
|
+
const open = require('open');
|
|
4
5
|
const api = require('../utils/api');
|
|
5
6
|
const config = require('../utils/config');
|
|
6
7
|
|
|
7
8
|
async function login(options) {
|
|
8
9
|
console.log(chalk.blue.bold('\nš API Response Manager - Login\n'));
|
|
9
10
|
|
|
11
|
+
// Check if social login is requested
|
|
12
|
+
if (options.provider) {
|
|
13
|
+
return await socialLogin(options.provider);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Ask for login method
|
|
17
|
+
const { method } = await inquirer.prompt([
|
|
18
|
+
{
|
|
19
|
+
type: 'list',
|
|
20
|
+
name: 'method',
|
|
21
|
+
message: 'Choose login method:',
|
|
22
|
+
choices: [
|
|
23
|
+
{ name: 'š§ Email & Password', value: 'email' },
|
|
24
|
+
{ name: 'š Google', value: 'google' },
|
|
25
|
+
{ name: 'š GitHub', value: 'github' },
|
|
26
|
+
{ name: 'šŖ Microsoft', value: 'microsoft' }
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
if (method !== 'email') {
|
|
32
|
+
return await socialLogin(method);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Traditional email/password login
|
|
10
36
|
let email = options.email;
|
|
11
37
|
let password = options.password;
|
|
12
38
|
|
|
@@ -85,4 +111,100 @@ async function login(options) {
|
|
|
85
111
|
}
|
|
86
112
|
}
|
|
87
113
|
|
|
114
|
+
async function socialLogin(provider) {
|
|
115
|
+
console.log(chalk.blue(`\nš Logging in with ${provider}...\n`));
|
|
116
|
+
|
|
117
|
+
const spinner = ora('Initiating OAuth flow...').start();
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
// Request device code from backend
|
|
121
|
+
const deviceResponse = await api.requestDeviceCode(provider);
|
|
122
|
+
|
|
123
|
+
spinner.stop();
|
|
124
|
+
|
|
125
|
+
const { device_code, user_code, verification_uri, expires_in } = deviceResponse;
|
|
126
|
+
|
|
127
|
+
console.log(chalk.yellow('\nš Please complete authentication:\n'));
|
|
128
|
+
console.log(chalk.white(' 1. Visit:'), chalk.cyan.underline(verification_uri));
|
|
129
|
+
console.log(chalk.white(' 2. Enter code:'), chalk.green.bold(user_code));
|
|
130
|
+
console.log(chalk.gray(`\n Code expires in ${expires_in} seconds\n`));
|
|
131
|
+
|
|
132
|
+
// Open browser automatically
|
|
133
|
+
const { openBrowser } = await inquirer.prompt([
|
|
134
|
+
{
|
|
135
|
+
type: 'confirm',
|
|
136
|
+
name: 'openBrowser',
|
|
137
|
+
message: 'Open browser automatically?',
|
|
138
|
+
default: true
|
|
139
|
+
}
|
|
140
|
+
]);
|
|
141
|
+
|
|
142
|
+
if (openBrowser) {
|
|
143
|
+
await open(verification_uri);
|
|
144
|
+
console.log(chalk.gray(' ā Browser opened\n'));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const pollSpinner = ora('Waiting for authentication...').start();
|
|
148
|
+
|
|
149
|
+
// Poll for token
|
|
150
|
+
const pollInterval = 5000; // 5 seconds
|
|
151
|
+
const maxAttempts = Math.ceil(expires_in / (pollInterval / 1000));
|
|
152
|
+
let attempts = 0;
|
|
153
|
+
|
|
154
|
+
const pollForToken = async () => {
|
|
155
|
+
while (attempts < maxAttempts) {
|
|
156
|
+
attempts++;
|
|
157
|
+
|
|
158
|
+
try {
|
|
159
|
+
const tokenResponse = await api.pollDeviceToken(device_code, provider);
|
|
160
|
+
|
|
161
|
+
if (tokenResponse.token) {
|
|
162
|
+
pollSpinner.succeed(chalk.green('Authentication successful!'));
|
|
163
|
+
|
|
164
|
+
// Store credentials
|
|
165
|
+
api.setToken(tokenResponse.token);
|
|
166
|
+
|
|
167
|
+
const userId = tokenResponse.user?._id || tokenResponse.user?.id;
|
|
168
|
+
const userEmail = tokenResponse.user?.email;
|
|
169
|
+
const userName = tokenResponse.user?.name;
|
|
170
|
+
|
|
171
|
+
if (userId) config.set('userId', userId);
|
|
172
|
+
if (userEmail) config.set('email', userEmail);
|
|
173
|
+
|
|
174
|
+
console.log(chalk.gray('\nUser:'), chalk.white(userName || userEmail));
|
|
175
|
+
console.log(chalk.gray('Provider:'), chalk.white(provider));
|
|
176
|
+
console.log(chalk.gray('Token saved to:'), chalk.white(config.path));
|
|
177
|
+
console.log(chalk.green('\nā You can now use all ARM CLI commands\n'));
|
|
178
|
+
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
} catch (error) {
|
|
182
|
+
if (error.response?.status === 428) {
|
|
183
|
+
// Still pending, continue polling
|
|
184
|
+
await new Promise(resolve => setTimeout(resolve, pollInterval));
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
throw error;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
throw new Error('Authentication timeout - please try again');
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
await pollForToken();
|
|
195
|
+
|
|
196
|
+
} catch (error) {
|
|
197
|
+
spinner.stop();
|
|
198
|
+
console.error(chalk.red('\nā Social login failed'));
|
|
199
|
+
|
|
200
|
+
if (error.response?.data?.msg) {
|
|
201
|
+
console.error(chalk.red(`ā ${error.response.data.msg}\n`));
|
|
202
|
+
} else {
|
|
203
|
+
console.error(chalk.red(`ā ${error.message}\n`));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
process.exit(1);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
88
210
|
module.exports = login;
|
package/commands/tunnel.js
CHANGED
|
@@ -21,6 +21,9 @@ async function start(port, options) {
|
|
|
21
21
|
name: options.name || `Tunnel-${port}`,
|
|
22
22
|
subdomain: options.subdomain,
|
|
23
23
|
localPort: parseInt(port),
|
|
24
|
+
protocol: options.protocol || 'http',
|
|
25
|
+
sslEnabled: options.ssl || options.protocol === 'https',
|
|
26
|
+
customDomain: options.domain,
|
|
24
27
|
security: {
|
|
25
28
|
requireAuth: options.auth || false
|
|
26
29
|
},
|
|
@@ -222,9 +225,147 @@ async function logs(tunnelId, options) {
|
|
|
222
225
|
}
|
|
223
226
|
}
|
|
224
227
|
|
|
228
|
+
// Set custom domain
|
|
229
|
+
async function setDomain(tunnelId, domain) {
|
|
230
|
+
const spinner = ora('Setting custom domain...').start();
|
|
231
|
+
|
|
232
|
+
try {
|
|
233
|
+
await api.setTunnelDomain(tunnelId, domain);
|
|
234
|
+
spinner.succeed(chalk.green('Custom domain set successfully'));
|
|
235
|
+
console.log(chalk.cyan(`\nā Tunnel now accessible at: https://${domain}\n`));
|
|
236
|
+
} catch (error) {
|
|
237
|
+
spinner.fail(chalk.red('Failed to set custom domain'));
|
|
238
|
+
console.error(chalk.red(`\nā ${error.response?.data?.msg || error.message}\n`));
|
|
239
|
+
process.exit(1);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Upload SSL certificate
|
|
244
|
+
async function uploadSSL(tunnelId, options) {
|
|
245
|
+
const spinner = ora('Uploading SSL certificate...').start();
|
|
246
|
+
|
|
247
|
+
try {
|
|
248
|
+
const fs = require('fs');
|
|
249
|
+
const cert = fs.readFileSync(options.cert, 'utf8');
|
|
250
|
+
const key = fs.readFileSync(options.key, 'utf8');
|
|
251
|
+
const ca = options.ca ? fs.readFileSync(options.ca, 'utf8') : null;
|
|
252
|
+
|
|
253
|
+
await api.uploadTunnelSSL(tunnelId, { cert, key, ca });
|
|
254
|
+
spinner.succeed(chalk.green('SSL certificate uploaded successfully'));
|
|
255
|
+
console.log();
|
|
256
|
+
} catch (error) {
|
|
257
|
+
spinner.fail(chalk.red('Failed to upload SSL certificate'));
|
|
258
|
+
console.error(chalk.red(`\nā ${error.response?.data?.msg || error.message}\n`));
|
|
259
|
+
process.exit(1);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Configure OAuth
|
|
264
|
+
async function configureOAuth(tunnelId, options) {
|
|
265
|
+
const spinner = ora('Configuring OAuth...').start();
|
|
266
|
+
|
|
267
|
+
try {
|
|
268
|
+
await api.configureTunnelOAuth(tunnelId, {
|
|
269
|
+
provider: options.provider,
|
|
270
|
+
clientId: options.clientId,
|
|
271
|
+
clientSecret: options.clientSecret,
|
|
272
|
+
callbackUrl: options.callbackUrl,
|
|
273
|
+
scope: options.scope ? options.scope.split(',') : ['openid', 'email', 'profile']
|
|
274
|
+
});
|
|
275
|
+
spinner.succeed(chalk.green('OAuth configured successfully'));
|
|
276
|
+
console.log();
|
|
277
|
+
} catch (error) {
|
|
278
|
+
spinner.fail(chalk.red('Failed to configure OAuth'));
|
|
279
|
+
console.error(chalk.red(`\nā ${error.response?.data?.msg || error.message}\n`));
|
|
280
|
+
process.exit(1);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Configure OIDC
|
|
285
|
+
async function configureOIDC(tunnelId, options) {
|
|
286
|
+
const spinner = ora('Configuring OIDC...').start();
|
|
287
|
+
|
|
288
|
+
try {
|
|
289
|
+
await api.configureTunnelOIDC(tunnelId, {
|
|
290
|
+
issuer: options.issuer,
|
|
291
|
+
clientId: options.clientId,
|
|
292
|
+
clientSecret: options.clientSecret,
|
|
293
|
+
callbackUrl: options.callbackUrl
|
|
294
|
+
});
|
|
295
|
+
spinner.succeed(chalk.green('OIDC configured successfully'));
|
|
296
|
+
console.log();
|
|
297
|
+
} catch (error) {
|
|
298
|
+
spinner.fail(chalk.red('Failed to configure OIDC'));
|
|
299
|
+
console.error(chalk.red(`\nā ${error.response?.data?.msg || error.message}\n`));
|
|
300
|
+
process.exit(1);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Configure SAML
|
|
305
|
+
async function configureSAML(tunnelId, options) {
|
|
306
|
+
const spinner = ora('Configuring SAML...').start();
|
|
307
|
+
|
|
308
|
+
try {
|
|
309
|
+
const fs = require('fs');
|
|
310
|
+
const cert = fs.readFileSync(options.cert, 'utf8');
|
|
311
|
+
|
|
312
|
+
await api.configureTunnelSAML(tunnelId, {
|
|
313
|
+
entryPoint: options.entryPoint,
|
|
314
|
+
issuer: options.issuer,
|
|
315
|
+
cert,
|
|
316
|
+
callbackUrl: options.callbackUrl
|
|
317
|
+
});
|
|
318
|
+
spinner.succeed(chalk.green('SAML configured successfully'));
|
|
319
|
+
console.log();
|
|
320
|
+
} catch (error) {
|
|
321
|
+
spinner.fail(chalk.red('Failed to configure SAML'));
|
|
322
|
+
console.error(chalk.red(`\nā ${error.response?.data?.msg || error.message}\n`));
|
|
323
|
+
process.exit(1);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Configure ingress
|
|
328
|
+
async function configureIngress(tunnelId, rules, options) {
|
|
329
|
+
const spinner = ora('Configuring ingress...').start();
|
|
330
|
+
|
|
331
|
+
try {
|
|
332
|
+
// Parse rules: "/api=localhost:3000,/admin=localhost:4000"
|
|
333
|
+
const parsedRules = rules.split(',').map(rule => {
|
|
334
|
+
const [path, backend] = rule.split('=');
|
|
335
|
+
const [host, port] = backend.split(':');
|
|
336
|
+
return {
|
|
337
|
+
path: path.trim(),
|
|
338
|
+
pathType: 'Prefix',
|
|
339
|
+
backend: {
|
|
340
|
+
host: host.trim(),
|
|
341
|
+
port: parseInt(port)
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
await api.configureTunnelIngress(tunnelId, {
|
|
347
|
+
enabled: true,
|
|
348
|
+
rules: parsedRules,
|
|
349
|
+
tls: { enabled: options.tls || false }
|
|
350
|
+
});
|
|
351
|
+
spinner.succeed(chalk.green('Ingress configured successfully'));
|
|
352
|
+
console.log();
|
|
353
|
+
} catch (error) {
|
|
354
|
+
spinner.fail(chalk.red('Failed to configure ingress'));
|
|
355
|
+
console.error(chalk.red(`\nā ${error.response?.data?.msg || error.message}\n`));
|
|
356
|
+
process.exit(1);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
225
360
|
module.exports = {
|
|
226
361
|
start,
|
|
227
362
|
list,
|
|
228
363
|
stop,
|
|
229
|
-
logs
|
|
364
|
+
logs,
|
|
365
|
+
setDomain,
|
|
366
|
+
uploadSSL,
|
|
367
|
+
configureOAuth,
|
|
368
|
+
configureOIDC,
|
|
369
|
+
configureSAML,
|
|
370
|
+
configureIngress
|
|
230
371
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "api-response-manager",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Command-line interface for API Response Manager",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -21,17 +21,18 @@
|
|
|
21
21
|
"author": "Vijay Singh Purohit",
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"commander": "^11.1.0",
|
|
25
24
|
"axios": "^1.6.2",
|
|
25
|
+
"boxen": "^5.1.2",
|
|
26
26
|
"chalk": "^4.1.2",
|
|
27
|
+
"cli-table3": "^0.6.3",
|
|
28
|
+
"commander": "^11.1.0",
|
|
29
|
+
"conf": "^10.2.0",
|
|
30
|
+
"dotenv": "^16.3.1",
|
|
27
31
|
"inquirer": "^8.2.5",
|
|
32
|
+
"open": "^8.4.0",
|
|
28
33
|
"ora": "^5.4.1",
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"conf": "^10.2.0",
|
|
32
|
-
"boxen": "^5.1.2",
|
|
33
|
-
"cli-table3": "^0.6.3",
|
|
34
|
-
"update-notifier": "^6.0.2"
|
|
34
|
+
"update-notifier": "^6.0.2",
|
|
35
|
+
"ws": "^8.14.2"
|
|
35
36
|
},
|
|
36
37
|
"devDependencies": {
|
|
37
38
|
"jest": "^29.7.0"
|
package/utils/api.js
CHANGED
|
@@ -58,6 +58,20 @@ class APIClient {
|
|
|
58
58
|
return response.data;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
// OAuth Device Flow for CLI
|
|
62
|
+
async requestDeviceCode(provider) {
|
|
63
|
+
const response = await this.client.post('/auth/device/code', { provider });
|
|
64
|
+
return response.data;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async pollDeviceToken(deviceCode, provider) {
|
|
68
|
+
const response = await this.client.post('/auth/device/token', {
|
|
69
|
+
device_code: deviceCode,
|
|
70
|
+
provider
|
|
71
|
+
});
|
|
72
|
+
return response.data;
|
|
73
|
+
}
|
|
74
|
+
|
|
61
75
|
// Tunnels
|
|
62
76
|
async createTunnel(data) {
|
|
63
77
|
const response = await this.client.post('/tunnels', data);
|
|
@@ -140,6 +154,37 @@ class APIClient {
|
|
|
140
154
|
const response = await this.client.get(`/projects/${id}/responses`, { params });
|
|
141
155
|
return response.data;
|
|
142
156
|
}
|
|
157
|
+
|
|
158
|
+
// Advanced Tunnel Features
|
|
159
|
+
async setTunnelDomain(id, domain) {
|
|
160
|
+
const response = await this.client.post(`/tunnels/${id}/custom-domain`, { domain });
|
|
161
|
+
return response.data;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async uploadTunnelSSL(id, data) {
|
|
165
|
+
const response = await this.client.post(`/tunnels/${id}/ssl`, data);
|
|
166
|
+
return response.data;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async configureTunnelOAuth(id, data) {
|
|
170
|
+
const response = await this.client.post(`/tunnels/${id}/auth/oauth`, data);
|
|
171
|
+
return response.data;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async configureTunnelOIDC(id, data) {
|
|
175
|
+
const response = await this.client.post(`/tunnels/${id}/auth/oidc`, data);
|
|
176
|
+
return response.data;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async configureTunnelSAML(id, data) {
|
|
180
|
+
const response = await this.client.post(`/tunnels/${id}/auth/saml`, data);
|
|
181
|
+
return response.data;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async configureTunnelIngress(id, data) {
|
|
185
|
+
const response = await this.client.post(`/tunnels/${id}/ingress`, data);
|
|
186
|
+
return response.data;
|
|
187
|
+
}
|
|
143
188
|
}
|
|
144
189
|
|
|
145
190
|
module.exports = new APIClient();
|