devtunnel-cli 3.0.11 ā 3.0.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/README.md +126 -145
- package/package.json +1 -1
- package/src/core/RUN.js +1 -5
- package/src/core/setup-cloudflared.js +145 -30
- package/src/core/start.js +1 -2
package/README.md
CHANGED
|
@@ -1,145 +1,126 @@
|
|
|
1
|
-
# DevTunnel š
|
|
2
|
-
|
|
3
|
-
**Share your local dev servers worldwide - Zero config tunnel for any framework**
|
|
4
|
-
|
|
5
|
-
[](https://opensource.org/licenses/MIT)
|
|
6
|
-
[](https://github.com/maiz-an/DevTunnel)
|
|
7
|
-
[](https://www.npmjs.com/package/devtunnel-cli)
|
|
8
|
-
[](https://maiz-an.github.io/DevTunnel/)
|
|
9
|
-
|
|
10
|
-
š **Website:** [devtunnel.vercel.app](https://devtunnel.vercel.app) | š¦ **npm:** [devtunnel-cli](https://www.npmjs.com/package/devtunnel-cli) | š» **GitHub Pages:** [maiz-an.github.io/DevTunnel](https://maiz-an.github.io/DevTunnel/)
|
|
11
|
-
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## ā” Quick Start
|
|
15
|
-
|
|
16
|
-
### Step-by-Step Guide
|
|
17
|
-
|
|
18
|
-
**1. Install DevTunnel (one-time setup):**
|
|
19
|
-
```bash
|
|
20
|
-
npm install -g devtunnel-cli
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
**2. Navigate to your project directory:**
|
|
24
|
-
```bash
|
|
25
|
-
cd your-project
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
**3. Start your dev server (in one terminal):**
|
|
29
|
-
```bash
|
|
30
|
-
npm start
|
|
31
|
-
# OR
|
|
32
|
-
npm run dev
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
**4. Run DevTunnel (in another terminal, same directory):**
|
|
36
|
-
```bash
|
|
37
|
-
cd your-project # Same directory where you run npm start
|
|
38
|
-
devtunnel # Auto-detects project and port!
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
**That's it!** DevTunnel will automatically detect your project and running dev server port.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
**
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
**
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
npm start
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
- [
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
**Version 3.0.10** | Made with ā¤ļø for developers worldwide
|
|
129
|
-
|
|
130
|
-
---
|
|
131
|
-
|
|
132
|
-
## š Search Keywords
|
|
133
|
-
|
|
134
|
-
**DevTunnel** | **dev tunnel** | **localhost tunnel** | **cloudflare tunnel** | **ngrok alternative** | **port forwarding** | **local development** | **vite tunnel** | **react dev server** | **nextjs tunnel** | **npm devtunnel** | **devtunnel-cli** | **share localhost** | **development tools** | **zero config tunnel**
|
|
135
|
-
|
|
136
|
-
---
|
|
137
|
-
|
|
138
|
-
## š¦ Installation & Links
|
|
139
|
-
|
|
140
|
-
- **npm Package**: [devtunnel-cli](https://www.npmjs.com/package/devtunnel-cli)
|
|
141
|
-
- **GitHub Repository**: [maiz-an/DevTunnel](https://github.com/maiz-an/DevTunnel)
|
|
142
|
-
- **GitHub Pages**: [maiz-an.github.io/DevTunnel](https://maiz-an.github.io/DevTunnel/)
|
|
143
|
-
- **Official Website**: [devtunnel.vercel.app](https://devtunnel.vercel.app)
|
|
144
|
-
- **Documentation**: [docs/README.md](docs/README.md)
|
|
145
|
-
- **Issues**: [GitHub Issues](https://github.com/maiz-an/DevTunnel/issues)
|
|
1
|
+
# DevTunnel š
|
|
2
|
+
|
|
3
|
+
**Share your local dev servers worldwide - Zero config tunnel for any framework**
|
|
4
|
+
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://github.com/maiz-an/DevTunnel)
|
|
7
|
+
[](https://www.npmjs.com/package/devtunnel-cli)
|
|
8
|
+
[](https://maiz-an.github.io/DevTunnel/)
|
|
9
|
+
|
|
10
|
+
š **Website:** [devtunnel.vercel.app](https://devtunnel.vercel.app) | š¦ **npm:** [devtunnel-cli](https://www.npmjs.com/package/devtunnel-cli) | š» **GitHub Pages:** [maiz-an.github.io/DevTunnel](https://maiz-an.github.io/DevTunnel/)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## ā” Quick Start
|
|
15
|
+
|
|
16
|
+
### Step-by-Step Guide
|
|
17
|
+
|
|
18
|
+
**1. Install DevTunnel (one-time setup):**
|
|
19
|
+
```bash
|
|
20
|
+
npm install -g devtunnel-cli
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**2. Navigate to your project directory:**
|
|
24
|
+
```bash
|
|
25
|
+
cd your-project
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**3. Start your dev server (in one terminal):**
|
|
29
|
+
```bash
|
|
30
|
+
npm start
|
|
31
|
+
# OR
|
|
32
|
+
npm run dev
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**4. Run DevTunnel (in another terminal, same directory):**
|
|
36
|
+
```bash
|
|
37
|
+
cd your-project # Same directory where you run npm start
|
|
38
|
+
devtunnel # Auto-detects project and port!
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**That's it!** DevTunnel will automatically detect your project and running dev server port.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## ⨠Features
|
|
46
|
+
|
|
47
|
+
- š¤ **Fully Automatic** - Cloudflare bundled, no installation needed
|
|
48
|
+
- šÆ **Zero Config** - No project changes needed
|
|
49
|
+
- š **Smart Proxy** - Bypasses Vite/React restrictions
|
|
50
|
+
- š **Cross-Platform** - Windows, macOS, Linux
|
|
51
|
+
- š **Any Framework** - Works with all
|
|
52
|
+
- š **Multi-Service** - Cloudflare, Ngrok, LocalTunnel fallback
|
|
53
|
+
- š¹ **Streaming Support** - Handles video/audio files (with limitations for large files)
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## š” How to Use
|
|
58
|
+
|
|
59
|
+
**Important:** Run `devtunnel` from the same directory where you run `npm start` or `npm run dev`!
|
|
60
|
+
|
|
61
|
+
1. **Install DevTunnel** (one-time): `npm install -g devtunnel-cli`
|
|
62
|
+
2. **Go to your project**: `cd your-project`
|
|
63
|
+
3. **Start your dev server**: `npm start` or `npm run dev` (keep this running)
|
|
64
|
+
4. **Open a new terminal** in the same project directory
|
|
65
|
+
5. **Run DevTunnel**: `devtunnel` (auto-detects everything!)
|
|
66
|
+
6. **Get your public URL** and share it! š
|
|
67
|
+
|
|
68
|
+
**Example:**
|
|
69
|
+
```bash
|
|
70
|
+
# Terminal 1 - Your dev server
|
|
71
|
+
cd my-react-app
|
|
72
|
+
npm run dev
|
|
73
|
+
|
|
74
|
+
# Terminal 2 - DevTunnel (same directory!)
|
|
75
|
+
cd my-react-app
|
|
76
|
+
devtunnel
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Works with any framework, API, or backend:** Vite, React, Next.js, Express, NestJS, FastAPI, Flask, Django, Spring Boot, Laravel, and any HTTP/HTTPS server!
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## š Documentation
|
|
84
|
+
|
|
85
|
+
Complete docs in `/docs` folder:
|
|
86
|
+
- [Complete Guide](docs/README.md)
|
|
87
|
+
- [Features](docs/FEATURES.md)
|
|
88
|
+
- [Troubleshooting](docs/TROUBLESHOOTING.md)
|
|
89
|
+
- [GitHub Pages Website](docs/DEPLOY-WEBSITE.md)
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## š ļø Requirements
|
|
94
|
+
|
|
95
|
+
- Node.js 16+ (download from [nodejs.org](https://nodejs.org))
|
|
96
|
+
- Internet connection
|
|
97
|
+
- Your dev server running
|
|
98
|
+
|
|
99
|
+
**No other installations needed!** Cloudflare is automatically bundled on first run.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## š License
|
|
104
|
+
|
|
105
|
+
MIT License - see [LICENSE](docs/LICENSE)
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
**Version 3.0.13** | Made with ā¤ļø for developers worldwide
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## š Search Keywords
|
|
114
|
+
|
|
115
|
+
**DevTunnel** | **dev tunnel** | **localhost tunnel** | **cloudflare tunnel** | **ngrok alternative** | **port forwarding** | **local development** | **vite tunnel** | **react dev server** | **nextjs tunnel** | **npm devtunnel** | **devtunnel-cli** | **share localhost** | **development tools** | **zero config tunnel**
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## š¦ Installation & Links
|
|
120
|
+
|
|
121
|
+
- **npm Package**: [devtunnel-cli](https://www.npmjs.com/package/devtunnel-cli)
|
|
122
|
+
- **GitHub Repository**: [maiz-an/DevTunnel](https://github.com/maiz-an/DevTunnel)
|
|
123
|
+
- **GitHub Pages**: [maiz-an.github.io/DevTunnel](https://maiz-an.github.io/DevTunnel/)
|
|
124
|
+
- **Official Website**: [devtunnel.vercel.app](https://devtunnel.vercel.app)
|
|
125
|
+
- **Documentation**: [docs/README.md](docs/README.md)
|
|
126
|
+
- **Issues**: [GitHub Issues](https://github.com/maiz-an/DevTunnel/issues)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devtunnel-cli",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "DevTunnel - Share local dev servers worldwide. Zero configuration tunnel for any framework. Install via npm: npm install -g devtunnel-cli. Works with Vite, React, Next.js, Express, NestJS and more.",
|
|
6
6
|
"main": "src/core/start.js",
|
package/src/core/RUN.js
CHANGED
|
@@ -9,21 +9,17 @@ import { dirname, join } from "path";
|
|
|
9
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
10
10
|
const __dirname = dirname(__filename);
|
|
11
11
|
|
|
12
|
-
// Suppress deprecation warnings from dependencies (harmless - from http-proxy/localtunnel)
|
|
13
12
|
const originalEmitWarning = process.emitWarning;
|
|
14
13
|
process.emitWarning = function(warning, ...args) {
|
|
15
14
|
if (typeof warning === 'string' && warning.includes('util._extend')) {
|
|
16
|
-
return;
|
|
15
|
+
return;
|
|
17
16
|
}
|
|
18
17
|
return originalEmitWarning.call(this, warning, ...args);
|
|
19
18
|
};
|
|
20
19
|
|
|
21
|
-
// Clear screen before starting
|
|
22
20
|
process.stdout.write('\x1B[2J\x1B[0f');
|
|
23
21
|
console.clear();
|
|
24
22
|
|
|
25
|
-
// Start the main app
|
|
26
|
-
// start.js is in the same directory as RUN.js (src/core/)
|
|
27
23
|
const startPath = join(__dirname, "start.js");
|
|
28
24
|
const child = spawn("node", [startPath], {
|
|
29
25
|
stdio: "inherit",
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { spawn } from 'child_process';
|
|
1
|
+
import { spawn, exec } from 'child_process';
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import https from 'https';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
6
|
import { dirname } from 'path';
|
|
7
|
+
import { promisify } from 'util';
|
|
7
8
|
|
|
9
|
+
const execAsync = promisify(exec);
|
|
8
10
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
11
|
const __dirname = dirname(__filename);
|
|
10
12
|
|
|
@@ -39,37 +41,109 @@ export function getBinaryPath() {
|
|
|
39
41
|
return path.join(BIN_DIR, platform, binName);
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
// Check available disk space (basic check)
|
|
43
44
|
function hasEnoughDiskSpace() {
|
|
44
45
|
try {
|
|
45
46
|
const stats = fs.statfsSync ? fs.statfsSync(BIN_DIR) : null;
|
|
46
47
|
if (stats) {
|
|
47
48
|
const availableSpace = stats.bavail * stats.bsize;
|
|
48
|
-
const requiredSpace = 50 * 1024 * 1024;
|
|
49
|
+
const requiredSpace = 50 * 1024 * 1024;
|
|
49
50
|
return availableSpace > requiredSpace;
|
|
50
51
|
}
|
|
51
|
-
return true;
|
|
52
|
+
return true;
|
|
52
53
|
} catch {
|
|
53
|
-
return true;
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function safeUnlink(filePath) {
|
|
59
|
+
try {
|
|
60
|
+
if (fs.existsSync(filePath)) {
|
|
61
|
+
fs.unlinkSync(filePath);
|
|
62
|
+
}
|
|
63
|
+
} catch (err) {
|
|
64
|
+
// Ignore permission errors - file might be locked or in use
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function isAdmin() {
|
|
69
|
+
if (process.platform !== 'win32') {
|
|
70
|
+
return process.getuid && process.getuid() === 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const { stdout } = await execAsync('net session');
|
|
75
|
+
return stdout.length > 0;
|
|
76
|
+
} catch {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function requestAdminElevation() {
|
|
82
|
+
if (process.platform !== 'win32') {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
console.log('\nš Requesting administrator privileges...');
|
|
87
|
+
console.log(' A UAC prompt will appear - please click "Yes"\n');
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
const script = `
|
|
91
|
+
Start-Process -FilePath "node" -ArgumentList "${process.argv[1]}" -Verb RunAs -Wait
|
|
92
|
+
`;
|
|
93
|
+
|
|
94
|
+
const { spawn } = await import('child_process');
|
|
95
|
+
return new Promise((resolve) => {
|
|
96
|
+
const proc = spawn('powershell', [
|
|
97
|
+
'-NoProfile',
|
|
98
|
+
'-NonInteractive',
|
|
99
|
+
'-ExecutionPolicy', 'Bypass',
|
|
100
|
+
'-Command', script
|
|
101
|
+
], {
|
|
102
|
+
stdio: 'inherit',
|
|
103
|
+
shell: false
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
proc.on('close', (code) => {
|
|
107
|
+
resolve(code === 0);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
proc.on('error', () => {
|
|
111
|
+
resolve(false);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
} catch {
|
|
115
|
+
return false;
|
|
54
116
|
}
|
|
55
117
|
}
|
|
56
118
|
|
|
57
119
|
function downloadFile(url, dest, retryCount = 0) {
|
|
58
120
|
return new Promise((resolve, reject) => {
|
|
59
|
-
// Create directory if needed
|
|
60
121
|
const dir = path.dirname(dest);
|
|
61
122
|
try {
|
|
62
123
|
if (!fs.existsSync(dir)) {
|
|
63
124
|
fs.mkdirSync(dir, { recursive: true });
|
|
64
125
|
}
|
|
65
126
|
} catch (err) {
|
|
66
|
-
reject(new Error(`Cannot create directory: ${err.message}
|
|
127
|
+
reject(new Error(`Cannot create directory: ${err.message}. Try running as administrator or choose a different location.`));
|
|
67
128
|
return;
|
|
68
129
|
}
|
|
69
130
|
|
|
70
|
-
// Create temp file first
|
|
71
131
|
const tempDest = dest + '.download';
|
|
72
|
-
|
|
132
|
+
|
|
133
|
+
// Clean up any existing temp file first
|
|
134
|
+
safeUnlink(tempDest);
|
|
135
|
+
|
|
136
|
+
let file;
|
|
137
|
+
try {
|
|
138
|
+
file = fs.createWriteStream(tempDest);
|
|
139
|
+
} catch (err) {
|
|
140
|
+
if (err.code === 'EPERM' || err.code === 'EACCES') {
|
|
141
|
+
reject(new Error(`Permission denied: Cannot write to ${dir}. Try running as administrator or check antivirus settings.`));
|
|
142
|
+
} else {
|
|
143
|
+
reject(new Error(`Cannot create download file: ${err.message}`));
|
|
144
|
+
}
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
73
147
|
|
|
74
148
|
const request = https.get(url, {
|
|
75
149
|
headers: {
|
|
@@ -78,10 +152,9 @@ function downloadFile(url, dest, retryCount = 0) {
|
|
|
78
152
|
},
|
|
79
153
|
timeout: 30000 // 30 second timeout
|
|
80
154
|
}, (response) => {
|
|
81
|
-
// Follow redirects
|
|
82
155
|
if (response.statusCode === 302 || response.statusCode === 301) {
|
|
83
156
|
file.close();
|
|
84
|
-
|
|
157
|
+
safeUnlink(tempDest);
|
|
85
158
|
downloadFile(response.headers.location, dest, retryCount)
|
|
86
159
|
.then(resolve)
|
|
87
160
|
.catch(reject);
|
|
@@ -90,7 +163,7 @@ function downloadFile(url, dest, retryCount = 0) {
|
|
|
90
163
|
|
|
91
164
|
if (response.statusCode !== 200) {
|
|
92
165
|
file.close();
|
|
93
|
-
|
|
166
|
+
safeUnlink(tempDest);
|
|
94
167
|
reject(new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`));
|
|
95
168
|
return;
|
|
96
169
|
}
|
|
@@ -155,20 +228,24 @@ function downloadFile(url, dest, retryCount = 0) {
|
|
|
155
228
|
request.on('timeout', () => {
|
|
156
229
|
request.destroy();
|
|
157
230
|
file.close();
|
|
158
|
-
|
|
231
|
+
safeUnlink(tempDest);
|
|
159
232
|
reject(new Error('Download timeout (30 seconds)'));
|
|
160
233
|
});
|
|
161
234
|
|
|
162
235
|
request.on('error', (err) => {
|
|
163
236
|
file.close();
|
|
164
|
-
|
|
237
|
+
safeUnlink(tempDest);
|
|
165
238
|
reject(err);
|
|
166
239
|
});
|
|
167
240
|
|
|
168
241
|
file.on('error', (err) => {
|
|
169
242
|
file.close();
|
|
170
|
-
|
|
171
|
-
|
|
243
|
+
safeUnlink(tempDest);
|
|
244
|
+
if (err.code === 'EPERM' || err.code === 'EACCES') {
|
|
245
|
+
reject(new Error(`Permission denied: Cannot write to ${tempDest}. Try running as administrator or check antivirus settings.`));
|
|
246
|
+
} else {
|
|
247
|
+
reject(new Error(`File write error: ${err.message}`));
|
|
248
|
+
}
|
|
172
249
|
});
|
|
173
250
|
});
|
|
174
251
|
}
|
|
@@ -193,7 +270,35 @@ async function downloadWithRetry(urls, dest, maxRetries = 3) {
|
|
|
193
270
|
const isLastRetry = retry === maxRetries - 1;
|
|
194
271
|
const isLastUrl = urlIndex === urls.length - 1;
|
|
195
272
|
|
|
196
|
-
if (err.message.includes('
|
|
273
|
+
if (err.message.includes('Permission denied') || err.message.includes('EPERM') || err.message.includes('EACCES')) {
|
|
274
|
+
console.log(`\nā Permission Error: ${err.message}`);
|
|
275
|
+
|
|
276
|
+
if (process.platform === 'win32') {
|
|
277
|
+
const admin = await isAdmin();
|
|
278
|
+
if (!admin) {
|
|
279
|
+
console.log('\nš Attempting to request administrator privileges...');
|
|
280
|
+
const elevated = await requestAdminElevation();
|
|
281
|
+
if (elevated) {
|
|
282
|
+
console.log('ā
Running with administrator privileges - retrying download...\n');
|
|
283
|
+
await downloadFile(url, dest, retry);
|
|
284
|
+
return true;
|
|
285
|
+
} else {
|
|
286
|
+
console.log('\nā ļø Could not elevate privileges automatically');
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
console.log('\nš” Solutions:');
|
|
292
|
+
if (process.platform === 'win32') {
|
|
293
|
+
console.log(' 1. Run terminal as Administrator (Right-click ā Run as administrator)');
|
|
294
|
+
} else {
|
|
295
|
+
console.log(' 1. Run with sudo: sudo npm install -g devtunnel-cli');
|
|
296
|
+
}
|
|
297
|
+
console.log(' 2. Check if antivirus is blocking file writes');
|
|
298
|
+
console.log(' 3. Check folder permissions for:', path.dirname(dest));
|
|
299
|
+
console.log(' 4. Try installing manually: https://github.com/cloudflare/cloudflared/releases\n');
|
|
300
|
+
throw err;
|
|
301
|
+
} else if (err.message.includes('ENOTFOUND') || err.message.includes('ECONNREFUSED')) {
|
|
197
302
|
console.log(`\nā Network error: ${err.message}`);
|
|
198
303
|
} else if (err.message.includes('timeout')) {
|
|
199
304
|
console.log(`\nā Download timeout`);
|
|
@@ -207,7 +312,7 @@ async function downloadWithRetry(urls, dest, maxRetries = 3) {
|
|
|
207
312
|
|
|
208
313
|
if (isLastRetry) {
|
|
209
314
|
console.log('š” Trying alternative source...\n');
|
|
210
|
-
break;
|
|
315
|
+
break;
|
|
211
316
|
}
|
|
212
317
|
}
|
|
213
318
|
}
|
|
@@ -240,13 +345,11 @@ export async function setupCloudflared() {
|
|
|
240
345
|
return binaryPath;
|
|
241
346
|
} else {
|
|
242
347
|
console.log('ā ļø Existing binary not working, re-downloading...\n');
|
|
243
|
-
|
|
348
|
+
safeUnlink(binaryPath);
|
|
244
349
|
}
|
|
245
350
|
} catch {
|
|
246
351
|
console.log('ā ļø Existing binary corrupted, re-downloading...\n');
|
|
247
|
-
|
|
248
|
-
fs.unlinkSync(binaryPath);
|
|
249
|
-
} catch {}
|
|
352
|
+
safeUnlink(binaryPath);
|
|
250
353
|
}
|
|
251
354
|
}
|
|
252
355
|
|
|
@@ -303,9 +406,7 @@ export async function setupCloudflared() {
|
|
|
303
406
|
return binaryPath;
|
|
304
407
|
} else {
|
|
305
408
|
console.error('ā Downloaded binary not working properly');
|
|
306
|
-
|
|
307
|
-
fs.unlinkSync(binaryPath);
|
|
308
|
-
} catch {}
|
|
409
|
+
safeUnlink(binaryPath);
|
|
309
410
|
return null;
|
|
310
411
|
}
|
|
311
412
|
|
|
@@ -315,11 +416,25 @@ export async function setupCloudflared() {
|
|
|
315
416
|
console.error('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
316
417
|
console.error(`Reason: ${err.message}\n`);
|
|
317
418
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
419
|
+
if (err.message.includes('Permission denied') || err.message.includes('EPERM') || err.message.includes('EACCES')) {
|
|
420
|
+
console.log('š” Permission Error Solutions:');
|
|
421
|
+
if (process.platform === 'win32') {
|
|
422
|
+
console.log(' 1. Run terminal as Administrator (Right-click ā Run as administrator)');
|
|
423
|
+
console.log(' 2. DevTunnel will automatically request admin privileges if needed');
|
|
424
|
+
} else {
|
|
425
|
+
console.log(' 1. Run with sudo: sudo npm install -g devtunnel-cli');
|
|
426
|
+
}
|
|
427
|
+
console.log(' 2. Check antivirus is not blocking file writes');
|
|
428
|
+
console.log(' 3. Check folder permissions for:', path.dirname(binaryPath));
|
|
429
|
+
console.log(' 4. Try installing Cloudflare manually:');
|
|
430
|
+
console.log(' https://github.com/cloudflare/cloudflared/releases\n');
|
|
431
|
+
} else {
|
|
432
|
+
console.log('š” Troubleshooting:');
|
|
433
|
+
console.log(' 1. Check internet connection');
|
|
434
|
+
console.log(' 2. Check firewall/antivirus settings');
|
|
435
|
+
console.log(' 3. Try running as administrator');
|
|
436
|
+
console.log(' 4. Install manually: https://github.com/cloudflare/cloudflared/releases\n');
|
|
437
|
+
}
|
|
323
438
|
|
|
324
439
|
console.log('š DevTunnel will use fallback tunnels (Ngrok/LocalTunnel)\n');
|
|
325
440
|
|
package/src/core/start.js
CHANGED
|
@@ -174,7 +174,6 @@ function showLogo() {
|
|
|
174
174
|
console.log("");
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
-
// Main function
|
|
178
177
|
async function main() {
|
|
179
178
|
// Clear screen - works on Windows, macOS, Linux
|
|
180
179
|
// ANSI escape codes for clear screen + cursor to top
|
|
@@ -184,7 +183,7 @@ async function main() {
|
|
|
184
183
|
// Show ASCII logo
|
|
185
184
|
showLogo();
|
|
186
185
|
|
|
187
|
-
console.log("DevTunnel v3.0.
|
|
186
|
+
console.log("DevTunnel v3.0.13");
|
|
188
187
|
console.log("Share your local dev servers worldwide");
|
|
189
188
|
console.log("");
|
|
190
189
|
console.log("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā");
|