api-response-manager 2.6.1 → 2.6.4
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 +1 -1
- package/commands/login.js +55 -3
- package/commands/serve.js +12 -4
- package/commands/tunnel.js +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
package/commands/login.js
CHANGED
|
@@ -1,10 +1,57 @@
|
|
|
1
1
|
const inquirer = require('inquirer');
|
|
2
2
|
const chalk = require('chalk');
|
|
3
3
|
const ora = require('ora');
|
|
4
|
-
const
|
|
4
|
+
const { spawn } = require('child_process');
|
|
5
5
|
const api = require('../utils/api');
|
|
6
6
|
const config = require('../utils/config');
|
|
7
7
|
|
|
8
|
+
// Safe browser opener that never throws
|
|
9
|
+
function openBrowserSafe(url) {
|
|
10
|
+
return new Promise((resolve) => {
|
|
11
|
+
const platform = process.platform;
|
|
12
|
+
let cmd, args;
|
|
13
|
+
|
|
14
|
+
if (platform === 'win32') {
|
|
15
|
+
cmd = 'cmd.exe';
|
|
16
|
+
args = ['/c', 'start', '""', url];
|
|
17
|
+
} else if (platform === 'darwin') {
|
|
18
|
+
cmd = 'open';
|
|
19
|
+
args = [url];
|
|
20
|
+
} else {
|
|
21
|
+
cmd = 'xdg-open';
|
|
22
|
+
args = [url];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const child = spawn(cmd, args, {
|
|
27
|
+
detached: true,
|
|
28
|
+
stdio: 'ignore'
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
let resolved = false;
|
|
32
|
+
|
|
33
|
+
child.on('error', () => {
|
|
34
|
+
if (!resolved) {
|
|
35
|
+
resolved = true;
|
|
36
|
+
resolve(false);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// On successful spawn, unref and resolve after brief delay
|
|
41
|
+
child.unref();
|
|
42
|
+
|
|
43
|
+
setTimeout(() => {
|
|
44
|
+
if (!resolved) {
|
|
45
|
+
resolved = true;
|
|
46
|
+
resolve(true);
|
|
47
|
+
}
|
|
48
|
+
}, 100);
|
|
49
|
+
} catch (e) {
|
|
50
|
+
resolve(false);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
8
55
|
async function login(options) {
|
|
9
56
|
// Token-based login for CI/CD automation
|
|
10
57
|
if (options.token) {
|
|
@@ -165,8 +212,13 @@ async function socialLogin(provider) {
|
|
|
165
212
|
]);
|
|
166
213
|
|
|
167
214
|
if (openBrowser) {
|
|
168
|
-
await
|
|
169
|
-
|
|
215
|
+
const browserOpened = await openBrowserSafe(verification_uri);
|
|
216
|
+
|
|
217
|
+
if (browserOpened) {
|
|
218
|
+
console.log(chalk.gray(' ✓ Browser opened\n'));
|
|
219
|
+
} else {
|
|
220
|
+
console.log(chalk.yellow(' ⚠ Could not open browser automatically. Please open the URL manually.\n'));
|
|
221
|
+
}
|
|
170
222
|
}
|
|
171
223
|
|
|
172
224
|
const pollSpinner = ora('Waiting for authentication...').start();
|
package/commands/serve.js
CHANGED
|
@@ -454,7 +454,10 @@ async function connectFileTunnel(tunnelId, subdomain, localPort) {
|
|
|
454
454
|
function connect() {
|
|
455
455
|
if (isShuttingDown) return;
|
|
456
456
|
|
|
457
|
-
const ws = new WebSocket(tunnelServerUrl
|
|
457
|
+
const ws = new WebSocket(tunnelServerUrl, {
|
|
458
|
+
// Keep connection alive with WebSocket-level ping/pong
|
|
459
|
+
perMessageDeflate: false
|
|
460
|
+
});
|
|
458
461
|
|
|
459
462
|
ws.on('open', () => {
|
|
460
463
|
reconnectAttempts = 0; // Reset on successful connection
|
|
@@ -476,12 +479,17 @@ async function connectFileTunnel(tunnelId, subdomain, localPort) {
|
|
|
476
479
|
clearInterval(heartbeatInterval);
|
|
477
480
|
}
|
|
478
481
|
|
|
479
|
-
// Heartbeat every
|
|
482
|
+
// Heartbeat every 10 seconds to keep connection alive during large transfers
|
|
480
483
|
heartbeatInterval = setInterval(() => {
|
|
481
484
|
if (ws.readyState === WebSocket.OPEN) {
|
|
482
485
|
ws.send(JSON.stringify({ type: 'heartbeat', tunnelId, subdomain }));
|
|
483
486
|
}
|
|
484
|
-
},
|
|
487
|
+
}, 10000);
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
// Respond to WebSocket-level ping from server
|
|
491
|
+
ws.on('ping', () => {
|
|
492
|
+
ws.pong();
|
|
485
493
|
});
|
|
486
494
|
|
|
487
495
|
ws.on('message', async (data) => {
|
|
@@ -524,7 +532,7 @@ async function connectFileTunnel(tunnelId, subdomain, localPort) {
|
|
|
524
532
|
validateStatus: () => true,
|
|
525
533
|
responseType: 'arraybuffer',
|
|
526
534
|
maxRedirects: 0,
|
|
527
|
-
timeout:
|
|
535
|
+
timeout: 0 // No timeout for large file transfers
|
|
528
536
|
});
|
|
529
537
|
|
|
530
538
|
const cleanHeaders = { ...response.headers };
|
package/commands/tunnel.js
CHANGED
|
@@ -160,11 +160,11 @@ async function connectTunnelClient(tunnelId, subdomain, localPort, protocol = 'h
|
|
|
160
160
|
console.log(chalk.white(` TCP Port: ${message.tcpPort}\n`));
|
|
161
161
|
if (message.sshCommand) {
|
|
162
162
|
console.log(chalk.gray('SSH Command (Linux/Mac):'));
|
|
163
|
-
console.log(chalk.cyan(` ${message.
|
|
163
|
+
console.log(chalk.cyan(` ssh -o ProxyCommand="sh -c '{ printf \\"SUBDOMAIN:${subdomain}\\\\n\\"; cat; } | nc %h %p'" user@${message.tcpHost} -p ${message.tcpPort}\n`));
|
|
164
164
|
console.log(chalk.gray('SSH Command (Windows with ncat):'));
|
|
165
|
-
console.log(chalk.cyan(` ssh -o ProxyCommand="ncat ${message.tcpHost} ${message.tcpPort}" user@${message.tcpHost}\n`));
|
|
165
|
+
console.log(chalk.cyan(` ssh -o ProxyCommand="cmd /c \\"(echo SUBDOMAIN:${subdomain}& type CON) | ncat ${message.tcpHost} ${message.tcpPort}\\"" user@${message.tcpHost}\n`));
|
|
166
166
|
console.log(chalk.gray('SSH with Key (passwordless):'));
|
|
167
|
-
console.log(chalk.cyan(` ssh -i ~/.ssh/your_key.pem -o ProxyCommand="
|
|
167
|
+
console.log(chalk.cyan(` ssh -i ~/.ssh/your_key.pem -o ProxyCommand="sh -c '{ printf \\"SUBDOMAIN:${subdomain}\\\\n\\"; cat; } | nc %h %p'" user@${message.tcpHost} -p ${message.tcpPort}\n`));
|
|
168
168
|
}
|
|
169
169
|
} else {
|
|
170
170
|
// Display QR code for HTTP/HTTPS tunnels (not for TCP/SSH)
|